@goflowstate/widget-sdk 0.1.0

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/README.md ADDED
@@ -0,0 +1,104 @@
1
+ # @goflowstate/widget-sdk
2
+
3
+ SDK for building widgets that run inside the Flowstate Canvas.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @goflowstate/widget-sdk
9
+ ```
10
+
11
+ Or via CDN (no bundler required):
12
+
13
+ ```html
14
+ <script src="https://unpkg.com/@goflowstate/widget-sdk/dist/canvas-widget-sdk.js"></script>
15
+ ```
16
+
17
+ ## Quick Start
18
+
19
+ ### ESM (bundler / TypeScript)
20
+
21
+ ```ts
22
+ import { CanvasWidget } from '@goflowstate/widget-sdk';
23
+
24
+ const widget = await CanvasWidget.init();
25
+
26
+ // React to display state changes
27
+ widget.onStateChange((state) => {
28
+ console.log('Widget state:', state); // 'collapsed' | 'expanding' | 'expanded' | 'collapsing'
29
+ });
30
+
31
+ // Expand into modal view
32
+ document.getElementById('open-btn')?.addEventListener('click', () => {
33
+ widget.requestExpand();
34
+ });
35
+ ```
36
+
37
+ ### Script tag (no bundler)
38
+
39
+ ```html
40
+ <script src="canvas-widget-sdk.js"></script>
41
+ <script>
42
+ CanvasWidget.init().then((widget) => {
43
+ widget.onStateChange((state) => console.log(state));
44
+ });
45
+ </script>
46
+ ```
47
+
48
+ ## Emitting and Subscribing to Events
49
+
50
+ ```ts
51
+ const widget = await CanvasWidget.init();
52
+
53
+ // Broadcast to other widgets on the same canvas
54
+ widget.emit('timer:tick', { remaining: 60 });
55
+
56
+ // Listen for events from other widgets
57
+ const unsub = widget.subscribe('timer:tick', (event) => {
58
+ console.log(event.topic, event.payload);
59
+ });
60
+
61
+ // Stop listening
62
+ unsub();
63
+ ```
64
+
65
+ ## Persistent Storage
66
+
67
+ ```ts
68
+ const widget = await CanvasWidget.init();
69
+
70
+ // Store a value (scoped to this widget installation)
71
+ await widget.storage.set('count', 42);
72
+
73
+ // Retrieve a value
74
+ const count = await widget.storage.get('count');
75
+
76
+ // Remove a value
77
+ await widget.storage.delete('count');
78
+ ```
79
+
80
+ ## User Context and Consent
81
+
82
+ ```ts
83
+ const widget = await CanvasWidget.init();
84
+
85
+ // Request access to user data
86
+ const result = await widget.requestConsent('user:profile', 'Needed to personalise your experience');
87
+ if (result.granted) {
88
+ console.log('User:', widget.user?.displayName);
89
+ }
90
+ ```
91
+
92
+ ## Notifications
93
+
94
+ ```ts
95
+ widget.notify('Saved!', { level: 'info', duration: 3000 });
96
+ ```
97
+
98
+ ## Full API Reference
99
+
100
+ See [`docs/widget-development/`](../../docs/widget-development/) for the complete API reference, manifest format, and hosting guide.
101
+
102
+ ## License
103
+
104
+ MIT
@@ -0,0 +1,477 @@
1
+ // @goflowstate/widget-sdk v0.1.0
2
+ // https://github.com/starteryllp/goflowstate-sdk
3
+
4
+ "use strict";
5
+ var CanvasWidgetSDK = (() => {
6
+ var __defProp = Object.defineProperty;
7
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
8
+ var __getOwnPropNames = Object.getOwnPropertyNames;
9
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
10
+ var __export = (target, all) => {
11
+ for (var name in all)
12
+ __defProp(target, name, { get: all[name], enumerable: true });
13
+ };
14
+ var __copyProps = (to, from, except, desc) => {
15
+ if (from && typeof from === "object" || typeof from === "function") {
16
+ for (let key of __getOwnPropNames(from))
17
+ if (!__hasOwnProp.call(to, key) && key !== except)
18
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
19
+ }
20
+ return to;
21
+ };
22
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
23
+
24
+ // src/sdk.ts
25
+ var sdk_exports = {};
26
+ __export(sdk_exports, {
27
+ CanvasWidget: () => CanvasWidget,
28
+ CanvasWidgetSDKImpl: () => CanvasWidgetSDKImpl
29
+ });
30
+
31
+ // src/service.ts
32
+ function createServiceClient(opts) {
33
+ const fetchImpl = opts.fetchImpl ?? globalThis.fetch.bind(globalThis);
34
+ const baseUrl = opts.baseUrl.replace(/\/+$/, "");
35
+ async function call(path, init, token) {
36
+ const url = `${baseUrl}${path.startsWith("/") ? path : `/${path}`}`;
37
+ const headers = new Headers(init.headers);
38
+ headers.set("authorization", `Bearer ${token}`);
39
+ if (init.body && !headers.has("content-type")) {
40
+ headers.set("content-type", "application/json");
41
+ }
42
+ return fetchImpl(url, { ...init, headers });
43
+ }
44
+ return {
45
+ async fetch(path, init = {}) {
46
+ let token = await opts.getJwt(false);
47
+ let res = await call(path, init, token);
48
+ if (res.status === 401) {
49
+ token = await opts.getJwt(true);
50
+ res = await call(path, init, token);
51
+ }
52
+ if (!res.ok) {
53
+ let body = {};
54
+ try {
55
+ body = await res.json();
56
+ } catch {
57
+ }
58
+ throw new Error(`Widget service request failed (${res.status}): ${body.message ?? ""}`);
59
+ }
60
+ return await res.json();
61
+ }
62
+ };
63
+ }
64
+
65
+ // src/sdk.ts
66
+ var PROTOCOL = "canvas-widget-v1";
67
+ var DEV_MODE_TOKEN = "dev-mode-skip";
68
+ var INIT_TIMEOUT_MS = 5e3;
69
+ var cachedKey = null;
70
+ async function getHmacKey(secret) {
71
+ if (cachedKey && cachedKey.secret === secret) return cachedKey.key;
72
+ const encoded = new TextEncoder().encode(secret);
73
+ const buf = new ArrayBuffer(encoded.byteLength);
74
+ new Uint8Array(buf).set(encoded);
75
+ const key = await crypto.subtle.importKey("raw", buf, { name: "HMAC", hash: "SHA-256" }, false, [
76
+ "sign"
77
+ ]);
78
+ cachedKey = { secret, key };
79
+ return key;
80
+ }
81
+ async function signToken(secret, type, widgetId, nonce, timestamp) {
82
+ const key = await getHmacKey(secret);
83
+ const data = new TextEncoder().encode(`${type}:${widgetId}:${nonce}:${timestamp}`);
84
+ const buf = new ArrayBuffer(data.byteLength);
85
+ new Uint8Array(buf).set(data);
86
+ const sig = await crypto.subtle.sign("HMAC", key, buf);
87
+ return Array.from(new Uint8Array(sig)).map((b) => b.toString(16).padStart(2, "0")).join("");
88
+ }
89
+ var CanvasWidgetSDKImpl = class {
90
+ _widgetId;
91
+ _state;
92
+ _hmacSecret;
93
+ _user;
94
+ _widgetApiUrl;
95
+ _widgetApiToken;
96
+ _installationId;
97
+ _pendingConsents = /* @__PURE__ */ new Map();
98
+ _cachedJwt = null;
99
+ _stateListeners = [];
100
+ _displayState = "collapsed";
101
+ _displayStateCallbacks = [];
102
+ _focused = false;
103
+ _focusCallbacks = [];
104
+ _settingsRemoteListeners = [];
105
+ _eventListeners = /* @__PURE__ */ new Map();
106
+ _settings;
107
+ _messageHandler;
108
+ /** Authenticated HTTP client scoped to the widget's declared service URL. Undefined when no service is declared. */
109
+ service;
110
+ constructor(init) {
111
+ this._widgetId = init.widgetId;
112
+ this._state = init.state;
113
+ this._hmacSecret = init.hmacSecret;
114
+ this._user = init.user;
115
+ this._widgetApiUrl = init.widgetApiUrl;
116
+ this._widgetApiToken = init.widgetApiToken ?? null;
117
+ this._installationId = init.installationId;
118
+ this._settings = init.settings ?? {};
119
+ if (init.serviceUrl) {
120
+ this.service = createServiceClient({
121
+ baseUrl: init.serviceUrl,
122
+ getJwt: (forceRefresh) => this.getJwt(forceRefresh)
123
+ });
124
+ }
125
+ this._messageHandler = this.handleMessage.bind(this);
126
+ window.addEventListener("message", this._messageHandler);
127
+ }
128
+ /** The unique identifier for this widget instance on the canvas. */
129
+ get widgetId() {
130
+ return this._widgetId;
131
+ }
132
+ /** The current display state of the widget (collapsed, expanding, expanded, collapsing). */
133
+ get state() {
134
+ return this._state;
135
+ }
136
+ /** The authenticated user context, or null when user data access has not been granted. */
137
+ get user() {
138
+ return this._user;
139
+ }
140
+ /** Subscribe to display state changes; returns an unsubscribe function. */
141
+ onStateChange(cb) {
142
+ this._stateListeners.push(cb);
143
+ return () => {
144
+ const idx = this._stateListeners.indexOf(cb);
145
+ if (idx !== -1) this._stateListeners.splice(idx, 1);
146
+ };
147
+ }
148
+ /** Ask the canvas host to expand this widget into its modal view. */
149
+ requestExpand() {
150
+ this.send("EXPAND_REQUEST", {});
151
+ }
152
+ /** Ask the canvas host to collapse this widget back to its tile view. */
153
+ requestCollapse() {
154
+ this.send("COLLAPSE_REQUEST", {});
155
+ }
156
+ /** Get the current display state */
157
+ getDisplayState() {
158
+ return this._displayState;
159
+ }
160
+ /** Register a callback for display state changes */
161
+ onDisplayStateChange(callback) {
162
+ this._displayStateCallbacks.push(callback);
163
+ return () => {
164
+ this._displayStateCallbacks = this._displayStateCallbacks.filter((cb) => cb !== callback);
165
+ };
166
+ }
167
+ /** Is this widget the user's current focus? Updates via FOCUS_CHANGE. */
168
+ isFocused() {
169
+ return this._focused;
170
+ }
171
+ /** Subscribe to focus transitions. Returns an unsubscribe function. */
172
+ onFocusChange(callback) {
173
+ this._focusCallbacks.push(callback);
174
+ return () => {
175
+ this._focusCallbacks = this._focusCallbacks.filter((cb) => cb !== callback);
176
+ };
177
+ }
178
+ /** Request promotion to fullscreen from partial */
179
+ requestFullscreen() {
180
+ this.send("FULLSCREEN_REQUEST", {});
181
+ }
182
+ /** Broadcast an event on the given topic to all subscribed widgets on the canvas. */
183
+ emit(topic, payload) {
184
+ this.send("EVENT_EMIT", { topic, payload });
185
+ }
186
+ /** Subscribe to events on the given topic; returns an unsubscribe function. */
187
+ subscribe(topic, cb) {
188
+ const list = this._eventListeners.get(topic) ?? [];
189
+ list.push(cb);
190
+ this._eventListeners.set(topic, list);
191
+ return () => {
192
+ const current = this._eventListeners.get(topic);
193
+ if (!current) return;
194
+ const idx = current.indexOf(cb);
195
+ if (idx !== -1) current.splice(idx, 1);
196
+ };
197
+ }
198
+ /** Send a structured log entry to the canvas host for centralized debugging. */
199
+ log(level, message, data) {
200
+ this.send("LOG", { level, message, data: data ?? null });
201
+ }
202
+ /** Request user consent for a named data scope; resolves with the consent decision. */
203
+ async requestConsent(scope, reason) {
204
+ return new Promise((resolve, reject) => {
205
+ const timeout = setTimeout(() => {
206
+ this._pendingConsents.delete(scope);
207
+ reject(new Error("Consent request timed out"));
208
+ }, 6e4);
209
+ this._pendingConsents.set(scope, {
210
+ resolve: (r) => {
211
+ clearTimeout(timeout);
212
+ resolve(r);
213
+ },
214
+ reject: (e) => {
215
+ clearTimeout(timeout);
216
+ reject(e);
217
+ }
218
+ });
219
+ this.send("CONSENT_REQUEST", { scope, reason });
220
+ });
221
+ }
222
+ /** Return the cached JWT for authenticating requests to external APIs; throws if no token is available. Pass forceRefresh=true to bypass the cache. */
223
+ async getJwt(forceRefresh) {
224
+ if (!forceRefresh && this._cachedJwt && Date.now() < this._cachedJwt.expiresAt - 3e4) {
225
+ return this._cachedJwt.token;
226
+ }
227
+ throw new Error("No cached JWT \u2014 widget must use OAuth flow for token refresh");
228
+ }
229
+ /** Persistent key-value storage scoped to this widget installation. */
230
+ get storage() {
231
+ return {
232
+ get: (key) => this.storageRequest("GET", key),
233
+ set: (key, value) => this.storageRequest("PUT", key, value).then(() => {
234
+ }),
235
+ delete: (key) => this.storageRequest("DELETE", key).then(() => {
236
+ })
237
+ };
238
+ }
239
+ /** Ad-hoc collections/records backend scoped to the canvas/room. */
240
+ get db() {
241
+ const req = (path, method, body) => this.widgetApiRequest(path, method, body);
242
+ return {
243
+ collection(name) {
244
+ const base = `/widget-api/db/${encodeURIComponent(name)}`;
245
+ return {
246
+ create: (data) => req(base, "POST", data),
247
+ get: (id) => req(`${base}/${encodeURIComponent(id)}`, "GET"),
248
+ list: (opts) => {
249
+ const qs = new URLSearchParams();
250
+ if (opts?.limit != null) qs.set("limit", String(opts.limit));
251
+ if (opts?.cursor) qs.set("cursor", opts.cursor);
252
+ if (opts?.sort) qs.set("sort", opts.sort);
253
+ if (opts?.mine) qs.set("mine", "true");
254
+ const suffix = qs.toString() ? `?${qs.toString()}` : "";
255
+ return req(`${base}${suffix}`, "GET");
256
+ },
257
+ update: (id, patch) => req(`${base}/${encodeURIComponent(id)}`, "PATCH", patch),
258
+ delete: (id) => req(`${base}/${encodeURIComponent(id)}`, "DELETE").then(() => {
259
+ })
260
+ };
261
+ }
262
+ };
263
+ }
264
+ /** Widget configuration settings persisted by the canvas host. */
265
+ get settings() {
266
+ return {
267
+ get: () => ({ ...this._settings }),
268
+ set: (newSettings) => {
269
+ this._settings = { ...this._settings, ...newSettings };
270
+ this.send("SETTINGS_WRITE", { settings: this._settings });
271
+ },
272
+ onRemoteChange: (cb) => {
273
+ this._settingsRemoteListeners.push(cb);
274
+ return () => {
275
+ this._settingsRemoteListeners = this._settingsRemoteListeners.filter((fn) => fn !== cb);
276
+ };
277
+ }
278
+ };
279
+ }
280
+ /** Display a toast notification in the canvas host UI. */
281
+ async notify(message, opts) {
282
+ this.send("NOTIFICATION", {
283
+ message,
284
+ level: opts?.level ?? "info",
285
+ duration: opts?.duration ?? 5e3
286
+ });
287
+ }
288
+ // ── Private ─────────────────────────────────────────────────
289
+ async widgetApiRequest(path, method, body) {
290
+ if (!this._widgetApiUrl) {
291
+ throw new Error("Widget API Gateway URL not available");
292
+ }
293
+ const url = `${this._widgetApiUrl}${path}`;
294
+ const headers = { "Content-Type": "application/json" };
295
+ if (this._widgetApiToken) {
296
+ headers["Authorization"] = `Bearer ${this._widgetApiToken}`;
297
+ }
298
+ const opts = { method, headers };
299
+ if (body !== void 0 && method !== "GET" && method !== "DELETE") {
300
+ opts.body = JSON.stringify(body);
301
+ }
302
+ const response = await fetch(url, opts);
303
+ if (!response.ok) {
304
+ const err = await response.json().catch(() => ({}));
305
+ throw new Error(err.message ?? `Request ${method} ${path} failed`);
306
+ }
307
+ if (method === "GET" || method === "POST" || method === "PATCH") {
308
+ const result = await response.json();
309
+ return result.data;
310
+ }
311
+ return void 0;
312
+ }
313
+ storageRequest(method, key, value) {
314
+ return this.widgetApiRequest(`/widget-api/storage/${encodeURIComponent(key)}`, method, value);
315
+ }
316
+ handleMessage(event) {
317
+ const msg = event.data;
318
+ if (!msg || typeof msg !== "object" || msg.protocol !== PROTOCOL) return;
319
+ switch (msg.type) {
320
+ case "STATE_CHANGE": {
321
+ const payload = msg.payload;
322
+ this._state = payload.state;
323
+ for (const listener of this._stateListeners) {
324
+ listener(payload.state);
325
+ }
326
+ break;
327
+ }
328
+ case "EVENT_BROADCAST": {
329
+ const payload = msg.payload;
330
+ const listeners = this._eventListeners.get(payload.topic);
331
+ if (listeners) {
332
+ const evt = {
333
+ topic: payload.topic,
334
+ payload: payload.payload,
335
+ emittedAt: payload.emittedAt
336
+ };
337
+ for (const listener of listeners) {
338
+ listener(evt);
339
+ }
340
+ }
341
+ break;
342
+ }
343
+ case "CONSENT_RESULT": {
344
+ const payload = msg.payload;
345
+ const pending = this._pendingConsents.get(payload.scope);
346
+ if (pending) {
347
+ this._pendingConsents.delete(payload.scope);
348
+ pending.resolve({
349
+ scope: payload.scope,
350
+ granted: payload.granted,
351
+ grantToken: payload.grantToken,
352
+ expiresIn: payload.expiresIn
353
+ });
354
+ }
355
+ break;
356
+ }
357
+ case "AUTH_TOKEN_REFRESH": {
358
+ const payload = msg.payload;
359
+ this._cachedJwt = {
360
+ token: payload.token,
361
+ expiresAt: Date.now() + payload.expiresIn * 1e3
362
+ };
363
+ break;
364
+ }
365
+ case "DISPLAY_STATE_CHANGE": {
366
+ const newState = msg.payload?.displayState;
367
+ if (newState) {
368
+ this._displayState = newState;
369
+ this._displayStateCallbacks.forEach((cb) => cb(newState));
370
+ }
371
+ break;
372
+ }
373
+ case "FOCUS_CHANGE": {
374
+ const next = !!msg.payload?.focused;
375
+ if (next !== this._focused) {
376
+ this._focused = next;
377
+ this._focusCallbacks.forEach((cb) => cb(next));
378
+ }
379
+ break;
380
+ }
381
+ case "SETTINGS_REMOTE_UPDATE": {
382
+ const p = msg.payload;
383
+ this._settings = { ...p.settings };
384
+ for (const fn of this._settingsRemoteListeners) {
385
+ try {
386
+ fn({ ...this._settings });
387
+ } catch {
388
+ }
389
+ }
390
+ break;
391
+ }
392
+ case "USER_CONTEXT":
393
+ case "CANVAS_CONTEXT":
394
+ break;
395
+ }
396
+ }
397
+ send(type, payload) {
398
+ this.buildMessage(type, payload).then((msg) => {
399
+ window.parent.postMessage(msg, "*");
400
+ });
401
+ }
402
+ async buildMessage(type, payload) {
403
+ const nonce = crypto.randomUUID();
404
+ const timestamp = Date.now();
405
+ let token;
406
+ if (this._hmacSecret) {
407
+ token = await signToken(this._hmacSecret, type, this._widgetId, nonce, timestamp);
408
+ } else {
409
+ token = DEV_MODE_TOKEN;
410
+ }
411
+ return {
412
+ protocol: PROTOCOL,
413
+ type,
414
+ widgetId: this._widgetId,
415
+ nonce,
416
+ timestamp,
417
+ token,
418
+ payload
419
+ };
420
+ }
421
+ /** Tear down the SDK instance, remove all listeners, and reject pending consent requests. */
422
+ destroy() {
423
+ window.removeEventListener("message", this._messageHandler);
424
+ this._stateListeners.length = 0;
425
+ this._eventListeners.clear();
426
+ for (const [, pending] of this._pendingConsents) {
427
+ pending.reject(new Error("Widget destroyed"));
428
+ }
429
+ this._pendingConsents.clear();
430
+ }
431
+ };
432
+ var CanvasWidget = {
433
+ /**
434
+ * Initialize the SDK and establish communication with the canvas host.
435
+ *
436
+ * Sends a READY message to the host and waits for an INIT response.
437
+ * Resolves with a fully initialized {@link CanvasWidgetSDK} instance.
438
+ * Rejects after 5 seconds if no INIT is received from the host.
439
+ */
440
+ init() {
441
+ return new Promise((resolve, reject) => {
442
+ const timeout = setTimeout(() => {
443
+ window.removeEventListener("message", handler);
444
+ reject(new Error("CanvasWidget.init() timed out \u2014 no INIT received from host within 5s"));
445
+ }, INIT_TIMEOUT_MS);
446
+ const handler = (event) => {
447
+ const msg = event.data;
448
+ if (!msg || typeof msg !== "object" || msg.protocol !== PROTOCOL) return;
449
+ if (msg.type !== "INIT") return;
450
+ clearTimeout(timeout);
451
+ window.removeEventListener("message", handler);
452
+ const payload = msg.payload;
453
+ const sdk = new CanvasWidgetSDKImpl(payload);
454
+ resolve(sdk);
455
+ };
456
+ window.addEventListener("message", handler);
457
+ const readyMsg = {
458
+ protocol: PROTOCOL,
459
+ type: "READY",
460
+ widgetId: "",
461
+ // Not yet known — host identifies us by iframe source
462
+ nonce: crypto.randomUUID(),
463
+ timestamp: Date.now(),
464
+ token: DEV_MODE_TOKEN,
465
+ // READY is always allowed, token doesn't matter
466
+ payload: { manifestVersion: "1" }
467
+ };
468
+ window.parent.postMessage(readyMsg, "*");
469
+ });
470
+ }
471
+ };
472
+ return __toCommonJS(sdk_exports);
473
+ })();
474
+
475
+ // Expose CanvasWidget on the global scope
476
+ if (typeof window !== "undefined") { window.CanvasWidget = CanvasWidgetSDK.CanvasWidget; }
477
+ //# sourceMappingURL=canvas-widget-sdk.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/sdk.ts", "../src/service.ts"],
4
+ "sourcesContent": ["// ============================================\n// Canvas Widget SDK \u2014 runs inside widget iframes\n// ============================================\n//\n// Usage in a widget:\n// <script src=\"canvas-widget-sdk.js\"></script>\n// <script>\n// const widget = await CanvasWidget.init();\n// widget.onStateChange(state => { ... });\n// </script>\n\nimport type {\n CanvasWidgetSDK,\n WidgetDisplayState,\n WidgetEvent,\n InitPayload,\n StateChangePayload,\n EventBroadcastPayload,\n ConsentResult,\n ConsentResultPayload,\n UserContext,\n StorageAPI,\n SettingsAPI,\n WidgetServiceClient,\n DbAPI,\n DbCollection,\n DbRecord,\n DbListOptions,\n} from './types';\nimport { createServiceClient } from './service';\n\nconst PROTOCOL = 'canvas-widget-v1';\nconst DEV_MODE_TOKEN = 'dev-mode-skip';\nconst INIT_TIMEOUT_MS = 5000;\n\ninterface CanvasMessage {\n protocol: string;\n type: string;\n widgetId: string;\n nonce: string;\n timestamp: number;\n token: string;\n payload: Record<string, unknown>;\n}\n\n// ============================================\n// HMAC utilities (mirrored from host side)\n// ============================================\n\nlet cachedKey: { secret: string; key: CryptoKey } | null = null;\n\nasync function getHmacKey(secret: string): Promise<CryptoKey> {\n if (cachedKey && cachedKey.secret === secret) return cachedKey.key;\n\n const encoded = new TextEncoder().encode(secret);\n const buf = new ArrayBuffer(encoded.byteLength);\n new Uint8Array(buf).set(encoded);\n\n const key = await crypto.subtle.importKey('raw', buf, { name: 'HMAC', hash: 'SHA-256' }, false, [\n 'sign',\n ]);\n\n cachedKey = { secret, key };\n return key;\n}\n\nasync function signToken(\n secret: string,\n type: string,\n widgetId: string,\n nonce: string,\n timestamp: number\n): Promise<string> {\n const key = await getHmacKey(secret);\n const data = new TextEncoder().encode(`${type}:${widgetId}:${nonce}:${timestamp}`);\n const buf = new ArrayBuffer(data.byteLength);\n new Uint8Array(buf).set(data);\n const sig = await crypto.subtle.sign('HMAC', key, buf);\n return Array.from(new Uint8Array(sig))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n\n// ============================================\n// SDK Implementation\n// ============================================\n\n/** Internal SDK implementation \u2014 not exposed directly to widget authors. */\nexport class CanvasWidgetSDKImpl implements CanvasWidgetSDK {\n private _widgetId: string;\n private _state: WidgetDisplayState;\n private _hmacSecret: string | null;\n private _user: UserContext | null;\n private _widgetApiUrl: string | null;\n private _widgetApiToken: string | null;\n private _installationId: string;\n private _pendingConsents = new Map<\n string,\n { resolve: (r: ConsentResult) => void; reject: (e: Error) => void }\n >();\n private _cachedJwt: { token: string; expiresAt: number } | null = null;\n private _stateListeners: Array<(state: WidgetDisplayState) => void> = [];\n private _displayState: WidgetDisplayState = 'collapsed';\n private _displayStateCallbacks: Array<(state: WidgetDisplayState) => void> = [];\n private _focused = false;\n private _focusCallbacks: Array<(focused: boolean) => void> = [];\n private _settingsRemoteListeners: Array<(settings: Record<string, unknown>) => void> = [];\n private _eventListeners = new Map<string, Array<(event: WidgetEvent) => void>>();\n private _settings: Record<string, unknown>;\n private _messageHandler: (event: MessageEvent) => void;\n\n /** Authenticated HTTP client scoped to the widget's declared service URL. Undefined when no service is declared. */\n readonly service: WidgetServiceClient | undefined;\n\n constructor(init: InitPayload) {\n this._widgetId = init.widgetId;\n this._state = init.state;\n this._hmacSecret = init.hmacSecret;\n this._user = init.user;\n this._widgetApiUrl = init.widgetApiUrl;\n this._widgetApiToken = init.widgetApiToken ?? null;\n this._installationId = init.installationId;\n this._settings = init.settings ?? {};\n\n // Wire sdk.service when the host provides a service URL from the manifest\n if (init.serviceUrl) {\n this.service = createServiceClient({\n baseUrl: init.serviceUrl,\n getJwt: (forceRefresh?: boolean) => this.getJwt(forceRefresh),\n });\n }\n\n this._messageHandler = this.handleMessage.bind(this);\n window.addEventListener('message', this._messageHandler);\n }\n\n /** The unique identifier for this widget instance on the canvas. */\n get widgetId(): string {\n return this._widgetId;\n }\n\n /** The current display state of the widget (collapsed, expanding, expanded, collapsing). */\n get state(): WidgetDisplayState {\n return this._state;\n }\n\n /** The authenticated user context, or null when user data access has not been granted. */\n get user(): UserContext | null {\n return this._user;\n }\n\n /** Subscribe to display state changes; returns an unsubscribe function. */\n onStateChange(cb: (state: WidgetDisplayState) => void): () => void {\n this._stateListeners.push(cb);\n return () => {\n const idx = this._stateListeners.indexOf(cb);\n if (idx !== -1) this._stateListeners.splice(idx, 1);\n };\n }\n\n /** Ask the canvas host to expand this widget into its modal view. */\n requestExpand(): void {\n this.send('EXPAND_REQUEST', {});\n }\n\n /** Ask the canvas host to collapse this widget back to its tile view. */\n requestCollapse(): void {\n this.send('COLLAPSE_REQUEST', {});\n }\n\n /** Get the current display state */\n getDisplayState(): WidgetDisplayState {\n return this._displayState;\n }\n\n /** Register a callback for display state changes */\n onDisplayStateChange(callback: (state: WidgetDisplayState) => void): () => void {\n this._displayStateCallbacks.push(callback);\n return () => {\n this._displayStateCallbacks = this._displayStateCallbacks.filter((cb) => cb !== callback);\n };\n }\n\n /** Is this widget the user's current focus? Updates via FOCUS_CHANGE. */\n isFocused(): boolean {\n return this._focused;\n }\n\n /** Subscribe to focus transitions. Returns an unsubscribe function. */\n onFocusChange(callback: (focused: boolean) => void): () => void {\n this._focusCallbacks.push(callback);\n return () => {\n this._focusCallbacks = this._focusCallbacks.filter((cb) => cb !== callback);\n };\n }\n\n /** Request promotion to fullscreen from partial */\n requestFullscreen(): void {\n this.send('FULLSCREEN_REQUEST', {});\n }\n\n /** Broadcast an event on the given topic to all subscribed widgets on the canvas. */\n emit(topic: string, payload: unknown): void {\n this.send('EVENT_EMIT', { topic, payload });\n }\n\n /** Subscribe to events on the given topic; returns an unsubscribe function. */\n subscribe(topic: string, cb: (event: WidgetEvent) => void): () => void {\n const list = this._eventListeners.get(topic) ?? [];\n list.push(cb);\n this._eventListeners.set(topic, list);\n return () => {\n const current = this._eventListeners.get(topic);\n if (!current) return;\n const idx = current.indexOf(cb);\n if (idx !== -1) current.splice(idx, 1);\n };\n }\n\n /** Send a structured log entry to the canvas host for centralized debugging. */\n log(level: 'info' | 'warn' | 'error', message: string, data?: unknown): void {\n this.send('LOG', { level, message, data: data ?? null });\n }\n\n /** Request user consent for a named data scope; resolves with the consent decision. */\n async requestConsent(scope: string, reason: string): Promise<ConsentResult> {\n return new Promise<ConsentResult>((resolve, reject) => {\n const timeout = setTimeout(() => {\n this._pendingConsents.delete(scope);\n reject(new Error('Consent request timed out'));\n }, 60000);\n\n this._pendingConsents.set(scope, {\n resolve: (r: ConsentResult) => {\n clearTimeout(timeout);\n resolve(r);\n },\n reject: (e: Error) => {\n clearTimeout(timeout);\n reject(e);\n },\n });\n\n this.send('CONSENT_REQUEST', { scope, reason });\n });\n }\n\n /** Return the cached JWT for authenticating requests to external APIs; throws if no token is available. Pass forceRefresh=true to bypass the cache. */\n async getJwt(forceRefresh?: boolean): Promise<string> {\n if (!forceRefresh && this._cachedJwt && Date.now() < this._cachedJwt.expiresAt - 30000) {\n return this._cachedJwt.token;\n }\n throw new Error('No cached JWT \u2014 widget must use OAuth flow for token refresh');\n }\n\n /** Persistent key-value storage scoped to this widget installation. */\n get storage(): StorageAPI {\n return {\n get: (key: string) => this.storageRequest('GET', key),\n set: (key: string, value: unknown) => this.storageRequest('PUT', key, value).then(() => {}),\n delete: (key: string) => this.storageRequest('DELETE', key).then(() => {}),\n };\n }\n\n /** Ad-hoc collections/records backend scoped to the canvas/room. */\n get db(): DbAPI {\n const req = (path: string, method: string, body?: unknown) => this.widgetApiRequest(path, method, body);\n return {\n collection(name: string): DbCollection {\n const base = `/widget-api/db/${encodeURIComponent(name)}`;\n return {\n create: (data) => req(base, 'POST', data) as Promise<DbRecord>,\n get: (id) => req(`${base}/${encodeURIComponent(id)}`, 'GET') as Promise<DbRecord>,\n list: (opts?: DbListOptions) => {\n const qs = new URLSearchParams();\n if (opts?.limit != null) qs.set('limit', String(opts.limit));\n if (opts?.cursor) qs.set('cursor', opts.cursor);\n if (opts?.sort) qs.set('sort', opts.sort);\n if (opts?.mine) qs.set('mine', 'true');\n const suffix = qs.toString() ? `?${qs.toString()}` : '';\n return req(`${base}${suffix}`, 'GET') as Promise<DbRecord[]>;\n },\n update: (id, patch) => req(`${base}/${encodeURIComponent(id)}`, 'PATCH', patch) as Promise<DbRecord>,\n delete: (id) => (req(`${base}/${encodeURIComponent(id)}`, 'DELETE') as Promise<unknown>).then(() => {}),\n };\n },\n };\n }\n\n /** Widget configuration settings persisted by the canvas host. */\n get settings(): SettingsAPI {\n return {\n get: () => ({ ...this._settings }),\n set: (newSettings: Record<string, unknown>) => {\n this._settings = { ...this._settings, ...newSettings };\n this.send('SETTINGS_WRITE', { settings: this._settings });\n },\n onRemoteChange: (cb: (settings: Record<string, unknown>) => void) => {\n this._settingsRemoteListeners.push(cb);\n return () => {\n this._settingsRemoteListeners = this._settingsRemoteListeners.filter((fn) => fn !== cb);\n };\n },\n };\n }\n\n /** Display a toast notification in the canvas host UI. */\n async notify(message: string, opts?: { level?: string; duration?: number }): Promise<void> {\n this.send('NOTIFICATION', {\n message,\n level: opts?.level ?? 'info',\n duration: opts?.duration ?? 5000,\n });\n }\n\n // \u2500\u2500 Private \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private async widgetApiRequest(path: string, method: string, body?: unknown): Promise<unknown> {\n if (!this._widgetApiUrl) {\n throw new Error('Widget API Gateway URL not available');\n }\n const url = `${this._widgetApiUrl}${path}`;\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n if (this._widgetApiToken) {\n headers['Authorization'] = `Bearer ${this._widgetApiToken}`;\n }\n const opts: RequestInit = { method, headers };\n if (body !== undefined && method !== 'GET' && method !== 'DELETE') {\n opts.body = JSON.stringify(body);\n }\n const response = await fetch(url, opts);\n if (!response.ok) {\n const err = await response.json().catch(() => ({}));\n throw new Error((err as Record<string, string>).message ?? `Request ${method} ${path} failed`);\n }\n if (method === 'GET' || method === 'POST' || method === 'PATCH') {\n const result = await response.json();\n return (result as Record<string, unknown>).data;\n }\n return undefined;\n }\n\n private storageRequest(method: string, key: string, value?: unknown): Promise<unknown> {\n return this.widgetApiRequest(`/widget-api/storage/${encodeURIComponent(key)}`, method, value);\n }\n\n private handleMessage(event: MessageEvent): void {\n const msg = event.data;\n if (!msg || typeof msg !== 'object' || msg.protocol !== PROTOCOL) return;\n\n switch (msg.type) {\n case 'STATE_CHANGE': {\n const payload = msg.payload as StateChangePayload;\n this._state = payload.state;\n for (const listener of this._stateListeners) {\n listener(payload.state);\n }\n break;\n }\n case 'EVENT_BROADCAST': {\n const payload = msg.payload as EventBroadcastPayload;\n const listeners = this._eventListeners.get(payload.topic);\n if (listeners) {\n const evt: WidgetEvent = {\n topic: payload.topic,\n payload: payload.payload,\n emittedAt: payload.emittedAt,\n };\n for (const listener of listeners) {\n listener(evt);\n }\n }\n break;\n }\n case 'CONSENT_RESULT': {\n const payload = msg.payload as ConsentResultPayload;\n const pending = this._pendingConsents.get(payload.scope);\n if (pending) {\n this._pendingConsents.delete(payload.scope);\n pending.resolve({\n scope: payload.scope,\n granted: payload.granted,\n grantToken: payload.grantToken,\n expiresIn: payload.expiresIn,\n });\n }\n break;\n }\n case 'AUTH_TOKEN_REFRESH': {\n const payload = msg.payload as { token: string; expiresIn: number };\n this._cachedJwt = {\n token: payload.token,\n expiresAt: Date.now() + payload.expiresIn * 1000,\n };\n break;\n }\n case 'DISPLAY_STATE_CHANGE': {\n const newState = msg.payload?.displayState as WidgetDisplayState;\n if (newState) {\n this._displayState = newState;\n this._displayStateCallbacks.forEach((cb) => cb(newState));\n }\n break;\n }\n case 'FOCUS_CHANGE': {\n const next = !!msg.payload?.focused;\n if (next !== this._focused) {\n this._focused = next;\n this._focusCallbacks.forEach((cb) => cb(next));\n }\n break;\n }\n case 'SETTINGS_REMOTE_UPDATE': {\n const p = msg.payload as { settings: Record<string, unknown> };\n this._settings = { ...p.settings };\n for (const fn of this._settingsRemoteListeners) {\n try {\n fn({ ...this._settings });\n } catch {\n // a listener throwing must not break message handling\n }\n }\n break;\n }\n case 'USER_CONTEXT':\n case 'CANVAS_CONTEXT':\n // Phase 3+ \u2014 reserved for future use\n break;\n }\n }\n\n private send(type: string, payload: Record<string, unknown>): void {\n // Fire and forget \u2014 sign is async but we don't need to await delivery\n this.buildMessage(type, payload).then((msg) => {\n window.parent.postMessage(msg, '*');\n });\n }\n\n private async buildMessage(\n type: string,\n payload: Record<string, unknown>\n ): Promise<CanvasMessage> {\n const nonce = crypto.randomUUID();\n const timestamp = Date.now();\n\n let token: string;\n if (this._hmacSecret) {\n token = await signToken(this._hmacSecret, type, this._widgetId, nonce, timestamp);\n } else {\n token = DEV_MODE_TOKEN;\n }\n\n return {\n protocol: PROTOCOL,\n type,\n widgetId: this._widgetId,\n nonce,\n timestamp,\n token,\n payload,\n };\n }\n\n /** Tear down the SDK instance, remove all listeners, and reject pending consent requests. */\n destroy(): void {\n window.removeEventListener('message', this._messageHandler);\n this._stateListeners.length = 0;\n this._eventListeners.clear();\n for (const [, pending] of this._pendingConsents) {\n pending.reject(new Error('Widget destroyed'));\n }\n this._pendingConsents.clear();\n }\n}\n\n// ============================================\n// Public API: CanvasWidget.init()\n// ============================================\n\n/**\n * Entry point for the Flowstate Canvas Widget SDK.\n *\n * Usage:\n * ```ts\n * import { CanvasWidget } from '@goflowstate/widget-sdk';\n * const widget = await CanvasWidget.init();\n * ```\n */\nexport const CanvasWidget = {\n /**\n * Initialize the SDK and establish communication with the canvas host.\n *\n * Sends a READY message to the host and waits for an INIT response.\n * Resolves with a fully initialized {@link CanvasWidgetSDK} instance.\n * Rejects after 5 seconds if no INIT is received from the host.\n */\n init(): Promise<CanvasWidgetSDK> {\n return new Promise<CanvasWidgetSDK>((resolve, reject) => {\n const timeout = setTimeout(() => {\n window.removeEventListener('message', handler);\n reject(new Error('CanvasWidget.init() timed out \u2014 no INIT received from host within 5s'));\n }, INIT_TIMEOUT_MS);\n\n const handler = (event: MessageEvent) => {\n const msg = event.data;\n if (!msg || typeof msg !== 'object' || msg.protocol !== PROTOCOL) return;\n if (msg.type !== 'INIT') return;\n\n clearTimeout(timeout);\n window.removeEventListener('message', handler);\n\n const payload = msg.payload as InitPayload;\n const sdk = new CanvasWidgetSDKImpl(payload);\n resolve(sdk);\n };\n\n window.addEventListener('message', handler);\n\n // Send READY to host \u2014 the host will respond with INIT\n const readyMsg: CanvasMessage = {\n protocol: PROTOCOL,\n type: 'READY',\n widgetId: '', // Not yet known \u2014 host identifies us by iframe source\n nonce: crypto.randomUUID(),\n timestamp: Date.now(),\n token: DEV_MODE_TOKEN, // READY is always allowed, token doesn't matter\n payload: { manifestVersion: '1' },\n };\n\n window.parent.postMessage(readyMsg, '*');\n });\n },\n};\n", "// packages/widget-sdk/src/service.ts\n\nimport type { WidgetServiceClient } from './types';\n\nexport interface CreateServiceClientOptions {\n baseUrl: string;\n getJwt: (forceRefresh?: boolean) => Promise<string>;\n fetchImpl?: typeof fetch;\n}\n\nexport function createServiceClient(opts: CreateServiceClientOptions): WidgetServiceClient {\n const fetchImpl = opts.fetchImpl ?? globalThis.fetch.bind(globalThis);\n const baseUrl = opts.baseUrl.replace(/\\/+$/, '');\n\n async function call(path: string, init: RequestInit, token: string): Promise<Response> {\n const url = `${baseUrl}${path.startsWith('/') ? path : `/${path}`}`;\n const headers = new Headers(init.headers);\n headers.set('authorization', `Bearer ${token}`);\n if (init.body && !headers.has('content-type')) {\n headers.set('content-type', 'application/json');\n }\n return fetchImpl(url, { ...init, headers });\n }\n\n return {\n async fetch<T = unknown>(path: string, init: RequestInit = {}): Promise<T> {\n let token = await opts.getJwt(false);\n let res = await call(path, init, token);\n\n if (res.status === 401) {\n token = await opts.getJwt(true);\n res = await call(path, init, token);\n }\n\n if (!res.ok) {\n let body: { message?: string } = {};\n try {\n body = (await res.json()) as { message?: string };\n } catch {\n // non-JSON body \u2014 ignore\n }\n throw new Error(`Widget service request failed (${res.status}): ${body.message ?? ''}`);\n }\n return (await res.json()) as T;\n },\n };\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=db.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.test.d.ts","sourceRoot":"","sources":["../src/db.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,6 @@
1
+ export { CanvasWidget } from './sdk';
2
+ export type { CanvasWidgetSDK, WidgetDisplayState, WidgetEvent, SettingsAPI } from './types';
3
+ export { createServiceClient } from './service';
4
+ export type { WidgetManifestServiceBlock, WidgetManifestServiceScope, WidgetServiceClient, DbRecord, DbCollection, DbAPI, DbListOptions, } from './types';
5
+ export type { CreateServiceClientOptions } from './service';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AACrC,YAAY,EAAE,eAAe,EAAE,kBAAkB,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC7F,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAChD,YAAY,EACV,0BAA0B,EAC1B,0BAA0B,EAC1B,mBAAmB,EACnB,QAAQ,EACR,YAAY,EACZ,KAAK,EACL,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,YAAY,EAAE,0BAA0B,EAAE,MAAM,WAAW,CAAC"}