@fias/arche-sdk 2.11.0 → 2.13.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/bridge.d.ts +27 -1
- package/dist/bridge.d.ts.map +1 -1
- package/dist/bridge.js +58 -0
- package/dist/bridge.js.map +1 -1
- package/dist/bridge.test.js +97 -4
- package/dist/bridge.test.js.map +1 -1
- package/dist/entity-ops.d.ts +24 -2
- package/dist/entity-ops.d.ts.map +1 -1
- package/dist/entity-ops.js +21 -1
- package/dist/entity-ops.js.map +1 -1
- package/dist/fias.d.ts +9 -4
- package/dist/fias.d.ts.map +1 -1
- package/dist/fias.js +15 -8
- package/dist/fias.js.map +1 -1
- package/dist/generated/permissions.d.ts +1 -1
- package/dist/generated/permissions.d.ts.map +1 -1
- package/dist/generated/permissions.js +6 -0
- package/dist/generated/permissions.js.map +1 -1
- package/dist/hooks.d.ts +58 -1
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +263 -3
- package/dist/hooks.js.map +1 -1
- package/dist/hooks.test.js +67 -0
- package/dist/hooks.test.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +719 -19
- package/dist/panels.d.ts +213 -0
- package/dist/panels.d.ts.map +1 -0
- package/dist/panels.js +422 -0
- package/dist/panels.js.map +1 -0
- package/dist/panels.test.d.ts +2 -0
- package/dist/panels.test.d.ts.map +1 -0
- package/dist/panels.test.js +127 -0
- package/dist/panels.test.js.map +1 -0
- package/dist/types.d.ts +311 -4
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/templates/default/AGENTS.md +186 -1
- package/templates/default/CLAUDE.md +186 -1
package/dist/index.mjs
CHANGED
|
@@ -124,6 +124,12 @@ var FiasBridge = class {
|
|
|
124
124
|
// useFiasPreviewState() callers don't collide. Providers produce a snapshot
|
|
125
125
|
// on `preview_state_capture`; restore listeners receive it after the reload.
|
|
126
126
|
this.previewStateProviders = /* @__PURE__ */ new Map();
|
|
127
|
+
/**
|
|
128
|
+
* The plugin's handler for host-dispatched Fias AI actions (one per plugin
|
|
129
|
+
* — `useFiasAIActions` owns registration). Throw/reject to report failure;
|
|
130
|
+
* the assistant awaits the result before telling the model it applied.
|
|
131
|
+
*/
|
|
132
|
+
this.aiActionHandler = null;
|
|
127
133
|
this.previewStateRestoreListeners = /* @__PURE__ */ new Map();
|
|
128
134
|
// A restore payload that arrived before its hook registered (the host
|
|
129
135
|
// restores on `ready`, but the React effect that registers runs later).
|
|
@@ -211,6 +217,30 @@ var FiasBridge = class {
|
|
|
211
217
|
}
|
|
212
218
|
return;
|
|
213
219
|
}
|
|
220
|
+
if (data.type === "ai_action_dispatch") {
|
|
221
|
+
const { messageId } = data;
|
|
222
|
+
const payload = data.payload;
|
|
223
|
+
const handler = this.aiActionHandler;
|
|
224
|
+
void (async () => {
|
|
225
|
+
try {
|
|
226
|
+
if (typeof payload?.actionId !== "string") {
|
|
227
|
+
throw new Error("malformed dispatch: missing actionId");
|
|
228
|
+
}
|
|
229
|
+
if (!handler) {
|
|
230
|
+
throw new Error("the plugin has no Fias AI action handler registered");
|
|
231
|
+
}
|
|
232
|
+
await handler(payload.actionId, payload.params ?? {});
|
|
233
|
+
this.send("ai_action_result", { ok: true }, messageId);
|
|
234
|
+
} catch (err) {
|
|
235
|
+
this.send(
|
|
236
|
+
"ai_action_result",
|
|
237
|
+
{ ok: false, error: err instanceof Error ? err.message : String(err) },
|
|
238
|
+
messageId
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
})();
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
214
244
|
if (data.type === "subscription_event") {
|
|
215
245
|
const payload = data.payload;
|
|
216
246
|
if (typeof payload?.subscriptionId === "string" && payload.event) {
|
|
@@ -491,6 +521,32 @@ var FiasBridge = class {
|
|
|
491
521
|
this.subscriptionEndedListeners.delete(subscriptionId);
|
|
492
522
|
this.send("subscription_unsubscribe", { subscriptionId });
|
|
493
523
|
}
|
|
524
|
+
/**
|
|
525
|
+
* Register (or clear, with null) THE handler for host-dispatched Fias AI
|
|
526
|
+
* actions. One per plugin — `useFiasAIActions` owns this; last write wins.
|
|
527
|
+
*/
|
|
528
|
+
setAiActionHandler(handler) {
|
|
529
|
+
this.aiActionHandler = handler;
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Declare (or clear, with null) the plugin's runtime Fias AI actions.
|
|
533
|
+
* Fire-and-forget; the host validates, bounds, and throttles (~1/s), and
|
|
534
|
+
* honours the runtime lane only for TRUSTED arches — non-trusted plugins
|
|
535
|
+
* declare statically via the manifest `fiasAI` block. Requires the
|
|
536
|
+
* `ai:actions` permission.
|
|
537
|
+
*/
|
|
538
|
+
declareAiActions(declaration) {
|
|
539
|
+
this.send("ai_actions_declare", declaration);
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* Push the state snapshot the assistant sees (and `availableWhen` filters
|
|
543
|
+
* against). Keep it SMALL and flag-shaped ({documentOpen: true, …}): the
|
|
544
|
+
* host drops snapshots over its byte cap, and accepted ones are embedded
|
|
545
|
+
* in the assistant's system prompt every turn.
|
|
546
|
+
*/
|
|
547
|
+
sendAiState(state) {
|
|
548
|
+
this.send("ai_state", state);
|
|
549
|
+
}
|
|
494
550
|
send(type, payload, messageId) {
|
|
495
551
|
if (typeof window === "undefined") return;
|
|
496
552
|
const message = {
|
|
@@ -714,6 +770,9 @@ var PLUGIN_DATASTORE_ENTITY_ID = "ent_intg_plugin_datastore_000000";
|
|
|
714
770
|
var PLUGIN_WORKSPACES_ENTITY_ID = "ent_intg_plugin_workspaces_00000";
|
|
715
771
|
var PLUGIN_STORE_ENTITY_ID = "ent_intg_plugin_store_0000000000";
|
|
716
772
|
var VAULT_USER_DOCUMENTS_ENTITY_ID = "ent_intg_vault_documents_0000000";
|
|
773
|
+
var COMMUNITY_ASSETS_ENTITY_ID = "ent_intg_community_assets_000000";
|
|
774
|
+
var COMMUNITY_ASSET_MAX_URL_BATCH = 50;
|
|
775
|
+
var COMMUNITY_ASSET_MAX_PUBLISH_BATCH = 20;
|
|
717
776
|
async function invokeEntityOp(bridge, entityId, op, args = {}) {
|
|
718
777
|
const res = await bridge.request("entity_invoke", {
|
|
719
778
|
entityId,
|
|
@@ -1188,7 +1247,8 @@ function useFiasDataStore() {
|
|
|
1188
1247
|
searchable: options?.searchable,
|
|
1189
1248
|
writeMinRole: options?.writeMinRole,
|
|
1190
1249
|
readMinRole: options?.readMinRole,
|
|
1191
|
-
writePolicy: options?.writePolicy
|
|
1250
|
+
writePolicy: options?.writePolicy,
|
|
1251
|
+
constraints: options?.constraints
|
|
1192
1252
|
}
|
|
1193
1253
|
);
|
|
1194
1254
|
return res.collection;
|
|
@@ -1211,12 +1271,18 @@ function useFiasDataStore() {
|
|
|
1211
1271
|
);
|
|
1212
1272
|
const put = useCallback(
|
|
1213
1273
|
async (collection, key, data, options) => {
|
|
1214
|
-
await invokeEntityOp(
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1274
|
+
const res = await invokeEntityOp(
|
|
1275
|
+
bridge,
|
|
1276
|
+
PLUGIN_DATASTORE_ENTITY_ID,
|
|
1277
|
+
"put",
|
|
1278
|
+
{
|
|
1279
|
+
collection,
|
|
1280
|
+
key,
|
|
1281
|
+
data,
|
|
1282
|
+
workspaceId: options?.workspaceId
|
|
1283
|
+
}
|
|
1284
|
+
);
|
|
1285
|
+
return { version: res?.version };
|
|
1220
1286
|
},
|
|
1221
1287
|
[bridge]
|
|
1222
1288
|
);
|
|
@@ -1248,6 +1314,7 @@ function useFiasDataStore() {
|
|
|
1248
1314
|
key: res.key ?? key,
|
|
1249
1315
|
data: res.data,
|
|
1250
1316
|
updatedAt: res.updatedAt ?? "",
|
|
1317
|
+
...res.version !== void 0 ? { version: res.version } : {},
|
|
1251
1318
|
...res.authoredByCollaborator !== void 0 ? { authoredByCollaborator: res.authoredByCollaborator } : {}
|
|
1252
1319
|
};
|
|
1253
1320
|
},
|
|
@@ -1291,8 +1358,17 @@ function useFiasDataStore() {
|
|
|
1291
1358
|
[bridge]
|
|
1292
1359
|
);
|
|
1293
1360
|
const batch = useCallback(
|
|
1294
|
-
async (operations) => {
|
|
1295
|
-
await invokeEntityOp(
|
|
1361
|
+
async (operations, options) => {
|
|
1362
|
+
const res = await invokeEntityOp(
|
|
1363
|
+
bridge,
|
|
1364
|
+
PLUGIN_DATASTORE_ENTITY_ID,
|
|
1365
|
+
"batch",
|
|
1366
|
+
{
|
|
1367
|
+
operations,
|
|
1368
|
+
...options?.preconditions?.length ? { preconditions: options.preconditions } : {}
|
|
1369
|
+
}
|
|
1370
|
+
);
|
|
1371
|
+
return { written: res?.written };
|
|
1296
1372
|
},
|
|
1297
1373
|
[bridge]
|
|
1298
1374
|
);
|
|
@@ -1858,6 +1934,221 @@ function useVaultUserDocuments() {
|
|
|
1858
1934
|
);
|
|
1859
1935
|
return useMemo2(() => ({ pick, list, get, getDownloadUrl }), [pick, list, get, getDownloadUrl]);
|
|
1860
1936
|
}
|
|
1937
|
+
var COMMUNITY_ASSET_URL_REFRESH_BUFFER_MS = 3e4;
|
|
1938
|
+
var communityAssetUrlCache = /* @__PURE__ */ new Map();
|
|
1939
|
+
var communityAssetUrlInflight = /* @__PURE__ */ new Map();
|
|
1940
|
+
async function fetchCommunityAssetUrls(bridge, assetIds) {
|
|
1941
|
+
const now = Date.now();
|
|
1942
|
+
const hits = [];
|
|
1943
|
+
const misses = [];
|
|
1944
|
+
for (const assetId of assetIds) {
|
|
1945
|
+
const cached = communityAssetUrlCache.get(assetId);
|
|
1946
|
+
if (cached && now < cached.expiresAt - COMMUNITY_ASSET_URL_REFRESH_BUFFER_MS) {
|
|
1947
|
+
hits.push(cached);
|
|
1948
|
+
} else {
|
|
1949
|
+
misses.push(assetId);
|
|
1950
|
+
}
|
|
1951
|
+
}
|
|
1952
|
+
if (misses.length === 0) return hits;
|
|
1953
|
+
const pending = [];
|
|
1954
|
+
const toRequest = [];
|
|
1955
|
+
for (const assetId of misses) {
|
|
1956
|
+
const inflight = communityAssetUrlInflight.get(assetId);
|
|
1957
|
+
if (inflight) pending.push(inflight);
|
|
1958
|
+
else toRequest.push(assetId);
|
|
1959
|
+
}
|
|
1960
|
+
for (let i = 0; i < toRequest.length; i += COMMUNITY_ASSET_MAX_URL_BATCH) {
|
|
1961
|
+
const chunk = toRequest.slice(i, i + COMMUNITY_ASSET_MAX_URL_BATCH);
|
|
1962
|
+
const promise = invokeEntityOp(
|
|
1963
|
+
bridge,
|
|
1964
|
+
COMMUNITY_ASSETS_ENTITY_ID,
|
|
1965
|
+
"get_urls",
|
|
1966
|
+
{ assetIds: chunk }
|
|
1967
|
+
).then((res) => {
|
|
1968
|
+
for (const url of res.urls) {
|
|
1969
|
+
communityAssetUrlCache.set(url.assetId, url);
|
|
1970
|
+
}
|
|
1971
|
+
return res.urls;
|
|
1972
|
+
}).finally(() => {
|
|
1973
|
+
for (const assetId of chunk) {
|
|
1974
|
+
communityAssetUrlInflight.delete(assetId);
|
|
1975
|
+
}
|
|
1976
|
+
});
|
|
1977
|
+
for (const assetId of chunk) {
|
|
1978
|
+
communityAssetUrlInflight.set(assetId, promise);
|
|
1979
|
+
}
|
|
1980
|
+
pending.push(promise);
|
|
1981
|
+
}
|
|
1982
|
+
const settled = await Promise.all(pending);
|
|
1983
|
+
const requested = new Set(assetIds);
|
|
1984
|
+
const seen = new Set(hits.map((h) => h.assetId));
|
|
1985
|
+
for (const batch of settled) {
|
|
1986
|
+
for (const url of batch) {
|
|
1987
|
+
if (!requested.has(url.assetId) || seen.has(url.assetId)) continue;
|
|
1988
|
+
seen.add(url.assetId);
|
|
1989
|
+
hits.push(url);
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
return hits;
|
|
1993
|
+
}
|
|
1994
|
+
function useCommunityAssets() {
|
|
1995
|
+
const bridge = useBridge();
|
|
1996
|
+
const publish = useCallback(
|
|
1997
|
+
async (input) => {
|
|
1998
|
+
const res = await invokeEntityOp(
|
|
1999
|
+
bridge,
|
|
2000
|
+
COMMUNITY_ASSETS_ENTITY_ID,
|
|
2001
|
+
"publish",
|
|
2002
|
+
{
|
|
2003
|
+
fileId: input.fileId,
|
|
2004
|
+
title: input.title,
|
|
2005
|
+
caption: input.caption,
|
|
2006
|
+
tags: input.tags,
|
|
2007
|
+
clientRef: input.clientRef,
|
|
2008
|
+
attributionName: input.attributionName
|
|
2009
|
+
}
|
|
2010
|
+
);
|
|
2011
|
+
return res.asset;
|
|
2012
|
+
},
|
|
2013
|
+
[bridge]
|
|
2014
|
+
);
|
|
2015
|
+
const publishMany = useCallback(
|
|
2016
|
+
async (items) => {
|
|
2017
|
+
const results = [];
|
|
2018
|
+
for (let i = 0; i < items.length; i += COMMUNITY_ASSET_MAX_PUBLISH_BATCH) {
|
|
2019
|
+
const res = await invokeEntityOp(
|
|
2020
|
+
bridge,
|
|
2021
|
+
COMMUNITY_ASSETS_ENTITY_ID,
|
|
2022
|
+
"publish_many",
|
|
2023
|
+
{ items: items.slice(i, i + COMMUNITY_ASSET_MAX_PUBLISH_BATCH) }
|
|
2024
|
+
);
|
|
2025
|
+
results.push(...res.results);
|
|
2026
|
+
}
|
|
2027
|
+
return results;
|
|
2028
|
+
},
|
|
2029
|
+
[bridge]
|
|
2030
|
+
);
|
|
2031
|
+
const unpublish = useCallback(
|
|
2032
|
+
async (assetId) => {
|
|
2033
|
+
const res = await invokeEntityOp(
|
|
2034
|
+
bridge,
|
|
2035
|
+
COMMUNITY_ASSETS_ENTITY_ID,
|
|
2036
|
+
"unpublish",
|
|
2037
|
+
{ assetId }
|
|
2038
|
+
);
|
|
2039
|
+
communityAssetUrlCache.delete(assetId);
|
|
2040
|
+
return res.asset;
|
|
2041
|
+
},
|
|
2042
|
+
[bridge]
|
|
2043
|
+
);
|
|
2044
|
+
const listMine = useCallback(
|
|
2045
|
+
async (options) => invokeEntityOp(bridge, COMMUNITY_ASSETS_ENTITY_ID, "list_mine", {
|
|
2046
|
+
limit: options?.limit,
|
|
2047
|
+
cursor: options?.cursor
|
|
2048
|
+
}),
|
|
2049
|
+
[bridge]
|
|
2050
|
+
);
|
|
2051
|
+
const listCommunity = useCallback(
|
|
2052
|
+
async (options) => invokeEntityOp(
|
|
2053
|
+
bridge,
|
|
2054
|
+
COMMUNITY_ASSETS_ENTITY_ID,
|
|
2055
|
+
"list_community",
|
|
2056
|
+
{ limit: options?.limit, cursor: options?.cursor, tag: options?.tag }
|
|
2057
|
+
),
|
|
2058
|
+
[bridge]
|
|
2059
|
+
);
|
|
2060
|
+
const get = useCallback(
|
|
2061
|
+
async (assetId) => {
|
|
2062
|
+
const res = await invokeEntityOp(
|
|
2063
|
+
bridge,
|
|
2064
|
+
COMMUNITY_ASSETS_ENTITY_ID,
|
|
2065
|
+
"get",
|
|
2066
|
+
{ assetId }
|
|
2067
|
+
);
|
|
2068
|
+
return res.asset;
|
|
2069
|
+
},
|
|
2070
|
+
[bridge]
|
|
2071
|
+
);
|
|
2072
|
+
const getUrls = useCallback(
|
|
2073
|
+
(assetIds) => fetchCommunityAssetUrls(bridge, assetIds),
|
|
2074
|
+
[bridge]
|
|
2075
|
+
);
|
|
2076
|
+
const getUrl = useCallback(
|
|
2077
|
+
async (assetId) => {
|
|
2078
|
+
const [url] = await fetchCommunityAssetUrls(bridge, [assetId]);
|
|
2079
|
+
if (!url) {
|
|
2080
|
+
throw new Error(`Community asset ${assetId} is not available`);
|
|
2081
|
+
}
|
|
2082
|
+
return url;
|
|
2083
|
+
},
|
|
2084
|
+
[bridge]
|
|
2085
|
+
);
|
|
2086
|
+
const report = useCallback(
|
|
2087
|
+
async (assetId, reason, details) => invokeEntityOp(
|
|
2088
|
+
bridge,
|
|
2089
|
+
COMMUNITY_ASSETS_ENTITY_ID,
|
|
2090
|
+
"report",
|
|
2091
|
+
{ assetId, reason, details }
|
|
2092
|
+
),
|
|
2093
|
+
[bridge]
|
|
2094
|
+
);
|
|
2095
|
+
return useMemo2(
|
|
2096
|
+
() => ({
|
|
2097
|
+
publish,
|
|
2098
|
+
publishMany,
|
|
2099
|
+
unpublish,
|
|
2100
|
+
listMine,
|
|
2101
|
+
listCommunity,
|
|
2102
|
+
get,
|
|
2103
|
+
getUrl,
|
|
2104
|
+
getUrls,
|
|
2105
|
+
report
|
|
2106
|
+
}),
|
|
2107
|
+
[publish, publishMany, unpublish, listMine, listCommunity, get, getUrl, getUrls, report]
|
|
2108
|
+
);
|
|
2109
|
+
}
|
|
2110
|
+
function useFiasAIActions(config) {
|
|
2111
|
+
const bridge = useBridge();
|
|
2112
|
+
const onActionRef = useRef(config?.onAction ?? null);
|
|
2113
|
+
onActionRef.current = config?.onAction ?? null;
|
|
2114
|
+
useEffect2(() => {
|
|
2115
|
+
bridge.setAiActionHandler((actionId, params) => {
|
|
2116
|
+
const handler = onActionRef.current;
|
|
2117
|
+
if (!handler) {
|
|
2118
|
+
throw new Error("no Fias AI action handler is currently registered");
|
|
2119
|
+
}
|
|
2120
|
+
return handler(actionId, params);
|
|
2121
|
+
});
|
|
2122
|
+
return () => bridge.setAiActionHandler(null);
|
|
2123
|
+
}, [bridge]);
|
|
2124
|
+
const declarationJson = config ? JSON.stringify({ description: config.description, actions: config.actions }) : null;
|
|
2125
|
+
useEffect2(() => {
|
|
2126
|
+
let cancelled = false;
|
|
2127
|
+
void bridge.waitForInit().then(() => {
|
|
2128
|
+
if (cancelled) return;
|
|
2129
|
+
bridge.declareAiActions(
|
|
2130
|
+
declarationJson ? JSON.parse(declarationJson) : null
|
|
2131
|
+
);
|
|
2132
|
+
});
|
|
2133
|
+
return () => {
|
|
2134
|
+
cancelled = true;
|
|
2135
|
+
};
|
|
2136
|
+
}, [bridge, declarationJson]);
|
|
2137
|
+
useEffect2(() => {
|
|
2138
|
+
return () => bridge.declareAiActions(null);
|
|
2139
|
+
}, [bridge]);
|
|
2140
|
+
const stateJson = config?.state ? JSON.stringify(config.state) : null;
|
|
2141
|
+
useEffect2(() => {
|
|
2142
|
+
if (stateJson === null) return;
|
|
2143
|
+
let cancelled = false;
|
|
2144
|
+
void bridge.waitForInit().then(() => {
|
|
2145
|
+
if (!cancelled) bridge.sendAiState(JSON.parse(stateJson));
|
|
2146
|
+
});
|
|
2147
|
+
return () => {
|
|
2148
|
+
cancelled = true;
|
|
2149
|
+
};
|
|
2150
|
+
}, [bridge, stateJson]);
|
|
2151
|
+
}
|
|
1861
2152
|
|
|
1862
2153
|
// src/generated/surfaces.ts
|
|
1863
2154
|
var AUDIO_AUDIO_ISOLATION_SURFACE_KEY = "audio.audio-isolation";
|
|
@@ -1925,6 +2216,9 @@ var useIntegrationWebSearch = () => useSurface(
|
|
|
1925
2216
|
|
|
1926
2217
|
// src/generated/permissions.ts
|
|
1927
2218
|
var VALID_PLUGIN_PERMISSIONS = [
|
|
2219
|
+
"ai:actions",
|
|
2220
|
+
"assets:community:publish",
|
|
2221
|
+
"assets:community:read",
|
|
1928
2222
|
"assets:read",
|
|
1929
2223
|
"data:search",
|
|
1930
2224
|
"data:store",
|
|
@@ -1949,6 +2243,9 @@ function isValidPluginPermission(perm) {
|
|
|
1949
2243
|
return VALID_PLUGIN_PERMISSIONS.includes(perm);
|
|
1950
2244
|
}
|
|
1951
2245
|
var PLUGIN_PERMISSION_DESCRIPTIONS = {
|
|
2246
|
+
"ai:actions": "Let Fias AI operate this app for you \u2014 only actions you could do yourself in its interface, and risky ones ask you first.",
|
|
2247
|
+
"assets:community:publish": "Share images you made here so other people using this app can see them, and manage what you have shared.",
|
|
2248
|
+
"assets:community:read": "Show you images that other people using this app have shared. Everything shared is checked before anyone can see it.",
|
|
1952
2249
|
"assets:read": "Show images from this app's published asset library.",
|
|
1953
2250
|
"data:search": "Search this app's own data semantically \u2014 costs credits per search.",
|
|
1954
2251
|
"data:store": "Save structured data in this app's own private database.",
|
|
@@ -2006,7 +2303,8 @@ var fias = {
|
|
|
2006
2303
|
name,
|
|
2007
2304
|
userScope: options?.userScope ?? "user",
|
|
2008
2305
|
searchable: options?.searchable,
|
|
2009
|
-
writePolicy: options?.writePolicy
|
|
2306
|
+
writePolicy: options?.writePolicy,
|
|
2307
|
+
constraints: options?.constraints
|
|
2010
2308
|
}
|
|
2011
2309
|
);
|
|
2012
2310
|
return res.collection;
|
|
@@ -2022,12 +2320,16 @@ var fias = {
|
|
|
2022
2320
|
async deleteCollection(name) {
|
|
2023
2321
|
await invokeEntityOp(getBridge(), PLUGIN_DATASTORE_ENTITY_ID, "delete_collection", { name });
|
|
2024
2322
|
},
|
|
2323
|
+
/** Write a document. Resolves with the document's post-write `version`
|
|
2324
|
+
* (ADR-014) so a follow-up CAS batch needs no read-back. */
|
|
2025
2325
|
async put(collection, key, data) {
|
|
2026
|
-
await invokeEntityOp(
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2326
|
+
const res = await invokeEntityOp(
|
|
2327
|
+
getBridge(),
|
|
2328
|
+
PLUGIN_DATASTORE_ENTITY_ID,
|
|
2329
|
+
"put",
|
|
2330
|
+
{ collection, key, data }
|
|
2331
|
+
);
|
|
2332
|
+
return { version: res?.version };
|
|
2031
2333
|
},
|
|
2032
2334
|
async get(collection, key) {
|
|
2033
2335
|
const res = await invokeEntityOp(
|
|
@@ -2047,6 +2349,7 @@ var fias = {
|
|
|
2047
2349
|
key: res.key ?? key,
|
|
2048
2350
|
data: res.data,
|
|
2049
2351
|
updatedAt: res.updatedAt ?? "",
|
|
2352
|
+
...res.version !== void 0 ? { version: res.version } : {},
|
|
2050
2353
|
...res.authoredByCollaborator !== void 0 ? { authoredByCollaborator: res.authoredByCollaborator } : {}
|
|
2051
2354
|
};
|
|
2052
2355
|
},
|
|
@@ -2070,9 +2373,20 @@ var fias = {
|
|
|
2070
2373
|
async delete(collection, key) {
|
|
2071
2374
|
await invokeEntityOp(getBridge(), PLUGIN_DATASTORE_ENTITY_ID, "delete", { collection, key });
|
|
2072
2375
|
},
|
|
2073
|
-
/** Apply up to 25 put/delete ops in one all-or-nothing transaction.
|
|
2074
|
-
|
|
2075
|
-
|
|
2376
|
+
/** Apply up to 25 put/delete ops in one all-or-nothing transaction.
|
|
2377
|
+
* Pass `options.preconditions` (ADR-014) to make the batch conditional;
|
|
2378
|
+
* the result carries each put's post-write version. */
|
|
2379
|
+
async batch(operations, options) {
|
|
2380
|
+
const res = await invokeEntityOp(
|
|
2381
|
+
getBridge(),
|
|
2382
|
+
PLUGIN_DATASTORE_ENTITY_ID,
|
|
2383
|
+
"batch",
|
|
2384
|
+
{
|
|
2385
|
+
operations,
|
|
2386
|
+
...options?.preconditions?.length ? { preconditions: options.preconditions } : {}
|
|
2387
|
+
}
|
|
2388
|
+
);
|
|
2389
|
+
return { written: res?.written };
|
|
2076
2390
|
}
|
|
2077
2391
|
}
|
|
2078
2392
|
};
|
|
@@ -4033,6 +4347,371 @@ function raceWithTimeout(promise, ms) {
|
|
|
4033
4347
|
function useFiasFonts() {
|
|
4034
4348
|
return useMemo3(() => ({ fonts: FONT_CATALOG, ensureFontLoaded }), []);
|
|
4035
4349
|
}
|
|
4350
|
+
|
|
4351
|
+
// src/panels.ts
|
|
4352
|
+
var PANEL_MIN_ELEMENTS = 1;
|
|
4353
|
+
var PANEL_MAX_ELEMENTS = 24;
|
|
4354
|
+
var PANEL_TITLE_MAX_LENGTH = 80;
|
|
4355
|
+
var PANEL_TEXT_MAX_LENGTH = 500;
|
|
4356
|
+
var PANEL_IMAGE_ALT_MAX_LENGTH = 120;
|
|
4357
|
+
var PANEL_IMAGE_KEY_MAX_LENGTH = 500;
|
|
4358
|
+
var PANEL_IMAGE_MIN_HEIGHT = 24;
|
|
4359
|
+
var PANEL_IMAGE_MAX_HEIGHT = 512;
|
|
4360
|
+
var PANEL_BUTTON_LABEL_MAX_LENGTH = 40;
|
|
4361
|
+
var PANEL_ACTION_MAX_LENGTH = 2048;
|
|
4362
|
+
var PANEL_EMIT_TOKEN_MAX_LENGTH = 64;
|
|
4363
|
+
var PANEL_ITEMS_EMPTY_TEXT_MAX_LENGTH = 120;
|
|
4364
|
+
var PANEL_ITEMS_SLOT_MAX_LENGTH = 64;
|
|
4365
|
+
var PANEL_SHOW_IF_MAX_LENGTH = 64;
|
|
4366
|
+
var PANEL_PRIORITY_ABS_MAX = 1e3;
|
|
4367
|
+
var PANEL_THEME_FONT_MAX_LENGTH = 200;
|
|
4368
|
+
var PANEL_THEME_AMOUNT_FORMAT_MAX_LENGTH = 24;
|
|
4369
|
+
var PANEL_THEME_Z_MAX = 1e6;
|
|
4370
|
+
var PANEL_THEME_LENGTH_MAX_INTEGER_DIGITS = 4;
|
|
4371
|
+
var PANEL_IMAGE_ROOTS = ["dfe-icons", "dfe-avatars"];
|
|
4372
|
+
var PANEL_ELEMENT_KINDS = [
|
|
4373
|
+
"text",
|
|
4374
|
+
"conditionalText",
|
|
4375
|
+
"image",
|
|
4376
|
+
"assetImage",
|
|
4377
|
+
"items",
|
|
4378
|
+
"slottedItems",
|
|
4379
|
+
"button",
|
|
4380
|
+
"spacer"
|
|
4381
|
+
];
|
|
4382
|
+
var PANEL_ID_PATTERN = /^[a-z0-9][a-z0-9-]{1,63}$/;
|
|
4383
|
+
var SLOT_PATTERN = new RegExp(`^[a-z0-9][a-z0-9_-]{0,${PANEL_ITEMS_SLOT_MAX_LENGTH - 1}}$`);
|
|
4384
|
+
var EMIT_TOKEN_PATTERN = new RegExp(`^[a-z0-9][a-z0-9_-]{0,${PANEL_EMIT_TOKEN_MAX_LENGTH - 1}}$`);
|
|
4385
|
+
var SHOW_IF_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
4386
|
+
var ASSET_ID_PATTERN = /^as_[a-f0-9]{32}$/;
|
|
4387
|
+
var ARCHE_ID_PATTERN = /^arc_[a-f0-9]{32}$/;
|
|
4388
|
+
var IMAGE_KEY_PATTERN = new RegExp(
|
|
4389
|
+
`^(?:${PANEL_IMAGE_ROOTS.join("|")})/[A-Za-z0-9._/-]+\\.(?:png|jpe?g|webp|gif|svg)$`,
|
|
4390
|
+
"i"
|
|
4391
|
+
);
|
|
4392
|
+
var THEME_COLOR_PATTERN = /^(?:#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})|rgba?\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*(?:,\s*(?:0|1|0?\.\d{1,3})\s*)?\))$/i;
|
|
4393
|
+
var THEME_LENGTH_PATTERN = new RegExp(
|
|
4394
|
+
`^\\d{1,${PANEL_THEME_LENGTH_MAX_INTEGER_DIGITS}}(?:\\.\\d{1,3})?(?:px|rem|em)$`
|
|
4395
|
+
);
|
|
4396
|
+
var THEME_FONT_PATTERN = /^[A-Za-z0-9 '",._-]+$/;
|
|
4397
|
+
var TEXT_STYLES = ["title", "body", "caption"];
|
|
4398
|
+
var TEXT_ALIGNS = ["left", "center", "right"];
|
|
4399
|
+
var SIZES = ["small", "medium", "large"];
|
|
4400
|
+
var BUTTON_VARIANTS = ["primary", "secondary"];
|
|
4401
|
+
function isRecord(value) {
|
|
4402
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4403
|
+
}
|
|
4404
|
+
function rejectUnknownKeys(value, allowed, path, issues) {
|
|
4405
|
+
for (const key of Object.keys(value)) {
|
|
4406
|
+
if (!allowed.includes(key)) issues.push(`${path}: unknown field "${key}"`);
|
|
4407
|
+
}
|
|
4408
|
+
}
|
|
4409
|
+
function checkString(value, path, issues, opts) {
|
|
4410
|
+
if (typeof value !== "string") {
|
|
4411
|
+
issues.push(`${path}: expected a string`);
|
|
4412
|
+
return;
|
|
4413
|
+
}
|
|
4414
|
+
if (value.length < (opts.min ?? 1)) issues.push(`${path}: must not be empty`);
|
|
4415
|
+
if (value.length > opts.max) issues.push(`${path}: longer than ${opts.max} characters`);
|
|
4416
|
+
if (opts.pattern && !opts.pattern.test(value)) {
|
|
4417
|
+
issues.push(`${path}: ${opts.hint ?? "does not match the required format"}`);
|
|
4418
|
+
}
|
|
4419
|
+
}
|
|
4420
|
+
function checkOptionalEnum(value, path, issues, allowed) {
|
|
4421
|
+
if (value === void 0) return;
|
|
4422
|
+
if (typeof value !== "string" || !allowed.includes(value)) {
|
|
4423
|
+
issues.push(`${path}: must be one of ${allowed.join(" | ")}`);
|
|
4424
|
+
}
|
|
4425
|
+
}
|
|
4426
|
+
function checkOptionalBoolean(value, path, issues) {
|
|
4427
|
+
if (value !== void 0 && typeof value !== "boolean") issues.push(`${path}: expected a boolean`);
|
|
4428
|
+
}
|
|
4429
|
+
function checkOptionalIntRange(value, path, issues, min, max) {
|
|
4430
|
+
if (value === void 0) return;
|
|
4431
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value < min || value > max) {
|
|
4432
|
+
issues.push(`${path}: must be an integer between ${min} and ${max}`);
|
|
4433
|
+
}
|
|
4434
|
+
}
|
|
4435
|
+
function validatePanelAction(action, path, issues) {
|
|
4436
|
+
if (typeof action !== "string" || action.length === 0) {
|
|
4437
|
+
issues.push(`${path}: expected an action string`);
|
|
4438
|
+
return;
|
|
4439
|
+
}
|
|
4440
|
+
if (action.length > PANEL_ACTION_MAX_LENGTH) {
|
|
4441
|
+
issues.push(`${path}: longer than ${PANEL_ACTION_MAX_LENGTH} characters`);
|
|
4442
|
+
return;
|
|
4443
|
+
}
|
|
4444
|
+
if (action === "close") return;
|
|
4445
|
+
if (action.startsWith("emit:")) {
|
|
4446
|
+
if (!EMIT_TOKEN_PATTERN.test(action.slice("emit:".length))) {
|
|
4447
|
+
issues.push(
|
|
4448
|
+
`${path}: emit token must be 1\u2013${PANEL_EMIT_TOKEN_MAX_LENGTH} chars \u2014 lowercase letters, digits, hyphens and underscores, not starting with a separator`
|
|
4449
|
+
);
|
|
4450
|
+
}
|
|
4451
|
+
return;
|
|
4452
|
+
}
|
|
4453
|
+
if (action.startsWith("open_arche:")) {
|
|
4454
|
+
if (!ARCHE_ID_PATTERN.test(action.slice("open_arche:".length))) {
|
|
4455
|
+
issues.push(`${path}: open_arche target must be an arche id (arc_ + 32 hex chars)`);
|
|
4456
|
+
}
|
|
4457
|
+
return;
|
|
4458
|
+
}
|
|
4459
|
+
if (action.startsWith("open_url:")) {
|
|
4460
|
+
if (/\s/.test(action)) {
|
|
4461
|
+
issues.push(`${path}: action must not contain whitespace`);
|
|
4462
|
+
return;
|
|
4463
|
+
}
|
|
4464
|
+
let parsed;
|
|
4465
|
+
try {
|
|
4466
|
+
parsed = new URL(action.slice("open_url:".length));
|
|
4467
|
+
} catch {
|
|
4468
|
+
issues.push(`${path}: open_url must be a valid absolute URL`);
|
|
4469
|
+
return;
|
|
4470
|
+
}
|
|
4471
|
+
if (parsed.protocol !== "https:") issues.push(`${path}: open_url scheme must be https`);
|
|
4472
|
+
return;
|
|
4473
|
+
}
|
|
4474
|
+
issues.push(
|
|
4475
|
+
`${path}: must be one of close | emit:<token> | open_arche:arc_<32 hex> | open_url:https://\u2026`
|
|
4476
|
+
);
|
|
4477
|
+
}
|
|
4478
|
+
function validateTextFields(element, path, issues) {
|
|
4479
|
+
checkString(element.text, `${path}.text`, issues, { max: PANEL_TEXT_MAX_LENGTH });
|
|
4480
|
+
checkOptionalEnum(element.style, `${path}.style`, issues, TEXT_STYLES);
|
|
4481
|
+
checkOptionalEnum(element.align, `${path}.align`, issues, TEXT_ALIGNS);
|
|
4482
|
+
checkOptionalBoolean(element.joinNext, `${path}.joinNext`, issues);
|
|
4483
|
+
}
|
|
4484
|
+
function validateItemsFields(element, path, issues) {
|
|
4485
|
+
checkOptionalBoolean(element.showIcons, `${path}.showIcons`, issues);
|
|
4486
|
+
checkOptionalEnum(element.iconSize, `${path}.iconSize`, issues, SIZES);
|
|
4487
|
+
if (element.emptyText !== void 0) {
|
|
4488
|
+
checkString(element.emptyText, `${path}.emptyText`, issues, {
|
|
4489
|
+
min: 0,
|
|
4490
|
+
max: PANEL_ITEMS_EMPTY_TEXT_MAX_LENGTH
|
|
4491
|
+
});
|
|
4492
|
+
}
|
|
4493
|
+
}
|
|
4494
|
+
function validateImageFields(element, path, issues) {
|
|
4495
|
+
if (element.alt !== void 0) {
|
|
4496
|
+
checkString(element.alt, `${path}.alt`, issues, { min: 0, max: PANEL_IMAGE_ALT_MAX_LENGTH });
|
|
4497
|
+
}
|
|
4498
|
+
checkOptionalIntRange(
|
|
4499
|
+
element.maxHeight,
|
|
4500
|
+
`${path}.maxHeight`,
|
|
4501
|
+
issues,
|
|
4502
|
+
PANEL_IMAGE_MIN_HEIGHT,
|
|
4503
|
+
PANEL_IMAGE_MAX_HEIGHT
|
|
4504
|
+
);
|
|
4505
|
+
}
|
|
4506
|
+
function validateElement(value, path, issues) {
|
|
4507
|
+
if (!isRecord(value)) {
|
|
4508
|
+
issues.push(`${path}: expected an object`);
|
|
4509
|
+
return;
|
|
4510
|
+
}
|
|
4511
|
+
const kind = value.kind;
|
|
4512
|
+
if (typeof kind !== "string" || !PANEL_ELEMENT_KINDS.includes(kind)) {
|
|
4513
|
+
issues.push(
|
|
4514
|
+
`${path}.kind: unknown element kind ${JSON.stringify(kind)} \u2014 expected one of ${PANEL_ELEMENT_KINDS.join(" | ")}`
|
|
4515
|
+
);
|
|
4516
|
+
return;
|
|
4517
|
+
}
|
|
4518
|
+
switch (kind) {
|
|
4519
|
+
case "text":
|
|
4520
|
+
rejectUnknownKeys(value, ["kind", "text", "style", "align", "joinNext"], path, issues);
|
|
4521
|
+
validateTextFields(value, path, issues);
|
|
4522
|
+
return;
|
|
4523
|
+
case "conditionalText":
|
|
4524
|
+
rejectUnknownKeys(
|
|
4525
|
+
value,
|
|
4526
|
+
["kind", "text", "style", "align", "joinNext", "showIf"],
|
|
4527
|
+
path,
|
|
4528
|
+
issues
|
|
4529
|
+
);
|
|
4530
|
+
validateTextFields(value, path, issues);
|
|
4531
|
+
checkString(value.showIf, `${path}.showIf`, issues, {
|
|
4532
|
+
max: PANEL_SHOW_IF_MAX_LENGTH,
|
|
4533
|
+
pattern: SHOW_IF_PATTERN,
|
|
4534
|
+
hint: "must be a value NAME (letters, digits, underscore; not starting with a digit) \u2014 expressions and operators are not supported"
|
|
4535
|
+
});
|
|
4536
|
+
return;
|
|
4537
|
+
case "image":
|
|
4538
|
+
rejectUnknownKeys(value, ["kind", "imageKey", "alt", "maxHeight"], path, issues);
|
|
4539
|
+
checkString(value.imageKey, `${path}.imageKey`, issues, {
|
|
4540
|
+
max: PANEL_IMAGE_KEY_MAX_LENGTH,
|
|
4541
|
+
pattern: IMAGE_KEY_PATTERN,
|
|
4542
|
+
hint: `must be a relative key under ${PANEL_IMAGE_ROOTS.join(" or ")}/ ending in an image extension (no URL, no leading slash)`
|
|
4543
|
+
});
|
|
4544
|
+
if (typeof value.imageKey === "string" && value.imageKey.includes("..")) {
|
|
4545
|
+
issues.push(`${path}.imageKey: must not contain ".."`);
|
|
4546
|
+
}
|
|
4547
|
+
validateImageFields(value, path, issues);
|
|
4548
|
+
return;
|
|
4549
|
+
case "assetImage":
|
|
4550
|
+
rejectUnknownKeys(value, ["kind", "assetId", "alt", "maxHeight"], path, issues);
|
|
4551
|
+
checkString(value.assetId, `${path}.assetId`, issues, {
|
|
4552
|
+
max: 64,
|
|
4553
|
+
pattern: ASSET_ID_PATTERN,
|
|
4554
|
+
hint: "must be an arche asset id (as_ + 32 hex chars)"
|
|
4555
|
+
});
|
|
4556
|
+
validateImageFields(value, path, issues);
|
|
4557
|
+
return;
|
|
4558
|
+
case "items":
|
|
4559
|
+
rejectUnknownKeys(value, ["kind", "showIcons", "iconSize", "emptyText"], path, issues);
|
|
4560
|
+
validateItemsFields(value, path, issues);
|
|
4561
|
+
return;
|
|
4562
|
+
case "slottedItems":
|
|
4563
|
+
rejectUnknownKeys(
|
|
4564
|
+
value,
|
|
4565
|
+
["kind", "slot", "showIcons", "iconSize", "emptyText"],
|
|
4566
|
+
path,
|
|
4567
|
+
issues
|
|
4568
|
+
);
|
|
4569
|
+
checkString(value.slot, `${path}.slot`, issues, {
|
|
4570
|
+
max: PANEL_ITEMS_SLOT_MAX_LENGTH,
|
|
4571
|
+
pattern: SLOT_PATTERN,
|
|
4572
|
+
hint: "must be lowercase letters, digits, hyphens and underscores, not starting with a separator"
|
|
4573
|
+
});
|
|
4574
|
+
validateItemsFields(value, path, issues);
|
|
4575
|
+
return;
|
|
4576
|
+
case "button":
|
|
4577
|
+
rejectUnknownKeys(value, ["kind", "label", "action", "variant"], path, issues);
|
|
4578
|
+
checkString(value.label, `${path}.label`, issues, { max: PANEL_BUTTON_LABEL_MAX_LENGTH });
|
|
4579
|
+
validatePanelAction(value.action, `${path}.action`, issues);
|
|
4580
|
+
checkOptionalEnum(value.variant, `${path}.variant`, issues, BUTTON_VARIANTS);
|
|
4581
|
+
return;
|
|
4582
|
+
case "spacer":
|
|
4583
|
+
rejectUnknownKeys(value, ["kind", "size"], path, issues);
|
|
4584
|
+
checkOptionalEnum(value.size, `${path}.size`, issues, SIZES);
|
|
4585
|
+
return;
|
|
4586
|
+
}
|
|
4587
|
+
}
|
|
4588
|
+
var THEME_COLOR_FIELDS = ["bg", "fg", "border", "accent", "accentFg", "scrim"];
|
|
4589
|
+
var THEME_LENGTH_FIELDS = [
|
|
4590
|
+
"radius",
|
|
4591
|
+
"buttonRadius",
|
|
4592
|
+
"gap",
|
|
4593
|
+
"fontSize",
|
|
4594
|
+
"widthSmall",
|
|
4595
|
+
"widthMedium",
|
|
4596
|
+
"widthLarge"
|
|
4597
|
+
];
|
|
4598
|
+
function validatePanelTheme(value, path = "theme") {
|
|
4599
|
+
const issues = [];
|
|
4600
|
+
if (!isRecord(value)) return { ok: false, issues: [`${path}: expected an object`] };
|
|
4601
|
+
rejectUnknownKeys(
|
|
4602
|
+
value,
|
|
4603
|
+
[...THEME_COLOR_FIELDS, ...THEME_LENGTH_FIELDS, "font", "z", "amountFormat"],
|
|
4604
|
+
path,
|
|
4605
|
+
issues
|
|
4606
|
+
);
|
|
4607
|
+
for (const field of THEME_COLOR_FIELDS) {
|
|
4608
|
+
if (value[field] === void 0) continue;
|
|
4609
|
+
checkString(value[field], `${path}.${field}`, issues, {
|
|
4610
|
+
max: 64,
|
|
4611
|
+
pattern: THEME_COLOR_PATTERN,
|
|
4612
|
+
hint: "must be a hex colour (#rgb, #rgba, #rrggbb, #rrggbbaa) or rgb()/rgba() with numeric components"
|
|
4613
|
+
});
|
|
4614
|
+
}
|
|
4615
|
+
for (const field of THEME_LENGTH_FIELDS) {
|
|
4616
|
+
if (value[field] === void 0) continue;
|
|
4617
|
+
checkString(value[field], `${path}.${field}`, issues, {
|
|
4618
|
+
max: 16,
|
|
4619
|
+
pattern: THEME_LENGTH_PATTERN,
|
|
4620
|
+
hint: `must be a non-negative number (max ${PANEL_THEME_LENGTH_MAX_INTEGER_DIGITS} digits before the point) followed by px, rem or em`
|
|
4621
|
+
});
|
|
4622
|
+
}
|
|
4623
|
+
if (value.font !== void 0) {
|
|
4624
|
+
checkString(value.font, `${path}.font`, issues, {
|
|
4625
|
+
max: PANEL_THEME_FONT_MAX_LENGTH,
|
|
4626
|
+
pattern: THEME_FONT_PATTERN,
|
|
4627
|
+
hint: "must be a font-family stack (names, commas, quotes) \u2014 no parentheses, so no url() or var()"
|
|
4628
|
+
});
|
|
4629
|
+
}
|
|
4630
|
+
checkOptionalIntRange(value.z, `${path}.z`, issues, 0, PANEL_THEME_Z_MAX);
|
|
4631
|
+
if (value.amountFormat !== void 0) {
|
|
4632
|
+
checkString(value.amountFormat, `${path}.amountFormat`, issues, {
|
|
4633
|
+
max: PANEL_THEME_AMOUNT_FORMAT_MAX_LENGTH
|
|
4634
|
+
});
|
|
4635
|
+
if (typeof value.amountFormat === "string" && !value.amountFormat.includes("{n}")) {
|
|
4636
|
+
issues.push(`${path}.amountFormat: must contain the placeholder {n}`);
|
|
4637
|
+
}
|
|
4638
|
+
}
|
|
4639
|
+
return issues.length === 0 ? { ok: true, issues: [] } : { ok: false, issues };
|
|
4640
|
+
}
|
|
4641
|
+
function validatePanelDefinition(value, path = "panel") {
|
|
4642
|
+
const issues = [];
|
|
4643
|
+
if (!isRecord(value)) return { ok: false, issues: [`${path}: expected an object`] };
|
|
4644
|
+
rejectUnknownKeys(value, ["id", "title", "elements", "presentation"], path, issues);
|
|
4645
|
+
checkString(value.id, `${path}.id`, issues, {
|
|
4646
|
+
max: 64,
|
|
4647
|
+
pattern: PANEL_ID_PATTERN,
|
|
4648
|
+
hint: "must be 2\u201364 chars: lowercase letters, digits and hyphens, not starting with a hyphen"
|
|
4649
|
+
});
|
|
4650
|
+
checkString(value.title, `${path}.title`, issues, { max: PANEL_TITLE_MAX_LENGTH });
|
|
4651
|
+
if (!Array.isArray(value.elements)) {
|
|
4652
|
+
issues.push(`${path}.elements: expected an array`);
|
|
4653
|
+
} else {
|
|
4654
|
+
if (value.elements.length < PANEL_MIN_ELEMENTS) {
|
|
4655
|
+
issues.push(`${path}.elements: needs at least ${PANEL_MIN_ELEMENTS} element`);
|
|
4656
|
+
}
|
|
4657
|
+
if (value.elements.length > PANEL_MAX_ELEMENTS) {
|
|
4658
|
+
issues.push(`${path}.elements: more than ${PANEL_MAX_ELEMENTS} elements`);
|
|
4659
|
+
}
|
|
4660
|
+
value.elements.forEach(
|
|
4661
|
+
(element, index) => validateElement(element, `${path}.elements[${index}]`, issues)
|
|
4662
|
+
);
|
|
4663
|
+
}
|
|
4664
|
+
if (value.presentation !== void 0) {
|
|
4665
|
+
if (!isRecord(value.presentation)) {
|
|
4666
|
+
issues.push(`${path}.presentation: expected an object`);
|
|
4667
|
+
} else {
|
|
4668
|
+
rejectUnknownKeys(
|
|
4669
|
+
value.presentation,
|
|
4670
|
+
["size", "dismissible", "priority"],
|
|
4671
|
+
`${path}.presentation`,
|
|
4672
|
+
issues
|
|
4673
|
+
);
|
|
4674
|
+
checkOptionalEnum(value.presentation.size, `${path}.presentation.size`, issues, SIZES);
|
|
4675
|
+
checkOptionalBoolean(
|
|
4676
|
+
value.presentation.dismissible,
|
|
4677
|
+
`${path}.presentation.dismissible`,
|
|
4678
|
+
issues
|
|
4679
|
+
);
|
|
4680
|
+
checkOptionalIntRange(
|
|
4681
|
+
value.presentation.priority,
|
|
4682
|
+
`${path}.presentation.priority`,
|
|
4683
|
+
issues,
|
|
4684
|
+
-PANEL_PRIORITY_ABS_MAX,
|
|
4685
|
+
PANEL_PRIORITY_ABS_MAX
|
|
4686
|
+
);
|
|
4687
|
+
}
|
|
4688
|
+
}
|
|
4689
|
+
return issues.length === 0 ? { ok: true, issues: [] } : { ok: false, issues };
|
|
4690
|
+
}
|
|
4691
|
+
function validatePanelCatalog(value) {
|
|
4692
|
+
const issues = [];
|
|
4693
|
+
if (!isRecord(value)) return { ok: false, issues: ["catalog: expected an object"] };
|
|
4694
|
+
rejectUnknownKeys(value, ["panels", "theme"], "catalog", issues);
|
|
4695
|
+
if (value.theme !== void 0) {
|
|
4696
|
+
const theme = validatePanelTheme(value.theme, "catalog.theme");
|
|
4697
|
+
if (!theme.ok) issues.push(...theme.issues);
|
|
4698
|
+
}
|
|
4699
|
+
if (!Array.isArray(value.panels)) {
|
|
4700
|
+
issues.push("catalog.panels: expected an array");
|
|
4701
|
+
return { ok: false, issues };
|
|
4702
|
+
}
|
|
4703
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4704
|
+
value.panels.forEach((panel, index) => {
|
|
4705
|
+
const path = `catalog.panels[${index}]`;
|
|
4706
|
+
const result = validatePanelDefinition(panel, path);
|
|
4707
|
+
if (!result.ok) issues.push(...result.issues);
|
|
4708
|
+
if (isRecord(panel) && typeof panel.id === "string") {
|
|
4709
|
+
if (seen.has(panel.id)) issues.push(`${path}.id: duplicate panel id "${panel.id}"`);
|
|
4710
|
+
seen.add(panel.id);
|
|
4711
|
+
}
|
|
4712
|
+
});
|
|
4713
|
+
return issues.length === 0 ? { ok: true, issues: [] } : { ok: false, issues };
|
|
4714
|
+
}
|
|
4036
4715
|
export {
|
|
4037
4716
|
AUDIO_AUDIO_ISOLATION_SURFACE_KEY,
|
|
4038
4717
|
AUDIO_FORCED_ALIGNMENT_SURFACE_KEY,
|
|
@@ -4065,6 +4744,21 @@ export {
|
|
|
4065
4744
|
LIGHT_THEME,
|
|
4066
4745
|
NLLB_LANGUAGES,
|
|
4067
4746
|
NLLB_TRANSLATION_ENTITY_ID,
|
|
4747
|
+
PANEL_BUTTON_LABEL_MAX_LENGTH,
|
|
4748
|
+
PANEL_ELEMENT_KINDS,
|
|
4749
|
+
PANEL_EMIT_TOKEN_MAX_LENGTH,
|
|
4750
|
+
PANEL_IMAGE_ROOTS,
|
|
4751
|
+
PANEL_ITEMS_SLOT_MAX_LENGTH,
|
|
4752
|
+
PANEL_MAX_ELEMENTS,
|
|
4753
|
+
PANEL_MIN_ELEMENTS,
|
|
4754
|
+
PANEL_PRIORITY_ABS_MAX,
|
|
4755
|
+
PANEL_SHOW_IF_MAX_LENGTH,
|
|
4756
|
+
PANEL_TEXT_MAX_LENGTH,
|
|
4757
|
+
PANEL_THEME_AMOUNT_FORMAT_MAX_LENGTH,
|
|
4758
|
+
PANEL_THEME_FONT_MAX_LENGTH,
|
|
4759
|
+
PANEL_THEME_LENGTH_MAX_INTEGER_DIGITS,
|
|
4760
|
+
PANEL_THEME_Z_MAX,
|
|
4761
|
+
PANEL_TITLE_MAX_LENGTH,
|
|
4068
4762
|
PLUGIN_PERMISSION_DESCRIPTIONS,
|
|
4069
4763
|
SDK_BRIDGE_PROTOCOL_VERSION,
|
|
4070
4764
|
SDK_REQUIRES_HOST_PROTOCOL_VERSION,
|
|
@@ -4082,6 +4776,7 @@ export {
|
|
|
4082
4776
|
useArcheAssets,
|
|
4083
4777
|
useAudioGeneration,
|
|
4084
4778
|
useClientEntity,
|
|
4779
|
+
useCommunityAssets,
|
|
4085
4780
|
useDataSubscription,
|
|
4086
4781
|
useElevenLabsAudioIsolation,
|
|
4087
4782
|
useElevenLabsForcedAlignment,
|
|
@@ -4092,6 +4787,7 @@ export {
|
|
|
4092
4787
|
useElevenLabsVoiceChanger,
|
|
4093
4788
|
useElevenLabsVoiceDesign,
|
|
4094
4789
|
useEntityInvocation,
|
|
4790
|
+
useFiasAIActions,
|
|
4095
4791
|
useFiasDataStore,
|
|
4096
4792
|
useFiasFonts,
|
|
4097
4793
|
useFiasNavigation,
|
|
@@ -4121,5 +4817,9 @@ export {
|
|
|
4121
4817
|
useStepNavigation,
|
|
4122
4818
|
useSurface,
|
|
4123
4819
|
useVaultDocuments,
|
|
4124
|
-
useVaultUserDocuments
|
|
4820
|
+
useVaultUserDocuments,
|
|
4821
|
+
validatePanelAction,
|
|
4822
|
+
validatePanelCatalog,
|
|
4823
|
+
validatePanelDefinition,
|
|
4824
|
+
validatePanelTheme
|
|
4125
4825
|
};
|