@happyvertical/smrt-web 0.49.3 → 0.49.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/dist/chunks/{src-BSrj5jW0.js → src-0IQGhPIM.js} +126 -12
- package/dist/chunks/src-0IQGhPIM.js.map +1 -0
- package/dist/index.d.ts +82 -0
- package/dist/index.js +2 -2
- package/dist/webmcp.js +1 -1
- package/package.json +3 -3
- package/dist/chunks/src-BSrj5jW0.js.map +0 -1
package/README.md
CHANGED
|
@@ -15,6 +15,12 @@ fetch one canonical bounded page. Visible runs update state; `background`,
|
|
|
15
15
|
stale rows available while refreshing, cancels superseded visible runs, and can
|
|
16
16
|
attach a query-scoped live subscription.
|
|
17
17
|
|
|
18
|
+
Data-surface actions use `executeSmrtWebDataSurfaceAction(transport, request)`.
|
|
19
|
+
Its request carries the server-issued revision and, for apply, an idempotency
|
|
20
|
+
key; the browser normalizer rejects malformed, oversized, or mismatched
|
|
21
|
+
preview/apply results before they reach UI state. The authenticated server still
|
|
22
|
+
derives authority and validates confirmation tokens.
|
|
23
|
+
|
|
18
24
|
## Installation
|
|
19
25
|
|
|
20
26
|
```bash
|
|
@@ -126,6 +132,7 @@ core.
|
|
|
126
132
|
| --- | --- |
|
|
127
133
|
| Collections | `createSmrtCollection`, `createSmrtWebClient`, `newLocalId` |
|
|
128
134
|
| Remote queries | `createSmrtWebQuery`, `SmrtWebQueryTransport` |
|
|
135
|
+
| Data-surface actions | `executeSmrtWebDataSurfaceAction`, `SmrtWebDataSurfaceActionTransport` |
|
|
129
136
|
| HTTP | `createDefinitionFetchers`, `unwrapListResult`, `unwrapItemResult` |
|
|
130
137
|
| Offline | `offlineOutbox`, `getOutboxHandle` |
|
|
131
138
|
| Persistence | `persistCollection`, `wipeDurableStore` |
|
|
@@ -21,7 +21,7 @@ var persistedMutationResults = /* @__PURE__ */ new WeakMap();
|
|
|
21
21
|
var mutationTargetHydrators = /* @__PURE__ */ new WeakMap();
|
|
22
22
|
//#endregion
|
|
23
23
|
//#region src/data-query.ts
|
|
24
|
-
var FORBIDDEN_KEYS = /* @__PURE__ */ new Set([
|
|
24
|
+
var FORBIDDEN_KEYS$1 = /* @__PURE__ */ new Set([
|
|
25
25
|
"__proto__",
|
|
26
26
|
"constructor",
|
|
27
27
|
"prototype"
|
|
@@ -44,10 +44,10 @@ function plainObject(value, label) {
|
|
|
44
44
|
if (!value || typeof value !== "object" || Array.isArray(value)) throw new TypeError(`${label} must be a plain object`);
|
|
45
45
|
const prototype = Object.getPrototypeOf(value);
|
|
46
46
|
if (prototype !== Object.prototype && prototype !== null) throw new TypeError(`${label} must be a plain object`);
|
|
47
|
-
for (const key of Object.keys(value)) if (FORBIDDEN_KEYS.has(key)) throw new TypeError(`${label} contains a forbidden key`);
|
|
47
|
+
for (const key of Object.keys(value)) if (FORBIDDEN_KEYS$1.has(key)) throw new TypeError(`${label} contains a forbidden key`);
|
|
48
48
|
return value;
|
|
49
49
|
}
|
|
50
|
-
function exactKeys(value, allowed, label) {
|
|
50
|
+
function exactKeys$1(value, allowed, label) {
|
|
51
51
|
const keys = new Set(allowed);
|
|
52
52
|
for (const key of Object.keys(value)) if (!keys.has(key)) throw new TypeError(`${label} contains ${key}`);
|
|
53
53
|
}
|
|
@@ -111,14 +111,14 @@ function normalizeTotal(value) {
|
|
|
111
111
|
const total = plainObject(value, "Data query total");
|
|
112
112
|
const kind = stringValue(total.kind, "Data query total kind");
|
|
113
113
|
if (kind === "unavailable") {
|
|
114
|
-
exactKeys(total, ["kind", "reason"], "Data query unavailable total");
|
|
114
|
+
exactKeys$1(total, ["kind", "reason"], "Data query unavailable total");
|
|
115
115
|
return {
|
|
116
116
|
kind,
|
|
117
117
|
...total.reason === void 0 ? {} : { reason: stringValue(total.reason, "Data query total reason") }
|
|
118
118
|
};
|
|
119
119
|
}
|
|
120
120
|
if (kind !== "exact" && kind !== "estimated") throw new TypeError("Data query total kind is invalid");
|
|
121
|
-
exactKeys(total, [
|
|
121
|
+
exactKeys$1(total, [
|
|
122
122
|
"kind",
|
|
123
123
|
"value",
|
|
124
124
|
"asOf"
|
|
@@ -136,7 +136,7 @@ function normalizeFacets(value, budget) {
|
|
|
136
136
|
const fields = /* @__PURE__ */ new Set();
|
|
137
137
|
return value.map((candidate, index) => {
|
|
138
138
|
const facet = plainObject(candidate, `Data query facet ${index}`);
|
|
139
|
-
exactKeys(facet, [
|
|
139
|
+
exactKeys$1(facet, [
|
|
140
140
|
"field",
|
|
141
141
|
"values",
|
|
142
142
|
"truncated"
|
|
@@ -151,7 +151,7 @@ function normalizeFacets(value, budget) {
|
|
|
151
151
|
field,
|
|
152
152
|
values: facet.values.map((value2, valueIndex) => {
|
|
153
153
|
const entry = plainObject(value2, `Data query facet ${index} value ${valueIndex}`);
|
|
154
|
-
exactKeys(entry, ["value", "count"], "Data query facet value");
|
|
154
|
+
exactKeys$1(entry, ["value", "count"], "Data query facet value");
|
|
155
155
|
return {
|
|
156
156
|
value: scalar(entry.value, "Data query facet value", budget),
|
|
157
157
|
count: nonNegativeInteger(entry.count, "Data query facet count")
|
|
@@ -163,7 +163,7 @@ function normalizeFacets(value, budget) {
|
|
|
163
163
|
}
|
|
164
164
|
function normalizeSmrtWebDataQueryResult(value) {
|
|
165
165
|
const result = plainObject(value, "Data query result");
|
|
166
|
-
exactKeys(result, [
|
|
166
|
+
exactKeys$1(result, [
|
|
167
167
|
"version",
|
|
168
168
|
"requestId",
|
|
169
169
|
"queryFingerprint",
|
|
@@ -190,7 +190,7 @@ function normalizeSmrtWebDataQueryResult(value) {
|
|
|
190
190
|
let page;
|
|
191
191
|
if (result.page !== void 0) {
|
|
192
192
|
const candidate = plainObject(result.page, "Data query page");
|
|
193
|
-
exactKeys(candidate, [
|
|
193
|
+
exactKeys$1(candidate, [
|
|
194
194
|
"kind",
|
|
195
195
|
"limit",
|
|
196
196
|
"offset",
|
|
@@ -227,7 +227,7 @@ function normalizeSmrtWebDataQueryResult(value) {
|
|
|
227
227
|
}
|
|
228
228
|
if (page && rows.length > page.limit) throw new TypeError("Data query rows exceed the declared page limit");
|
|
229
229
|
const freshness = plainObject(result.freshness, "Data query freshness");
|
|
230
|
-
exactKeys(freshness, ["state", "asOf"], "Data query freshness");
|
|
230
|
+
exactKeys$1(freshness, ["state", "asOf"], "Data query freshness");
|
|
231
231
|
const state = stringValue(freshness.state, "Data query freshness state");
|
|
232
232
|
if (state !== "fresh" && state !== "stale" && state !== "unknown") throw new TypeError("Data query freshness state is invalid");
|
|
233
233
|
if (!Array.isArray(result.warnings) || result.warnings.length > 100 || result.warnings.some((item) => typeof item !== "string")) throw new TypeError("Data query warnings must be strings");
|
|
@@ -259,6 +259,120 @@ async function executeSmrtWebDataQuery(transport, request, options) {
|
|
|
259
259
|
return result;
|
|
260
260
|
}
|
|
261
261
|
//#endregion
|
|
262
|
+
//#region src/data-surface-actions.ts
|
|
263
|
+
var MAX_SMRT_WEB_DATA_SURFACE_ACTION_RESULT_BYTES = 1e6;
|
|
264
|
+
var MAX_SMRT_WEB_DATA_SURFACE_ACTION_IDENTIFIER_LENGTH = 256;
|
|
265
|
+
var MAX_SMRT_WEB_DATA_SURFACE_ACTION_JSON_DEPTH = 16;
|
|
266
|
+
var MAX_SMRT_WEB_DATA_SURFACE_ACTION_CONTAINER_ITEMS = 1e3;
|
|
267
|
+
var FORBIDDEN_KEYS = /* @__PURE__ */ new Set([
|
|
268
|
+
"__proto__",
|
|
269
|
+
"constructor",
|
|
270
|
+
"prototype"
|
|
271
|
+
]);
|
|
272
|
+
function object(value, label) {
|
|
273
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new TypeError(`${label} must be a plain object`);
|
|
274
|
+
const prototype = Object.getPrototypeOf(value);
|
|
275
|
+
if (prototype !== Object.prototype && prototype !== null) throw new TypeError(`${label} must be a plain object`);
|
|
276
|
+
for (const key of Object.keys(value)) if (FORBIDDEN_KEYS.has(key)) throw new TypeError(`${label} contains a forbidden key`);
|
|
277
|
+
return value;
|
|
278
|
+
}
|
|
279
|
+
function exactKeys(value, allowed, label) {
|
|
280
|
+
const allowedKeys = new Set(allowed);
|
|
281
|
+
for (const key of Object.keys(value)) if (!allowedKeys.has(key)) throw new TypeError(`${label} contains ${key}`);
|
|
282
|
+
}
|
|
283
|
+
function identifier(value, label) {
|
|
284
|
+
if (typeof value !== "string" || value.length === 0 || value.length > 256) throw new TypeError(`${label} must be a bounded non-empty string`);
|
|
285
|
+
return value;
|
|
286
|
+
}
|
|
287
|
+
function json(value, label, depth = 0) {
|
|
288
|
+
if (depth > 16) throw new TypeError(`${label} exceeds JSON depth`);
|
|
289
|
+
if (value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value)) return value;
|
|
290
|
+
if (Array.isArray(value)) {
|
|
291
|
+
if (value.length > 1e3) throw new TypeError(`${label} exceeds the container-item limit`);
|
|
292
|
+
return value.map((entry, index) => json(entry, `${label}[${index}]`, depth + 1));
|
|
293
|
+
}
|
|
294
|
+
const source = object(value, label);
|
|
295
|
+
if (Object.keys(source).length > 1e3) throw new TypeError(`${label} exceeds the container-item limit`);
|
|
296
|
+
const result = /* @__PURE__ */ Object.create(null);
|
|
297
|
+
for (const [key, entry] of Object.entries(source)) result[key] = json(entry, `${label}.${key}`, depth + 1);
|
|
298
|
+
return result;
|
|
299
|
+
}
|
|
300
|
+
function identity(value) {
|
|
301
|
+
const source = object(value, "Data surface identity");
|
|
302
|
+
exactKeys(source, [
|
|
303
|
+
"surfaceId",
|
|
304
|
+
"kind",
|
|
305
|
+
"subject"
|
|
306
|
+
], "Data surface identity");
|
|
307
|
+
const kind = source.kind;
|
|
308
|
+
if (![
|
|
309
|
+
"table",
|
|
310
|
+
"list",
|
|
311
|
+
"report",
|
|
312
|
+
"custom"
|
|
313
|
+
].includes(kind)) throw new TypeError("Data surface identity kind is invalid");
|
|
314
|
+
const result = {
|
|
315
|
+
surfaceId: identifier(source.surfaceId, "Data surface identity surfaceId"),
|
|
316
|
+
kind
|
|
317
|
+
};
|
|
318
|
+
if (source.subject !== void 0) {
|
|
319
|
+
const subject = object(source.subject, "Data surface identity subject");
|
|
320
|
+
exactKeys(subject, [
|
|
321
|
+
"type",
|
|
322
|
+
"id",
|
|
323
|
+
"label"
|
|
324
|
+
], "Data surface identity subject");
|
|
325
|
+
result.subject = {
|
|
326
|
+
type: identifier(subject.type, "Data surface identity subject type"),
|
|
327
|
+
id: identifier(subject.id, "Data surface identity subject id"),
|
|
328
|
+
...subject.label === void 0 ? {} : { label: identifier(subject.label, "Data surface identity subject label") }
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
return result;
|
|
332
|
+
}
|
|
333
|
+
function sameIdentity(left, right) {
|
|
334
|
+
return left.surfaceId === right.surfaceId && left.kind === right.kind && left.subject?.type === right.subject?.type && left.subject?.id === right.subject?.id;
|
|
335
|
+
}
|
|
336
|
+
function normalizeSmrtWebDataSurfaceActionResult(value) {
|
|
337
|
+
const serialized = JSON.stringify(value);
|
|
338
|
+
if (serialized === void 0 || new TextEncoder().encode(serialized).byteLength > 1e6) throw new TypeError("Data surface action result exceeds the maximum byte limit");
|
|
339
|
+
const source = object(value, "Data surface action result");
|
|
340
|
+
exactKeys(source, [
|
|
341
|
+
"version",
|
|
342
|
+
"requestId",
|
|
343
|
+
"identity",
|
|
344
|
+
"actionId",
|
|
345
|
+
"phase",
|
|
346
|
+
"ok",
|
|
347
|
+
"reason",
|
|
348
|
+
"confirmationToken",
|
|
349
|
+
"details"
|
|
350
|
+
], "Data surface action result");
|
|
351
|
+
if (source.version !== 1 || source.phase !== "preview" && source.phase !== "apply") throw new TypeError("Data surface action result has an invalid version or phase");
|
|
352
|
+
if (typeof source.ok !== "boolean") throw new TypeError("Data surface action result ok must be boolean");
|
|
353
|
+
const result = {
|
|
354
|
+
version: 1,
|
|
355
|
+
requestId: identifier(source.requestId, "Data surface action result requestId"),
|
|
356
|
+
identity: identity(source.identity),
|
|
357
|
+
actionId: identifier(source.actionId, "Data surface action result actionId"),
|
|
358
|
+
phase: source.phase,
|
|
359
|
+
ok: source.ok
|
|
360
|
+
};
|
|
361
|
+
if (source.reason !== void 0) result.reason = identifier(source.reason, "Data surface action result reason");
|
|
362
|
+
if (source.confirmationToken !== void 0) result.confirmationToken = identifier(source.confirmationToken, "Data surface action result confirmationToken");
|
|
363
|
+
if (source.details !== void 0) {
|
|
364
|
+
const details = json(source.details, "Data surface action result details");
|
|
365
|
+
if (Array.isArray(details) || details === null || typeof details !== "object") throw new TypeError("Data surface action result details must be an object");
|
|
366
|
+
result.details = details;
|
|
367
|
+
}
|
|
368
|
+
return result;
|
|
369
|
+
}
|
|
370
|
+
async function executeSmrtWebDataSurfaceAction(transport, request, options) {
|
|
371
|
+
const result = normalizeSmrtWebDataSurfaceActionResult(await transport.action(request, options));
|
|
372
|
+
if (result.requestId !== request.requestId || result.actionId !== request.actionId || result.phase !== request.phase || !sameIdentity(result.identity, request.identity)) throw new TypeError("Data surface action result does not match its request");
|
|
373
|
+
return result;
|
|
374
|
+
}
|
|
375
|
+
//#endregion
|
|
262
376
|
//#region src/durable-store.ts
|
|
263
377
|
function durableStoreNamespace(key) {
|
|
264
378
|
const optional = (value) => value === void 0 ? "" : `_${encodeURIComponent(value)}`;
|
|
@@ -3037,6 +3151,6 @@ function createSmrtCollection(definition, options) {
|
|
|
3037
3151
|
return handle;
|
|
3038
3152
|
}
|
|
3039
3153
|
//#endregion
|
|
3040
|
-
export {
|
|
3154
|
+
export { MAX_SMRT_WEB_DATA_SURFACE_ACTION_RESULT_BYTES as A, MAX_SMRT_WEB_DATA_QUERY_STRING_LENGTH as B, offlineOutbox as C, MAX_SMRT_WEB_DATA_SURFACE_ACTION_CONTAINER_ITEMS as D, wipeDurableStore as E, MAX_SMRT_WEB_DATA_QUERY_FACET_VALUES as F, executeSmrtWebDataQuery as H, MAX_SMRT_WEB_DATA_QUERY_OFFSET as I, MAX_SMRT_WEB_DATA_QUERY_PAGE_LIMIT as L, normalizeSmrtWebDataSurfaceActionResult as M, MAX_SMRT_WEB_DATA_QUERY_CONTAINER_ITEMS as N, MAX_SMRT_WEB_DATA_SURFACE_ACTION_IDENTIFIER_LENGTH as O, MAX_SMRT_WEB_DATA_QUERY_FACETS as P, MAX_SMRT_WEB_DATA_QUERY_RESULT_BYTES as R, getOutboxHandle as S, registerDurableResource as T, normalizeSmrtWebDataQueryResult as U, MAX_SMRT_WEB_DATA_QUERY_WARNINGS as V, runWrapMutation as W, createSmrtWebEventSubscriber as _, createSmrtWebClient as a, DEFAULT_PERSIST_DEBOUNCE_MS as b, newLocalId as c, unwrapListResult as d, validateSmrtWebClient as f, createUpdateState as g, registerWebMcpTools as h, createSmrtCollection as i, executeSmrtWebDataSurfaceAction as j, MAX_SMRT_WEB_DATA_SURFACE_ACTION_JSON_DEPTH as k, throwIfSmrtWebError as l, registerWebMcpBespokeTool as m, buildListQuery as n, getEngineCollection as o, registerViewIntent as p, createDefinitionFetchers as r, invalidateSmrtWebCollections as s, SmrtWebRequestError as t, unwrapItemResult as u, liveInvalidation as v, durableStoreNamespace as w, persistCollection as x, createSmrtWebQuery as y, MAX_SMRT_WEB_DATA_QUERY_ROWS as z };
|
|
3041
3155
|
|
|
3042
|
-
//# sourceMappingURL=src-
|
|
3156
|
+
//# sourceMappingURL=src-0IQGhPIM.js.map
|