@fias/arche-sdk 2.3.0 → 2.10.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 +7 -1
  14. package/dist/fias.d.ts.map +1 -1
  15. package/dist/fias.js +19 -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 +36 -1
  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 +230 -3
  26. package/dist/hooks.d.ts.map +1 -1
  27. package/dist/hooks.js +519 -72
  28. package/dist/hooks.js.map +1 -1
  29. package/dist/hooks.test.js +322 -219
  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 -1
  34. package/dist/index.js.map +1 -1
  35. package/dist/index.mjs +966 -97
  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 +339 -13
  51. package/dist/types.d.ts.map +1 -1
  52. package/package.json +2 -1
  53. package/templates/default/AGENTS.md +328 -26
  54. package/templates/default/CLAUDE.md +328 -26
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
  );
@@ -574,6 +966,76 @@ function useBackgroundRemoval() {
574
966
  );
575
967
  return { removeBackground, isLoading, result, error };
576
968
  }
969
+ var CLIENT_ENTITY_INVOKE_TIMEOUT_MS = 12e4;
970
+ function useClientEntity() {
971
+ const bridge = useBridge();
972
+ const [isLoading, setIsLoading] = useState2(false);
973
+ const [error, setError] = useState2(null);
974
+ const invoke = useCallback(
975
+ async (entityId, input) => {
976
+ setIsLoading(true);
977
+ setError(null);
978
+ try {
979
+ return await bridge.request(
980
+ "client_entity_invoke",
981
+ { entityId, input },
982
+ CLIENT_ENTITY_INVOKE_TIMEOUT_MS
983
+ );
984
+ } catch (err) {
985
+ const e = err instanceof Error ? err : new Error(String(err));
986
+ setError(e);
987
+ throw e;
988
+ } finally {
989
+ setIsLoading(false);
990
+ }
991
+ },
992
+ [bridge]
993
+ );
994
+ return { invoke, isLoading, error };
995
+ }
996
+ var NLLB_TRANSLATION_ENTITY_ID = "ent_intg_nllb_xlate_000000000000";
997
+ var NLLB_LANGUAGES = [
998
+ { label: "Arabic", code: "arb_Arab" },
999
+ { label: "Bengali", code: "ben_Beng" },
1000
+ { label: "Bulgarian", code: "bul_Cyrl" },
1001
+ { label: "Catalan", code: "cat_Latn" },
1002
+ { label: "Chinese (Simplified)", code: "zho_Hans" },
1003
+ { label: "Chinese (Traditional)", code: "zho_Hant" },
1004
+ { label: "Croatian", code: "hrv_Latn" },
1005
+ { label: "Czech", code: "ces_Latn" },
1006
+ { label: "Danish", code: "dan_Latn" },
1007
+ { label: "Dutch", code: "nld_Latn" },
1008
+ { label: "English", code: "eng_Latn" },
1009
+ { label: "Finnish", code: "fin_Latn" },
1010
+ { label: "French", code: "fra_Latn" },
1011
+ { label: "German", code: "deu_Latn" },
1012
+ { label: "Greek", code: "ell_Grek" },
1013
+ { label: "Hebrew", code: "heb_Hebr" },
1014
+ { label: "Hindi", code: "hin_Deva" },
1015
+ { label: "Hungarian", code: "hun_Latn" },
1016
+ { label: "Indonesian", code: "ind_Latn" },
1017
+ { label: "Italian", code: "ita_Latn" },
1018
+ { label: "Japanese", code: "jpn_Jpan" },
1019
+ { label: "Korean", code: "kor_Hang" },
1020
+ { label: "Norwegian", code: "nob_Latn" },
1021
+ { label: "Persian", code: "pes_Arab" },
1022
+ { label: "Polish", code: "pol_Latn" },
1023
+ { label: "Portuguese", code: "por_Latn" },
1024
+ { label: "Romanian", code: "ron_Latn" },
1025
+ { label: "Russian", code: "rus_Cyrl" },
1026
+ { label: "Serbian", code: "srp_Cyrl" },
1027
+ { label: "Slovak", code: "slk_Latn" },
1028
+ { label: "Spanish", code: "spa_Latn" },
1029
+ { label: "Swedish", code: "swe_Latn" },
1030
+ { label: "Tamil", code: "tam_Taml" },
1031
+ { label: "Telugu", code: "tel_Telu" },
1032
+ { label: "Thai", code: "tha_Thai" },
1033
+ { label: "Turkish", code: "tur_Latn" },
1034
+ { label: "Ukrainian", code: "ukr_Cyrl" },
1035
+ { label: "Urdu", code: "urd_Arab" },
1036
+ { label: "Vietnamese", code: "vie_Latn" }
1037
+ ];
1038
+ var GRAMMAR_CHECK_ENTITY_ID = "ent_intg_grammar_check_000000000";
577
1039
  function useAudioGeneration() {
578
1040
  const bridge = useBridge();
579
1041
  const [isLoading, setIsLoading] = useState2(false);
@@ -648,7 +1110,13 @@ function useFiasNavigation() {
648
1110
  },
649
1111
  [bridge]
650
1112
  );
651
- return { navigateTo, currentPath };
1113
+ const openArche = useCallback(
1114
+ (archeId, opts) => {
1115
+ bridge.request("open_arche", { archeId, newTab: opts?.newTab === true });
1116
+ },
1117
+ [bridge]
1118
+ );
1119
+ return { navigateTo, openArche, currentPath };
652
1120
  }
653
1121
  function usePersistentState(key, initialValue) {
654
1122
  const bridge = useBridge();
@@ -657,7 +1125,7 @@ function usePersistentState(key, initialValue) {
657
1125
  const valueRef = useRef(initialValue);
658
1126
  const writer = useMemo2(() => createDebouncedWriter(bridge), [bridge]);
659
1127
  useEffect2(() => {
660
- bridge.request("storage_read", { path: `__state/${key}` }).then((result) => {
1128
+ invokeEntityOp(bridge, PLUGIN_STORAGE_ENTITY_ID, "read", { path: `__state/${key}` }).then((result) => {
661
1129
  if (result.exists && result.content !== null) {
662
1130
  try {
663
1131
  const parsed = JSON.parse(result.content);
@@ -667,6 +1135,8 @@ function usePersistentState(key, initialValue) {
667
1135
  }
668
1136
  }
669
1137
  initializedRef.current = true;
1138
+ }).catch(() => {
1139
+ initializedRef.current = true;
670
1140
  });
671
1141
  return () => {
672
1142
  writer.flush();
@@ -695,9 +1165,12 @@ function useStepNavigation(initialStep, options) {
695
1165
  return;
696
1166
  }
697
1167
  let cancelled = false;
698
- bridge.request("storage_read", {
699
- path: `__state/${persistKey}`
700
- }).then((result) => {
1168
+ invokeEntityOp(
1169
+ bridge,
1170
+ PLUGIN_STORAGE_ENTITY_ID,
1171
+ "read",
1172
+ { path: `__state/${persistKey}` }
1173
+ ).then((result) => {
701
1174
  if (cancelled || initializedRef.current) return;
702
1175
  if (result.exists && result.content !== null) {
703
1176
  try {
@@ -741,55 +1214,103 @@ function useFiasDataStore() {
741
1214
  const bridge = useBridge();
742
1215
  const createCollection = useCallback(
743
1216
  async (name, options) => {
744
- const res = await bridge.request(
745
- "data_create_collection",
746
- { name, userScope: options?.userScope ?? "user" }
1217
+ const res = await invokeEntityOp(
1218
+ bridge,
1219
+ PLUGIN_DATASTORE_ENTITY_ID,
1220
+ "create_collection",
1221
+ {
1222
+ name,
1223
+ userScope: options?.userScope ?? "user",
1224
+ searchable: options?.searchable,
1225
+ writeMinRole: options?.writeMinRole,
1226
+ readMinRole: options?.readMinRole
1227
+ }
747
1228
  );
748
1229
  return res.collection;
749
1230
  },
750
1231
  [bridge]
751
1232
  );
752
1233
  const listCollections = useCallback(async () => {
753
- const res = await bridge.request(
754
- "data_list_collections",
755
- {}
1234
+ const res = await invokeEntityOp(
1235
+ bridge,
1236
+ PLUGIN_DATASTORE_ENTITY_ID,
1237
+ "list_collections"
756
1238
  );
757
1239
  return res.collections;
758
1240
  }, [bridge]);
759
1241
  const deleteCollection = useCallback(
760
1242
  async (name) => {
761
- await bridge.request("data_delete_collection", { name });
1243
+ await invokeEntityOp(bridge, PLUGIN_DATASTORE_ENTITY_ID, "delete_collection", { name });
762
1244
  },
763
1245
  [bridge]
764
1246
  );
765
1247
  const put = useCallback(
766
- async (collection, key, data) => {
767
- await bridge.request("data_put", { collection, key, data });
1248
+ async (collection, key, data, options) => {
1249
+ await invokeEntityOp(bridge, PLUGIN_DATASTORE_ENTITY_ID, "put", {
1250
+ collection,
1251
+ key,
1252
+ data,
1253
+ workspaceId: options?.workspaceId
1254
+ });
768
1255
  },
769
1256
  [bridge]
770
1257
  );
771
1258
  const get = useCallback(
772
- async (collection, key) => {
773
- const res = await bridge.request("data_get", {
774
- collection,
775
- key
776
- });
1259
+ async (collection, key, options) => {
1260
+ const res = await invokeEntityOp(
1261
+ bridge,
1262
+ PLUGIN_DATASTORE_ENTITY_ID,
1263
+ "get",
1264
+ {
1265
+ collection,
1266
+ key,
1267
+ workspaceId: options?.workspaceId
1268
+ }
1269
+ );
777
1270
  return res.data;
778
1271
  },
779
1272
  [bridge]
780
1273
  );
781
1274
  const query = useCallback(
782
- async (collection, options) => {
783
- return bridge.request("data_query", {
1275
+ async (collection, options, scope) => {
1276
+ return invokeEntityOp(bridge, PLUGIN_DATASTORE_ENTITY_ID, "query", {
784
1277
  collection,
785
- ...options
1278
+ ...options,
1279
+ workspaceId: scope?.workspaceId
786
1280
  });
787
1281
  },
788
1282
  [bridge]
789
1283
  );
1284
+ const search = useCallback(
1285
+ async (collection, queryText, options, scope) => {
1286
+ const res = await invokeEntityOp(
1287
+ bridge,
1288
+ PLUGIN_DATASTORE_ENTITY_ID,
1289
+ "search",
1290
+ {
1291
+ collection,
1292
+ query: queryText,
1293
+ ...options,
1294
+ workspaceId: scope?.workspaceId
1295
+ }
1296
+ );
1297
+ return res.matches;
1298
+ },
1299
+ [bridge]
1300
+ );
790
1301
  const deleteDoc = useCallback(
791
- async (collection, key) => {
792
- await bridge.request("data_delete", { collection, key });
1302
+ async (collection, key, options) => {
1303
+ await invokeEntityOp(bridge, PLUGIN_DATASTORE_ENTITY_ID, "delete", {
1304
+ collection,
1305
+ key,
1306
+ workspaceId: options?.workspaceId
1307
+ });
1308
+ },
1309
+ [bridge]
1310
+ );
1311
+ const batch = useCallback(
1312
+ async (operations) => {
1313
+ await invokeEntityOp(bridge, PLUGIN_DATASTORE_ENTITY_ID, "batch", { operations });
793
1314
  },
794
1315
  [bridge]
795
1316
  );
@@ -801,9 +1322,116 @@ function useFiasDataStore() {
801
1322
  put,
802
1323
  get,
803
1324
  query,
804
- delete: deleteDoc
1325
+ search,
1326
+ delete: deleteDoc,
1327
+ batch
805
1328
  }),
806
- [createCollection, listCollections, deleteCollection, put, get, query, deleteDoc]
1329
+ [
1330
+ createCollection,
1331
+ listCollections,
1332
+ deleteCollection,
1333
+ put,
1334
+ get,
1335
+ query,
1336
+ search,
1337
+ deleteDoc,
1338
+ batch
1339
+ ]
1340
+ );
1341
+ }
1342
+ function useFiasWorkspaces() {
1343
+ const bridge = useBridge();
1344
+ const create = useCallback(
1345
+ async (displayName) => {
1346
+ const res = await invokeEntityOp(
1347
+ bridge,
1348
+ PLUGIN_WORKSPACES_ENTITY_ID,
1349
+ "create",
1350
+ { displayName }
1351
+ );
1352
+ return res.workspace;
1353
+ },
1354
+ [bridge]
1355
+ );
1356
+ const list = useCallback(async () => {
1357
+ const res = await invokeEntityOp(
1358
+ bridge,
1359
+ PLUGIN_WORKSPACES_ENTITY_ID,
1360
+ "list"
1361
+ );
1362
+ return res.workspaces;
1363
+ }, [bridge]);
1364
+ const get = useCallback(
1365
+ async (workspaceId) => {
1366
+ const res = await invokeEntityOp(
1367
+ bridge,
1368
+ PLUGIN_WORKSPACES_ENTITY_ID,
1369
+ "get",
1370
+ { workspaceId }
1371
+ );
1372
+ return res.workspace;
1373
+ },
1374
+ [bridge]
1375
+ );
1376
+ const archive = useCallback(
1377
+ async (workspaceId) => {
1378
+ await invokeEntityOp(bridge, PLUGIN_WORKSPACES_ENTITY_ID, "archive", { workspaceId });
1379
+ },
1380
+ [bridge]
1381
+ );
1382
+ const listMembers = useCallback(
1383
+ async (workspaceId) => {
1384
+ const res = await invokeEntityOp(
1385
+ bridge,
1386
+ PLUGIN_WORKSPACES_ENTITY_ID,
1387
+ "list_members",
1388
+ { workspaceId }
1389
+ );
1390
+ return res.members;
1391
+ },
1392
+ [bridge]
1393
+ );
1394
+ const addMember = useCallback(
1395
+ async (workspaceId, username, role, expiresAt) => {
1396
+ const res = await invokeEntityOp(
1397
+ bridge,
1398
+ PLUGIN_WORKSPACES_ENTITY_ID,
1399
+ "add_member",
1400
+ {
1401
+ workspaceId,
1402
+ username,
1403
+ role,
1404
+ expiresAt
1405
+ }
1406
+ );
1407
+ return res.member;
1408
+ },
1409
+ [bridge]
1410
+ );
1411
+ const updateMember = useCallback(
1412
+ async (workspaceId, username, role) => {
1413
+ const res = await invokeEntityOp(
1414
+ bridge,
1415
+ PLUGIN_WORKSPACES_ENTITY_ID,
1416
+ "update_member",
1417
+ { workspaceId, username, role }
1418
+ );
1419
+ return res.member;
1420
+ },
1421
+ [bridge]
1422
+ );
1423
+ const removeMember = useCallback(
1424
+ async (workspaceId, username) => {
1425
+ await invokeEntityOp(bridge, PLUGIN_WORKSPACES_ENTITY_ID, "remove_member", {
1426
+ workspaceId,
1427
+ username
1428
+ });
1429
+ },
1430
+ [bridge]
1431
+ );
1432
+ return useMemo2(
1433
+ () => ({ create, list, get, archive, listMembers, addMember, updateMember, removeMember }),
1434
+ [create, list, get, archive, listMembers, addMember, updateMember, removeMember]
807
1435
  );
808
1436
  }
809
1437
  function useFiasStore() {
@@ -814,8 +1442,8 @@ function useFiasStore() {
814
1442
  useEffect2(() => {
815
1443
  let mounted = true;
816
1444
  Promise.all([
817
- bridge.request("store_get_products", {}),
818
- bridge.request("store_get_entitlements", {})
1445
+ invokeStoreOp(bridge, "get_products"),
1446
+ invokeStoreOp(bridge, "get_entitlements")
819
1447
  ]).then(([prods, ents]) => {
820
1448
  if (mounted) {
821
1449
  setProducts(prods);
@@ -831,7 +1459,7 @@ function useFiasStore() {
831
1459
  }, [bridge]);
832
1460
  const purchase = useCallback(
833
1461
  async (productIdentifier, options) => {
834
- const result = await bridge.request("store_purchase", {
1462
+ const result = await invokeStoreOp(bridge, "purchase", {
835
1463
  productIdentifier,
836
1464
  ...options
837
1465
  });
@@ -859,14 +1487,11 @@ function useFiasStore() {
859
1487
  [entitlements]
860
1488
  );
861
1489
  const getPurchaseHistory = useCallback(async () => {
862
- const res = await bridge.request(
863
- "store_get_purchase_history",
864
- {}
865
- );
1490
+ const res = await invokeStoreOp(bridge, "get_purchase_history");
866
1491
  return res.purchases;
867
1492
  }, [bridge]);
868
1493
  const restorePurchases = useCallback(async () => {
869
- const restored = await bridge.request("store_restore", {});
1494
+ const restored = await invokeStoreOp(bridge, "restore");
870
1495
  setEntitlements(restored);
871
1496
  return restored;
872
1497
  }, [bridge]);
@@ -1039,29 +1664,17 @@ function useVaultDocuments() {
1039
1664
  const upload = useCallback(
1040
1665
  async (bytes, params) => {
1041
1666
  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
1667
+ return bridge.request("vault_documents_upload", {
1668
+ name: params.name,
1669
+ mimeType: params.mimeType,
1670
+ bytes: bytesToBase64(src),
1671
+ tags: params.tags,
1672
+ sensitivity: params.sensitivity,
1673
+ folderPath: params.folderPath,
1674
+ replacesDocumentId: params.replacesDocumentId
1055
1675
  });
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
1676
  },
1064
- [uploadInit, uploadFinalize]
1677
+ [bridge]
1065
1678
  );
1066
1679
  return useMemo2(
1067
1680
  () => ({
@@ -1094,12 +1707,13 @@ function useVaultDocuments() {
1094
1707
  ]
1095
1708
  );
1096
1709
  }
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");
1710
+ function bytesToBase64(bytes) {
1711
+ let binary = "";
1712
+ const chunk = 32768;
1713
+ for (let i = 0; i < bytes.length; i += chunk) {
1714
+ binary += String.fromCharCode(...bytes.subarray(i, i + chunk));
1101
1715
  }
1102
- return out;
1716
+ return btoa(binary);
1103
1717
  }
1104
1718
  function useArcheAssets() {
1105
1719
  const bridge = useBridge();
@@ -1130,6 +1744,136 @@ function useArcheAssets() {
1130
1744
  );
1131
1745
  return useMemo2(() => ({ list, index, getUrl }), [list, index, getUrl]);
1132
1746
  }
1747
+ function useFiasPreviewState(key, getState, onRestore) {
1748
+ const bridge = useBridge();
1749
+ const getStateRef = useRef(getState);
1750
+ getStateRef.current = getState;
1751
+ const onRestoreRef = useRef(onRestore);
1752
+ onRestoreRef.current = onRestore;
1753
+ useEffect2(() => {
1754
+ return bridge.registerPreviewState(
1755
+ key,
1756
+ () => getStateRef.current(),
1757
+ (state) => onRestoreRef.current(state)
1758
+ );
1759
+ }, [bridge, key]);
1760
+ }
1761
+ function useDataSubscription(collection, onInvalidate, options) {
1762
+ const bridge = useBridge();
1763
+ const [state, setState] = useState2({ status: "subscribing" });
1764
+ const onInvalidateRef = useRef(onInvalidate);
1765
+ onInvalidateRef.current = onInvalidate;
1766
+ const enabled = options?.enabled ?? true;
1767
+ const workspaceId = options?.workspaceId;
1768
+ useEffect2(() => {
1769
+ if (!enabled) {
1770
+ setState({ status: "ended", endedReason: "unsubscribed" });
1771
+ return;
1772
+ }
1773
+ let cancelled = false;
1774
+ let subscriptionId = null;
1775
+ let unsubscribeEvent = null;
1776
+ let unsubscribeEnded = null;
1777
+ let refetching = false;
1778
+ let trailing = false;
1779
+ const runInvalidate = async () => {
1780
+ if (refetching) {
1781
+ trailing = true;
1782
+ return;
1783
+ }
1784
+ refetching = true;
1785
+ try {
1786
+ await onInvalidateRef.current();
1787
+ } catch {
1788
+ }
1789
+ refetching = false;
1790
+ if (trailing && !cancelled) {
1791
+ trailing = false;
1792
+ void runInvalidate();
1793
+ }
1794
+ };
1795
+ setState({ status: "subscribing" });
1796
+ void (async () => {
1797
+ try {
1798
+ const res = await bridge.request("entity_invoke", {
1799
+ entityId: PLUGIN_DATASTORE_ENTITY_ID,
1800
+ payload: { op: "subscribe", collection, workspaceId }
1801
+ });
1802
+ const subscription = res?.output;
1803
+ if (!subscription || subscription.kind !== "subscription" || typeof subscription.subscriptionId !== "string") {
1804
+ if (!cancelled) setState({ status: "ended", endedReason: "transport_error" });
1805
+ return;
1806
+ }
1807
+ if (cancelled) {
1808
+ bridge.releaseSubscription(subscription.subscriptionId);
1809
+ return;
1810
+ }
1811
+ subscriptionId = subscription.subscriptionId;
1812
+ unsubscribeEvent = bridge.onSubscriptionEvent(subscriptionId, () => void runInvalidate());
1813
+ unsubscribeEnded = bridge.onSubscriptionEnded(subscriptionId, (reason) => {
1814
+ if (!cancelled) setState({ status: "ended", endedReason: reason });
1815
+ });
1816
+ setState({ status: "active" });
1817
+ void runInvalidate();
1818
+ } catch {
1819
+ if (!cancelled) setState({ status: "ended", endedReason: "transport_error" });
1820
+ }
1821
+ })();
1822
+ return () => {
1823
+ cancelled = true;
1824
+ unsubscribeEvent?.();
1825
+ unsubscribeEnded?.();
1826
+ if (subscriptionId) bridge.releaseSubscription(subscriptionId);
1827
+ };
1828
+ }, [bridge, collection, workspaceId, enabled]);
1829
+ return state;
1830
+ }
1831
+ function useVaultUserDocuments() {
1832
+ const bridge = useBridge();
1833
+ const pick = useCallback(
1834
+ async (options) => {
1835
+ return bridge.request("vault_documents_pick", {
1836
+ maxDocuments: options?.maxDocuments
1837
+ });
1838
+ },
1839
+ [bridge]
1840
+ );
1841
+ const list = useCallback(
1842
+ async (options) => {
1843
+ const res = await invokeEntityOp(
1844
+ bridge,
1845
+ VAULT_USER_DOCUMENTS_ENTITY_ID,
1846
+ "list_consented_documents",
1847
+ { limit: options?.limit, offset: options?.offset }
1848
+ );
1849
+ return res.documents;
1850
+ },
1851
+ [bridge]
1852
+ );
1853
+ const get = useCallback(
1854
+ async (documentId, options) => {
1855
+ return invokeEntityOp(
1856
+ bridge,
1857
+ VAULT_USER_DOCUMENTS_ENTITY_ID,
1858
+ "get_consented_document",
1859
+ { documentId, includeContent: options?.includeContent }
1860
+ );
1861
+ },
1862
+ [bridge]
1863
+ );
1864
+ const getDownloadUrl = useCallback(
1865
+ async (documentId) => {
1866
+ const res = await invokeEntityOp(bridge, VAULT_USER_DOCUMENTS_ENTITY_ID, "get_consented_document_url", { documentId });
1867
+ return {
1868
+ url: res.url,
1869
+ expiresAt: new Date(res.expiresAt).getTime(),
1870
+ contentType: res.contentType
1871
+ };
1872
+ },
1873
+ [bridge]
1874
+ );
1875
+ return useMemo2(() => ({ pick, list, get, getDownloadUrl }), [pick, list, get, getDownloadUrl]);
1876
+ }
1133
1877
 
1134
1878
  // src/generated/surfaces.ts
1135
1879
  var AUDIO_AUDIO_ISOLATION_SURFACE_KEY = "audio.audio-isolation";
@@ -1158,25 +1902,91 @@ var AUDIO_VOICE_DESIGN_SURFACE_KEY = "audio.voice-design";
1158
1902
  var useElevenLabsVoiceDesign = () => useSurface(
1159
1903
  AUDIO_VOICE_DESIGN_SURFACE_KEY
1160
1904
  );
1905
+ var IMAGE_SMART_CONTROL_SURFACE_KEY = "image.smart-control";
1906
+ var useSmartControl = () => useSurface(IMAGE_SMART_CONTROL_SURFACE_KEY);
1907
+ var IMAGE_SMART_ERASE_SURFACE_KEY = "image.smart-erase";
1908
+ var useSmartErase = () => useSurface(IMAGE_SMART_ERASE_SURFACE_KEY);
1909
+ var IMAGE_SMART_IMAGE_TO_IMAGE_SURFACE_KEY = "image.smart-image-to-image";
1910
+ var useSmartImageToImage = () => useSurface(
1911
+ IMAGE_SMART_IMAGE_TO_IMAGE_SURFACE_KEY
1912
+ );
1913
+ var IMAGE_SMART_INPAINT_SURFACE_KEY = "image.smart-inpaint";
1914
+ var useSmartInpaint = () => useSurface(IMAGE_SMART_INPAINT_SURFACE_KEY);
1915
+ var IMAGE_SMART_OUTPAINT_SURFACE_KEY = "image.smart-outpaint";
1916
+ var useSmartOutpaint = () => useSurface(IMAGE_SMART_OUTPAINT_SURFACE_KEY);
1917
+ var IMAGE_SMART_REMOVE_BACKGROUND_SURFACE_KEY = "image.smart-remove-background";
1918
+ var useSmartRemoveBackground = () => useSurface(
1919
+ IMAGE_SMART_REMOVE_BACKGROUND_SURFACE_KEY
1920
+ );
1921
+ var IMAGE_SMART_REPLACE_BACKGROUND_SURFACE_KEY = "image.smart-replace-background";
1922
+ var useSmartReplaceBackground = () => useSurface(
1923
+ IMAGE_SMART_REPLACE_BACKGROUND_SURFACE_KEY
1924
+ );
1925
+ var IMAGE_SMART_SEARCH_RECOLOR_SURFACE_KEY = "image.smart-search-recolor";
1926
+ var useSmartSearchRecolor = () => useSurface(
1927
+ IMAGE_SMART_SEARCH_RECOLOR_SURFACE_KEY
1928
+ );
1929
+ var IMAGE_SMART_SEARCH_REPLACE_SURFACE_KEY = "image.smart-search-replace";
1930
+ var useSmartSearchReplace = () => useSurface(
1931
+ IMAGE_SMART_SEARCH_REPLACE_SURFACE_KEY
1932
+ );
1933
+ var IMAGE_SMART_UPSCALE_SURFACE_KEY = "image.smart-upscale";
1934
+ var useSmartUpscale = () => useSurface(IMAGE_SMART_UPSCALE_SURFACE_KEY);
1935
+ var IMAGE_SMART_VECTORIZE_SURFACE_KEY = "image.smart-vectorize";
1936
+ var useSmartVectorize = () => useSurface(IMAGE_SMART_VECTORIZE_SURFACE_KEY);
1937
+ var INTEGRATION_WEB_SEARCH_SURFACE_KEY = "integration.web-search";
1938
+ var useIntegrationWebSearch = () => useSurface(
1939
+ INTEGRATION_WEB_SEARCH_SURFACE_KEY
1940
+ );
1161
1941
 
1162
1942
  // src/generated/permissions.ts
1163
1943
  var VALID_PLUGIN_PERMISSIONS = [
1164
1944
  "assets:read",
1945
+ "data:search",
1165
1946
  "data:store",
1947
+ "data:workspace",
1166
1948
  "entities:audio_generate",
1949
+ "entities:client_invoke",
1950
+ "entities:image_edit",
1167
1951
  "entities:image_generate",
1168
1952
  "entities:image_remove_background",
1169
1953
  "entities:invoke",
1954
+ "entities:web_search",
1955
+ "navigation:open_arche",
1956
+ "sandbox:vendored-libraries",
1170
1957
  "storage:sandbox",
1171
1958
  "store:purchase",
1172
1959
  "theme:read",
1173
1960
  "user:profile:read",
1174
1961
  "vault:documents:read",
1175
- "vault:documents:write"
1962
+ "vault:documents:write",
1963
+ "vault:user-documents:read"
1176
1964
  ];
1177
1965
  function isValidPluginPermission(perm) {
1178
1966
  return VALID_PLUGIN_PERMISSIONS.includes(perm);
1179
1967
  }
1968
+ var PLUGIN_PERMISSION_DESCRIPTIONS = {
1969
+ "assets:read": "Show images from this app's published asset library.",
1970
+ "data:search": "Search this app's own data semantically \u2014 costs credits per search.",
1971
+ "data:store": "Save structured data in this app's own private database.",
1972
+ "data:workspace": "Create team workspaces and manage their members.",
1973
+ "entities:audio_generate": "Generate audio with platform AI \u2014 costs credits.",
1974
+ "entities:client_invoke": "Use free on-device tools (grammar check, translation, background removal) in your browser.",
1975
+ "entities:image_edit": "Edit images with platform AI \u2014 costs credits.",
1976
+ "entities:image_generate": "Generate images with platform AI \u2014 costs credits.",
1977
+ "entities:image_remove_background": "Remove image backgrounds.",
1978
+ "entities:invoke": "Use platform AI (text) on your behalf \u2014 costs credits.",
1979
+ "entities:web_search": "Search the live web on your behalf \u2014 costs credits.",
1980
+ "navigation:open_arche": "Open other arches for you (navigation only).",
1981
+ "sandbox:vendored-libraries": "Load platform-hosted libraries (like the PDF renderer) from the trusted CDN.",
1982
+ "storage:sandbox": "Save files in this app's own private storage.",
1983
+ "store:purchase": "Offer in-app purchases (you approve each purchase).",
1984
+ "theme:read": "Match your platform theme.",
1985
+ "user:profile:read": "See your display name and avatar.",
1986
+ "vault:documents:read": "Read documents this app itself created in your Vault.",
1987
+ "vault:documents:write": "Create and manage its own documents in your Vault.",
1988
+ "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."
1989
+ };
1180
1990
 
1181
1991
  // src/fias.ts
1182
1992
  var fias = {
@@ -1206,40 +2016,64 @@ var fias = {
1206
2016
  */
1207
2017
  dataStore: {
1208
2018
  async createCollection(name, options) {
1209
- const res = await getBridge().request(
1210
- "data_create_collection",
1211
- { name, userScope: options?.userScope ?? "user" }
2019
+ const res = await invokeEntityOp(
2020
+ getBridge(),
2021
+ PLUGIN_DATASTORE_ENTITY_ID,
2022
+ "create_collection",
2023
+ { name, userScope: options?.userScope ?? "user", searchable: options?.searchable }
1212
2024
  );
1213
2025
  return res.collection;
1214
2026
  },
1215
2027
  async listCollections() {
1216
- const res = await getBridge().request(
1217
- "data_list_collections",
1218
- {}
2028
+ const res = await invokeEntityOp(
2029
+ getBridge(),
2030
+ PLUGIN_DATASTORE_ENTITY_ID,
2031
+ "list_collections"
1219
2032
  );
1220
2033
  return res.collections;
1221
2034
  },
1222
2035
  async deleteCollection(name) {
1223
- await getBridge().request("data_delete_collection", { name });
2036
+ await invokeEntityOp(getBridge(), PLUGIN_DATASTORE_ENTITY_ID, "delete_collection", { name });
1224
2037
  },
1225
2038
  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", {
2039
+ await invokeEntityOp(getBridge(), PLUGIN_DATASTORE_ENTITY_ID, "put", {
1230
2040
  collection,
1231
- key
2041
+ key,
2042
+ data
1232
2043
  });
2044
+ },
2045
+ async get(collection, key) {
2046
+ const res = await invokeEntityOp(
2047
+ getBridge(),
2048
+ PLUGIN_DATASTORE_ENTITY_ID,
2049
+ "get",
2050
+ { collection, key }
2051
+ );
1233
2052
  return res.data;
1234
2053
  },
1235
2054
  async query(collection, options) {
1236
- return getBridge().request("data_query", {
1237
- collection,
1238
- ...options
1239
- });
2055
+ return invokeEntityOp(
2056
+ getBridge(),
2057
+ PLUGIN_DATASTORE_ENTITY_ID,
2058
+ "query",
2059
+ { collection, ...options }
2060
+ );
2061
+ },
2062
+ async search(collection, query, options) {
2063
+ const res = await invokeEntityOp(
2064
+ getBridge(),
2065
+ PLUGIN_DATASTORE_ENTITY_ID,
2066
+ "search",
2067
+ { collection, query, ...options }
2068
+ );
2069
+ return res.matches;
1240
2070
  },
1241
2071
  async delete(collection, key) {
1242
- await getBridge().request("data_delete", { collection, key });
2072
+ await invokeEntityOp(getBridge(), PLUGIN_DATASTORE_ENTITY_ID, "delete", { collection, key });
2073
+ },
2074
+ /** Apply up to 25 put/delete ops in one all-or-nothing transaction. */
2075
+ async batch(operations) {
2076
+ await invokeEntityOp(getBridge(), PLUGIN_DATASTORE_ENTITY_ID, "batch", { operations });
1243
2077
  }
1244
2078
  }
1245
2079
  };
@@ -3214,8 +4048,25 @@ export {
3214
4048
  FONT_CATALOG,
3215
4049
  FONT_PAIRINGS,
3216
4050
  FiasBridge,
4051
+ FiasBridgeError,
3217
4052
  FiasProvider,
4053
+ GRAMMAR_CHECK_ENTITY_ID,
4054
+ IMAGE_SMART_CONTROL_SURFACE_KEY,
4055
+ IMAGE_SMART_ERASE_SURFACE_KEY,
4056
+ IMAGE_SMART_IMAGE_TO_IMAGE_SURFACE_KEY,
4057
+ IMAGE_SMART_INPAINT_SURFACE_KEY,
4058
+ IMAGE_SMART_OUTPAINT_SURFACE_KEY,
4059
+ IMAGE_SMART_REMOVE_BACKGROUND_SURFACE_KEY,
4060
+ IMAGE_SMART_REPLACE_BACKGROUND_SURFACE_KEY,
4061
+ IMAGE_SMART_SEARCH_RECOLOR_SURFACE_KEY,
4062
+ IMAGE_SMART_SEARCH_REPLACE_SURFACE_KEY,
4063
+ IMAGE_SMART_UPSCALE_SURFACE_KEY,
4064
+ IMAGE_SMART_VECTORIZE_SURFACE_KEY,
4065
+ INTEGRATION_WEB_SEARCH_SURFACE_KEY,
3218
4066
  LIGHT_THEME,
4067
+ NLLB_LANGUAGES,
4068
+ NLLB_TRANSLATION_ENTITY_ID,
4069
+ PLUGIN_PERMISSION_DESCRIPTIONS,
3219
4070
  SDK_BRIDGE_PROTOCOL_VERSION,
3220
4071
  SDK_REQUIRES_HOST_PROTOCOL_VERSION,
3221
4072
  THEME_CATALOG,
@@ -3232,6 +4083,8 @@ export {
3232
4083
  useArcheAssets,
3233
4084
  useAudioGeneration,
3234
4085
  useBackgroundRemoval,
4086
+ useClientEntity,
4087
+ useDataSubscription,
3235
4088
  useElevenLabsAudioIsolation,
3236
4089
  useElevenLabsForcedAlignment,
3237
4090
  useElevenLabsMusic,
@@ -3244,15 +4097,31 @@ export {
3244
4097
  useFiasDataStore,
3245
4098
  useFiasFonts,
3246
4099
  useFiasNavigation,
4100
+ useFiasPreviewState,
3247
4101
  useFiasStorage,
3248
4102
  useFiasStore,
3249
4103
  useFiasTheme,
3250
4104
  useFiasUser,
4105
+ useFiasVendoredAssets,
4106
+ useFiasWorkspaces,
3251
4107
  useImageEntities,
3252
4108
  useImageGeneration,
4109
+ useIntegrationWebSearch,
3253
4110
  useLyriaMusic,
3254
4111
  usePersistentState,
4112
+ useSmartControl,
4113
+ useSmartErase,
4114
+ useSmartImageToImage,
4115
+ useSmartInpaint,
4116
+ useSmartOutpaint,
4117
+ useSmartRemoveBackground,
4118
+ useSmartReplaceBackground,
4119
+ useSmartSearchRecolor,
4120
+ useSmartSearchReplace,
4121
+ useSmartUpscale,
4122
+ useSmartVectorize,
3255
4123
  useStepNavigation,
3256
4124
  useSurface,
3257
- useVaultDocuments
4125
+ useVaultDocuments,
4126
+ useVaultUserDocuments
3258
4127
  };