@fias/arche-sdk 2.10.0 → 2.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -714,6 +714,9 @@ var PLUGIN_DATASTORE_ENTITY_ID = "ent_intg_plugin_datastore_000000";
714
714
  var PLUGIN_WORKSPACES_ENTITY_ID = "ent_intg_plugin_workspaces_00000";
715
715
  var PLUGIN_STORE_ENTITY_ID = "ent_intg_plugin_store_0000000000";
716
716
  var VAULT_USER_DOCUMENTS_ENTITY_ID = "ent_intg_vault_documents_0000000";
717
+ var COMMUNITY_ASSETS_ENTITY_ID = "ent_intg_community_assets_000000";
718
+ var COMMUNITY_ASSET_MAX_URL_BATCH = 50;
719
+ var COMMUNITY_ASSET_MAX_PUBLISH_BATCH = 20;
717
720
  async function invokeEntityOp(bridge, entityId, op, args = {}) {
718
721
  const res = await bridge.request("entity_invoke", {
719
722
  entityId,
@@ -930,42 +933,6 @@ function useImageEntities(filter) {
930
933
  }, [fetchOnce]);
931
934
  return { entities, isLoading, error, refetch: fetchOnce };
932
935
  }
933
- var BG_REMOVAL_MAX_BYTES = 25 * 1024 * 1024;
934
- var IMGLY_BACKGROUND_REMOVAL_ENTITY_ID = "ent_intg_imgly_bgrm_000000000000";
935
- function useBackgroundRemoval() {
936
- const bridge = useBridge();
937
- const [isLoading, setIsLoading] = useState2(false);
938
- const [result, setResult] = useState2(null);
939
- const [error, setError] = useState2(null);
940
- const removeBackground = useCallback(
941
- async (image) => {
942
- if (image.size > BG_REMOVAL_MAX_BYTES) {
943
- const e = new Error("background-removal: image exceeds 25 MiB limit");
944
- setError(e);
945
- throw e;
946
- }
947
- setIsLoading(true);
948
- setError(null);
949
- try {
950
- const res = await bridge.request(
951
- "client_entity_invoke",
952
- { entityId: IMGLY_BACKGROUND_REMOVAL_ENTITY_ID, input: { image } },
953
- 12e4
954
- );
955
- setResult(res.image);
956
- return res.image;
957
- } catch (err) {
958
- const e = err instanceof Error ? err : new Error(String(err));
959
- setError(e);
960
- throw e;
961
- } finally {
962
- setIsLoading(false);
963
- }
964
- },
965
- [bridge]
966
- );
967
- return { removeBackground, isLoading, result, error };
968
- }
969
936
  var CLIENT_ENTITY_INVOKE_TIMEOUT_MS = 12e4;
970
937
  function useClientEntity() {
971
938
  const bridge = useBridge();
@@ -1223,7 +1190,8 @@ function useFiasDataStore() {
1223
1190
  userScope: options?.userScope ?? "user",
1224
1191
  searchable: options?.searchable,
1225
1192
  writeMinRole: options?.writeMinRole,
1226
- readMinRole: options?.readMinRole
1193
+ readMinRole: options?.readMinRole,
1194
+ writePolicy: options?.writePolicy
1227
1195
  }
1228
1196
  );
1229
1197
  return res.collection;
@@ -1271,6 +1239,23 @@ function useFiasDataStore() {
1271
1239
  },
1272
1240
  [bridge]
1273
1241
  );
1242
+ const getDocument = useCallback(
1243
+ async (collection, key, options) => {
1244
+ const res = await invokeEntityOp(bridge, PLUGIN_DATASTORE_ENTITY_ID, "get", {
1245
+ collection,
1246
+ key,
1247
+ workspaceId: options?.workspaceId
1248
+ });
1249
+ if (res.data === null || res.data === void 0) return null;
1250
+ return {
1251
+ key: res.key ?? key,
1252
+ data: res.data,
1253
+ updatedAt: res.updatedAt ?? "",
1254
+ ...res.authoredByCollaborator !== void 0 ? { authoredByCollaborator: res.authoredByCollaborator } : {}
1255
+ };
1256
+ },
1257
+ [bridge]
1258
+ );
1274
1259
  const query = useCallback(
1275
1260
  async (collection, options, scope) => {
1276
1261
  return invokeEntityOp(bridge, PLUGIN_DATASTORE_ENTITY_ID, "query", {
@@ -1321,6 +1306,7 @@ function useFiasDataStore() {
1321
1306
  deleteCollection,
1322
1307
  put,
1323
1308
  get,
1309
+ getDocument,
1324
1310
  query,
1325
1311
  search,
1326
1312
  delete: deleteDoc,
@@ -1332,6 +1318,7 @@ function useFiasDataStore() {
1332
1318
  deleteCollection,
1333
1319
  put,
1334
1320
  get,
1321
+ getDocument,
1335
1322
  query,
1336
1323
  search,
1337
1324
  deleteDoc,
@@ -1874,6 +1861,179 @@ function useVaultUserDocuments() {
1874
1861
  );
1875
1862
  return useMemo2(() => ({ pick, list, get, getDownloadUrl }), [pick, list, get, getDownloadUrl]);
1876
1863
  }
1864
+ var COMMUNITY_ASSET_URL_REFRESH_BUFFER_MS = 3e4;
1865
+ var communityAssetUrlCache = /* @__PURE__ */ new Map();
1866
+ var communityAssetUrlInflight = /* @__PURE__ */ new Map();
1867
+ async function fetchCommunityAssetUrls(bridge, assetIds) {
1868
+ const now = Date.now();
1869
+ const hits = [];
1870
+ const misses = [];
1871
+ for (const assetId of assetIds) {
1872
+ const cached = communityAssetUrlCache.get(assetId);
1873
+ if (cached && now < cached.expiresAt - COMMUNITY_ASSET_URL_REFRESH_BUFFER_MS) {
1874
+ hits.push(cached);
1875
+ } else {
1876
+ misses.push(assetId);
1877
+ }
1878
+ }
1879
+ if (misses.length === 0) return hits;
1880
+ const pending = [];
1881
+ const toRequest = [];
1882
+ for (const assetId of misses) {
1883
+ const inflight = communityAssetUrlInflight.get(assetId);
1884
+ if (inflight) pending.push(inflight);
1885
+ else toRequest.push(assetId);
1886
+ }
1887
+ for (let i = 0; i < toRequest.length; i += COMMUNITY_ASSET_MAX_URL_BATCH) {
1888
+ const chunk = toRequest.slice(i, i + COMMUNITY_ASSET_MAX_URL_BATCH);
1889
+ const promise = invokeEntityOp(
1890
+ bridge,
1891
+ COMMUNITY_ASSETS_ENTITY_ID,
1892
+ "get_urls",
1893
+ { assetIds: chunk }
1894
+ ).then((res) => {
1895
+ for (const url of res.urls) {
1896
+ communityAssetUrlCache.set(url.assetId, url);
1897
+ }
1898
+ return res.urls;
1899
+ }).finally(() => {
1900
+ for (const assetId of chunk) {
1901
+ communityAssetUrlInflight.delete(assetId);
1902
+ }
1903
+ });
1904
+ for (const assetId of chunk) {
1905
+ communityAssetUrlInflight.set(assetId, promise);
1906
+ }
1907
+ pending.push(promise);
1908
+ }
1909
+ const settled = await Promise.all(pending);
1910
+ const requested = new Set(assetIds);
1911
+ const seen = new Set(hits.map((h) => h.assetId));
1912
+ for (const batch of settled) {
1913
+ for (const url of batch) {
1914
+ if (!requested.has(url.assetId) || seen.has(url.assetId)) continue;
1915
+ seen.add(url.assetId);
1916
+ hits.push(url);
1917
+ }
1918
+ }
1919
+ return hits;
1920
+ }
1921
+ function useCommunityAssets() {
1922
+ const bridge = useBridge();
1923
+ const publish = useCallback(
1924
+ async (input) => {
1925
+ const res = await invokeEntityOp(
1926
+ bridge,
1927
+ COMMUNITY_ASSETS_ENTITY_ID,
1928
+ "publish",
1929
+ {
1930
+ fileId: input.fileId,
1931
+ title: input.title,
1932
+ caption: input.caption,
1933
+ tags: input.tags,
1934
+ clientRef: input.clientRef,
1935
+ attributionName: input.attributionName
1936
+ }
1937
+ );
1938
+ return res.asset;
1939
+ },
1940
+ [bridge]
1941
+ );
1942
+ const publishMany = useCallback(
1943
+ async (items) => {
1944
+ const results = [];
1945
+ for (let i = 0; i < items.length; i += COMMUNITY_ASSET_MAX_PUBLISH_BATCH) {
1946
+ const res = await invokeEntityOp(
1947
+ bridge,
1948
+ COMMUNITY_ASSETS_ENTITY_ID,
1949
+ "publish_many",
1950
+ { items: items.slice(i, i + COMMUNITY_ASSET_MAX_PUBLISH_BATCH) }
1951
+ );
1952
+ results.push(...res.results);
1953
+ }
1954
+ return results;
1955
+ },
1956
+ [bridge]
1957
+ );
1958
+ const unpublish = useCallback(
1959
+ async (assetId) => {
1960
+ const res = await invokeEntityOp(
1961
+ bridge,
1962
+ COMMUNITY_ASSETS_ENTITY_ID,
1963
+ "unpublish",
1964
+ { assetId }
1965
+ );
1966
+ communityAssetUrlCache.delete(assetId);
1967
+ return res.asset;
1968
+ },
1969
+ [bridge]
1970
+ );
1971
+ const listMine = useCallback(
1972
+ async (options) => invokeEntityOp(bridge, COMMUNITY_ASSETS_ENTITY_ID, "list_mine", {
1973
+ limit: options?.limit,
1974
+ cursor: options?.cursor
1975
+ }),
1976
+ [bridge]
1977
+ );
1978
+ const listCommunity = useCallback(
1979
+ async (options) => invokeEntityOp(
1980
+ bridge,
1981
+ COMMUNITY_ASSETS_ENTITY_ID,
1982
+ "list_community",
1983
+ { limit: options?.limit, cursor: options?.cursor, tag: options?.tag }
1984
+ ),
1985
+ [bridge]
1986
+ );
1987
+ const get = useCallback(
1988
+ async (assetId) => {
1989
+ const res = await invokeEntityOp(
1990
+ bridge,
1991
+ COMMUNITY_ASSETS_ENTITY_ID,
1992
+ "get",
1993
+ { assetId }
1994
+ );
1995
+ return res.asset;
1996
+ },
1997
+ [bridge]
1998
+ );
1999
+ const getUrls = useCallback(
2000
+ (assetIds) => fetchCommunityAssetUrls(bridge, assetIds),
2001
+ [bridge]
2002
+ );
2003
+ const getUrl = useCallback(
2004
+ async (assetId) => {
2005
+ const [url] = await fetchCommunityAssetUrls(bridge, [assetId]);
2006
+ if (!url) {
2007
+ throw new Error(`Community asset ${assetId} is not available`);
2008
+ }
2009
+ return url;
2010
+ },
2011
+ [bridge]
2012
+ );
2013
+ const report = useCallback(
2014
+ async (assetId, reason, details) => invokeEntityOp(
2015
+ bridge,
2016
+ COMMUNITY_ASSETS_ENTITY_ID,
2017
+ "report",
2018
+ { assetId, reason, details }
2019
+ ),
2020
+ [bridge]
2021
+ );
2022
+ return useMemo2(
2023
+ () => ({
2024
+ publish,
2025
+ publishMany,
2026
+ unpublish,
2027
+ listMine,
2028
+ listCommunity,
2029
+ get,
2030
+ getUrl,
2031
+ getUrls,
2032
+ report
2033
+ }),
2034
+ [publish, publishMany, unpublish, listMine, listCommunity, get, getUrl, getUrls, report]
2035
+ );
2036
+ }
1877
2037
 
1878
2038
  // src/generated/surfaces.ts
1879
2039
  var AUDIO_AUDIO_ISOLATION_SURFACE_KEY = "audio.audio-isolation";
@@ -1941,6 +2101,8 @@ var useIntegrationWebSearch = () => useSurface(
1941
2101
 
1942
2102
  // src/generated/permissions.ts
1943
2103
  var VALID_PLUGIN_PERMISSIONS = [
2104
+ "assets:community:publish",
2105
+ "assets:community:read",
1944
2106
  "assets:read",
1945
2107
  "data:search",
1946
2108
  "data:store",
@@ -1949,7 +2111,6 @@ var VALID_PLUGIN_PERMISSIONS = [
1949
2111
  "entities:client_invoke",
1950
2112
  "entities:image_edit",
1951
2113
  "entities:image_generate",
1952
- "entities:image_remove_background",
1953
2114
  "entities:invoke",
1954
2115
  "entities:web_search",
1955
2116
  "navigation:open_arche",
@@ -1966,15 +2127,16 @@ function isValidPluginPermission(perm) {
1966
2127
  return VALID_PLUGIN_PERMISSIONS.includes(perm);
1967
2128
  }
1968
2129
  var PLUGIN_PERMISSION_DESCRIPTIONS = {
2130
+ "assets:community:publish": "Share images you made here so other people using this app can see them, and manage what you have shared.",
2131
+ "assets:community:read": "Show you images that other people using this app have shared. Everything shared is checked before anyone can see it.",
1969
2132
  "assets:read": "Show images from this app's published asset library.",
1970
2133
  "data:search": "Search this app's own data semantically \u2014 costs credits per search.",
1971
2134
  "data:store": "Save structured data in this app's own private database.",
1972
2135
  "data:workspace": "Create team workspaces and manage their members.",
1973
2136
  "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.",
2137
+ "entities:client_invoke": "Use free on-device tools (grammar check, translation) in your browser.",
1975
2138
  "entities:image_edit": "Edit images with platform AI \u2014 costs credits.",
1976
2139
  "entities:image_generate": "Generate images with platform AI \u2014 costs credits.",
1977
- "entities:image_remove_background": "Remove image backgrounds.",
1978
2140
  "entities:invoke": "Use platform AI (text) on your behalf \u2014 costs credits.",
1979
2141
  "entities:web_search": "Search the live web on your behalf \u2014 costs credits.",
1980
2142
  "navigation:open_arche": "Open other arches for you (navigation only).",
@@ -2020,7 +2182,12 @@ var fias = {
2020
2182
  getBridge(),
2021
2183
  PLUGIN_DATASTORE_ENTITY_ID,
2022
2184
  "create_collection",
2023
- { name, userScope: options?.userScope ?? "user", searchable: options?.searchable }
2185
+ {
2186
+ name,
2187
+ userScope: options?.userScope ?? "user",
2188
+ searchable: options?.searchable,
2189
+ writePolicy: options?.writePolicy
2190
+ }
2024
2191
  );
2025
2192
  return res.collection;
2026
2193
  },
@@ -2051,6 +2218,18 @@ var fias = {
2051
2218
  );
2052
2219
  return res.data;
2053
2220
  },
2221
+ /** Like get(), but returns the full envelope incl. the shared-scope
2222
+ * `authoredByCollaborator` trust signal. */
2223
+ async getDocument(collection, key) {
2224
+ const res = await invokeEntityOp(getBridge(), PLUGIN_DATASTORE_ENTITY_ID, "get", { collection, key });
2225
+ if (res.data === null || res.data === void 0) return null;
2226
+ return {
2227
+ key: res.key ?? key,
2228
+ data: res.data,
2229
+ updatedAt: res.updatedAt ?? "",
2230
+ ...res.authoredByCollaborator !== void 0 ? { authoredByCollaborator: res.authoredByCollaborator } : {}
2231
+ };
2232
+ },
2054
2233
  async query(collection, options) {
2055
2234
  return invokeEntityOp(
2056
2235
  getBridge(),
@@ -4082,8 +4261,8 @@ export {
4082
4261
  resetBridge,
4083
4262
  useArcheAssets,
4084
4263
  useAudioGeneration,
4085
- useBackgroundRemoval,
4086
4264
  useClientEntity,
4265
+ useCommunityAssets,
4087
4266
  useDataSubscription,
4088
4267
  useElevenLabsAudioIsolation,
4089
4268
  useElevenLabsForcedAlignment,
package/dist/types.d.ts CHANGED
@@ -342,27 +342,6 @@ export interface ImageGenerationApi {
342
342
  result: ImageGenerationResult | null;
343
343
  error: Error | null;
344
344
  }
345
- /**
346
- * Result of background removal via the `client_entity_invoke` bridge op
347
- * targeting the imgly background-removal entity. A transparent PNG.
348
- *
349
- * The blob is processed entirely in the host page using a WASM/ONNX model —
350
- * bytes never leave the user's device. Inputs are capped at 25 MiB
351
- * (26,214,400 bytes); larger inputs reject with an error.
352
- */
353
- export interface ImageRemoveBackgroundResult {
354
- image: Blob;
355
- }
356
- /**
357
- * Background removal API available via useBackgroundRemoval() hook.
358
- */
359
- export interface BackgroundRemovalApi {
360
- removeBackground: (image: Blob) => Promise<Blob>;
361
- isLoading: boolean;
362
- /** The Blob returned by the most recent successful call, or null. */
363
- result: Blob | null;
364
- error: Error | null;
365
- }
366
345
  /**
367
346
  * Parameters for on-device translation via the `client_entity_invoke` bridge
368
347
  * op targeting the NLLB-200 translation entity.
@@ -847,6 +826,143 @@ export interface ArcheAssetsApi {
847
826
  /** Refresh the signed URL for a single asset. */
848
827
  getUrl: (assetId: string) => Promise<ArcheAsset>;
849
828
  }
829
+ /** Where an asset sits in the moderation lifecycle, from the author's view. */
830
+ export type CommunityAssetStatus =
831
+ /** Awaiting a verdict. Nobody else can see it yet. */
832
+ 'pending_moderation'
833
+ /** Live — every user of this arche can see it. */
834
+ | 'published'
835
+ /** Moderation said no. Terminal; `moderationReason` says roughly why. */
836
+ | 'rejected'
837
+ /** Held for a human moderator. */
838
+ | 'needs_review'
839
+ /** The author removed it. */
840
+ | 'unpublished'
841
+ /** An admin removed it. */
842
+ | 'taken_down';
843
+ export interface CommunityAsset {
844
+ assetId: string;
845
+ archeId: string;
846
+ title: string | null;
847
+ caption: string | null;
848
+ tags: string[];
849
+ /** Opt-in display credit chosen by the publisher; null when anonymous. */
850
+ attributionName: string | null;
851
+ /** Always `image/png` — publishing normalizes to a canonical PNG. */
852
+ contentType: string;
853
+ sizeBytes: number;
854
+ /** ISO timestamp, or null while it is not published. */
855
+ publishedAt: string | null;
856
+ /** Present only on YOUR OWN assets (`listMine`, and `get` when you published it). */
857
+ status?: CommunityAssetStatus;
858
+ /** Coarse reason a rejected asset was refused. Own assets only. */
859
+ moderationReason?: string | null;
860
+ /** Whatever `clientRef` you passed at publish time. Own assets only. */
861
+ clientRef?: string | null;
862
+ createdAt?: string;
863
+ }
864
+ /** A short-lived signed URL for one published asset. Render with `<img src>`. */
865
+ export interface CommunityAssetUrl {
866
+ assetId: string;
867
+ url: string;
868
+ /**
869
+ * Epoch MILLISECONDS (the Vault convention — note `ArcheAsset.expiresAt`
870
+ * above is unix SECONDS). URLs last ~5 minutes; the hook refreshes them for
871
+ * you, so prefer calling `getUrls` again over caching this yourself.
872
+ */
873
+ expiresAt: number;
874
+ }
875
+ export interface CommunityAssetPublishInput {
876
+ /**
877
+ * The `fileId` from a `useImageGeneration()` result — the image must be one
878
+ * YOU created or uploaded, in your own Fias files.
879
+ *
880
+ * Required here, while `ImageGenerationResult.fileId` is OPTIONAL (it is
881
+ * absent if the generated image was never written to the user's files). That
882
+ * mismatch is deliberate: TypeScript makes you handle the missing case rather
883
+ * than forwarding `undefined` and discovering it as a runtime
884
+ * `FILE_NOT_FOUND`. Guard before publishing:
885
+ *
886
+ * ```ts
887
+ * const image = await generate({ prompt });
888
+ * if (!image.fileId) return; // nothing saved — nothing to publish
889
+ * await publish({ fileId: image.fileId });
890
+ * ```
891
+ */
892
+ fileId: string;
893
+ title?: string | null;
894
+ caption?: string | null;
895
+ /** Up to 16, each ≤64 chars. The only filterable dimension in `listCommunity`. */
896
+ tags?: string[];
897
+ /** Your own correlation handle (e.g. `"page-3"`), echoed back per item. */
898
+ clientRef?: string | null;
899
+ /** Opt-in display credit. Screened like every other author-supplied string. */
900
+ attributionName?: string | null;
901
+ }
902
+ /**
903
+ * One item's outcome from `publishMany`. Items succeed or fail INDEPENDENTLY —
904
+ * a single rejected page must not sink a whole book — and retrying only the
905
+ * failures is safe: publishing the same bytes twice returns the first result
906
+ * rather than creating a duplicate.
907
+ */
908
+ export type CommunityAssetPublishResult = {
909
+ clientRef: string | null;
910
+ asset: CommunityAsset;
911
+ error?: undefined;
912
+ } | {
913
+ clientRef: string | null;
914
+ asset?: undefined;
915
+ error: {
916
+ code: string;
917
+ message: string;
918
+ };
919
+ };
920
+ export interface CommunityAssetListOptions {
921
+ /** 1..100. Default 30. */
922
+ limit?: number;
923
+ /** `nextCursor` from the previous page. */
924
+ cursor?: string | null;
925
+ /** Return only assets carrying this tag. `listCommunity` only. */
926
+ tag?: string | null;
927
+ }
928
+ export interface CommunityAssetListResult {
929
+ assets: CommunityAsset[];
930
+ /** Null when there are no more pages. */
931
+ nextCursor: string | null;
932
+ }
933
+ export type CommunityAssetReportReason = 'sexual' | 'violence' | 'hate' | 'illegal' | 'copyright' | 'spam' | 'other';
934
+ export interface CommunityAssetsApi {
935
+ /**
936
+ * Publish one image you created so other users of this arche can see it.
937
+ * Free. It becomes visible only after moderation — expect
938
+ * `status: 'pending_moderation'` back, not `'published'`.
939
+ */
940
+ publish: (input: CommunityAssetPublishInput) => Promise<CommunityAsset>;
941
+ /** Publish up to 20 at once; each item succeeds or fails on its own. */
942
+ publishMany: (items: CommunityAssetPublishInput[]) => Promise<CommunityAssetPublishResult[]>;
943
+ /** Remove one of YOUR published assets. */
944
+ unpublish: (assetId: string) => Promise<CommunityAsset>;
945
+ /** Your own publications here, including moderation status. */
946
+ listMine: (options?: CommunityAssetListOptions) => Promise<CommunityAssetListResult>;
947
+ /** Browse what this arche's community has published. */
948
+ listCommunity: (options?: CommunityAssetListOptions) => Promise<CommunityAssetListResult>;
949
+ /** Metadata for one asset. */
950
+ get: (assetId: string) => Promise<CommunityAsset>;
951
+ /** A signed URL for one asset. Cached and auto-refreshed by the hook. */
952
+ getUrl: (assetId: string) => Promise<CommunityAssetUrl>;
953
+ /**
954
+ * Signed URLs for up to 50 assets in ONE call. Use this for a gallery or a
955
+ * multi-page book — 13 separate `getUrl` calls against a 5-minute TTL is the
956
+ * shape this exists to avoid. Ids that are gone or not yet published are
957
+ * simply omitted from the result rather than throwing.
958
+ */
959
+ getUrls: (assetIds: string[]) => Promise<CommunityAssetUrl[]>;
960
+ /** Report a published asset for moderator review. */
961
+ report: (assetId: string, reason: CommunityAssetReportReason, details?: string) => Promise<{
962
+ reportId: string;
963
+ status: string;
964
+ }>;
965
+ }
850
966
  /**
851
967
  * Message types sent from the plugin iframe to the parent frame.
852
968
  */
@@ -1005,8 +1121,28 @@ export interface DataStoreCollection {
1005
1121
  /** Min workspace role to write / read (workspace-scoped only); null = default. */
1006
1122
  writeMinRole?: WorkspaceRole | null;
1007
1123
  readMinRole?: WorkspaceRole | null;
1124
+ /** Who may write (shared-scoped only): see {@link DataStoreWritePolicy}. */
1125
+ writePolicy?: DataStoreWritePolicy;
1008
1126
  createdAt: string;
1009
1127
  }
1128
+ /**
1129
+ * Write policy for a `shared`-scope collection. Shared collections are
1130
+ * read-by-all; the write policy narrows who may WRITE:
1131
+ *
1132
+ * - 'any' (default): every user of the arche may write any document.
1133
+ * - 'author': creating a NEW key is open to everyone, but overwriting or
1134
+ * deleting an existing document requires being its author (the last
1135
+ * successful writer) or an arche collaborator. Use for shared catalogs /
1136
+ * caches where users publish their own entries.
1137
+ * - 'collaborators': only arche collaborators (owner/publisher) may write.
1138
+ * Use for curated content like a category taxonomy.
1139
+ *
1140
+ * Tighten-only after creation: re-declaring a STRICTER policy on an existing
1141
+ * collection upgrades it when the caller is a collaborator (and is silently
1142
+ * kept as-is for other users, so a shipped `ensure` call stays safe), while
1143
+ * loosening is refused.
1144
+ */
1145
+ export type DataStoreWritePolicy = 'any' | 'author' | 'collaborators';
1010
1146
  /**
1011
1147
  * A document returned from the data store.
1012
1148
  */
@@ -1014,6 +1150,15 @@ export interface DataStoreDocument<T = Record<string, unknown>> {
1014
1150
  key: string;
1015
1151
  data: T;
1016
1152
  updatedAt: string;
1153
+ /**
1154
+ * Present on SHARED-scope documents only: whether the document's last writer
1155
+ * is an active arche collaborator (owner/publisher). The trust signal for
1156
+ * shared content — e.g. refuse to feed a document into an AI prompt unless
1157
+ * it was authored by a collaborator. The raw author identity is never
1158
+ * exposed. Requires a platform/SDK version with write-policy support;
1159
+ * absent otherwise.
1160
+ */
1161
+ authoredByCollaborator?: boolean;
1017
1162
  }
1018
1163
  /**
1019
1164
  * Filter condition for querying documents.
@@ -1069,6 +1214,8 @@ export interface DataStoreSearchMatch<T = Record<string, unknown>> {
1069
1214
  data: T;
1070
1215
  /** Cosine similarity in [0, 1]; higher is closer. */
1071
1216
  similarity: number;
1217
+ /** Present on shared-scope matches: see {@link DataStoreDocument.authoredByCollaborator}. */
1218
+ authoredByCollaborator?: boolean;
1072
1219
  }
1073
1220
  /**
1074
1221
  * Data Store API available via useFiasDataStore() hook.
@@ -1096,6 +1243,8 @@ export interface FiasDataStoreApi {
1096
1243
  * collection above the default (write ≥ member, read ≥ viewer). */
1097
1244
  writeMinRole?: WorkspaceRole;
1098
1245
  readMinRole?: WorkspaceRole;
1246
+ /** Shared-scoped only: who may write. See {@link DataStoreWritePolicy}. */
1247
+ writePolicy?: DataStoreWritePolicy;
1099
1248
  }) => Promise<DataStoreCollection>;
1100
1249
  /** List all collections for this arche. */
1101
1250
  listCollections: () => Promise<DataStoreCollection[]>;
@@ -1110,6 +1259,14 @@ export interface FiasDataStoreApi {
1110
1259
  /** Get a document by key. Returns null if not found. Pass `{ workspaceId }`
1111
1260
  * for a workspace-scoped collection. */
1112
1261
  get: <T extends Record<string, unknown> = Record<string, unknown>>(collection: string, key: string, options?: DataStoreScopeOptions) => Promise<T | null>;
1262
+ /**
1263
+ * Like {@link get}, but returns the full document envelope — key,
1264
+ * `updatedAt`, and (for shared-scope documents) the
1265
+ * {@link DataStoreDocument.authoredByCollaborator} trust signal — instead of
1266
+ * the bare data. Use when the caller needs provenance, e.g. before feeding
1267
+ * shared content into an AI prompt.
1268
+ */
1269
+ getDocument: <T extends Record<string, unknown> = Record<string, unknown>>(collection: string, key: string, options?: DataStoreScopeOptions) => Promise<DataStoreDocument<T> | null>;
1113
1270
  /** Query documents with filters, sorting, and pagination. For a
1114
1271
  * `workspace`-scoped collection pass `scope: { workspaceId }`; the caller must
1115
1272
  * be an active member (any role can read). */