@fabricorg/experience-runtime 0.4.8 → 0.4.9

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/client.js CHANGED
@@ -1,119 +1,126 @@
1
- // client.ts
1
+ //#region client.ts
2
2
  function createExperienceSession(plan, gateway) {
3
- const fragments = indexFragments(plan.root);
4
- return {
5
- plan,
6
- async invoke(fragmentId, eventName, parameters, idempotencyKey) {
7
- const fragment = fragments.get(fragmentId);
8
- if (!fragment?.events?.includes(eventName)) {
9
- throw new Error(`Fragment event "${fragmentId}.${eventName}" is not in the render plan.`);
10
- }
11
- return gateway.invoke({
12
- planId: plan.planId,
13
- fragmentId,
14
- eventName,
15
- parameters,
16
- ...idempotencyKey === void 0 ? {} : { idempotencyKey }
17
- });
18
- },
19
- async read(fragmentId, bindingName, parameters) {
20
- const fragment = fragments.get(fragmentId);
21
- if (!fragment?.bindings?.includes(bindingName)) {
22
- throw new Error(`Fragment binding "${fragmentId}.${bindingName}" is not in the render plan.`);
23
- }
24
- return gateway.read({
25
- planId: plan.planId,
26
- fragmentId,
27
- bindingName,
28
- ...parameters === void 0 ? {} : { parameters }
29
- });
30
- }
31
- };
3
+ const fragments = indexFragments(plan.root);
4
+ return {
5
+ plan,
6
+ async invoke(fragmentId, eventName, parameters, idempotencyKey) {
7
+ if (!fragments.get(fragmentId)?.events?.includes(eventName)) throw new Error(`Fragment event "${fragmentId}.${eventName}" is not in the render plan.`);
8
+ return gateway.invoke({
9
+ planId: plan.planId,
10
+ fragmentId,
11
+ eventName,
12
+ parameters,
13
+ ...idempotencyKey === void 0 ? {} : { idempotencyKey }
14
+ });
15
+ },
16
+ async read(fragmentId, bindingName, parameters) {
17
+ if (!fragments.get(fragmentId)?.bindings?.includes(bindingName)) throw new Error(`Fragment binding "${fragmentId}.${bindingName}" is not in the render plan.`);
18
+ return gateway.read({
19
+ planId: plan.planId,
20
+ fragmentId,
21
+ bindingName,
22
+ ...parameters === void 0 ? {} : { parameters }
23
+ });
24
+ }
25
+ };
32
26
  }
33
27
  function experienceClientChecks() {
34
- const plan = {
35
- formatVersion: 1,
36
- planId: "conformance-plan",
37
- application: "conformance",
38
- channel: "test",
39
- releaseDigest: "a".repeat(64),
40
- assemblyDigest: "b".repeat(64),
41
- treeId: "root",
42
- tokenSet: { name: "conformance", version: "1.0.0" },
43
- expiresAt: "2099-01-01T00:00:00.000Z",
44
- root: { id: "root", component: "Action", events: ["press"], bindings: ["summary"] }
45
- };
46
- return [
47
- {
48
- id: "fabric.experience.client-tuple-routing.v1",
49
- async run(subject) {
50
- const calls = [];
51
- const session = subject.create(plan, {
52
- async invoke(request) {
53
- calls.push(`${request.fragmentId}.${request.eventName}`);
54
- return { status: "accepted" };
55
- },
56
- async read(request) {
57
- calls.push(`${request.fragmentId}.${request.bindingName}`);
58
- return { data: { ok: true } };
59
- }
60
- });
61
- await session.invoke("root", "press", {});
62
- await session.read("root", "summary");
63
- if (calls.join(",") !== "root.press,root.summary") throw new Error("Client did not route through fragment-event and fragment-binding tuples.");
64
- return calls;
65
- }
66
- },
67
- {
68
- id: "fabric.experience.client-plan-denial.v1",
69
- async run(subject) {
70
- let called = false;
71
- const session = subject.create(plan, {
72
- async invoke() {
73
- called = true;
74
- return { status: "accepted" };
75
- },
76
- async read() {
77
- called = true;
78
- return { data: null };
79
- }
80
- });
81
- let rejected = false;
82
- try {
83
- await session.invoke("root", "undeclared", {});
84
- } catch {
85
- rejected = true;
86
- }
87
- if (!rejected || called) throw new Error("Client forwarded an event that was absent from the scoped plan.");
88
- return ["undeclared event rejected locally"];
89
- }
90
- }
91
- ];
28
+ const plan = {
29
+ formatVersion: 1,
30
+ planId: "conformance-plan",
31
+ application: "conformance",
32
+ channel: "test",
33
+ releaseDigest: "a".repeat(64),
34
+ assemblyDigest: "b".repeat(64),
35
+ treeId: "root",
36
+ tokenSet: {
37
+ name: "conformance",
38
+ version: "1.0.0"
39
+ },
40
+ expiresAt: "2099-01-01T00:00:00.000Z",
41
+ root: {
42
+ id: "root",
43
+ component: "Action",
44
+ events: ["press"],
45
+ bindings: ["summary"]
46
+ }
47
+ };
48
+ return [{
49
+ id: "fabric.experience.client-tuple-routing.v1",
50
+ async run(subject) {
51
+ const calls = [];
52
+ const session = subject.create(plan, {
53
+ async invoke(request) {
54
+ calls.push(`${request.fragmentId}.${request.eventName}`);
55
+ return { status: "accepted" };
56
+ },
57
+ async read(request) {
58
+ calls.push(`${request.fragmentId}.${request.bindingName}`);
59
+ return { data: { ok: true } };
60
+ }
61
+ });
62
+ await session.invoke("root", "press", {});
63
+ await session.read("root", "summary");
64
+ if (calls.join(",") !== "root.press,root.summary") throw new Error("Client did not route through fragment-event and fragment-binding tuples.");
65
+ return calls;
66
+ }
67
+ }, {
68
+ id: "fabric.experience.client-plan-denial.v1",
69
+ async run(subject) {
70
+ let called = false;
71
+ const session = subject.create(plan, {
72
+ async invoke() {
73
+ called = true;
74
+ return { status: "accepted" };
75
+ },
76
+ async read() {
77
+ called = true;
78
+ return { data: null };
79
+ }
80
+ });
81
+ let rejected = false;
82
+ try {
83
+ await session.invoke("root", "undeclared", {});
84
+ } catch {
85
+ rejected = true;
86
+ }
87
+ if (!rejected || called) throw new Error("Client forwarded an event that was absent from the scoped plan.");
88
+ return ["undeclared event rejected locally"];
89
+ }
90
+ }];
92
91
  }
93
92
  async function runExperienceClientChecks(subject, checks = experienceClientChecks()) {
94
- const results = [];
95
- for (const check of checks) {
96
- try {
97
- results.push({ id: check.id, status: "passed", evidence: await check.run(subject) });
98
- } catch (error) {
99
- results.push({ id: check.id, status: "failed", evidence: [], error: error instanceof Error ? error.message : String(error) });
100
- }
101
- }
102
- return { passed: results.every((result) => result.status === "passed"), checks: results };
93
+ const results = [];
94
+ for (const check of checks) try {
95
+ results.push({
96
+ id: check.id,
97
+ status: "passed",
98
+ evidence: await check.run(subject)
99
+ });
100
+ } catch (error) {
101
+ results.push({
102
+ id: check.id,
103
+ status: "failed",
104
+ evidence: [],
105
+ error: error instanceof Error ? error.message : String(error)
106
+ });
107
+ }
108
+ return {
109
+ passed: results.every((result) => result.status === "passed"),
110
+ checks: results
111
+ };
103
112
  }
104
113
  function indexFragments(root) {
105
- const fragments = /* @__PURE__ */ new Map();
106
- const visit = (fragment) => {
107
- if (fragments.has(fragment.id)) throw new Error(`Render plan repeats fragment "${fragment.id}".`);
108
- fragments.set(fragment.id, fragment);
109
- for (const child of fragment.children ?? []) visit(child);
110
- };
111
- visit(root);
112
- return fragments;
114
+ const fragments = /* @__PURE__ */ new Map();
115
+ const visit = (fragment) => {
116
+ if (fragments.has(fragment.id)) throw new Error(`Render plan repeats fragment "${fragment.id}".`);
117
+ fragments.set(fragment.id, fragment);
118
+ for (const child of fragment.children ?? []) visit(child);
119
+ };
120
+ visit(root);
121
+ return fragments;
113
122
  }
114
- export {
115
- createExperienceSession,
116
- experienceClientChecks,
117
- runExperienceClientChecks
118
- };
123
+ //#endregion
124
+ export { createExperienceSession, experienceClientChecks, runExperienceClientChecks };
125
+
119
126
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../client.ts"],"sourcesContent":["import type {\n\tExperienceGatewayClient,\n\tExperienceSession,\n\tRenderPlanFragment,\n\tScopedRenderPlan,\n} from \"./contracts\";\n\nexport type {\n\tExperienceGatewayClient,\n\tExperienceIntentRequest,\n\tExperienceReadRequest,\n\tExperienceSession,\n\tRenderPlanFragment,\n\tScopedRenderPlan,\n} from \"./contracts\";\n\nexport function createExperienceSession(\n\tplan: ScopedRenderPlan,\n\tgateway: ExperienceGatewayClient,\n): ExperienceSession {\n\tconst fragments = indexFragments(plan.root);\n\treturn {\n\t\tplan,\n\t\tasync invoke(fragmentId, eventName, parameters, idempotencyKey) {\n\t\t\tconst fragment = fragments.get(fragmentId);\n\t\t\tif (!fragment?.events?.includes(eventName)) {\n\t\t\t\tthrow new Error(`Fragment event \"${fragmentId}.${eventName}\" is not in the render plan.`);\n\t\t\t}\n\t\t\treturn gateway.invoke({\n\t\t\t\tplanId: plan.planId,\n\t\t\t\tfragmentId,\n\t\t\t\teventName,\n\t\t\t\tparameters,\n\t\t\t\t...(idempotencyKey === undefined ? {} : { idempotencyKey }),\n\t\t\t});\n\t\t},\n\t\tasync read(fragmentId, bindingName, parameters) {\n\t\t\tconst fragment = fragments.get(fragmentId);\n\t\t\tif (!fragment?.bindings?.includes(bindingName)) {\n\t\t\t\tthrow new Error(`Fragment binding \"${fragmentId}.${bindingName}\" is not in the render plan.`);\n\t\t\t}\n\t\t\treturn gateway.read({\n\t\t\t\tplanId: plan.planId,\n\t\t\t\tfragmentId,\n\t\t\t\tbindingName,\n\t\t\t\t...(parameters === undefined ? {} : { parameters }),\n\t\t\t});\n\t\t},\n\t};\n}\n\nexport interface ExperienceClientConformanceSubject {\n\tcreate(plan: ScopedRenderPlan, gateway: ExperienceGatewayClient): ExperienceSession;\n}\n\nexport interface ExperienceClientCheck {\n\tid: \"fabric.experience.client-tuple-routing.v1\" | \"fabric.experience.client-plan-denial.v1\";\n\trun(subject: ExperienceClientConformanceSubject): Promise<string[]>;\n}\n\nexport function experienceClientChecks(): readonly ExperienceClientCheck[] {\n\tconst plan: ScopedRenderPlan = {\n\t\tformatVersion: 1,\n\t\tplanId: \"conformance-plan\",\n\t\tapplication: \"conformance\",\n\t\tchannel: \"test\",\n\t\treleaseDigest: \"a\".repeat(64),\n\t\tassemblyDigest: \"b\".repeat(64),\n\t\ttreeId: \"root\",\n\t\ttokenSet: { name: \"conformance\", version: \"1.0.0\" },\n\t\texpiresAt: \"2099-01-01T00:00:00.000Z\",\n\t\troot: { id: \"root\", component: \"Action\", events: [\"press\"], bindings: [\"summary\"] },\n\t};\n\treturn [\n\t\t{\n\t\t\tid: \"fabric.experience.client-tuple-routing.v1\",\n\t\t\tasync run(subject) {\n\t\t\t\tconst calls: string[] = [];\n\t\t\t\tconst session = subject.create(plan, {\n\t\t\t\t\tasync invoke(request) { calls.push(`${request.fragmentId}.${request.eventName}`); return { status: \"accepted\" }; },\n\t\t\t\t\tasync read(request) { calls.push(`${request.fragmentId}.${request.bindingName}`); return { data: { ok: true } }; },\n\t\t\t\t});\n\t\t\t\tawait session.invoke(\"root\", \"press\", {});\n\t\t\t\tawait session.read(\"root\", \"summary\");\n\t\t\t\tif (calls.join(\",\") !== \"root.press,root.summary\") throw new Error(\"Client did not route through fragment-event and fragment-binding tuples.\");\n\t\t\t\treturn calls;\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: \"fabric.experience.client-plan-denial.v1\",\n\t\t\tasync run(subject) {\n\t\t\t\tlet called = false;\n\t\t\t\tconst session = subject.create(plan, {\n\t\t\t\t\tasync invoke() { called = true; return { status: \"accepted\" }; },\n\t\t\t\t\tasync read() { called = true; return { data: null }; },\n\t\t\t\t});\n\t\t\t\tlet rejected = false;\n\t\t\t\ttry { await session.invoke(\"root\", \"undeclared\", {}); } catch { rejected = true; }\n\t\t\t\tif (!rejected || called) throw new Error(\"Client forwarded an event that was absent from the scoped plan.\");\n\t\t\t\treturn [\"undeclared event rejected locally\"];\n\t\t\t},\n\t\t},\n\t];\n}\n\nexport async function runExperienceClientChecks(\n\tsubject: ExperienceClientConformanceSubject,\n\tchecks: readonly ExperienceClientCheck[] = experienceClientChecks(),\n): Promise<{ passed: boolean; checks: Array<{ id: ExperienceClientCheck[\"id\"]; status: \"passed\" | \"failed\"; evidence: string[]; error?: string }> }> {\n\tconst results: Array<{ id: ExperienceClientCheck[\"id\"]; status: \"passed\" | \"failed\"; evidence: string[]; error?: string }> = [];\n\tfor (const check of checks) {\n\t\ttry { results.push({ id: check.id, status: \"passed\", evidence: await check.run(subject) }); }\n\t\tcatch (error) { results.push({ id: check.id, status: \"failed\", evidence: [], error: error instanceof Error ? error.message : String(error) }); }\n\t}\n\treturn { passed: results.every((result) => result.status === \"passed\"), checks: results };\n}\n\nfunction indexFragments(root: RenderPlanFragment): Map<string, RenderPlanFragment> {\n\tconst fragments = new Map<string, RenderPlanFragment>();\n\tconst visit = (fragment: RenderPlanFragment): void => {\n\t\tif (fragments.has(fragment.id)) throw new Error(`Render plan repeats fragment \"${fragment.id}\".`);\n\t\tfragments.set(fragment.id, fragment);\n\t\tfor (const child of fragment.children ?? []) visit(child);\n\t};\n\tvisit(root);\n\treturn fragments;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"file":"client.js","names":[],"sources":["../client.ts"],"sourcesContent":["import type {\n\tExperienceGatewayClient,\n\tExperienceSession,\n\tRenderPlanFragment,\n\tScopedRenderPlan,\n} from \"./contracts\";\n\nexport type {\n\tExperienceGatewayClient,\n\tExperienceIntentRequest,\n\tExperienceReadRequest,\n\tExperienceSession,\n\tRenderPlanFragment,\n\tScopedRenderPlan,\n} from \"./contracts\";\n\nexport function createExperienceSession(\n\tplan: ScopedRenderPlan,\n\tgateway: ExperienceGatewayClient,\n): ExperienceSession {\n\tconst fragments = indexFragments(plan.root);\n\treturn {\n\t\tplan,\n\t\tasync invoke(fragmentId, eventName, parameters, idempotencyKey) {\n\t\t\tconst fragment = fragments.get(fragmentId);\n\t\t\tif (!fragment?.events?.includes(eventName)) {\n\t\t\t\tthrow new Error(`Fragment event \"${fragmentId}.${eventName}\" is not in the render plan.`);\n\t\t\t}\n\t\t\treturn gateway.invoke({\n\t\t\t\tplanId: plan.planId,\n\t\t\t\tfragmentId,\n\t\t\t\teventName,\n\t\t\t\tparameters,\n\t\t\t\t...(idempotencyKey === undefined ? {} : { idempotencyKey }),\n\t\t\t});\n\t\t},\n\t\tasync read(fragmentId, bindingName, parameters) {\n\t\t\tconst fragment = fragments.get(fragmentId);\n\t\t\tif (!fragment?.bindings?.includes(bindingName)) {\n\t\t\t\tthrow new Error(`Fragment binding \"${fragmentId}.${bindingName}\" is not in the render plan.`);\n\t\t\t}\n\t\t\treturn gateway.read({\n\t\t\t\tplanId: plan.planId,\n\t\t\t\tfragmentId,\n\t\t\t\tbindingName,\n\t\t\t\t...(parameters === undefined ? {} : { parameters }),\n\t\t\t});\n\t\t},\n\t};\n}\n\nexport interface ExperienceClientConformanceSubject {\n\tcreate(plan: ScopedRenderPlan, gateway: ExperienceGatewayClient): ExperienceSession;\n}\n\nexport interface ExperienceClientCheck {\n\tid: \"fabric.experience.client-tuple-routing.v1\" | \"fabric.experience.client-plan-denial.v1\";\n\trun(subject: ExperienceClientConformanceSubject): Promise<string[]>;\n}\n\nexport function experienceClientChecks(): readonly ExperienceClientCheck[] {\n\tconst plan: ScopedRenderPlan = {\n\t\tformatVersion: 1,\n\t\tplanId: \"conformance-plan\",\n\t\tapplication: \"conformance\",\n\t\tchannel: \"test\",\n\t\treleaseDigest: \"a\".repeat(64),\n\t\tassemblyDigest: \"b\".repeat(64),\n\t\ttreeId: \"root\",\n\t\ttokenSet: { name: \"conformance\", version: \"1.0.0\" },\n\t\texpiresAt: \"2099-01-01T00:00:00.000Z\",\n\t\troot: { id: \"root\", component: \"Action\", events: [\"press\"], bindings: [\"summary\"] },\n\t};\n\treturn [\n\t\t{\n\t\t\tid: \"fabric.experience.client-tuple-routing.v1\",\n\t\t\tasync run(subject) {\n\t\t\t\tconst calls: string[] = [];\n\t\t\t\tconst session = subject.create(plan, {\n\t\t\t\t\tasync invoke(request) { calls.push(`${request.fragmentId}.${request.eventName}`); return { status: \"accepted\" }; },\n\t\t\t\t\tasync read(request) { calls.push(`${request.fragmentId}.${request.bindingName}`); return { data: { ok: true } }; },\n\t\t\t\t});\n\t\t\t\tawait session.invoke(\"root\", \"press\", {});\n\t\t\t\tawait session.read(\"root\", \"summary\");\n\t\t\t\tif (calls.join(\",\") !== \"root.press,root.summary\") throw new Error(\"Client did not route through fragment-event and fragment-binding tuples.\");\n\t\t\t\treturn calls;\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: \"fabric.experience.client-plan-denial.v1\",\n\t\t\tasync run(subject) {\n\t\t\t\tlet called = false;\n\t\t\t\tconst session = subject.create(plan, {\n\t\t\t\t\tasync invoke() { called = true; return { status: \"accepted\" }; },\n\t\t\t\t\tasync read() { called = true; return { data: null }; },\n\t\t\t\t});\n\t\t\t\tlet rejected = false;\n\t\t\t\ttry { await session.invoke(\"root\", \"undeclared\", {}); } catch { rejected = true; }\n\t\t\t\tif (!rejected || called) throw new Error(\"Client forwarded an event that was absent from the scoped plan.\");\n\t\t\t\treturn [\"undeclared event rejected locally\"];\n\t\t\t},\n\t\t},\n\t];\n}\n\nexport async function runExperienceClientChecks(\n\tsubject: ExperienceClientConformanceSubject,\n\tchecks: readonly ExperienceClientCheck[] = experienceClientChecks(),\n): Promise<{ passed: boolean; checks: Array<{ id: ExperienceClientCheck[\"id\"]; status: \"passed\" | \"failed\"; evidence: string[]; error?: string }> }> {\n\tconst results: Array<{ id: ExperienceClientCheck[\"id\"]; status: \"passed\" | \"failed\"; evidence: string[]; error?: string }> = [];\n\tfor (const check of checks) {\n\t\ttry { results.push({ id: check.id, status: \"passed\", evidence: await check.run(subject) }); }\n\t\tcatch (error) { results.push({ id: check.id, status: \"failed\", evidence: [], error: error instanceof Error ? error.message : String(error) }); }\n\t}\n\treturn { passed: results.every((result) => result.status === \"passed\"), checks: results };\n}\n\nfunction indexFragments(root: RenderPlanFragment): Map<string, RenderPlanFragment> {\n\tconst fragments = new Map<string, RenderPlanFragment>();\n\tconst visit = (fragment: RenderPlanFragment): void => {\n\t\tif (fragments.has(fragment.id)) throw new Error(`Render plan repeats fragment \"${fragment.id}\".`);\n\t\tfragments.set(fragment.id, fragment);\n\t\tfor (const child of fragment.children ?? []) visit(child);\n\t};\n\tvisit(root);\n\treturn fragments;\n}\n"],"mappings":"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"}
@@ -1,19 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __copyProps = (to, from, except, desc) => {
7
- if (from && typeof from === "object" || typeof from === "function") {
8
- for (let key of __getOwnPropNames(from))
9
- if (!__hasOwnProp.call(to, key) && key !== except)
10
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
- }
12
- return to;
13
- };
14
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
-
16
- // contracts.ts
17
- var contracts_exports = {};
18
- module.exports = __toCommonJS(contracts_exports);
19
- //# sourceMappingURL=contracts.cjs.map
@@ -1,40 +1,41 @@
1
- interface ExperienceScope {
2
- tenantId: string;
3
- spaceId: string;
4
- actorId: string;
5
- actorType: string;
1
+ //#region contracts.d.ts
2
+ export interface ExperienceScope {
3
+ tenantId: string;
4
+ spaceId: string;
5
+ actorId: string;
6
+ actorType: string;
6
7
  }
7
- interface RenderPlanFragment {
8
- id: string;
9
- component?: string;
10
- props?: Record<string, unknown>;
11
- slot?: string;
12
- events?: readonly string[];
13
- offlineEvents?: readonly string[];
14
- bindings?: readonly string[];
15
- children?: readonly RenderPlanFragment[];
8
+ export interface RenderPlanFragment {
9
+ id: string;
10
+ component?: string;
11
+ props?: Record<string, unknown>;
12
+ slot?: string;
13
+ events?: readonly string[];
14
+ offlineEvents?: readonly string[];
15
+ bindings?: readonly string[];
16
+ children?: readonly RenderPlanFragment[];
16
17
  }
17
- interface ScopedRenderPlan {
18
- formatVersion: 1;
19
- planId: string;
20
- application: string;
21
- channel: string;
22
- releaseDigest: string;
23
- assemblyDigest: string;
24
- treeId: string;
25
- root: RenderPlanFragment;
26
- tokenSet: {
27
- name: string;
28
- version: string;
29
- };
30
- expiresAt: string;
18
+ export interface ScopedRenderPlan {
19
+ formatVersion: 1;
20
+ planId: string;
21
+ application: string;
22
+ channel: string;
23
+ releaseDigest: string;
24
+ assemblyDigest: string;
25
+ treeId: string;
26
+ root: RenderPlanFragment;
27
+ tokenSet: {
28
+ name: string;
29
+ version: string;
30
+ };
31
+ expiresAt: string;
31
32
  }
32
- interface ExperienceIntentRequest {
33
- planId: string;
34
- fragmentId: string;
35
- eventName: string;
36
- parameters: Record<string, unknown>;
37
- idempotencyKey?: string;
33
+ export interface ExperienceIntentRequest {
34
+ planId: string;
35
+ fragmentId: string;
36
+ eventName: string;
37
+ parameters: Record<string, unknown>;
38
+ idempotencyKey?: string;
38
39
  }
39
40
  /**
40
41
  * A replay of an action captured while disconnected.
@@ -45,25 +46,25 @@ interface ExperienceIntentRequest {
45
46
  * capture-authority evidence stamped at receipt cannot truthfully attest when
46
47
  * the operator actually acted.
47
48
  */
48
- interface ExperienceReplayRequest extends ExperienceIntentRequest {
49
- executionReason: "offline_replay";
50
- /** RFC 3339 instant the action was captured on the device. */
51
- capturedAt: string;
52
- idempotencyKey: string;
49
+ export interface ExperienceReplayRequest extends ExperienceIntentRequest {
50
+ executionReason: "offline_replay";
51
+ /** RFC 3339 instant the action was captured on the device. */
52
+ capturedAt: string;
53
+ idempotencyKey: string;
53
54
  }
54
- interface ExperienceReadRequest {
55
- planId: string;
56
- fragmentId: string;
57
- bindingName: string;
58
- parameters?: Record<string, unknown>;
55
+ export interface ExperienceReadRequest {
56
+ planId: string;
57
+ fragmentId: string;
58
+ bindingName: string;
59
+ parameters?: Record<string, unknown>;
59
60
  }
60
- interface ExperienceGatewayClient {
61
- invoke(request: ExperienceIntentRequest): Promise<unknown>;
62
- replay?(request: ExperienceReplayRequest): Promise<ExperienceInvocationOutcome>;
63
- read(request: ExperienceReadRequest): Promise<{
64
- data: unknown;
65
- stale?: boolean;
66
- }>;
61
+ export interface ExperienceGatewayClient {
62
+ invoke(request: ExperienceIntentRequest): Promise<unknown>;
63
+ replay?(request: ExperienceReplayRequest): Promise<ExperienceInvocationOutcome>;
64
+ read(request: ExperienceReadRequest): Promise<{
65
+ data: unknown;
66
+ stale?: boolean;
67
+ }>;
67
68
  }
68
69
  /**
69
70
  * What a governed submission comes back as.
@@ -73,25 +74,24 @@ interface ExperienceGatewayClient {
73
74
  * an error. Anything reading only the exception path will count a refusal as a
74
75
  * success.
75
76
  */
76
- interface ExperienceInvocationOutcome {
77
- status?: string;
78
- /** `executionReason` names the attempt that produced this; `"recovery"` means effects may already have landed. */
79
- reconciliation?: {
80
- kind?: string;
81
- message?: string;
82
- executionReason?: string;
83
- };
84
- /** Present when an adapter's own outcome could not be determined. */
85
- adapterReconciliation?: unknown;
86
- [key: string]: unknown;
77
+ export interface ExperienceInvocationOutcome {
78
+ status?: string;
79
+ /** `executionReason` names the attempt that produced this; `"recovery"` means effects may already have landed. */
80
+ reconciliation?: {
81
+ kind?: string;
82
+ message?: string;
83
+ executionReason?: string;
84
+ };
85
+ /** Present when an adapter's own outcome could not be determined. */
86
+ adapterReconciliation?: unknown;
87
+ [key: string]: unknown;
87
88
  }
88
- interface ExperienceSession {
89
- readonly plan: ScopedRenderPlan;
90
- invoke(fragmentId: string, eventName: string, parameters: Record<string, unknown>, idempotencyKey?: string): Promise<unknown>;
91
- read(fragmentId: string, bindingName: string, parameters?: Record<string, unknown>): Promise<{
92
- data: unknown;
93
- stale?: boolean;
94
- }>;
89
+ export interface ExperienceSession {
90
+ readonly plan: ScopedRenderPlan;
91
+ invoke(fragmentId: string, eventName: string, parameters: Record<string, unknown>, idempotencyKey?: string): Promise<unknown>;
92
+ read(fragmentId: string, bindingName: string, parameters?: Record<string, unknown>): Promise<{
93
+ data: unknown;
94
+ stale?: boolean;
95
+ }>;
95
96
  }
96
-
97
- export type { ExperienceGatewayClient, ExperienceIntentRequest, ExperienceInvocationOutcome, ExperienceReadRequest, ExperienceReplayRequest, ExperienceScope, ExperienceSession, RenderPlanFragment, ScopedRenderPlan };
97
+ //#endregion
@@ -1,40 +1,41 @@
1
- interface ExperienceScope {
2
- tenantId: string;
3
- spaceId: string;
4
- actorId: string;
5
- actorType: string;
1
+ //#region contracts.d.ts
2
+ export interface ExperienceScope {
3
+ tenantId: string;
4
+ spaceId: string;
5
+ actorId: string;
6
+ actorType: string;
6
7
  }
7
- interface RenderPlanFragment {
8
- id: string;
9
- component?: string;
10
- props?: Record<string, unknown>;
11
- slot?: string;
12
- events?: readonly string[];
13
- offlineEvents?: readonly string[];
14
- bindings?: readonly string[];
15
- children?: readonly RenderPlanFragment[];
8
+ export interface RenderPlanFragment {
9
+ id: string;
10
+ component?: string;
11
+ props?: Record<string, unknown>;
12
+ slot?: string;
13
+ events?: readonly string[];
14
+ offlineEvents?: readonly string[];
15
+ bindings?: readonly string[];
16
+ children?: readonly RenderPlanFragment[];
16
17
  }
17
- interface ScopedRenderPlan {
18
- formatVersion: 1;
19
- planId: string;
20
- application: string;
21
- channel: string;
22
- releaseDigest: string;
23
- assemblyDigest: string;
24
- treeId: string;
25
- root: RenderPlanFragment;
26
- tokenSet: {
27
- name: string;
28
- version: string;
29
- };
30
- expiresAt: string;
18
+ export interface ScopedRenderPlan {
19
+ formatVersion: 1;
20
+ planId: string;
21
+ application: string;
22
+ channel: string;
23
+ releaseDigest: string;
24
+ assemblyDigest: string;
25
+ treeId: string;
26
+ root: RenderPlanFragment;
27
+ tokenSet: {
28
+ name: string;
29
+ version: string;
30
+ };
31
+ expiresAt: string;
31
32
  }
32
- interface ExperienceIntentRequest {
33
- planId: string;
34
- fragmentId: string;
35
- eventName: string;
36
- parameters: Record<string, unknown>;
37
- idempotencyKey?: string;
33
+ export interface ExperienceIntentRequest {
34
+ planId: string;
35
+ fragmentId: string;
36
+ eventName: string;
37
+ parameters: Record<string, unknown>;
38
+ idempotencyKey?: string;
38
39
  }
39
40
  /**
40
41
  * A replay of an action captured while disconnected.
@@ -45,25 +46,25 @@ interface ExperienceIntentRequest {
45
46
  * capture-authority evidence stamped at receipt cannot truthfully attest when
46
47
  * the operator actually acted.
47
48
  */
48
- interface ExperienceReplayRequest extends ExperienceIntentRequest {
49
- executionReason: "offline_replay";
50
- /** RFC 3339 instant the action was captured on the device. */
51
- capturedAt: string;
52
- idempotencyKey: string;
49
+ export interface ExperienceReplayRequest extends ExperienceIntentRequest {
50
+ executionReason: "offline_replay";
51
+ /** RFC 3339 instant the action was captured on the device. */
52
+ capturedAt: string;
53
+ idempotencyKey: string;
53
54
  }
54
- interface ExperienceReadRequest {
55
- planId: string;
56
- fragmentId: string;
57
- bindingName: string;
58
- parameters?: Record<string, unknown>;
55
+ export interface ExperienceReadRequest {
56
+ planId: string;
57
+ fragmentId: string;
58
+ bindingName: string;
59
+ parameters?: Record<string, unknown>;
59
60
  }
60
- interface ExperienceGatewayClient {
61
- invoke(request: ExperienceIntentRequest): Promise<unknown>;
62
- replay?(request: ExperienceReplayRequest): Promise<ExperienceInvocationOutcome>;
63
- read(request: ExperienceReadRequest): Promise<{
64
- data: unknown;
65
- stale?: boolean;
66
- }>;
61
+ export interface ExperienceGatewayClient {
62
+ invoke(request: ExperienceIntentRequest): Promise<unknown>;
63
+ replay?(request: ExperienceReplayRequest): Promise<ExperienceInvocationOutcome>;
64
+ read(request: ExperienceReadRequest): Promise<{
65
+ data: unknown;
66
+ stale?: boolean;
67
+ }>;
67
68
  }
68
69
  /**
69
70
  * What a governed submission comes back as.
@@ -73,25 +74,24 @@ interface ExperienceGatewayClient {
73
74
  * an error. Anything reading only the exception path will count a refusal as a
74
75
  * success.
75
76
  */
76
- interface ExperienceInvocationOutcome {
77
- status?: string;
78
- /** `executionReason` names the attempt that produced this; `"recovery"` means effects may already have landed. */
79
- reconciliation?: {
80
- kind?: string;
81
- message?: string;
82
- executionReason?: string;
83
- };
84
- /** Present when an adapter's own outcome could not be determined. */
85
- adapterReconciliation?: unknown;
86
- [key: string]: unknown;
77
+ export interface ExperienceInvocationOutcome {
78
+ status?: string;
79
+ /** `executionReason` names the attempt that produced this; `"recovery"` means effects may already have landed. */
80
+ reconciliation?: {
81
+ kind?: string;
82
+ message?: string;
83
+ executionReason?: string;
84
+ };
85
+ /** Present when an adapter's own outcome could not be determined. */
86
+ adapterReconciliation?: unknown;
87
+ [key: string]: unknown;
87
88
  }
88
- interface ExperienceSession {
89
- readonly plan: ScopedRenderPlan;
90
- invoke(fragmentId: string, eventName: string, parameters: Record<string, unknown>, idempotencyKey?: string): Promise<unknown>;
91
- read(fragmentId: string, bindingName: string, parameters?: Record<string, unknown>): Promise<{
92
- data: unknown;
93
- stale?: boolean;
94
- }>;
89
+ export interface ExperienceSession {
90
+ readonly plan: ScopedRenderPlan;
91
+ invoke(fragmentId: string, eventName: string, parameters: Record<string, unknown>, idempotencyKey?: string): Promise<unknown>;
92
+ read(fragmentId: string, bindingName: string, parameters?: Record<string, unknown>): Promise<{
93
+ data: unknown;
94
+ stale?: boolean;
95
+ }>;
95
96
  }
96
-
97
- export type { ExperienceGatewayClient, ExperienceIntentRequest, ExperienceInvocationOutcome, ExperienceReadRequest, ExperienceReplayRequest, ExperienceScope, ExperienceSession, RenderPlanFragment, ScopedRenderPlan };
97
+ //#endregion
package/dist/contracts.js CHANGED
@@ -1 +1 @@
1
- //# sourceMappingURL=contracts.js.map
1
+ export {};