@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/CHANGELOG.md +25 -0
- package/dist/client.cjs +120 -137
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +19 -20
- package/dist/client.d.ts +19 -20
- package/dist/client.js +117 -110
- package/dist/client.js.map +1 -1
- package/dist/contracts.cjs +0 -19
- package/dist/contracts.d.cts +71 -71
- package/dist/contracts.d.ts +71 -71
- package/dist/contracts.js +1 -1
- package/dist/offline.cjs +307 -270
- package/dist/offline.cjs.map +1 -1
- package/dist/offline.d.cts +87 -88
- package/dist/offline.d.ts +87 -88
- package/dist/offline.js +305 -244
- package/dist/offline.js.map +1 -1
- package/dist/server.cjs +230 -225
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +88 -89
- package/dist/server.d.ts +88 -89
- package/dist/server.js +226 -200
- package/dist/server.js.map +1 -1
- package/package.json +8 -7
- package/dist/contracts.cjs.map +0 -1
- package/dist/contracts.js.map +0 -1
package/dist/server.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../server.ts"],"sourcesContent":["import type {\n\tReleaseCryptoPort,\n\tReleaseGenerationStore,\n\tReleaseTrustStore,\n\tExperienceIntentRoute,\n\tExperienceViewRoute,\n\tSduiFragment,\n\tSduiFragmentValue,\n\tSduiReleaseV3,\n} from \"@fabricorg/sdui-release/contracts\";\nimport {\n\tactivateReleaseChannelPointer,\n\tverifySignedExperienceRelease,\n} from \"@fabricorg/sdui-release/contracts\";\nimport type {\n\tExperienceScope,\n\tRenderPlanFragment,\n\tScopedRenderPlan,\n} from \"./contracts\";\n\nexport type {\n\tExperienceScope,\n\tRenderPlanFragment,\n\tScopedRenderPlan,\n} from \"./contracts\";\n\nexport interface ExperiencePlanState {\n\tpublicPlan: ScopedRenderPlan;\n\tscope: ExperienceScope;\n\tintents: ReadonlyMap<string, {\n\t\tfragmentId: string;\n\t\teventName: string;\n\t\troute: ExperienceIntentRoute;\n\t}>;\n\tviews: ReadonlyMap<string, {\n\t\tfragmentId: string;\n\t\tbindingName: string;\n\t\troute: ExperienceViewRoute;\n\t}>;\n}\n\nexport interface ExperiencePlanStore {\n\tsave(state: ExperiencePlanState): Promise<void>;\n\tload(planId: string): Promise<ExperiencePlanState | null>;\n}\n\nexport interface IssueRenderPlanInput {\n\tapplication: string;\n\tchannel: string;\n\tscope: ExperienceScope;\n\tvariantId?: string;\n\tttlMs?: number;\n}\n\nexport interface ResolveIntentInput {\n\tplanId: string;\n\tfragmentId: string;\n\teventName: string;\n\tscope: ExperienceScope;\n}\n\nexport interface ResolvedExperienceIntent {\n\tactionId: `${string}.${string}`;\n\tactionVersion: number;\n\texecution: ExperienceIntentRoute[\"execution\"];\n\tinitiatingReleaseDigest: string;\n\tassemblyDigest: string;\n}\n\nexport interface ResolvedExperienceView {\n\tname: `${string}/${string}`;\n\tversion: string;\n\tinitiatingReleaseDigest: string;\n\tassemblyDigest: string;\n}\n\nexport interface ExperienceServerRuntime {\n\tissuePlan(input: IssueRenderPlanInput): Promise<ScopedRenderPlan>;\n\tresolveIntent(input: ResolveIntentInput): Promise<ResolvedExperienceIntent>;\n\tresolveView(input: {\n\t\tplanId: string;\n\t\tfragmentId: string;\n\t\tbindingName: string;\n\t\tscope: ExperienceScope;\n\t}): Promise<ResolvedExperienceView>;\n}\n\nexport interface ExperienceServerConformanceSubject {\n\truntime: ExperienceServerRuntime;\n\tissue: IssueRenderPlanInput;\n\tintent: { fragmentId: string; eventName: string };\n\twrongScope: ExperienceScope;\n}\n\nexport interface ExperienceServerCheck {\n\tid: \"fabric.experience.plan-opaque.v1\" | \"fabric.experience.scope-isolation.v1\" | \"fabric.experience.intent-resolution.v1\";\n\trun(subject: ExperienceServerConformanceSubject): Promise<string[]>;\n}\n\nexport function experienceServerChecks(): readonly ExperienceServerCheck[] {\n\treturn [\n\t\t{\n\t\t\tid: \"fabric.experience.plan-opaque.v1\",\n\t\t\tasync run(subject) {\n\t\t\t\tconst plan = await subject.runtime.issuePlan(subject.issue);\n\t\t\t\tconst serialized = JSON.stringify(plan);\n\t\t\t\tif (serialized.includes(\"capability://\")) throw new Error(\"Public render plan exposes a capability reference.\");\n\t\t\t\treturn [plan.planId];\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: \"fabric.experience.scope-isolation.v1\",\n\t\t\tasync run(subject) {\n\t\t\t\tconst plan = await subject.runtime.issuePlan(subject.issue);\n\t\t\t\ttry {\n\t\t\t\t\tawait subject.runtime.resolveIntent({\n\t\t\t\t\t\tplanId: plan.planId,\n\t\t\t\t\t\t...subject.intent,\n\t\t\t\t\t\tscope: subject.wrongScope,\n\t\t\t\t\t});\n\t\t\t\t\tthrow new Error(\"Runtime accepted an intent from the wrong trusted scope.\");\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (error instanceof Error && error.message === \"Runtime accepted an intent from the wrong trusted scope.\") throw error;\n\t\t\t\t}\n\t\t\t\treturn [\"wrong scope rejected\"];\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: \"fabric.experience.intent-resolution.v1\",\n\t\t\tasync run(subject) {\n\t\t\t\tconst plan = await subject.runtime.issuePlan(subject.issue);\n\t\t\t\tconst resolved = await subject.runtime.resolveIntent({\n\t\t\t\t\tplanId: plan.planId,\n\t\t\t\t\t...subject.intent,\n\t\t\t\t\tscope: subject.issue.scope,\n\t\t\t\t});\n\t\t\t\treturn [`${resolved.actionId}@${resolved.actionVersion}`];\n\t\t\t},\n\t\t},\n\t];\n}\n\nexport async function runExperienceServerChecks(\n\tsubject: ExperienceServerConformanceSubject,\n\tchecks: readonly ExperienceServerCheck[] = experienceServerChecks(),\n): Promise<{\n\tpassed: boolean;\n\tchecks: Array<{ id: ExperienceServerCheck[\"id\"]; status: \"passed\" | \"failed\"; evidence: string[]; error?: string }>;\n}> {\n\tconst results: Array<{ id: ExperienceServerCheck[\"id\"]; status: \"passed\" | \"failed\"; evidence: string[]; error?: string }> = [];\n\tfor (const check of checks) {\n\t\ttry {\n\t\t\tresults.push({ id: check.id, status: \"passed\", evidence: await check.run(subject) });\n\t\t} catch (error) {\n\t\t\tresults.push({ id: check.id, status: \"failed\", evidence: [], error: error instanceof Error ? error.message : String(error) });\n\t\t}\n\t}\n\treturn { passed: results.every((result) => result.status === \"passed\"), checks: results };\n}\n\nexport function createExperienceServerRuntime(options: {\n\tstore: ExperiencePlanStore;\n\tresolveChannel(input: { application: string; channel: string }): Promise<{\n\t\tpointerJws: string;\n\t\treleaseJws: string;\n\t}>;\n\tissuer: string;\n\tcrypto: ReleaseCryptoPort;\n\ttrust: ReleaseTrustStore;\n\tgenerations: ReleaseGenerationStore;\n\tnextOpaqueId(): string;\n\tnow?: () => Date;\n}): ExperienceServerRuntime {\n\tconst now = options.now ?? (() => new Date());\n\treturn {\n\t\tasync issuePlan(input) {\n\t\t\tconst admitted = await options.resolveChannel({ application: input.application, channel: input.channel });\n\t\t\tconst pointer = await activateReleaseChannelPointer({\n\t\t\t\tcompactJws: admitted.pointerJws,\n\t\t\t\tcrypto: options.crypto,\n\t\t\t\ttrust: options.trust,\n\t\t\t\tgenerations: options.generations,\n\t\t\t\texpected: { issuer: options.issuer, application: input.application, channel: input.channel },\n\t\t\t\tnow: now(),\n\t\t\t});\n\t\t\tconst release = await verifySignedExperienceRelease({\n\t\t\t\tcompactJws: admitted.releaseJws,\n\t\t\t\tcrypto: options.crypto,\n\t\t\t\ttrust: options.trust,\n\t\t\t\texpected: {\n\t\t\t\t\tissuer: options.issuer,\n\t\t\t\t\tapplication: input.application,\n\t\t\t\t\tassemblyDigest: pointer.assemblyDigest,\n\t\t\t\t},\n\t\t\t});\n\t\t\tif (release.releaseDigest !== pointer.activeReleaseDigest) {\n\t\t\t\tthrow new Error(\"Selected experience release does not match the active release-channel pointer.\");\n\t\t\t}\n\t\t\tconst selected = selectTree(release, input.variantId);\n\t\t\tconst planId = options.nextOpaqueId();\n\t\t\tif (!planId || /capability:\\/\\//.test(planId)) throw new Error(\"Experience plan id must be opaque.\");\n\t\t\tconst intents = new Map<string, ExperiencePlanState[\"intents\"] extends ReadonlyMap<string, infer Value> ? Value : never>();\n\t\t\tconst views = new Map<string, ExperiencePlanState[\"views\"] extends ReadonlyMap<string, infer Value> ? Value : never>();\n\t\t\tconst root = toRenderPlanFragment(selected.root, release, selected.treeId, intents, views);\n\t\t\tconst publicPlan: ScopedRenderPlan = Object.freeze({\n\t\t\t\tformatVersion: 1,\n\t\t\t\tplanId,\n\t\t\t\tapplication: input.application,\n\t\t\t\tchannel: input.channel,\n\t\t\t\treleaseDigest: release.releaseDigest,\n\t\t\t\tassemblyDigest: release.assemblyDigest,\n\t\t\t\ttreeId: selected.treeId,\n\t\t\t\troot,\n\t\t\t\ttokenSet: { name: release.tokenSet.name, version: release.tokenSet.version },\n\t\t\t\texpiresAt: new Date(now().getTime() + (input.ttlMs ?? 300_000)).toISOString(),\n\t\t\t});\n\t\t\tif (JSON.stringify(publicPlan).includes(\"capability://\")) {\n\t\t\t\tthrow new Error(\"Public render plan exposes a capability reference.\");\n\t\t\t}\n\t\t\tawait options.store.save({ publicPlan, scope: { ...input.scope }, intents, views });\n\t\t\treturn publicPlan;\n\t\t},\n\t\tasync resolveIntent(input) {\n\t\t\tconst state = await options.store.load(input.planId);\n\t\t\tif (!state) throw new Error(\"Experience render plan was not found.\");\n\t\t\tif (Date.parse(state.publicPlan.expiresAt) <= now().getTime()) throw new Error(\"Experience render plan has expired.\");\n\t\t\tif (!sameScope(state.scope, input.scope)) throw new Error(\"Experience render plan scope does not match trusted request scope.\");\n\t\t\tconst intent = state.intents.get(`${input.fragmentId}\\u0000${input.eventName}`);\n\t\t\tif (!intent) throw new Error(`Fragment event \"${input.fragmentId}.${input.eventName}\" is not granted by the render plan.`);\n\t\t\treturn {\n\t\t\t\tactionId: intent.route.actionId,\n\t\t\t\tactionVersion: intent.route.version,\n\t\t\t\texecution: intent.route.execution,\n\t\t\t\tinitiatingReleaseDigest: state.publicPlan.releaseDigest,\n\t\t\t\tassemblyDigest: state.publicPlan.assemblyDigest,\n\t\t\t};\n\t\t},\n\t\tasync resolveView(input) {\n\t\t\tconst state = await loadPlan(options.store, input.planId, input.scope, now());\n\t\t\tconst view = state.views.get(`${input.fragmentId}\\u0000${input.bindingName}`);\n\t\t\tif (!view) throw new Error(`Fragment binding \"${input.fragmentId}.${input.bindingName}\" is not granted by the render plan.`);\n\t\t\treturn {\n\t\t\t\tname: view.route.name,\n\t\t\t\tversion: view.route.version,\n\t\t\t\tinitiatingReleaseDigest: state.publicPlan.releaseDigest,\n\t\t\t\tassemblyDigest: state.publicPlan.assemblyDigest,\n\t\t\t};\n\t\t},\n\t};\n}\n\nfunction selectTree(release: SduiReleaseV3, variantId?: string): { treeId: string; root: SduiFragment } {\n\tif (variantId === undefined) return { treeId: \"root\", root: release.document.root };\n\tconst variant = release.document.variants?.find((candidate) => candidate.id === variantId);\n\tif (!variant) throw new Error(`Variant \"${variantId}\" is not enumerated by the promoted release.`);\n\treturn { treeId: variant.id, root: variant.root };\n}\n\nfunction toRenderPlanFragment(\n\tfragment: SduiFragment,\n\trelease: SduiReleaseV3,\n\ttreeId: string,\n\tintents: Map<string, { fragmentId: string; eventName: string; route: ExperienceIntentRoute }>,\n\tviews: Map<string, { fragmentId: string; bindingName: string; route: ExperienceViewRoute }>,\n): RenderPlanFragment {\n\tconst effective = release.effectiveGrants.find((grant) => grant.treeId === treeId && grant.fragmentId === fragment.id);\n\tif (!effective) throw new Error(`Promoted release has no effective grant for \"${treeId}:${fragment.id}\".`);\n\tconst events: string[] = [];\n\tconst offlineEvents: string[] = [];\n\tconst bindings: string[] = [];\n\tif (fragment.dataRef !== undefined) {\n\t\tif (!effective.views.includes(fragment.dataRef)) throw new Error(`Fragment data binding \"${fragment.id}\" exceeds its effective grants.`);\n\t\tconst route = release.routes.views.find((candidate) => candidate.reference === fragment.dataRef);\n\t\tif (!route) throw new Error(`Fragment data binding \"${fragment.id}\" has no compiled view route.`);\n\t\tviews.set(`${fragment.id}\\u0000$data`, { fragmentId: fragment.id, bindingName: \"$data\", route });\n\t\tbindings.push(\"$data\");\n\t}\n\tfor (const [eventName, action] of Object.entries(fragment.actions ?? {})) {\n\t\tif (!effective.intents.includes(action.intent)) throw new Error(`Fragment event \"${fragment.id}.${eventName}\" exceeds its effective grants.`);\n\t\tconst route = release.routes.intents.find((candidate) => candidate.reference === action.intent);\n\t\tif (!route) throw new Error(`Fragment event \"${fragment.id}.${eventName}\" has no compiled intent route.`);\n\t\tintents.set(`${fragment.id}\\u0000${eventName}`, { fragmentId: fragment.id, eventName, route });\n\t\tevents.push(eventName);\n\t\tif (route.execution?.connectivity === \"offline-capturable\") offlineEvents.push(eventName);\n\t}\n\treturn Object.freeze({\n\t\tid: fragment.id,\n\t\t...(fragment.component === undefined ? {} : { component: fragment.component }),\n\t\t...(fragment.props === undefined ? {} : { props: stripCapabilityReferences(fragment.props) }),\n\t\t...(fragment.slot === undefined ? {} : { slot: fragment.slot }),\n\t\t...(events.length === 0 ? {} : { events: Object.freeze(events.sort()) }),\n\t\t...(offlineEvents.length === 0 ? {} : { offlineEvents: Object.freeze(offlineEvents.sort()) }),\n\t\t...(bindings.length === 0 ? {} : { bindings: Object.freeze(bindings) }),\n\t\t...(fragment.children === undefined ? {} : {\n\t\t\tchildren: Object.freeze(fragment.children.map((child) => toRenderPlanFragment(child, release, treeId, intents, views))),\n\t\t}),\n\t});\n}\n\nasync function loadPlan(\n\tstore: ExperiencePlanStore,\n\tplanId: string,\n\tscope: ExperienceScope,\n\tnow: Date,\n): Promise<ExperiencePlanState> {\n\tconst state = await store.load(planId);\n\tif (!state) throw new Error(\"Experience render plan was not found.\");\n\tif (Date.parse(state.publicPlan.expiresAt) <= now.getTime()) throw new Error(\"Experience render plan has expired.\");\n\tif (!sameScope(state.scope, scope)) throw new Error(\"Experience render plan scope does not match trusted request scope.\");\n\treturn state;\n}\n\nfunction stripCapabilityReferences(value: Record<string, SduiFragmentValue>): Record<string, unknown> {\n\tconst strip = (candidate: SduiFragmentValue): unknown => {\n\t\tif (Array.isArray(candidate)) return candidate.map(strip);\n\t\tif (candidate && typeof candidate === \"object\") {\n\t\t\tif (\"$ref\" in candidate) return undefined;\n\t\t\treturn Object.fromEntries(Object.entries(candidate).flatMap(([key, entry]) => {\n\t\t\t\tconst stripped = strip(entry);\n\t\t\t\treturn stripped === undefined ? [] : [[key, stripped]];\n\t\t\t}));\n\t\t}\n\t\treturn candidate;\n\t};\n\treturn strip(value) as Record<string, unknown>;\n}\n\nfunction sameScope(left: ExperienceScope, right: ExperienceScope): boolean {\n\treturn left.tenantId === right.tenantId\n\t\t&& left.spaceId === right.spaceId\n\t\t&& left.actorId === right.actorId\n\t\t&& left.actorType === right.actorType;\n}\n\nexport function createMemoryExperiencePlanStore(): ExperiencePlanStore {\n\tconst plans = new Map<string, ExperiencePlanState>();\n\treturn {\n\t\tasync save(state) {\n\t\t\tif (plans.has(state.publicPlan.planId)) throw new Error(`Experience render plan \"${state.publicPlan.planId}\" already exists.`);\n\t\t\tplans.set(state.publicPlan.planId, state);\n\t\t},\n\t\tasync load(planId) {\n\t\t\treturn plans.get(planId) ?? null;\n\t\t},\n\t};\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"file":"server.cjs","names":["activateReleaseChannelPointer","verifySignedExperienceRelease"],"sources":["../server.ts"],"sourcesContent":["import type {\n\tReleaseCryptoPort,\n\tReleaseGenerationStore,\n\tReleaseTrustStore,\n\tExperienceIntentRoute,\n\tExperienceViewRoute,\n\tSduiFragment,\n\tSduiFragmentValue,\n\tSduiReleaseV3,\n} from \"@fabricorg/sdui-release/contracts\";\nimport {\n\tactivateReleaseChannelPointer,\n\tverifySignedExperienceRelease,\n} from \"@fabricorg/sdui-release/contracts\";\nimport type {\n\tExperienceScope,\n\tRenderPlanFragment,\n\tScopedRenderPlan,\n} from \"./contracts\";\n\nexport type {\n\tExperienceScope,\n\tRenderPlanFragment,\n\tScopedRenderPlan,\n} from \"./contracts\";\n\nexport interface ExperiencePlanState {\n\tpublicPlan: ScopedRenderPlan;\n\tscope: ExperienceScope;\n\tintents: ReadonlyMap<string, {\n\t\tfragmentId: string;\n\t\teventName: string;\n\t\troute: ExperienceIntentRoute;\n\t}>;\n\tviews: ReadonlyMap<string, {\n\t\tfragmentId: string;\n\t\tbindingName: string;\n\t\troute: ExperienceViewRoute;\n\t}>;\n}\n\nexport interface ExperiencePlanStore {\n\tsave(state: ExperiencePlanState): Promise<void>;\n\tload(planId: string): Promise<ExperiencePlanState | null>;\n}\n\nexport interface IssueRenderPlanInput {\n\tapplication: string;\n\tchannel: string;\n\tscope: ExperienceScope;\n\tvariantId?: string;\n\tttlMs?: number;\n}\n\nexport interface ResolveIntentInput {\n\tplanId: string;\n\tfragmentId: string;\n\teventName: string;\n\tscope: ExperienceScope;\n}\n\nexport interface ResolvedExperienceIntent {\n\tactionId: `${string}.${string}`;\n\tactionVersion: number;\n\texecution: ExperienceIntentRoute[\"execution\"];\n\tinitiatingReleaseDigest: string;\n\tassemblyDigest: string;\n}\n\nexport interface ResolvedExperienceView {\n\tname: `${string}/${string}`;\n\tversion: string;\n\tinitiatingReleaseDigest: string;\n\tassemblyDigest: string;\n}\n\nexport interface ExperienceServerRuntime {\n\tissuePlan(input: IssueRenderPlanInput): Promise<ScopedRenderPlan>;\n\tresolveIntent(input: ResolveIntentInput): Promise<ResolvedExperienceIntent>;\n\tresolveView(input: {\n\t\tplanId: string;\n\t\tfragmentId: string;\n\t\tbindingName: string;\n\t\tscope: ExperienceScope;\n\t}): Promise<ResolvedExperienceView>;\n}\n\nexport interface ExperienceServerConformanceSubject {\n\truntime: ExperienceServerRuntime;\n\tissue: IssueRenderPlanInput;\n\tintent: { fragmentId: string; eventName: string };\n\twrongScope: ExperienceScope;\n}\n\nexport interface ExperienceServerCheck {\n\tid: \"fabric.experience.plan-opaque.v1\" | \"fabric.experience.scope-isolation.v1\" | \"fabric.experience.intent-resolution.v1\";\n\trun(subject: ExperienceServerConformanceSubject): Promise<string[]>;\n}\n\nexport function experienceServerChecks(): readonly ExperienceServerCheck[] {\n\treturn [\n\t\t{\n\t\t\tid: \"fabric.experience.plan-opaque.v1\",\n\t\t\tasync run(subject) {\n\t\t\t\tconst plan = await subject.runtime.issuePlan(subject.issue);\n\t\t\t\tconst serialized = JSON.stringify(plan);\n\t\t\t\tif (serialized.includes(\"capability://\")) throw new Error(\"Public render plan exposes a capability reference.\");\n\t\t\t\treturn [plan.planId];\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: \"fabric.experience.scope-isolation.v1\",\n\t\t\tasync run(subject) {\n\t\t\t\tconst plan = await subject.runtime.issuePlan(subject.issue);\n\t\t\t\ttry {\n\t\t\t\t\tawait subject.runtime.resolveIntent({\n\t\t\t\t\t\tplanId: plan.planId,\n\t\t\t\t\t\t...subject.intent,\n\t\t\t\t\t\tscope: subject.wrongScope,\n\t\t\t\t\t});\n\t\t\t\t\tthrow new Error(\"Runtime accepted an intent from the wrong trusted scope.\");\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (error instanceof Error && error.message === \"Runtime accepted an intent from the wrong trusted scope.\") throw error;\n\t\t\t\t}\n\t\t\t\treturn [\"wrong scope rejected\"];\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: \"fabric.experience.intent-resolution.v1\",\n\t\t\tasync run(subject) {\n\t\t\t\tconst plan = await subject.runtime.issuePlan(subject.issue);\n\t\t\t\tconst resolved = await subject.runtime.resolveIntent({\n\t\t\t\t\tplanId: plan.planId,\n\t\t\t\t\t...subject.intent,\n\t\t\t\t\tscope: subject.issue.scope,\n\t\t\t\t});\n\t\t\t\treturn [`${resolved.actionId}@${resolved.actionVersion}`];\n\t\t\t},\n\t\t},\n\t];\n}\n\nexport async function runExperienceServerChecks(\n\tsubject: ExperienceServerConformanceSubject,\n\tchecks: readonly ExperienceServerCheck[] = experienceServerChecks(),\n): Promise<{\n\tpassed: boolean;\n\tchecks: Array<{ id: ExperienceServerCheck[\"id\"]; status: \"passed\" | \"failed\"; evidence: string[]; error?: string }>;\n}> {\n\tconst results: Array<{ id: ExperienceServerCheck[\"id\"]; status: \"passed\" | \"failed\"; evidence: string[]; error?: string }> = [];\n\tfor (const check of checks) {\n\t\ttry {\n\t\t\tresults.push({ id: check.id, status: \"passed\", evidence: await check.run(subject) });\n\t\t} catch (error) {\n\t\t\tresults.push({ id: check.id, status: \"failed\", evidence: [], error: error instanceof Error ? error.message : String(error) });\n\t\t}\n\t}\n\treturn { passed: results.every((result) => result.status === \"passed\"), checks: results };\n}\n\nexport function createExperienceServerRuntime(options: {\n\tstore: ExperiencePlanStore;\n\tresolveChannel(input: { application: string; channel: string }): Promise<{\n\t\tpointerJws: string;\n\t\treleaseJws: string;\n\t}>;\n\tissuer: string;\n\tcrypto: ReleaseCryptoPort;\n\ttrust: ReleaseTrustStore;\n\tgenerations: ReleaseGenerationStore;\n\tnextOpaqueId(): string;\n\tnow?: () => Date;\n}): ExperienceServerRuntime {\n\tconst now = options.now ?? (() => new Date());\n\treturn {\n\t\tasync issuePlan(input) {\n\t\t\tconst admitted = await options.resolveChannel({ application: input.application, channel: input.channel });\n\t\t\tconst pointer = await activateReleaseChannelPointer({\n\t\t\t\tcompactJws: admitted.pointerJws,\n\t\t\t\tcrypto: options.crypto,\n\t\t\t\ttrust: options.trust,\n\t\t\t\tgenerations: options.generations,\n\t\t\t\texpected: { issuer: options.issuer, application: input.application, channel: input.channel },\n\t\t\t\tnow: now(),\n\t\t\t});\n\t\t\tconst release = await verifySignedExperienceRelease({\n\t\t\t\tcompactJws: admitted.releaseJws,\n\t\t\t\tcrypto: options.crypto,\n\t\t\t\ttrust: options.trust,\n\t\t\t\texpected: {\n\t\t\t\t\tissuer: options.issuer,\n\t\t\t\t\tapplication: input.application,\n\t\t\t\t\tassemblyDigest: pointer.assemblyDigest,\n\t\t\t\t},\n\t\t\t});\n\t\t\tif (release.releaseDigest !== pointer.activeReleaseDigest) {\n\t\t\t\tthrow new Error(\"Selected experience release does not match the active release-channel pointer.\");\n\t\t\t}\n\t\t\tconst selected = selectTree(release, input.variantId);\n\t\t\tconst planId = options.nextOpaqueId();\n\t\t\tif (!planId || /capability:\\/\\//.test(planId)) throw new Error(\"Experience plan id must be opaque.\");\n\t\t\tconst intents = new Map<string, ExperiencePlanState[\"intents\"] extends ReadonlyMap<string, infer Value> ? Value : never>();\n\t\t\tconst views = new Map<string, ExperiencePlanState[\"views\"] extends ReadonlyMap<string, infer Value> ? Value : never>();\n\t\t\tconst root = toRenderPlanFragment(selected.root, release, selected.treeId, intents, views);\n\t\t\tconst publicPlan: ScopedRenderPlan = Object.freeze({\n\t\t\t\tformatVersion: 1,\n\t\t\t\tplanId,\n\t\t\t\tapplication: input.application,\n\t\t\t\tchannel: input.channel,\n\t\t\t\treleaseDigest: release.releaseDigest,\n\t\t\t\tassemblyDigest: release.assemblyDigest,\n\t\t\t\ttreeId: selected.treeId,\n\t\t\t\troot,\n\t\t\t\ttokenSet: { name: release.tokenSet.name, version: release.tokenSet.version },\n\t\t\t\texpiresAt: new Date(now().getTime() + (input.ttlMs ?? 300_000)).toISOString(),\n\t\t\t});\n\t\t\tif (JSON.stringify(publicPlan).includes(\"capability://\")) {\n\t\t\t\tthrow new Error(\"Public render plan exposes a capability reference.\");\n\t\t\t}\n\t\t\tawait options.store.save({ publicPlan, scope: { ...input.scope }, intents, views });\n\t\t\treturn publicPlan;\n\t\t},\n\t\tasync resolveIntent(input) {\n\t\t\tconst state = await options.store.load(input.planId);\n\t\t\tif (!state) throw new Error(\"Experience render plan was not found.\");\n\t\t\tif (Date.parse(state.publicPlan.expiresAt) <= now().getTime()) throw new Error(\"Experience render plan has expired.\");\n\t\t\tif (!sameScope(state.scope, input.scope)) throw new Error(\"Experience render plan scope does not match trusted request scope.\");\n\t\t\tconst intent = state.intents.get(`${input.fragmentId}\\u0000${input.eventName}`);\n\t\t\tif (!intent) throw new Error(`Fragment event \"${input.fragmentId}.${input.eventName}\" is not granted by the render plan.`);\n\t\t\treturn {\n\t\t\t\tactionId: intent.route.actionId,\n\t\t\t\tactionVersion: intent.route.version,\n\t\t\t\texecution: intent.route.execution,\n\t\t\t\tinitiatingReleaseDigest: state.publicPlan.releaseDigest,\n\t\t\t\tassemblyDigest: state.publicPlan.assemblyDigest,\n\t\t\t};\n\t\t},\n\t\tasync resolveView(input) {\n\t\t\tconst state = await loadPlan(options.store, input.planId, input.scope, now());\n\t\t\tconst view = state.views.get(`${input.fragmentId}\\u0000${input.bindingName}`);\n\t\t\tif (!view) throw new Error(`Fragment binding \"${input.fragmentId}.${input.bindingName}\" is not granted by the render plan.`);\n\t\t\treturn {\n\t\t\t\tname: view.route.name,\n\t\t\t\tversion: view.route.version,\n\t\t\t\tinitiatingReleaseDigest: state.publicPlan.releaseDigest,\n\t\t\t\tassemblyDigest: state.publicPlan.assemblyDigest,\n\t\t\t};\n\t\t},\n\t};\n}\n\nfunction selectTree(release: SduiReleaseV3, variantId?: string): { treeId: string; root: SduiFragment } {\n\tif (variantId === undefined) return { treeId: \"root\", root: release.document.root };\n\tconst variant = release.document.variants?.find((candidate) => candidate.id === variantId);\n\tif (!variant) throw new Error(`Variant \"${variantId}\" is not enumerated by the promoted release.`);\n\treturn { treeId: variant.id, root: variant.root };\n}\n\nfunction toRenderPlanFragment(\n\tfragment: SduiFragment,\n\trelease: SduiReleaseV3,\n\ttreeId: string,\n\tintents: Map<string, { fragmentId: string; eventName: string; route: ExperienceIntentRoute }>,\n\tviews: Map<string, { fragmentId: string; bindingName: string; route: ExperienceViewRoute }>,\n): RenderPlanFragment {\n\tconst effective = release.effectiveGrants.find((grant) => grant.treeId === treeId && grant.fragmentId === fragment.id);\n\tif (!effective) throw new Error(`Promoted release has no effective grant for \"${treeId}:${fragment.id}\".`);\n\tconst events: string[] = [];\n\tconst offlineEvents: string[] = [];\n\tconst bindings: string[] = [];\n\tif (fragment.dataRef !== undefined) {\n\t\tif (!effective.views.includes(fragment.dataRef)) throw new Error(`Fragment data binding \"${fragment.id}\" exceeds its effective grants.`);\n\t\tconst route = release.routes.views.find((candidate) => candidate.reference === fragment.dataRef);\n\t\tif (!route) throw new Error(`Fragment data binding \"${fragment.id}\" has no compiled view route.`);\n\t\tviews.set(`${fragment.id}\\u0000$data`, { fragmentId: fragment.id, bindingName: \"$data\", route });\n\t\tbindings.push(\"$data\");\n\t}\n\tfor (const [eventName, action] of Object.entries(fragment.actions ?? {})) {\n\t\tif (!effective.intents.includes(action.intent)) throw new Error(`Fragment event \"${fragment.id}.${eventName}\" exceeds its effective grants.`);\n\t\tconst route = release.routes.intents.find((candidate) => candidate.reference === action.intent);\n\t\tif (!route) throw new Error(`Fragment event \"${fragment.id}.${eventName}\" has no compiled intent route.`);\n\t\tintents.set(`${fragment.id}\\u0000${eventName}`, { fragmentId: fragment.id, eventName, route });\n\t\tevents.push(eventName);\n\t\tif (route.execution?.connectivity === \"offline-capturable\") offlineEvents.push(eventName);\n\t}\n\treturn Object.freeze({\n\t\tid: fragment.id,\n\t\t...(fragment.component === undefined ? {} : { component: fragment.component }),\n\t\t...(fragment.props === undefined ? {} : { props: stripCapabilityReferences(fragment.props) }),\n\t\t...(fragment.slot === undefined ? {} : { slot: fragment.slot }),\n\t\t...(events.length === 0 ? {} : { events: Object.freeze(events.sort()) }),\n\t\t...(offlineEvents.length === 0 ? {} : { offlineEvents: Object.freeze(offlineEvents.sort()) }),\n\t\t...(bindings.length === 0 ? {} : { bindings: Object.freeze(bindings) }),\n\t\t...(fragment.children === undefined ? {} : {\n\t\t\tchildren: Object.freeze(fragment.children.map((child) => toRenderPlanFragment(child, release, treeId, intents, views))),\n\t\t}),\n\t});\n}\n\nasync function loadPlan(\n\tstore: ExperiencePlanStore,\n\tplanId: string,\n\tscope: ExperienceScope,\n\tnow: Date,\n): Promise<ExperiencePlanState> {\n\tconst state = await store.load(planId);\n\tif (!state) throw new Error(\"Experience render plan was not found.\");\n\tif (Date.parse(state.publicPlan.expiresAt) <= now.getTime()) throw new Error(\"Experience render plan has expired.\");\n\tif (!sameScope(state.scope, scope)) throw new Error(\"Experience render plan scope does not match trusted request scope.\");\n\treturn state;\n}\n\nfunction stripCapabilityReferences(value: Record<string, SduiFragmentValue>): Record<string, unknown> {\n\tconst strip = (candidate: SduiFragmentValue): unknown => {\n\t\tif (Array.isArray(candidate)) return candidate.map(strip);\n\t\tif (candidate && typeof candidate === \"object\") {\n\t\t\tif (\"$ref\" in candidate) return undefined;\n\t\t\treturn Object.fromEntries(Object.entries(candidate).flatMap(([key, entry]) => {\n\t\t\t\tconst stripped = strip(entry);\n\t\t\t\treturn stripped === undefined ? [] : [[key, stripped]];\n\t\t\t}));\n\t\t}\n\t\treturn candidate;\n\t};\n\treturn strip(value) as Record<string, unknown>;\n}\n\nfunction sameScope(left: ExperienceScope, right: ExperienceScope): boolean {\n\treturn left.tenantId === right.tenantId\n\t\t&& left.spaceId === right.spaceId\n\t\t&& left.actorId === right.actorId\n\t\t&& left.actorType === right.actorType;\n}\n\nexport function createMemoryExperiencePlanStore(): ExperiencePlanStore {\n\tconst plans = new Map<string, ExperiencePlanState>();\n\treturn {\n\t\tasync save(state) {\n\t\t\tif (plans.has(state.publicPlan.planId)) throw new Error(`Experience render plan \"${state.publicPlan.planId}\" already exists.`);\n\t\t\tplans.set(state.publicPlan.planId, state);\n\t\t},\n\t\tasync load(planId) {\n\t\t\treturn plans.get(planId) ?? null;\n\t\t},\n\t};\n}\n"],"mappings":";;;AAmGA,SAAgB,yBAA2D;CAC1E,OAAO;EACN;GACC,IAAI;GACJ,MAAM,IAAI,SAAS;IAClB,MAAM,OAAO,MAAM,QAAQ,QAAQ,UAAU,QAAQ,KAAK;IAE1D,IADmB,KAAK,UAAU,IACrB,CAAC,CAAC,SAAS,eAAe,GAAG,MAAM,IAAI,MAAM,oDAAoD;IAC9G,OAAO,CAAC,KAAK,MAAM;GACpB;EACD;EACA;GACC,IAAI;GACJ,MAAM,IAAI,SAAS;IAClB,MAAM,OAAO,MAAM,QAAQ,QAAQ,UAAU,QAAQ,KAAK;IAC1D,IAAI;KACH,MAAM,QAAQ,QAAQ,cAAc;MACnC,QAAQ,KAAK;MACb,GAAG,QAAQ;MACX,OAAO,QAAQ;KAChB,CAAC;KACD,MAAM,IAAI,MAAM,0DAA0D;IAC3E,SAAS,OAAO;KACf,IAAI,iBAAiB,SAAS,MAAM,YAAY,4DAA4D,MAAM;IACnH;IACA,OAAO,CAAC,sBAAsB;GAC/B;EACD;EACA;GACC,IAAI;GACJ,MAAM,IAAI,SAAS;IAClB,MAAM,OAAO,MAAM,QAAQ,QAAQ,UAAU,QAAQ,KAAK;IAC1D,MAAM,WAAW,MAAM,QAAQ,QAAQ,cAAc;KACpD,QAAQ,KAAK;KACb,GAAG,QAAQ;KACX,OAAO,QAAQ,MAAM;IACtB,CAAC;IACD,OAAO,CAAC,GAAG,SAAS,SAAS,GAAG,SAAS,eAAe;GACzD;EACD;CACD;AACD;AAEA,eAAsB,0BACrB,SACA,SAA2C,uBAAuB,GAIhE;CACF,MAAM,UAAuH,CAAC;CAC9H,KAAK,MAAM,SAAS,QACnB,IAAI;EACH,QAAQ,KAAK;GAAE,IAAI,MAAM;GAAI,QAAQ;GAAU,UAAU,MAAM,MAAM,IAAI,OAAO;EAAE,CAAC;CACpF,SAAS,OAAO;EACf,QAAQ,KAAK;GAAE,IAAI,MAAM;GAAI,QAAQ;GAAU,UAAU,CAAC;GAAG,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EAAE,CAAC;CAC7H;CAED,OAAO;EAAE,QAAQ,QAAQ,OAAO,WAAW,OAAO,WAAW,QAAQ;EAAG,QAAQ;CAAQ;AACzF;AAEA,SAAgB,8BAA8B,SAYlB;CAC3B,MAAM,MAAM,QAAQ,8BAAc,IAAI,KAAK;CAC3C,OAAO;EACN,MAAM,UAAU,OAAO;GACtB,MAAM,WAAW,MAAM,QAAQ,eAAe;IAAE,aAAa,MAAM;IAAa,SAAS,MAAM;GAAQ,CAAC;GACxG,MAAM,UAAU,OAAA,GAAMA,kCAAAA,8BAAAA,CAA8B;IACnD,YAAY,SAAS;IACrB,QAAQ,QAAQ;IAChB,OAAO,QAAQ;IACf,aAAa,QAAQ;IACrB,UAAU;KAAE,QAAQ,QAAQ;KAAQ,aAAa,MAAM;KAAa,SAAS,MAAM;IAAQ;IAC3F,KAAK,IAAI;GACV,CAAC;GACD,MAAM,UAAU,OAAA,GAAMC,kCAAAA,8BAAAA,CAA8B;IACnD,YAAY,SAAS;IACrB,QAAQ,QAAQ;IAChB,OAAO,QAAQ;IACf,UAAU;KACT,QAAQ,QAAQ;KAChB,aAAa,MAAM;KACnB,gBAAgB,QAAQ;IACzB;GACD,CAAC;GACD,IAAI,QAAQ,kBAAkB,QAAQ,qBACrC,MAAM,IAAI,MAAM,gFAAgF;GAEjG,MAAM,WAAW,WAAW,SAAS,MAAM,SAAS;GACpD,MAAM,SAAS,QAAQ,aAAa;GACpC,IAAI,CAAC,UAAU,kBAAkB,KAAK,MAAM,GAAG,MAAM,IAAI,MAAM,oCAAoC;GACnG,MAAM,0BAAU,IAAI,IAAqG;GACzH,MAAM,wBAAQ,IAAI,IAAmG;GACrH,MAAM,OAAO,qBAAqB,SAAS,MAAM,SAAS,SAAS,QAAQ,SAAS,KAAK;GACzF,MAAM,aAA+B,OAAO,OAAO;IAClD,eAAe;IACf;IACA,aAAa,MAAM;IACnB,SAAS,MAAM;IACf,eAAe,QAAQ;IACvB,gBAAgB,QAAQ;IACxB,QAAQ,SAAS;IACjB;IACA,UAAU;KAAE,MAAM,QAAQ,SAAS;KAAM,SAAS,QAAQ,SAAS;IAAQ;IAC3E,WAAW,IAAI,KAAK,IAAI,CAAC,CAAC,QAAQ,KAAK,MAAM,SAAS,IAAQ,CAAC,CAAC,YAAY;GAC7E,CAAC;GACD,IAAI,KAAK,UAAU,UAAU,CAAC,CAAC,SAAS,eAAe,GACtD,MAAM,IAAI,MAAM,oDAAoD;GAErE,MAAM,QAAQ,MAAM,KAAK;IAAE;IAAY,OAAO,EAAE,GAAG,MAAM,MAAM;IAAG;IAAS;GAAM,CAAC;GAClF,OAAO;EACR;EACA,MAAM,cAAc,OAAO;GAC1B,MAAM,QAAQ,MAAM,QAAQ,MAAM,KAAK,MAAM,MAAM;GACnD,IAAI,CAAC,OAAO,MAAM,IAAI,MAAM,uCAAuC;GACnE,IAAI,KAAK,MAAM,MAAM,WAAW,SAAS,KAAK,IAAI,CAAC,CAAC,QAAQ,GAAG,MAAM,IAAI,MAAM,qCAAqC;GACpH,IAAI,CAAC,UAAU,MAAM,OAAO,MAAM,KAAK,GAAG,MAAM,IAAI,MAAM,oEAAoE;GAC9H,MAAM,SAAS,MAAM,QAAQ,IAAI,GAAG,MAAM,WAAW,QAAQ,MAAM,WAAW;GAC9E,IAAI,CAAC,QAAQ,MAAM,IAAI,MAAM,mBAAmB,MAAM,WAAW,GAAG,MAAM,UAAU,qCAAqC;GACzH,OAAO;IACN,UAAU,OAAO,MAAM;IACvB,eAAe,OAAO,MAAM;IAC5B,WAAW,OAAO,MAAM;IACxB,yBAAyB,MAAM,WAAW;IAC1C,gBAAgB,MAAM,WAAW;GAClC;EACD;EACA,MAAM,YAAY,OAAO;GACxB,MAAM,QAAQ,MAAM,SAAS,QAAQ,OAAO,MAAM,QAAQ,MAAM,OAAO,IAAI,CAAC;GAC5E,MAAM,OAAO,MAAM,MAAM,IAAI,GAAG,MAAM,WAAW,QAAQ,MAAM,aAAa;GAC5E,IAAI,CAAC,MAAM,MAAM,IAAI,MAAM,qBAAqB,MAAM,WAAW,GAAG,MAAM,YAAY,qCAAqC;GAC3H,OAAO;IACN,MAAM,KAAK,MAAM;IACjB,SAAS,KAAK,MAAM;IACpB,yBAAyB,MAAM,WAAW;IAC1C,gBAAgB,MAAM,WAAW;GAClC;EACD;CACD;AACD;AAEA,SAAS,WAAW,SAAwB,WAA4D;CACvG,IAAI,cAAc,KAAA,GAAW,OAAO;EAAE,QAAQ;EAAQ,MAAM,QAAQ,SAAS;CAAK;CAClF,MAAM,UAAU,QAAQ,SAAS,UAAU,MAAM,cAAc,UAAU,OAAO,SAAS;CACzF,IAAI,CAAC,SAAS,MAAM,IAAI,MAAM,YAAY,UAAU,6CAA6C;CACjG,OAAO;EAAE,QAAQ,QAAQ;EAAI,MAAM,QAAQ;CAAK;AACjD;AAEA,SAAS,qBACR,UACA,SACA,QACA,SACA,OACqB;CACrB,MAAM,YAAY,QAAQ,gBAAgB,MAAM,UAAU,MAAM,WAAW,UAAU,MAAM,eAAe,SAAS,EAAE;CACrH,IAAI,CAAC,WAAW,MAAM,IAAI,MAAM,gDAAgD,OAAO,GAAG,SAAS,GAAG,GAAG;CACzG,MAAM,SAAmB,CAAC;CAC1B,MAAM,gBAA0B,CAAC;CACjC,MAAM,WAAqB,CAAC;CAC5B,IAAI,SAAS,YAAY,KAAA,GAAW;EACnC,IAAI,CAAC,UAAU,MAAM,SAAS,SAAS,OAAO,GAAG,MAAM,IAAI,MAAM,0BAA0B,SAAS,GAAG,gCAAgC;EACvI,MAAM,QAAQ,QAAQ,OAAO,MAAM,MAAM,cAAc,UAAU,cAAc,SAAS,OAAO;EAC/F,IAAI,CAAC,OAAO,MAAM,IAAI,MAAM,0BAA0B,SAAS,GAAG,8BAA8B;EAChG,MAAM,IAAI,GAAG,SAAS,GAAG,cAAc;GAAE,YAAY,SAAS;GAAI,aAAa;GAAS;EAAM,CAAC;EAC/F,SAAS,KAAK,OAAO;CACtB;CACA,KAAK,MAAM,CAAC,WAAW,WAAW,OAAO,QAAQ,SAAS,WAAW,CAAC,CAAC,GAAG;EACzE,IAAI,CAAC,UAAU,QAAQ,SAAS,OAAO,MAAM,GAAG,MAAM,IAAI,MAAM,mBAAmB,SAAS,GAAG,GAAG,UAAU,gCAAgC;EAC5I,MAAM,QAAQ,QAAQ,OAAO,QAAQ,MAAM,cAAc,UAAU,cAAc,OAAO,MAAM;EAC9F,IAAI,CAAC,OAAO,MAAM,IAAI,MAAM,mBAAmB,SAAS,GAAG,GAAG,UAAU,gCAAgC;EACxG,QAAQ,IAAI,GAAG,SAAS,GAAG,QAAQ,aAAa;GAAE,YAAY,SAAS;GAAI;GAAW;EAAM,CAAC;EAC7F,OAAO,KAAK,SAAS;EACrB,IAAI,MAAM,WAAW,iBAAiB,sBAAsB,cAAc,KAAK,SAAS;CACzF;CACA,OAAO,OAAO,OAAO;EACpB,IAAI,SAAS;EACb,GAAI,SAAS,cAAc,KAAA,IAAY,CAAC,IAAI,EAAE,WAAW,SAAS,UAAU;EAC5E,GAAI,SAAS,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO,0BAA0B,SAAS,KAAK,EAAE;EAC3F,GAAI,SAAS,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,MAAM,SAAS,KAAK;EAC7D,GAAI,OAAO,WAAW,IAAI,CAAC,IAAI,EAAE,QAAQ,OAAO,OAAO,OAAO,KAAK,CAAC,EAAE;EACtE,GAAI,cAAc,WAAW,IAAI,CAAC,IAAI,EAAE,eAAe,OAAO,OAAO,cAAc,KAAK,CAAC,EAAE;EAC3F,GAAI,SAAS,WAAW,IAAI,CAAC,IAAI,EAAE,UAAU,OAAO,OAAO,QAAQ,EAAE;EACrE,GAAI,SAAS,aAAa,KAAA,IAAY,CAAC,IAAI,EAC1C,UAAU,OAAO,OAAO,SAAS,SAAS,KAAK,UAAU,qBAAqB,OAAO,SAAS,QAAQ,SAAS,KAAK,CAAC,CAAC,EACvH;CACD,CAAC;AACF;AAEA,eAAe,SACd,OACA,QACA,OACA,KAC+B;CAC/B,MAAM,QAAQ,MAAM,MAAM,KAAK,MAAM;CACrC,IAAI,CAAC,OAAO,MAAM,IAAI,MAAM,uCAAuC;CACnE,IAAI,KAAK,MAAM,MAAM,WAAW,SAAS,KAAK,IAAI,QAAQ,GAAG,MAAM,IAAI,MAAM,qCAAqC;CAClH,IAAI,CAAC,UAAU,MAAM,OAAO,KAAK,GAAG,MAAM,IAAI,MAAM,oEAAoE;CACxH,OAAO;AACR;AAEA,SAAS,0BAA0B,OAAmE;CACrG,MAAM,SAAS,cAA0C;EACxD,IAAI,MAAM,QAAQ,SAAS,GAAG,OAAO,UAAU,IAAI,KAAK;EACxD,IAAI,aAAa,OAAO,cAAc,UAAU;GAC/C,IAAI,UAAU,WAAW,OAAO,KAAA;GAChC,OAAO,OAAO,YAAY,OAAO,QAAQ,SAAS,CAAC,CAAC,SAAS,CAAC,KAAK,WAAW;IAC7E,MAAM,WAAW,MAAM,KAAK;IAC5B,OAAO,aAAa,KAAA,IAAY,CAAC,IAAI,CAAC,CAAC,KAAK,QAAQ,CAAC;GACtD,CAAC,CAAC;EACH;EACA,OAAO;CACR;CACA,OAAO,MAAM,KAAK;AACnB;AAEA,SAAS,UAAU,MAAuB,OAAiC;CAC1E,OAAO,KAAK,aAAa,MAAM,YAC3B,KAAK,YAAY,MAAM,WACvB,KAAK,YAAY,MAAM,WACvB,KAAK,cAAc,MAAM;AAC9B;AAEA,SAAgB,kCAAuD;CACtE,MAAM,wBAAQ,IAAI,IAAiC;CACnD,OAAO;EACN,MAAM,KAAK,OAAO;GACjB,IAAI,MAAM,IAAI,MAAM,WAAW,MAAM,GAAG,MAAM,IAAI,MAAM,2BAA2B,MAAM,WAAW,OAAO,kBAAkB;GAC7H,MAAM,IAAI,MAAM,WAAW,QAAQ,KAAK;EACzC;EACA,MAAM,KAAK,QAAQ;GAClB,OAAO,MAAM,IAAI,MAAM,KAAK;EAC7B;CACD;AACD"}
|
package/dist/server.d.cts
CHANGED
|
@@ -1,100 +1,99 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}>;
|
|
1
|
+
import { ExperienceScope, RenderPlanFragment, ScopedRenderPlan } from "./contracts.cjs";
|
|
2
|
+
import { ExperienceIntentRoute, ExperienceViewRoute, ReleaseCryptoPort, ReleaseGenerationStore, ReleaseTrustStore } from "@fabricorg/sdui-release/contracts";
|
|
3
|
+
//#region server.d.ts
|
|
4
|
+
export interface ExperiencePlanState {
|
|
5
|
+
publicPlan: ScopedRenderPlan;
|
|
6
|
+
scope: ExperienceScope;
|
|
7
|
+
intents: ReadonlyMap<string, {
|
|
8
|
+
fragmentId: string;
|
|
9
|
+
eventName: string;
|
|
10
|
+
route: ExperienceIntentRoute;
|
|
11
|
+
}>;
|
|
12
|
+
views: ReadonlyMap<string, {
|
|
13
|
+
fragmentId: string;
|
|
14
|
+
bindingName: string;
|
|
15
|
+
route: ExperienceViewRoute;
|
|
16
|
+
}>;
|
|
18
17
|
}
|
|
19
|
-
interface ExperiencePlanStore {
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
export interface ExperiencePlanStore {
|
|
19
|
+
save(state: ExperiencePlanState): Promise<void>;
|
|
20
|
+
load(planId: string): Promise<ExperiencePlanState | null>;
|
|
22
21
|
}
|
|
23
|
-
interface IssueRenderPlanInput {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
export interface IssueRenderPlanInput {
|
|
23
|
+
application: string;
|
|
24
|
+
channel: string;
|
|
25
|
+
scope: ExperienceScope;
|
|
26
|
+
variantId?: string;
|
|
27
|
+
ttlMs?: number;
|
|
29
28
|
}
|
|
30
|
-
interface ResolveIntentInput {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
29
|
+
export interface ResolveIntentInput {
|
|
30
|
+
planId: string;
|
|
31
|
+
fragmentId: string;
|
|
32
|
+
eventName: string;
|
|
33
|
+
scope: ExperienceScope;
|
|
35
34
|
}
|
|
36
|
-
interface ResolvedExperienceIntent {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
35
|
+
export interface ResolvedExperienceIntent {
|
|
36
|
+
actionId: `${string}.${string}`;
|
|
37
|
+
actionVersion: number;
|
|
38
|
+
execution: ExperienceIntentRoute["execution"];
|
|
39
|
+
initiatingReleaseDigest: string;
|
|
40
|
+
assemblyDigest: string;
|
|
42
41
|
}
|
|
43
|
-
interface ResolvedExperienceView {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
42
|
+
export interface ResolvedExperienceView {
|
|
43
|
+
name: `${string}/${string}`;
|
|
44
|
+
version: string;
|
|
45
|
+
initiatingReleaseDigest: string;
|
|
46
|
+
assemblyDigest: string;
|
|
48
47
|
}
|
|
49
|
-
interface ExperienceServerRuntime {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
48
|
+
export interface ExperienceServerRuntime {
|
|
49
|
+
issuePlan(input: IssueRenderPlanInput): Promise<ScopedRenderPlan>;
|
|
50
|
+
resolveIntent(input: ResolveIntentInput): Promise<ResolvedExperienceIntent>;
|
|
51
|
+
resolveView(input: {
|
|
52
|
+
planId: string;
|
|
53
|
+
fragmentId: string;
|
|
54
|
+
bindingName: string;
|
|
55
|
+
scope: ExperienceScope;
|
|
56
|
+
}): Promise<ResolvedExperienceView>;
|
|
58
57
|
}
|
|
59
|
-
interface ExperienceServerConformanceSubject {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
58
|
+
export interface ExperienceServerConformanceSubject {
|
|
59
|
+
runtime: ExperienceServerRuntime;
|
|
60
|
+
issue: IssueRenderPlanInput;
|
|
61
|
+
intent: {
|
|
62
|
+
fragmentId: string;
|
|
63
|
+
eventName: string;
|
|
64
|
+
};
|
|
65
|
+
wrongScope: ExperienceScope;
|
|
67
66
|
}
|
|
68
|
-
interface ExperienceServerCheck {
|
|
69
|
-
|
|
70
|
-
|
|
67
|
+
export interface ExperienceServerCheck {
|
|
68
|
+
id: "fabric.experience.plan-opaque.v1" | "fabric.experience.scope-isolation.v1" | "fabric.experience.intent-resolution.v1";
|
|
69
|
+
run(subject: ExperienceServerConformanceSubject): Promise<string[]>;
|
|
71
70
|
}
|
|
72
|
-
declare function experienceServerChecks(): readonly ExperienceServerCheck[];
|
|
73
|
-
declare function runExperienceServerChecks(subject: ExperienceServerConformanceSubject, checks?: readonly ExperienceServerCheck[]): Promise<{
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
71
|
+
export declare function experienceServerChecks(): readonly ExperienceServerCheck[];
|
|
72
|
+
export declare function runExperienceServerChecks(subject: ExperienceServerConformanceSubject, checks?: readonly ExperienceServerCheck[]): Promise<{
|
|
73
|
+
passed: boolean;
|
|
74
|
+
checks: Array<{
|
|
75
|
+
id: ExperienceServerCheck["id"];
|
|
76
|
+
status: "passed" | "failed";
|
|
77
|
+
evidence: string[];
|
|
78
|
+
error?: string;
|
|
79
|
+
}>;
|
|
81
80
|
}>;
|
|
82
|
-
declare function createExperienceServerRuntime(options: {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
81
|
+
export declare function createExperienceServerRuntime(options: {
|
|
82
|
+
store: ExperiencePlanStore;
|
|
83
|
+
resolveChannel(input: {
|
|
84
|
+
application: string;
|
|
85
|
+
channel: string;
|
|
86
|
+
}): Promise<{
|
|
87
|
+
pointerJws: string;
|
|
88
|
+
releaseJws: string;
|
|
89
|
+
}>;
|
|
90
|
+
issuer: string;
|
|
91
|
+
crypto: ReleaseCryptoPort;
|
|
92
|
+
trust: ReleaseTrustStore;
|
|
93
|
+
generations: ReleaseGenerationStore;
|
|
94
|
+
nextOpaqueId(): string;
|
|
95
|
+
now?: () => Date;
|
|
97
96
|
}): ExperienceServerRuntime;
|
|
98
|
-
declare function createMemoryExperiencePlanStore(): ExperiencePlanStore;
|
|
99
|
-
|
|
100
|
-
export
|
|
97
|
+
export declare function createMemoryExperiencePlanStore(): ExperiencePlanStore;
|
|
98
|
+
//#endregion
|
|
99
|
+
export type { ExperienceScope, RenderPlanFragment, ScopedRenderPlan };
|
package/dist/server.d.ts
CHANGED
|
@@ -1,100 +1,99 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}>;
|
|
1
|
+
import { ExperienceScope, RenderPlanFragment, ScopedRenderPlan } from "./contracts.js";
|
|
2
|
+
import { ExperienceIntentRoute, ExperienceViewRoute, ReleaseCryptoPort, ReleaseGenerationStore, ReleaseTrustStore } from "@fabricorg/sdui-release/contracts";
|
|
3
|
+
//#region server.d.ts
|
|
4
|
+
export interface ExperiencePlanState {
|
|
5
|
+
publicPlan: ScopedRenderPlan;
|
|
6
|
+
scope: ExperienceScope;
|
|
7
|
+
intents: ReadonlyMap<string, {
|
|
8
|
+
fragmentId: string;
|
|
9
|
+
eventName: string;
|
|
10
|
+
route: ExperienceIntentRoute;
|
|
11
|
+
}>;
|
|
12
|
+
views: ReadonlyMap<string, {
|
|
13
|
+
fragmentId: string;
|
|
14
|
+
bindingName: string;
|
|
15
|
+
route: ExperienceViewRoute;
|
|
16
|
+
}>;
|
|
18
17
|
}
|
|
19
|
-
interface ExperiencePlanStore {
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
export interface ExperiencePlanStore {
|
|
19
|
+
save(state: ExperiencePlanState): Promise<void>;
|
|
20
|
+
load(planId: string): Promise<ExperiencePlanState | null>;
|
|
22
21
|
}
|
|
23
|
-
interface IssueRenderPlanInput {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
export interface IssueRenderPlanInput {
|
|
23
|
+
application: string;
|
|
24
|
+
channel: string;
|
|
25
|
+
scope: ExperienceScope;
|
|
26
|
+
variantId?: string;
|
|
27
|
+
ttlMs?: number;
|
|
29
28
|
}
|
|
30
|
-
interface ResolveIntentInput {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
29
|
+
export interface ResolveIntentInput {
|
|
30
|
+
planId: string;
|
|
31
|
+
fragmentId: string;
|
|
32
|
+
eventName: string;
|
|
33
|
+
scope: ExperienceScope;
|
|
35
34
|
}
|
|
36
|
-
interface ResolvedExperienceIntent {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
35
|
+
export interface ResolvedExperienceIntent {
|
|
36
|
+
actionId: `${string}.${string}`;
|
|
37
|
+
actionVersion: number;
|
|
38
|
+
execution: ExperienceIntentRoute["execution"];
|
|
39
|
+
initiatingReleaseDigest: string;
|
|
40
|
+
assemblyDigest: string;
|
|
42
41
|
}
|
|
43
|
-
interface ResolvedExperienceView {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
42
|
+
export interface ResolvedExperienceView {
|
|
43
|
+
name: `${string}/${string}`;
|
|
44
|
+
version: string;
|
|
45
|
+
initiatingReleaseDigest: string;
|
|
46
|
+
assemblyDigest: string;
|
|
48
47
|
}
|
|
49
|
-
interface ExperienceServerRuntime {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
48
|
+
export interface ExperienceServerRuntime {
|
|
49
|
+
issuePlan(input: IssueRenderPlanInput): Promise<ScopedRenderPlan>;
|
|
50
|
+
resolveIntent(input: ResolveIntentInput): Promise<ResolvedExperienceIntent>;
|
|
51
|
+
resolveView(input: {
|
|
52
|
+
planId: string;
|
|
53
|
+
fragmentId: string;
|
|
54
|
+
bindingName: string;
|
|
55
|
+
scope: ExperienceScope;
|
|
56
|
+
}): Promise<ResolvedExperienceView>;
|
|
58
57
|
}
|
|
59
|
-
interface ExperienceServerConformanceSubject {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
58
|
+
export interface ExperienceServerConformanceSubject {
|
|
59
|
+
runtime: ExperienceServerRuntime;
|
|
60
|
+
issue: IssueRenderPlanInput;
|
|
61
|
+
intent: {
|
|
62
|
+
fragmentId: string;
|
|
63
|
+
eventName: string;
|
|
64
|
+
};
|
|
65
|
+
wrongScope: ExperienceScope;
|
|
67
66
|
}
|
|
68
|
-
interface ExperienceServerCheck {
|
|
69
|
-
|
|
70
|
-
|
|
67
|
+
export interface ExperienceServerCheck {
|
|
68
|
+
id: "fabric.experience.plan-opaque.v1" | "fabric.experience.scope-isolation.v1" | "fabric.experience.intent-resolution.v1";
|
|
69
|
+
run(subject: ExperienceServerConformanceSubject): Promise<string[]>;
|
|
71
70
|
}
|
|
72
|
-
declare function experienceServerChecks(): readonly ExperienceServerCheck[];
|
|
73
|
-
declare function runExperienceServerChecks(subject: ExperienceServerConformanceSubject, checks?: readonly ExperienceServerCheck[]): Promise<{
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
71
|
+
export declare function experienceServerChecks(): readonly ExperienceServerCheck[];
|
|
72
|
+
export declare function runExperienceServerChecks(subject: ExperienceServerConformanceSubject, checks?: readonly ExperienceServerCheck[]): Promise<{
|
|
73
|
+
passed: boolean;
|
|
74
|
+
checks: Array<{
|
|
75
|
+
id: ExperienceServerCheck["id"];
|
|
76
|
+
status: "passed" | "failed";
|
|
77
|
+
evidence: string[];
|
|
78
|
+
error?: string;
|
|
79
|
+
}>;
|
|
81
80
|
}>;
|
|
82
|
-
declare function createExperienceServerRuntime(options: {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
81
|
+
export declare function createExperienceServerRuntime(options: {
|
|
82
|
+
store: ExperiencePlanStore;
|
|
83
|
+
resolveChannel(input: {
|
|
84
|
+
application: string;
|
|
85
|
+
channel: string;
|
|
86
|
+
}): Promise<{
|
|
87
|
+
pointerJws: string;
|
|
88
|
+
releaseJws: string;
|
|
89
|
+
}>;
|
|
90
|
+
issuer: string;
|
|
91
|
+
crypto: ReleaseCryptoPort;
|
|
92
|
+
trust: ReleaseTrustStore;
|
|
93
|
+
generations: ReleaseGenerationStore;
|
|
94
|
+
nextOpaqueId(): string;
|
|
95
|
+
now?: () => Date;
|
|
97
96
|
}): ExperienceServerRuntime;
|
|
98
|
-
declare function createMemoryExperiencePlanStore(): ExperiencePlanStore;
|
|
99
|
-
|
|
100
|
-
export
|
|
97
|
+
export declare function createMemoryExperiencePlanStore(): ExperiencePlanStore;
|
|
98
|
+
//#endregion
|
|
99
|
+
export type { ExperienceScope, RenderPlanFragment, ScopedRenderPlan };
|