94 lines
6.3 KiB
JavaScript
94 lines
6.3 KiB
JavaScript
(()=>{
|
|
'use strict';
|
|
if(window.CateriumDataV1771)return;
|
|
|
|
const VERSION='17.7.1';
|
|
const RELEASE='20260909-v17-7-1-data-layer-adoption';
|
|
const listeners=new Map();
|
|
const clone=value=>{try{return structuredClone(value)}catch(_){return JSON.parse(JSON.stringify(value))}};
|
|
const safeJson=(raw,fallback)=>{try{const value=JSON.parse(raw);return value==null?fallback:value}catch(_){return fallback}};
|
|
const emit=(topic,payload)=>{for(const fn of listeners.get(topic)||[]){try{fn(payload)}catch(error){console.error('[Caterium Data]',error)}}};
|
|
const subscribe=(topic,fn)=>{if(typeof fn!=='function')return()=>{};if(!listeners.has(topic))listeners.set(topic,new Set());listeners.get(topic).add(fn);return()=>listeners.get(topic)?.delete(fn)};
|
|
|
|
function runtimeOrders(){try{if(typeof orders!=='undefined'&&Array.isArray(orders))return orders}catch(_){}return null}
|
|
function runtimeCatalog(){try{if(typeof boxes!=='undefined'&&Array.isArray(boxes))return boxes}catch(_){}return null}
|
|
function runtimePersist(){try{return typeof persist==='function'?persist:null}catch(_){return null}}
|
|
function cloud(){return window.SunCloudV2||null}
|
|
function session(){try{return cloud()?.getSession?.()||null}catch(_){return null}}
|
|
function workspace(){try{return cloud()?.getWorkspace?.()||null}catch(_){return null}}
|
|
function supportMode(){try{return cloud()?.getSupportMode?.()||null}catch(_){return null}}
|
|
function isSignedIn(){return Boolean(session()?.user)}
|
|
function isSupportReadOnly(){return Boolean(supportMode()||cloud()?.isSupportMode?.())}
|
|
function canWrite(permission='app.write'){
|
|
if(isSupportReadOnly())return false;
|
|
if(!isSignedIn())return true;
|
|
try{const c=cloud();if(typeof c?.hasPermission==='function')return c.hasPermission(permission)||c.hasPermission('app.write')}catch(_){}
|
|
return true;
|
|
}
|
|
|
|
const storage={
|
|
read(key,fallback=null){const raw=localStorage.getItem(String(key));if(raw==null)return fallback;return safeJson(raw,fallback)},
|
|
write(key,value,{silent=false}={}){localStorage.setItem(String(key),JSON.stringify(value));if(!silent)emit(`storage:${key}`,clone(value));return value},
|
|
remove(key){localStorage.removeItem(String(key));emit(`storage:${key}`,null)},
|
|
raw(key){return localStorage.getItem(String(key))}
|
|
};
|
|
|
|
function persistDomain(key,list,persistLocal){
|
|
if(!persistLocal){storage.write(key,list,{silent:true});return}
|
|
const p=runtimePersist();
|
|
if(p){try{p();return}catch(error){console.warn('[Caterium Data] persist fallback',error)}}
|
|
storage.write(key,list,{silent:true});
|
|
}
|
|
|
|
function getOrders(){const live=runtimeOrders();return clone(live||storage.read('sunOrders',[])||[])}
|
|
function replaceOrders(next,{persistLocal=true,reason='replace'}={}){
|
|
const list=Array.isArray(next)?clone(next):[],live=runtimeOrders();
|
|
if(live){live.length=0;live.push(...clone(list))}
|
|
persistDomain('sunOrders',list,persistLocal);emit('orders',{reason,orders:clone(list)});return list;
|
|
}
|
|
function getOrder(id){return getOrders().find(o=>String(o?.id)===String(id))||null}
|
|
function updateOrder(id,updater,{persistLocal=true,reason='update'}={}){
|
|
const list=getOrders(),index=list.findIndex(o=>String(o?.id)===String(id));if(index<0)return null;
|
|
const current=clone(list[index]),next=typeof updater==='function'?updater(current):{...current,...clone(updater||{})};if(!next)return null;
|
|
list[index]=next;replaceOrders(list,{persistLocal,reason});return clone(next);
|
|
}
|
|
function applyServerOrders(changed,{reason='server'}={}){
|
|
const patches=Array.isArray(changed)?changed:[];if(!patches.length)return {changed:0,ids:[]};
|
|
const list=getOrders(),map=new Map(list.map((o,i)=>[String(o?.id),i])),ids=[];
|
|
for(const patch of patches){const id=String(patch?.id??'');if(!id)continue;const index=map.get(id);if(index==null){list.push(clone(patch));map.set(id,list.length-1)}else list[index]=clone(patch);ids.push(id)}
|
|
replaceOrders(list,{persistLocal:false,reason});
|
|
try{window.render?.();window.renderOrders?.();window.renderStats?.();window.renderClients?.()}catch(_){}
|
|
try{window.dispatchEvent(new CustomEvent('caterium:data-orders-applied',{detail:{ids,reason}}))}catch(_){}
|
|
return {changed:ids.length,ids};
|
|
}
|
|
|
|
function getCatalog(){const live=runtimeCatalog();return clone(live||storage.read('sunBoxes',[])||[])}
|
|
function replaceCatalog(next,{persistLocal=true,reason='replace'}={}){
|
|
const list=Array.isArray(next)?clone(next):[],live=runtimeCatalog();
|
|
if(live){live.length=0;live.push(...clone(list))}
|
|
persistDomain('sunBoxes',list,persistLocal);emit('catalog',{reason,items:clone(list)});return list;
|
|
}
|
|
function getCatalogItem(id){return getCatalog().find(x=>String(x?.id)===String(id))||null}
|
|
function upsertCatalogItem(item,{persistLocal=true,reason='upsert'}={}){
|
|
if(!item?.id)return null;const list=getCatalog(),index=list.findIndex(x=>String(x?.id)===String(item.id)),next=clone(item);
|
|
if(index<0)list.push(next);else list[index]=next;replaceCatalog(list,{persistLocal,reason});return clone(next);
|
|
}
|
|
function removeCatalogItem(id,{persistLocal=true,reason='remove'}={}){
|
|
const list=getCatalog(),next=list.filter(x=>String(x?.id)!==String(id));if(next.length===list.length)return false;
|
|
replaceCatalog(next,{persistLocal,reason});return true;
|
|
}
|
|
|
|
const ordersRepo={list:getOrders,get:getOrder,replace:replaceOrders,update:updateOrder,applyServerChanges:applyServerOrders};
|
|
const catalogRepo={list:getCatalog,get:getCatalogItem,replace:replaceCatalog,upsert:upsertCatalogItem,remove:removeCatalogItem};
|
|
const diagnostics={
|
|
snapshot(){return {version:VERSION,workspaceId:workspace()?.id||null,signedIn:isSignedIn(),supportReadOnly:isSupportReadOnly(),orderCount:getOrders().length,catalogCount:getCatalog().length,listenerTopics:listeners.size}},
|
|
measure(name,fn){const started=performance.now();return Promise.resolve().then(fn).finally(()=>emit('metric',{name,durationMs:Math.round((performance.now()-started)*10)/10,at:new Date().toISOString()}))}
|
|
};
|
|
|
|
const api={VERSION,RELEASE,storage,orders:ordersRepo,catalog:catalogRepo,subscribe,emit,cloud,session,workspace,isSignedIn,isSupportReadOnly,canWrite,diagnostics};
|
|
window.CateriumDataV1771=api;
|
|
window.CateriumDataV1770=api;
|
|
window.CateriumData=api;
|
|
try{window.dispatchEvent(new CustomEvent('caterium:data-ready',{detail:{version:VERSION,phase:2}}))}catch(_){}
|
|
})();
|