dolphin-client 1.1.2 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -41,6 +41,10 @@
41
41
  "name": "dolphin-toast",
42
42
  "description": "Dolphin CLI Component"
43
43
  },
44
+ {
45
+ "name": "dolphin-store",
46
+ "description": "Declarative UI Store Initialization Component (Seeds state via attributes or JSON text content)"
47
+ },
44
48
  {
45
49
  "name": "dolphin-modal",
46
50
  "description": "Dolphin CLI Component"
@@ -464,6 +468,10 @@
464
468
  "name": "dolphin-toast",
465
469
  "description": "Dolphin CLI Component (dolphin-toast.html)"
466
470
  },
471
+ {
472
+ "name": "dolphin-store",
473
+ "description": "Declarative UI Store Component"
474
+ },
467
475
  {
468
476
  "name": "dolphin-modal",
469
477
  "description": "Dolphin CLI Component (dolphin-modal.html)"
@@ -1381,6 +1381,73 @@ var DolphinModule = (() => {
1381
1381
  };
1382
1382
  clientProto._scanStoreBinds = function() {
1383
1383
  if (typeof document === "undefined") return;
1384
+ const storeElements = document.querySelectorAll("dolphin-store");
1385
+ storeElements.forEach((el) => {
1386
+ if (typeof el.getAttribute !== "function") return;
1387
+ const storeName = el.getAttribute("name") || el.getAttribute("data-store");
1388
+ if (!storeName) return;
1389
+ const hasChildren = el.children && el.children.length > 0;
1390
+ if (hasChildren) {
1391
+ if (typeof el.setAttribute === "function") {
1392
+ el.setAttribute("data-rt-bind", `store/${storeName}`);
1393
+ el.setAttribute("data-rt-type", "context");
1394
+ }
1395
+ } else {
1396
+ if (el.style) {
1397
+ el.style.display = "none";
1398
+ }
1399
+ }
1400
+ if (!hasChildren) {
1401
+ const content = el.textContent ? el.textContent.trim() : "";
1402
+ if (content && content.startsWith("{")) {
1403
+ try {
1404
+ const parsed = JSON.parse(content);
1405
+ if (parsed && typeof parsed === "object") {
1406
+ Object.keys(parsed).forEach((key) => {
1407
+ this.setStoreState(storeName, key, parsed[key]);
1408
+ });
1409
+ }
1410
+ } catch (err) {
1411
+ console.error(`[Dolphin Store Init Error] Failed to parse JSON inside <dolphin-store name="${storeName}">:`, err);
1412
+ }
1413
+ }
1414
+ }
1415
+ const templateSelector = el.getAttribute("template");
1416
+ if (el.attributes) {
1417
+ const excludeAttrs = ["name", "data-store", "style", "data-rt-bind", "data-rt-type", "template"];
1418
+ Array.from(el.attributes).forEach((attr) => {
1419
+ if (!excludeAttrs.includes(attr.name)) {
1420
+ let val = attr.value;
1421
+ if (val === "true") val = true;
1422
+ else if (val === "false") val = false;
1423
+ else if (val === "null") val = null;
1424
+ else if (!isNaN(Number(val)) && val.trim() !== "") val = Number(val);
1425
+ this.setStoreState(storeName, attr.name, val);
1426
+ }
1427
+ });
1428
+ }
1429
+ if (templateSelector && !hasChildren && el.parentNode && typeof document !== "undefined") {
1430
+ const markerId = `_ds_${storeName}_${templateSelector.replace(/[^a-z0-9]/gi, "_")}`;
1431
+ let wrapper = document.querySelector(`[data-ds-wired="${markerId}"]`);
1432
+ if (!wrapper) {
1433
+ wrapper = document.createElement("div");
1434
+ wrapper.setAttribute("data-rt-bind", `store/${storeName}`);
1435
+ wrapper.setAttribute("data-rt-template", templateSelector);
1436
+ wrapper.setAttribute("data-ds-wired", markerId);
1437
+ el.parentNode.insertBefore(wrapper, el.nextSibling);
1438
+ }
1439
+ if (typeof this._updateDOM === "function") {
1440
+ this.uiStores = this.uiStores || /* @__PURE__ */ new Map();
1441
+ const currentStore = this.uiStores.get(storeName) || {};
1442
+ this._updateDOM(`store/${storeName}`, currentStore);
1443
+ }
1444
+ }
1445
+ if (hasChildren && typeof this._updateDOM === "function") {
1446
+ this.uiStores = this.uiStores || /* @__PURE__ */ new Map();
1447
+ const currentStore = this.uiStores.get(storeName) || {};
1448
+ this._updateDOM(`store/${storeName}`, currentStore);
1449
+ }
1450
+ });
1384
1451
  const writeEls = document.querySelectorAll("[data-store-write]");
1385
1452
  writeEls.forEach((el) => {
1386
1453
  const writeBind = el.getAttribute("data-store-write");
@@ -2786,6 +2853,32 @@ var DolphinModule = (() => {
2786
2853
  }
2787
2854
 
2788
2855
  // src/testing.ts
2856
+ function createMockFn() {
2857
+ if (typeof jest !== "undefined" && typeof jest.fn === "function") {
2858
+ return jest.fn();
2859
+ }
2860
+ const fn = (...args) => {
2861
+ fn.mock.calls.push(args);
2862
+ if (fn._implementation) {
2863
+ return fn._implementation(...args);
2864
+ }
2865
+ return fn._returnValue;
2866
+ };
2867
+ fn.mock = {
2868
+ calls: []
2869
+ };
2870
+ fn._returnValue = void 0;
2871
+ fn._implementation = null;
2872
+ fn.mockReturnValue = (val) => {
2873
+ fn._returnValue = val;
2874
+ return fn;
2875
+ };
2876
+ fn.mockImplementation = (impl) => {
2877
+ fn._implementation = impl;
2878
+ return fn;
2879
+ };
2880
+ return fn;
2881
+ }
2789
2882
  var DolphinTestUtils = class {
2790
2883
  static render(html) {
2791
2884
  if (typeof document === "undefined") {
@@ -2812,11 +2905,11 @@ var DolphinModule = (() => {
2812
2905
  send: (data) => {
2813
2906
  sentMessages.push(data);
2814
2907
  },
2815
- close: jest.fn(),
2816
- onopen: jest.fn(),
2817
- onmessage: jest.fn(),
2818
- onclose: jest.fn(),
2819
- onerror: jest.fn(),
2908
+ close: createMockFn(),
2909
+ onopen: createMockFn(),
2910
+ onmessage: createMockFn(),
2911
+ onclose: createMockFn(),
2912
+ onerror: createMockFn(),
2820
2913
  sentMessages
2821
2914
  };
2822
2915
  global.WebSocket = class {
@@ -2851,8 +2944,8 @@ var DolphinModule = (() => {
2851
2944
  static simulateClick(el) {
2852
2945
  const clickEvt = {
2853
2946
  target: el,
2854
- preventDefault: jest.fn(),
2855
- stopPropagation: jest.fn()
2947
+ preventDefault: createMockFn(),
2948
+ stopPropagation: createMockFn()
2856
2949
  };
2857
2950
  const clickListeners = global.document._listeners?.["click"] || [];
2858
2951
  clickListeners.forEach((listener) => listener(clickEvt));
@@ -2861,8 +2954,8 @@ var DolphinModule = (() => {
2861
2954
  el.value = value;
2862
2955
  const changeEvt = {
2863
2956
  target: el,
2864
- preventDefault: jest.fn(),
2865
- stopPropagation: jest.fn()
2957
+ preventDefault: createMockFn(),
2958
+ stopPropagation: createMockFn()
2866
2959
  };
2867
2960
  const changeListeners = global.document._listeners?.["change"] || [];
2868
2961
  changeListeners.forEach((listener) => listener(changeEvt));
@@ -1,29 +1,29 @@
1
- var DolphinModule=(()=>{var q=Object.defineProperty;var et=Object.getOwnPropertyDescriptor;var nt=Object.getOwnPropertyNames;var st=Object.prototype.hasOwnProperty;var it=(_,t)=>{for(var e in t)q(_,e,{get:t[e],enumerable:!0})},rt=(_,t,e,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of nt(t))!st.call(_,i)&&i!==e&&q(_,i,{get:()=>t[i],enumerable:!(n=et(t,i))||n.enumerable});return _};var ot=_=>rt(q({},"__esModule",{value:!0}),_);var ct={};it(ct,{DolphinClient:()=>x});var I=class{client;constructor(t){return this.client=t,this._createProxy([])}_createProxy(t){let e=t.join("/"),n=r=>this.request("GET",e,null,r);n.get=(r,a)=>typeof r=="string"?this.request("GET",r,null,a):this.request("GET",e,null,r),n.post=(r,a,h)=>typeof r=="string"?this.request("POST",r,a,h):this.request("POST",e,r,a),n.put=(r,a,h)=>typeof r=="string"?this.request("PUT",r,a,h):this.request("PUT",e,r,a),n.patch=(r,a,h)=>typeof r=="string"?this.request("PATCH",r,a,h):this.request("PATCH",e,r,a),n.del=(r,a)=>typeof r=="string"?this.request("DELETE",r,null,a):this.request("DELETE",e,null,r),n.request=(r,a,h,T)=>{let E=a?e?`${e}/${a.startsWith("/")?a.slice(1):a}`:a:e;return this.request(r,E,h,T)},n.requestDirect=(r,a,h,T)=>this.requestDirect(r,a,h,T),n._findCSRFToken=()=>this._findCSRFToken(),n._resolveBaseUrl=r=>this._resolveBaseUrl(r),n._normalizeValidationErrors=r=>this._normalizeValidationErrors(r);let i=["get","post","put","patch","del","request","requestDirect","_findCSRFToken","_resolveBaseUrl","_normalizeValidationErrors"];return new Proxy(n,{get:(r,a)=>typeof a=="string"&&!i.includes(a)?this._createProxy([...t,a]):r[a]})}_findCSRFToken(){if(typeof document>"u")return null;let t=["csrf-token","_csrf","xsrf-token","csrf_token"];for(let r of t){let a=document.querySelector(`meta[name="${r}"], meta[content][name$="${r}"]`);if(a){let h=a.getAttribute("content");if(h)return h}}let e=["_csrfToken","_token","_csrf","csrf_token"];for(let r of e){let a=document.querySelector(`input[type="hidden"][name="${r}"]`);if(a&&a.value)return a.value}let n=["csrfToken","XSRF-TOKEN","_csrf","csrf_token"];for(let r of n){let a=document.cookie.match(new RegExp("(^|;\\s*)"+r+"=([^;]*)"));if(a)return decodeURIComponent(a[2])}let i=typeof window<"u"&&window.wpApiSettings?.nonce;return i||null}_resolveBaseUrl(t){if(t.startsWith("http://")||t.startsWith("https://"))return t;let e=this.client.httpUrl;if(typeof document<"u"){let i=document.querySelector("base[href]");if(i){let r=i.getAttribute("href")||"";if(r&&r!=="/"){let a=r.endsWith("/")?r.slice(0,-1):r;e=`${this.client.httpUrl}${a.startsWith("/")?a:"/"+a}`}}else{let r=document.querySelector('meta[name="base-path"]');if(r){let a=r.getAttribute("content")||"";if(a&&a!=="/"){let h=a.endsWith("/")?a.slice(0,-1):a;e=`${this.client.httpUrl}${h.startsWith("/")?h:"/"+h}`}}}}let n=t.startsWith("/")?t:"/"+t;return`${e}${n}`}_normalizeValidationErrors(t){let e={};if(!t||typeof t!="object")return e;let n=t.errors||t.validationErrors||t;if(Array.isArray(n)){for(let i of n)if(i&&typeof i=="object"){let r=i.path||i.param||i.field||i.property,a=i.msg||i.message||i.error;r&&a&&(e[r]=Array.isArray(a)?a[0]:a)}return e}if(typeof n=="object"&&n!==null)for(let i in n){let r=n[i];if(r)if(Array.isArray(r))r.length>0&&(e[i]=String(r[0]));else if(typeof r=="object"){let a=Object.keys(r);if(a.length>0){let h=a[0];e[i]=String(r[h])}}else e[i]=String(r)}return e}async request(t,e,n=null,i={}){if(this.client.offline){let r=this.client.offline.isOnline,a=`${t.toUpperCase()}:${e}`;if(t.toUpperCase()==="GET")if(r)try{let h=await this.requestDirect(t,e,n,i);return await this.client.offline.setCache(a,h),h}catch(h){let T=await this.client.offline.getCache(a);if(T!=null)return T;throw h}else{let h=await this.client.offline.getCache(a);if(h!=null)return h;throw{status:503,data:{error:"Offline, no cache available"}}}else return r?this.requestDirect(t,e,n,i):(await this.client.offline.queueMutation(t,e,n),this.client._dispatch("offline:queued",{method:t,path:e,body:n}),{success:!0,offline:!0,message:"Mutation queued offline"})}return this.requestDirect(t,e,n,i)}async requestDirect(t,e,n=null,i={}){let r=i._isRetry===!0,a=t.toUpperCase(),h=n,E={...!["GET","HEAD"].includes(a)?{"Content-Type":"application/json"}:{},...i.headers||{}};["PUT","PATCH","DELETE"].includes(a)&&(this.client.options.methodSpoofing||i.methodSpoofing)&&(E["X-HTTP-Method-Override"]=a,h instanceof FormData?h.append("_method",a):h&&typeof h=="object"?h={...h,_method:a}:h||(h={_method:a}),a="POST");let D=this._resolveBaseUrl(e);this.client.options.debug&&console.log("%c\u{1F680} [Dolphin API Request]:","color: #3b82f6; font-weight: bold;",t.toUpperCase(),e,h||"");let k=new AbortController,M=setTimeout(()=>k.abort(),this.client.options.timeout);if(this.client.accessToken&&(E.Authorization=`Bearer ${this.client.accessToken}`),["POST","PUT","PATCH","DELETE"].includes(t.toUpperCase())){let d=this._findCSRFToken();d&&(E["X-CSRF-Token"]=d,E["X-XSRF-TOKEN"]=d,E["X-CSRFToken"]=d,E["X-WP-Nonce"]=d,h&&typeof h=="object"&&!h._csrfToken&&!h._token&&!h._csrf&&(h={...h,_csrfToken:d,_token:d,_csrf:d}))}let $={...i};delete $._isRetry,delete $.methodSpoofing;try{let d=await fetch(D,{method:a,headers:E,signal:k.signal,...h?{body:JSON.stringify(h)}:{},...$});if(clearTimeout(M),d.status===401&&!r&&this.client.options.autoRefreshToken&&await this.client.auth._silentRefresh())return this.request(t,e,n,{...i,_isRetry:!0});let l=(d.headers.get("content-type")||"").includes("application/json")?await d.json():await d.text();if(!d.ok)throw{status:d.status,data:l};if(this.client.options.debug&&console.log("%c\u2705 [Dolphin API Success]:","color: #10b981; font-weight: bold;",t.toUpperCase(),e,l),l&&typeof l=="object"&&l.accessToken&&(this.client.setToken(l.accessToken),l.user&&(this.client.auth.user=l.user)),this.client.options.autoBroadcast&&["POST","PUT","PATCH","DELETE"].includes(t.toUpperCase())){let s=e.startsWith("/")?e.substring(1):e;this.client.publish(s,{method:t.toUpperCase(),payload:n,result:l})}return l}catch(d){if(clearTimeout(M),this.client.options.debug&&console.error("%c\u274C [Dolphin API Error]:","color: #ef4444; font-weight: bold;",t.toUpperCase(),e,d),d&&typeof d=="object"&&d.data){let f=this._normalizeValidationErrors(d.data);if(Object.keys(f).length>0)for(let l in f)this.client.publish(`errors/${l}`,f[l])}throw d.name==="AbortError"?{status:408,data:{error:"Request timed out"}}:d}}};var R=class{client;user;_refreshing;constructor(t){this.client=t,this.user=null,this._refreshing=!1}async login(t,e){let n=await this.client.api.post("/api/auth/login",{email:t,password:e});return n.accessToken&&(this.client.setToken(n.accessToken),this.user=n.user||null),n}async register(t){return this.client.api.post("/api/auth/register",t)}async me(){let t=await this.client.api.get("/api/auth/me");return t.success&&(this.user=t.data),t}async logout(){try{await this.client.api.post("/api/auth/logout")}catch{}this.client.setToken(null),this.user=null}async refresh(){return this._silentRefresh()}async _silentRefresh(){if(this._refreshing)return!1;this._refreshing=!0;try{let t=await this.client.api.post("/api/auth/refresh",null,{_isRetry:!0});return t.accessToken?(this.client.setToken(t.accessToken),!0):!1}catch{return this.client.setToken(null),!1}finally{this._refreshing=!1}}async verify2FA(t,e){let n={code:t,email:e||this.user?.email},i=await this.client.api.post("/api/auth/2fa/verify",n);return i.accessToken&&(this.client.setToken(i.accessToken),i.user&&(this.user=i.user)),i}async enable2FA(){return this.client.api.post("/api/auth/2fa/enable")}async disable2FA(t){return this.client.api.post("/api/auth/2fa/disable",{code:t})}async forgotPassword(t){return this.client.api.post("/api/auth/forgot-password",{email:t})}async resetPassword(t,e){return this.client.api.post("/api/auth/reset-password",{token:t,newPassword:e})}};var N=class{client;data;listeners;subscribed;_unsubscribers;constructor(t){return this.client=t,this.data=new Map,this.listeners=new Set,this.subscribed=new Set,this._unsubscribers=new Map,new Proxy(this,{get:(e,n)=>{if(n in e)return e[n];if(typeof n=="string")return this._getCollection(n)}})}_getCollection(t){if(!this.data.has(t)){let e={_rawItems:[],items:[],loading:!0,error:null,success:!1,_filter:null,_sort:null,where:n=>(e._filter=n,this._applyTransform(e),e),orderBy:(n,i="asc")=>(e._sort={key:n,direction:i},this._applyTransform(e),e),reset:()=>(e._filter=null,e._sort=null,this._applyTransform(e),e)};this.data.set(t,e),this._fetchAndSync(t)}return this.data.get(t)}async _fetchAndSync(t){let e=this.data.get(t);try{let n=await this.client.api.get(`/${t.toLowerCase()}`);if(e._rawItems=Array.isArray(n)?n:n.data||[],e.loading=!1,e.success=!0,e.error=null,this._applyTransform(e),!this.subscribed.has(t)){let i=()=>this.client.unsubscribe(`db:sync/${t.toLowerCase()}`,r),r=a=>{this._handleRemoteUpdate(t,a)};this.client.subscribe(`db:sync/${t.toLowerCase()}`,r),this._unsubscribers.set(t,i),this.subscribed.add(t)}}catch(n){e.loading=!1,e.success=!1,e.error=n.data?.error||n.message||"Fetch failed",this._notify()}}_applyTransform(t){let e=[...t._rawItems];if(t._filter&&(e=e.filter(t._filter)),t._sort){let{key:n,direction:i}=t._sort;e.sort((r,a)=>r[n]===a[n]?0:(r[n]>a[n]?1:-1)*(i==="asc"?1:-1))}t.items=e,this._notify()}_handleRemoteUpdate(t,e){let n=this.data.get(t);if(!n)return;let{type:i,data:r}=e,a=n._rawItems;i==="create"?a=[...a,r]:i==="update"?a=a.map(h=>h.id===r.id||h._id===r._id?{...h,...r}:h):i==="delete"&&(a=a.filter(h=>!(r.id!=null&&h.id===r.id||r._id!=null&&h._id===r._id))),n._rawItems=a,this._applyTransform(n)}subscribe(t){return this.listeners.add(t),()=>this.listeners.delete(t)}getSnapshot(t){return this.data.get(t)||{items:[],loading:!1,error:null,success:!1}}_notify(){this.listeners.forEach(t=>t())}destroy(){this._unsubscribers.forEach(t=>{try{t()}catch{}}),this._unsubscribers.clear(),this.subscribed.clear(),this.listeners.clear(),this.data.clear()}};var x=class{host;httpUrl;deviceId;options;socket;storage;accessToken;api;auth;store;handlers;signalHandlers;fileHandlers;_offlineQueue;reconnectAttempts;_reconnectTimer;_attachedListeners;constructor(t="",e="",n={}){!t&&typeof window<"u"&&(t=window.location.host);let i="http:";t.startsWith("https://")?i="https:":t.startsWith("http://")?i="http:":typeof window<"u"&&(i=window.location.protocol),this.host=(t||"localhost").replace(/\/$/,"").replace(/^https?:\/\//,""),this.httpUrl=`${i}//${this.host}`,this.deviceId=e||(typeof crypto<"u"&&typeof crypto.randomUUID=="function"?"web_"+crypto.randomUUID().replace(/-/g,"").slice(0,8):"web_"+Math.random().toString(36).slice(2,10)),this.options={timeout:15e3,chunkSize:65536,maxReconnect:5,autoRefreshToken:!0,debug:!1,methodSpoofing:!1,routerViewport:"main, #viewport, body",routerTransitions:!0,...n},this.socket=null,this.storage=typeof localStorage<"u"?localStorage:{getItem:()=>null,setItem:()=>{},removeItem:()=>{}},this.accessToken=this.storage.getItem("dolphin_token"),this.api=new I(this),this.auth=new R(this),this.store=new N(this),this.handlers=new Map,this.signalHandlers=new Set,this.fileHandlers=new Set,this._offlineQueue=[],this.reconnectAttempts=0,this._reconnectTimer=null,this._attachedListeners=[],typeof window<"u"&&typeof this._initDOMBinding=="function"&&this._initDOMBinding(),typeof this._initOffline=="function"&&this._initOffline(),typeof this._initA11y=="function"&&this._initA11y(),typeof this._initI18n=="function"&&this._initI18n(),typeof this._initDragDrop=="function"&&this._initDragDrop(),typeof this._initCollab=="function"&&this._initCollab()}setToken(t){this.accessToken=t,t?this.storage.setItem("dolphin_token",t):this.storage.removeItem("dolphin_token")}async connect(){return this.socket&&(this.socket.readyState===WebSocket.OPEN||this.socket.readyState===WebSocket.CONNECTING)?Promise.resolve():new Promise((t,e)=>{let i=`${this.httpUrl.startsWith("https")?"wss:":"ws:"}//${this.host}/realtime?deviceId=${this.deviceId}`;console.log(`[Dolphin] Connecting to ${i}...`),this.socket=new WebSocket(i),this.socket.onopen=()=>{console.log(`[Dolphin] Connected as "${this.deviceId}" \u{1F42C}`),this.reconnectAttempts=0,this._flushOfflineQueue(),t()},this.socket.onmessage=r=>this._handleMessage(r.data),this.socket.onclose=()=>{console.warn("[Dolphin] Connection closed"),this._maybeReconnect()},this.socket.onerror=r=>{console.error("[Dolphin] WebSocket error:",r),e(r)}})}disconnect(){this._reconnectTimer!==null&&(clearTimeout(this._reconnectTimer),this._reconnectTimer=null),this.socket&&(this.socket.onclose=null,this.socket.close(),this.socket=null),typeof this._collabCleanup=="function"&&this._collabCleanup(),this.cleanupDomListeners()}_handleMessage(t){try{let e=JSON.parse(t);this.options.debug&&console.log("%c\u{1F4E5} [Dolphin WS Incoming]:","color: #eab308; font-weight: bold;",e),e.type&&e.from&&(e.to===this.deviceId||e.to==="all")&&(e.msgId&&e.type!=="ACK"&&this._sendAck(e.from,e.msgId),this.signalHandlers.forEach(n=>n(e))),e.type==="FILE_AVAILABLE"&&this.fileHandlers.forEach(n=>n(e)),e.type==="FILE_CHUNK"&&(this.saveFileProgress(e.fileId,e.chunkIndex),this._dispatch("file:chunk",e),this._dispatch(`file:chunk/${e.fileId}`,e)),e.type==="FILE_UPLOAD_ACK"&&this._dispatch(`file:upload:ack/${e.fileId}`,e),e.type==="PULL_RESPONSE"&&(this._dispatch("pull:response",e.payload,e.topic),this._dispatch(`pull:response/${e.topic}`,e.payload,e.topic)),e.topic&&e.payload!==void 0&&this.handlers.forEach((n,i)=>{this._matchTopic(i,e.topic)&&n.forEach(r=>r(e.payload,e.topic))})}catch{this._dispatch("raw",t)}}_dispatch(t,e,n){let i=this.handlers.get(t);i&&i.forEach(r=>r(e,n||t))}_sendRaw(t){this.options.debug&&console.log("%c\u{1F4E4} [Dolphin WS Outgoing]:","color: #8b5cf6; font-weight: bold;",t);let e=typeof t=="string"?t:JSON.stringify(t);this.socket&&this.socket.readyState===WebSocket.OPEN?this.socket.send(e):this._offlineQueue.length<100&&this._offlineQueue.push(e)}_flushOfflineQueue(){for(;this._offlineQueue.length>0;){let t=this._offlineQueue.shift();this.socket&&this.socket.readyState===WebSocket.OPEN&&this.socket.send(t)}}_sendAck(t,e){this._sendRaw({type:"ACK",from:this.deviceId,to:t,data:{ackId:e},timestamp:Date.now()})}_matchTopic(t,e){if(t===e||t==="#")return!0;let n=t.split("/"),i=e.split("/");if(n.length!==i.length&&!t.includes("#"))return!1;for(let r=0;r<n.length;r++){if(n[r]==="#")return!0;if(n[r]!=="+"&&n[r]!==i[r])return!1}return n.length===i.length}_maybeReconnect(){if(this.reconnectAttempts<this.options.maxReconnect){this.reconnectAttempts++;let t=Math.pow(2,this.reconnectAttempts)*1e3;console.log(`[Dolphin] Reconnecting in ${t/1e3}s (attempt ${this.reconnectAttempts})...`),this._reconnectTimer=setTimeout(()=>{this._reconnectTimer=null,this.connect().catch(()=>{})},t)}else console.error("[Dolphin] Max reconnect attempts reached.")}subscribe(t,e){this.handlers.has(t)||(this.handlers.set(t,new Set),this._sendRaw({type:"sub",topic:t})),this.handlers.get(t).add(e)}unsubscribe(t,e){if(this.handlers.has(t)){let n=this.handlers.get(t);n.delete(e),n.size===0&&(this.handlers.delete(t),this._sendRaw({type:"unsub",topic:t}))}}publish(t,e){this._sendRaw({topic:t,payload:e})}pubPush(t,e){this._sendRaw({type:"pub",topic:t,payload:e})}subPull(t,e=10){this._sendRaw({type:"PULL_REQUEST",topic:t,count:e})}async pubFile(t,e,n="",i){let r;e instanceof Blob?r=await e.arrayBuffer():e instanceof ArrayBuffer?r=e:r=e.buffer||e;let a=new Uint8Array(r),h=this.options.chunkSize,T=Math.ceil(a.length/h);this._sendRaw({type:"FILE_UPLOAD_START",fileId:t,name:n,size:a.length,totalChunks:T,chunkSize:h});for(let E=0;E<T;E++){let D=a.slice(E*h,(E+1)*h),k=this._uint8ToBase64(D);this._sendRaw({type:"FILE_UPLOAD_CHUNK",fileId:t,chunkIndex:E,totalChunks:T,data:k}),i&&i(Math.round((E+1)/T*100)),E%10===0&&await new Promise(M=>setTimeout(M,0))}this._sendRaw({type:"FILE_UPLOAD_DONE",fileId:t})}_uint8ToBase64(t){let e="";for(let n=0;n<t.length;n++)e+=String.fromCharCode(t[n]);return typeof btoa<"u"?btoa(e):Buffer.from(e,"binary").toString("base64")}subFile(t,e=0){this._sendRaw({type:"FILE_REQUEST",fileId:t,startChunk:e})}resumeFile(t){let e=parseInt(this.storage.getItem(`dolphin_file_${t}`)||"-1");this.subFile(t,e+1)}saveFileProgress(t,e){this.storage.setItem(`dolphin_file_${t}`,e.toString())}onSignal(t){this.signalHandlers.add(t)}offSignal(t){this.signalHandlers.delete(t)}onFileAvailable(t){this.fileHandlers.add(t)}offFileAvailable(t){this.fileHandlers.delete(t)}addDomListener(t,e,n){t&&(t.addEventListener(e,n),this._attachedListeners=this._attachedListeners||[],this._attachedListeners.push({target:t,event:e,cb:n}))}cleanupDomListeners(){this._attachedListeners&&(this._attachedListeners.forEach(({target:t,event:e,cb:n})=>{try{t.removeEventListener(e,n)}catch{}}),this._attachedListeners=[])}};function W(_){let t=new Map;function e(d){return d.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function n(d,f){if(!(!f||typeof f!="object"))try{let l=new Proxy(f,{has(o,c){return!0},get(o,c){if(typeof c=="string"){if(c in o)return o[c];if(typeof globalThis<"u"&&c in globalThis)return globalThis[c];if(typeof window<"u"&&c in window)return window[c]}}});return new Function("ctx",`with(ctx) { return (${d}); }`)(l)}catch{return f[d]}}function i(d,f){let l=[],s="",o=!1,c=!1,p=!1,u=0;for(let b=0;b<d.length;b++){let g=d[b];g==="'"&&!c&&!p?o=!o:g==='"'&&!o&&!p?c=!c:g==="`"&&!o&&!c?p=!p:g==="("||g==="["||g==="{"?!o&&!c&&!p&&u++:(g===")"||g==="]"||g==="}")&&!o&&!c&&!p&&u--,g===f&&!o&&!c&&!p&&u===0?(l.push(s),s=""):s+=g}return l.push(s),l}function r(d){let f=!1,l=!1,s=!1,o=0;for(let c=0;c<d.length;c++){let p=d[c];if(p==="'"&&!l&&!s?f=!f:p==='"'&&!f&&!s?l=!l:p==="`"&&!f&&!l?s=!s:p==="("||p==="["||p==="{"?!f&&!l&&!s&&o++:(p===")"||p==="]"||p==="}")&&!f&&!l&&!s&&o--,p===":"&&!f&&!l&&!s&&o===0)return[d.slice(0,c),d.slice(c+1)]}return null}function a(d){let f=d.getAttribute("data-rt-template");if(!f)return null;if(typeof document<"u"&&!f.includes("<"))try{let l=document.querySelector(f);if(l)return l.innerHTML}catch{}return f}function h(d,f){if(!d.includes("{#if")&&!d.includes("{#each")){let l=d;for(let s in f){let o=s.replace(/[.*+?^$${}()|[\]\\]/g,"\\$&");l=l.replace(new RegExp("\\{\\{"+o+"\\}}","g"),f[s]!==void 0&&f[s]!==null?f[s]:"")}return l=l.replace(/\{\{([\s\S]*?)\}\}/g,(s,o)=>{let c=o.trim();if(!c)return"";if(/^[a-zA-Z_$][a-zA-Z0-9_$]*(?:\??\.[a-zA-Z_$][a-zA-Z0-9_$]*)+$/.test(c)){let p=c.split(/\??\./),u=f;for(let b of p){if(u==null){u=void 0;break}u=u[b]}return u??""}return s}),l}try{let l=y=>y.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/\t/g,"\\t"),s=`let out = "";
2
- `,o=0,c=/(\{\{([\s\S]*?)\}\}|\{#if\s+([\s\S]*?)\}|\{:else\s+if\s+([\s\S]*?)\}|\{:else\}|\{\/if\}|\{#each\s+([\s\S]*?)\s+as\s+([a-zA-Z_$][a-zA-Z0-9_$]*)(?:\s*,\s*([a-zA-Z_$][a-zA-Z0-9_$]*))?\}|\{\/each\}|\{([^{}]+?)\})/g,p=[],u;for(;(u=c.exec(d))!==null;){let y=d.slice(o,u.index);y&&(s+=`out += "${l(y)}";
3
- `);let w=u[0];if(w.startsWith("{{")){let S=u[2];s+=`out += (${S} !== undefined && ${S} !== null ? ${S} : "");
4
- `}else if(w.startsWith("{#if")){let S=u[3];s+=`if (${S}) {
5
- `}else if(w.startsWith("{:else if")){let S=u[4];s+=`} else if (${S}) {
6
- `}else if(w.startsWith("{:else}"))s+=`} else {
7
- `;else if(w.startsWith("{/if}"))s+=`}
8
- `;else if(w.startsWith("{#each")){let S=u[5],C=u[6],v=u[7];p.push({indexVar:v}),s+=`if (typeof ${S} !== "undefined" && ${S} !== null && Array.isArray(${S})) {
9
- `,v&&(s+=` let ${v} = 0;
10
- `),s+=` for (let ${C} of ${S}) {
11
- `}else if(w.startsWith("{/each}")){let S=p.pop();S&&S.indexVar&&(s+=` ${S.indexVar}++;
12
- `),s+=` }
1
+ var DolphinModule=(()=>{var U=Object.defineProperty;var nt=Object.getOwnPropertyDescriptor;var it=Object.getOwnPropertyNames;var st=Object.prototype.hasOwnProperty;var rt=(w,t)=>{for(var e in t)U(w,e,{get:t[e],enumerable:!0})},ot=(w,t,e,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of it(t))!st.call(w,s)&&s!==e&&U(w,s,{get:()=>t[s],enumerable:!(i=nt(t,s))||i.enumerable});return w};var at=w=>ot(U({},"__esModule",{value:!0}),w);var lt={};rt(lt,{DolphinClient:()=>$});var N=class{client;constructor(t){return this.client=t,this._createProxy([])}_createProxy(t){let e=t.join("/"),i=r=>this.request("GET",e,null,r);i.get=(r,a)=>typeof r=="string"?this.request("GET",r,null,a):this.request("GET",e,null,r),i.post=(r,a,y)=>typeof r=="string"?this.request("POST",r,a,y):this.request("POST",e,r,a),i.put=(r,a,y)=>typeof r=="string"?this.request("PUT",r,a,y):this.request("PUT",e,r,a),i.patch=(r,a,y)=>typeof r=="string"?this.request("PATCH",r,a,y):this.request("PATCH",e,r,a),i.del=(r,a)=>typeof r=="string"?this.request("DELETE",r,null,a):this.request("DELETE",e,null,r),i.request=(r,a,y,T)=>{let E=a?e?`${e}/${a.startsWith("/")?a.slice(1):a}`:a:e;return this.request(r,E,y,T)},i.requestDirect=(r,a,y,T)=>this.requestDirect(r,a,y,T),i._findCSRFToken=()=>this._findCSRFToken(),i._resolveBaseUrl=r=>this._resolveBaseUrl(r),i._normalizeValidationErrors=r=>this._normalizeValidationErrors(r);let s=["get","post","put","patch","del","request","requestDirect","_findCSRFToken","_resolveBaseUrl","_normalizeValidationErrors"];return new Proxy(i,{get:(r,a)=>typeof a=="string"&&!s.includes(a)?this._createProxy([...t,a]):r[a]})}_findCSRFToken(){if(typeof document>"u")return null;let t=["csrf-token","_csrf","xsrf-token","csrf_token"];for(let r of t){let a=document.querySelector(`meta[name="${r}"], meta[content][name$="${r}"]`);if(a){let y=a.getAttribute("content");if(y)return y}}let e=["_csrfToken","_token","_csrf","csrf_token"];for(let r of e){let a=document.querySelector(`input[type="hidden"][name="${r}"]`);if(a&&a.value)return a.value}let i=["csrfToken","XSRF-TOKEN","_csrf","csrf_token"];for(let r of i){let a=document.cookie.match(new RegExp("(^|;\\s*)"+r+"=([^;]*)"));if(a)return decodeURIComponent(a[2])}let s=typeof window<"u"&&window.wpApiSettings?.nonce;return s||null}_resolveBaseUrl(t){if(t.startsWith("http://")||t.startsWith("https://"))return t;let e=this.client.httpUrl;if(typeof document<"u"){let s=document.querySelector("base[href]");if(s){let r=s.getAttribute("href")||"";if(r&&r!=="/"){let a=r.endsWith("/")?r.slice(0,-1):r;e=`${this.client.httpUrl}${a.startsWith("/")?a:"/"+a}`}}else{let r=document.querySelector('meta[name="base-path"]');if(r){let a=r.getAttribute("content")||"";if(a&&a!=="/"){let y=a.endsWith("/")?a.slice(0,-1):a;e=`${this.client.httpUrl}${y.startsWith("/")?y:"/"+y}`}}}}let i=t.startsWith("/")?t:"/"+t;return`${e}${i}`}_normalizeValidationErrors(t){let e={};if(!t||typeof t!="object")return e;let i=t.errors||t.validationErrors||t;if(Array.isArray(i)){for(let s of i)if(s&&typeof s=="object"){let r=s.path||s.param||s.field||s.property,a=s.msg||s.message||s.error;r&&a&&(e[r]=Array.isArray(a)?a[0]:a)}return e}if(typeof i=="object"&&i!==null)for(let s in i){let r=i[s];if(r)if(Array.isArray(r))r.length>0&&(e[s]=String(r[0]));else if(typeof r=="object"){let a=Object.keys(r);if(a.length>0){let y=a[0];e[s]=String(r[y])}}else e[s]=String(r)}return e}async request(t,e,i=null,s={}){if(this.client.offline){let r=this.client.offline.isOnline,a=`${t.toUpperCase()}:${e}`;if(t.toUpperCase()==="GET")if(r)try{let y=await this.requestDirect(t,e,i,s);return await this.client.offline.setCache(a,y),y}catch(y){let T=await this.client.offline.getCache(a);if(T!=null)return T;throw y}else{let y=await this.client.offline.getCache(a);if(y!=null)return y;throw{status:503,data:{error:"Offline, no cache available"}}}else return r?this.requestDirect(t,e,i,s):(await this.client.offline.queueMutation(t,e,i),this.client._dispatch("offline:queued",{method:t,path:e,body:i}),{success:!0,offline:!0,message:"Mutation queued offline"})}return this.requestDirect(t,e,i,s)}async requestDirect(t,e,i=null,s={}){let r=s._isRetry===!0,a=t.toUpperCase(),y=i,E={...!["GET","HEAD"].includes(a)?{"Content-Type":"application/json"}:{},...s.headers||{}};["PUT","PATCH","DELETE"].includes(a)&&(this.client.options.methodSpoofing||s.methodSpoofing)&&(E["X-HTTP-Method-Override"]=a,y instanceof FormData?y.append("_method",a):y&&typeof y=="object"?y={...y,_method:a}:y||(y={_method:a}),a="POST");let D=this._resolveBaseUrl(e);this.client.options.debug&&console.log("%c\u{1F680} [Dolphin API Request]:","color: #3b82f6; font-weight: bold;",t.toUpperCase(),e,y||"");let k=new AbortController,M=setTimeout(()=>k.abort(),this.client.options.timeout);if(this.client.accessToken&&(E.Authorization=`Bearer ${this.client.accessToken}`),["POST","PUT","PATCH","DELETE"].includes(t.toUpperCase())){let h=this._findCSRFToken();h&&(E["X-CSRF-Token"]=h,E["X-XSRF-TOKEN"]=h,E["X-CSRFToken"]=h,E["X-WP-Nonce"]=h,y&&typeof y=="object"&&!y._csrfToken&&!y._token&&!y._csrf&&(y={...y,_csrfToken:h,_token:h,_csrf:h}))}let x={...s};delete x._isRetry,delete x.methodSpoofing;try{let h=await fetch(D,{method:a,headers:E,signal:k.signal,...y?{body:JSON.stringify(y)}:{},...x});if(clearTimeout(M),h.status===401&&!r&&this.client.options.autoRefreshToken&&await this.client.auth._silentRefresh())return this.request(t,e,i,{...s,_isRetry:!0});let f=(h.headers.get("content-type")||"").includes("application/json")?await h.json():await h.text();if(!h.ok)throw{status:h.status,data:f};if(this.client.options.debug&&console.log("%c\u2705 [Dolphin API Success]:","color: #10b981; font-weight: bold;",t.toUpperCase(),e,f),f&&typeof f=="object"&&f.accessToken&&(this.client.setToken(f.accessToken),f.user&&(this.client.auth.user=f.user)),this.client.options.autoBroadcast&&["POST","PUT","PATCH","DELETE"].includes(t.toUpperCase())){let n=e.startsWith("/")?e.substring(1):e;this.client.publish(n,{method:t.toUpperCase(),payload:i,result:f})}return f}catch(h){if(clearTimeout(M),this.client.options.debug&&console.error("%c\u274C [Dolphin API Error]:","color: #ef4444; font-weight: bold;",t.toUpperCase(),e,h),h&&typeof h=="object"&&h.data){let d=this._normalizeValidationErrors(h.data);if(Object.keys(d).length>0)for(let f in d)this.client.publish(`errors/${f}`,d[f])}throw h.name==="AbortError"?{status:408,data:{error:"Request timed out"}}:h}}};var R=class{client;user;_refreshing;constructor(t){this.client=t,this.user=null,this._refreshing=!1}async login(t,e){let i=await this.client.api.post("/api/auth/login",{email:t,password:e});return i.accessToken&&(this.client.setToken(i.accessToken),this.user=i.user||null),i}async register(t){return this.client.api.post("/api/auth/register",t)}async me(){let t=await this.client.api.get("/api/auth/me");return t.success&&(this.user=t.data),t}async logout(){try{await this.client.api.post("/api/auth/logout")}catch{}this.client.setToken(null),this.user=null}async refresh(){return this._silentRefresh()}async _silentRefresh(){if(this._refreshing)return!1;this._refreshing=!0;try{let t=await this.client.api.post("/api/auth/refresh",null,{_isRetry:!0});return t.accessToken?(this.client.setToken(t.accessToken),!0):!1}catch{return this.client.setToken(null),!1}finally{this._refreshing=!1}}async verify2FA(t,e){let i={code:t,email:e||this.user?.email},s=await this.client.api.post("/api/auth/2fa/verify",i);return s.accessToken&&(this.client.setToken(s.accessToken),s.user&&(this.user=s.user)),s}async enable2FA(){return this.client.api.post("/api/auth/2fa/enable")}async disable2FA(t){return this.client.api.post("/api/auth/2fa/disable",{code:t})}async forgotPassword(t){return this.client.api.post("/api/auth/forgot-password",{email:t})}async resetPassword(t,e){return this.client.api.post("/api/auth/reset-password",{token:t,newPassword:e})}};var O=class{client;data;listeners;subscribed;_unsubscribers;constructor(t){return this.client=t,this.data=new Map,this.listeners=new Set,this.subscribed=new Set,this._unsubscribers=new Map,new Proxy(this,{get:(e,i)=>{if(i in e)return e[i];if(typeof i=="string")return this._getCollection(i)}})}_getCollection(t){if(!this.data.has(t)){let e={_rawItems:[],items:[],loading:!0,error:null,success:!1,_filter:null,_sort:null,where:i=>(e._filter=i,this._applyTransform(e),e),orderBy:(i,s="asc")=>(e._sort={key:i,direction:s},this._applyTransform(e),e),reset:()=>(e._filter=null,e._sort=null,this._applyTransform(e),e)};this.data.set(t,e),this._fetchAndSync(t)}return this.data.get(t)}async _fetchAndSync(t){let e=this.data.get(t);try{let i=await this.client.api.get(`/${t.toLowerCase()}`);if(e._rawItems=Array.isArray(i)?i:i.data||[],e.loading=!1,e.success=!0,e.error=null,this._applyTransform(e),!this.subscribed.has(t)){let s=()=>this.client.unsubscribe(`db:sync/${t.toLowerCase()}`,r),r=a=>{this._handleRemoteUpdate(t,a)};this.client.subscribe(`db:sync/${t.toLowerCase()}`,r),this._unsubscribers.set(t,s),this.subscribed.add(t)}}catch(i){e.loading=!1,e.success=!1,e.error=i.data?.error||i.message||"Fetch failed",this._notify()}}_applyTransform(t){let e=[...t._rawItems];if(t._filter&&(e=e.filter(t._filter)),t._sort){let{key:i,direction:s}=t._sort;e.sort((r,a)=>r[i]===a[i]?0:(r[i]>a[i]?1:-1)*(s==="asc"?1:-1))}t.items=e,this._notify()}_handleRemoteUpdate(t,e){let i=this.data.get(t);if(!i)return;let{type:s,data:r}=e,a=i._rawItems;s==="create"?a=[...a,r]:s==="update"?a=a.map(y=>y.id===r.id||y._id===r._id?{...y,...r}:y):s==="delete"&&(a=a.filter(y=>!(r.id!=null&&y.id===r.id||r._id!=null&&y._id===r._id))),i._rawItems=a,this._applyTransform(i)}subscribe(t){return this.listeners.add(t),()=>this.listeners.delete(t)}getSnapshot(t){return this.data.get(t)||{items:[],loading:!1,error:null,success:!1}}_notify(){this.listeners.forEach(t=>t())}destroy(){this._unsubscribers.forEach(t=>{try{t()}catch{}}),this._unsubscribers.clear(),this.subscribed.clear(),this.listeners.clear(),this.data.clear()}};var $=class{host;httpUrl;deviceId;options;socket;storage;accessToken;api;auth;store;handlers;signalHandlers;fileHandlers;_offlineQueue;reconnectAttempts;_reconnectTimer;_attachedListeners;constructor(t="",e="",i={}){!t&&typeof window<"u"&&(t=window.location.host);let s="http:";t.startsWith("https://")?s="https:":t.startsWith("http://")?s="http:":typeof window<"u"&&(s=window.location.protocol),this.host=(t||"localhost").replace(/\/$/,"").replace(/^https?:\/\//,""),this.httpUrl=`${s}//${this.host}`,this.deviceId=e||(typeof crypto<"u"&&typeof crypto.randomUUID=="function"?"web_"+crypto.randomUUID().replace(/-/g,"").slice(0,8):"web_"+Math.random().toString(36).slice(2,10)),this.options={timeout:15e3,chunkSize:65536,maxReconnect:5,autoRefreshToken:!0,debug:!1,methodSpoofing:!1,routerViewport:"main, #viewport, body",routerTransitions:!0,...i},this.socket=null,this.storage=typeof localStorage<"u"?localStorage:{getItem:()=>null,setItem:()=>{},removeItem:()=>{}},this.accessToken=this.storage.getItem("dolphin_token"),this.api=new N(this),this.auth=new R(this),this.store=new O(this),this.handlers=new Map,this.signalHandlers=new Set,this.fileHandlers=new Set,this._offlineQueue=[],this.reconnectAttempts=0,this._reconnectTimer=null,this._attachedListeners=[],typeof window<"u"&&typeof this._initDOMBinding=="function"&&this._initDOMBinding(),typeof this._initOffline=="function"&&this._initOffline(),typeof this._initA11y=="function"&&this._initA11y(),typeof this._initI18n=="function"&&this._initI18n(),typeof this._initDragDrop=="function"&&this._initDragDrop(),typeof this._initCollab=="function"&&this._initCollab()}setToken(t){this.accessToken=t,t?this.storage.setItem("dolphin_token",t):this.storage.removeItem("dolphin_token")}async connect(){return this.socket&&(this.socket.readyState===WebSocket.OPEN||this.socket.readyState===WebSocket.CONNECTING)?Promise.resolve():new Promise((t,e)=>{let s=`${this.httpUrl.startsWith("https")?"wss:":"ws:"}//${this.host}/realtime?deviceId=${this.deviceId}`;console.log(`[Dolphin] Connecting to ${s}...`),this.socket=new WebSocket(s),this.socket.onopen=()=>{console.log(`[Dolphin] Connected as "${this.deviceId}" \u{1F42C}`),this.reconnectAttempts=0,this._flushOfflineQueue(),t()},this.socket.onmessage=r=>this._handleMessage(r.data),this.socket.onclose=()=>{console.warn("[Dolphin] Connection closed"),this._maybeReconnect()},this.socket.onerror=r=>{console.error("[Dolphin] WebSocket error:",r),e(r)}})}disconnect(){this._reconnectTimer!==null&&(clearTimeout(this._reconnectTimer),this._reconnectTimer=null),this.socket&&(this.socket.onclose=null,this.socket.close(),this.socket=null),typeof this._collabCleanup=="function"&&this._collabCleanup(),this.cleanupDomListeners()}_handleMessage(t){try{let e=JSON.parse(t);this.options.debug&&console.log("%c\u{1F4E5} [Dolphin WS Incoming]:","color: #eab308; font-weight: bold;",e),e.type&&e.from&&(e.to===this.deviceId||e.to==="all")&&(e.msgId&&e.type!=="ACK"&&this._sendAck(e.from,e.msgId),this.signalHandlers.forEach(i=>i(e))),e.type==="FILE_AVAILABLE"&&this.fileHandlers.forEach(i=>i(e)),e.type==="FILE_CHUNK"&&(this.saveFileProgress(e.fileId,e.chunkIndex),this._dispatch("file:chunk",e),this._dispatch(`file:chunk/${e.fileId}`,e)),e.type==="FILE_UPLOAD_ACK"&&this._dispatch(`file:upload:ack/${e.fileId}`,e),e.type==="PULL_RESPONSE"&&(this._dispatch("pull:response",e.payload,e.topic),this._dispatch(`pull:response/${e.topic}`,e.payload,e.topic)),e.topic&&e.payload!==void 0&&this.handlers.forEach((i,s)=>{this._matchTopic(s,e.topic)&&i.forEach(r=>r(e.payload,e.topic))})}catch{this._dispatch("raw",t)}}_dispatch(t,e,i){let s=this.handlers.get(t);s&&s.forEach(r=>r(e,i||t))}_sendRaw(t){this.options.debug&&console.log("%c\u{1F4E4} [Dolphin WS Outgoing]:","color: #8b5cf6; font-weight: bold;",t);let e=typeof t=="string"?t:JSON.stringify(t);this.socket&&this.socket.readyState===WebSocket.OPEN?this.socket.send(e):this._offlineQueue.length<100&&this._offlineQueue.push(e)}_flushOfflineQueue(){for(;this._offlineQueue.length>0;){let t=this._offlineQueue.shift();this.socket&&this.socket.readyState===WebSocket.OPEN&&this.socket.send(t)}}_sendAck(t,e){this._sendRaw({type:"ACK",from:this.deviceId,to:t,data:{ackId:e},timestamp:Date.now()})}_matchTopic(t,e){if(t===e||t==="#")return!0;let i=t.split("/"),s=e.split("/");if(i.length!==s.length&&!t.includes("#"))return!1;for(let r=0;r<i.length;r++){if(i[r]==="#")return!0;if(i[r]!=="+"&&i[r]!==s[r])return!1}return i.length===s.length}_maybeReconnect(){if(this.reconnectAttempts<this.options.maxReconnect){this.reconnectAttempts++;let t=Math.pow(2,this.reconnectAttempts)*1e3;console.log(`[Dolphin] Reconnecting in ${t/1e3}s (attempt ${this.reconnectAttempts})...`),this._reconnectTimer=setTimeout(()=>{this._reconnectTimer=null,this.connect().catch(()=>{})},t)}else console.error("[Dolphin] Max reconnect attempts reached.")}subscribe(t,e){this.handlers.has(t)||(this.handlers.set(t,new Set),this._sendRaw({type:"sub",topic:t})),this.handlers.get(t).add(e)}unsubscribe(t,e){if(this.handlers.has(t)){let i=this.handlers.get(t);i.delete(e),i.size===0&&(this.handlers.delete(t),this._sendRaw({type:"unsub",topic:t}))}}publish(t,e){this._sendRaw({topic:t,payload:e})}pubPush(t,e){this._sendRaw({type:"pub",topic:t,payload:e})}subPull(t,e=10){this._sendRaw({type:"PULL_REQUEST",topic:t,count:e})}async pubFile(t,e,i="",s){let r;e instanceof Blob?r=await e.arrayBuffer():e instanceof ArrayBuffer?r=e:r=e.buffer||e;let a=new Uint8Array(r),y=this.options.chunkSize,T=Math.ceil(a.length/y);this._sendRaw({type:"FILE_UPLOAD_START",fileId:t,name:i,size:a.length,totalChunks:T,chunkSize:y});for(let E=0;E<T;E++){let D=a.slice(E*y,(E+1)*y),k=this._uint8ToBase64(D);this._sendRaw({type:"FILE_UPLOAD_CHUNK",fileId:t,chunkIndex:E,totalChunks:T,data:k}),s&&s(Math.round((E+1)/T*100)),E%10===0&&await new Promise(M=>setTimeout(M,0))}this._sendRaw({type:"FILE_UPLOAD_DONE",fileId:t})}_uint8ToBase64(t){let e="";for(let i=0;i<t.length;i++)e+=String.fromCharCode(t[i]);return typeof btoa<"u"?btoa(e):Buffer.from(e,"binary").toString("base64")}subFile(t,e=0){this._sendRaw({type:"FILE_REQUEST",fileId:t,startChunk:e})}resumeFile(t){let e=parseInt(this.storage.getItem(`dolphin_file_${t}`)||"-1");this.subFile(t,e+1)}saveFileProgress(t,e){this.storage.setItem(`dolphin_file_${t}`,e.toString())}onSignal(t){this.signalHandlers.add(t)}offSignal(t){this.signalHandlers.delete(t)}onFileAvailable(t){this.fileHandlers.add(t)}offFileAvailable(t){this.fileHandlers.delete(t)}addDomListener(t,e,i){t&&(t.addEventListener(e,i),this._attachedListeners=this._attachedListeners||[],this._attachedListeners.push({target:t,event:e,cb:i}))}cleanupDomListeners(){this._attachedListeners&&(this._attachedListeners.forEach(({target:t,event:e,cb:i})=>{try{t.removeEventListener(e,i)}catch{}}),this._attachedListeners=[])}};function B(w){let t=new Map;function e(h){return h.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function i(h,d){if(!(!d||typeof d!="object"))try{let f=new Proxy(d,{has(o,c){return!0},get(o,c){if(typeof c=="string"){if(c in o)return o[c];if(typeof globalThis<"u"&&c in globalThis)return globalThis[c];if(typeof window<"u"&&c in window)return window[c]}}});return new Function("ctx",`with(ctx) { return (${h}); }`)(f)}catch{return d[h]}}function s(h,d){let f=[],n="",o=!1,c=!1,p=!1,l=0;for(let g=0;g<h.length;g++){let u=h[g];u==="'"&&!c&&!p?o=!o:u==='"'&&!o&&!p?c=!c:u==="`"&&!o&&!c?p=!p:u==="("||u==="["||u==="{"?!o&&!c&&!p&&l++:(u===")"||u==="]"||u==="}")&&!o&&!c&&!p&&l--,u===d&&!o&&!c&&!p&&l===0?(f.push(n),n=""):n+=u}return f.push(n),f}function r(h){let d=!1,f=!1,n=!1,o=0;for(let c=0;c<h.length;c++){let p=h[c];if(p==="'"&&!f&&!n?d=!d:p==='"'&&!d&&!n?f=!f:p==="`"&&!d&&!f?n=!n:p==="("||p==="["||p==="{"?!d&&!f&&!n&&o++:(p===")"||p==="]"||p==="}")&&!d&&!f&&!n&&o--,p===":"&&!d&&!f&&!n&&o===0)return[h.slice(0,c),h.slice(c+1)]}return null}function a(h){let d=h.getAttribute("data-rt-template");if(!d)return null;if(typeof document<"u"&&!d.includes("<"))try{let f=document.querySelector(d);if(f)return f.innerHTML}catch{}return d}function y(h,d){if(!h.includes("{#if")&&!h.includes("{#each")){let f=h;for(let n in d){let o=n.replace(/[.*+?^$${}()|[\]\\]/g,"\\$&");f=f.replace(new RegExp("\\{\\{"+o+"\\}}","g"),d[n]!==void 0&&d[n]!==null?d[n]:"")}return f=f.replace(/\{\{([\s\S]*?)\}\}/g,(n,o)=>{let c=o.trim();if(!c)return"";if(/^[a-zA-Z_$][a-zA-Z0-9_$]*(?:\??\.[a-zA-Z_$][a-zA-Z0-9_$]*)+$/.test(c)){let p=c.split(/\??\./),l=d;for(let g of p){if(l==null){l=void 0;break}l=l[g]}return l??""}return n}),f}try{let f=m=>m.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/\t/g,"\\t"),n=`let out = "";
2
+ `,o=0,c=/(\{\{([\s\S]*?)\}\}|\{#if\s+([\s\S]*?)\}|\{:else\s+if\s+([\s\S]*?)\}|\{:else\}|\{\/if\}|\{#each\s+([\s\S]*?)\s+as\s+([a-zA-Z_$][a-zA-Z0-9_$]*)(?:\s*,\s*([a-zA-Z_$][a-zA-Z0-9_$]*))?\}|\{\/each\}|\{([^{}]+?)\})/g,p=[],l;for(;(l=c.exec(h))!==null;){let m=h.slice(o,l.index);m&&(n+=`out += "${f(m)}";
3
+ `);let _=l[0];if(_.startsWith("{{")){let S=l[2];n+=`out += (${S} !== undefined && ${S} !== null ? ${S} : "");
4
+ `}else if(_.startsWith("{#if")){let S=l[3];n+=`if (${S}) {
5
+ `}else if(_.startsWith("{:else if")){let S=l[4];n+=`} else if (${S}) {
6
+ `}else if(_.startsWith("{:else}"))n+=`} else {
7
+ `;else if(_.startsWith("{/if}"))n+=`}
8
+ `;else if(_.startsWith("{#each")){let S=l[5],C=l[6],v=l[7];p.push({indexVar:v}),n+=`if (typeof ${S} !== "undefined" && ${S} !== null && Array.isArray(${S})) {
9
+ `,v&&(n+=` let ${v} = 0;
10
+ `),n+=` for (let ${C} of ${S}) {
11
+ `}else if(_.startsWith("{/each}")){let S=p.pop();S&&S.indexVar&&(n+=` ${S.indexVar}++;
12
+ `),n+=` }
13
13
  }
14
- `}else if(w.startsWith("{")){let S=u[8];S&&(s+=`out += (${S} !== undefined && ${S} !== null ? ${S} : "");
15
- `)}o=c.lastIndex}let b=d.slice(o);b&&(s+=`out += "${l(b)}";
16
- `),s+=`return out;
17
- `;let g=`
14
+ `}else if(_.startsWith("{")){let S=l[8];S&&(n+=`out += (${S} !== undefined && ${S} !== null ? ${S} : "");
15
+ `)}o=c.lastIndex}let g=h.slice(o);g&&(n+=`out += "${f(g)}";
16
+ `),n+=`return out;
17
+ `;let u=`
18
18
  with (context) {
19
19
  try {
20
- ${s}
20
+ ${n}
21
21
  } catch (innerErr) {
22
22
  console.warn('[Dolphin Template Eval Warning]:', innerErr);
23
23
  return '';
24
24
  }
25
25
  }
26
- `,A=f;return typeof Proxy<"u"&&f!==null&&typeof f=="object"&&(A=new Proxy(f,{has(y,w){return typeof w!="symbol"},get(y,w){if(w!==Symbol.unscopables){if(w in y)return y[w];if(typeof globalThis<"u"&&w in globalThis)return globalThis[w];if(typeof window<"u"&&w in window)return window[w]}}})),new Function("context",g)(A)}catch(l){console.error("[Dolphin Template Compiler Error]:",l);let s=d;for(let o in f){let c=o.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");s=s.replace(new RegExp(`\\{\\{${c}\\}\\}`,"g"),f[o]!==void 0&&f[o]!==null?f[o]:"")}return s}}function T(d){if(typeof document>"u")return d;try{let f=new DOMParser,s=/<\s*(?:body|html)\b/i.test(d)?d:`<body>${d}</body>`,c=f.parseFromString(s,"text/html").body,p=u=>{let b=u.tagName.toLowerCase();if(["script","iframe","object","embed","link","style","meta","applet","svg"].includes(b)){u.parentNode?.removeChild(u);return}let g=u.attributes;for(let A=g.length-1;A>=0;A--){let m=g[A].name.toLowerCase(),y=g[A].value.toLowerCase();(m.startsWith("on")||["src","href","data"].includes(m)&&(y.includes("javascript:")||y.includes("data:text/html")))&&u.removeAttribute(g[A].name)}Array.from(u.children).forEach(p)};return Array.from(c.children).forEach(p),c.innerHTML}catch{return d}}function E(d,f){if(d.nodeType!==f.nodeType){d.parentNode?.replaceChild(f.cloneNode(!0),d);return}if(d.nodeType===Node.TEXT_NODE){d.textContent!==f.textContent&&(d.textContent=f.textContent);return}if(d.nodeType===Node.ELEMENT_NODE){let l=d,s=f;if(l.tagName!==s.tagName){l.parentNode?.replaceChild(s.cloneNode(!0),l);return}let o=l.attributes,c=s.attributes;for(let m=o.length-1;m>=0;m--){let y=o[m].name;s.hasAttribute(y)||l.removeAttribute(y)}for(let m=0;m<c.length;m++){let y=c[m].name,w=c[m].value;l.getAttribute(y)!==w&&l.setAttribute(y,w)}l.tagName==="INPUT"||l.tagName==="TEXTAREA"?(l.value!==s.value&&(l.value=s.value),l.checked!==s.checked&&(l.checked=s.checked)):l.tagName==="SELECT"&&l.value!==s.value&&(l.value=s.value);let p=Array.from(l.childNodes),u=Array.from(s.childNodes),b=p.length,g=u.length,A=Math.max(b,g);for(let m=0;m<A;m++)m>=b?l.appendChild(u[m].cloneNode(!0)):m>=g?l.removeChild(p[m]):E(p[m],u[m])}}function D(d,f){if(typeof document>"u")return;let l=document.createElement(d.tagName);l.innerHTML=f;let s=Array.from(d.childNodes),o=Array.from(l.childNodes),c=s.length,p=o.length,u=Math.max(c,p);for(let b=0;b<u;b++)b>=c?d.appendChild(o[b].cloneNode(!0)):b>=p?d.removeChild(s[b]):E(s[b],o[b])}let k=new Map,M=!1;function $(d,f){k.set(d,f),M||(M=!0,(typeof requestAnimationFrame<"u"?requestAnimationFrame:s=>setTimeout(s,0))(()=>{k.forEach((s,o)=>{o.isConnected!==!1&&D(o,s)}),k.clear(),M=!1}))}_.setStoreState=function(d,f,l,s){this.uiStores=this.uiStores||new Map,this.uiStores.has(d)||this.uiStores.set(d,{});let o=this.uiStores.get(d);o[f]=l,this.options.debug&&console.log("%c\u{1F4BE} [Dolphin Store Update]:","color: #ec4899; font-weight: bold;",`${d}.${f}`,"=",l),typeof document<"u"&&document.querySelectorAll(`[data-store-read="${d}.${f}"]`).forEach(p=>{p!==s&&(p.tagName==="INPUT"||p.tagName==="TEXTAREA"?p.type==="checkbox"?p.checked=!!l:p.value=l??"":p.textContent=l??"")}),this.publish(`store/${d}`,o),typeof this._updateDOM=="function"&&this._updateDOM(`store/${d}`,o)},_.getStoreState=function(d,f){this.uiStores=this.uiStores||new Map;let l=this.uiStores.get(d);return l?l[f]:void 0},_._scanStoreBinds=function(){if(typeof document>"u")return;document.querySelectorAll("[data-store-write]").forEach(l=>{let s=l.getAttribute("data-store-write");if(s){let o=s.split(".");if(o.length===2){let c=o[0],p=o[1],u=l.type==="checkbox"?l.checked:l.value;this.uiStores=this.uiStores||new Map,this.uiStores.has(c)||this.uiStores.set(c,{});let b=this.uiStores.get(c);b[p]===void 0&&(b[p]=u)}}}),document.querySelectorAll("[data-store-read]").forEach(l=>{let s=l.getAttribute("data-store-read");if(s){let o=s.split(".");if(o.length===2){let c=o[0],p=o[1],u=this.getStoreState(c,p);u!=null&&(l.tagName==="INPUT"||l.tagName==="TEXTAREA"?l.type==="checkbox"?l.checked=!!u:l.value=u:l.textContent=u)}}})},_.getClosestContext=function(d,f){let l=d;for(;l;){if(l._rtContext){let s=l._rtContext;return f?s[f]:s}l=l.parentElement||l.parentNode}return null},_._executeStoreAction=function(d,f){this.uiStores=this.uiStores||new Map;let l=f&&typeof this.getClosestContext=="function"?this.getClosestContext(f):null,s=new Proxy({},{has:(o,c)=>!0,get:(o,c)=>{if(typeof c=="string")return c==="log"?p=>{if(p===void 0){let u={};this.uiStores.forEach((b,g)=>{u[g]={...b}}),console.log("%c\u{1F4CA} [Dolphin All UI Stores]:","color: #06b6d4; font-weight: bold;",u)}else if(p&&typeof p=="object"&&p.__isStoreProxy__){let u=p.__storeName__,b=this.uiStores.get(u);console.log(`%c\u{1F4CA} [Dolphin Store: ${u}]:`,"color: #06b6d4; font-weight: bold;",b?{...b}:{})}else console.log("%c\u{1F4CA} [Dolphin Log]:","color: #06b6d4; font-weight: bold;",p)}:l&&l[c]!==void 0?l[c]:typeof globalThis<"u"&&c in globalThis?globalThis[c]:typeof window<"u"&&c in window?window[c]:new Proxy({},{get:(p,u)=>{if(u==="__storeName__")return c;if(u==="__isStoreProxy__")return!0;if(typeof u=="string")return this.getStoreState(c,u)},set:(p,u,b)=>typeof u=="string"?(this.setStoreState(c,u,b),!0):!1})}});try{new Function("ctx",`with(ctx) { ${d} }`)(s)}catch(o){console.error("%c[Dolphin Store Action Error]:","color: #ef4444; font-weight: bold;",o),f&&console.error("%cFailed Element:","color: #f97316; font-weight: bold;",f),console.error("%cFailed Expression:","color: #3b82f6; font-style: italic;",d)}},_._initDOMBinding=function(){if(this._domInitialized)return;this._domInitialized=!0;let d=["input","change","keyup","paste","blur"],f=new WeakMap;d.forEach(s=>{this.addDomListener(document,s,o=>{if(!o.target||!o.target.getAttribute)return;let c=o.target.getAttribute("data-store-write");if(c){let g=c.split(".");if(g.length===2){let A=g[0],m=g[1],y=o.target.type==="checkbox"?o.target.checked:o.target.value;this.setStoreState(A,m,y,o.target)}}let p=o.target.getAttribute("data-rt-validate"),u=o.target.name;if(p&&u&&typeof this.validateField=="function"){let g=o.target.closest("form"),A=g?Object.fromEntries(new FormData(g).entries()):{},m=this.validateField(o.target.value,p,A);m?(o.target.classList.add("invalid"),this.publish(`errors/${u}`,m)):(o.target.classList.remove("invalid"),this.publish(`errors/${u}`,""))}let b=o.target.getAttribute("data-rt-push");if(b){let g=o.target.getAttribute("data-rt-debounce"),A=g?parseInt(g,10):0,m=()=>{let y={name:o.target.name,value:o.target.value};this.pubPush(b,y)};if(A>0){f.has(o.target)&&clearTimeout(f.get(o.target));let y=setTimeout(m,A);f.set(o.target,y)}else m()}})}),this.addDomListener(document,"submit",async s=>{if(!s.target||!s.target.getAttribute)return;let o=s.target.getAttribute("data-rt-submit"),c=s.target.getAttribute("data-api-submit");if(o||c){s.target.querySelectorAll("[name]").forEach(y=>{let w=y.name;w&&(this.publish(`errors/${w}`,""),y.classList.remove("invalid"))});let u=s.target.querySelectorAll("[data-rt-validate]"),b=!0;if(u.length>0&&typeof this.validateField=="function"){let y=Object.fromEntries(new FormData(s.target).entries());u.forEach(w=>{let S=w.getAttribute("data-rt-validate"),C=w.name;if(S&&C){let v=this.validateField(w.value,S,y);v&&(b=!1,w.classList.add("invalid"),this.publish(`errors/${C}`,v))}})}if(!b){s.preventDefault(),s.stopPropagation();return}s.preventDefault();let g=this.getClosestContext(s.target)||{},A=new FormData(s.target),m=Object.fromEntries(A.entries());if(o){let y=o;for(let w in g){let S=e(w);y=y.replace(new RegExp(`\\{\\{${S}\\}\\}`,"g"),g[w]!==void 0&&g[w]!==null?g[w]:"")}this.publish(y,m)}else if(c){let y=c;for(let v in g){let L=e(v);y=y.replace(new RegExp(`\\{\\{${L}\\}\\}`,"g"),g[v]!==void 0&&g[v]!==null?g[v]:"")}let w=y.trim().split(" "),S=w.length>1?w[0].toUpperCase():"POST",C=w.length>1?w[1]:w[0];m._method&&(S=String(m._method).toUpperCase());try{let v=await this.api.request(S,C,m),L=s.target.getAttribute("data-api-result");L&&this._updateDOM(L,v);let P=s.target.getAttribute("data-api-redirect");P&&(window.location.href=P),s.target.hasAttribute("data-api-reload")&&window.location.reload()}catch(v){console.error("[Dolphin] API Submit Error:",v)}}}}),["click","change","submit","input","keydown","keyup","dblclick","focus","blur","mouseenter","mouseleave"].forEach(s=>{this.addDomListener(document,s,async o=>{if(!o.target||!o.target.closest)return;let c=o.target.closest(`[data-rt-${s}]`),p=o.target.closest(`[data-api-${s}]`);if(c){s==="submit"&&o.preventDefault();let b=c.getAttribute(`data-rt-${s}`),g=c.getAttribute("data-rt-payload"),A=this.getClosestContext(c)||{},m={};if(g){let y=g;for(let w in A){let S=e(w);y=y.replace(new RegExp(`\\{\\{${S}\\}\\}`,"g"),A[w]!==void 0&&A[w]!==null?A[w]:"")}try{m=JSON.parse(y)}catch{m={}}}this.publish(b,m)}if(p){s==="submit"&&o.preventDefault();let b=p.getAttribute(`data-api-${s}`),g=p.getAttribute("data-api-payload"),A=this.getClosestContext(p)||{},m=b.trim().split(" "),y=m.length>1?m[0].toUpperCase():"POST",w=m.length>1?m[1]:m[0],S=null;if(g){let C=g;for(let v in A){let L=e(v);C=C.replace(new RegExp(`\\{\\{${L}\\}\\}`,"g"),A[v]!==void 0&&A[v]!==null?A[v]:"")}try{S=JSON.parse(C)}catch{S=null}}try{let C=await this.api.request(y,w,S),v=p.getAttribute("data-api-result");v&&this._updateDOM(v,C);let L=p.getAttribute("data-api-redirect");L&&(window.location.href=L),p.hasAttribute("data-api-reload")&&window.location.reload()}catch(C){console.error(`[Dolphin] API ${s} Error:`,C)}}let u=o.target.closest(`[data-store-${s}]`);if(u){s==="submit"&&o.preventDefault();let b=u.getAttribute(`data-store-${s}`);b&&this._executeStoreAction(b,u)}})}),this.subscribe("#",(s,o)=>{this._updateDOM(o,s)}),this._scanAndFetchAPIBinds(),this._scanStoreBinds(),this._resolveImports(),this._initSPARouter()},_._scanAndFetchAPIBinds=async function(){if(typeof document>"u")return;let d=document.querySelectorAll("[data-api-get]");for(let f of Array.from(d)){let l=f.getAttribute("data-api-get");if(l&&!(typeof f.hasAttribute=="function"&&f.hasAttribute("data-api-initialized"))){typeof f.setAttribute=="function"&&f.setAttribute("data-api-initialized","true");try{let s=await this.api.get(l),o=f.getAttribute("data-api-store");if(o){let p=o.split(".");p.length===2&&this.setStoreState(p[0],p[1],s)}let c=f.getAttribute("data-rt-bind");if(c&&!o)this._updateDOM(c,s);else if(!o){let p=a(f);if(p&&typeof s=="object"&&s!==null){let u=this._applyDeclarativeDirectives(f,s);if(Array.isArray(u)){let b="";for(let g of u)b+=h(p,g);$(f,b)}else $(f,h(p,u))}else if(f.tagName==="INPUT"||f.tagName==="TEXTAREA")f.value=typeof s=="object"?s.value!==void 0?s.value:"":s;else{let u=typeof s=="object"?s.html||s.text||JSON.stringify(s):String(s);f.innerHTML=T(u)}}}catch(s){console.error("[Dolphin] API Get Error:",s)}}}},_._applyDeclarativeDirectives=function(d,f){let l=f;if(typeof f=="object"&&f!==null){let s=o=>{let c=[...o],p=d.getAttribute("data-rt-filter");if(p){let g=p.split("==");if(g.length===2){let A=g[0].trim(),m=g[1].trim(),y,w=m.split(".");w.length===2?y=this.getStoreState(w[0],w[1]):y=f[m]!==void 0?f[m]:this.getStoreState("app",m),y!=null&&y!==""&&(c=c.filter(S=>S[A]===y))}}let u=d.getAttribute("data-rt-search");if(u){let g=u.split("==");if(g.length===2){let A=g[0].trim(),m=g[1].trim(),y,w=m.split(".");if(w.length===2?y=this.getStoreState(w[0],w[1]):y=f[m]!==void 0?f[m]:this.getStoreState("app",m),y!=null&&y!==""){let S=String(y).toLowerCase();c=c.filter(C=>{let v=C[A];return v!=null&&String(v).toLowerCase().includes(S)})}}}let b=d.getAttribute("data-rt-sort");if(b){let g,A=b.split(".");if(A.length===2?g=this.getStoreState(A[0],A[1]):g=f[b]!==void 0?f[b]:this.getStoreState("app",b),g&&g!=="")if(g==="popular")c.sort((m,y)=>{let w=m.rating?.rate||m.rate||0;return(y.rating?.rate||y.rate||0)-w});else{let m="",y="asc";g.endsWith("-low")||g.endsWith("-asc")?(m=g.replace("-low","").replace("-asc",""),y="asc"):(g.endsWith("-high")||g.endsWith("-desc"))&&(m=g.replace("-high","").replace("-desc",""),y="desc"),m&&c.sort((w,S)=>{let C=(G,Y)=>Y.split(".").reduce((F,tt)=>F&&F[tt],G),v=C(w,m),L=C(S,m);if(v===void 0&&(v=w[m]),L===void 0&&(L=S[m]),typeof v=="string"&&typeof L=="string")return y==="asc"?v.localeCompare(L):L.localeCompare(v);let P=Number(v),O=Number(L);return!isNaN(P)&&!isNaN(O)?y==="asc"?P-O:O-P:0})}}return c};if(Array.isArray(f))l=s(f);else{let o="";for(let c in f)if(Array.isArray(f[c])){o=c;break}if(o){let c=s(f[o]);l={...f,[o]:c}}}}return l},_._updateDOM=function(d,f){if(typeof document>"u")return;document.querySelectorAll(`[data-rt-bind="${d}"]`).forEach(s=>{let o=this._applyDeclarativeDirectives(s,f);if(s.getAttribute("data-rt-type")==="context"&&typeof o=="object"&&o!==null){s._rtContext=o;let p=u=>{if(u.hasAttribute("data-rt-text")){let b=u.getAttribute("data-rt-text");if(b){let g=n(b,o);g!=null&&(u.textContent=g)}}if(u.hasAttribute("data-rt-html")){let b=u.getAttribute("data-rt-html");if(b){let g=n(b,o);g!=null&&(u.innerHTML=T(g))}}if(u.hasAttribute("data-rt-attr")){let b=u.getAttribute("data-rt-attr");b&&i(b,",").forEach(g=>{let A=r(g);if(A){let m=A[0].trim(),y=A[1].trim();if(m&&y){let w=n(y,o);w!=null&&u.setAttribute(m,w)}}})}if(u.hasAttribute("data-rt-class")){let b=u.getAttribute("data-rt-class");b&&i(b,",").forEach(g=>{let A=r(g);if(A){let m=A[0].trim(),y=A[1].trim(),w=m.split(/\s+/).filter(Boolean);n(y,o)?w.forEach(S=>u.classList.add(S)):w.forEach(S=>u.classList.remove(S))}})}if(u.hasAttribute("data-rt-if")){let b=u.getAttribute("data-rt-if");b&&(n(b,o)?u.style.display="":u.style.display="none")}if(u.hasAttribute("data-rt-hide")){let b=u.getAttribute("data-rt-hide");b&&(n(b,o)?u.style.display="none":u.style.display="")}};p(s),s.querySelectorAll("[data-rt-text], [data-rt-html], [data-rt-attr], [data-rt-class], [data-rt-if], [data-rt-hide]").forEach(p);return}let c=a(s);if(c&&typeof o=="object"&&o!==null){if(Array.isArray(o)){let p="";for(let u of o)p+=h(c,u);$(s,p)}else $(s,h(c,o));return}if(s.tagName==="INPUT"||s.tagName==="TEXTAREA")s.value=typeof o=="object"?o.value!==void 0?o.value:"":o;else if(c)s.innerHTML=typeof o=="object"?o.html||o.text||JSON.stringify(o):String(o);else{let p=typeof o=="object"?o.html||o.text||JSON.stringify(o):String(o);s.innerHTML=T(p)}})},_._resolveImports=async function(d){if(typeof document>"u")return;let f=d||document.body||document;if(!f||typeof f.querySelectorAll!="function")return;let l=f.querySelectorAll("[data-import]");if(l.length===0)return;let s=async(c,p)=>{let u=c.getAttribute("data-import");if(!u)return;if(p.has(u)){console.warn(`[Dolphin Component Warning]: Circular import detected for "${u}". Skipping resolving.`),c.innerHTML=`<span style="color:red;font-weight:bold;">Circular import: ${u}</span>`;return}p.add(u);let b=u.indexOf("#"),g=b!==-1?u.substring(0,b):u,A=b!==-1?u.substring(b):null,m=t.get(g);m||(m=fetch(g).then(S=>{if(!S.ok)throw new Error(`HTTP ${S.status}`);return S.text()}),m.catch(()=>t.delete(g)),t.set(g,m));let y="";try{if(y=await m,A&&typeof DOMParser<"u"){let v=new DOMParser().parseFromString(y,"text/html").querySelector(A);v?y=v.outerHTML:(console.warn(`[Dolphin Component Warning]: Selector "${A}" not found in imported file "${g}".`),y=`<span style="color:orange;font-weight:bold;">Selector ${A} not found in ${g}</span>`)}}catch(S){console.error(`[Dolphin Component Error]: Failed to fetch component "${g}":`,S),y=`<span style="color:red;font-weight:bold;">Failed to import ${g}</span>`}c.innerHTML=T(y),c.removeAttribute("data-import");let w=c.querySelectorAll("[data-import]");if(w.length>0){let S=Array.from(w).map(C=>s(C,new Set(p)));await Promise.all(S)}this._scanStoreBinds(),this._scanAndFetchAPIBinds()},o=Array.from(l).map(c=>s(c,new Set));await Promise.all(o)},_._initSPARouter=function(){if(typeof window>"u"||typeof document>"u"||this._routerInitialized)return;this._routerInitialized=!0;let d=null,f=()=>{let o=(this.options.routerViewport||"main, #viewport, body").split(",").map(c=>c.trim());for(let c of o){let p=document.querySelector(c);if(p)return p}return document.body},l=async(s,o=!0)=>{try{this.options.debug&&console.log(`%c\u{1F6E3}\uFE0F [Dolphin Router]: Navigating to ${s}...`,"color: #3b82f6; font-weight: bold;"),d&&d.abort(),d=new AbortController;let c=d.signal,p=f();this.options.routerTransitions&&p&&(p.classList.add("dolphin-fade-out"),await new Promise(w=>setTimeout(w,150)));let u=await fetch(s,{signal:c});if(!u.ok)throw new Error(`HTTP ${u.status}`);let b=await u.text();d=null;let A=new DOMParser().parseFromString(b,"text/html");A.title&&(document.title=A.title);let m=A.querySelector(this.options.routerViewport||"main, #viewport, body"),y=f();m&&y?(y.innerHTML=m.innerHTML,Array.from(m.attributes).forEach(w=>{y.setAttribute(w.name,w.value)})):y&&(y.innerHTML=A.body.innerHTML),o&&window.history.pushState({dolphinSpa:!0,url:s},"",s),this.options.routerTransitions&&y&&(y.classList.remove("dolphin-fade-out"),y.classList.add("dolphin-fade-in"),setTimeout(()=>y.classList.remove("dolphin-fade-in"),300)),await this._resolveImports(y),this._scanStoreBinds(),this._scanAndFetchAPIBinds()}catch(c){if(c&&c.name==="AbortError")return;console.error("[Dolphin Router Error]: Failed to route page:",c),window.location.href=s}};if(this.addDomListener(document,"click",s=>{let o=s.target.closest("a");if(!o||!o.hasAttribute("data-spa")&&o.getAttribute("data-spa")!=="true")return;let c=o.getAttribute("href");!c||c.startsWith("#")||c.startsWith("javascript:")||c.startsWith("mailto:")||c.startsWith("tel:")||new URL(c,window.location.href).origin!==window.location.origin||(s.preventDefault(),l(c))}),this.addDomListener(window,"popstate",s=>{s.state&&s.state.dolphinSpa?l(s.state.url,!1):s.state===null&&l(window.location.pathname,!1)}),this.options.routerTransitions){let s=document.createElement("style");s.innerHTML=`
26
+ `,A=d;return typeof Proxy<"u"&&d!==null&&typeof d=="object"&&(A=new Proxy(d,{has(m,_){return typeof _!="symbol"},get(m,_){if(_!==Symbol.unscopables){if(_ in m)return m[_];if(typeof globalThis<"u"&&_ in globalThis)return globalThis[_];if(typeof window<"u"&&_ in window)return window[_]}}})),new Function("context",u)(A)}catch(f){console.error("[Dolphin Template Compiler Error]:",f);let n=h;for(let o in d){let c=o.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");n=n.replace(new RegExp(`\\{\\{${c}\\}\\}`,"g"),d[o]!==void 0&&d[o]!==null?d[o]:"")}return n}}function T(h){if(typeof document>"u")return h;try{let d=new DOMParser,n=/<\s*(?:body|html)\b/i.test(h)?h:`<body>${h}</body>`,c=d.parseFromString(n,"text/html").body,p=l=>{let g=l.tagName.toLowerCase();if(["script","iframe","object","embed","link","style","meta","applet","svg"].includes(g)){l.parentNode?.removeChild(l);return}let u=l.attributes;for(let A=u.length-1;A>=0;A--){let b=u[A].name.toLowerCase(),m=u[A].value.toLowerCase();(b.startsWith("on")||["src","href","data"].includes(b)&&(m.includes("javascript:")||m.includes("data:text/html")))&&l.removeAttribute(u[A].name)}Array.from(l.children).forEach(p)};return Array.from(c.children).forEach(p),c.innerHTML}catch{return h}}function E(h,d){if(h.nodeType!==d.nodeType){h.parentNode?.replaceChild(d.cloneNode(!0),h);return}if(h.nodeType===Node.TEXT_NODE){h.textContent!==d.textContent&&(h.textContent=d.textContent);return}if(h.nodeType===Node.ELEMENT_NODE){let f=h,n=d;if(f.tagName!==n.tagName){f.parentNode?.replaceChild(n.cloneNode(!0),f);return}let o=f.attributes,c=n.attributes;for(let b=o.length-1;b>=0;b--){let m=o[b].name;n.hasAttribute(m)||f.removeAttribute(m)}for(let b=0;b<c.length;b++){let m=c[b].name,_=c[b].value;f.getAttribute(m)!==_&&f.setAttribute(m,_)}f.tagName==="INPUT"||f.tagName==="TEXTAREA"?(f.value!==n.value&&(f.value=n.value),f.checked!==n.checked&&(f.checked=n.checked)):f.tagName==="SELECT"&&f.value!==n.value&&(f.value=n.value);let p=Array.from(f.childNodes),l=Array.from(n.childNodes),g=p.length,u=l.length,A=Math.max(g,u);for(let b=0;b<A;b++)b>=g?f.appendChild(l[b].cloneNode(!0)):b>=u?f.removeChild(p[b]):E(p[b],l[b])}}function D(h,d){if(typeof document>"u")return;let f=document.createElement(h.tagName);f.innerHTML=d;let n=Array.from(h.childNodes),o=Array.from(f.childNodes),c=n.length,p=o.length,l=Math.max(c,p);for(let g=0;g<l;g++)g>=c?h.appendChild(o[g].cloneNode(!0)):g>=p?h.removeChild(n[g]):E(n[g],o[g])}let k=new Map,M=!1;function x(h,d){k.set(h,d),M||(M=!0,(typeof requestAnimationFrame<"u"?requestAnimationFrame:n=>setTimeout(n,0))(()=>{k.forEach((n,o)=>{o.isConnected!==!1&&D(o,n)}),k.clear(),M=!1}))}w.setStoreState=function(h,d,f,n){this.uiStores=this.uiStores||new Map,this.uiStores.has(h)||this.uiStores.set(h,{});let o=this.uiStores.get(h);o[d]=f,this.options.debug&&console.log("%c\u{1F4BE} [Dolphin Store Update]:","color: #ec4899; font-weight: bold;",`${h}.${d}`,"=",f),typeof document<"u"&&document.querySelectorAll(`[data-store-read="${h}.${d}"]`).forEach(p=>{p!==n&&(p.tagName==="INPUT"||p.tagName==="TEXTAREA"?p.type==="checkbox"?p.checked=!!f:p.value=f??"":p.textContent=f??"")}),this.publish(`store/${h}`,o),typeof this._updateDOM=="function"&&this._updateDOM(`store/${h}`,o)},w.getStoreState=function(h,d){this.uiStores=this.uiStores||new Map;let f=this.uiStores.get(h);return f?f[d]:void 0},w._scanStoreBinds=function(){if(typeof document>"u")return;document.querySelectorAll("dolphin-store").forEach(n=>{if(typeof n.getAttribute!="function")return;let o=n.getAttribute("name")||n.getAttribute("data-store");if(!o)return;let c=n.children&&n.children.length>0;if(c?typeof n.setAttribute=="function"&&(n.setAttribute("data-rt-bind",`store/${o}`),n.setAttribute("data-rt-type","context")):n.style&&(n.style.display="none"),!c){let l=n.textContent?n.textContent.trim():"";if(l&&l.startsWith("{"))try{let g=JSON.parse(l);g&&typeof g=="object"&&Object.keys(g).forEach(u=>{this.setStoreState(o,u,g[u])})}catch(g){console.error(`[Dolphin Store Init Error] Failed to parse JSON inside <dolphin-store name="${o}">:`,g)}}let p=n.getAttribute("template");if(n.attributes){let l=["name","data-store","style","data-rt-bind","data-rt-type","template"];Array.from(n.attributes).forEach(g=>{if(!l.includes(g.name)){let u=g.value;u==="true"?u=!0:u==="false"?u=!1:u==="null"?u=null:!isNaN(Number(u))&&u.trim()!==""&&(u=Number(u)),this.setStoreState(o,g.name,u)}})}if(p&&!c&&n.parentNode&&typeof document<"u"){let l=`_ds_${o}_${p.replace(/[^a-z0-9]/gi,"_")}`,g=document.querySelector(`[data-ds-wired="${l}"]`);if(g||(g=document.createElement("div"),g.setAttribute("data-rt-bind",`store/${o}`),g.setAttribute("data-rt-template",p),g.setAttribute("data-ds-wired",l),n.parentNode.insertBefore(g,n.nextSibling)),typeof this._updateDOM=="function"){this.uiStores=this.uiStores||new Map;let u=this.uiStores.get(o)||{};this._updateDOM(`store/${o}`,u)}}if(c&&typeof this._updateDOM=="function"){this.uiStores=this.uiStores||new Map;let l=this.uiStores.get(o)||{};this._updateDOM(`store/${o}`,l)}}),document.querySelectorAll("[data-store-write]").forEach(n=>{let o=n.getAttribute("data-store-write");if(o){let c=o.split(".");if(c.length===2){let p=c[0],l=c[1],g=n.type==="checkbox"?n.checked:n.value;this.uiStores=this.uiStores||new Map,this.uiStores.has(p)||this.uiStores.set(p,{});let u=this.uiStores.get(p);u[l]===void 0&&(u[l]=g)}}}),document.querySelectorAll("[data-store-read]").forEach(n=>{let o=n.getAttribute("data-store-read");if(o){let c=o.split(".");if(c.length===2){let p=c[0],l=c[1],g=this.getStoreState(p,l);g!=null&&(n.tagName==="INPUT"||n.tagName==="TEXTAREA"?n.type==="checkbox"?n.checked=!!g:n.value=g:n.textContent=g)}}})},w.getClosestContext=function(h,d){let f=h;for(;f;){if(f._rtContext){let n=f._rtContext;return d?n[d]:n}f=f.parentElement||f.parentNode}return null},w._executeStoreAction=function(h,d){this.uiStores=this.uiStores||new Map;let f=d&&typeof this.getClosestContext=="function"?this.getClosestContext(d):null,n=new Proxy({},{has:(o,c)=>!0,get:(o,c)=>{if(typeof c=="string")return c==="log"?p=>{if(p===void 0){let l={};this.uiStores.forEach((g,u)=>{l[u]={...g}}),console.log("%c\u{1F4CA} [Dolphin All UI Stores]:","color: #06b6d4; font-weight: bold;",l)}else if(p&&typeof p=="object"&&p.__isStoreProxy__){let l=p.__storeName__,g=this.uiStores.get(l);console.log(`%c\u{1F4CA} [Dolphin Store: ${l}]:`,"color: #06b6d4; font-weight: bold;",g?{...g}:{})}else console.log("%c\u{1F4CA} [Dolphin Log]:","color: #06b6d4; font-weight: bold;",p)}:f&&f[c]!==void 0?f[c]:typeof globalThis<"u"&&c in globalThis?globalThis[c]:typeof window<"u"&&c in window?window[c]:new Proxy({},{get:(p,l)=>{if(l==="__storeName__")return c;if(l==="__isStoreProxy__")return!0;if(typeof l=="string")return this.getStoreState(c,l)},set:(p,l,g)=>typeof l=="string"?(this.setStoreState(c,l,g),!0):!1})}});try{new Function("ctx",`with(ctx) { ${h} }`)(n)}catch(o){console.error("%c[Dolphin Store Action Error]:","color: #ef4444; font-weight: bold;",o),d&&console.error("%cFailed Element:","color: #f97316; font-weight: bold;",d),console.error("%cFailed Expression:","color: #3b82f6; font-style: italic;",h)}},w._initDOMBinding=function(){if(this._domInitialized)return;this._domInitialized=!0;let h=["input","change","keyup","paste","blur"],d=new WeakMap;h.forEach(n=>{this.addDomListener(document,n,o=>{if(!o.target||!o.target.getAttribute)return;let c=o.target.getAttribute("data-store-write");if(c){let u=c.split(".");if(u.length===2){let A=u[0],b=u[1],m=o.target.type==="checkbox"?o.target.checked:o.target.value;this.setStoreState(A,b,m,o.target)}}let p=o.target.getAttribute("data-rt-validate"),l=o.target.name;if(p&&l&&typeof this.validateField=="function"){let u=o.target.closest("form"),A=u?Object.fromEntries(new FormData(u).entries()):{},b=this.validateField(o.target.value,p,A);b?(o.target.classList.add("invalid"),this.publish(`errors/${l}`,b)):(o.target.classList.remove("invalid"),this.publish(`errors/${l}`,""))}let g=o.target.getAttribute("data-rt-push");if(g){let u=o.target.getAttribute("data-rt-debounce"),A=u?parseInt(u,10):0,b=()=>{let m={name:o.target.name,value:o.target.value};this.pubPush(g,m)};if(A>0){d.has(o.target)&&clearTimeout(d.get(o.target));let m=setTimeout(b,A);d.set(o.target,m)}else b()}})}),this.addDomListener(document,"submit",async n=>{if(!n.target||!n.target.getAttribute)return;let o=n.target.getAttribute("data-rt-submit"),c=n.target.getAttribute("data-api-submit");if(o||c){n.target.querySelectorAll("[name]").forEach(m=>{let _=m.name;_&&(this.publish(`errors/${_}`,""),m.classList.remove("invalid"))});let l=n.target.querySelectorAll("[data-rt-validate]"),g=!0;if(l.length>0&&typeof this.validateField=="function"){let m=Object.fromEntries(new FormData(n.target).entries());l.forEach(_=>{let S=_.getAttribute("data-rt-validate"),C=_.name;if(S&&C){let v=this.validateField(_.value,S,m);v&&(g=!1,_.classList.add("invalid"),this.publish(`errors/${C}`,v))}})}if(!g){n.preventDefault(),n.stopPropagation();return}n.preventDefault();let u=this.getClosestContext(n.target)||{},A=new FormData(n.target),b=Object.fromEntries(A.entries());if(o){let m=o;for(let _ in u){let S=e(_);m=m.replace(new RegExp(`\\{\\{${S}\\}\\}`,"g"),u[_]!==void 0&&u[_]!==null?u[_]:"")}this.publish(m,b)}else if(c){let m=c;for(let v in u){let L=e(v);m=m.replace(new RegExp(`\\{\\{${L}\\}\\}`,"g"),u[v]!==void 0&&u[v]!==null?u[v]:"")}let _=m.trim().split(" "),S=_.length>1?_[0].toUpperCase():"POST",C=_.length>1?_[1]:_[0];b._method&&(S=String(b._method).toUpperCase());try{let v=await this.api.request(S,C,b),L=n.target.getAttribute("data-api-result");L&&this._updateDOM(L,v);let P=n.target.getAttribute("data-api-redirect");P&&(window.location.href=P),n.target.hasAttribute("data-api-reload")&&window.location.reload()}catch(v){console.error("[Dolphin] API Submit Error:",v)}}}}),["click","change","submit","input","keydown","keyup","dblclick","focus","blur","mouseenter","mouseleave"].forEach(n=>{this.addDomListener(document,n,async o=>{if(!o.target||!o.target.closest)return;let c=o.target.closest(`[data-rt-${n}]`),p=o.target.closest(`[data-api-${n}]`);if(c){n==="submit"&&o.preventDefault();let g=c.getAttribute(`data-rt-${n}`),u=c.getAttribute("data-rt-payload"),A=this.getClosestContext(c)||{},b={};if(u){let m=u;for(let _ in A){let S=e(_);m=m.replace(new RegExp(`\\{\\{${S}\\}\\}`,"g"),A[_]!==void 0&&A[_]!==null?A[_]:"")}try{b=JSON.parse(m)}catch{b={}}}this.publish(g,b)}if(p){n==="submit"&&o.preventDefault();let g=p.getAttribute(`data-api-${n}`),u=p.getAttribute("data-api-payload"),A=this.getClosestContext(p)||{},b=g.trim().split(" "),m=b.length>1?b[0].toUpperCase():"POST",_=b.length>1?b[1]:b[0],S=null;if(u){let C=u;for(let v in A){let L=e(v);C=C.replace(new RegExp(`\\{\\{${L}\\}\\}`,"g"),A[v]!==void 0&&A[v]!==null?A[v]:"")}try{S=JSON.parse(C)}catch{S=null}}try{let C=await this.api.request(m,_,S),v=p.getAttribute("data-api-result");v&&this._updateDOM(v,C);let L=p.getAttribute("data-api-redirect");L&&(window.location.href=L),p.hasAttribute("data-api-reload")&&window.location.reload()}catch(C){console.error(`[Dolphin] API ${n} Error:`,C)}}let l=o.target.closest(`[data-store-${n}]`);if(l){n==="submit"&&o.preventDefault();let g=l.getAttribute(`data-store-${n}`);g&&this._executeStoreAction(g,l)}})}),this.subscribe("#",(n,o)=>{this._updateDOM(o,n)}),this._scanAndFetchAPIBinds(),this._scanStoreBinds(),this._resolveImports(),this._initSPARouter()},w._scanAndFetchAPIBinds=async function(){if(typeof document>"u")return;let h=document.querySelectorAll("[data-api-get]");for(let d of Array.from(h)){let f=d.getAttribute("data-api-get");if(f&&!(typeof d.hasAttribute=="function"&&d.hasAttribute("data-api-initialized"))){typeof d.setAttribute=="function"&&d.setAttribute("data-api-initialized","true");try{let n=await this.api.get(f),o=d.getAttribute("data-api-store");if(o){let p=o.split(".");p.length===2&&this.setStoreState(p[0],p[1],n)}let c=d.getAttribute("data-rt-bind");if(c&&!o)this._updateDOM(c,n);else if(!o){let p=a(d);if(p&&typeof n=="object"&&n!==null){let l=this._applyDeclarativeDirectives(d,n);if(Array.isArray(l)){let g="";for(let u of l)g+=y(p,u);x(d,g)}else x(d,y(p,l))}else if(d.tagName==="INPUT"||d.tagName==="TEXTAREA")d.value=typeof n=="object"?n.value!==void 0?n.value:"":n;else{let l=typeof n=="object"?n.html||n.text||JSON.stringify(n):String(n);d.innerHTML=T(l)}}}catch(n){console.error("[Dolphin] API Get Error:",n)}}}},w._applyDeclarativeDirectives=function(h,d){let f=d;if(typeof d=="object"&&d!==null){let n=o=>{let c=[...o],p=h.getAttribute("data-rt-filter");if(p){let u=p.split("==");if(u.length===2){let A=u[0].trim(),b=u[1].trim(),m,_=b.split(".");_.length===2?m=this.getStoreState(_[0],_[1]):m=d[b]!==void 0?d[b]:this.getStoreState("app",b),m!=null&&m!==""&&(c=c.filter(S=>S[A]===m))}}let l=h.getAttribute("data-rt-search");if(l){let u=l.split("==");if(u.length===2){let A=u[0].trim(),b=u[1].trim(),m,_=b.split(".");if(_.length===2?m=this.getStoreState(_[0],_[1]):m=d[b]!==void 0?d[b]:this.getStoreState("app",b),m!=null&&m!==""){let S=String(m).toLowerCase();c=c.filter(C=>{let v=C[A];return v!=null&&String(v).toLowerCase().includes(S)})}}}let g=h.getAttribute("data-rt-sort");if(g){let u,A=g.split(".");if(A.length===2?u=this.getStoreState(A[0],A[1]):u=d[g]!==void 0?d[g]:this.getStoreState("app",g),u&&u!=="")if(u==="popular")c.sort((b,m)=>{let _=b.rating?.rate||b.rate||0;return(m.rating?.rate||m.rate||0)-_});else{let b="",m="asc";u.endsWith("-low")||u.endsWith("-asc")?(b=u.replace("-low","").replace("-asc",""),m="asc"):(u.endsWith("-high")||u.endsWith("-desc"))&&(b=u.replace("-high","").replace("-desc",""),m="desc"),b&&c.sort((_,S)=>{let C=(Y,tt)=>tt.split(".").reduce((W,et)=>W&&W[et],Y),v=C(_,b),L=C(S,b);if(v===void 0&&(v=_[b]),L===void 0&&(L=S[b]),typeof v=="string"&&typeof L=="string")return m==="asc"?v.localeCompare(L):L.localeCompare(v);let P=Number(v),q=Number(L);return!isNaN(P)&&!isNaN(q)?m==="asc"?P-q:q-P:0})}}return c};if(Array.isArray(d))f=n(d);else{let o="";for(let c in d)if(Array.isArray(d[c])){o=c;break}if(o){let c=n(d[o]);f={...d,[o]:c}}}}return f},w._updateDOM=function(h,d){if(typeof document>"u")return;document.querySelectorAll(`[data-rt-bind="${h}"]`).forEach(n=>{let o=this._applyDeclarativeDirectives(n,d);if(n.getAttribute("data-rt-type")==="context"&&typeof o=="object"&&o!==null){n._rtContext=o;let p=l=>{if(l.hasAttribute("data-rt-text")){let g=l.getAttribute("data-rt-text");if(g){let u=i(g,o);u!=null&&(l.textContent=u)}}if(l.hasAttribute("data-rt-html")){let g=l.getAttribute("data-rt-html");if(g){let u=i(g,o);u!=null&&(l.innerHTML=T(u))}}if(l.hasAttribute("data-rt-attr")){let g=l.getAttribute("data-rt-attr");g&&s(g,",").forEach(u=>{let A=r(u);if(A){let b=A[0].trim(),m=A[1].trim();if(b&&m){let _=i(m,o);_!=null&&l.setAttribute(b,_)}}})}if(l.hasAttribute("data-rt-class")){let g=l.getAttribute("data-rt-class");g&&s(g,",").forEach(u=>{let A=r(u);if(A){let b=A[0].trim(),m=A[1].trim(),_=b.split(/\s+/).filter(Boolean);i(m,o)?_.forEach(S=>l.classList.add(S)):_.forEach(S=>l.classList.remove(S))}})}if(l.hasAttribute("data-rt-if")){let g=l.getAttribute("data-rt-if");g&&(i(g,o)?l.style.display="":l.style.display="none")}if(l.hasAttribute("data-rt-hide")){let g=l.getAttribute("data-rt-hide");g&&(i(g,o)?l.style.display="none":l.style.display="")}};p(n),n.querySelectorAll("[data-rt-text], [data-rt-html], [data-rt-attr], [data-rt-class], [data-rt-if], [data-rt-hide]").forEach(p);return}let c=a(n);if(c&&typeof o=="object"&&o!==null){if(Array.isArray(o)){let p="";for(let l of o)p+=y(c,l);x(n,p)}else x(n,y(c,o));return}if(n.tagName==="INPUT"||n.tagName==="TEXTAREA")n.value=typeof o=="object"?o.value!==void 0?o.value:"":o;else if(c)n.innerHTML=typeof o=="object"?o.html||o.text||JSON.stringify(o):String(o);else{let p=typeof o=="object"?o.html||o.text||JSON.stringify(o):String(o);n.innerHTML=T(p)}})},w._resolveImports=async function(h){if(typeof document>"u")return;let d=h||document.body||document;if(!d||typeof d.querySelectorAll!="function")return;let f=d.querySelectorAll("[data-import]");if(f.length===0)return;let n=async(c,p)=>{let l=c.getAttribute("data-import");if(!l)return;if(p.has(l)){console.warn(`[Dolphin Component Warning]: Circular import detected for "${l}". Skipping resolving.`),c.innerHTML=`<span style="color:red;font-weight:bold;">Circular import: ${l}</span>`;return}p.add(l);let g=l.indexOf("#"),u=g!==-1?l.substring(0,g):l,A=g!==-1?l.substring(g):null,b=t.get(u);b||(b=fetch(u).then(S=>{if(!S.ok)throw new Error(`HTTP ${S.status}`);return S.text()}),b.catch(()=>t.delete(u)),t.set(u,b));let m="";try{if(m=await b,A&&typeof DOMParser<"u"){let v=new DOMParser().parseFromString(m,"text/html").querySelector(A);v?m=v.outerHTML:(console.warn(`[Dolphin Component Warning]: Selector "${A}" not found in imported file "${u}".`),m=`<span style="color:orange;font-weight:bold;">Selector ${A} not found in ${u}</span>`)}}catch(S){console.error(`[Dolphin Component Error]: Failed to fetch component "${u}":`,S),m=`<span style="color:red;font-weight:bold;">Failed to import ${u}</span>`}c.innerHTML=T(m),c.removeAttribute("data-import");let _=c.querySelectorAll("[data-import]");if(_.length>0){let S=Array.from(_).map(C=>n(C,new Set(p)));await Promise.all(S)}this._scanStoreBinds(),this._scanAndFetchAPIBinds()},o=Array.from(f).map(c=>n(c,new Set));await Promise.all(o)},w._initSPARouter=function(){if(typeof window>"u"||typeof document>"u"||this._routerInitialized)return;this._routerInitialized=!0;let h=null,d=()=>{let o=(this.options.routerViewport||"main, #viewport, body").split(",").map(c=>c.trim());for(let c of o){let p=document.querySelector(c);if(p)return p}return document.body},f=async(n,o=!0)=>{try{this.options.debug&&console.log(`%c\u{1F6E3}\uFE0F [Dolphin Router]: Navigating to ${n}...`,"color: #3b82f6; font-weight: bold;"),h&&h.abort(),h=new AbortController;let c=h.signal,p=d();this.options.routerTransitions&&p&&(p.classList.add("dolphin-fade-out"),await new Promise(_=>setTimeout(_,150)));let l=await fetch(n,{signal:c});if(!l.ok)throw new Error(`HTTP ${l.status}`);let g=await l.text();h=null;let A=new DOMParser().parseFromString(g,"text/html");A.title&&(document.title=A.title);let b=A.querySelector(this.options.routerViewport||"main, #viewport, body"),m=d();b&&m?(m.innerHTML=b.innerHTML,Array.from(b.attributes).forEach(_=>{m.setAttribute(_.name,_.value)})):m&&(m.innerHTML=A.body.innerHTML),o&&window.history.pushState({dolphinSpa:!0,url:n},"",n),this.options.routerTransitions&&m&&(m.classList.remove("dolphin-fade-out"),m.classList.add("dolphin-fade-in"),setTimeout(()=>m.classList.remove("dolphin-fade-in"),300)),await this._resolveImports(m),this._scanStoreBinds(),this._scanAndFetchAPIBinds()}catch(c){if(c&&c.name==="AbortError")return;console.error("[Dolphin Router Error]: Failed to route page:",c),window.location.href=n}};if(this.addDomListener(document,"click",n=>{let o=n.target.closest("a");if(!o||!o.hasAttribute("data-spa")&&o.getAttribute("data-spa")!=="true")return;let c=o.getAttribute("href");!c||c.startsWith("#")||c.startsWith("javascript:")||c.startsWith("mailto:")||c.startsWith("tel:")||new URL(c,window.location.href).origin!==window.location.origin||(n.preventDefault(),f(c))}),this.addDomListener(window,"popstate",n=>{n.state&&n.state.dolphinSpa?f(n.state.url,!1):n.state===null&&f(window.location.pathname,!1)}),this.options.routerTransitions){let n=document.createElement("style");n.innerHTML=`
27
27
  .dolphin-fade-out {
28
28
  opacity: 0;
29
29
  transition: opacity 0.15s ease-in-out;
@@ -34,4 +34,4 @@ var DolphinModule=(()=>{var q=Object.defineProperty;var et=Object.getOwnProperty
34
34
  main, #viewport, body {
35
35
  transition: opacity 0.15s ease-in-out;
36
36
  }
37
- `,document.head.appendChild(s)}}}var U=class{client;db;isOnline;memoryCache=new Map;memoryMutations=[];constructor(t){this.client=t,this.isOnline=typeof window<"u"&&typeof navigator<"u"?navigator.onLine:!0,this.initDB(),this.setupNetworkListeners()}initDB(){if(!(typeof indexedDB>"u"))try{let t=indexedDB.open("dolphin_offline",1);t.onupgradeneeded=e=>{let n=e.target.result;n.objectStoreNames.contains("cache")||n.createObjectStore("cache"),n.objectStoreNames.contains("mutations")||n.createObjectStore("mutations",{keyPath:"id",autoIncrement:!0})},t.onsuccess=e=>{this.db=e.target.result,this.isOnline&&this.syncMutations()}}catch(t){console.warn("[Dolphin Offline] Failed to initialize IndexedDB:",t)}}setupNetworkListeners(){typeof window>"u"||(this.client.addDomListener(window,"online",()=>{this.isOnline=!0,this.client._dispatch("network:status",{online:!0}),this.syncMutations()}),this.client.addDomListener(window,"offline",()=>{this.isOnline=!1,this.client._dispatch("network:status",{online:!1})}))}async getCache(t){return this.db?new Promise(e=>{try{let r=this.db.transaction("cache","readonly").objectStore("cache").get(t);r.onsuccess=()=>e(r.result?r.result.data:null),r.onerror=()=>e(null)}catch{e(null)}}):this.memoryCache.get(t)}async setCache(t,e){if(!this.db){this.memoryCache.set(t,e);return}return new Promise(n=>{try{let i=this.db.transaction("cache","readwrite");i.objectStore("cache").put({data:e,timestamp:Date.now()},t),i.oncomplete=()=>n(),i.onerror=()=>{console.warn("[Dolphin Offline] setCache write failed for key:",t),n()}}catch{n()}})}async queueMutation(t,e,n){let i={method:t,path:e,payload:n,timestamp:Date.now()};if(!this.db){this.memoryMutations.push(i);return}return new Promise(r=>{try{let a=this.db.transaction("mutations","readwrite");a.objectStore("mutations").add(i),a.oncomplete=()=>r(),a.onerror=()=>{console.warn("[Dolphin Offline] queueMutation write failed:",t,e),this.memoryMutations.push(i),r()}}catch{r()}})}async getMutations(){return this.db?new Promise(t=>{try{let i=this.db.transaction("mutations","readonly").objectStore("mutations").getAll();i.onsuccess=()=>t(i.result||[]),i.onerror=()=>t([])}catch{t([])}}):[...this.memoryMutations]}async removeMutation(t){if(!this.db){this.memoryMutations=this.memoryMutations.filter(e=>e.id!==t);return}return new Promise(e=>{try{let n=this.db.transaction("mutations","readwrite");n.objectStore("mutations").delete(t),n.oncomplete=()=>e(),n.onerror=()=>{console.warn("[Dolphin Offline] removeMutation failed for id:",t),e()}}catch{e()}})}async syncMutations(){let t=await this.getMutations();if(t.length!==0){console.log(`[Dolphin Offline] Syncing ${t.length} queued mutations...`);for(let e of t)try{await this.client.api.requestDirect(e.method,e.path,e.payload),e.id!==void 0?await this.removeMutation(e.id):this.memoryMutations.shift()}catch(n){if(console.error(`[Dolphin Offline] Sync failed for mutation ${e.method} ${e.path}:`,n),n&&n.status&&n.status>=400&&n.status<500)console.warn("[Dolphin Offline] Discarding invalid mutation."),e.id!==void 0?await this.removeMutation(e.id):this.memoryMutations.shift();else break}}}};function B(_){_._initOffline=function(){this.offline=new U(this)}}function at(_,t,e){let n=t.split(",");for(let i of n){let r=i.trim().split(":"),a=r[0],h=r[1];if(a==="required"){if(!_||_.trim()==="")return"This field is required"}else if(a==="email"){if(_&&_.trim()!==""&&!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(_))return"Please enter a valid email address"}else if(a==="min"){let T=parseInt(h,10);if(!_||_.length<T)return`Must be at least ${T} characters`}else if(a==="match"&&e&&_!==e[h])return`Must match ${h}`}return null}function j(_){_.validateField=at}function z(_){_.animateElement=function(t,e,n=300){if(typeof t.animate!="function"){t.classList.add(e),setTimeout(()=>t.classList.remove(e),n);return}e==="fade-in"?t.animate([{opacity:0,transform:"translateY(10px)"},{opacity:1,transform:"translateY(0)"}],{duration:n,easing:"ease-out"}):e==="fade-out"&&t.animate([{opacity:1,transform:"translateY(0)"},{opacity:0,transform:"translateY(10px)"}],{duration:n,easing:"ease-in"})},_.staggerListItems=function(t,e,n=50){if(typeof document>"u")return;t.querySelectorAll(e).forEach((r,a)=>{r.style.animationDelay=`${a*n}ms`,r.classList.add("staggered-item")})}}function V(_){_._initA11y=function(){typeof document>"u"||(this.addDomListener(document,"keydown",t=>{if(t.key!=="Tab")return;document.querySelectorAll("[data-rt-a11y-focus-trap]").forEach(n=>{if(n.style.display==="none"||n.hasAttribute("aria-hidden")&&n.getAttribute("aria-hidden")==="true")return;let r=Array.from(n.querySelectorAll('a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex="0"], [contenteditable]'));if(r.length===0)return;let a=r[0],h=r[r.length-1];t.shiftKey?document.activeElement===a&&(h.focus(),t.preventDefault()):document.activeElement===h&&(a.focus(),t.preventDefault())})}),this.addDomListener(document,"keydown",t=>{if(!["ArrowUp","ArrowDown","Enter"].includes(t.key))return;document.querySelectorAll("[data-rt-keynav]").forEach(n=>{let i=Array.from(n.children);if(i.length===0)return;let r=i.findIndex(a=>a.classList.contains("active")||document.activeElement===a);t.key==="ArrowDown"?(r=(r+1)%i.length,i[r].focus(),i.forEach((a,h)=>{h===r?a.classList.add("active"):a.classList.remove("active")}),t.preventDefault()):t.key==="ArrowUp"?(r=(r-1+i.length)%i.length,i[r].focus(),i.forEach((a,h)=>{h===r?a.classList.add("active"):a.classList.remove("active")}),t.preventDefault()):t.key==="Enter"&&r!==-1&&(i[r].click(),t.preventDefault())})}))},_.autoAriaModal=function(t,e){e?(t.setAttribute("role","dialog"),t.setAttribute("aria-modal","true"),t.setAttribute("aria-hidden","false"),t.focus()):t.setAttribute("aria-hidden","true")}}function K(_){_._initI18n=function(){if(this.i18n=this.i18n||{locale:"en",dicts:{}},typeof document>"u")return;if(document.querySelectorAll("[data-i18n-dict]").forEach(e=>{let n=e.getAttribute("data-i18n-dict");if(n)try{let i=JSON.parse(e.textContent||"{}");this.i18n.dicts[n]={...this.i18n.dicts[n]||{},...i}}catch(i){console.warn("[Dolphin i18n] Failed to parse dictionary for locale:",n,i)}}),!this.i18n.locale&&typeof navigator<"u"){let e=navigator.language.split("-")[0];this.i18n.dicts[e]&&(this.i18n.locale=e)}this.addDomListener(document,"click",e=>{let n=e.target.closest("[data-i18n-switch]");if(n){let i=n.getAttribute("data-i18n-switch");i&&this.setLocale(i)}}),this.translateDOM()},_.setLocale=function(t){this.i18n=this.i18n||{locale:"en",dicts:{}},this.i18n.locale=t,this.translateDOM(),this.publish("i18n/locale",t)},_.translateDOM=function(){if(typeof document>"u")return;this.i18n=this.i18n||{locale:"en",dicts:{}};let t=this.i18n.locale||"en",e=this.i18n.dicts[t]||{};document.querySelectorAll("[data-i18n-key]").forEach(i=>{let r=i.getAttribute("data-i18n-key");if(!r)return;let a=r.split(".").reduce((T,E)=>T?T[E]:null,e);a==null&&(a=r);let h=i.getAttribute("data-i18n-params");if(h)try{let T=JSON.parse(h),E=D=>D.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");for(let D in T){let k=E(D);a=a.replace(new RegExp(`\\{\\{${k}\\}\\}`,"g"),T[D])}}catch{}i.tagName==="INPUT"||i.tagName==="TEXTAREA"?i.placeholder=a:i.textContent=a})}}function X(_){_._initDragDrop=function(){typeof document>"u"||(this.addDomListener(document,"dragstart",t=>{let e=t.target.closest("[data-drag]");if(!e)return;let n=e.getAttribute("data-drag");n&&(t.dataTransfer.setData("text/plain",n),t.dataTransfer.effectAllowed="move",e.classList.add("dragging"))}),this.addDomListener(document,"dragend",t=>{let e=t.target.closest("[data-drag]");e&&e.classList.remove("dragging")}),this.addDomListener(document,"dragover",t=>{let e=t.target.closest("[data-drop]");e&&(t.preventDefault(),e.classList.add("drag-over"))}),this.addDomListener(document,"dragleave",t=>{let e=t.target.closest("[data-drop]");e&&e.classList.remove("drag-over")}),this.addDomListener(document,"drop",t=>{let e=t.target.closest("[data-drop]");if(!e)return;t.preventDefault(),e.classList.remove("drag-over");let n=e.getAttribute("data-drop"),i=t.dataTransfer.getData("text/plain");if(n&&i)try{let r=JSON.parse(i);this.publish(n,r)}catch{this.publish(n,{value:i})}}),this.addDomListener(document,"dragover",t=>{let e=t.target.closest("[data-sortable]");if(!e)return;t.preventDefault();let n=e.querySelector(".dragging");if(!n)return;let r=Array.from(e.querySelectorAll("[data-drag]:not(.dragging)")).find(a=>{let h=a.getBoundingClientRect();return t.clientY-h.top-h.height/2<0});r?e.insertBefore(n,r):e.appendChild(n)}),this.addDomListener(document,"drop",t=>{let e=t.target.closest("[data-sortable]");if(!e)return;let n=e.getAttribute("data-sortable");if(!n)return;let r=Array.from(e.querySelectorAll("[data-drag]")).map((a,h)=>{let T=a.getAttribute("data-drag");try{return{index:h,payload:JSON.parse(T||"{}")}}catch{return{index:h,payload:T}}});this.publish(n,r)}))}}function Q(_){_._initCollab=function(){if(typeof document>"u")return;let t=new Map,e=new Map,n=5e3;this.addDomListener(document,"mousemove",i=>{document.querySelectorAll("[data-rt-cursor-share]").forEach(a=>{let h=a.getAttribute("data-rt-cursor-share");if(!h)return;let T=a.getBoundingClientRect(),E=(i.clientX-T.left)/T.width,D=(i.clientY-T.top)/T.height,k=Date.now();(!a._lastSent||k-a._lastSent>50)&&(a._lastSent=k,this.pubPush(`collab/${h}/cursor/${this.deviceId}`,{deviceId:this.deviceId,x:E,y:D}))})}),this.addDomListener(document,"input",i=>{let r=i.target.getAttribute("data-rt-typing");if(!r)return;let a=r,h=T=>{this.pubPush(`collab/${a}/typing/${this.deviceId}`,{deviceId:this.deviceId,typing:T})};i.target._isTyping||(i.target._isTyping=!0,h(!0)),i.target._typingTimer&&clearTimeout(i.target._typingTimer),i.target._typingTimer=setTimeout(()=>{i.target._isTyping=!1,i.target._typingTimer=null,h(!1)},2e3)}),this.addDomListener(document,"input",i=>{let r=i.target.getAttribute("data-rt-crdt");if(!r)return;let a=r,h=i.target.value,T=Date.now();this.publish(`collab/${a}/crdt`,{deviceId:this.deviceId,value:h,timestamp:T,cursorPos:i.target.selectionStart})}),this.subscribe("collab/+/cursor/+",(i,r)=>{let a=r.split("/"),h=a[1],T=a[3];if(T===this.deviceId)return;let E=document.querySelector(`[data-rt-cursor-share="${h}"]`);if(!E)return;let D=`${h}::${T}`,k=t.get(D);(!k||!document.contains(k))&&(k=document.createElement("div"),k.className=`rt-cursor rt-cursor-${T}`,k.style.position="absolute",k.style.width="10px",k.style.height="10px",k.style.borderRadius="50%",k.style.backgroundColor="#"+Math.floor(Math.random()*16777215).toString(16).padStart(6,"0"),k.style.pointerEvents="none",E.appendChild(k),t.set(D,k));let M=E.getBoundingClientRect();k.style.left=i.x*M.width+"px",k.style.top=i.y*M.height+"px",e.has(D)&&clearTimeout(e.get(D)),e.set(D,setTimeout(()=>{let $=t.get(D);$&&$.parentNode&&$.parentNode.removeChild($),t.delete(D),e.delete(D)},n))}),this.subscribe("collab/+/crdt",(i,r)=>{if(i.deviceId===this.deviceId)return;let h=r.split("/")[1];document.querySelectorAll(`[data-rt-crdt="${h}"]`).forEach(E=>{if(!E._lastUpdate||i.timestamp>E._lastUpdate){E._lastUpdate=i.timestamp;let D=E.selectionStart;E.value=i.value,document.activeElement===E&&E.setSelectionRange(D,D)}})}),this._collabCleanup=()=>{e.forEach(i=>clearTimeout(i)),e.clear(),t.forEach(i=>{i&&i.parentNode&&i.parentNode.removeChild(i)}),t.clear()}}}function J(_){_.registerServiceWorker=async function(t="/sw.js"){if(typeof navigator>"u"||!("serviceWorker"in navigator))return console.warn("[Dolphin PWA] Service Workers are not supported in this browser."),null;try{let e=await navigator.serviceWorker.register(t);return console.log("[Dolphin PWA] Service Worker registered successfully with scope:",e.scope),e}catch(e){return console.error("[Dolphin PWA] Service Worker registration failed:",e),null}},_.subscribePushNotifications=async function(t){if(typeof window>"u"||!("serviceWorker"in navigator)||!("PushManager"in window))return console.warn("[Dolphin PWA] Push notifications are not supported in this browser."),null;try{let e=await navigator.serviceWorker.ready,n=await e.pushManager.getSubscription();if(!n){let i="=".repeat((4-t.length%4)%4),r=(t+i).replace(/\-/g,"+").replace(/_/g,"/"),a=window.atob(r),h=new Uint8Array(a.length);for(let T=0;T<a.length;++T)h[T]=a.charCodeAt(T);n=await e.pushManager.subscribe({userVisibleOnly:!0,applicationServerKey:h})}return console.log("[Dolphin PWA] Subscribed to push notifications:",n),n}catch(e){return console.error("[Dolphin PWA] Push notification subscription failed:",e),null}}}var H=class{static render(t){if(typeof document>"u")throw new Error("DolphinTestUtils.render requires a DOM document environment to execute.");let e=document.createElement("div");return e.innerHTML=t,document.body.appendChild(e),{container:e,find:n=>e.querySelector(n),fireEvent:(n,i)=>{let r=document.createEvent("Event");r.initEvent(i,!0,!0),n.dispatchEvent(r)}}}static mockWebSocket(){let t=[],e={readyState:1,send:n=>{t.push(n)},close:jest.fn(),onopen:jest.fn(),onmessage:jest.fn(),onclose:jest.fn(),onerror:jest.fn(),sentMessages:t};return global.WebSocket=class{static OPEN=1;readyState=e.readyState;send=e.send;close=e.close;set onopen(n){e.onopen=n}get onopen(){return e.onopen}set onmessage(n){e.onmessage=n}get onmessage(){return e.onmessage}set onclose(n){e.onclose=n}get getonclose(){return e.onclose}constructor(){setTimeout(()=>e.onopen&&e.onopen(),0)}},e}static simulateClick(t){let e={target:t,preventDefault:jest.fn(),stopPropagation:jest.fn()};(global.document._listeners?.click||[]).forEach(i=>i(e))}static simulateChange(t,e){t.value=e;let n={target:t,preventDefault:jest.fn(),stopPropagation:jest.fn()};(global.document._listeners?.change||[]).forEach(r=>r(n))}};function Z(_){_.testing=H}W(x.prototype);B(x.prototype);j(x.prototype);z(x.prototype);V(x.prototype);K(x.prototype);X(x.prototype);Q(x.prototype);J(x.prototype);Z(x.prototype);typeof window<"u"&&(window.DolphinClient=x,document.addEventListener("DOMContentLoaded",()=>{if(!window.dolphin){let _=document.querySelector('script[src*="dolphin-client"]'),t=_?_.getAttribute("data-debug")==="true":!1,e=new x(void 0,void 0,{debug:t});window.dolphin=e,t&&(console.log("%c\u{1F42C} [Dolphin Client] Auto-initialized local reactive engine!","color: #06b6d4; font-weight: bold; font-size: 14px;"),console.log('%c\u{1F449} Tip: You can access the client instance via "window.dolphin" in console.',"color: #94a3b8; font-style: italic;")),document.querySelector('[data-store-write="app.username"]')&&e.setStoreState("app","username","\u0928\u092E\u0938\u094D\u0924\u0947 \u0938\u093E\u0925\u0940!")}}));return ot(ct);})();
37
+ `,document.head.appendChild(n)}}}var F=class{client;db;isOnline;memoryCache=new Map;memoryMutations=[];constructor(t){this.client=t,this.isOnline=typeof window<"u"&&typeof navigator<"u"?navigator.onLine:!0,this.initDB(),this.setupNetworkListeners()}initDB(){if(!(typeof indexedDB>"u"))try{let t=indexedDB.open("dolphin_offline",1);t.onupgradeneeded=e=>{let i=e.target.result;i.objectStoreNames.contains("cache")||i.createObjectStore("cache"),i.objectStoreNames.contains("mutations")||i.createObjectStore("mutations",{keyPath:"id",autoIncrement:!0})},t.onsuccess=e=>{this.db=e.target.result,this.isOnline&&this.syncMutations()}}catch(t){console.warn("[Dolphin Offline] Failed to initialize IndexedDB:",t)}}setupNetworkListeners(){typeof window>"u"||(this.client.addDomListener(window,"online",()=>{this.isOnline=!0,this.client._dispatch("network:status",{online:!0}),this.syncMutations()}),this.client.addDomListener(window,"offline",()=>{this.isOnline=!1,this.client._dispatch("network:status",{online:!1})}))}async getCache(t){return this.db?new Promise(e=>{try{let r=this.db.transaction("cache","readonly").objectStore("cache").get(t);r.onsuccess=()=>e(r.result?r.result.data:null),r.onerror=()=>e(null)}catch{e(null)}}):this.memoryCache.get(t)}async setCache(t,e){if(!this.db){this.memoryCache.set(t,e);return}return new Promise(i=>{try{let s=this.db.transaction("cache","readwrite");s.objectStore("cache").put({data:e,timestamp:Date.now()},t),s.oncomplete=()=>i(),s.onerror=()=>{console.warn("[Dolphin Offline] setCache write failed for key:",t),i()}}catch{i()}})}async queueMutation(t,e,i){let s={method:t,path:e,payload:i,timestamp:Date.now()};if(!this.db){this.memoryMutations.push(s);return}return new Promise(r=>{try{let a=this.db.transaction("mutations","readwrite");a.objectStore("mutations").add(s),a.oncomplete=()=>r(),a.onerror=()=>{console.warn("[Dolphin Offline] queueMutation write failed:",t,e),this.memoryMutations.push(s),r()}}catch{r()}})}async getMutations(){return this.db?new Promise(t=>{try{let s=this.db.transaction("mutations","readonly").objectStore("mutations").getAll();s.onsuccess=()=>t(s.result||[]),s.onerror=()=>t([])}catch{t([])}}):[...this.memoryMutations]}async removeMutation(t){if(!this.db){this.memoryMutations=this.memoryMutations.filter(e=>e.id!==t);return}return new Promise(e=>{try{let i=this.db.transaction("mutations","readwrite");i.objectStore("mutations").delete(t),i.oncomplete=()=>e(),i.onerror=()=>{console.warn("[Dolphin Offline] removeMutation failed for id:",t),e()}}catch{e()}})}async syncMutations(){let t=await this.getMutations();if(t.length!==0){console.log(`[Dolphin Offline] Syncing ${t.length} queued mutations...`);for(let e of t)try{await this.client.api.requestDirect(e.method,e.path,e.payload),e.id!==void 0?await this.removeMutation(e.id):this.memoryMutations.shift()}catch(i){if(console.error(`[Dolphin Offline] Sync failed for mutation ${e.method} ${e.path}:`,i),i&&i.status&&i.status>=400&&i.status<500)console.warn("[Dolphin Offline] Discarding invalid mutation."),e.id!==void 0?await this.removeMutation(e.id):this.memoryMutations.shift();else break}}}};function j(w){w._initOffline=function(){this.offline=new F(this)}}function ct(w,t,e){let i=t.split(",");for(let s of i){let r=s.trim().split(":"),a=r[0],y=r[1];if(a==="required"){if(!w||w.trim()==="")return"This field is required"}else if(a==="email"){if(w&&w.trim()!==""&&!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(w))return"Please enter a valid email address"}else if(a==="min"){let T=parseInt(y,10);if(!w||w.length<T)return`Must be at least ${T} characters`}else if(a==="match"&&e&&w!==e[y])return`Must match ${y}`}return null}function V(w){w.validateField=ct}function z(w){w.animateElement=function(t,e,i=300){if(typeof t.animate!="function"){t.classList.add(e),setTimeout(()=>t.classList.remove(e),i);return}e==="fade-in"?t.animate([{opacity:0,transform:"translateY(10px)"},{opacity:1,transform:"translateY(0)"}],{duration:i,easing:"ease-out"}):e==="fade-out"&&t.animate([{opacity:1,transform:"translateY(0)"},{opacity:0,transform:"translateY(10px)"}],{duration:i,easing:"ease-in"})},w.staggerListItems=function(t,e,i=50){if(typeof document>"u")return;t.querySelectorAll(e).forEach((r,a)=>{r.style.animationDelay=`${a*i}ms`,r.classList.add("staggered-item")})}}function K(w){w._initA11y=function(){typeof document>"u"||(this.addDomListener(document,"keydown",t=>{if(t.key!=="Tab")return;document.querySelectorAll("[data-rt-a11y-focus-trap]").forEach(i=>{if(i.style.display==="none"||i.hasAttribute("aria-hidden")&&i.getAttribute("aria-hidden")==="true")return;let r=Array.from(i.querySelectorAll('a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex="0"], [contenteditable]'));if(r.length===0)return;let a=r[0],y=r[r.length-1];t.shiftKey?document.activeElement===a&&(y.focus(),t.preventDefault()):document.activeElement===y&&(a.focus(),t.preventDefault())})}),this.addDomListener(document,"keydown",t=>{if(!["ArrowUp","ArrowDown","Enter"].includes(t.key))return;document.querySelectorAll("[data-rt-keynav]").forEach(i=>{let s=Array.from(i.children);if(s.length===0)return;let r=s.findIndex(a=>a.classList.contains("active")||document.activeElement===a);t.key==="ArrowDown"?(r=(r+1)%s.length,s[r].focus(),s.forEach((a,y)=>{y===r?a.classList.add("active"):a.classList.remove("active")}),t.preventDefault()):t.key==="ArrowUp"?(r=(r-1+s.length)%s.length,s[r].focus(),s.forEach((a,y)=>{y===r?a.classList.add("active"):a.classList.remove("active")}),t.preventDefault()):t.key==="Enter"&&r!==-1&&(s[r].click(),t.preventDefault())})}))},w.autoAriaModal=function(t,e){e?(t.setAttribute("role","dialog"),t.setAttribute("aria-modal","true"),t.setAttribute("aria-hidden","false"),t.focus()):t.setAttribute("aria-hidden","true")}}function X(w){w._initI18n=function(){if(this.i18n=this.i18n||{locale:"en",dicts:{}},typeof document>"u")return;if(document.querySelectorAll("[data-i18n-dict]").forEach(e=>{let i=e.getAttribute("data-i18n-dict");if(i)try{let s=JSON.parse(e.textContent||"{}");this.i18n.dicts[i]={...this.i18n.dicts[i]||{},...s}}catch(s){console.warn("[Dolphin i18n] Failed to parse dictionary for locale:",i,s)}}),!this.i18n.locale&&typeof navigator<"u"){let e=navigator.language.split("-")[0];this.i18n.dicts[e]&&(this.i18n.locale=e)}this.addDomListener(document,"click",e=>{let i=e.target.closest("[data-i18n-switch]");if(i){let s=i.getAttribute("data-i18n-switch");s&&this.setLocale(s)}}),this.translateDOM()},w.setLocale=function(t){this.i18n=this.i18n||{locale:"en",dicts:{}},this.i18n.locale=t,this.translateDOM(),this.publish("i18n/locale",t)},w.translateDOM=function(){if(typeof document>"u")return;this.i18n=this.i18n||{locale:"en",dicts:{}};let t=this.i18n.locale||"en",e=this.i18n.dicts[t]||{};document.querySelectorAll("[data-i18n-key]").forEach(s=>{let r=s.getAttribute("data-i18n-key");if(!r)return;let a=r.split(".").reduce((T,E)=>T?T[E]:null,e);a==null&&(a=r);let y=s.getAttribute("data-i18n-params");if(y)try{let T=JSON.parse(y),E=D=>D.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");for(let D in T){let k=E(D);a=a.replace(new RegExp(`\\{\\{${k}\\}\\}`,"g"),T[D])}}catch{}s.tagName==="INPUT"||s.tagName==="TEXTAREA"?s.placeholder=a:s.textContent=a})}}function J(w){w._initDragDrop=function(){typeof document>"u"||(this.addDomListener(document,"dragstart",t=>{let e=t.target.closest("[data-drag]");if(!e)return;let i=e.getAttribute("data-drag");i&&(t.dataTransfer.setData("text/plain",i),t.dataTransfer.effectAllowed="move",e.classList.add("dragging"))}),this.addDomListener(document,"dragend",t=>{let e=t.target.closest("[data-drag]");e&&e.classList.remove("dragging")}),this.addDomListener(document,"dragover",t=>{let e=t.target.closest("[data-drop]");e&&(t.preventDefault(),e.classList.add("drag-over"))}),this.addDomListener(document,"dragleave",t=>{let e=t.target.closest("[data-drop]");e&&e.classList.remove("drag-over")}),this.addDomListener(document,"drop",t=>{let e=t.target.closest("[data-drop]");if(!e)return;t.preventDefault(),e.classList.remove("drag-over");let i=e.getAttribute("data-drop"),s=t.dataTransfer.getData("text/plain");if(i&&s)try{let r=JSON.parse(s);this.publish(i,r)}catch{this.publish(i,{value:s})}}),this.addDomListener(document,"dragover",t=>{let e=t.target.closest("[data-sortable]");if(!e)return;t.preventDefault();let i=e.querySelector(".dragging");if(!i)return;let r=Array.from(e.querySelectorAll("[data-drag]:not(.dragging)")).find(a=>{let y=a.getBoundingClientRect();return t.clientY-y.top-y.height/2<0});r?e.insertBefore(i,r):e.appendChild(i)}),this.addDomListener(document,"drop",t=>{let e=t.target.closest("[data-sortable]");if(!e)return;let i=e.getAttribute("data-sortable");if(!i)return;let r=Array.from(e.querySelectorAll("[data-drag]")).map((a,y)=>{let T=a.getAttribute("data-drag");try{return{index:y,payload:JSON.parse(T||"{}")}}catch{return{index:y,payload:T}}});this.publish(i,r)}))}}function Q(w){w._initCollab=function(){if(typeof document>"u")return;let t=new Map,e=new Map,i=5e3;this.addDomListener(document,"mousemove",s=>{document.querySelectorAll("[data-rt-cursor-share]").forEach(a=>{let y=a.getAttribute("data-rt-cursor-share");if(!y)return;let T=a.getBoundingClientRect(),E=(s.clientX-T.left)/T.width,D=(s.clientY-T.top)/T.height,k=Date.now();(!a._lastSent||k-a._lastSent>50)&&(a._lastSent=k,this.pubPush(`collab/${y}/cursor/${this.deviceId}`,{deviceId:this.deviceId,x:E,y:D}))})}),this.addDomListener(document,"input",s=>{let r=s.target.getAttribute("data-rt-typing");if(!r)return;let a=r,y=T=>{this.pubPush(`collab/${a}/typing/${this.deviceId}`,{deviceId:this.deviceId,typing:T})};s.target._isTyping||(s.target._isTyping=!0,y(!0)),s.target._typingTimer&&clearTimeout(s.target._typingTimer),s.target._typingTimer=setTimeout(()=>{s.target._isTyping=!1,s.target._typingTimer=null,y(!1)},2e3)}),this.addDomListener(document,"input",s=>{let r=s.target.getAttribute("data-rt-crdt");if(!r)return;let a=r,y=s.target.value,T=Date.now();this.publish(`collab/${a}/crdt`,{deviceId:this.deviceId,value:y,timestamp:T,cursorPos:s.target.selectionStart})}),this.subscribe("collab/+/cursor/+",(s,r)=>{let a=r.split("/"),y=a[1],T=a[3];if(T===this.deviceId)return;let E=document.querySelector(`[data-rt-cursor-share="${y}"]`);if(!E)return;let D=`${y}::${T}`,k=t.get(D);(!k||!document.contains(k))&&(k=document.createElement("div"),k.className=`rt-cursor rt-cursor-${T}`,k.style.position="absolute",k.style.width="10px",k.style.height="10px",k.style.borderRadius="50%",k.style.backgroundColor="#"+Math.floor(Math.random()*16777215).toString(16).padStart(6,"0"),k.style.pointerEvents="none",E.appendChild(k),t.set(D,k));let M=E.getBoundingClientRect();k.style.left=s.x*M.width+"px",k.style.top=s.y*M.height+"px",e.has(D)&&clearTimeout(e.get(D)),e.set(D,setTimeout(()=>{let x=t.get(D);x&&x.parentNode&&x.parentNode.removeChild(x),t.delete(D),e.delete(D)},i))}),this.subscribe("collab/+/crdt",(s,r)=>{if(s.deviceId===this.deviceId)return;let y=r.split("/")[1];document.querySelectorAll(`[data-rt-crdt="${y}"]`).forEach(E=>{if(!E._lastUpdate||s.timestamp>E._lastUpdate){E._lastUpdate=s.timestamp;let D=E.selectionStart;E.value=s.value,document.activeElement===E&&E.setSelectionRange(D,D)}})}),this._collabCleanup=()=>{e.forEach(s=>clearTimeout(s)),e.clear(),t.forEach(s=>{s&&s.parentNode&&s.parentNode.removeChild(s)}),t.clear()}}}function Z(w){w.registerServiceWorker=async function(t="/sw.js"){if(typeof navigator>"u"||!("serviceWorker"in navigator))return console.warn("[Dolphin PWA] Service Workers are not supported in this browser."),null;try{let e=await navigator.serviceWorker.register(t);return console.log("[Dolphin PWA] Service Worker registered successfully with scope:",e.scope),e}catch(e){return console.error("[Dolphin PWA] Service Worker registration failed:",e),null}},w.subscribePushNotifications=async function(t){if(typeof window>"u"||!("serviceWorker"in navigator)||!("PushManager"in window))return console.warn("[Dolphin PWA] Push notifications are not supported in this browser."),null;try{let e=await navigator.serviceWorker.ready,i=await e.pushManager.getSubscription();if(!i){let s="=".repeat((4-t.length%4)%4),r=(t+s).replace(/\-/g,"+").replace(/_/g,"/"),a=window.atob(r),y=new Uint8Array(a.length);for(let T=0;T<a.length;++T)y[T]=a.charCodeAt(T);i=await e.pushManager.subscribe({userVisibleOnly:!0,applicationServerKey:y})}return console.log("[Dolphin PWA] Subscribed to push notifications:",i),i}catch(e){return console.error("[Dolphin PWA] Push notification subscription failed:",e),null}}}function I(){if(typeof jest<"u"&&typeof jest.fn=="function")return jest.fn();let w=(...t)=>(w.mock.calls.push(t),w._implementation?w._implementation(...t):w._returnValue);return w.mock={calls:[]},w._returnValue=void 0,w._implementation=null,w.mockReturnValue=t=>(w._returnValue=t,w),w.mockImplementation=t=>(w._implementation=t,w),w}var H=class{static render(t){if(typeof document>"u")throw new Error("DolphinTestUtils.render requires a DOM document environment to execute.");let e=document.createElement("div");return e.innerHTML=t,document.body.appendChild(e),{container:e,find:i=>e.querySelector(i),fireEvent:(i,s)=>{let r=document.createEvent("Event");r.initEvent(s,!0,!0),i.dispatchEvent(r)}}}static mockWebSocket(){let t=[],e={readyState:1,send:i=>{t.push(i)},close:I(),onopen:I(),onmessage:I(),onclose:I(),onerror:I(),sentMessages:t};return global.WebSocket=class{static OPEN=1;readyState=e.readyState;send=e.send;close=e.close;set onopen(i){e.onopen=i}get onopen(){return e.onopen}set onmessage(i){e.onmessage=i}get onmessage(){return e.onmessage}set onclose(i){e.onclose=i}get getonclose(){return e.onclose}constructor(){setTimeout(()=>e.onopen&&e.onopen(),0)}},e}static simulateClick(t){let e={target:t,preventDefault:I(),stopPropagation:I()};(global.document._listeners?.click||[]).forEach(s=>s(e))}static simulateChange(t,e){t.value=e;let i={target:t,preventDefault:I(),stopPropagation:I()};(global.document._listeners?.change||[]).forEach(r=>r(i))}};function G(w){w.testing=H}B($.prototype);j($.prototype);V($.prototype);z($.prototype);K($.prototype);X($.prototype);J($.prototype);Q($.prototype);Z($.prototype);G($.prototype);typeof window<"u"&&(window.DolphinClient=$,document.addEventListener("DOMContentLoaded",()=>{if(!window.dolphin){let w=document.querySelector('script[src*="dolphin-client"]'),t=w?w.getAttribute("data-debug")==="true":!1,e=new $(void 0,void 0,{debug:t});window.dolphin=e,t&&(console.log("%c\u{1F42C} [Dolphin Client] Auto-initialized local reactive engine!","color: #06b6d4; font-weight: bold; font-size: 14px;"),console.log('%c\u{1F449} Tip: You can access the client instance via "window.dolphin" in console.',"color: #94a3b8; font-style: italic;")),document.querySelector('[data-store-write="app.username"]')&&e.setStoreState("app","username","\u0928\u092E\u0938\u094D\u0924\u0947 \u0938\u093E\u0925\u0940!")}}));return at(lt);})();
package/dist/index.cjs CHANGED
@@ -1381,6 +1381,73 @@ function attachDOMBinding(clientProto) {
1381
1381
  };
1382
1382
  clientProto._scanStoreBinds = function() {
1383
1383
  if (typeof document === "undefined") return;
1384
+ const storeElements = document.querySelectorAll("dolphin-store");
1385
+ storeElements.forEach((el) => {
1386
+ if (typeof el.getAttribute !== "function") return;
1387
+ const storeName = el.getAttribute("name") || el.getAttribute("data-store");
1388
+ if (!storeName) return;
1389
+ const hasChildren = el.children && el.children.length > 0;
1390
+ if (hasChildren) {
1391
+ if (typeof el.setAttribute === "function") {
1392
+ el.setAttribute("data-rt-bind", `store/${storeName}`);
1393
+ el.setAttribute("data-rt-type", "context");
1394
+ }
1395
+ } else {
1396
+ if (el.style) {
1397
+ el.style.display = "none";
1398
+ }
1399
+ }
1400
+ if (!hasChildren) {
1401
+ const content = el.textContent ? el.textContent.trim() : "";
1402
+ if (content && content.startsWith("{")) {
1403
+ try {
1404
+ const parsed = JSON.parse(content);
1405
+ if (parsed && typeof parsed === "object") {
1406
+ Object.keys(parsed).forEach((key) => {
1407
+ this.setStoreState(storeName, key, parsed[key]);
1408
+ });
1409
+ }
1410
+ } catch (err) {
1411
+ console.error(`[Dolphin Store Init Error] Failed to parse JSON inside <dolphin-store name="${storeName}">:`, err);
1412
+ }
1413
+ }
1414
+ }
1415
+ const templateSelector = el.getAttribute("template");
1416
+ if (el.attributes) {
1417
+ const excludeAttrs = ["name", "data-store", "style", "data-rt-bind", "data-rt-type", "template"];
1418
+ Array.from(el.attributes).forEach((attr) => {
1419
+ if (!excludeAttrs.includes(attr.name)) {
1420
+ let val = attr.value;
1421
+ if (val === "true") val = true;
1422
+ else if (val === "false") val = false;
1423
+ else if (val === "null") val = null;
1424
+ else if (!isNaN(Number(val)) && val.trim() !== "") val = Number(val);
1425
+ this.setStoreState(storeName, attr.name, val);
1426
+ }
1427
+ });
1428
+ }
1429
+ if (templateSelector && !hasChildren && el.parentNode && typeof document !== "undefined") {
1430
+ const markerId = `_ds_${storeName}_${templateSelector.replace(/[^a-z0-9]/gi, "_")}`;
1431
+ let wrapper = document.querySelector(`[data-ds-wired="${markerId}"]`);
1432
+ if (!wrapper) {
1433
+ wrapper = document.createElement("div");
1434
+ wrapper.setAttribute("data-rt-bind", `store/${storeName}`);
1435
+ wrapper.setAttribute("data-rt-template", templateSelector);
1436
+ wrapper.setAttribute("data-ds-wired", markerId);
1437
+ el.parentNode.insertBefore(wrapper, el.nextSibling);
1438
+ }
1439
+ if (typeof this._updateDOM === "function") {
1440
+ this.uiStores = this.uiStores || /* @__PURE__ */ new Map();
1441
+ const currentStore = this.uiStores.get(storeName) || {};
1442
+ this._updateDOM(`store/${storeName}`, currentStore);
1443
+ }
1444
+ }
1445
+ if (hasChildren && typeof this._updateDOM === "function") {
1446
+ this.uiStores = this.uiStores || /* @__PURE__ */ new Map();
1447
+ const currentStore = this.uiStores.get(storeName) || {};
1448
+ this._updateDOM(`store/${storeName}`, currentStore);
1449
+ }
1450
+ });
1384
1451
  const writeEls = document.querySelectorAll("[data-store-write]");
1385
1452
  writeEls.forEach((el) => {
1386
1453
  const writeBind = el.getAttribute("data-store-write");
@@ -2786,6 +2853,32 @@ function attachPwa(clientProto) {
2786
2853
  }
2787
2854
 
2788
2855
  // src/testing.ts
2856
+ function createMockFn() {
2857
+ if (typeof jest !== "undefined" && typeof jest.fn === "function") {
2858
+ return jest.fn();
2859
+ }
2860
+ const fn = (...args) => {
2861
+ fn.mock.calls.push(args);
2862
+ if (fn._implementation) {
2863
+ return fn._implementation(...args);
2864
+ }
2865
+ return fn._returnValue;
2866
+ };
2867
+ fn.mock = {
2868
+ calls: []
2869
+ };
2870
+ fn._returnValue = void 0;
2871
+ fn._implementation = null;
2872
+ fn.mockReturnValue = (val) => {
2873
+ fn._returnValue = val;
2874
+ return fn;
2875
+ };
2876
+ fn.mockImplementation = (impl) => {
2877
+ fn._implementation = impl;
2878
+ return fn;
2879
+ };
2880
+ return fn;
2881
+ }
2789
2882
  var DolphinTestUtils = class {
2790
2883
  static render(html) {
2791
2884
  if (typeof document === "undefined") {
@@ -2812,11 +2905,11 @@ var DolphinTestUtils = class {
2812
2905
  send: (data) => {
2813
2906
  sentMessages.push(data);
2814
2907
  },
2815
- close: jest.fn(),
2816
- onopen: jest.fn(),
2817
- onmessage: jest.fn(),
2818
- onclose: jest.fn(),
2819
- onerror: jest.fn(),
2908
+ close: createMockFn(),
2909
+ onopen: createMockFn(),
2910
+ onmessage: createMockFn(),
2911
+ onclose: createMockFn(),
2912
+ onerror: createMockFn(),
2820
2913
  sentMessages
2821
2914
  };
2822
2915
  global.WebSocket = class {
@@ -2851,8 +2944,8 @@ var DolphinTestUtils = class {
2851
2944
  static simulateClick(el) {
2852
2945
  const clickEvt = {
2853
2946
  target: el,
2854
- preventDefault: jest.fn(),
2855
- stopPropagation: jest.fn()
2947
+ preventDefault: createMockFn(),
2948
+ stopPropagation: createMockFn()
2856
2949
  };
2857
2950
  const clickListeners = global.document._listeners?.["click"] || [];
2858
2951
  clickListeners.forEach((listener) => listener(clickEvt));
@@ -2861,8 +2954,8 @@ var DolphinTestUtils = class {
2861
2954
  el.value = value;
2862
2955
  const changeEvt = {
2863
2956
  target: el,
2864
- preventDefault: jest.fn(),
2865
- stopPropagation: jest.fn()
2957
+ preventDefault: createMockFn(),
2958
+ stopPropagation: createMockFn()
2866
2959
  };
2867
2960
  const changeListeners = global.document._listeners?.["change"] || [];
2868
2961
  changeListeners.forEach((listener) => listener(changeEvt));
package/dist/index.js CHANGED
@@ -1356,6 +1356,73 @@ function attachDOMBinding(clientProto) {
1356
1356
  };
1357
1357
  clientProto._scanStoreBinds = function() {
1358
1358
  if (typeof document === "undefined") return;
1359
+ const storeElements = document.querySelectorAll("dolphin-store");
1360
+ storeElements.forEach((el) => {
1361
+ if (typeof el.getAttribute !== "function") return;
1362
+ const storeName = el.getAttribute("name") || el.getAttribute("data-store");
1363
+ if (!storeName) return;
1364
+ const hasChildren = el.children && el.children.length > 0;
1365
+ if (hasChildren) {
1366
+ if (typeof el.setAttribute === "function") {
1367
+ el.setAttribute("data-rt-bind", `store/${storeName}`);
1368
+ el.setAttribute("data-rt-type", "context");
1369
+ }
1370
+ } else {
1371
+ if (el.style) {
1372
+ el.style.display = "none";
1373
+ }
1374
+ }
1375
+ if (!hasChildren) {
1376
+ const content = el.textContent ? el.textContent.trim() : "";
1377
+ if (content && content.startsWith("{")) {
1378
+ try {
1379
+ const parsed = JSON.parse(content);
1380
+ if (parsed && typeof parsed === "object") {
1381
+ Object.keys(parsed).forEach((key) => {
1382
+ this.setStoreState(storeName, key, parsed[key]);
1383
+ });
1384
+ }
1385
+ } catch (err) {
1386
+ console.error(`[Dolphin Store Init Error] Failed to parse JSON inside <dolphin-store name="${storeName}">:`, err);
1387
+ }
1388
+ }
1389
+ }
1390
+ const templateSelector = el.getAttribute("template");
1391
+ if (el.attributes) {
1392
+ const excludeAttrs = ["name", "data-store", "style", "data-rt-bind", "data-rt-type", "template"];
1393
+ Array.from(el.attributes).forEach((attr) => {
1394
+ if (!excludeAttrs.includes(attr.name)) {
1395
+ let val = attr.value;
1396
+ if (val === "true") val = true;
1397
+ else if (val === "false") val = false;
1398
+ else if (val === "null") val = null;
1399
+ else if (!isNaN(Number(val)) && val.trim() !== "") val = Number(val);
1400
+ this.setStoreState(storeName, attr.name, val);
1401
+ }
1402
+ });
1403
+ }
1404
+ if (templateSelector && !hasChildren && el.parentNode && typeof document !== "undefined") {
1405
+ const markerId = `_ds_${storeName}_${templateSelector.replace(/[^a-z0-9]/gi, "_")}`;
1406
+ let wrapper = document.querySelector(`[data-ds-wired="${markerId}"]`);
1407
+ if (!wrapper) {
1408
+ wrapper = document.createElement("div");
1409
+ wrapper.setAttribute("data-rt-bind", `store/${storeName}`);
1410
+ wrapper.setAttribute("data-rt-template", templateSelector);
1411
+ wrapper.setAttribute("data-ds-wired", markerId);
1412
+ el.parentNode.insertBefore(wrapper, el.nextSibling);
1413
+ }
1414
+ if (typeof this._updateDOM === "function") {
1415
+ this.uiStores = this.uiStores || /* @__PURE__ */ new Map();
1416
+ const currentStore = this.uiStores.get(storeName) || {};
1417
+ this._updateDOM(`store/${storeName}`, currentStore);
1418
+ }
1419
+ }
1420
+ if (hasChildren && typeof this._updateDOM === "function") {
1421
+ this.uiStores = this.uiStores || /* @__PURE__ */ new Map();
1422
+ const currentStore = this.uiStores.get(storeName) || {};
1423
+ this._updateDOM(`store/${storeName}`, currentStore);
1424
+ }
1425
+ });
1359
1426
  const writeEls = document.querySelectorAll("[data-store-write]");
1360
1427
  writeEls.forEach((el) => {
1361
1428
  const writeBind = el.getAttribute("data-store-write");
@@ -2761,6 +2828,32 @@ function attachPwa(clientProto) {
2761
2828
  }
2762
2829
 
2763
2830
  // src/testing.ts
2831
+ function createMockFn() {
2832
+ if (typeof jest !== "undefined" && typeof jest.fn === "function") {
2833
+ return jest.fn();
2834
+ }
2835
+ const fn = (...args) => {
2836
+ fn.mock.calls.push(args);
2837
+ if (fn._implementation) {
2838
+ return fn._implementation(...args);
2839
+ }
2840
+ return fn._returnValue;
2841
+ };
2842
+ fn.mock = {
2843
+ calls: []
2844
+ };
2845
+ fn._returnValue = void 0;
2846
+ fn._implementation = null;
2847
+ fn.mockReturnValue = (val) => {
2848
+ fn._returnValue = val;
2849
+ return fn;
2850
+ };
2851
+ fn.mockImplementation = (impl) => {
2852
+ fn._implementation = impl;
2853
+ return fn;
2854
+ };
2855
+ return fn;
2856
+ }
2764
2857
  var DolphinTestUtils = class {
2765
2858
  static render(html) {
2766
2859
  if (typeof document === "undefined") {
@@ -2787,11 +2880,11 @@ var DolphinTestUtils = class {
2787
2880
  send: (data) => {
2788
2881
  sentMessages.push(data);
2789
2882
  },
2790
- close: jest.fn(),
2791
- onopen: jest.fn(),
2792
- onmessage: jest.fn(),
2793
- onclose: jest.fn(),
2794
- onerror: jest.fn(),
2883
+ close: createMockFn(),
2884
+ onopen: createMockFn(),
2885
+ onmessage: createMockFn(),
2886
+ onclose: createMockFn(),
2887
+ onerror: createMockFn(),
2795
2888
  sentMessages
2796
2889
  };
2797
2890
  global.WebSocket = class {
@@ -2826,8 +2919,8 @@ var DolphinTestUtils = class {
2826
2919
  static simulateClick(el) {
2827
2920
  const clickEvt = {
2828
2921
  target: el,
2829
- preventDefault: jest.fn(),
2830
- stopPropagation: jest.fn()
2922
+ preventDefault: createMockFn(),
2923
+ stopPropagation: createMockFn()
2831
2924
  };
2832
2925
  const clickListeners = global.document._listeners?.["click"] || [];
2833
2926
  clickListeners.forEach((listener) => listener(clickEvt));
@@ -2836,8 +2929,8 @@ var DolphinTestUtils = class {
2836
2929
  el.value = value;
2837
2930
  const changeEvt = {
2838
2931
  target: el,
2839
- preventDefault: jest.fn(),
2840
- stopPropagation: jest.fn()
2932
+ preventDefault: createMockFn(),
2933
+ stopPropagation: createMockFn()
2841
2934
  };
2842
2935
  const changeListeners = global.document._listeners?.["change"] || [];
2843
2936
  changeListeners.forEach((listener) => listener(changeEvt));
package/dist/testing.d.ts CHANGED
@@ -7,11 +7,11 @@ export declare class DolphinTestUtils {
7
7
  static mockWebSocket(): {
8
8
  readyState: number;
9
9
  send: (data: string) => void;
10
- close: jest.Mock<any, any, any>;
11
- onopen: jest.Mock<any, any, any>;
12
- onmessage: jest.Mock<any, any, any>;
13
- onclose: jest.Mock<any, any, any>;
14
- onerror: jest.Mock<any, any, any>;
10
+ close: any;
11
+ onopen: any;
12
+ onmessage: any;
13
+ onclose: any;
14
+ onerror: any;
15
15
  sentMessages: string[];
16
16
  };
17
17
  static simulateClick(el: any): void;
package/fulltutorial.md CHANGED
@@ -503,6 +503,61 @@ Ternary operator (`condition ? true : false`) वा बहु-लाइन `if/
503
503
  <button data-store-click="app.darkMode = !app.darkMode">डार्क मोड अन/अफ</button>
504
504
  ```
505
505
 
506
+ ### १०.१.३. Declarative Store Initialization & Context Containers (`<dolphin-store>`) - स्टोर घोषणा, प्रारम्भिकरण र अटो-बाइन्डिङ
507
+
508
+ Dolphin Client v2.0 introduces the `<dolphin-store>` tag for declaring, seeding, and auto-wiring reactive stores directly in HTML without writing custom JavaScript scripts.
509
+
510
+ #### क) Seed-Only Mode (विशुद्ध डेटा सीडिङ)
511
+ If the `<dolphin-store>` tag does not contain child elements, it seeds the store and remains hidden (`display: none`). You can seed data via tag attributes or inline JSON content:
512
+
513
+ **Attribute-Based Seeding:**
514
+ ```html
515
+ <!-- Automatically seeds store "app" with boolean, numeric, null, and string types -->
516
+ <dolphin-store name="app" count="0" isAdding="false" user="null" theme="dark"></dolphin-store>
517
+ ```
518
+
519
+ **JSON-Based Seeding:**
520
+ ```html
521
+ <!-- Seed complex objects/arrays by putting JSON content inside the tag -->
522
+ <dolphin-store name="app">
523
+ {
524
+ "count": 10,
525
+ "user": { "name": "Shankar", "role": "admin" },
526
+ "loggedIn": true
527
+ }
528
+ </dolphin-store>
529
+ ```
530
+
531
+ #### ख) Context Container Dual-Mode (डबल-मोड - डेटा कन्टेनर)
532
+ If the `<dolphin-store>` tag contains child elements, it acts as a **reactive context container** and remains visible. Its children can read and write to the store dynamically using `data-store-*` directives:
533
+
534
+ ```html
535
+ <!-- Acts as the reactive container for 'store/profile' -->
536
+ <dolphin-store name="profile" username="Shankar" role="Admin">
537
+ <div class="card">
538
+ <h3 data-rt-text="username"></h3>
539
+ <span class="badge" data-rt-text="role"></span>
540
+ </div>
541
+ </dolphin-store>
542
+ ```
543
+
544
+ #### ग) Template Auto-Wiring (टेम्पलेट स्वतः-कनेक्सन)
545
+ By setting the `template` attribute on a `<dolphin-store>`, Dolphin will automatically generate a reactive binding `div` right after it, compile the specified template selector, and render it with the store's seeded state immediately on page load:
546
+
547
+ ```html
548
+ <!-- 1. The Svelte-style template -->
549
+ <template id="counter-ui">
550
+ <div class="counter-box">
551
+ <p>Count: {{count}}</p>
552
+ <button data-rt-click="app.count = app.count + 1">Increment</button>
553
+ </div>
554
+ </template>
555
+
556
+ <!-- 2. Auto-wire the store app to the template (No separate wrapper div required!) -->
557
+ <dolphin-store name="app" template="#counter-ui" count="5"></dolphin-store>
558
+ ```
559
+ Under the hood, this dynamically injects a binding container that subscribes to `store/app` and updates the UI in real-time.
560
+
506
561
  ### १०.२. Declarative Validations (`data-validate`)
507
562
  Apply robust validation rules to inputs and forms instantly. Tagged invalid inputs automatically receive `.invalid` classes and publish error text:
508
563
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dolphin-client",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
4
4
  "description": "HTML is back! Hookless, framework-agnostic real-time reactive DOM-binding client for Dolphin Server with WebSockets, WebRTC signaling, and offline REST API fallbacks.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",