@fias/arche-sdk 2.3.0 → 2.11.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.
Files changed (54) hide show
  1. package/dist/bridge.d.ts +76 -1
  2. package/dist/bridge.d.ts.map +1 -1
  3. package/dist/bridge.js +219 -6
  4. package/dist/bridge.js.map +1 -1
  5. package/dist/bridge.test.js +155 -6
  6. package/dist/bridge.test.js.map +1 -1
  7. package/dist/coverage-fills.test.js +26 -32
  8. package/dist/coverage-fills.test.js.map +1 -1
  9. package/dist/entity-ops.d.ts +55 -0
  10. package/dist/entity-ops.d.ts.map +1 -0
  11. package/dist/entity-ops.js +48 -0
  12. package/dist/entity-ops.js.map +1 -0
  13. package/dist/fias.d.ts +11 -1
  14. package/dist/fias.d.ts.map +1 -1
  15. package/dist/fias.js +39 -12
  16. package/dist/fias.js.map +1 -1
  17. package/dist/generated/permissions.d.ts +7 -1
  18. package/dist/generated/permissions.d.ts.map +1 -1
  19. package/dist/generated/permissions.js +35 -2
  20. package/dist/generated/permissions.js.map +1 -1
  21. package/dist/generated/surfaces.d.ts +424 -0
  22. package/dist/generated/surfaces.d.ts.map +1 -1
  23. package/dist/generated/surfaces.js +97 -1
  24. package/dist/generated/surfaces.js.map +1 -1
  25. package/dist/hooks.d.ts +228 -13
  26. package/dist/hooks.d.ts.map +1 -1
  27. package/dist/hooks.js +527 -104
  28. package/dist/hooks.js.map +1 -1
  29. package/dist/hooks.test.js +314 -247
  30. package/dist/hooks.test.js.map +1 -1
  31. package/dist/index.d.ts +4 -4
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +12 -2
  34. package/dist/index.js.map +1 -1
  35. package/dist/index.mjs +982 -115
  36. package/dist/protocol.d.ts +7 -0
  37. package/dist/protocol.d.ts.map +1 -1
  38. package/dist/protocol.js +7 -0
  39. package/dist/protocol.js.map +1 -1
  40. package/dist/provider.d.ts +50 -1
  41. package/dist/provider.d.ts.map +1 -1
  42. package/dist/provider.js +187 -2
  43. package/dist/provider.js.map +1 -1
  44. package/dist/provider.render.test.d.ts +17 -0
  45. package/dist/provider.render.test.d.ts.map +1 -0
  46. package/dist/provider.render.test.js +191 -0
  47. package/dist/provider.render.test.js.map +1 -0
  48. package/dist/provider.test.js +64 -8
  49. package/dist/provider.test.js.map +1 -1
  50. package/dist/types.d.ts +373 -27
  51. package/dist/types.d.ts.map +1 -1
  52. package/package.json +2 -1
  53. package/templates/default/AGENTS.md +321 -34
  54. package/templates/default/CLAUDE.md +321 -34
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/provider.tsx
2
- import { useEffect, useMemo, useState } from "react";
2
+ import React, { Component, useEffect, useMemo, useState } from "react";
3
3
 
4
4
  // src/context.ts
5
5
  import { createContext } from "react";
@@ -83,6 +83,16 @@ var messageCounter = 0;
83
83
  function generateMessageId() {
84
84
  return `msg_${Date.now()}_${++messageCounter}`;
85
85
  }
86
+ var FiasBridgeError = class extends Error {
87
+ constructor(message, code) {
88
+ super(message);
89
+ this.name = "FiasBridgeError";
90
+ this.code = code;
91
+ }
92
+ toJSON() {
93
+ return { name: "FiasBridgeError", code: this.code, message: this.message };
94
+ }
95
+ };
86
96
  function mergeThemeWithDefaults(incoming) {
87
97
  const defaults = getDefaultTheme(incoming.mode ?? "dark");
88
98
  return {
@@ -104,11 +114,27 @@ var FiasBridge = class {
104
114
  this.archId = "";
105
115
  this.permissions = [];
106
116
  this.theme = null;
117
+ this.vendoredAssets = null;
107
118
  this.currentPath = "";
108
119
  this.hostOrigin = "";
109
120
  this.themeListeners = /* @__PURE__ */ new Set();
110
121
  this.navigationListeners = /* @__PURE__ */ new Set();
111
122
  this.stepNavigationListeners = /* @__PURE__ */ new Set();
123
+ // Preview-state preservation (preview mode only). Keyed so multiple
124
+ // useFiasPreviewState() callers don't collide. Providers produce a snapshot
125
+ // on `preview_state_capture`; restore listeners receive it after the reload.
126
+ this.previewStateProviders = /* @__PURE__ */ new Map();
127
+ this.previewStateRestoreListeners = /* @__PURE__ */ new Map();
128
+ // A restore payload that arrived before its hook registered (the host
129
+ // restores on `ready`, but the React effect that registers runs later).
130
+ // Consumed per-key as listeners register.
131
+ this.bufferedRestoreState = null;
132
+ // Realtime subscriptions (ADR-012 Phase M4), keyed by the HOST-MINTED
133
+ // logical subscriptionId returned from a subscribe-kind entity_invoke.
134
+ // The plugin never sees grants/topics — the host manages the transport;
135
+ // these listeners receive typed invalidations and terminal endings.
136
+ this.subscriptionEventListeners = /* @__PURE__ */ new Map();
137
+ this.subscriptionEndedListeners = /* @__PURE__ */ new Map();
112
138
  this.listening = false;
113
139
  this.handleMessage = (event) => {
114
140
  const data = event.data;
@@ -127,6 +153,7 @@ var FiasBridge = class {
127
153
  this.archId = initMsg.payload.archId;
128
154
  this.permissions = initMsg.payload.permissions;
129
155
  this.theme = mergeThemeWithDefaults(initMsg.payload.theme);
156
+ this.vendoredAssets = initMsg.payload.vendoredAssets ?? null;
130
157
  this.currentPath = initMsg.payload.currentPath;
131
158
  this.initialized = true;
132
159
  this.initResolve?.();
@@ -159,6 +186,23 @@ var FiasBridge = class {
159
186
  }
160
187
  return;
161
188
  }
189
+ if (data.type === "preview_state_capture") {
190
+ const snapshot = {};
191
+ for (const [key, provider] of this.previewStateProviders) {
192
+ try {
193
+ snapshot[key] = JSON.parse(JSON.stringify(provider()));
194
+ } catch {
195
+ }
196
+ }
197
+ this.send("preview_state", snapshot);
198
+ return;
199
+ }
200
+ if (data.type === "preview_state_restore") {
201
+ const state = data.payload ?? {};
202
+ this.bufferedRestoreState = { ...this.bufferedRestoreState ?? {}, ...state };
203
+ this.deliverBufferedRestore();
204
+ return;
205
+ }
162
206
  if (data.type === "stream_token") {
163
207
  const { messageId, text } = data;
164
208
  const pending = this.pendingRequests.get(messageId);
@@ -167,6 +211,28 @@ var FiasBridge = class {
167
211
  }
168
212
  return;
169
213
  }
214
+ if (data.type === "subscription_event") {
215
+ const payload = data.payload;
216
+ if (typeof payload?.subscriptionId === "string" && payload.event) {
217
+ const listeners = this.subscriptionEventListeners.get(payload.subscriptionId);
218
+ if (listeners) {
219
+ for (const listener of listeners) listener(payload.event);
220
+ }
221
+ }
222
+ return;
223
+ }
224
+ if (data.type === "subscription_ended") {
225
+ const payload = data.payload;
226
+ if (typeof payload?.subscriptionId === "string" && payload.reason) {
227
+ const listeners = this.subscriptionEndedListeners.get(payload.subscriptionId);
228
+ if (listeners) {
229
+ for (const listener of listeners) listener(payload.reason);
230
+ }
231
+ this.subscriptionEventListeners.delete(payload.subscriptionId);
232
+ this.subscriptionEndedListeners.delete(payload.subscriptionId);
233
+ }
234
+ return;
235
+ }
170
236
  if (data.type === "response") {
171
237
  const response = data;
172
238
  const pending = this.pendingRequests.get(response.messageId);
@@ -174,7 +240,12 @@ var FiasBridge = class {
174
240
  clearTimeout(pending.timer);
175
241
  this.pendingRequests.delete(response.messageId);
176
242
  if (response.error) {
177
- pending.reject(new Error(response.error));
243
+ pending.reject(
244
+ new FiasBridgeError(
245
+ response.error || "Bridge request failed",
246
+ response.errorCode ?? "BRIDGE_ERROR"
247
+ )
248
+ );
178
249
  } else {
179
250
  pending.resolve(response.payload);
180
251
  }
@@ -215,7 +286,12 @@ var FiasBridge = class {
215
286
  * an out-of-date plugin before it tries to call ops the host removed.
216
287
  */
217
288
  ready() {
218
- this.send("ready", { sdkProtocolVersion: SDK_BRIDGE_PROTOCOL_VERSION });
289
+ this.send("ready", {
290
+ sdkProtocolVersion: SDK_BRIDGE_PROTOCOL_VERSION,
291
+ // Advertise preview-state support so the host can snapshot/restore us
292
+ // across a preview rebuild. Older SDKs omit this and the host skips it.
293
+ supportsPreviewState: true
294
+ });
219
295
  }
220
296
  /**
221
297
  * Request the host to resize the plugin iframe.
@@ -238,7 +314,7 @@ var FiasBridge = class {
238
314
  const messageId = generateMessageId();
239
315
  const timer = setTimeout(() => {
240
316
  this.pendingRequests.delete(messageId);
241
- reject(new Error(`Bridge request timed out: ${type}`));
317
+ reject(new FiasBridgeError(`Bridge request timed out: ${type}`, "TIMEOUT"));
242
318
  }, timeoutMs ?? DEFAULT_TIMEOUT_MS);
243
319
  this.pendingRequests.set(messageId, {
244
320
  resolve,
@@ -257,6 +333,16 @@ var FiasBridge = class {
257
333
  getTheme() {
258
334
  return this.theme;
259
335
  }
336
+ /**
337
+ * Asset URLs for a platform-vendored library (init payload), or null when the
338
+ * host's CDN is unconfigured, the plugin lacks `sandbox:vendored-libraries`,
339
+ * or the library isn't vendored. Static per session — no update listener
340
+ * needed. `importSpecifier` is the library's bare module name (e.g.
341
+ * `'pdfjs-dist'`). See `useFiasVendoredAssets`.
342
+ */
343
+ getVendoredAssets(importSpecifier) {
344
+ return this.vendoredAssets?.[importSpecifier] ?? null;
345
+ }
260
346
  getCurrentPath() {
261
347
  return this.currentPath;
262
348
  }
@@ -272,6 +358,41 @@ var FiasBridge = class {
272
358
  this.stepNavigationListeners.add(listener);
273
359
  return () => this.stepNavigationListeners.delete(listener);
274
360
  }
361
+ /**
362
+ * Opt into preview-state preservation. In the builder preview, an in-place
363
+ * rebuild reloads the iframe and destroys the plugin's in-memory state (e.g.
364
+ * a generated report). Registering here lets the host snapshot `getState()`
365
+ * before the reload and hand it back to `onRestore` afterwards.
366
+ *
367
+ * `key` namespaces the snapshot so independent callers don't collide. Outside
368
+ * preview mode the host never requests a capture, so this is inert. Returns an
369
+ * unregister function.
370
+ */
371
+ registerPreviewState(key, getState, onRestore) {
372
+ this.previewStateProviders.set(key, getState);
373
+ this.previewStateRestoreListeners.set(key, onRestore);
374
+ this.deliverBufferedRestore();
375
+ return () => {
376
+ this.previewStateProviders.delete(key);
377
+ this.previewStateRestoreListeners.delete(key);
378
+ };
379
+ }
380
+ /** Deliver any buffered restore payload to registered listeners (once per key). */
381
+ deliverBufferedRestore() {
382
+ if (!this.bufferedRestoreState) return;
383
+ for (const [key, listener] of this.previewStateRestoreListeners) {
384
+ if (key in this.bufferedRestoreState) {
385
+ try {
386
+ listener(this.bufferedRestoreState[key]);
387
+ } catch {
388
+ }
389
+ delete this.bufferedRestoreState[key];
390
+ }
391
+ }
392
+ if (Object.keys(this.bufferedRestoreState).length === 0) {
393
+ this.bufferedRestoreState = null;
394
+ }
395
+ }
275
396
  /**
276
397
  * Send a streaming entity_invoke request. Tokens arrive via stream_token
277
398
  * messages and are forwarded to the onToken callback. The returned promise
@@ -284,7 +405,7 @@ var FiasBridge = class {
284
405
  const messageId = generateMessageId();
285
406
  const timer = setTimeout(() => {
286
407
  this.pendingRequests.delete(messageId);
287
- reject(new Error("Bridge streaming request timed out: entity_invoke"));
408
+ reject(new FiasBridgeError("Bridge streaming request timed out: entity_invoke", "TIMEOUT"));
288
409
  }, 12e4);
289
410
  this.pendingRequests.set(messageId, {
290
411
  resolve,
@@ -306,12 +427,69 @@ var FiasBridge = class {
306
427
  }
307
428
  for (const pending of this.pendingRequests.values()) {
308
429
  clearTimeout(pending.timer);
309
- pending.reject(new Error("Bridge destroyed"));
430
+ pending.reject(new FiasBridgeError("Bridge destroyed", "BRIDGE_DESTROYED"));
310
431
  }
311
432
  this.pendingRequests.clear();
312
433
  this.themeListeners.clear();
313
434
  this.navigationListeners.clear();
314
435
  this.stepNavigationListeners.clear();
436
+ this.previewStateProviders.clear();
437
+ this.previewStateRestoreListeners.clear();
438
+ this.bufferedRestoreState = null;
439
+ this.subscriptionEventListeners.clear();
440
+ this.subscriptionEndedListeners.clear();
441
+ }
442
+ /**
443
+ * Listens for invalidation events on a logical realtime subscription
444
+ * (the id returned by a subscribe-kind entity_invoke). Returns an
445
+ * unsubscribe function for the LISTENER only — releasing the
446
+ * subscription itself is `releaseSubscription`.
447
+ */
448
+ onSubscriptionEvent(subscriptionId, listener) {
449
+ let set = this.subscriptionEventListeners.get(subscriptionId);
450
+ if (!set) {
451
+ set = /* @__PURE__ */ new Set();
452
+ this.subscriptionEventListeners.set(subscriptionId, set);
453
+ }
454
+ set.add(listener);
455
+ return () => {
456
+ const listeners = this.subscriptionEventListeners.get(subscriptionId);
457
+ listeners?.delete(listener);
458
+ if (listeners && listeners.size === 0) {
459
+ this.subscriptionEventListeners.delete(subscriptionId);
460
+ }
461
+ };
462
+ }
463
+ /**
464
+ * Listens for the terminal ending of a logical realtime subscription.
465
+ * Reasons are a closed union — `authorization_revoked` and
466
+ * `collection_deleted` are definitive; the rest may be worth a fresh
467
+ * subscribe once conditions change.
468
+ */
469
+ onSubscriptionEnded(subscriptionId, listener) {
470
+ let set = this.subscriptionEndedListeners.get(subscriptionId);
471
+ if (!set) {
472
+ set = /* @__PURE__ */ new Set();
473
+ this.subscriptionEndedListeners.set(subscriptionId, set);
474
+ }
475
+ set.add(listener);
476
+ return () => {
477
+ const listeners = this.subscriptionEndedListeners.get(subscriptionId);
478
+ listeners?.delete(listener);
479
+ if (listeners && listeners.size === 0) {
480
+ this.subscriptionEndedListeners.delete(subscriptionId);
481
+ }
482
+ };
483
+ }
484
+ /**
485
+ * Releases one logical realtime subscription (fire-and-forget). The host
486
+ * refcounts: the underlying socket topic is torn down when the last
487
+ * logical subscriber releases.
488
+ */
489
+ releaseSubscription(subscriptionId) {
490
+ this.subscriptionEventListeners.delete(subscriptionId);
491
+ this.subscriptionEndedListeners.delete(subscriptionId);
492
+ this.send("subscription_unsubscribe", { subscriptionId });
315
493
  }
316
494
  send(type, payload, messageId) {
317
495
  if (typeof window === "undefined") return;
@@ -337,9 +515,156 @@ function resetBridge() {
337
515
  }
338
516
 
339
517
  // src/provider.tsx
340
- import { jsx } from "react/jsx-runtime";
518
+ import { jsx, jsxs } from "react/jsx-runtime";
519
+ function FiasErrorScreen({
520
+ error,
521
+ onReset
522
+ }) {
523
+ const code = error.code;
524
+ return /* @__PURE__ */ jsxs(
525
+ "div",
526
+ {
527
+ role: "alert",
528
+ style: {
529
+ boxSizing: "border-box",
530
+ minHeight: "100vh",
531
+ display: "flex",
532
+ flexDirection: "column",
533
+ alignItems: "center",
534
+ justifyContent: "center",
535
+ gap: "12px",
536
+ padding: "24px",
537
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
538
+ color: "#1a1a1a",
539
+ background: "#fff",
540
+ textAlign: "center"
541
+ },
542
+ children: [
543
+ /* @__PURE__ */ jsx("div", { style: { fontSize: "15px", fontWeight: 600 }, children: "This plugin hit an error" }),
544
+ /* @__PURE__ */ jsx(
545
+ "div",
546
+ {
547
+ style: {
548
+ fontSize: "13px",
549
+ lineHeight: 1.5,
550
+ maxWidth: "520px",
551
+ color: "#b00020",
552
+ wordBreak: "break-word"
553
+ },
554
+ children: error.message
555
+ }
556
+ ),
557
+ typeof code === "string" && code.length > 0 ? /* @__PURE__ */ jsxs("div", { style: { fontSize: "11px", color: "#737373" }, children: [
558
+ "Code: ",
559
+ code
560
+ ] }) : null,
561
+ onReset ? /* @__PURE__ */ jsx(
562
+ "button",
563
+ {
564
+ type: "button",
565
+ onClick: onReset,
566
+ style: {
567
+ marginTop: "4px",
568
+ padding: "8px 20px",
569
+ fontSize: "13px",
570
+ fontWeight: 600,
571
+ fontFamily: "inherit",
572
+ color: "#fff",
573
+ background: "#1a1a1a",
574
+ border: "none",
575
+ borderRadius: "6px",
576
+ cursor: "pointer"
577
+ },
578
+ children: "Try again"
579
+ }
580
+ ) : null
581
+ ]
582
+ }
583
+ );
584
+ }
585
+ var PluginErrorBoundary = class extends Component {
586
+ constructor() {
587
+ super(...arguments);
588
+ this.state = { error: null, resetCount: 0 };
589
+ this.handleReset = () => {
590
+ this.setState((prev) => ({ error: null, resetCount: prev.resetCount + 1 }));
591
+ };
592
+ }
593
+ static getDerivedStateFromError(error) {
594
+ return { error };
595
+ }
596
+ componentDidCatch(error, info) {
597
+ console.error("[fias-sdk] Uncaught error in plugin render:", error, info.componentStack);
598
+ }
599
+ render() {
600
+ if (this.state.error) {
601
+ return /* @__PURE__ */ jsx(FiasErrorScreen, { error: this.state.error, onReset: this.handleReset });
602
+ }
603
+ return /* @__PURE__ */ jsx(React.Fragment, { children: this.props.children }, this.state.resetCount);
604
+ }
605
+ };
606
+ function UnhandledRejectionBanner({
607
+ message,
608
+ onDismiss
609
+ }) {
610
+ return /* @__PURE__ */ jsxs(
611
+ "div",
612
+ {
613
+ role: "alert",
614
+ style: {
615
+ boxSizing: "border-box",
616
+ display: "flex",
617
+ alignItems: "center",
618
+ gap: "10px",
619
+ padding: "8px 12px",
620
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
621
+ fontSize: "12px",
622
+ lineHeight: 1.4,
623
+ color: "#7a2900",
624
+ background: "#fff4ec",
625
+ borderBottom: "1px solid #f0c9ae"
626
+ },
627
+ children: [
628
+ /* @__PURE__ */ jsxs("span", { style: { flex: 1, wordBreak: "break-word" }, children: [
629
+ "Something went wrong in this app: ",
630
+ message
631
+ ] }),
632
+ /* @__PURE__ */ jsx(
633
+ "button",
634
+ {
635
+ type: "button",
636
+ onClick: onDismiss,
637
+ "aria-label": "Dismiss",
638
+ style: {
639
+ flexShrink: 0,
640
+ padding: "2px 8px",
641
+ fontSize: "12px",
642
+ fontFamily: "inherit",
643
+ color: "#7a2900",
644
+ background: "transparent",
645
+ border: "1px solid #f0c9ae",
646
+ borderRadius: "4px",
647
+ cursor: "pointer"
648
+ },
649
+ children: "Dismiss"
650
+ }
651
+ )
652
+ ]
653
+ }
654
+ );
655
+ }
656
+ function describeRejectionReason(reason) {
657
+ if (reason instanceof Error) return reason.message || reason.name;
658
+ if (typeof reason === "string") return reason;
659
+ try {
660
+ return JSON.stringify(reason) ?? String(reason);
661
+ } catch {
662
+ return String(reason);
663
+ }
664
+ }
341
665
  function FiasProvider({ children }) {
342
666
  const [ready, setReady] = useState(false);
667
+ const [rejectionMessage, setRejectionMessage] = useState(null);
343
668
  const bridge = useMemo(() => getBridge(), []);
344
669
  useEffect(() => {
345
670
  let mounted = true;
@@ -353,15 +678,57 @@ function FiasProvider({ children }) {
353
678
  mounted = false;
354
679
  };
355
680
  }, [bridge]);
681
+ useEffect(() => {
682
+ if (typeof window === "undefined") return;
683
+ const handler = (event) => {
684
+ console.error("[fias-sdk] Unhandled rejection:", event.reason);
685
+ setRejectionMessage(describeRejectionReason(event.reason) || "Unknown error");
686
+ };
687
+ window.addEventListener("unhandledrejection", handler);
688
+ return () => {
689
+ window.removeEventListener("unhandledrejection", handler);
690
+ };
691
+ }, []);
356
692
  if (!ready) {
357
693
  return null;
358
694
  }
359
- return /* @__PURE__ */ jsx(FiasBridgeContext.Provider, { value: bridge, children });
695
+ return /* @__PURE__ */ jsxs(FiasBridgeContext.Provider, { value: bridge, children: [
696
+ rejectionMessage !== null ? /* @__PURE__ */ jsx(
697
+ UnhandledRejectionBanner,
698
+ {
699
+ message: rejectionMessage,
700
+ onDismiss: () => setRejectionMessage(null)
701
+ }
702
+ ) : null,
703
+ /* @__PURE__ */ jsx(PluginErrorBoundary, { children })
704
+ ] });
360
705
  }
361
706
 
362
707
  // src/hooks.ts
363
708
  import { useCallback, useContext, useEffect as useEffect2, useMemo as useMemo2, useRef, useState as useState2 } from "react";
364
709
  import { flushSync } from "react-dom";
710
+
711
+ // src/entity-ops.ts
712
+ var PLUGIN_STORAGE_ENTITY_ID = "ent_intg_plugin_storage_00000000";
713
+ var PLUGIN_DATASTORE_ENTITY_ID = "ent_intg_plugin_datastore_000000";
714
+ var PLUGIN_WORKSPACES_ENTITY_ID = "ent_intg_plugin_workspaces_00000";
715
+ var PLUGIN_STORE_ENTITY_ID = "ent_intg_plugin_store_0000000000";
716
+ var VAULT_USER_DOCUMENTS_ENTITY_ID = "ent_intg_vault_documents_0000000";
717
+ async function invokeEntityOp(bridge, entityId, op, args = {}) {
718
+ const res = await bridge.request("entity_invoke", {
719
+ entityId,
720
+ payload: { op, ...args }
721
+ });
722
+ return res.output;
723
+ }
724
+ async function invokeStoreOp(bridge, op, args = {}) {
725
+ return bridge.request("entity_invoke", {
726
+ entityId: PLUGIN_STORE_ENTITY_ID,
727
+ payload: { op, ...args }
728
+ });
729
+ }
730
+
731
+ // src/hooks.ts
365
732
  function useBridge() {
366
733
  const bridge = useContext(FiasBridgeContext);
367
734
  if (!bridge) {
@@ -378,8 +745,10 @@ function createDebouncedWriter(bridge) {
378
745
  const { path, content, timerId } = pending;
379
746
  if (timerId !== null) clearTimeout(timerId);
380
747
  pending = null;
381
- bridge.request("storage_write", { path, content }).catch(() => {
382
- });
748
+ invokeEntityOp(bridge, PLUGIN_STORAGE_ENTITY_ID, "write", { path, content }).catch(
749
+ () => {
750
+ }
751
+ );
383
752
  }
384
753
  function schedule(path, content) {
385
754
  const now = Date.now();
@@ -402,15 +771,22 @@ function createDebouncedWriter(bridge) {
402
771
  function useFiasUser() {
403
772
  const bridge = useBridge();
404
773
  const [user, setUser] = useState2(null);
774
+ const [error, setError] = useState2(null);
405
775
  useEffect2(() => {
406
776
  let mounted = true;
407
- bridge.request("get_user", {}).then((data) => {
408
- if (mounted) setUser(data);
409
- });
777
+ bridge.request("get_user", {}).then(
778
+ (data) => {
779
+ if (mounted) setUser(data);
780
+ },
781
+ (err) => {
782
+ if (mounted) setError(err instanceof Error ? err : new Error(String(err)));
783
+ }
784
+ );
410
785
  return () => {
411
786
  mounted = false;
412
787
  };
413
788
  }, [bridge]);
789
+ if (error) throw error;
414
790
  return user;
415
791
  }
416
792
  function useFiasTheme() {
@@ -421,12 +797,18 @@ function useFiasTheme() {
421
797
  }, [bridge]);
422
798
  return theme;
423
799
  }
800
+ function useFiasVendoredAssets(importSpecifier) {
801
+ const bridge = useBridge();
802
+ return bridge.getVendoredAssets(importSpecifier);
803
+ }
424
804
  function useFiasStorage() {
425
805
  const bridge = useBridge();
426
806
  const readFile = useCallback(
427
807
  async (path) => {
428
- const res = await bridge.request(
429
- "storage_read",
808
+ const res = await invokeEntityOp(
809
+ bridge,
810
+ PLUGIN_STORAGE_ENTITY_ID,
811
+ "read",
430
812
  { path }
431
813
  );
432
814
  return res?.content ?? null;
@@ -435,20 +817,30 @@ function useFiasStorage() {
435
817
  );
436
818
  const writeFile = useCallback(
437
819
  async (path, content) => {
438
- await bridge.request("storage_write", { path, content });
820
+ await invokeEntityOp(bridge, PLUGIN_STORAGE_ENTITY_ID, "write", {
821
+ path,
822
+ content
823
+ });
439
824
  },
440
825
  [bridge]
441
826
  );
442
827
  const listFiles = useCallback(
443
828
  async (prefix) => {
444
- const res = await bridge.request("storage_list", { prefix });
829
+ const res = await invokeEntityOp(
830
+ bridge,
831
+ PLUGIN_STORAGE_ENTITY_ID,
832
+ "list",
833
+ { prefix }
834
+ );
445
835
  return res?.files ?? [];
446
836
  },
447
837
  [bridge]
448
838
  );
449
839
  const deleteFile = useCallback(
450
840
  async (path) => {
451
- await bridge.request("storage_delete", { path });
841
+ await invokeEntityOp(bridge, PLUGIN_STORAGE_ENTITY_ID, "delete", {
842
+ path
843
+ });
452
844
  },
453
845
  [bridge]
454
846
  );
@@ -538,30 +930,21 @@ function useImageEntities(filter) {
538
930
  }, [fetchOnce]);
539
931
  return { entities, isLoading, error, refetch: fetchOnce };
540
932
  }
541
- var BG_REMOVAL_MAX_BYTES = 25 * 1024 * 1024;
542
- var IMGLY_BACKGROUND_REMOVAL_ENTITY_ID = "ent_intg_imgly_bgrm_000000000000";
543
- function useBackgroundRemoval() {
933
+ var CLIENT_ENTITY_INVOKE_TIMEOUT_MS = 12e4;
934
+ function useClientEntity() {
544
935
  const bridge = useBridge();
545
936
  const [isLoading, setIsLoading] = useState2(false);
546
- const [result, setResult] = useState2(null);
547
937
  const [error, setError] = useState2(null);
548
- const removeBackground = useCallback(
549
- async (image) => {
550
- if (image.size > BG_REMOVAL_MAX_BYTES) {
551
- const e = new Error("background-removal: image exceeds 25 MiB limit");
552
- setError(e);
553
- throw e;
554
- }
938
+ const invoke = useCallback(
939
+ async (entityId, input) => {
555
940
  setIsLoading(true);
556
941
  setError(null);
557
942
  try {
558
- const res = await bridge.request(
943
+ return await bridge.request(
559
944
  "client_entity_invoke",
560
- { entityId: IMGLY_BACKGROUND_REMOVAL_ENTITY_ID, input: { image } },
561
- 12e4
945
+ { entityId, input },
946
+ CLIENT_ENTITY_INVOKE_TIMEOUT_MS
562
947
  );
563
- setResult(res.image);
564
- return res.image;
565
948
  } catch (err) {
566
949
  const e = err instanceof Error ? err : new Error(String(err));
567
950
  setError(e);
@@ -572,8 +955,51 @@ function useBackgroundRemoval() {
572
955
  },
573
956
  [bridge]
574
957
  );
575
- return { removeBackground, isLoading, result, error };
958
+ return { invoke, isLoading, error };
576
959
  }
960
+ var NLLB_TRANSLATION_ENTITY_ID = "ent_intg_nllb_xlate_000000000000";
961
+ var NLLB_LANGUAGES = [
962
+ { label: "Arabic", code: "arb_Arab" },
963
+ { label: "Bengali", code: "ben_Beng" },
964
+ { label: "Bulgarian", code: "bul_Cyrl" },
965
+ { label: "Catalan", code: "cat_Latn" },
966
+ { label: "Chinese (Simplified)", code: "zho_Hans" },
967
+ { label: "Chinese (Traditional)", code: "zho_Hant" },
968
+ { label: "Croatian", code: "hrv_Latn" },
969
+ { label: "Czech", code: "ces_Latn" },
970
+ { label: "Danish", code: "dan_Latn" },
971
+ { label: "Dutch", code: "nld_Latn" },
972
+ { label: "English", code: "eng_Latn" },
973
+ { label: "Finnish", code: "fin_Latn" },
974
+ { label: "French", code: "fra_Latn" },
975
+ { label: "German", code: "deu_Latn" },
976
+ { label: "Greek", code: "ell_Grek" },
977
+ { label: "Hebrew", code: "heb_Hebr" },
978
+ { label: "Hindi", code: "hin_Deva" },
979
+ { label: "Hungarian", code: "hun_Latn" },
980
+ { label: "Indonesian", code: "ind_Latn" },
981
+ { label: "Italian", code: "ita_Latn" },
982
+ { label: "Japanese", code: "jpn_Jpan" },
983
+ { label: "Korean", code: "kor_Hang" },
984
+ { label: "Norwegian", code: "nob_Latn" },
985
+ { label: "Persian", code: "pes_Arab" },
986
+ { label: "Polish", code: "pol_Latn" },
987
+ { label: "Portuguese", code: "por_Latn" },
988
+ { label: "Romanian", code: "ron_Latn" },
989
+ { label: "Russian", code: "rus_Cyrl" },
990
+ { label: "Serbian", code: "srp_Cyrl" },
991
+ { label: "Slovak", code: "slk_Latn" },
992
+ { label: "Spanish", code: "spa_Latn" },
993
+ { label: "Swedish", code: "swe_Latn" },
994
+ { label: "Tamil", code: "tam_Taml" },
995
+ { label: "Telugu", code: "tel_Telu" },
996
+ { label: "Thai", code: "tha_Thai" },
997
+ { label: "Turkish", code: "tur_Latn" },
998
+ { label: "Ukrainian", code: "ukr_Cyrl" },
999
+ { label: "Urdu", code: "urd_Arab" },
1000
+ { label: "Vietnamese", code: "vie_Latn" }
1001
+ ];
1002
+ var GRAMMAR_CHECK_ENTITY_ID = "ent_intg_grammar_check_000000000";
577
1003
  function useAudioGeneration() {
578
1004
  const bridge = useBridge();
579
1005
  const [isLoading, setIsLoading] = useState2(false);
@@ -648,7 +1074,13 @@ function useFiasNavigation() {
648
1074
  },
649
1075
  [bridge]
650
1076
  );
651
- return { navigateTo, currentPath };
1077
+ const openArche = useCallback(
1078
+ (archeId, opts) => {
1079
+ bridge.request("open_arche", { archeId, newTab: opts?.newTab === true });
1080
+ },
1081
+ [bridge]
1082
+ );
1083
+ return { navigateTo, openArche, currentPath };
652
1084
  }
653
1085
  function usePersistentState(key, initialValue) {
654
1086
  const bridge = useBridge();
@@ -657,7 +1089,7 @@ function usePersistentState(key, initialValue) {
657
1089
  const valueRef = useRef(initialValue);
658
1090
  const writer = useMemo2(() => createDebouncedWriter(bridge), [bridge]);
659
1091
  useEffect2(() => {
660
- bridge.request("storage_read", { path: `__state/${key}` }).then((result) => {
1092
+ invokeEntityOp(bridge, PLUGIN_STORAGE_ENTITY_ID, "read", { path: `__state/${key}` }).then((result) => {
661
1093
  if (result.exists && result.content !== null) {
662
1094
  try {
663
1095
  const parsed = JSON.parse(result.content);
@@ -667,6 +1099,8 @@ function usePersistentState(key, initialValue) {
667
1099
  }
668
1100
  }
669
1101
  initializedRef.current = true;
1102
+ }).catch(() => {
1103
+ initializedRef.current = true;
670
1104
  });
671
1105
  return () => {
672
1106
  writer.flush();
@@ -695,9 +1129,12 @@ function useStepNavigation(initialStep, options) {
695
1129
  return;
696
1130
  }
697
1131
  let cancelled = false;
698
- bridge.request("storage_read", {
699
- path: `__state/${persistKey}`
700
- }).then((result) => {
1132
+ invokeEntityOp(
1133
+ bridge,
1134
+ PLUGIN_STORAGE_ENTITY_ID,
1135
+ "read",
1136
+ { path: `__state/${persistKey}` }
1137
+ ).then((result) => {
701
1138
  if (cancelled || initializedRef.current) return;
702
1139
  if (result.exists && result.content !== null) {
703
1140
  try {
@@ -741,55 +1178,121 @@ function useFiasDataStore() {
741
1178
  const bridge = useBridge();
742
1179
  const createCollection = useCallback(
743
1180
  async (name, options) => {
744
- const res = await bridge.request(
745
- "data_create_collection",
746
- { name, userScope: options?.userScope ?? "user" }
1181
+ const res = await invokeEntityOp(
1182
+ bridge,
1183
+ PLUGIN_DATASTORE_ENTITY_ID,
1184
+ "create_collection",
1185
+ {
1186
+ name,
1187
+ userScope: options?.userScope ?? "user",
1188
+ searchable: options?.searchable,
1189
+ writeMinRole: options?.writeMinRole,
1190
+ readMinRole: options?.readMinRole,
1191
+ writePolicy: options?.writePolicy
1192
+ }
747
1193
  );
748
1194
  return res.collection;
749
1195
  },
750
1196
  [bridge]
751
1197
  );
752
1198
  const listCollections = useCallback(async () => {
753
- const res = await bridge.request(
754
- "data_list_collections",
755
- {}
1199
+ const res = await invokeEntityOp(
1200
+ bridge,
1201
+ PLUGIN_DATASTORE_ENTITY_ID,
1202
+ "list_collections"
756
1203
  );
757
1204
  return res.collections;
758
1205
  }, [bridge]);
759
1206
  const deleteCollection = useCallback(
760
1207
  async (name) => {
761
- await bridge.request("data_delete_collection", { name });
1208
+ await invokeEntityOp(bridge, PLUGIN_DATASTORE_ENTITY_ID, "delete_collection", { name });
762
1209
  },
763
1210
  [bridge]
764
1211
  );
765
1212
  const put = useCallback(
766
- async (collection, key, data) => {
767
- await bridge.request("data_put", { collection, key, data });
1213
+ async (collection, key, data, options) => {
1214
+ await invokeEntityOp(bridge, PLUGIN_DATASTORE_ENTITY_ID, "put", {
1215
+ collection,
1216
+ key,
1217
+ data,
1218
+ workspaceId: options?.workspaceId
1219
+ });
768
1220
  },
769
1221
  [bridge]
770
1222
  );
771
1223
  const get = useCallback(
772
- async (collection, key) => {
773
- const res = await bridge.request("data_get", {
1224
+ async (collection, key, options) => {
1225
+ const res = await invokeEntityOp(
1226
+ bridge,
1227
+ PLUGIN_DATASTORE_ENTITY_ID,
1228
+ "get",
1229
+ {
1230
+ collection,
1231
+ key,
1232
+ workspaceId: options?.workspaceId
1233
+ }
1234
+ );
1235
+ return res.data;
1236
+ },
1237
+ [bridge]
1238
+ );
1239
+ const getDocument = useCallback(
1240
+ async (collection, key, options) => {
1241
+ const res = await invokeEntityOp(bridge, PLUGIN_DATASTORE_ENTITY_ID, "get", {
774
1242
  collection,
775
- key
1243
+ key,
1244
+ workspaceId: options?.workspaceId
776
1245
  });
777
- return res.data;
1246
+ if (res.data === null || res.data === void 0) return null;
1247
+ return {
1248
+ key: res.key ?? key,
1249
+ data: res.data,
1250
+ updatedAt: res.updatedAt ?? "",
1251
+ ...res.authoredByCollaborator !== void 0 ? { authoredByCollaborator: res.authoredByCollaborator } : {}
1252
+ };
778
1253
  },
779
1254
  [bridge]
780
1255
  );
781
1256
  const query = useCallback(
782
- async (collection, options) => {
783
- return bridge.request("data_query", {
1257
+ async (collection, options, scope) => {
1258
+ return invokeEntityOp(bridge, PLUGIN_DATASTORE_ENTITY_ID, "query", {
784
1259
  collection,
785
- ...options
1260
+ ...options,
1261
+ workspaceId: scope?.workspaceId
786
1262
  });
787
1263
  },
788
1264
  [bridge]
789
1265
  );
1266
+ const search = useCallback(
1267
+ async (collection, queryText, options, scope) => {
1268
+ const res = await invokeEntityOp(
1269
+ bridge,
1270
+ PLUGIN_DATASTORE_ENTITY_ID,
1271
+ "search",
1272
+ {
1273
+ collection,
1274
+ query: queryText,
1275
+ ...options,
1276
+ workspaceId: scope?.workspaceId
1277
+ }
1278
+ );
1279
+ return res.matches;
1280
+ },
1281
+ [bridge]
1282
+ );
790
1283
  const deleteDoc = useCallback(
791
- async (collection, key) => {
792
- await bridge.request("data_delete", { collection, key });
1284
+ async (collection, key, options) => {
1285
+ await invokeEntityOp(bridge, PLUGIN_DATASTORE_ENTITY_ID, "delete", {
1286
+ collection,
1287
+ key,
1288
+ workspaceId: options?.workspaceId
1289
+ });
1290
+ },
1291
+ [bridge]
1292
+ );
1293
+ const batch = useCallback(
1294
+ async (operations) => {
1295
+ await invokeEntityOp(bridge, PLUGIN_DATASTORE_ENTITY_ID, "batch", { operations });
793
1296
  },
794
1297
  [bridge]
795
1298
  );
@@ -800,10 +1303,119 @@ function useFiasDataStore() {
800
1303
  deleteCollection,
801
1304
  put,
802
1305
  get,
1306
+ getDocument,
803
1307
  query,
804
- delete: deleteDoc
1308
+ search,
1309
+ delete: deleteDoc,
1310
+ batch
805
1311
  }),
806
- [createCollection, listCollections, deleteCollection, put, get, query, deleteDoc]
1312
+ [
1313
+ createCollection,
1314
+ listCollections,
1315
+ deleteCollection,
1316
+ put,
1317
+ get,
1318
+ getDocument,
1319
+ query,
1320
+ search,
1321
+ deleteDoc,
1322
+ batch
1323
+ ]
1324
+ );
1325
+ }
1326
+ function useFiasWorkspaces() {
1327
+ const bridge = useBridge();
1328
+ const create = useCallback(
1329
+ async (displayName) => {
1330
+ const res = await invokeEntityOp(
1331
+ bridge,
1332
+ PLUGIN_WORKSPACES_ENTITY_ID,
1333
+ "create",
1334
+ { displayName }
1335
+ );
1336
+ return res.workspace;
1337
+ },
1338
+ [bridge]
1339
+ );
1340
+ const list = useCallback(async () => {
1341
+ const res = await invokeEntityOp(
1342
+ bridge,
1343
+ PLUGIN_WORKSPACES_ENTITY_ID,
1344
+ "list"
1345
+ );
1346
+ return res.workspaces;
1347
+ }, [bridge]);
1348
+ const get = useCallback(
1349
+ async (workspaceId) => {
1350
+ const res = await invokeEntityOp(
1351
+ bridge,
1352
+ PLUGIN_WORKSPACES_ENTITY_ID,
1353
+ "get",
1354
+ { workspaceId }
1355
+ );
1356
+ return res.workspace;
1357
+ },
1358
+ [bridge]
1359
+ );
1360
+ const archive = useCallback(
1361
+ async (workspaceId) => {
1362
+ await invokeEntityOp(bridge, PLUGIN_WORKSPACES_ENTITY_ID, "archive", { workspaceId });
1363
+ },
1364
+ [bridge]
1365
+ );
1366
+ const listMembers = useCallback(
1367
+ async (workspaceId) => {
1368
+ const res = await invokeEntityOp(
1369
+ bridge,
1370
+ PLUGIN_WORKSPACES_ENTITY_ID,
1371
+ "list_members",
1372
+ { workspaceId }
1373
+ );
1374
+ return res.members;
1375
+ },
1376
+ [bridge]
1377
+ );
1378
+ const addMember = useCallback(
1379
+ async (workspaceId, username, role, expiresAt) => {
1380
+ const res = await invokeEntityOp(
1381
+ bridge,
1382
+ PLUGIN_WORKSPACES_ENTITY_ID,
1383
+ "add_member",
1384
+ {
1385
+ workspaceId,
1386
+ username,
1387
+ role,
1388
+ expiresAt
1389
+ }
1390
+ );
1391
+ return res.member;
1392
+ },
1393
+ [bridge]
1394
+ );
1395
+ const updateMember = useCallback(
1396
+ async (workspaceId, username, role) => {
1397
+ const res = await invokeEntityOp(
1398
+ bridge,
1399
+ PLUGIN_WORKSPACES_ENTITY_ID,
1400
+ "update_member",
1401
+ { workspaceId, username, role }
1402
+ );
1403
+ return res.member;
1404
+ },
1405
+ [bridge]
1406
+ );
1407
+ const removeMember = useCallback(
1408
+ async (workspaceId, username) => {
1409
+ await invokeEntityOp(bridge, PLUGIN_WORKSPACES_ENTITY_ID, "remove_member", {
1410
+ workspaceId,
1411
+ username
1412
+ });
1413
+ },
1414
+ [bridge]
1415
+ );
1416
+ return useMemo2(
1417
+ () => ({ create, list, get, archive, listMembers, addMember, updateMember, removeMember }),
1418
+ [create, list, get, archive, listMembers, addMember, updateMember, removeMember]
807
1419
  );
808
1420
  }
809
1421
  function useFiasStore() {
@@ -814,8 +1426,8 @@ function useFiasStore() {
814
1426
  useEffect2(() => {
815
1427
  let mounted = true;
816
1428
  Promise.all([
817
- bridge.request("store_get_products", {}),
818
- bridge.request("store_get_entitlements", {})
1429
+ invokeStoreOp(bridge, "get_products"),
1430
+ invokeStoreOp(bridge, "get_entitlements")
819
1431
  ]).then(([prods, ents]) => {
820
1432
  if (mounted) {
821
1433
  setProducts(prods);
@@ -831,7 +1443,7 @@ function useFiasStore() {
831
1443
  }, [bridge]);
832
1444
  const purchase = useCallback(
833
1445
  async (productIdentifier, options) => {
834
- const result = await bridge.request("store_purchase", {
1446
+ const result = await invokeStoreOp(bridge, "purchase", {
835
1447
  productIdentifier,
836
1448
  ...options
837
1449
  });
@@ -859,14 +1471,11 @@ function useFiasStore() {
859
1471
  [entitlements]
860
1472
  );
861
1473
  const getPurchaseHistory = useCallback(async () => {
862
- const res = await bridge.request(
863
- "store_get_purchase_history",
864
- {}
865
- );
1474
+ const res = await invokeStoreOp(bridge, "get_purchase_history");
866
1475
  return res.purchases;
867
1476
  }, [bridge]);
868
1477
  const restorePurchases = useCallback(async () => {
869
- const restored = await bridge.request("store_restore", {});
1478
+ const restored = await invokeStoreOp(bridge, "restore");
870
1479
  setEntitlements(restored);
871
1480
  return restored;
872
1481
  }, [bridge]);
@@ -1039,29 +1648,17 @@ function useVaultDocuments() {
1039
1648
  const upload = useCallback(
1040
1649
  async (bytes, params) => {
1041
1650
  const src = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);
1042
- const u8 = new Uint8Array(src.byteLength);
1043
- u8.set(src);
1044
- const sizeBytes = u8.byteLength;
1045
- const digest = await crypto.subtle.digest("SHA-256", u8);
1046
- const checksumHex = bytesToHex(new Uint8Array(digest));
1047
- const init = await uploadInit({ ...params, sizeBytes, checksumSha256: checksumHex });
1048
- const browserHeaders = Object.fromEntries(
1049
- Object.entries(init.requiredHeaders).filter(([k]) => k.toLowerCase() !== "content-length")
1050
- );
1051
- const putResp = await fetch(init.uploadUrl, {
1052
- method: "PUT",
1053
- body: u8,
1054
- headers: browserHeaders
1651
+ return bridge.request("vault_documents_upload", {
1652
+ name: params.name,
1653
+ mimeType: params.mimeType,
1654
+ bytes: bytesToBase64(src),
1655
+ tags: params.tags,
1656
+ sensitivity: params.sensitivity,
1657
+ folderPath: params.folderPath,
1658
+ replacesDocumentId: params.replacesDocumentId
1055
1659
  });
1056
- if (!putResp.ok) {
1057
- const text = await putResp.text().catch(() => "");
1058
- throw new Error(
1059
- `Vault upload PUT failed (${putResp.status}): ${text || putResp.statusText}`
1060
- );
1061
- }
1062
- return uploadFinalize({ documentId: init.documentId, checksumSha256: checksumHex });
1063
1660
  },
1064
- [uploadInit, uploadFinalize]
1661
+ [bridge]
1065
1662
  );
1066
1663
  return useMemo2(
1067
1664
  () => ({
@@ -1094,12 +1691,13 @@ function useVaultDocuments() {
1094
1691
  ]
1095
1692
  );
1096
1693
  }
1097
- function bytesToHex(bytes) {
1098
- let out = "";
1099
- for (let i = 0; i < bytes.length; i++) {
1100
- out += bytes[i].toString(16).padStart(2, "0");
1694
+ function bytesToBase64(bytes) {
1695
+ let binary = "";
1696
+ const chunk = 32768;
1697
+ for (let i = 0; i < bytes.length; i += chunk) {
1698
+ binary += String.fromCharCode(...bytes.subarray(i, i + chunk));
1101
1699
  }
1102
- return out;
1700
+ return btoa(binary);
1103
1701
  }
1104
1702
  function useArcheAssets() {
1105
1703
  const bridge = useBridge();
@@ -1130,6 +1728,136 @@ function useArcheAssets() {
1130
1728
  );
1131
1729
  return useMemo2(() => ({ list, index, getUrl }), [list, index, getUrl]);
1132
1730
  }
1731
+ function useFiasPreviewState(key, getState, onRestore) {
1732
+ const bridge = useBridge();
1733
+ const getStateRef = useRef(getState);
1734
+ getStateRef.current = getState;
1735
+ const onRestoreRef = useRef(onRestore);
1736
+ onRestoreRef.current = onRestore;
1737
+ useEffect2(() => {
1738
+ return bridge.registerPreviewState(
1739
+ key,
1740
+ () => getStateRef.current(),
1741
+ (state) => onRestoreRef.current(state)
1742
+ );
1743
+ }, [bridge, key]);
1744
+ }
1745
+ function useDataSubscription(collection, onInvalidate, options) {
1746
+ const bridge = useBridge();
1747
+ const [state, setState] = useState2({ status: "subscribing" });
1748
+ const onInvalidateRef = useRef(onInvalidate);
1749
+ onInvalidateRef.current = onInvalidate;
1750
+ const enabled = options?.enabled ?? true;
1751
+ const workspaceId = options?.workspaceId;
1752
+ useEffect2(() => {
1753
+ if (!enabled) {
1754
+ setState({ status: "ended", endedReason: "unsubscribed" });
1755
+ return;
1756
+ }
1757
+ let cancelled = false;
1758
+ let subscriptionId = null;
1759
+ let unsubscribeEvent = null;
1760
+ let unsubscribeEnded = null;
1761
+ let refetching = false;
1762
+ let trailing = false;
1763
+ const runInvalidate = async () => {
1764
+ if (refetching) {
1765
+ trailing = true;
1766
+ return;
1767
+ }
1768
+ refetching = true;
1769
+ try {
1770
+ await onInvalidateRef.current();
1771
+ } catch {
1772
+ }
1773
+ refetching = false;
1774
+ if (trailing && !cancelled) {
1775
+ trailing = false;
1776
+ void runInvalidate();
1777
+ }
1778
+ };
1779
+ setState({ status: "subscribing" });
1780
+ void (async () => {
1781
+ try {
1782
+ const res = await bridge.request("entity_invoke", {
1783
+ entityId: PLUGIN_DATASTORE_ENTITY_ID,
1784
+ payload: { op: "subscribe", collection, workspaceId }
1785
+ });
1786
+ const subscription = res?.output;
1787
+ if (!subscription || subscription.kind !== "subscription" || typeof subscription.subscriptionId !== "string") {
1788
+ if (!cancelled) setState({ status: "ended", endedReason: "transport_error" });
1789
+ return;
1790
+ }
1791
+ if (cancelled) {
1792
+ bridge.releaseSubscription(subscription.subscriptionId);
1793
+ return;
1794
+ }
1795
+ subscriptionId = subscription.subscriptionId;
1796
+ unsubscribeEvent = bridge.onSubscriptionEvent(subscriptionId, () => void runInvalidate());
1797
+ unsubscribeEnded = bridge.onSubscriptionEnded(subscriptionId, (reason) => {
1798
+ if (!cancelled) setState({ status: "ended", endedReason: reason });
1799
+ });
1800
+ setState({ status: "active" });
1801
+ void runInvalidate();
1802
+ } catch {
1803
+ if (!cancelled) setState({ status: "ended", endedReason: "transport_error" });
1804
+ }
1805
+ })();
1806
+ return () => {
1807
+ cancelled = true;
1808
+ unsubscribeEvent?.();
1809
+ unsubscribeEnded?.();
1810
+ if (subscriptionId) bridge.releaseSubscription(subscriptionId);
1811
+ };
1812
+ }, [bridge, collection, workspaceId, enabled]);
1813
+ return state;
1814
+ }
1815
+ function useVaultUserDocuments() {
1816
+ const bridge = useBridge();
1817
+ const pick = useCallback(
1818
+ async (options) => {
1819
+ return bridge.request("vault_documents_pick", {
1820
+ maxDocuments: options?.maxDocuments
1821
+ });
1822
+ },
1823
+ [bridge]
1824
+ );
1825
+ const list = useCallback(
1826
+ async (options) => {
1827
+ const res = await invokeEntityOp(
1828
+ bridge,
1829
+ VAULT_USER_DOCUMENTS_ENTITY_ID,
1830
+ "list_consented_documents",
1831
+ { limit: options?.limit, offset: options?.offset }
1832
+ );
1833
+ return res.documents;
1834
+ },
1835
+ [bridge]
1836
+ );
1837
+ const get = useCallback(
1838
+ async (documentId, options) => {
1839
+ return invokeEntityOp(
1840
+ bridge,
1841
+ VAULT_USER_DOCUMENTS_ENTITY_ID,
1842
+ "get_consented_document",
1843
+ { documentId, includeContent: options?.includeContent }
1844
+ );
1845
+ },
1846
+ [bridge]
1847
+ );
1848
+ const getDownloadUrl = useCallback(
1849
+ async (documentId) => {
1850
+ const res = await invokeEntityOp(bridge, VAULT_USER_DOCUMENTS_ENTITY_ID, "get_consented_document_url", { documentId });
1851
+ return {
1852
+ url: res.url,
1853
+ expiresAt: new Date(res.expiresAt).getTime(),
1854
+ contentType: res.contentType
1855
+ };
1856
+ },
1857
+ [bridge]
1858
+ );
1859
+ return useMemo2(() => ({ pick, list, get, getDownloadUrl }), [pick, list, get, getDownloadUrl]);
1860
+ }
1133
1861
 
1134
1862
  // src/generated/surfaces.ts
1135
1863
  var AUDIO_AUDIO_ISOLATION_SURFACE_KEY = "audio.audio-isolation";
@@ -1158,25 +1886,89 @@ var AUDIO_VOICE_DESIGN_SURFACE_KEY = "audio.voice-design";
1158
1886
  var useElevenLabsVoiceDesign = () => useSurface(
1159
1887
  AUDIO_VOICE_DESIGN_SURFACE_KEY
1160
1888
  );
1889
+ var IMAGE_SMART_CONTROL_SURFACE_KEY = "image.smart-control";
1890
+ var useSmartControl = () => useSurface(IMAGE_SMART_CONTROL_SURFACE_KEY);
1891
+ var IMAGE_SMART_ERASE_SURFACE_KEY = "image.smart-erase";
1892
+ var useSmartErase = () => useSurface(IMAGE_SMART_ERASE_SURFACE_KEY);
1893
+ var IMAGE_SMART_IMAGE_TO_IMAGE_SURFACE_KEY = "image.smart-image-to-image";
1894
+ var useSmartImageToImage = () => useSurface(
1895
+ IMAGE_SMART_IMAGE_TO_IMAGE_SURFACE_KEY
1896
+ );
1897
+ var IMAGE_SMART_INPAINT_SURFACE_KEY = "image.smart-inpaint";
1898
+ var useSmartInpaint = () => useSurface(IMAGE_SMART_INPAINT_SURFACE_KEY);
1899
+ var IMAGE_SMART_OUTPAINT_SURFACE_KEY = "image.smart-outpaint";
1900
+ var useSmartOutpaint = () => useSurface(IMAGE_SMART_OUTPAINT_SURFACE_KEY);
1901
+ var IMAGE_SMART_REMOVE_BACKGROUND_SURFACE_KEY = "image.smart-remove-background";
1902
+ var useSmartRemoveBackground = () => useSurface(
1903
+ IMAGE_SMART_REMOVE_BACKGROUND_SURFACE_KEY
1904
+ );
1905
+ var IMAGE_SMART_REPLACE_BACKGROUND_SURFACE_KEY = "image.smart-replace-background";
1906
+ var useSmartReplaceBackground = () => useSurface(
1907
+ IMAGE_SMART_REPLACE_BACKGROUND_SURFACE_KEY
1908
+ );
1909
+ var IMAGE_SMART_SEARCH_RECOLOR_SURFACE_KEY = "image.smart-search-recolor";
1910
+ var useSmartSearchRecolor = () => useSurface(
1911
+ IMAGE_SMART_SEARCH_RECOLOR_SURFACE_KEY
1912
+ );
1913
+ var IMAGE_SMART_SEARCH_REPLACE_SURFACE_KEY = "image.smart-search-replace";
1914
+ var useSmartSearchReplace = () => useSurface(
1915
+ IMAGE_SMART_SEARCH_REPLACE_SURFACE_KEY
1916
+ );
1917
+ var IMAGE_SMART_UPSCALE_SURFACE_KEY = "image.smart-upscale";
1918
+ var useSmartUpscale = () => useSurface(IMAGE_SMART_UPSCALE_SURFACE_KEY);
1919
+ var IMAGE_SMART_VECTORIZE_SURFACE_KEY = "image.smart-vectorize";
1920
+ var useSmartVectorize = () => useSurface(IMAGE_SMART_VECTORIZE_SURFACE_KEY);
1921
+ var INTEGRATION_WEB_SEARCH_SURFACE_KEY = "integration.web-search";
1922
+ var useIntegrationWebSearch = () => useSurface(
1923
+ INTEGRATION_WEB_SEARCH_SURFACE_KEY
1924
+ );
1161
1925
 
1162
1926
  // src/generated/permissions.ts
1163
1927
  var VALID_PLUGIN_PERMISSIONS = [
1164
1928
  "assets:read",
1929
+ "data:search",
1165
1930
  "data:store",
1931
+ "data:workspace",
1166
1932
  "entities:audio_generate",
1933
+ "entities:client_invoke",
1934
+ "entities:image_edit",
1167
1935
  "entities:image_generate",
1168
- "entities:image_remove_background",
1169
1936
  "entities:invoke",
1937
+ "entities:web_search",
1938
+ "navigation:open_arche",
1939
+ "sandbox:vendored-libraries",
1170
1940
  "storage:sandbox",
1171
1941
  "store:purchase",
1172
1942
  "theme:read",
1173
1943
  "user:profile:read",
1174
1944
  "vault:documents:read",
1175
- "vault:documents:write"
1945
+ "vault:documents:write",
1946
+ "vault:user-documents:read"
1176
1947
  ];
1177
1948
  function isValidPluginPermission(perm) {
1178
1949
  return VALID_PLUGIN_PERMISSIONS.includes(perm);
1179
1950
  }
1951
+ var PLUGIN_PERMISSION_DESCRIPTIONS = {
1952
+ "assets:read": "Show images from this app's published asset library.",
1953
+ "data:search": "Search this app's own data semantically \u2014 costs credits per search.",
1954
+ "data:store": "Save structured data in this app's own private database.",
1955
+ "data:workspace": "Create team workspaces and manage their members.",
1956
+ "entities:audio_generate": "Generate audio with platform AI \u2014 costs credits.",
1957
+ "entities:client_invoke": "Use free on-device tools (grammar check, translation) in your browser.",
1958
+ "entities:image_edit": "Edit images with platform AI \u2014 costs credits.",
1959
+ "entities:image_generate": "Generate images with platform AI \u2014 costs credits.",
1960
+ "entities:invoke": "Use platform AI (text) on your behalf \u2014 costs credits.",
1961
+ "entities:web_search": "Search the live web on your behalf \u2014 costs credits.",
1962
+ "navigation:open_arche": "Open other arches for you (navigation only).",
1963
+ "sandbox:vendored-libraries": "Load platform-hosted libraries (like the PDF renderer) from the trusted CDN.",
1964
+ "storage:sandbox": "Save files in this app's own private storage.",
1965
+ "store:purchase": "Offer in-app purchases (you approve each purchase).",
1966
+ "theme:read": "Match your platform theme.",
1967
+ "user:profile:read": "See your display name and avatar.",
1968
+ "vault:documents:read": "Read documents this app itself created in your Vault.",
1969
+ "vault:documents:write": "Create and manage its own documents in your Vault.",
1970
+ "vault:user-documents:read": "Read documents YOU choose to share with it from your Vault \u2014 you pick each document, and you can remove access any time in Vault \u2192 App Access."
1971
+ };
1180
1972
 
1181
1973
  // src/fias.ts
1182
1974
  var fias = {
@@ -1206,40 +1998,81 @@ var fias = {
1206
1998
  */
1207
1999
  dataStore: {
1208
2000
  async createCollection(name, options) {
1209
- const res = await getBridge().request(
1210
- "data_create_collection",
1211
- { name, userScope: options?.userScope ?? "user" }
2001
+ const res = await invokeEntityOp(
2002
+ getBridge(),
2003
+ PLUGIN_DATASTORE_ENTITY_ID,
2004
+ "create_collection",
2005
+ {
2006
+ name,
2007
+ userScope: options?.userScope ?? "user",
2008
+ searchable: options?.searchable,
2009
+ writePolicy: options?.writePolicy
2010
+ }
1212
2011
  );
1213
2012
  return res.collection;
1214
2013
  },
1215
2014
  async listCollections() {
1216
- const res = await getBridge().request(
1217
- "data_list_collections",
1218
- {}
2015
+ const res = await invokeEntityOp(
2016
+ getBridge(),
2017
+ PLUGIN_DATASTORE_ENTITY_ID,
2018
+ "list_collections"
1219
2019
  );
1220
2020
  return res.collections;
1221
2021
  },
1222
2022
  async deleteCollection(name) {
1223
- await getBridge().request("data_delete_collection", { name });
2023
+ await invokeEntityOp(getBridge(), PLUGIN_DATASTORE_ENTITY_ID, "delete_collection", { name });
1224
2024
  },
1225
2025
  async put(collection, key, data) {
1226
- await getBridge().request("data_put", { collection, key, data });
1227
- },
1228
- async get(collection, key) {
1229
- const res = await getBridge().request("data_get", {
2026
+ await invokeEntityOp(getBridge(), PLUGIN_DATASTORE_ENTITY_ID, "put", {
1230
2027
  collection,
1231
- key
2028
+ key,
2029
+ data
1232
2030
  });
2031
+ },
2032
+ async get(collection, key) {
2033
+ const res = await invokeEntityOp(
2034
+ getBridge(),
2035
+ PLUGIN_DATASTORE_ENTITY_ID,
2036
+ "get",
2037
+ { collection, key }
2038
+ );
1233
2039
  return res.data;
1234
2040
  },
2041
+ /** Like get(), but returns the full envelope incl. the shared-scope
2042
+ * `authoredByCollaborator` trust signal. */
2043
+ async getDocument(collection, key) {
2044
+ const res = await invokeEntityOp(getBridge(), PLUGIN_DATASTORE_ENTITY_ID, "get", { collection, key });
2045
+ if (res.data === null || res.data === void 0) return null;
2046
+ return {
2047
+ key: res.key ?? key,
2048
+ data: res.data,
2049
+ updatedAt: res.updatedAt ?? "",
2050
+ ...res.authoredByCollaborator !== void 0 ? { authoredByCollaborator: res.authoredByCollaborator } : {}
2051
+ };
2052
+ },
1235
2053
  async query(collection, options) {
1236
- return getBridge().request("data_query", {
1237
- collection,
1238
- ...options
1239
- });
2054
+ return invokeEntityOp(
2055
+ getBridge(),
2056
+ PLUGIN_DATASTORE_ENTITY_ID,
2057
+ "query",
2058
+ { collection, ...options }
2059
+ );
2060
+ },
2061
+ async search(collection, query, options) {
2062
+ const res = await invokeEntityOp(
2063
+ getBridge(),
2064
+ PLUGIN_DATASTORE_ENTITY_ID,
2065
+ "search",
2066
+ { collection, query, ...options }
2067
+ );
2068
+ return res.matches;
1240
2069
  },
1241
2070
  async delete(collection, key) {
1242
- await getBridge().request("data_delete", { collection, key });
2071
+ await invokeEntityOp(getBridge(), PLUGIN_DATASTORE_ENTITY_ID, "delete", { collection, key });
2072
+ },
2073
+ /** Apply up to 25 put/delete ops in one all-or-nothing transaction. */
2074
+ async batch(operations) {
2075
+ await invokeEntityOp(getBridge(), PLUGIN_DATASTORE_ENTITY_ID, "batch", { operations });
1243
2076
  }
1244
2077
  }
1245
2078
  };
@@ -3214,8 +4047,25 @@ export {
3214
4047
  FONT_CATALOG,
3215
4048
  FONT_PAIRINGS,
3216
4049
  FiasBridge,
4050
+ FiasBridgeError,
3217
4051
  FiasProvider,
4052
+ GRAMMAR_CHECK_ENTITY_ID,
4053
+ IMAGE_SMART_CONTROL_SURFACE_KEY,
4054
+ IMAGE_SMART_ERASE_SURFACE_KEY,
4055
+ IMAGE_SMART_IMAGE_TO_IMAGE_SURFACE_KEY,
4056
+ IMAGE_SMART_INPAINT_SURFACE_KEY,
4057
+ IMAGE_SMART_OUTPAINT_SURFACE_KEY,
4058
+ IMAGE_SMART_REMOVE_BACKGROUND_SURFACE_KEY,
4059
+ IMAGE_SMART_REPLACE_BACKGROUND_SURFACE_KEY,
4060
+ IMAGE_SMART_SEARCH_RECOLOR_SURFACE_KEY,
4061
+ IMAGE_SMART_SEARCH_REPLACE_SURFACE_KEY,
4062
+ IMAGE_SMART_UPSCALE_SURFACE_KEY,
4063
+ IMAGE_SMART_VECTORIZE_SURFACE_KEY,
4064
+ INTEGRATION_WEB_SEARCH_SURFACE_KEY,
3218
4065
  LIGHT_THEME,
4066
+ NLLB_LANGUAGES,
4067
+ NLLB_TRANSLATION_ENTITY_ID,
4068
+ PLUGIN_PERMISSION_DESCRIPTIONS,
3219
4069
  SDK_BRIDGE_PROTOCOL_VERSION,
3220
4070
  SDK_REQUIRES_HOST_PROTOCOL_VERSION,
3221
4071
  THEME_CATALOG,
@@ -3231,7 +4081,8 @@ export {
3231
4081
  resetBridge,
3232
4082
  useArcheAssets,
3233
4083
  useAudioGeneration,
3234
- useBackgroundRemoval,
4084
+ useClientEntity,
4085
+ useDataSubscription,
3235
4086
  useElevenLabsAudioIsolation,
3236
4087
  useElevenLabsForcedAlignment,
3237
4088
  useElevenLabsMusic,
@@ -3244,15 +4095,31 @@ export {
3244
4095
  useFiasDataStore,
3245
4096
  useFiasFonts,
3246
4097
  useFiasNavigation,
4098
+ useFiasPreviewState,
3247
4099
  useFiasStorage,
3248
4100
  useFiasStore,
3249
4101
  useFiasTheme,
3250
4102
  useFiasUser,
4103
+ useFiasVendoredAssets,
4104
+ useFiasWorkspaces,
3251
4105
  useImageEntities,
3252
4106
  useImageGeneration,
4107
+ useIntegrationWebSearch,
3253
4108
  useLyriaMusic,
3254
4109
  usePersistentState,
4110
+ useSmartControl,
4111
+ useSmartErase,
4112
+ useSmartImageToImage,
4113
+ useSmartInpaint,
4114
+ useSmartOutpaint,
4115
+ useSmartRemoveBackground,
4116
+ useSmartReplaceBackground,
4117
+ useSmartSearchRecolor,
4118
+ useSmartSearchReplace,
4119
+ useSmartUpscale,
4120
+ useSmartVectorize,
3255
4121
  useStepNavigation,
3256
4122
  useSurface,
3257
- useVaultDocuments
4123
+ useVaultDocuments,
4124
+ useVaultUserDocuments
3258
4125
  };