1
0
mirror of https://github.com/ZeroCatDev/Classworks.git synced 2026-06-27 19:35:07 +00:00
Classworks/assets/dataProvider-BvLZfUfL.js

2 lines
18 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import{a as ge,g as he}from"./vendor-utils-B_Y_1aLs.js";import{n as d,ai as Se,s as B}from"./index-BxeI5EAR.js";import{i as j,t as x,g as q}from"./serverRotation-J4OEk8av.js";const J=(e,t)=>t.some(r=>e instanceof r);let Y,ee;function pe(){return Y||(Y=[IDBDatabase,IDBObjectStore,IDBIndex,IDBCursor,IDBTransaction])}function De(){return ee||(ee=[IDBCursor.prototype.advance,IDBCursor.prototype.continue,IDBCursor.prototype.continuePrimaryKey])}const M=new WeakMap,P=new WeakMap,K=new WeakMap;function be(e){const t=new Promise((r,n)=>{const s=()=>{e.removeEventListener("success",a),e.removeEventListener("error",o)},a=()=>{r(O(e.result)),s()},o=()=>{n(e.error),s()};e.addEventListener("success",a),e.addEventListener("error",o)});return K.set(t,e),t}function ke(e){if(M.has(e))return;const t=new Promise((r,n)=>{const s=()=>{e.removeEventListener("complete",a),e.removeEventListener("error",o),e.removeEventListener("abort",o)},a=()=>{r(),s()},o=()=>{n(e.error||new DOMException("AbortError","AbortError")),s()};e.addEventListener("complete",a),e.addEventListener("error",o),e.addEventListener("abort",o)});M.set(e,t)}let W={get(e,t,r){if(e instanceof IDBTransaction){if(t==="done")return M.get(e);if(t==="store")return r.objectStoreNames[1]?void 0:r.objectStore(r.objectStoreNames[0])}return O(e[t])},set(e,t,r){return e[t]=r,!0},has(e,t){return e instanceof IDBTransaction&&(t==="done"||t==="store")?!0:t in e}};function ie(e){W=e(W)}function Ee(e){return De().includes(e)?function(...t){return e.apply(H(this),t),O(this.request)}:function(...t){return O(e.apply(H(this),t))}}function Ie(e){return typeof e=="function"?Ee(e):(e instanceof IDBTransaction&&ke(e),J(e,pe())?new Proxy(e,W):e)}function O(e){if(e instanceof IDBRequest)return be(e);if(P.has(e))return P.get(e);const t=Ie(e);return t!==e&&(P.set(e,t),K.set(t,e)),t}const H=e=>K.get(e);function ue(e,t,{blocked:r,upgrade:n,blocking:s,terminated:a}={}){const o=indexedDB.open(e,t),i=O(o);return n&&o.addEventListener("upgradeneeded",c=>{n(O(o.result),c.oldVersion,c.newVersion,O(o.transaction),c)}),r&&o.addEventListener("blocked",c=>r(c.oldVersion,c.newVersion,c)),i.then(c=>{a&&c.addEventListener("close",()=>a()),s&&c.addEventListener("versionchange",u=>s(u.oldVersion,u.newVersion,u))}).catch(()=>{}),i}const Ne=["get","getKey","getAll","getAllKeys","count"],Oe=["put","add","delete","clear"],F=new Map;function te(e,t){if(!(e instanceof IDBDatabase&&!(t in e)&&typeof t=="string"))return;if(F.get(t))return F.get(t);const r=t.replace(/FromIndex$/,""),n=t!==r,s=Oe.includes(r);if(!(r in(n?IDBIndex:IDBObjectStore).prototype)||!(s||Ne.includes(r)))return;const a=async function(o,...i){const c=this.transaction(o,s?"readwrite":"readonly");let u=c.store;return n&&(u=u.index(i.shift())),(await Promise.all([u[r](...i),s&&c.done]))[0]};return F.set(t,a),a}ie(e=>({...e,get:(t,r,n)=>te(t,r)||e.get(t,r,n),has:(t,r)=>!!te(t,r)||e.has(t,r)}));const Te=["continue","continuePrimaryKey","advance"],re={},z=new WeakMap,de=new WeakMap,Re={get(e,t){if(!Te.includes(t))return e[t];let r=re[t];return r||(r=re[t]=function(...n){z.set(this,de.get(this)[t](...n))}),r}};async function*_e(...e){let t=this;if(t instanceof IDBCursor||(t=await t.openCursor(...e)),!t)return;t=t;const r=new Proxy(t,Re);for(de.set(r,t),K.set(r,H(t));t;)yield r,t=await(z.get(r)||t.continue()),z.delete(r)}function ne(e,t){return t===Symbol.asyncIterator&&J(e,[IDBIndex,IDBObjectStore,IDBCursor])||t==="iterate"&&J(e,[IDBIndex,IDBObjectStore])}ie(e=>({...e,get(t,r,n){return ne(t,r)?_e:e.get(t,r,n)},has(t,r){return ne(t,r)||e.has(t,r)}}));const je="ClassworksDB",xe=3,E=async()=>ue(je,xe,{upgrade(e){e.objectStoreNames.contains("kv")||e.createObjectStore("kv"),e.objectStoreNames.contains("system")||e.createObjectStore("system"),e.objectStoreNames.contains("syncQueue")||e.createObjectStore("syncQueue")}}),S={async loadData(e){try{const r=await(await E()).get("kv",e);return r?v(JSON.parse(r)):f("数据不存在","NOT_FOUND")}catch(t){return f("读取本地数据失败:"+t)}},async saveData(e,t){try{return await(await E()).put("kv",JSON.stringify(t),e),v(!0)}catch(r){return f("保存本地数据失败:"+r)}},async loadKeys(e={}){try{const s=await(await E()).transaction(["kv"],"readonly").objectStore("kv").getAllKeys(),{sortDir:a="asc",limit:o=100,skip:i=0}=e,c=s.sort((h,y)=>a==="desc"?y.localeCompare(h):h.localeCompare(y)),u=c.length,l=c.slice(i,i+o),g={keys:l,total_rows:u,current_page:{limit:o,skip:i,count:l.length},load_more:null};return v(g)}catch(t){return f("获取本地键名列表失败:"+t.message)}},async addToSyncQueue(e){try{return await(await E()).put("syncQueue",JSON.stringify(e),e.key),v(!0)}catch(t){return f("添加同步队列失败:"+t)}},async getSyncQueue(){try{const e=await E(),t=await e.getAllKeys("syncQueue"),r=[];for(const n of t){const s=await e.get("syncQueue",n);s&&r.push(JSON.parse(s))}return r.sort((n,s)=>n.timestamp-s.timestamp),v(r)}catch(e){return f("获取同步队列失败:"+e)}},async removeFromSyncQueue(e){try{return await(await E()).delete("syncQueue",e),v(!0)}catch(t){return f("删除同步队列项失败:"+t)}},async deleteByPrefix(e){try{const r=(await E()).transaction("kv","readwrite"),n=r.objectStore("kv"),s=await n.getAllKeys();let a=0;for(const o of s)o.startsWith(e)&&(await n.delete(o),a++);return await r.done,a}catch(t){return console.warn("kvLocalProvider.deleteByPrefix 失败:",t),0}}};function Le(e,t){return"headers"in e&&typeof e.headers=="object"&&!Array.isArray(e.headers)?U(e.headers):"getHeaders"in e&&typeof e.getHeaders=="function"?U(e.getHeaders()):U(e)}function U(e,t){const r=D(e,"ratelimit");if(r)return $e(r);let n;if(D(e,"ratelimit-remaining"))n="ratelimit-";else if(D(e,"x-ratelimit-remaining"))n="x-ratelimit-";else if(D(e,"x-rate-limit-remaining"))n="x-rate-limit-";else return;const s=p(D(e,`${n}limit`)),a=p(D(e,`${n}used`))||p(D(e,`${n}observed`)),o=p(D(e,`${n}remaining`));let i;const c=D(e,`${n}reset`);switch(void 0){case"date":{i=fe(c??"");break}case"unix":{i=G(c??"");break}case"seconds":{i=le(c??"");break}case"milliseconds":{i=Be(c??"");break}default:if(c)i=Fe(c);else{const l=D(e,"retry-after");l&&(i=G(l))}}return{limit:Number.isNaN(s)?a+o:s,used:Number.isNaN(a)?s-o:a,remaining:o,reset:i}}var Ae=/limit\s*=\s*(\d+)/i,Ce=/remaining\s*=\s*(\d+)/i,Ke=/reset\s*=\s*(\d+)/i;function $e(e){var t,r,n;const s=p((t=Ae.exec(e))==null?void 0:t[1]),a=p((r=Ce.exec(e))==null?void 0:r[1]),o=p((n=Ke.exec(e))==null?void 0:n[1]),i=X(o);return{limit:s,used:s-a,remaining:a,reset:i}}function X(e){const t=new Date;return t.setSeconds(t.getSeconds()+e),t}function p(e){return typeof e=="number"?e:Number.parseInt(e??"",10)}function D(e,t){var r;if("get"in e&&typeof e.get=="function")return(r=e.get(t))!=null?r:void 0;if(t in e&&typeof e[t]=="string")return e[t]}function fe(e){return new Date(e)}function G(e){const t=p(e);return new Date(t*1e3)}function le(e){const t=p(e);return X(t)}function Be(e){const t=p(e);return X(t/1e3)}var Pe=/[a-z]/i;function Fe(e){if(Pe.test(e))return fe(e);const t=p(e);return t&&t>1e9?G(t):le(t)}const w=ge.create({timeout:1e4});w.interceptors.request.use(e=>{const t=d("server.provider");if(t==="kv-server"||t==="classworkscloud"){const r=d("server.kvToken");if(r)e.headers["x-app-token"]=r;else{const n=d("server.siteKey");n&&(e.headers["x-site-key"]=he.encode(n))}}return e},e=>(console.log(e),Promise.reject(e)));w.interceptors.response.use(e=>e,e=>{if(e.response&&e.response.status===429)try{const t=Le(e.response);t&&Se.show(t.reset,e.config.url,e.config.method.toUpperCase())}catch(t){console.error("解析限速头信息失败:",t)}return Promise.reject(e)});const nt=Object.freeze(Object.defineProperty({__proto__:null,default:w},Symbol.toStringTag,{value:"Module"})),b=()=>{const e={Accept:"application/json"},t=d("server.kvToken"),r=d("server.siteKey");return t?e["x-app-token"]=t:r&&(e["x-site-key"]=r),e},I={async loadNamespaceInfo(){var e,t;try{if(j())return await x(async s=>{const a=await w.get(`${s}/kv/_info`,{headers:b()});return v(a.data)});const r=d("server.domain"),n=await w.get(`${r}/kv/_info`,{headers:b()});return v(n.data)}catch(r){return console.error("获取命名空间信息失败:",r),f(((t=(e=r.response)==null?void 0:e.data)==null?void 0:t.message)||"获取命名空间信息失败","NAMESPACE_ERROR")}},async updateNamespaceInfo(e){var t,r;try{if(j())return await x(async a=>await w.put(`${a}/kv/_info`,e,{headers:b()}));const n=d("server.domain");return await w.put(`${n}/kv/_info`,e,{headers:b()})}catch(n){return f(((r=(t=n.response)==null?void 0:t.data)==null?void 0:r.message)||"更新命名空间信息失败","NAMESPACE_ERROR")}},async loadData(e){var t,r,n;try{if(j())return await x(async o=>{const i=await w.get(`${o}/kv/${e}`,{headers:b()});return v(i.data)});const s=d("server.domain"),a=await w.get(`${s}/kv/${e}`,{headers:b()});return v(a.data)}catch(s){return((t=s.response)==null?void 0:t.status)===404?f("数据不存在","NOT_FOUND"):(console.log(s),f(((n=(r=s.response)==null?void 0:r.data)==null?void 0:n.message)||"服务器连接失败","NETWORK_ERROR"))}},async saveData(e,t){var r,n;try{if(j())return await x(async a=>(await w.post(`${a}/kv/${e}`,t,{headers:b()}),v(!0)));const s=d("server.domain");return await w.post(`${s}/kv/${e}`,t,{headers:b()}),v(!0)}catch(s){return console.log(s),f(((n=(r=s.response)==null?void 0:r.data)==null?void 0:n.message)||"保存失败","SAVE_ERROR")}},async loadKeys(e={}){var t,r,n,s,a;try{const{sortBy:o="key",sortDir:i="asc",limit:c=100,skip:u=0}=e,l=new URLSearchParams({sortBy:o,sortDir:i,limit:c.toString(),skip:u.toString()});if(j())return await x(async y=>{const m=await w.get(`${y}/kv/_keys?${l}`,{headers:b()});return v(m.data)});const g=d("server.domain"),h=await w.get(`${g}/kv/_keys?${l}`,{headers:b()});return v(h.data)}catch(o){return((t=o.response)==null?void 0:t.status)===404?f("命名空间不存在","NOT_FOUND"):((r=o.response)==null?void 0:r.status)===403?f("无权限访问此命名空间","PERMISSION_DENIED"):((n=o.response)==null?void 0:n.status)===401?f("认证失败","UNAUTHORIZED"):(console.log(o),f(((a=(s=o.response)==null?void 0:s.data)==null?void 0:a.message)||"获取键名列表失败","NETWORK_ERROR"))}}};function T(e){return{vc:{[e]:0},ts:0,deviceId:e,_fieldTs:{},lastSyncedData:null,lastSyncedTs:0,lastSyncedVc:{[e]:0}}}function se(e,t){const r={...e.vc};return r[t]=(r[t]||0)+1,{...e,vc:r,ts:Date.now(),deviceId:t}}function Ue(e,t){const r={...e};for(const[n,s]of Object.entries(t))r[n]=Math.max(r[n]||0,s);return r}function R(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function Ve(e,t){if(!e&&!t)return{};if(!e)return{...t};if(!t)return{...e};const r={...e};for(const[n,s]of Object.entries(t)){const a=r[n];(!a||s.ts>a.ts||s.ts===a.ts&&s.deviceId<a.deviceId)&&(r[n]=s)}return r}function ae(e){if(!e||e.length===0)return null;const t=e[0];if(R(t)){if("id"in t)return r=>R(r)?r.id:JSON.stringify(r);if("name"in t)return r=>R(r)?r.name:JSON.stringify(r);if("key"in t)return r=>R(r)?r.key:JSON.stringify(r)}return null}function Qe(e,t,r){const n=ae(e)||ae(r)||(c=>JSON.stringify(c)),s=new Map,a=new Map;e.forEach(c=>{const u=n(c);s.has(u)||s.set(u,c)}),r.forEach(c=>{const u=n(c);a.has(u)||a.set(u,c)});const o=[],i=new Set;for(const[c,u]of s)i.has(c)||(i.add(c),o.push(u));for(const[c,u]of a)i.has(c)||(i.add(c),o.push(u));return o}function Je(e,t,r,n){var o,i;const s={},a=new Set([...Object.keys(e),...Object.keys(r)]);for(const c of a){const u=c in e,l=c in r;if(u&&!l)s[c]=e[c];else if(!u&&l)s[c]=r[c];else{const g=((o=t._fieldTs)==null?void 0:o[c])||{ts:t.ts,deviceId:t.deviceId},h=((i=n._fieldTs)==null?void 0:i[c])||{ts:n.ts,deviceId:n.deviceId};g.ts>h.ts?s[c]=e[c]:h.ts>g.ts?s[c]=r[c]:s[c]=g.deviceId<=h.deviceId?e[c]:r[c]}}return s}function Me(e,t,r,n){const s=Ue(t.vc||{},n.vc||{}),a=Math.max(t.ts||0,n.ts||0),o=Ve(t._fieldTs,n._fieldTs);let i;return R(e)&&R(r)?i=Je(e,t,r,n):Array.isArray(e)&&Array.isArray(r)?i=Qe(e,t,r):typeof e==typeof r&&typeof e!="object"?(t.ts||0)>(n.ts||0)?i=e:(n.ts||0)>(t.ts||0)?i=r:i=(t.deviceId||"")<=(n.deviceId||"")?e:r:i=(t.ts||0)>=(n.ts||0)?e:r,{data:i,meta:{vc:s,ts:a,deviceId:a===(t.ts||0)?t.deviceId:n.deviceId,_fieldTs:o,lastSyncedData:n.lastSyncedData??t.lastSyncedData??null,lastSyncedTs:Math.max(t.lastSyncedTs||0,n.lastSyncedTs||0),lastSyncedVc:s}}}const $="_cache:",We="ClassworksDB",ye=7*24*60*60*1e3,He=[{pattern:"*",ttl:ye}];async function Z(){return ue(We,void 0,{upgrade(e){e.objectStoreNames.contains("kv")||e.createObjectStore("kv"),e.objectStoreNames.contains("system")||e.createObjectStore("system"),e.objectStoreNames.contains("syncQueue")||e.createObjectStore("syncQueue")}})}function ze(e,t){const r="^"+e.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*")+"$";return new RegExp(r).test(t)}function Ge(e){return e&&typeof e=="object"&&!("meta"in e)&&!("cacheTimestamp"in e)}function me(e){return e&&typeof e=="object"&&"meta"in e&&"cacheTimestamp"in e}function ve(e){for(const{pattern:t,ttl:r}of He)if(ze(t,e))return r;return ye}async function A(e){try{const t=await Z(),r=$+e,n=await t.get("kv",r);if(!n)return null;let s;try{s=typeof n=="string"?JSON.parse(n):n}catch{return null}if(Ge(s)){const a=d("device.uuid")||"unknown",o=T(a);o.ts=Date.now(),o.lastSyncedData=s;const i={data:s,meta:o,cacheTimestamp:Date.now(),cacheTTL:ve(e)};return await t.put("kv",JSON.stringify(i),r),{data:i.data,meta:i.meta}}return me(s)?Date.now()-s.cacheTimestamp>s.cacheTTL?(await t.delete("kv",r),null):{data:s.data,meta:s.meta}:null}catch(t){return console.warn("cacheManager.getCacheEntry 失败:",t),null}}async function N(e,t,r){try{const n=await Z(),s=$+e,a={data:t,meta:r,cacheTimestamp:Date.now(),cacheTTL:ve(e)};return await n.put("kv",JSON.stringify(a),s),!0}catch(n){return console.warn("cacheManager.setCacheEntry 失败:",n),!1}}async function we(){let e=0;try{const r=(await Z()).transaction("kv","readwrite"),n=r.objectStore("kv"),s=await n.getAllKeys();for(const a of s){if(!a.startsWith($))continue;const o=await n.get(a);if(!o)continue;let i;try{i=typeof o=="string"?JSON.parse(o):o}catch{continue}me(i)&&Date.now()-i.cacheTimestamp>i.cacheTTL&&(await n.delete(a),e++)}await r.done}catch(t){console.warn("cacheManager.cleanupExpiredEntries 失败:",t)}return e}let _=null,V=!1;async function C(e={}){var n;if(V)return{synced:0,failed:0};V=!0;let t=0,r=0;try{const s=await S.getSyncQueue();if(s.success===!1||!Array.isArray(s)||s.length===0)return{synced:0,failed:0};for(const a of s)try{const o=await I.saveData(a.key,a.data);if(o.success!==!1){if(await S.removeFromSyncQueue(a.key),a.meta){const i=d("device.uuid")||"unknown",c=await A(a.key);if(c){const u={...c.meta};u.lastSyncedData=a.data,u.lastSyncedTs=Date.now(),u.lastSyncedVc={...u.vc},await N(a.key,c.data,u)}else{const u=a.meta||T(i);u.lastSyncedData=a.data,u.lastSyncedTs=Date.now(),u.lastSyncedVc={...u.vc},await N(a.key,a.data,u)}}t++}else r++,e.silent||console.warn(`smartSync: 跳过 key=${a.key}, 服务器错误:`,(n=o.error)==null?void 0:n.message)}catch{r++;break}t>0&&we()}finally{V=!1}return!e.silent&&t>0&&console.log(`smartSync: 同步完成,成功 ${t} 条,失败 ${r}`),{synced:t,failed:r}}async function Xe(){try{const e=await S.getSyncQueue();if(e.success===!1||!Array.isArray(e)||e.length===0)return;C({silent:!0})}catch{}}function Ze(){_||(_=()=>C(),window.addEventListener("online",_),we(),navigator.onLine&&C())}function qe(){_&&(window.removeEventListener("online",_),_=null)}const v=e=>e,f=(e,t="UNKNOWN_ERROR")=>({success:!1,error:{code:t,message:e}});function Ye(e){return e&&e.success===!1}function oe(e){var t;return Ye(e)&&((t=e.error)==null?void 0:t.code)==="NETWORK_ERROR"}function ce(){return d("device.uuid")||"unknown"}function L(e){return e&&typeof e=="object"&&!Array.isArray(e)&&"value"in e?e.value:e}const st={init:Ze,destroy:qe,flushNow:C};function Q(){const e=d("server.provider");return e==="kv-server"||e==="classworkscloud"}const at={loadData:async e=>{if(!Q())return S.loadData(e);const t=await I.loadData(e),r=L(t);if(!oe(r)){if(r.success!==!1){const a=await A(e),o=ce();if(a){const i=L(a.data),c=JSON.stringify(i),u=JSON.stringify(r),l=JSON.stringify(L(a.meta.lastSyncedData)??null);if(u===c)return i;if(u!==l){const g=a.meta.vc||{},h=a.meta.lastSyncedVc||{};if((g[o]||0)>(h[o]||0)){const m=T("server");m.ts=Date.now();const k=Me(i,a.meta,r,m);return await N(e,k.data,k.meta),I.saveData(e,k.data),k.data}else{const m=T(o);return m.ts=Date.now(),m.lastSyncedData=r,m.lastSyncedTs=Date.now(),m.lastSyncedVc={...m.vc},await N(e,r,m),r}}else return i}else{const i=T(o);return i.ts=Date.now(),i.lastSyncedData=r,i.lastSyncedTs=Date.now(),i.lastSyncedVc={...i.vc},await N(e,r,i),r}}return r}const n=await A(e);if(n){const a=L(n.data);return typeof a=="object"&&a!==null&&(a.fromCache=!0),a}const s=await S.loadData($+e);return s.success!==!1?{...s,fromCache:!0}:r},saveData:async(e,t)=>{if(!Q())return S.saveData(e,t);const r=ce(),n=await A(e);let s;n?s=se(n.meta,r):s=se(T(r),r),await N(e,t,s);const a=await I.saveData(e,t);return a.success!==!1?(s.lastSyncedData=t,s.lastSyncedTs=Date.now(),s.lastSyncedVc={...s.vc},await N(e,t,s),await S.removeFromSyncQueue(e),Xe(),a):(await S.addToSyncQueue({key:e,data:t,timestamp:Date.now(),meta:s}),{success:!0,queuedForSync:!0})},loadKeys:async(e={})=>{if(!Q())return S.loadKeys(e);const t=await I.loadKeys(e);return oe(t)?S.loadKeys(e):t},async getKeyCloudUrl(e,t={}){var s;const{migrateFromLocal:r=!0,autoConfigureCloud:n=!0}=t;try{const a=d("server.provider");let o;a==="classworkscloud"?o=q():o=d("server.domain");let i=d("server.siteKey");const c=d("device.uuid");let u=!1;if(!o||!c)if(n){const y={"server.domain":"https://kv-service.houlang.cloud","server.siteKey":""};o||(B("server.domain",y["server.domain"]),o=y["server.domain"],u=!0),i||(B("server.siteKey",y["server.siteKey"]),i=y["server.siteKey"]),B("server.provider","classworkscloud"),o=q()}else return f("云端配置无效请检查服务器域名和设备UUID","CONFIG_ERROR");let l=!1;if(r)try{const y=await S.loadData(e);if(y&&y.success!==!1){const m=await I.loadData(e);if(m&&m.success===!1&&((s=m.error)==null?void 0:s.code)==="NOT_FOUND"){const k=await I.saveData(e,y);k&&k.success!==!1&&(l=!0,console.log(`已成功将键 ${e} 的数据从本地迁移到云端`))}}}catch(y){console.warn(`迁移键 ${e} 的数据时出错:`,y)}const g=d("server.kvToken");return{success:!0,url:`${o}/kv/${e}?token=${g}`,migrated:l,configured:u}}catch(a){return console.error("获取键云端地址时出错:",a),f(a.message||"获取键云端地址失败","CLOUD_URL_ERROR")}}};export{w as a,S as b,nt as c,at as d,I as k,ue as o,st as s};