@loomwork/ui-hydration 0.0.0-stage → 0.1.1

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 (179) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +8 -0
  3. package/README.md +398 -2
  4. package/dist/cache.d.ts +71 -0
  5. package/dist/cache.d.ts.map +1 -0
  6. package/dist/cache.js +157 -0
  7. package/dist/cache.js.map +1 -0
  8. package/dist/chatSource.d.ts +105 -0
  9. package/dist/chatSource.d.ts.map +1 -0
  10. package/dist/chatSource.js +264 -0
  11. package/dist/chatSource.js.map +1 -0
  12. package/dist/client.d.ts +17 -0
  13. package/dist/client.d.ts.map +1 -0
  14. package/dist/client.js +36 -0
  15. package/dist/client.js.map +1 -0
  16. package/dist/contentRefs.d.ts +78 -0
  17. package/dist/contentRefs.d.ts.map +1 -0
  18. package/dist/contentRefs.js +129 -0
  19. package/dist/contentRefs.js.map +1 -0
  20. package/dist/controller.d.ts +228 -0
  21. package/dist/controller.d.ts.map +1 -0
  22. package/dist/controller.js +454 -0
  23. package/dist/controller.js.map +1 -0
  24. package/dist/dataProvider.d.ts +53 -0
  25. package/dist/dataProvider.d.ts.map +1 -0
  26. package/dist/dataProvider.js +77 -0
  27. package/dist/dataProvider.js.map +1 -0
  28. package/dist/esm/cache.js +151 -0
  29. package/dist/esm/cache.js.map +1 -0
  30. package/dist/esm/chatSource.js +259 -0
  31. package/dist/esm/chatSource.js.map +1 -0
  32. package/dist/esm/client.js +15 -0
  33. package/dist/esm/client.js.map +1 -0
  34. package/dist/esm/contentRefs.js +119 -0
  35. package/dist/esm/contentRefs.js.map +1 -0
  36. package/dist/esm/controller.js +449 -0
  37. package/dist/esm/controller.js.map +1 -0
  38. package/dist/esm/dataProvider.js +72 -0
  39. package/dist/esm/dataProvider.js.map +1 -0
  40. package/dist/esm/index.js +15 -0
  41. package/dist/esm/index.js.map +1 -0
  42. package/dist/esm/invoker.js +2 -0
  43. package/dist/esm/invoker.js.map +1 -0
  44. package/dist/esm/invokers.js +310 -0
  45. package/dist/esm/invokers.js.map +1 -0
  46. package/dist/esm/loomEffectProvider.js +96 -0
  47. package/dist/esm/loomEffectProvider.js.map +1 -0
  48. package/dist/esm/params.js +207 -0
  49. package/dist/esm/params.js.map +1 -0
  50. package/dist/esm/path.js +24 -0
  51. package/dist/esm/path.js.map +1 -0
  52. package/dist/esm/plan.js +190 -0
  53. package/dist/esm/plan.js.map +1 -0
  54. package/dist/esm/projection.js +230 -0
  55. package/dist/esm/projection.js.map +1 -0
  56. package/dist/esm/provider.js +416 -0
  57. package/dist/esm/provider.js.map +1 -0
  58. package/dist/esm/repair.js +53 -0
  59. package/dist/esm/repair.js.map +1 -0
  60. package/dist/esm/reshape.js +156 -0
  61. package/dist/esm/reshape.js.map +1 -0
  62. package/dist/esm/restricted.js +54 -0
  63. package/dist/esm/restricted.js.map +1 -0
  64. package/dist/esm/scheduler.js +247 -0
  65. package/dist/esm/scheduler.js.map +1 -0
  66. package/dist/esm/select.js +18 -0
  67. package/dist/esm/select.js.map +1 -0
  68. package/dist/esm/shape.js +34 -0
  69. package/dist/esm/shape.js.map +1 -0
  70. package/dist/esm/split/client.js +312 -0
  71. package/dist/esm/split/client.js.map +1 -0
  72. package/dist/esm/split/index.js +3 -0
  73. package/dist/esm/split/index.js.map +1 -0
  74. package/dist/esm/split/server.js +488 -0
  75. package/dist/esm/split/server.js.map +1 -0
  76. package/dist/esm/split/shared.js +13 -0
  77. package/dist/esm/split/shared.js.map +1 -0
  78. package/dist/index.d.ts +29 -0
  79. package/dist/index.d.ts.map +1 -0
  80. package/dist/index.js +63 -0
  81. package/dist/index.js.map +1 -0
  82. package/dist/invoker.d.ts +10 -0
  83. package/dist/invoker.d.ts.map +1 -0
  84. package/dist/invoker.js +3 -0
  85. package/dist/invoker.js.map +1 -0
  86. package/dist/invokers.d.ts +36 -0
  87. package/dist/invokers.d.ts.map +1 -0
  88. package/dist/invokers.js +315 -0
  89. package/dist/invokers.js.map +1 -0
  90. package/dist/loomEffectProvider.d.ts +67 -0
  91. package/dist/loomEffectProvider.d.ts.map +1 -0
  92. package/dist/loomEffectProvider.js +101 -0
  93. package/dist/loomEffectProvider.js.map +1 -0
  94. package/dist/params.d.ts +103 -0
  95. package/dist/params.d.ts.map +1 -0
  96. package/dist/params.js +221 -0
  97. package/dist/params.js.map +1 -0
  98. package/dist/path.d.ts +12 -0
  99. package/dist/path.d.ts.map +1 -0
  100. package/dist/path.js +28 -0
  101. package/dist/path.js.map +1 -0
  102. package/dist/plan.d.ts +56 -0
  103. package/dist/plan.d.ts.map +1 -0
  104. package/dist/plan.js +199 -0
  105. package/dist/plan.js.map +1 -0
  106. package/dist/projection.d.ts +122 -0
  107. package/dist/projection.d.ts.map +1 -0
  108. package/dist/projection.js +238 -0
  109. package/dist/projection.js.map +1 -0
  110. package/dist/provider.d.ts +152 -0
  111. package/dist/provider.d.ts.map +1 -0
  112. package/dist/provider.js +421 -0
  113. package/dist/provider.js.map +1 -0
  114. package/dist/repair.d.ts +18 -0
  115. package/dist/repair.d.ts.map +1 -0
  116. package/dist/repair.js +57 -0
  117. package/dist/repair.js.map +1 -0
  118. package/dist/reshape.d.ts +32 -0
  119. package/dist/reshape.d.ts.map +1 -0
  120. package/dist/reshape.js +164 -0
  121. package/dist/reshape.js.map +1 -0
  122. package/dist/restricted.d.ts +21 -0
  123. package/dist/restricted.d.ts.map +1 -0
  124. package/dist/restricted.js +61 -0
  125. package/dist/restricted.js.map +1 -0
  126. package/dist/scheduler.d.ts +82 -0
  127. package/dist/scheduler.d.ts.map +1 -0
  128. package/dist/scheduler.js +254 -0
  129. package/dist/scheduler.js.map +1 -0
  130. package/dist/select.d.ts +34 -0
  131. package/dist/select.d.ts.map +1 -0
  132. package/dist/select.js +21 -0
  133. package/dist/select.js.map +1 -0
  134. package/dist/shape.d.ts +3 -0
  135. package/dist/shape.d.ts.map +1 -0
  136. package/dist/shape.js +37 -0
  137. package/dist/shape.js.map +1 -0
  138. package/dist/split/client.d.ts +135 -0
  139. package/dist/split/client.d.ts.map +1 -0
  140. package/dist/split/client.js +316 -0
  141. package/dist/split/client.js.map +1 -0
  142. package/dist/split/index.d.ts +5 -0
  143. package/dist/split/index.d.ts.map +1 -0
  144. package/dist/split/index.js +14 -0
  145. package/dist/split/index.js.map +1 -0
  146. package/dist/split/server.d.ts +160 -0
  147. package/dist/split/server.d.ts.map +1 -0
  148. package/dist/split/server.js +496 -0
  149. package/dist/split/server.js.map +1 -0
  150. package/dist/split/shared.d.ts +6 -0
  151. package/dist/split/shared.d.ts.map +1 -0
  152. package/dist/split/shared.js +19 -0
  153. package/dist/split/shared.js.map +1 -0
  154. package/package.json +77 -3
  155. package/src/cache.ts +211 -0
  156. package/src/chatSource.ts +378 -0
  157. package/src/client.ts +46 -0
  158. package/src/contentRefs.ts +195 -0
  159. package/src/controller.ts +708 -0
  160. package/src/dataProvider.ts +141 -0
  161. package/src/index.ts +86 -0
  162. package/src/invoker.ts +14 -0
  163. package/src/invokers.ts +348 -0
  164. package/src/loomEffectProvider.ts +136 -0
  165. package/src/params.ts +314 -0
  166. package/src/path.ts +26 -0
  167. package/src/plan.ts +197 -0
  168. package/src/projection.ts +297 -0
  169. package/src/provider.ts +657 -0
  170. package/src/repair.ts +70 -0
  171. package/src/reshape.ts +193 -0
  172. package/src/restricted.ts +69 -0
  173. package/src/scheduler.ts +284 -0
  174. package/src/select.ts +59 -0
  175. package/src/shape.ts +39 -0
  176. package/src/split/client.ts +452 -0
  177. package/src/split/index.ts +18 -0
  178. package/src/split/server.ts +746 -0
  179. package/src/split/shared.ts +18 -0
package/dist/client.js ADDED
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.publishChat = exports.connectConversation = exports.SplitHydrationController = exports.outputShapeHashOf = exports.jsonPathSelect = exports.topoWaves = exports.terminalSteps = exports.stepReferences = exports.checkParams = exports.DEFAULT_TIME_RANGE = exports.handleOfPath = exports.HYDRATION_VALUES_PREFIX = exports.isReservedHandle = exports.hydrationProjection = exports.HydrationStore = exports.HYDRATION_SET_EVENT = exports.HYDRATION_PROJECTION_VERSION = exports.HYDRATION_PROJECTION_ID = void 0;
4
+ // ── @loomwork/ui-hydration/client: the browser entry ─────────────────────────────────
5
+ // Everything a browser needs for SPLIT hydration and nothing that executes a provider: the split
6
+ // controller, the loader contract it calls, the store it publishes to, and param checks. The
7
+ // server half (`handleInventory`, `serveHandles`, `executeProvider`, the invokers and reshapers)
8
+ // stays on the root entry, `@loomwork/ui-hydration`, which imports the sandbox and the MCP plugin.
9
+ // `clientEntry.test.ts` fails the build if this entry's module graph ever reaches them.
10
+ var projection_1 = require("./projection");
11
+ Object.defineProperty(exports, "HYDRATION_PROJECTION_ID", { enumerable: true, get: function () { return projection_1.HYDRATION_PROJECTION_ID; } });
12
+ Object.defineProperty(exports, "HYDRATION_PROJECTION_VERSION", { enumerable: true, get: function () { return projection_1.HYDRATION_PROJECTION_VERSION; } });
13
+ Object.defineProperty(exports, "HYDRATION_SET_EVENT", { enumerable: true, get: function () { return projection_1.HYDRATION_SET_EVENT; } });
14
+ Object.defineProperty(exports, "HydrationStore", { enumerable: true, get: function () { return projection_1.HydrationStore; } });
15
+ Object.defineProperty(exports, "hydrationProjection", { enumerable: true, get: function () { return projection_1.hydrationProjection; } });
16
+ Object.defineProperty(exports, "isReservedHandle", { enumerable: true, get: function () { return projection_1.isReservedHandle; } });
17
+ var path_1 = require("./path");
18
+ Object.defineProperty(exports, "HYDRATION_VALUES_PREFIX", { enumerable: true, get: function () { return path_1.HYDRATION_VALUES_PREFIX; } });
19
+ Object.defineProperty(exports, "handleOfPath", { enumerable: true, get: function () { return path_1.handleOfPath; } });
20
+ var params_1 = require("./params");
21
+ Object.defineProperty(exports, "DEFAULT_TIME_RANGE", { enumerable: true, get: function () { return params_1.DEFAULT_TIME_RANGE; } });
22
+ Object.defineProperty(exports, "checkParams", { enumerable: true, get: function () { return params_1.checkParams; } });
23
+ var plan_1 = require("./plan");
24
+ Object.defineProperty(exports, "stepReferences", { enumerable: true, get: function () { return plan_1.stepReferences; } });
25
+ Object.defineProperty(exports, "terminalSteps", { enumerable: true, get: function () { return plan_1.terminalSteps; } });
26
+ Object.defineProperty(exports, "topoWaves", { enumerable: true, get: function () { return plan_1.topoWaves; } });
27
+ var select_1 = require("./select");
28
+ Object.defineProperty(exports, "jsonPathSelect", { enumerable: true, get: function () { return select_1.jsonPathSelect; } });
29
+ var shape_1 = require("./shape");
30
+ Object.defineProperty(exports, "outputShapeHashOf", { enumerable: true, get: function () { return shape_1.outputShapeHashOf; } });
31
+ var client_1 = require("./split/client");
32
+ Object.defineProperty(exports, "SplitHydrationController", { enumerable: true, get: function () { return client_1.SplitHydrationController; } });
33
+ var chatSource_1 = require("./chatSource");
34
+ Object.defineProperty(exports, "connectConversation", { enumerable: true, get: function () { return chatSource_1.connectConversation; } });
35
+ Object.defineProperty(exports, "publishChat", { enumerable: true, get: function () { return chatSource_1.publishChat; } });
36
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":";;;AAAA,wFAAwF;AACxF,iGAAiG;AACjG,6FAA6F;AAC7F,iGAAiG;AACjG,mGAAmG;AACnG,wFAAwF;AACxF,2CAOsB;AANpB,qHAAA,uBAAuB,OAAA;AACvB,0HAAA,4BAA4B,OAAA;AAC5B,iHAAA,mBAAmB,OAAA;AACnB,4GAAA,cAAc,OAAA;AACd,iHAAA,mBAAmB,OAAA;AACnB,8GAAA,gBAAgB,OAAA;AASlB,+BAA+D;AAAtD,+GAAA,uBAAuB,OAAA;AAAE,oGAAA,YAAY,OAAA;AAC9C,mCAA2D;AAAlD,4GAAA,kBAAkB,OAAA;AAAE,qGAAA,WAAW,OAAA;AAGxC,+BAAkE;AAAzD,sGAAA,cAAc,OAAA;AAAE,qGAAA,aAAa,OAAA;AAAE,iGAAA,SAAS,OAAA;AACjD,mCAA0C;AAAjC,wGAAA,cAAc,OAAA;AAEvB,iCAA4C;AAAnC,0GAAA,iBAAiB,OAAA;AAG1B,yCAA0D;AAAjD,kHAAA,wBAAwB,OAAA;AAQjC,2CAAgE;AAAvD,iHAAA,mBAAmB,OAAA;AAAE,yGAAA,WAAW,OAAA"}
@@ -0,0 +1,78 @@
1
+ import type { TransientInvokeOptions } from "@loomwork/effect-runtime";
2
+ import { type ContentRefTable, type Finding, type MCPToolNode, type ProviderSpec } from "@loomwork/ui-core";
3
+ import { type LoadParams } from "./params";
4
+ export type ContentRefPrincipal = TransientInvokeOptions["principal"];
5
+ /** What the host's gate is told about a param that would fill a content-reference argument. */
6
+ export interface ContentRefParamContext {
7
+ readonly handle: string;
8
+ readonly stepId: string;
9
+ readonly toolName: string;
10
+ readonly kind?: string;
11
+ readonly param: string;
12
+ readonly value: unknown;
13
+ /** The viewer the load runs for (the controller's `principal.id` / serve's `principalId`). */
14
+ readonly principalId?: string;
15
+ /** The full principal chain, when the load has one. */
16
+ readonly principal?: ContentRefPrincipal;
17
+ }
18
+ /**
19
+ * The host's gate on a PARAM that would fill a content-reference argument (U9b). Called once per
20
+ * replaced top-level argument that holds a marked path (for a tool whose schema is `"unknown"`, once
21
+ * per replaced param), EVERY time the answer is wanted: before a cache lookup as well as before a call.
22
+ * Return `true` only for a reference the host itself vouches for: one that `acceptMediaAttach`
23
+ * accepted, was ISSUED TO `ctx.principalId` (check issuance to THIS principal, not merely "some
24
+ * principal"), and is still current (a revoked share must answer `false`). Synchronous; a throw or a
25
+ * non-`true` answer refuses the step. With no gate configured, EVERY such param is refused: a param is
26
+ * a client-reachable value and a content address is a capability.
27
+ */
28
+ export type ContentRefParamGate = (ctx: ContentRefParamContext) => boolean;
29
+ /** Everything the guard needs about the load; built once per provider load. */
30
+ export interface ContentRefEnv {
31
+ readonly table: ContentRefTable;
32
+ readonly handle: string;
33
+ readonly steps: ReadonlyMap<string, MCPToolNode>;
34
+ readonly acceptContentRefParam?: ContentRefParamGate;
35
+ readonly principalId?: string;
36
+ readonly principal?: ContentRefPrincipal;
37
+ }
38
+ export declare const contentRefEnv: (table: ContentRefTable, spec: ProviderSpec, gate: ContentRefParamGate | undefined, who: {
39
+ principalId?: string | undefined;
40
+ principal?: ContentRefPrincipal | undefined;
41
+ }) => ContentRefEnv;
42
+ /**
43
+ * U9b, defence in depth behind composition: after params are applied and BEFORE anything resolves,
44
+ * a marked content-reference argument must be absent / null, a step reference to an output its tool
45
+ * declares to be a content reference, or a param the host's gate accepted. A model-authored literal,
46
+ * an echo / concat reference, or an ungated param refuses the step, so the call is never made.
47
+ * `paramFilled` says a param filled a guarded argument (the caller then caches per principal only).
48
+ */
49
+ export declare function checkContentRefs(node: MCPToolNode, applied: {
50
+ readonly args: Record<string, unknown>;
51
+ readonly replaced: readonly string[];
52
+ }, env: ContentRefEnv): {
53
+ readonly finding?: Finding;
54
+ readonly paramFilled: boolean;
55
+ };
56
+ /** `args` without JSON null at the step's marked paths (a tool never sees `null` where a reference belongs). */
57
+ export declare function finishContentRefArgs(node: MCPToolNode, args: Record<string, unknown>, table: ContentRefTable): Record<string, unknown>;
58
+ /**
59
+ * Judge a whole provider BEFORE a cache lookup: the same guard `executeProvider` runs per step, over
60
+ * every step, with the gate asked now. A cached value was produced for an argument the gate accepted
61
+ * once; serving it to another principal, or after the host revoked it, would skip the gate. A
62
+ * refusal means: do not serve from the cache (the load itself will refuse). `paramFilled` means the
63
+ * answer depends on who is asking: cache it per principal, never globally.
64
+ */
65
+ export declare function inspectContentRefs(spec: ProviderSpec, params: LoadParams, env: ContentRefEnv): {
66
+ readonly refusal?: Finding;
67
+ readonly paramFilled: boolean;
68
+ };
69
+ /** `spec` with `cachePolicy.scope: "principal"` (memoised per spec object, so its fingerprint is computed once). */
70
+ export declare function principalScoped(spec: ProviderSpec): ProviderSpec;
71
+ /** `contentRefArgs` is missing or malformed: a configuration error, never read as "nothing is guarded". */
72
+ export declare class ContentRefConfigError extends Error {
73
+ readonly code = "content-ref-config";
74
+ constructor(where: string);
75
+ }
76
+ /** Throws {@link ContentRefConfigError} unless `value` is `"none"` or exactly a well-formed table. */
77
+ export declare function assertContentRefConfig(value: unknown, where: string): void;
78
+ //# sourceMappingURL=contentRefs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contentRefs.d.ts","sourceRoot":"","sources":["../src/contentRefs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ContentRefConfigError = exports.contentRefEnv = void 0;
4
+ exports.checkContentRefs = checkContentRefs;
5
+ exports.finishContentRefArgs = finishContentRefArgs;
6
+ exports.inspectContentRefs = inspectContentRefs;
7
+ exports.principalScoped = principalScoped;
8
+ exports.assertContentRefConfig = assertContentRefConfig;
9
+ const ui_core_1 = require("@loomwork/ui-core");
10
+ const params_1 = require("./params");
11
+ // U9b, the SERVER half: a module of its own so that the browser entry (which imports params.ts) never
12
+ // reaches `@loomwork/ui-core`'s root, which pulls in node:crypto.
13
+ const bad = (code, message) => ({ code, severity: "error", message });
14
+ const contentRefEnv = (table, spec, gate, who) => ({
15
+ table,
16
+ handle: spec.handle,
17
+ steps: new Map(spec.executionGraph.map((s) => [s.stepId, s])),
18
+ ...(gate !== undefined && { acceptContentRefParam: gate }),
19
+ ...(who.principalId !== undefined && { principalId: who.principalId }),
20
+ ...(who.principal !== undefined && { principal: who.principal }),
21
+ });
22
+ exports.contentRefEnv = contentRefEnv;
23
+ /**
24
+ * U9b, defence in depth behind composition: after params are applied and BEFORE anything resolves,
25
+ * a marked content-reference argument must be absent / null, a step reference to an output its tool
26
+ * declares to be a content reference, or a param the host's gate accepted. A model-authored literal,
27
+ * an echo / concat reference, or an ungated param refuses the step, so the call is never made.
28
+ * `paramFilled` says a param filled a guarded argument (the caller then caches per principal only).
29
+ */
30
+ function checkContentRefs(node, applied, env) {
31
+ const entry = (0, ui_core_1.contentRefEntry)(env.table, (0, ui_core_1.toolKey)(node));
32
+ if (entry === undefined)
33
+ return { paramFilled: false };
34
+ const skip = new Set();
35
+ // A tool whose schema mentions the marker but cannot be read: every replaced param is gated.
36
+ const guarded = entry === "unknown"
37
+ ? new Set(applied.replaced)
38
+ : typeof entry === "string"
39
+ ? new Set()
40
+ : (0, ui_core_1.markedTopLevelKeys)(entry);
41
+ let paramFilled = false;
42
+ for (const name of applied.replaced) {
43
+ if (!guarded.has(name))
44
+ continue;
45
+ paramFilled = true;
46
+ let ok = false;
47
+ try {
48
+ ok =
49
+ env.acceptContentRefParam?.({
50
+ handle: env.handle,
51
+ stepId: node.stepId,
52
+ toolName: node.toolName,
53
+ ...(node.kind !== undefined && { kind: node.kind }),
54
+ param: name,
55
+ value: applied.args[name],
56
+ ...(env.principalId !== undefined && { principalId: env.principalId }),
57
+ ...(env.principal !== undefined && { principal: env.principal }),
58
+ }) === true;
59
+ }
60
+ catch {
61
+ ok = false;
62
+ }
63
+ if (!ok)
64
+ return {
65
+ paramFilled,
66
+ finding: bad("media-arg-param-refused", `step "${node.stepId}": the param for "${name}" fills a content-reference argument and the host did not accept it`),
67
+ };
68
+ skip.add(name);
69
+ }
70
+ const found = (0, ui_core_1.contentRefArgFindings)(applied.args, entry, `step "${node.stepId}"`, {
71
+ skipKeys: skip,
72
+ proven: (0, ui_core_1.provenIn)(env.table, env.steps, node.stepId, ui_core_1.toolKey),
73
+ }).find((f) => f.severity === "error");
74
+ return { paramFilled, ...(found !== undefined && { finding: found }) };
75
+ }
76
+ /** `args` without JSON null at the step's marked paths (a tool never sees `null` where a reference belongs). */
77
+ function finishContentRefArgs(node, args, table) {
78
+ const entry = (0, ui_core_1.contentRefEntry)(table, (0, ui_core_1.toolKey)(node));
79
+ return entry === undefined || typeof entry === "string"
80
+ ? args
81
+ : (0, ui_core_1.stripNullContentRefs)(args, entry);
82
+ }
83
+ /**
84
+ * Judge a whole provider BEFORE a cache lookup: the same guard `executeProvider` runs per step, over
85
+ * every step, with the gate asked now. A cached value was produced for an argument the gate accepted
86
+ * once; serving it to another principal, or after the host revoked it, would skip the gate. A
87
+ * refusal means: do not serve from the cache (the load itself will refuse). `paramFilled` means the
88
+ * answer depends on who is asking: cache it per principal, never globally.
89
+ */
90
+ function inspectContentRefs(spec, params, env) {
91
+ let paramFilled = false;
92
+ for (const step of spec.executionGraph) {
93
+ const applied = (0, params_1.applyParamsDetailed)(step, params);
94
+ const r = checkContentRefs(step, applied, env);
95
+ paramFilled ||= r.paramFilled;
96
+ if (r.finding !== undefined)
97
+ return { refusal: r.finding, paramFilled };
98
+ }
99
+ return { paramFilled };
100
+ }
101
+ const PRINCIPAL_SCOPED = new WeakMap();
102
+ /** `spec` with `cachePolicy.scope: "principal"` (memoised per spec object, so its fingerprint is computed once). */
103
+ function principalScoped(spec) {
104
+ if (spec.cachePolicy.scope === "principal")
105
+ return spec;
106
+ let s = PRINCIPAL_SCOPED.get(spec);
107
+ if (s === undefined) {
108
+ s = { ...spec, cachePolicy: { ...spec.cachePolicy, scope: "principal" } };
109
+ PRINCIPAL_SCOPED.set(spec, s);
110
+ }
111
+ return s;
112
+ }
113
+ /** `contentRefArgs` is missing or malformed: a configuration error, never read as "nothing is guarded". */
114
+ class ContentRefConfigError extends Error {
115
+ code = "content-ref-config";
116
+ constructor(where) {
117
+ super(`${where}: contentRefArgs is required: pass the table contentRefArgsFrom(capabilities) builds (a malformed or missing one is refused, never read as "none"), or the explicit opt-out "none"`);
118
+ this.name = "ContentRefConfigError";
119
+ }
120
+ }
121
+ exports.ContentRefConfigError = ContentRefConfigError;
122
+ /** Throws {@link ContentRefConfigError} unless `value` is `"none"` or exactly a well-formed table. */
123
+ function assertContentRefConfig(value, where) {
124
+ if (value === "none")
125
+ return;
126
+ if ((0, ui_core_1.parseContentRefTable)(value) === undefined)
127
+ throw new ContentRefConfigError(where);
128
+ }
129
+ //# sourceMappingURL=contentRefs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contentRefs.js","sourceRoot":"","sources":["../src/contentRefs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,228 @@
1
+ import type { TransientInvokeOptions } from "@loomwork/effect-runtime";
2
+ import { type Audience, type ContentRefTable, type DeclaredToolClasses, type Experience, type Finding, type ProviderSpec, type ReadPolicy, type SemanticCatalog, type Surface, type UndeclaredToolPolicy, type Viewer } from "@loomwork/ui-core";
3
+ import { HydrationCache } from "./cache";
4
+ import { type ContentRefParamGate } from "./contentRefs";
5
+ import type { DataProviderRegistry } from "./dataProvider";
6
+ import type { TransientInvoker } from "./invoker";
7
+ import { type ArgumentHook, type LoadParams } from "./params";
8
+ import { type HydrationStore } from "./projection";
9
+ import { type DriftRecord, type InputDriftMode } from "./provider";
10
+ import type { ReshaperRegistry } from "./reshape";
11
+ export interface DriftReport {
12
+ readonly experienceId: string;
13
+ readonly versionHash: string;
14
+ readonly handle: string;
15
+ readonly spec: ProviderSpec;
16
+ readonly drift: readonly DriftRecord[];
17
+ readonly findings: readonly Finding[];
18
+ /** `true` when the load retried with the observed pin and published (`inputDrift: "report-and-proceed"`). */
19
+ readonly proceeded: boolean;
20
+ }
21
+ export interface ControllerOptions {
22
+ readonly invoker: TransientInvoker;
23
+ readonly store: HydrationStore;
24
+ /** Cache TTLs AND relative-time tokens run on this clock (read once per pass). Default `Date.now`. */
25
+ readonly clock?: () => number;
26
+ /** Schedule `fn` after `ms`; returns a cancel. Default: setTimeout/clearTimeout. */
27
+ readonly setTimer?: (fn: () => void, ms: number) => () => void;
28
+ readonly batchWindowMs?: number;
29
+ /** Parallel steps per wave within ONE provider. Default 4. */
30
+ readonly concurrency?: number;
31
+ /** At most this many transient calls in flight across the WHOLE controller. Default: unbounded. */
32
+ readonly maxConcurrentCalls?: number;
33
+ readonly principal?: {
34
+ readonly id: string;
35
+ readonly chain?: TransientInvokeOptions["principal"];
36
+ };
37
+ readonly cache?: HydrationCache;
38
+ /**
39
+ * Who the data is for (`@loomwork/ui-core`'s `Viewer`). A handle bound by any node classified above
40
+ * the viewer's clearance is never loaded: its provider is not invoked, nothing is cached for it,
41
+ * and NOTHING is written to the store for it (no value, no status: a store projected to a client
42
+ * must not even name it). SNAPSHOT at construction: later mutation of this object changes
43
+ * nothing; a different viewer needs {@link HydrationController.setViewer} (or a new
44
+ * controller). FAIL-CLOSED: absent = a viewer
45
+ * with no clearance (and `load` reports one `viewer-not-supplied` warn if anything is
46
+ * classified); unclassified handles are unaffected. Pass `{ clearance: "secret" }` for full access.
47
+ */
48
+ readonly viewer?: Viewer;
49
+ /**
50
+ * Who the surface is for, the SAME value `compile` takes (`@loomwork/ui-core` `Audience`). `"broadcast"`
51
+ * clamps the viewer to the audience's ceiling (unclassified data only): every handle `compile`
52
+ * withheld for the audience is never loaded, cached or written to the store, and `appendStream`
53
+ * and friends refuse it, whoever the `viewer` is. Absent / `"viewer"` = the viewer as given.
54
+ */
55
+ readonly audience?: Audience;
56
+ /**
57
+ * The host's DECLARED class per tool (`toolKey`), a read-time floor under every handle calling
58
+ * that tool (`@loomwork/ui-core` `DeclaredToolClasses`): a handle whose stored nodes carry no class
59
+ * is still gated as strictly as its tool is declared. Absent = only the experience's own classes.
60
+ */
61
+ readonly declaredToolClasses?: DeclaredToolClasses;
62
+ /**
63
+ * The host's whole {@link ReadPolicy}, the SAME value `createServeSurface` takes, so one policy
64
+ * serves both. Bound first; the separate `declaredToolClasses` / `undeclared` options join it
65
+ * raise-only (`mergeReadPolicy`), so neither can lower the other.
66
+ */
67
+ readonly readPolicy?: ReadPolicy;
68
+ /**
69
+ * What a tool the `declaredToolClasses` table does not list reads as: `"allow"` (default) = as the
70
+ * experience itself says; `"deny"` = no viewer may read it (only with a table present).
71
+ */
72
+ readonly undeclared?: UndeclaredToolPolicy;
73
+ readonly onDrift?: (report: DriftReport) => void;
74
+ /**
75
+ * Where `outputCheck: "contract"` providers get their kinds: every bound node resolved on this
76
+ * surface through this catalogue (`handleKinds`). Without it a contract provider is an error.
77
+ */
78
+ readonly outputKinds?: {
79
+ readonly catalog: SemanticCatalog;
80
+ readonly surface: Surface;
81
+ };
82
+ /** Params every load starts from (e.g. `DEFAULT_TIME_RANGE`); `setParams` layers over them. */
83
+ readonly defaultParams?: LoadParams;
84
+ /** On an input-schema drift: `"report"` (default) goes stale; `"report-and-proceed"` publishes. */
85
+ readonly inputDrift?: InputDriftMode;
86
+ /** The host's last word on each step's arguments (after params, time tokens, templates). */
87
+ readonly argumentHook?: ArgumentHook;
88
+ /**
89
+ * REQUIRED (U9b): the marked content-reference argument paths per tool, derived from the offered
90
+ * capabilities with the planner's `contentRefArgsFrom(capabilities)` (persist it with the capability
91
+ * set; `parseContentRefTable` re-reads it). A step whose marked argument holds a literal, or a
92
+ * reference to an output its tool does not declare to be one, is refused (`media-arg-literal` /
93
+ * `media-arg-unproven-ref`) and its call is NOT made, whatever validation did or did not run. `"none"`
94
+ * is the explicit opt-out: nothing is guarded, and loading an experience with media nodes then returns
95
+ * a `media-content-refs-unguarded` warning.
96
+ */
97
+ readonly contentRefArgs: ContentRefTable | "none";
98
+ /**
99
+ * U9b: the host's gate on a PARAM that fills a marked argument. Return `true` only for a reference
100
+ * the host vouches for, i.e. one that `acceptMediaAttach` accepted for this principal. Absent =
101
+ * every such param is refused.
102
+ */
103
+ readonly acceptContentRefParam?: ContentRefParamGate;
104
+ /** Where `Named` reshaping looks its reshapers up. */
105
+ readonly reshapers?: ReshaperRegistry;
106
+ /** The data-provider kinds composed for this controller (default: MCP only). */
107
+ readonly providers?: DataProviderRegistry;
108
+ /**
109
+ * Attach the RAW terminal output to each output-drift record `onDrift` reports, as a tainted
110
+ * sample (`DriftRecord.observedSample`) — what a planner repair pins against. Default false.
111
+ * The same option `serveHandle` takes, so in-process and split drift reports carry the same.
112
+ */
113
+ readonly captureSample?: boolean;
114
+ }
115
+ export declare function loadFingerprint(spec: ProviderSpec, kinds: readonly string[]): string;
116
+ export declare class HydrationController {
117
+ private readonly opts;
118
+ private readonly cache;
119
+ private readonly clock;
120
+ private readonly sched;
121
+ private current;
122
+ private kinds;
123
+ private globalParams;
124
+ private readonly scopedParams;
125
+ private readonly lifetime;
126
+ /**
127
+ * Throws `RangeError` for a `maxConcurrentCalls` that is not a positive integer, or
128
+ * `defaultParams` that `checkParams` refuses.
129
+ */
130
+ /** The viewer, copied once at construction so a live mutation of the caller's object is inert. */
131
+ private viewer;
132
+ /**
133
+ * Handles that may take token chunks RIGHT NOW: bound by the current experience, cleared for the
134
+ * viewer, and (when output kinds are known) resolving to `StreamingText`. Rebuilt on every bind.
135
+ */
136
+ private streamable;
137
+ private bound;
138
+ private readonly policy;
139
+ private readonly broadcast;
140
+ private readonly audience;
141
+ constructor(opts: ControllerOptions);
142
+ /**
143
+ * Bind an experience: schedule every handle it binds. Findings for handles that cannot load.
144
+ * A second `load` while one experience is already bound IS a recompose — the previous
145
+ * experience's handles are aborted and dropped rather than left published forever.
146
+ */
147
+ load(exp: Experience): {
148
+ findings: Finding[];
149
+ };
150
+ /**
151
+ * Replace the viewer and re-plan the bound experience: a handle the new viewer may not see is
152
+ * aborted and dropped (an in-flight result is discarded, a loaded value removed), one it newly
153
+ * may see is scheduled. Before any `load` it only records the viewer.
154
+ */
155
+ setViewer(viewer: Viewer | undefined): {
156
+ findings: Finding[];
157
+ };
158
+ /**
159
+ * Append one token chunk to a `StreamingText` handle, through the same viewer gate as `load`:
160
+ * refused (a finding, nothing written) for a handle that is not bound by the current
161
+ * experience (`stream-unbound`), is restricted for the viewer (`restricted`, the fixed text that
162
+ * names nothing), or — when `outputKinds` is configured — does not resolve to `StreamingText`
163
+ * (`stream-kind-mismatch`). Without `outputKinds` the kind is unknown and is not checked. The
164
+ * store's own `append` is gated by the same rule once a controller fronts it.
165
+ */
166
+ append(handle: string, chunk: unknown): {
167
+ ok: true;
168
+ applied: boolean;
169
+ } | {
170
+ ok: false;
171
+ finding: Finding;
172
+ };
173
+ /**
174
+ * Publish a value for a handle that is NOT loaded by a provider (a live transcript a browser
175
+ * connection folds, ...), through the same gates as a load: the handle must be bound by the current
176
+ * experience, must not be restricted for the viewer (`restricted`, the fixed text that names
177
+ * nothing), must resolve to the kind the caller names (when it names one), and the value must pass
178
+ * EVERY bound kind's contract (a kind with none is refused: nothing is published unchecked).
179
+ * Refused = a finding and nothing written.
180
+ */
181
+ publishValue(handle: string, value: unknown, options?: {
182
+ readonly state?: "ready" | "pending";
183
+ readonly kind?: string;
184
+ }): {
185
+ ok: true;
186
+ } | {
187
+ ok: false;
188
+ finding: Finding;
189
+ };
190
+ private appendRefusal;
191
+ private restrictedHandles;
192
+ /** The surface reports a lazy (P2) widget entered the viewport. */
193
+ markVisible(handle: string): void;
194
+ /** A new artifact replaces the current one: abort and drop unbound handles, keep the rest, load new ones. */
195
+ recompose(next: Experience): {
196
+ findings: Finding[];
197
+ };
198
+ /**
199
+ * Replace the global params (no `scope.handle`) or one handle's scoped params, then re-ask
200
+ * every bound handle whose question changed — only those, so a handle that ended on `error`
201
+ * with an unchanged question is NOT retried here (`invalidate` retries it). `{}` clears.
202
+ * Refused, with nothing changed, for params `checkParams` refuses or a reserved handle. A lazy
203
+ * (P2) handle whose question changed waits for its next `markVisible`. Params scoped to a handle
204
+ * the experience does not bind are kept only until the next bind, which forgets them.
205
+ */
206
+ setParams(params: LoadParams, scope?: {
207
+ readonly handle?: string;
208
+ }): {
209
+ findings: Finding[];
210
+ };
211
+ /**
212
+ * Drop cached results (one handle or all) and reload the affected bound handles. An in-flight
213
+ * load answering the invalidated question is superseded; a lazy (P2) widget stays lazy.
214
+ */
215
+ invalidate(handle?: string): {
216
+ findings: Finding[];
217
+ };
218
+ inFlight(): string[];
219
+ /** Terminal: every in-flight load is aborted and reported, and nothing schedules again. */
220
+ dispose(): void;
221
+ private bind;
222
+ /** Pure: the jobs `exp` asks for right now, and the handles that cannot load (with why). */
223
+ private plan;
224
+ /** The content-reference guard over a whole job (asks the host's gate now); `undefined` when nothing is guarded. */
225
+ private refsVerdict;
226
+ private run;
227
+ }
228
+ //# sourceMappingURL=controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../src/controller.ts"],"names":[],"mappings":"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"}