@goodo/platform-plugin 0.1.5 → 0.1.6
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.
- package/dist/host-sdk.d.ts +2 -0
- package/dist/host-sdk.d.ts.map +1 -1
- package/dist/host.cjs +1 -1
- package/dist/host.cjs.map +1 -1
- package/dist/host.js +86 -53
- package/dist/host.js.map +1 -1
- package/package.json +1 -1
package/dist/host-sdk.d.ts
CHANGED
|
@@ -90,6 +90,8 @@ export declare class LocalWidget implements LocalWidgetProps {
|
|
|
90
90
|
}
|
|
91
91
|
export declare const LOCAL_WIDGETS_STORAGE_KEY = "goodo_local_widgets";
|
|
92
92
|
export declare function getLocalWidgets(): LocalWidget[];
|
|
93
|
+
export declare function getLocalWidgetById(id?: string): LocalWidgetProps | null;
|
|
93
94
|
export declare function createLocalWidget(props: LocalWidgetProps): LocalWidget;
|
|
94
95
|
export declare function removeLocalWidget(id: string): void;
|
|
96
|
+
export declare function updateLocalWidget(id: string, props: Partial<LocalWidgetProps>): LocalWidgetProps | null;
|
|
95
97
|
//# sourceMappingURL=host-sdk.d.ts.map
|
package/dist/host-sdk.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host-sdk.d.ts","sourceRoot":"","sources":["../src/host-sdk.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"host-sdk.d.ts","sourceRoot":"","sources":["../src/host-sdk.ts"],"names":[],"mappings":"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"}
|
package/dist/host.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var u=Object.defineProperty;var m=(s,e,t)=>e in s?u(s,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):s[e]=t;var n=(s,e,t)=>m(s,typeof e!="symbol"?e+"":e,t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=require("./communicator-DQZOTxOF.cjs");class h{constructor(e){n(this,"_communicator",null);n(this,"iframeWindow");n(this,"subscriptions",new Set);n(this,"initPromise",null);n(this,"isDestroyed",!1);this.iframeWindow=e}get communicator(){if(!this._communicator)throw new Error("Host is not initialized. Call init() first.");return this._communicator}onMessage(e,t){const r={actionType:e,handler:t,off:null,cancelled:!1};return this._communicator&&(r.off=this._communicator.registerHandler(e,t)),this.subscriptions.add(r),()=>{r.cancelled||(r.cancelled=!0,this.subscriptions.delete(r),r.off&&(r.off(),r.off=null))}}async sendMessage(e,t,r){return this._communicator?this._communicator.sendRequest(e,t,r):this.initPromise?(await this.initPromise).sendRequest(e,t,r):this.communicator.sendRequest(e,t,r)}async init(e){if(this.isDestroyed)throw new Error("Host has already been destroyed.");return this._communicator?this._communicator:(this.initPromise||(this.initPromise=(async()=>{try{const t=await c.ping(this.iframeWindow,e);if(this.isDestroyed)throw t.destroy(),new Error("Host was destroyed during initialization.");this._communicator=t;for(const r of this.subscriptions)!r.cancelled&&!r.off&&(r.off=t.registerHandler(r.actionType,r.handler));return t}catch(t){throw this.initPromise=null,t}})()),this.initPromise)}destroy(){var e;this.isDestroyed=!0;for(const t of this.subscriptions)t.off&&(t.off(),t.off=null),t.cancelled=!0;this.subscriptions.clear(),(e=this._communicator)==null||e.destroy(),this._communicator=null,this.initPromise=null}}class l{constructor(e){n(this,"id");n(this,"mainAddress");n(this,"editorAddress");n(this,"runtimeAddress");n(this,"manifest",null);n(this,"ws",null);n(this,"isDestroyed",!1);n(this,"reconnectTimer",null);n(this,"manifestUpdateHandlers",new Set);n(this,"manifestErrorHandlers",new Set);n(this,"fileChangeHandlers",new Set);this.mainAddress=e.mainAddress.replace(/\/+$/,""),this.editorAddress=e.editorAddress,this.runtimeAddress=e.runtimeAddress,this.id=e.id||(typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID():`${Date.now()}_${Math.random().toString(36).substring(2,9)}`),this.initHMR()}initHMR(){if(!(typeof window>"u"||typeof WebSocket>"u")&&!(this.ws||this.isDestroyed))try{const e=this.mainAddress.replace(/^http(s)?:\/\//i,(r,i)=>i?"wss://":"ws://"),t=new WebSocket(e);this.ws=t,t.onmessage=r=>{try{const i=JSON.parse(r.data);if(i.type==="manifest:update"&&i.data){this.manifest=i.data;for(const a of this.manifestUpdateHandlers)a(i.data)}else if(i.type==="manifest:error")for(const a of this.manifestErrorHandlers)a(i.errors||"Manifest error");else if(i.type==="file:change")for(const a of this.fileChangeHandlers)a({file:i.file,event:i.event})}catch(i){console.error("[LocalWidget] Failed to parse HMR message:",i)}},t.onerror=()=>{},t.onclose=()=>{this.ws=null,this.isDestroyed||(this.reconnectTimer&&clearTimeout(this.reconnectTimer),this.reconnectTimer=setTimeout(()=>{this.isDestroyed||this.initHMR()},3e3))}}catch(e){console.error("[LocalWidget] Failed to initialize WebSocket HMR:",e)}}async fetchManifest(){if(typeof fetch>"u")return null;try{const e=`${this.mainAddress}/manifest.json`,t=await fetch(e);if(!t.ok)throw new Error(`Failed to fetch manifest: HTTP ${t.status}`);const r=await t.json();return this.manifest=r,r}catch(e){return console.error(`[LocalWidget] Failed to fetch manifest from ${this.mainAddress}:`,e),null}}onManifestUpdate(e){return this.manifestUpdateHandlers.add(e),this.manifest&&e(this.manifest),()=>{this.manifestUpdateHandlers.delete(e)}}onManifestError(e){return this.manifestErrorHandlers.add(e),()=>{this.manifestErrorHandlers.delete(e)}}onFileChange(e){return this.fileChangeHandlers.add(e),()=>{this.fileChangeHandlers.delete(e)}}destroy(){this.isDestroyed=!0,this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.ws&&(this.ws.close(),this.ws=null),this.manifestUpdateHandlers.clear(),this.manifestErrorHandlers.clear(),this.fileChangeHandlers.clear()}toJSON(){return{id:this.id,mainAddress:this.mainAddress,editorAddress:this.editorAddress,runtimeAddress:this.runtimeAddress}}}const o="goodo_local_widgets";function g(){if(typeof localStorage>"u")return[];try{const s=localStorage.getItem(o);if(!s)return[];const e=JSON.parse(s);return Array.isArray(e)?e.map(t=>new l(t)):[]}catch{return[]}}function y(s){if(typeof localStorage>"u"||!s)return null;try{const e=localStorage.getItem(o);if(!e)return null;const t=JSON.parse(e);return Array.isArray(t)&&t.find(r=>r.id===s)||null}catch{return null}}function w(s){const e=new l(s);if(typeof localStorage<"u")try{const t=localStorage.getItem(o),r=t?JSON.parse(t):[],i=Array.isArray(r)?r:[];i.push(e.toJSON()),localStorage.setItem(o,JSON.stringify(i))}catch(t){console.error("Failed to save local widget to localStorage:",t)}return e}function S(s){if(!(typeof localStorage>"u"))try{const e=localStorage.getItem(o);if(!e)return;const t=JSON.parse(e);if(Array.isArray(t)){const r=t.filter(i=>i.id!==s);localStorage.setItem(o,JSON.stringify(r))}}catch(e){console.error("Failed to remove local widget from localStorage:",e)}}function p(s,e){if(typeof localStorage>"u"||!s)return null;try{const t=localStorage.getItem(o);if(!t)return null;const r=JSON.parse(t);if(!Array.isArray(r))return null;const i=r.findIndex(f=>f.id===s);if(i===-1)return null;const a=r[i],d={...a,...e,id:s,mainAddress:e.mainAddress!==void 0?e.mainAddress.replace(/\/+$/,""):a.mainAddress};return r[i]=d,localStorage.setItem(o,JSON.stringify(r)),d}catch(t){return console.error("Failed to update local widget in localStorage:",t),null}}exports.Communicator=c.Communicator;exports.PING_TOKEN=c.PING_TOKEN;exports.PONG_TOKEN=c.PONG_TOKEN;exports.ping=c.ping;exports.Host=h;exports.LOCAL_WIDGETS_STORAGE_KEY=o;exports.LocalWidget=l;exports.createLocalWidget=w;exports.getLocalWidgetById=y;exports.getLocalWidgets=g;exports.removeLocalWidget=S;exports.updateLocalWidget=p;
|
|
2
2
|
//# sourceMappingURL=host.cjs.map
|
package/dist/host.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host.cjs","sources":["../src/host-sdk.ts"],"sourcesContent":["import { Communicator, ping, PingOptions } from './communicator';\nimport { ActionMap } from './types';\nimport type { ResolvedWidgetManifest } from './manifest';\n\ninterface HostSubscription {\n actionType: keyof ActionMap;\n handler: (payload: any) => any;\n off: (() => void) | null;\n cancelled: boolean;\n}\n\nexport class Host {\n private _communicator: Communicator | null = null;\n\n private iframeWindow: Window;\n\n private subscriptions = new Set<HostSubscription>();\n\n private initPromise: Promise<Communicator> | null = null;\n\n private isDestroyed = false;\n\n private get communicator(): Communicator {\n if (!this._communicator) {\n throw new Error('Host is not initialized. Call init() first.');\n }\n return this._communicator;\n }\n\n /**\n * Initialize Host SDK for a specific iframe widget\n * @param iframeWindow The contentWindow of the widget's iframe\n */\n constructor(iframeWindow: Window) {\n this.iframeWindow = iframeWindow;\n }\n\n /**\n * Register a unified handler for a specific message action type.\n * Can be called before or after `init()`.\n * Returns an unsubscribe function.\n */\n public onMessage<A extends keyof ActionMap>(\n actionType: A,\n handler: (payload: Parameters<ActionMap[A]>[0]) => Promise<ReturnType<ActionMap[A]>> | ReturnType<ActionMap[A]>\n ): () => void {\n const sub: HostSubscription = {\n actionType,\n handler,\n off: null,\n cancelled: false,\n };\n\n if (this._communicator) {\n sub.off = this._communicator.registerHandler(actionType, handler);\n }\n\n this.subscriptions.add(sub);\n\n return () => {\n if (sub.cancelled) return;\n sub.cancelled = true;\n this.subscriptions.delete(sub);\n if (sub.off) {\n sub.off();\n sub.off = null;\n }\n };\n }\n\n /**\n * Send a message/request to the widget and wait for the response.\n */\n public async sendMessage<A extends keyof ActionMap>(\n actionType: A,\n payload?: Parameters<ActionMap[A]>[0],\n timeout?: number\n ): Promise<ReturnType<ActionMap[A]>> {\n if (this._communicator) {\n return this._communicator.sendRequest(actionType, payload, timeout);\n }\n\n if (this.initPromise) {\n const comm = await this.initPromise;\n\n return comm.sendRequest(actionType, payload, timeout);\n }\n\n return this.communicator.sendRequest(actionType, payload, timeout);\n }\n\n /**\n * Complete the handshake with the target widget iframe and attach all registered handlers.\n */\n public async init(options?: PingOptions): Promise<Communicator> {\n if (this.isDestroyed) {\n throw new Error('Host has already been destroyed.');\n }\n\n if (this._communicator) {\n return this._communicator;\n }\n\n if (!this.initPromise) {\n this.initPromise = (async () => {\n try {\n const comm = await ping(this.iframeWindow, options);\n\n if (this.isDestroyed) {\n comm.destroy();\n throw new Error('Host was destroyed during initialization.');\n }\n\n this._communicator = comm;\n\n // Attach all active subscriptions to communicator\n for (const sub of this.subscriptions) {\n if (!sub.cancelled && !sub.off) {\n sub.off = comm.registerHandler(sub.actionType, sub.handler);\n }\n }\n\n return comm;\n } catch (err) {\n this.initPromise = null;\n throw err;\n }\n })();\n }\n\n return this.initPromise;\n }\n\n public destroy(): void {\n this.isDestroyed = true;\n\n for (const sub of this.subscriptions) {\n if (sub.off) {\n sub.off();\n sub.off = null;\n }\n sub.cancelled = true;\n }\n this.subscriptions.clear();\n\n this._communicator?.destroy();\n\n this._communicator = null;\n\n this.initPromise = null;\n }\n}\n\nexport type LocalWidgetProps = {\n id?: string;\n mainAddress: string;\n editorAddress?: string;\n runtimeAddress?: string;\n};\n\nexport type ManifestUpdateHandler = (manifest: ResolvedWidgetManifest) => void;\nexport type ManifestErrorHandler = (errors: Array<{ path: string; message: string }> | string) => void;\nexport type FileChangeHandler = (payload: { file: string; event: string }) => void;\n\nexport class LocalWidget implements LocalWidgetProps {\n id: string;\n\n mainAddress: string;\n\n editorAddress?: string;\n\n runtimeAddress?: string;\n\n manifest: ResolvedWidgetManifest | null = null;\n\n private ws: WebSocket | null = null;\n\n private isDestroyed = false;\n\n private reconnectTimer: any = null;\n\n private manifestUpdateHandlers = new Set<ManifestUpdateHandler>();\n\n private manifestErrorHandlers = new Set<ManifestErrorHandler>();\n\n private fileChangeHandlers = new Set<FileChangeHandler>();\n\n constructor(props: LocalWidgetProps) {\n this.mainAddress = props.mainAddress.replace(/\\/+$/, '');\n this.editorAddress = props.editorAddress;\n this.runtimeAddress = props.runtimeAddress;\n this.id =\n props.id ||\n (typeof crypto !== 'undefined' && crypto.randomUUID\n ? crypto.randomUUID()\n : `${Date.now()}_${Math.random().toString(36).substring(2, 9)}`);\n\n this.initHMR();\n }\n\n /**\n * Initialize WebSocket connection for mini-HMR with the dev server\n */\n public initHMR(): void {\n if (typeof window === 'undefined' || typeof WebSocket === 'undefined') {\n return;\n }\n\n if (this.ws || this.isDestroyed) {\n return;\n }\n\n try {\n const wsUrl = this.mainAddress.replace(/^http(s)?:\\/\\//i, (_, s) => (s ? 'wss://' : 'ws://'));\n const ws = new WebSocket(wsUrl);\n this.ws = ws;\n\n ws.onmessage = (event) => {\n try {\n const msg = JSON.parse(event.data);\n if (msg.type === 'manifest:update' && msg.data) {\n this.manifest = msg.data;\n for (const handler of this.manifestUpdateHandlers) {\n handler(msg.data);\n }\n } else if (msg.type === 'manifest:error') {\n for (const handler of this.manifestErrorHandlers) {\n handler(msg.errors || 'Manifest error');\n }\n } else if (msg.type === 'file:change') {\n for (const handler of this.fileChangeHandlers) {\n handler({ file: msg.file, event: msg.event });\n }\n }\n } catch (e) {\n console.error('[LocalWidget] Failed to parse HMR message:', e);\n }\n };\n\n ws.onerror = () => { };\n\n ws.onclose = () => {\n this.ws = null;\n if (!this.isDestroyed) {\n if (this.reconnectTimer) clearTimeout(this.reconnectTimer);\n this.reconnectTimer = setTimeout(() => {\n if (!this.isDestroyed) {\n this.initHMR();\n }\n }, 3000);\n }\n };\n } catch (e) {\n console.error('[LocalWidget] Failed to initialize WebSocket HMR:', e);\n }\n }\n\n /**\n * Fetch the latest manifest from the dev server via HTTP\n */\n public async fetchManifest(): Promise<ResolvedWidgetManifest | null> {\n if (typeof fetch === 'undefined') return null;\n try {\n const url = `${this.mainAddress}/manifest.json`;\n const res = await fetch(url);\n if (!res.ok) {\n throw new Error(`Failed to fetch manifest: HTTP ${res.status}`);\n }\n const data = (await res.json()) as ResolvedWidgetManifest;\n this.manifest = data;\n return data;\n } catch (e) {\n console.error(`[LocalWidget] Failed to fetch manifest from ${this.mainAddress}:`, e);\n return null;\n }\n }\n\n /**\n * Subscribe to manifest update events\n */\n public onManifestUpdate(handler: ManifestUpdateHandler): () => void {\n this.manifestUpdateHandlers.add(handler);\n if (this.manifest) {\n handler(this.manifest);\n }\n return () => {\n this.manifestUpdateHandlers.delete(handler);\n };\n }\n\n /**\n * Subscribe to manifest validation errors\n */\n public onManifestError(handler: ManifestErrorHandler): () => void {\n this.manifestErrorHandlers.add(handler);\n return () => {\n this.manifestErrorHandlers.delete(handler);\n };\n }\n\n /**\n * Subscribe to file change events in .goodo\n */\n public onFileChange(handler: FileChangeHandler): () => void {\n this.fileChangeHandlers.add(handler);\n return () => {\n this.fileChangeHandlers.delete(handler);\n };\n }\n\n /**\n * Destroy the instance, closing WebSocket and cleaning up timers and listeners\n */\n public destroy(): void {\n this.isDestroyed = true;\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n this.manifestUpdateHandlers.clear();\n this.manifestErrorHandlers.clear();\n this.fileChangeHandlers.clear();\n }\n\n /**\n * JSON serialization helper for localStorage\n */\n public toJSON(): LocalWidgetProps & { id: string } {\n return {\n id: this.id,\n mainAddress: this.mainAddress,\n editorAddress: this.editorAddress,\n runtimeAddress: this.runtimeAddress,\n };\n }\n}\n\nexport const LOCAL_WIDGETS_STORAGE_KEY = 'goodo_local_widgets';\n\nexport function getLocalWidgets(): LocalWidget[] {\n if (typeof localStorage === 'undefined') {\n return [];\n }\n try {\n const raw = localStorage.getItem(LOCAL_WIDGETS_STORAGE_KEY);\n if (!raw) return [];\n const parsed = JSON.parse(raw);\n if (!Array.isArray(parsed)) return [];\n return parsed.map((item: LocalWidgetProps) => new LocalWidget(item));\n } catch {\n return [];\n }\n}\n\nexport function createLocalWidget(props: LocalWidgetProps): LocalWidget {\n const localWidget = new LocalWidget(props);\n\n if (typeof localStorage !== 'undefined') {\n try {\n const raw = localStorage.getItem(LOCAL_WIDGETS_STORAGE_KEY);\n const list = raw ? JSON.parse(raw) : [];\n const validList = Array.isArray(list) ? list : [];\n validList.push(localWidget.toJSON());\n localStorage.setItem(LOCAL_WIDGETS_STORAGE_KEY, JSON.stringify(validList));\n } catch (e) {\n console.error('Failed to save local widget to localStorage:', e);\n }\n }\n\n return localWidget;\n}\n\nexport function removeLocalWidget(id: string): void {\n if (typeof localStorage === 'undefined') return;\n try {\n const raw = localStorage.getItem(LOCAL_WIDGETS_STORAGE_KEY);\n if (!raw) return;\n const list = JSON.parse(raw);\n if (Array.isArray(list)) {\n const filtered = list.filter((item: { id: string }) => item.id !== id);\n localStorage.setItem(LOCAL_WIDGETS_STORAGE_KEY, JSON.stringify(filtered));\n }\n } catch (e) {\n console.error('Failed to remove local widget from localStorage:', e);\n }\n}"],"names":["Host","iframeWindow","__publicField","actionType","handler","sub","payload","timeout","options","comm","ping","err","_a","LocalWidget","props","wsUrl","_","ws","event","msg","e","url","res","data","LOCAL_WIDGETS_STORAGE_KEY","getLocalWidgets","raw","parsed","item","createLocalWidget","localWidget","list","validList","removeLocalWidget","id","filtered"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"host.cjs","sources":["../src/host-sdk.ts"],"sourcesContent":["import { Communicator, ping, PingOptions } from './communicator';\nimport { ActionMap } from './types';\nimport type { ResolvedWidgetManifest } from './manifest';\n\ninterface HostSubscription {\n actionType: keyof ActionMap;\n handler: (payload: any) => any;\n off: (() => void) | null;\n cancelled: boolean;\n}\n\nexport class Host {\n private _communicator: Communicator | null = null;\n\n private iframeWindow: Window;\n\n private subscriptions = new Set<HostSubscription>();\n\n private initPromise: Promise<Communicator> | null = null;\n\n private isDestroyed = false;\n\n private get communicator(): Communicator {\n if (!this._communicator) {\n throw new Error('Host is not initialized. Call init() first.');\n }\n return this._communicator;\n }\n\n /**\n * Initialize Host SDK for a specific iframe widget\n * @param iframeWindow The contentWindow of the widget's iframe\n */\n constructor(iframeWindow: Window) {\n this.iframeWindow = iframeWindow;\n }\n\n /**\n * Register a unified handler for a specific message action type.\n * Can be called before or after `init()`.\n * Returns an unsubscribe function.\n */\n public onMessage<A extends keyof ActionMap>(\n actionType: A,\n handler: (payload: Parameters<ActionMap[A]>[0]) => Promise<ReturnType<ActionMap[A]>> | ReturnType<ActionMap[A]>\n ): () => void {\n const sub: HostSubscription = {\n actionType,\n handler,\n off: null,\n cancelled: false,\n };\n\n if (this._communicator) {\n sub.off = this._communicator.registerHandler(actionType, handler);\n }\n\n this.subscriptions.add(sub);\n\n return () => {\n if (sub.cancelled) return;\n sub.cancelled = true;\n this.subscriptions.delete(sub);\n if (sub.off) {\n sub.off();\n sub.off = null;\n }\n };\n }\n\n /**\n * Send a message/request to the widget and wait for the response.\n */\n public async sendMessage<A extends keyof ActionMap>(\n actionType: A,\n payload?: Parameters<ActionMap[A]>[0],\n timeout?: number\n ): Promise<ReturnType<ActionMap[A]>> {\n if (this._communicator) {\n return this._communicator.sendRequest(actionType, payload, timeout);\n }\n\n if (this.initPromise) {\n const comm = await this.initPromise;\n\n return comm.sendRequest(actionType, payload, timeout);\n }\n\n return this.communicator.sendRequest(actionType, payload, timeout);\n }\n\n /**\n * Complete the handshake with the target widget iframe and attach all registered handlers.\n */\n public async init(options?: PingOptions): Promise<Communicator> {\n if (this.isDestroyed) {\n throw new Error('Host has already been destroyed.');\n }\n\n if (this._communicator) {\n return this._communicator;\n }\n\n if (!this.initPromise) {\n this.initPromise = (async () => {\n try {\n const comm = await ping(this.iframeWindow, options);\n\n if (this.isDestroyed) {\n comm.destroy();\n throw new Error('Host was destroyed during initialization.');\n }\n\n this._communicator = comm;\n\n // Attach all active subscriptions to communicator\n for (const sub of this.subscriptions) {\n if (!sub.cancelled && !sub.off) {\n sub.off = comm.registerHandler(sub.actionType, sub.handler);\n }\n }\n\n return comm;\n } catch (err) {\n this.initPromise = null;\n throw err;\n }\n })();\n }\n\n return this.initPromise;\n }\n\n public destroy(): void {\n this.isDestroyed = true;\n\n for (const sub of this.subscriptions) {\n if (sub.off) {\n sub.off();\n sub.off = null;\n }\n sub.cancelled = true;\n }\n this.subscriptions.clear();\n\n this._communicator?.destroy();\n\n this._communicator = null;\n\n this.initPromise = null;\n }\n}\n\nexport type LocalWidgetProps = {\n id?: string;\n mainAddress: string;\n editorAddress?: string;\n runtimeAddress?: string;\n};\n\nexport type ManifestUpdateHandler = (manifest: ResolvedWidgetManifest) => void;\nexport type ManifestErrorHandler = (errors: Array<{ path: string; message: string }> | string) => void;\nexport type FileChangeHandler = (payload: { file: string; event: string }) => void;\n\nexport class LocalWidget implements LocalWidgetProps {\n id: string;\n\n mainAddress: string;\n\n editorAddress?: string;\n\n runtimeAddress?: string;\n\n manifest: ResolvedWidgetManifest | null = null;\n\n private ws: WebSocket | null = null;\n\n private isDestroyed = false;\n\n private reconnectTimer: any = null;\n\n private manifestUpdateHandlers = new Set<ManifestUpdateHandler>();\n\n private manifestErrorHandlers = new Set<ManifestErrorHandler>();\n\n private fileChangeHandlers = new Set<FileChangeHandler>();\n\n constructor(props: LocalWidgetProps) {\n this.mainAddress = props.mainAddress.replace(/\\/+$/, '');\n this.editorAddress = props.editorAddress;\n this.runtimeAddress = props.runtimeAddress;\n this.id =\n props.id ||\n (typeof crypto !== 'undefined' && crypto.randomUUID\n ? crypto.randomUUID()\n : `${Date.now()}_${Math.random().toString(36).substring(2, 9)}`);\n\n this.initHMR();\n }\n\n /**\n * Initialize WebSocket connection for mini-HMR with the dev server\n */\n public initHMR(): void {\n if (typeof window === 'undefined' || typeof WebSocket === 'undefined') {\n return;\n }\n\n if (this.ws || this.isDestroyed) {\n return;\n }\n\n try {\n const wsUrl = this.mainAddress.replace(/^http(s)?:\\/\\//i, (_, s) => (s ? 'wss://' : 'ws://'));\n const ws = new WebSocket(wsUrl);\n this.ws = ws;\n\n ws.onmessage = (event) => {\n try {\n const msg = JSON.parse(event.data);\n if (msg.type === 'manifest:update' && msg.data) {\n this.manifest = msg.data;\n for (const handler of this.manifestUpdateHandlers) {\n handler(msg.data);\n }\n } else if (msg.type === 'manifest:error') {\n for (const handler of this.manifestErrorHandlers) {\n handler(msg.errors || 'Manifest error');\n }\n } else if (msg.type === 'file:change') {\n for (const handler of this.fileChangeHandlers) {\n handler({ file: msg.file, event: msg.event });\n }\n }\n } catch (e) {\n console.error('[LocalWidget] Failed to parse HMR message:', e);\n }\n };\n\n ws.onerror = () => { };\n\n ws.onclose = () => {\n this.ws = null;\n if (!this.isDestroyed) {\n if (this.reconnectTimer) clearTimeout(this.reconnectTimer);\n this.reconnectTimer = setTimeout(() => {\n if (!this.isDestroyed) {\n this.initHMR();\n }\n }, 3000);\n }\n };\n } catch (e) {\n console.error('[LocalWidget] Failed to initialize WebSocket HMR:', e);\n }\n }\n\n /**\n * Fetch the latest manifest from the dev server via HTTP\n */\n public async fetchManifest(): Promise<ResolvedWidgetManifest | null> {\n if (typeof fetch === 'undefined') return null;\n try {\n const url = `${this.mainAddress}/manifest.json`;\n const res = await fetch(url);\n if (!res.ok) {\n throw new Error(`Failed to fetch manifest: HTTP ${res.status}`);\n }\n const data = (await res.json()) as ResolvedWidgetManifest;\n this.manifest = data;\n return data;\n } catch (e) {\n console.error(`[LocalWidget] Failed to fetch manifest from ${this.mainAddress}:`, e);\n return null;\n }\n }\n\n /**\n * Subscribe to manifest update events\n */\n public onManifestUpdate(handler: ManifestUpdateHandler): () => void {\n this.manifestUpdateHandlers.add(handler);\n if (this.manifest) {\n handler(this.manifest);\n }\n return () => {\n this.manifestUpdateHandlers.delete(handler);\n };\n }\n\n /**\n * Subscribe to manifest validation errors\n */\n public onManifestError(handler: ManifestErrorHandler): () => void {\n this.manifestErrorHandlers.add(handler);\n return () => {\n this.manifestErrorHandlers.delete(handler);\n };\n }\n\n /**\n * Subscribe to file change events in .goodo\n */\n public onFileChange(handler: FileChangeHandler): () => void {\n this.fileChangeHandlers.add(handler);\n return () => {\n this.fileChangeHandlers.delete(handler);\n };\n }\n\n /**\n * Destroy the instance, closing WebSocket and cleaning up timers and listeners\n */\n public destroy(): void {\n this.isDestroyed = true;\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n this.manifestUpdateHandlers.clear();\n this.manifestErrorHandlers.clear();\n this.fileChangeHandlers.clear();\n }\n\n /**\n * JSON serialization helper for localStorage\n */\n public toJSON(): LocalWidgetProps & { id: string } {\n return {\n id: this.id,\n mainAddress: this.mainAddress,\n editorAddress: this.editorAddress,\n runtimeAddress: this.runtimeAddress,\n };\n }\n}\n\nexport const LOCAL_WIDGETS_STORAGE_KEY = 'goodo_local_widgets';\n\nexport function getLocalWidgets(): LocalWidget[] {\n if (typeof localStorage === 'undefined') {\n return [];\n }\n try {\n const raw = localStorage.getItem(LOCAL_WIDGETS_STORAGE_KEY);\n if (!raw) return [];\n const parsed = JSON.parse(raw);\n if (!Array.isArray(parsed)) return [];\n return parsed.map((item: LocalWidgetProps) => new LocalWidget(item));\n } catch {\n return [];\n }\n}\n\nexport function getLocalWidgetById(id?: string): LocalWidgetProps | null {\n if (typeof localStorage === 'undefined' || !id) return null;\n try {\n const raw = localStorage.getItem(LOCAL_WIDGETS_STORAGE_KEY);\n if (!raw) return null;\n const parsed = JSON.parse(raw);\n if (!Array.isArray(parsed)) return null;\n return parsed.find((item: LocalWidgetProps) => item.id === id) || null;\n } catch {\n return null;\n }\n}\n\nexport function createLocalWidget(props: LocalWidgetProps): LocalWidget {\n const localWidget = new LocalWidget(props);\n\n if (typeof localStorage !== 'undefined') {\n try {\n const raw = localStorage.getItem(LOCAL_WIDGETS_STORAGE_KEY);\n const list = raw ? JSON.parse(raw) : [];\n const validList = Array.isArray(list) ? list : [];\n validList.push(localWidget.toJSON());\n localStorage.setItem(LOCAL_WIDGETS_STORAGE_KEY, JSON.stringify(validList));\n } catch (e) {\n console.error('Failed to save local widget to localStorage:', e);\n }\n }\n\n return localWidget;\n}\n\nexport function removeLocalWidget(id: string): void {\n if (typeof localStorage === 'undefined') return;\n try {\n const raw = localStorage.getItem(LOCAL_WIDGETS_STORAGE_KEY);\n if (!raw) return;\n const list = JSON.parse(raw);\n if (Array.isArray(list)) {\n const filtered = list.filter((item: { id: string }) => item.id !== id);\n localStorage.setItem(LOCAL_WIDGETS_STORAGE_KEY, JSON.stringify(filtered));\n }\n } catch (e) {\n console.error('Failed to remove local widget from localStorage:', e);\n }\n}\n\nexport function updateLocalWidget(id: string, props: Partial<LocalWidgetProps>): LocalWidgetProps | null {\n if (typeof localStorage === 'undefined' || !id) return null;\n try {\n const raw = localStorage.getItem(LOCAL_WIDGETS_STORAGE_KEY);\n if (!raw) return null;\n const list = JSON.parse(raw);\n if (!Array.isArray(list)) return null;\n const idx = list.findIndex((item: LocalWidgetProps) => item.id === id);\n if (idx === -1) return null;\n const existing = list[idx];\n const updated: LocalWidgetProps = {\n ...existing,\n ...props,\n id,\n mainAddress: props.mainAddress !== undefined ? props.mainAddress.replace(/\\/+$/, '') : existing.mainAddress\n };\n list[idx] = updated;\n localStorage.setItem(LOCAL_WIDGETS_STORAGE_KEY, JSON.stringify(list));\n return updated;\n } catch (e) {\n console.error('Failed to update local widget in localStorage:', e);\n return null;\n }\n}"],"names":["Host","iframeWindow","__publicField","actionType","handler","sub","payload","timeout","options","comm","ping","err","_a","LocalWidget","props","wsUrl","_","s","ws","event","msg","e","url","res","data","LOCAL_WIDGETS_STORAGE_KEY","getLocalWidgets","raw","parsed","item","getLocalWidgetById","id","createLocalWidget","localWidget","list","validList","removeLocalWidget","filtered","updateLocalWidget","idx","existing","updated"],"mappings":"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"}
|
package/dist/host.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
import { p as
|
|
5
|
-
import { C as
|
|
6
|
-
class
|
|
1
|
+
var f = Object.defineProperty;
|
|
2
|
+
var u = (s, e, t) => e in s ? f(s, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : s[e] = t;
|
|
3
|
+
var n = (s, e, t) => u(s, typeof e != "symbol" ? e + "" : e, t);
|
|
4
|
+
import { p as m } from "./communicator-BF77R7Qs.js";
|
|
5
|
+
import { C as O, P as E, a as N } from "./communicator-BF77R7Qs.js";
|
|
6
|
+
class y {
|
|
7
7
|
/**
|
|
8
8
|
* Initialize Host SDK for a specific iframe widget
|
|
9
9
|
* @param iframeWindow The contentWindow of the widget's iframe
|
|
10
10
|
*/
|
|
11
11
|
constructor(e) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
n(this, "_communicator", null);
|
|
13
|
+
n(this, "iframeWindow");
|
|
14
|
+
n(this, "subscriptions", /* @__PURE__ */ new Set());
|
|
15
|
+
n(this, "initPromise", null);
|
|
16
|
+
n(this, "isDestroyed", !1);
|
|
17
17
|
this.iframeWindow = e;
|
|
18
18
|
}
|
|
19
19
|
get communicator() {
|
|
@@ -27,21 +27,21 @@ class u {
|
|
|
27
27
|
* Returns an unsubscribe function.
|
|
28
28
|
*/
|
|
29
29
|
onMessage(e, t) {
|
|
30
|
-
const
|
|
30
|
+
const r = {
|
|
31
31
|
actionType: e,
|
|
32
32
|
handler: t,
|
|
33
33
|
off: null,
|
|
34
34
|
cancelled: !1
|
|
35
35
|
};
|
|
36
|
-
return this._communicator && (
|
|
37
|
-
|
|
36
|
+
return this._communicator && (r.off = this._communicator.registerHandler(e, t)), this.subscriptions.add(r), () => {
|
|
37
|
+
r.cancelled || (r.cancelled = !0, this.subscriptions.delete(r), r.off && (r.off(), r.off = null));
|
|
38
38
|
};
|
|
39
39
|
}
|
|
40
40
|
/**
|
|
41
41
|
* Send a message/request to the widget and wait for the response.
|
|
42
42
|
*/
|
|
43
|
-
async sendMessage(e, t,
|
|
44
|
-
return this._communicator ? this._communicator.sendRequest(e, t,
|
|
43
|
+
async sendMessage(e, t, r) {
|
|
44
|
+
return this._communicator ? this._communicator.sendRequest(e, t, r) : this.initPromise ? (await this.initPromise).sendRequest(e, t, r) : this.communicator.sendRequest(e, t, r);
|
|
45
45
|
}
|
|
46
46
|
/**
|
|
47
47
|
* Complete the handshake with the target widget iframe and attach all registered handlers.
|
|
@@ -51,12 +51,12 @@ class u {
|
|
|
51
51
|
throw new Error("Host has already been destroyed.");
|
|
52
52
|
return this._communicator ? this._communicator : (this.initPromise || (this.initPromise = (async () => {
|
|
53
53
|
try {
|
|
54
|
-
const t = await
|
|
54
|
+
const t = await m(this.iframeWindow, e);
|
|
55
55
|
if (this.isDestroyed)
|
|
56
56
|
throw t.destroy(), new Error("Host was destroyed during initialization.");
|
|
57
57
|
this._communicator = t;
|
|
58
|
-
for (const
|
|
59
|
-
!
|
|
58
|
+
for (const r of this.subscriptions)
|
|
59
|
+
!r.cancelled && !r.off && (r.off = t.registerHandler(r.actionType, r.handler));
|
|
60
60
|
return t;
|
|
61
61
|
} catch (t) {
|
|
62
62
|
throw this.initPromise = null, t;
|
|
@@ -73,17 +73,17 @@ class u {
|
|
|
73
73
|
}
|
|
74
74
|
class c {
|
|
75
75
|
constructor(e) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
76
|
+
n(this, "id");
|
|
77
|
+
n(this, "mainAddress");
|
|
78
|
+
n(this, "editorAddress");
|
|
79
|
+
n(this, "runtimeAddress");
|
|
80
|
+
n(this, "manifest", null);
|
|
81
|
+
n(this, "ws", null);
|
|
82
|
+
n(this, "isDestroyed", !1);
|
|
83
|
+
n(this, "reconnectTimer", null);
|
|
84
|
+
n(this, "manifestUpdateHandlers", /* @__PURE__ */ new Set());
|
|
85
|
+
n(this, "manifestErrorHandlers", /* @__PURE__ */ new Set());
|
|
86
|
+
n(this, "fileChangeHandlers", /* @__PURE__ */ new Set());
|
|
87
87
|
this.mainAddress = e.mainAddress.replace(/\/+$/, ""), this.editorAddress = e.editorAddress, this.runtimeAddress = e.runtimeAddress, this.id = e.id || (typeof crypto < "u" && crypto.randomUUID ? crypto.randomUUID() : `${Date.now()}_${Math.random().toString(36).substring(2, 9)}`), this.initHMR();
|
|
88
88
|
}
|
|
89
89
|
/**
|
|
@@ -92,10 +92,10 @@ class c {
|
|
|
92
92
|
initHMR() {
|
|
93
93
|
if (!(typeof window > "u" || typeof WebSocket > "u") && !(this.ws || this.isDestroyed))
|
|
94
94
|
try {
|
|
95
|
-
const e = this.mainAddress.replace(/^http(s)?:\/\//i, (
|
|
96
|
-
this.ws = t, t.onmessage = (
|
|
95
|
+
const e = this.mainAddress.replace(/^http(s)?:\/\//i, (r, i) => i ? "wss://" : "ws://"), t = new WebSocket(e);
|
|
96
|
+
this.ws = t, t.onmessage = (r) => {
|
|
97
97
|
try {
|
|
98
|
-
const i = JSON.parse(
|
|
98
|
+
const i = JSON.parse(r.data);
|
|
99
99
|
if (i.type === "manifest:update" && i.data) {
|
|
100
100
|
this.manifest = i.data;
|
|
101
101
|
for (const o of this.manifestUpdateHandlers)
|
|
@@ -128,8 +128,8 @@ class c {
|
|
|
128
128
|
const e = `${this.mainAddress}/manifest.json`, t = await fetch(e);
|
|
129
129
|
if (!t.ok)
|
|
130
130
|
throw new Error(`Failed to fetch manifest: HTTP ${t.status}`);
|
|
131
|
-
const
|
|
132
|
-
return this.manifest =
|
|
131
|
+
const r = await t.json();
|
|
132
|
+
return this.manifest = r, r;
|
|
133
133
|
} catch (e) {
|
|
134
134
|
return console.error(`[LocalWidget] Failed to fetch manifest from ${this.mainAddress}:`, e), null;
|
|
135
135
|
}
|
|
@@ -177,53 +177,86 @@ class c {
|
|
|
177
177
|
}
|
|
178
178
|
}
|
|
179
179
|
const a = "goodo_local_widgets";
|
|
180
|
-
function
|
|
180
|
+
function w() {
|
|
181
181
|
if (typeof localStorage > "u")
|
|
182
182
|
return [];
|
|
183
183
|
try {
|
|
184
|
-
const
|
|
185
|
-
if (!
|
|
186
|
-
const e = JSON.parse(
|
|
184
|
+
const s = localStorage.getItem(a);
|
|
185
|
+
if (!s) return [];
|
|
186
|
+
const e = JSON.parse(s);
|
|
187
187
|
return Array.isArray(e) ? e.map((t) => new c(t)) : [];
|
|
188
188
|
} catch {
|
|
189
189
|
return [];
|
|
190
190
|
}
|
|
191
191
|
}
|
|
192
|
-
function
|
|
193
|
-
|
|
192
|
+
function p(s) {
|
|
193
|
+
if (typeof localStorage > "u" || !s) return null;
|
|
194
|
+
try {
|
|
195
|
+
const e = localStorage.getItem(a);
|
|
196
|
+
if (!e) return null;
|
|
197
|
+
const t = JSON.parse(e);
|
|
198
|
+
return Array.isArray(t) && t.find((r) => r.id === s) || null;
|
|
199
|
+
} catch {
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
function S(s) {
|
|
204
|
+
const e = new c(s);
|
|
194
205
|
if (typeof localStorage < "u")
|
|
195
206
|
try {
|
|
196
|
-
const t = localStorage.getItem(a),
|
|
207
|
+
const t = localStorage.getItem(a), r = t ? JSON.parse(t) : [], i = Array.isArray(r) ? r : [];
|
|
197
208
|
i.push(e.toJSON()), localStorage.setItem(a, JSON.stringify(i));
|
|
198
209
|
} catch (t) {
|
|
199
210
|
console.error("Failed to save local widget to localStorage:", t);
|
|
200
211
|
}
|
|
201
212
|
return e;
|
|
202
213
|
}
|
|
203
|
-
function
|
|
214
|
+
function A(s) {
|
|
204
215
|
if (!(typeof localStorage > "u"))
|
|
205
216
|
try {
|
|
206
217
|
const e = localStorage.getItem(a);
|
|
207
218
|
if (!e) return;
|
|
208
219
|
const t = JSON.parse(e);
|
|
209
220
|
if (Array.isArray(t)) {
|
|
210
|
-
const
|
|
211
|
-
localStorage.setItem(a, JSON.stringify(
|
|
221
|
+
const r = t.filter((i) => i.id !== s);
|
|
222
|
+
localStorage.setItem(a, JSON.stringify(r));
|
|
212
223
|
}
|
|
213
224
|
} catch (e) {
|
|
214
225
|
console.error("Failed to remove local widget from localStorage:", e);
|
|
215
226
|
}
|
|
216
227
|
}
|
|
228
|
+
function H(s, e) {
|
|
229
|
+
if (typeof localStorage > "u" || !s) return null;
|
|
230
|
+
try {
|
|
231
|
+
const t = localStorage.getItem(a);
|
|
232
|
+
if (!t) return null;
|
|
233
|
+
const r = JSON.parse(t);
|
|
234
|
+
if (!Array.isArray(r)) return null;
|
|
235
|
+
const i = r.findIndex((d) => d.id === s);
|
|
236
|
+
if (i === -1) return null;
|
|
237
|
+
const o = r[i], l = {
|
|
238
|
+
...o,
|
|
239
|
+
...e,
|
|
240
|
+
id: s,
|
|
241
|
+
mainAddress: e.mainAddress !== void 0 ? e.mainAddress.replace(/\/+$/, "") : o.mainAddress
|
|
242
|
+
};
|
|
243
|
+
return r[i] = l, localStorage.setItem(a, JSON.stringify(r)), l;
|
|
244
|
+
} catch (t) {
|
|
245
|
+
return console.error("Failed to update local widget in localStorage:", t), null;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
217
248
|
export {
|
|
218
|
-
|
|
219
|
-
|
|
249
|
+
O as Communicator,
|
|
250
|
+
y as Host,
|
|
220
251
|
a as LOCAL_WIDGETS_STORAGE_KEY,
|
|
221
252
|
c as LocalWidget,
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
253
|
+
E as PING_TOKEN,
|
|
254
|
+
N as PONG_TOKEN,
|
|
255
|
+
S as createLocalWidget,
|
|
256
|
+
p as getLocalWidgetById,
|
|
257
|
+
w as getLocalWidgets,
|
|
258
|
+
m as ping,
|
|
259
|
+
A as removeLocalWidget,
|
|
260
|
+
H as updateLocalWidget
|
|
228
261
|
};
|
|
229
262
|
//# sourceMappingURL=host.js.map
|
package/dist/host.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host.js","sources":["../src/host-sdk.ts"],"sourcesContent":["import { Communicator, ping, PingOptions } from './communicator';\nimport { ActionMap } from './types';\nimport type { ResolvedWidgetManifest } from './manifest';\n\ninterface HostSubscription {\n actionType: keyof ActionMap;\n handler: (payload: any) => any;\n off: (() => void) | null;\n cancelled: boolean;\n}\n\nexport class Host {\n private _communicator: Communicator | null = null;\n\n private iframeWindow: Window;\n\n private subscriptions = new Set<HostSubscription>();\n\n private initPromise: Promise<Communicator> | null = null;\n\n private isDestroyed = false;\n\n private get communicator(): Communicator {\n if (!this._communicator) {\n throw new Error('Host is not initialized. Call init() first.');\n }\n return this._communicator;\n }\n\n /**\n * Initialize Host SDK for a specific iframe widget\n * @param iframeWindow The contentWindow of the widget's iframe\n */\n constructor(iframeWindow: Window) {\n this.iframeWindow = iframeWindow;\n }\n\n /**\n * Register a unified handler for a specific message action type.\n * Can be called before or after `init()`.\n * Returns an unsubscribe function.\n */\n public onMessage<A extends keyof ActionMap>(\n actionType: A,\n handler: (payload: Parameters<ActionMap[A]>[0]) => Promise<ReturnType<ActionMap[A]>> | ReturnType<ActionMap[A]>\n ): () => void {\n const sub: HostSubscription = {\n actionType,\n handler,\n off: null,\n cancelled: false,\n };\n\n if (this._communicator) {\n sub.off = this._communicator.registerHandler(actionType, handler);\n }\n\n this.subscriptions.add(sub);\n\n return () => {\n if (sub.cancelled) return;\n sub.cancelled = true;\n this.subscriptions.delete(sub);\n if (sub.off) {\n sub.off();\n sub.off = null;\n }\n };\n }\n\n /**\n * Send a message/request to the widget and wait for the response.\n */\n public async sendMessage<A extends keyof ActionMap>(\n actionType: A,\n payload?: Parameters<ActionMap[A]>[0],\n timeout?: number\n ): Promise<ReturnType<ActionMap[A]>> {\n if (this._communicator) {\n return this._communicator.sendRequest(actionType, payload, timeout);\n }\n\n if (this.initPromise) {\n const comm = await this.initPromise;\n\n return comm.sendRequest(actionType, payload, timeout);\n }\n\n return this.communicator.sendRequest(actionType, payload, timeout);\n }\n\n /**\n * Complete the handshake with the target widget iframe and attach all registered handlers.\n */\n public async init(options?: PingOptions): Promise<Communicator> {\n if (this.isDestroyed) {\n throw new Error('Host has already been destroyed.');\n }\n\n if (this._communicator) {\n return this._communicator;\n }\n\n if (!this.initPromise) {\n this.initPromise = (async () => {\n try {\n const comm = await ping(this.iframeWindow, options);\n\n if (this.isDestroyed) {\n comm.destroy();\n throw new Error('Host was destroyed during initialization.');\n }\n\n this._communicator = comm;\n\n // Attach all active subscriptions to communicator\n for (const sub of this.subscriptions) {\n if (!sub.cancelled && !sub.off) {\n sub.off = comm.registerHandler(sub.actionType, sub.handler);\n }\n }\n\n return comm;\n } catch (err) {\n this.initPromise = null;\n throw err;\n }\n })();\n }\n\n return this.initPromise;\n }\n\n public destroy(): void {\n this.isDestroyed = true;\n\n for (const sub of this.subscriptions) {\n if (sub.off) {\n sub.off();\n sub.off = null;\n }\n sub.cancelled = true;\n }\n this.subscriptions.clear();\n\n this._communicator?.destroy();\n\n this._communicator = null;\n\n this.initPromise = null;\n }\n}\n\nexport type LocalWidgetProps = {\n id?: string;\n mainAddress: string;\n editorAddress?: string;\n runtimeAddress?: string;\n};\n\nexport type ManifestUpdateHandler = (manifest: ResolvedWidgetManifest) => void;\nexport type ManifestErrorHandler = (errors: Array<{ path: string; message: string }> | string) => void;\nexport type FileChangeHandler = (payload: { file: string; event: string }) => void;\n\nexport class LocalWidget implements LocalWidgetProps {\n id: string;\n\n mainAddress: string;\n\n editorAddress?: string;\n\n runtimeAddress?: string;\n\n manifest: ResolvedWidgetManifest | null = null;\n\n private ws: WebSocket | null = null;\n\n private isDestroyed = false;\n\n private reconnectTimer: any = null;\n\n private manifestUpdateHandlers = new Set<ManifestUpdateHandler>();\n\n private manifestErrorHandlers = new Set<ManifestErrorHandler>();\n\n private fileChangeHandlers = new Set<FileChangeHandler>();\n\n constructor(props: LocalWidgetProps) {\n this.mainAddress = props.mainAddress.replace(/\\/+$/, '');\n this.editorAddress = props.editorAddress;\n this.runtimeAddress = props.runtimeAddress;\n this.id =\n props.id ||\n (typeof crypto !== 'undefined' && crypto.randomUUID\n ? crypto.randomUUID()\n : `${Date.now()}_${Math.random().toString(36).substring(2, 9)}`);\n\n this.initHMR();\n }\n\n /**\n * Initialize WebSocket connection for mini-HMR with the dev server\n */\n public initHMR(): void {\n if (typeof window === 'undefined' || typeof WebSocket === 'undefined') {\n return;\n }\n\n if (this.ws || this.isDestroyed) {\n return;\n }\n\n try {\n const wsUrl = this.mainAddress.replace(/^http(s)?:\\/\\//i, (_, s) => (s ? 'wss://' : 'ws://'));\n const ws = new WebSocket(wsUrl);\n this.ws = ws;\n\n ws.onmessage = (event) => {\n try {\n const msg = JSON.parse(event.data);\n if (msg.type === 'manifest:update' && msg.data) {\n this.manifest = msg.data;\n for (const handler of this.manifestUpdateHandlers) {\n handler(msg.data);\n }\n } else if (msg.type === 'manifest:error') {\n for (const handler of this.manifestErrorHandlers) {\n handler(msg.errors || 'Manifest error');\n }\n } else if (msg.type === 'file:change') {\n for (const handler of this.fileChangeHandlers) {\n handler({ file: msg.file, event: msg.event });\n }\n }\n } catch (e) {\n console.error('[LocalWidget] Failed to parse HMR message:', e);\n }\n };\n\n ws.onerror = () => { };\n\n ws.onclose = () => {\n this.ws = null;\n if (!this.isDestroyed) {\n if (this.reconnectTimer) clearTimeout(this.reconnectTimer);\n this.reconnectTimer = setTimeout(() => {\n if (!this.isDestroyed) {\n this.initHMR();\n }\n }, 3000);\n }\n };\n } catch (e) {\n console.error('[LocalWidget] Failed to initialize WebSocket HMR:', e);\n }\n }\n\n /**\n * Fetch the latest manifest from the dev server via HTTP\n */\n public async fetchManifest(): Promise<ResolvedWidgetManifest | null> {\n if (typeof fetch === 'undefined') return null;\n try {\n const url = `${this.mainAddress}/manifest.json`;\n const res = await fetch(url);\n if (!res.ok) {\n throw new Error(`Failed to fetch manifest: HTTP ${res.status}`);\n }\n const data = (await res.json()) as ResolvedWidgetManifest;\n this.manifest = data;\n return data;\n } catch (e) {\n console.error(`[LocalWidget] Failed to fetch manifest from ${this.mainAddress}:`, e);\n return null;\n }\n }\n\n /**\n * Subscribe to manifest update events\n */\n public onManifestUpdate(handler: ManifestUpdateHandler): () => void {\n this.manifestUpdateHandlers.add(handler);\n if (this.manifest) {\n handler(this.manifest);\n }\n return () => {\n this.manifestUpdateHandlers.delete(handler);\n };\n }\n\n /**\n * Subscribe to manifest validation errors\n */\n public onManifestError(handler: ManifestErrorHandler): () => void {\n this.manifestErrorHandlers.add(handler);\n return () => {\n this.manifestErrorHandlers.delete(handler);\n };\n }\n\n /**\n * Subscribe to file change events in .goodo\n */\n public onFileChange(handler: FileChangeHandler): () => void {\n this.fileChangeHandlers.add(handler);\n return () => {\n this.fileChangeHandlers.delete(handler);\n };\n }\n\n /**\n * Destroy the instance, closing WebSocket and cleaning up timers and listeners\n */\n public destroy(): void {\n this.isDestroyed = true;\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n this.manifestUpdateHandlers.clear();\n this.manifestErrorHandlers.clear();\n this.fileChangeHandlers.clear();\n }\n\n /**\n * JSON serialization helper for localStorage\n */\n public toJSON(): LocalWidgetProps & { id: string } {\n return {\n id: this.id,\n mainAddress: this.mainAddress,\n editorAddress: this.editorAddress,\n runtimeAddress: this.runtimeAddress,\n };\n }\n}\n\nexport const LOCAL_WIDGETS_STORAGE_KEY = 'goodo_local_widgets';\n\nexport function getLocalWidgets(): LocalWidget[] {\n if (typeof localStorage === 'undefined') {\n return [];\n }\n try {\n const raw = localStorage.getItem(LOCAL_WIDGETS_STORAGE_KEY);\n if (!raw) return [];\n const parsed = JSON.parse(raw);\n if (!Array.isArray(parsed)) return [];\n return parsed.map((item: LocalWidgetProps) => new LocalWidget(item));\n } catch {\n return [];\n }\n}\n\nexport function createLocalWidget(props: LocalWidgetProps): LocalWidget {\n const localWidget = new LocalWidget(props);\n\n if (typeof localStorage !== 'undefined') {\n try {\n const raw = localStorage.getItem(LOCAL_WIDGETS_STORAGE_KEY);\n const list = raw ? JSON.parse(raw) : [];\n const validList = Array.isArray(list) ? list : [];\n validList.push(localWidget.toJSON());\n localStorage.setItem(LOCAL_WIDGETS_STORAGE_KEY, JSON.stringify(validList));\n } catch (e) {\n console.error('Failed to save local widget to localStorage:', e);\n }\n }\n\n return localWidget;\n}\n\nexport function removeLocalWidget(id: string): void {\n if (typeof localStorage === 'undefined') return;\n try {\n const raw = localStorage.getItem(LOCAL_WIDGETS_STORAGE_KEY);\n if (!raw) return;\n const list = JSON.parse(raw);\n if (Array.isArray(list)) {\n const filtered = list.filter((item: { id: string }) => item.id !== id);\n localStorage.setItem(LOCAL_WIDGETS_STORAGE_KEY, JSON.stringify(filtered));\n }\n } catch (e) {\n console.error('Failed to remove local widget from localStorage:', e);\n }\n}"],"names":["Host","iframeWindow","__publicField","actionType","handler","sub","payload","timeout","options","comm","ping","err","_a","LocalWidget","props","wsUrl","_","s","ws","event","msg","e","url","res","data","LOCAL_WIDGETS_STORAGE_KEY","getLocalWidgets","raw","parsed","item","createLocalWidget","localWidget","list","validList","removeLocalWidget","id","filtered"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"host.js","sources":["../src/host-sdk.ts"],"sourcesContent":["import { Communicator, ping, PingOptions } from './communicator';\nimport { ActionMap } from './types';\nimport type { ResolvedWidgetManifest } from './manifest';\n\ninterface HostSubscription {\n actionType: keyof ActionMap;\n handler: (payload: any) => any;\n off: (() => void) | null;\n cancelled: boolean;\n}\n\nexport class Host {\n private _communicator: Communicator | null = null;\n\n private iframeWindow: Window;\n\n private subscriptions = new Set<HostSubscription>();\n\n private initPromise: Promise<Communicator> | null = null;\n\n private isDestroyed = false;\n\n private get communicator(): Communicator {\n if (!this._communicator) {\n throw new Error('Host is not initialized. Call init() first.');\n }\n return this._communicator;\n }\n\n /**\n * Initialize Host SDK for a specific iframe widget\n * @param iframeWindow The contentWindow of the widget's iframe\n */\n constructor(iframeWindow: Window) {\n this.iframeWindow = iframeWindow;\n }\n\n /**\n * Register a unified handler for a specific message action type.\n * Can be called before or after `init()`.\n * Returns an unsubscribe function.\n */\n public onMessage<A extends keyof ActionMap>(\n actionType: A,\n handler: (payload: Parameters<ActionMap[A]>[0]) => Promise<ReturnType<ActionMap[A]>> | ReturnType<ActionMap[A]>\n ): () => void {\n const sub: HostSubscription = {\n actionType,\n handler,\n off: null,\n cancelled: false,\n };\n\n if (this._communicator) {\n sub.off = this._communicator.registerHandler(actionType, handler);\n }\n\n this.subscriptions.add(sub);\n\n return () => {\n if (sub.cancelled) return;\n sub.cancelled = true;\n this.subscriptions.delete(sub);\n if (sub.off) {\n sub.off();\n sub.off = null;\n }\n };\n }\n\n /**\n * Send a message/request to the widget and wait for the response.\n */\n public async sendMessage<A extends keyof ActionMap>(\n actionType: A,\n payload?: Parameters<ActionMap[A]>[0],\n timeout?: number\n ): Promise<ReturnType<ActionMap[A]>> {\n if (this._communicator) {\n return this._communicator.sendRequest(actionType, payload, timeout);\n }\n\n if (this.initPromise) {\n const comm = await this.initPromise;\n\n return comm.sendRequest(actionType, payload, timeout);\n }\n\n return this.communicator.sendRequest(actionType, payload, timeout);\n }\n\n /**\n * Complete the handshake with the target widget iframe and attach all registered handlers.\n */\n public async init(options?: PingOptions): Promise<Communicator> {\n if (this.isDestroyed) {\n throw new Error('Host has already been destroyed.');\n }\n\n if (this._communicator) {\n return this._communicator;\n }\n\n if (!this.initPromise) {\n this.initPromise = (async () => {\n try {\n const comm = await ping(this.iframeWindow, options);\n\n if (this.isDestroyed) {\n comm.destroy();\n throw new Error('Host was destroyed during initialization.');\n }\n\n this._communicator = comm;\n\n // Attach all active subscriptions to communicator\n for (const sub of this.subscriptions) {\n if (!sub.cancelled && !sub.off) {\n sub.off = comm.registerHandler(sub.actionType, sub.handler);\n }\n }\n\n return comm;\n } catch (err) {\n this.initPromise = null;\n throw err;\n }\n })();\n }\n\n return this.initPromise;\n }\n\n public destroy(): void {\n this.isDestroyed = true;\n\n for (const sub of this.subscriptions) {\n if (sub.off) {\n sub.off();\n sub.off = null;\n }\n sub.cancelled = true;\n }\n this.subscriptions.clear();\n\n this._communicator?.destroy();\n\n this._communicator = null;\n\n this.initPromise = null;\n }\n}\n\nexport type LocalWidgetProps = {\n id?: string;\n mainAddress: string;\n editorAddress?: string;\n runtimeAddress?: string;\n};\n\nexport type ManifestUpdateHandler = (manifest: ResolvedWidgetManifest) => void;\nexport type ManifestErrorHandler = (errors: Array<{ path: string; message: string }> | string) => void;\nexport type FileChangeHandler = (payload: { file: string; event: string }) => void;\n\nexport class LocalWidget implements LocalWidgetProps {\n id: string;\n\n mainAddress: string;\n\n editorAddress?: string;\n\n runtimeAddress?: string;\n\n manifest: ResolvedWidgetManifest | null = null;\n\n private ws: WebSocket | null = null;\n\n private isDestroyed = false;\n\n private reconnectTimer: any = null;\n\n private manifestUpdateHandlers = new Set<ManifestUpdateHandler>();\n\n private manifestErrorHandlers = new Set<ManifestErrorHandler>();\n\n private fileChangeHandlers = new Set<FileChangeHandler>();\n\n constructor(props: LocalWidgetProps) {\n this.mainAddress = props.mainAddress.replace(/\\/+$/, '');\n this.editorAddress = props.editorAddress;\n this.runtimeAddress = props.runtimeAddress;\n this.id =\n props.id ||\n (typeof crypto !== 'undefined' && crypto.randomUUID\n ? crypto.randomUUID()\n : `${Date.now()}_${Math.random().toString(36).substring(2, 9)}`);\n\n this.initHMR();\n }\n\n /**\n * Initialize WebSocket connection for mini-HMR with the dev server\n */\n public initHMR(): void {\n if (typeof window === 'undefined' || typeof WebSocket === 'undefined') {\n return;\n }\n\n if (this.ws || this.isDestroyed) {\n return;\n }\n\n try {\n const wsUrl = this.mainAddress.replace(/^http(s)?:\\/\\//i, (_, s) => (s ? 'wss://' : 'ws://'));\n const ws = new WebSocket(wsUrl);\n this.ws = ws;\n\n ws.onmessage = (event) => {\n try {\n const msg = JSON.parse(event.data);\n if (msg.type === 'manifest:update' && msg.data) {\n this.manifest = msg.data;\n for (const handler of this.manifestUpdateHandlers) {\n handler(msg.data);\n }\n } else if (msg.type === 'manifest:error') {\n for (const handler of this.manifestErrorHandlers) {\n handler(msg.errors || 'Manifest error');\n }\n } else if (msg.type === 'file:change') {\n for (const handler of this.fileChangeHandlers) {\n handler({ file: msg.file, event: msg.event });\n }\n }\n } catch (e) {\n console.error('[LocalWidget] Failed to parse HMR message:', e);\n }\n };\n\n ws.onerror = () => { };\n\n ws.onclose = () => {\n this.ws = null;\n if (!this.isDestroyed) {\n if (this.reconnectTimer) clearTimeout(this.reconnectTimer);\n this.reconnectTimer = setTimeout(() => {\n if (!this.isDestroyed) {\n this.initHMR();\n }\n }, 3000);\n }\n };\n } catch (e) {\n console.error('[LocalWidget] Failed to initialize WebSocket HMR:', e);\n }\n }\n\n /**\n * Fetch the latest manifest from the dev server via HTTP\n */\n public async fetchManifest(): Promise<ResolvedWidgetManifest | null> {\n if (typeof fetch === 'undefined') return null;\n try {\n const url = `${this.mainAddress}/manifest.json`;\n const res = await fetch(url);\n if (!res.ok) {\n throw new Error(`Failed to fetch manifest: HTTP ${res.status}`);\n }\n const data = (await res.json()) as ResolvedWidgetManifest;\n this.manifest = data;\n return data;\n } catch (e) {\n console.error(`[LocalWidget] Failed to fetch manifest from ${this.mainAddress}:`, e);\n return null;\n }\n }\n\n /**\n * Subscribe to manifest update events\n */\n public onManifestUpdate(handler: ManifestUpdateHandler): () => void {\n this.manifestUpdateHandlers.add(handler);\n if (this.manifest) {\n handler(this.manifest);\n }\n return () => {\n this.manifestUpdateHandlers.delete(handler);\n };\n }\n\n /**\n * Subscribe to manifest validation errors\n */\n public onManifestError(handler: ManifestErrorHandler): () => void {\n this.manifestErrorHandlers.add(handler);\n return () => {\n this.manifestErrorHandlers.delete(handler);\n };\n }\n\n /**\n * Subscribe to file change events in .goodo\n */\n public onFileChange(handler: FileChangeHandler): () => void {\n this.fileChangeHandlers.add(handler);\n return () => {\n this.fileChangeHandlers.delete(handler);\n };\n }\n\n /**\n * Destroy the instance, closing WebSocket and cleaning up timers and listeners\n */\n public destroy(): void {\n this.isDestroyed = true;\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n this.manifestUpdateHandlers.clear();\n this.manifestErrorHandlers.clear();\n this.fileChangeHandlers.clear();\n }\n\n /**\n * JSON serialization helper for localStorage\n */\n public toJSON(): LocalWidgetProps & { id: string } {\n return {\n id: this.id,\n mainAddress: this.mainAddress,\n editorAddress: this.editorAddress,\n runtimeAddress: this.runtimeAddress,\n };\n }\n}\n\nexport const LOCAL_WIDGETS_STORAGE_KEY = 'goodo_local_widgets';\n\nexport function getLocalWidgets(): LocalWidget[] {\n if (typeof localStorage === 'undefined') {\n return [];\n }\n try {\n const raw = localStorage.getItem(LOCAL_WIDGETS_STORAGE_KEY);\n if (!raw) return [];\n const parsed = JSON.parse(raw);\n if (!Array.isArray(parsed)) return [];\n return parsed.map((item: LocalWidgetProps) => new LocalWidget(item));\n } catch {\n return [];\n }\n}\n\nexport function getLocalWidgetById(id?: string): LocalWidgetProps | null {\n if (typeof localStorage === 'undefined' || !id) return null;\n try {\n const raw = localStorage.getItem(LOCAL_WIDGETS_STORAGE_KEY);\n if (!raw) return null;\n const parsed = JSON.parse(raw);\n if (!Array.isArray(parsed)) return null;\n return parsed.find((item: LocalWidgetProps) => item.id === id) || null;\n } catch {\n return null;\n }\n}\n\nexport function createLocalWidget(props: LocalWidgetProps): LocalWidget {\n const localWidget = new LocalWidget(props);\n\n if (typeof localStorage !== 'undefined') {\n try {\n const raw = localStorage.getItem(LOCAL_WIDGETS_STORAGE_KEY);\n const list = raw ? JSON.parse(raw) : [];\n const validList = Array.isArray(list) ? list : [];\n validList.push(localWidget.toJSON());\n localStorage.setItem(LOCAL_WIDGETS_STORAGE_KEY, JSON.stringify(validList));\n } catch (e) {\n console.error('Failed to save local widget to localStorage:', e);\n }\n }\n\n return localWidget;\n}\n\nexport function removeLocalWidget(id: string): void {\n if (typeof localStorage === 'undefined') return;\n try {\n const raw = localStorage.getItem(LOCAL_WIDGETS_STORAGE_KEY);\n if (!raw) return;\n const list = JSON.parse(raw);\n if (Array.isArray(list)) {\n const filtered = list.filter((item: { id: string }) => item.id !== id);\n localStorage.setItem(LOCAL_WIDGETS_STORAGE_KEY, JSON.stringify(filtered));\n }\n } catch (e) {\n console.error('Failed to remove local widget from localStorage:', e);\n }\n}\n\nexport function updateLocalWidget(id: string, props: Partial<LocalWidgetProps>): LocalWidgetProps | null {\n if (typeof localStorage === 'undefined' || !id) return null;\n try {\n const raw = localStorage.getItem(LOCAL_WIDGETS_STORAGE_KEY);\n if (!raw) return null;\n const list = JSON.parse(raw);\n if (!Array.isArray(list)) return null;\n const idx = list.findIndex((item: LocalWidgetProps) => item.id === id);\n if (idx === -1) return null;\n const existing = list[idx];\n const updated: LocalWidgetProps = {\n ...existing,\n ...props,\n id,\n mainAddress: props.mainAddress !== undefined ? props.mainAddress.replace(/\\/+$/, '') : existing.mainAddress\n };\n list[idx] = updated;\n localStorage.setItem(LOCAL_WIDGETS_STORAGE_KEY, JSON.stringify(list));\n return updated;\n } catch (e) {\n console.error('Failed to update local widget in localStorage:', e);\n return null;\n }\n}"],"names":["Host","iframeWindow","__publicField","actionType","handler","sub","payload","timeout","options","comm","ping","err","_a","LocalWidget","props","wsUrl","_","s","ws","event","msg","e","url","res","data","LOCAL_WIDGETS_STORAGE_KEY","getLocalWidgets","raw","parsed","item","getLocalWidgetById","id","createLocalWidget","localWidget","list","validList","removeLocalWidget","filtered","updateLocalWidget","idx","existing","updated"],"mappings":"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"}
|