@dreamboard-games/sdk 0.4.0-alpha.6 → 0.4.0-alpha.7
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/REFERENCE.md +408 -8
- package/dist/authoring/index.d.ts +5 -4
- package/dist/authoring/index.js +3 -3
- package/dist/authoring/index.js.map +1 -1
- package/dist/{chunk-PAPIAMYX.js → chunk-3QIZKXJ2.js} +6 -4
- package/dist/{chunk-PAPIAMYX.js.map → chunk-3QIZKXJ2.js.map} +1 -1
- package/dist/chunk-5IHU5CUK.js +575 -0
- package/dist/chunk-5IHU5CUK.js.map +1 -0
- package/dist/chunk-IU6KGPY7.js +659 -0
- package/dist/chunk-IU6KGPY7.js.map +1 -0
- package/dist/{chunk-HK3WN4U7.js → chunk-KYEWGZ2Y.js} +2 -2
- package/dist/{chunk-HK3WN4U7.js.map → chunk-KYEWGZ2Y.js.map} +1 -1
- package/dist/{chunk-DDST4U2P.js → chunk-NO537WSS.js} +2 -2
- package/dist/{chunk-SOBNI363.js → chunk-Q322XCY2.js} +11 -6
- package/dist/{chunk-SOBNI363.js.map → chunk-Q322XCY2.js.map} +1 -1
- package/dist/{chunk-OV6JC2BM.js → chunk-RKGJ64UN.js} +19 -15
- package/dist/chunk-RKGJ64UN.js.map +1 -0
- package/dist/chunk-VLG4YST5.js +564 -0
- package/dist/chunk-VLG4YST5.js.map +1 -0
- package/dist/{stale-contract-artifact-error-BelRiIDR.d.ts → diagnostics-1BWjRo6-.d.ts} +1 -18
- package/dist/index.js +2 -2
- package/dist/package-set.d.ts +2 -2
- package/dist/package-set.js +2 -2
- package/dist/reducer.d.ts +3 -2
- package/dist/reducer.js +5 -5
- package/dist/reducer.js.map +1 -1
- package/dist/reference-games/index.d.ts +223 -0
- package/dist/reference-games/index.js +230 -0
- package/dist/reference-games/index.js.map +1 -0
- package/dist/runtime/primitives.js +4 -3
- package/dist/runtime/workspace-contract.js +5 -4
- package/dist/runtime.js +15 -205
- package/dist/runtime.js.map +1 -1
- package/dist/stale-contract-artifact-error-C5AaZPJ8.d.ts +18 -0
- package/dist/testing-runtime.d.ts +42 -0
- package/dist/testing-runtime.js +153 -0
- package/dist/testing-runtime.js.map +1 -0
- package/dist/testing.d.ts +5 -191
- package/dist/testing.js +22 -640
- package/dist/testing.js.map +1 -1
- package/dist/types-DcADVHe9.d.ts +192 -0
- package/package.json +13 -2
- package/dist/chunk-OV6JC2BM.js.map +0 -1
- package/dist/chunk-UUQNOGZV.js +0 -1266
- package/dist/chunk-UUQNOGZV.js.map +0 -1
- /package/dist/{chunk-DDST4U2P.js.map → chunk-NO537WSS.js.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/runtime/core/create-plugin-runtime-client.ts","../src/runtime/components/PluginRuntimeBoundary.tsx"],"sourcesContent":["import {\n HostToPluginEnvelopeSchema,\n RuntimeJsonSchema,\n type HostToPluginEnvelope,\n type PluginGameplayFrame,\n type PluginInteractionBasis,\n type PluginSessionDescriptor,\n type SubmissionResult,\n type ValidationResult,\n} from \"@dreamboard-games/plugin-runtime-contract\";\nimport type {\n PluginRuntimeClient,\n PluginRuntimeClientOptions,\n RuntimeClock,\n RuntimeIdFactory,\n} from \"./types.js\";\n\nconst defaultClock: RuntimeClock = {\n now: () => Date.now(),\n};\n\nconst defaultIdFactory: RuntimeIdFactory = {\n nextId: (prefix) => {\n const cryptoLike = (\n globalThis as typeof globalThis & {\n crypto?: { randomUUID?: () => string };\n }\n ).crypto;\n if (cryptoLike?.randomUUID) {\n try {\n return `${prefix}-${cryptoLike.randomUUID()}`;\n } catch {\n // Fall through to deterministic-enough fallback for older test DOMs.\n }\n }\n return `${prefix}-${Date.now().toString(16)}-${Math.random()\n .toString(16)\n .slice(2)}`;\n },\n};\n\nfunction createSubmissionError(\n result: Extract<SubmissionResult, { accepted: false }>,\n): Error & { errorCode?: string } {\n const error = new Error(result.message ?? \"Submission failed\") as Error & {\n errorCode?: string;\n };\n error.name = \"SubmissionError\";\n error.errorCode = result.errorCode;\n return error;\n}\n\nfunction disconnectedValidationResult(): ValidationResult {\n return {\n valid: false,\n errorCode: \"runtime-disconnected\",\n message: \"Plugin runtime disconnected\",\n };\n}\n\nexport function createPluginRuntimeClient(\n options: PluginRuntimeClientOptions,\n): PluginRuntimeClient {\n const clock = options.clock ?? defaultClock;\n const idFactory = options.idFactory ?? defaultIdFactory;\n const requestTimeoutMs = options.requestTimeoutMs ?? 10_000;\n let session: PluginSessionDescriptor | null = null;\n let frame: PluginGameplayFrame | null = null;\n let disconnected = false;\n let stopTransport: (() => void) | undefined;\n const sessionListeners = new Set<() => void>();\n const frameListeners = new Set<() => void>();\n const pendingValidations = new Map<\n string,\n (result: ValidationResult) => void\n >();\n const pendingSubmissions = new Map<\n string,\n {\n resolve: () => void;\n reject: (error: Error & { errorCode?: string }) => void;\n }\n >();\n\n const notifySession = () => {\n for (const listener of sessionListeners) {\n listener();\n }\n };\n\n const notifyFrame = () => {\n for (const listener of frameListeners) {\n listener();\n }\n };\n\n const currentBasis = (): PluginInteractionBasis => {\n if (!frame) {\n throw new Error(\"Plugin runtime has not received a gameplay frame.\");\n }\n return {\n gameVersion: frame.gameVersion,\n actionSetVersion: frame.actionSetVersion,\n perspectivePlayerId: frame.perspectivePlayerId,\n };\n };\n\n const sendRuntimeError = (message: string, code?: string) => {\n if (disconnected) {\n return;\n }\n options.transport.send({\n type: \"runtime.error\",\n message,\n ...(code ? { code } : {}),\n });\n };\n\n const handleHostMessage = (rawMessage: HostToPluginEnvelope) => {\n if (disconnected) {\n return;\n }\n const parseResult = HostToPluginEnvelopeSchema.safeParse(rawMessage);\n if (!parseResult.success) {\n sendRuntimeError(\n \"Invalid host-to-plugin protocol envelope.\",\n \"invalid-envelope\",\n );\n return;\n }\n const message = parseResult.data;\n const clientReceivedAtMs = clock.now();\n\n switch (message.payload.type) {\n case \"runtime.init\": {\n session = message.payload.session;\n notifySession();\n options.transport.send({ type: \"runtime.ready\" });\n options.transport.send({\n type: \"runtime.ack\",\n sequence: message.sequence,\n clientReceivedAtMs,\n });\n break;\n }\n case \"gameplay.frame\": {\n frame = message.payload.frame;\n notifyFrame();\n const sendRenderedAck = () => {\n if (disconnected) {\n return;\n }\n options.transport.send({\n type: \"runtime.ack\",\n sequence: message.sequence,\n clientReceivedAtMs,\n clientRenderedAtMs: clock.now(),\n });\n };\n if (typeof requestAnimationFrame === \"function\") {\n requestAnimationFrame(sendRenderedAck);\n } else {\n queueMicrotask(sendRenderedAck);\n }\n break;\n }\n case \"interaction.validation-result\": {\n const resolve = pendingValidations.get(message.payload.requestId);\n if (resolve) {\n pendingValidations.delete(message.payload.requestId);\n resolve(message.payload.result);\n }\n break;\n }\n case \"interaction.submit-result\": {\n const pending = pendingSubmissions.get(message.payload.requestId);\n if (!pending) {\n break;\n }\n pendingSubmissions.delete(message.payload.requestId);\n if (message.payload.result.accepted) {\n pending.resolve();\n } else {\n pending.reject(createSubmissionError(message.payload.result));\n }\n break;\n }\n default: {\n const _exhaustive: never = message.payload;\n return _exhaustive;\n }\n }\n };\n\n stopTransport = options.transport.start(handleHostMessage);\n\n const rejectPending = () => {\n for (const resolve of pendingValidations.values()) {\n resolve(disconnectedValidationResult());\n }\n pendingValidations.clear();\n for (const pending of pendingSubmissions.values()) {\n const error = new Error(\"Plugin runtime disconnected\") as Error & {\n errorCode?: string;\n };\n error.name = \"SubmissionError\";\n error.errorCode = \"runtime-disconnected\";\n pending.reject(error);\n }\n pendingSubmissions.clear();\n };\n\n return {\n getSession: () => session,\n subscribeSession: (listener) => {\n sessionListeners.add(listener);\n return () => {\n sessionListeners.delete(listener);\n };\n },\n getFrame: () => frame,\n subscribeFrame: (listener) => {\n frameListeners.add(listener);\n return () => {\n frameListeners.delete(listener);\n };\n },\n validateInteraction: async (interactionId, params) =>\n new Promise((resolve) => {\n if (disconnected) {\n resolve(disconnectedValidationResult());\n return;\n }\n let basis: PluginInteractionBasis;\n try {\n basis = currentBasis();\n } catch (error) {\n resolve({\n valid: false,\n errorCode: \"runtime-not-ready\",\n message:\n error instanceof Error\n ? error.message\n : \"Plugin runtime is not ready.\",\n });\n return;\n }\n const parsedParams = RuntimeJsonSchema.safeParse(params);\n if (!parsedParams.success) {\n resolve({\n valid: false,\n errorCode: \"invalid-runtime-json\",\n message: \"Interaction params must be runtime JSON.\",\n });\n return;\n }\n const requestId = idFactory.nextId(\"validate\");\n pendingValidations.set(requestId, resolve);\n options.transport.send({\n type: \"interaction.validate\",\n requestId,\n basis,\n interactionId,\n params: parsedParams.data,\n });\n setTimeout(() => {\n if (!pendingValidations.delete(requestId)) {\n return;\n }\n resolve({\n valid: false,\n errorCode: \"validation-timeout\",\n message: \"Validation request timed out\",\n });\n }, requestTimeoutMs);\n }),\n submitInteraction: async (interactionId, params) =>\n new Promise((resolve, reject) => {\n if (disconnected) {\n const error = new Error(\"Plugin runtime disconnected\") as Error & {\n errorCode?: string;\n };\n error.name = \"SubmissionError\";\n error.errorCode = \"runtime-disconnected\";\n reject(error);\n return;\n }\n const parsedParams = RuntimeJsonSchema.safeParse(params);\n if (!parsedParams.success) {\n const error = new Error(\n \"Interaction params must be runtime JSON.\",\n ) as Error & { errorCode?: string };\n error.name = \"SubmissionError\";\n error.errorCode = \"invalid-runtime-json\";\n reject(error);\n return;\n }\n let basis: PluginInteractionBasis;\n try {\n basis = currentBasis();\n } catch (error) {\n const submissionError = new Error(\n error instanceof Error\n ? error.message\n : \"Plugin runtime is not ready.\",\n ) as Error & { errorCode?: string };\n submissionError.name = \"SubmissionError\";\n submissionError.errorCode = \"runtime-not-ready\";\n reject(submissionError);\n return;\n }\n const requestId = idFactory.nextId(\"submit\");\n pendingSubmissions.set(requestId, { resolve, reject });\n options.transport.send({\n type: \"interaction.submit\",\n requestId,\n basis,\n interactionId,\n params: parsedParams.data,\n });\n setTimeout(() => {\n const pending = pendingSubmissions.get(requestId);\n if (!pending) {\n return;\n }\n pendingSubmissions.delete(requestId);\n const error = new Error(\"Submission request timed out\") as Error & {\n errorCode?: string;\n };\n error.name = \"SubmissionError\";\n error.errorCode = \"submission-timeout\";\n pending.reject(error);\n }, requestTimeoutMs);\n }),\n disconnect: () => {\n disconnected = true;\n stopTransport?.();\n stopTransport = undefined;\n sessionListeners.clear();\n frameListeners.clear();\n rejectPending();\n session = null;\n frame = null;\n },\n };\n}\n","import React, { useMemo } from \"react\";\nimport { InteractionUiProvider } from \"../context/InteractionDraftContext.js\";\nimport {\n PluginSessionProvider,\n usePluginSession,\n} from \"../context/PluginSessionContext.js\";\nimport { PluginGameplayFrameProvider } from \"../context/PluginGameplayFrameContext.js\";\nimport { RuntimeContext } from \"../context/RuntimeContext.js\";\nimport type { PluginRuntimeClient } from \"../core/types.js\";\nimport type { RuntimeAPI } from \"../types/runtime-api.js\";\n\nfunction runtimeApiFromClient(runtime: PluginRuntimeClient): RuntimeAPI {\n return {\n validateInteraction: (interactionId, params) =>\n runtime.validateInteraction(interactionId, params),\n submitInteraction: (interactionId, params) =>\n runtime.submitInteraction(interactionId, params),\n getSessionState: () => {\n const session = runtime.getSession();\n const frame = runtime.getFrame();\n return {\n status: session ? \"ready\" : \"loading\",\n sessionId: session?.sessionId ?? null,\n controllingPlayerId: frame?.perspectivePlayerId ?? null,\n };\n },\n disconnect: () => runtime.disconnect(),\n };\n}\n\nexport function PluginRuntimeBoundary({\n runtime,\n children,\n}: {\n runtime: PluginRuntimeClient;\n children: React.ReactNode;\n}) {\n const runtimeApi = useMemo(() => runtimeApiFromClient(runtime), [runtime]);\n\n return (\n <RuntimeContext.Provider value={runtimeApi}>\n <PluginSessionProvider runtime={runtime}>\n <PluginGameplayFrameProvider runtime={runtime}>\n <SessionScopedInteractionUiProvider>\n {children}\n </SessionScopedInteractionUiProvider>\n </PluginGameplayFrameProvider>\n </PluginSessionProvider>\n </RuntimeContext.Provider>\n );\n}\n\nfunction SessionScopedInteractionUiProvider({\n children,\n}: {\n children: React.ReactNode;\n}) {\n const { controllingPlayerId } = usePluginSession();\n return (\n <InteractionUiProvider key={controllingPlayerId ?? \"__no_player__\"}>\n {children}\n </InteractionUiProvider>\n );\n}\n"],"mappings":";;;;;;;;;;;AAiBA,IAAM,eAA6B;AAAA,EACjC,KAAK,MAAM,KAAK,IAAI;AACtB;AAEA,IAAM,mBAAqC;AAAA,EACzC,QAAQ,CAAC,WAAW;AAClB,UAAM,aACJ,WAGA;AACF,QAAI,YAAY,YAAY;AAC1B,UAAI;AACF,eAAO,GAAG,MAAM,IAAI,WAAW,WAAW,CAAC;AAAA,MAC7C,QAAQ;AAAA,MAER;AAAA,IACF;AACA,WAAO,GAAG,MAAM,IAAI,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC,IAAI,KAAK,OAAO,EACxD,SAAS,EAAE,EACX,MAAM,CAAC,CAAC;AAAA,EACb;AACF;AAEA,SAAS,sBACP,QACgC;AAChC,QAAM,QAAQ,IAAI,MAAM,OAAO,WAAW,mBAAmB;AAG7D,QAAM,OAAO;AACb,QAAM,YAAY,OAAO;AACzB,SAAO;AACT;AAEA,SAAS,+BAAiD;AACxD,SAAO;AAAA,IACL,OAAO;AAAA,IACP,WAAW;AAAA,IACX,SAAS;AAAA,EACX;AACF;AAEO,SAAS,0BACd,SACqB;AACrB,QAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,mBAAmB,QAAQ,oBAAoB;AACrD,MAAI,UAA0C;AAC9C,MAAI,QAAoC;AACxC,MAAI,eAAe;AACnB,MAAI;AACJ,QAAM,mBAAmB,oBAAI,IAAgB;AAC7C,QAAM,iBAAiB,oBAAI,IAAgB;AAC3C,QAAM,qBAAqB,oBAAI,IAG7B;AACF,QAAM,qBAAqB,oBAAI,IAM7B;AAEF,QAAM,gBAAgB,MAAM;AAC1B,eAAW,YAAY,kBAAkB;AACvC,eAAS;AAAA,IACX;AAAA,EACF;AAEA,QAAM,cAAc,MAAM;AACxB,eAAW,YAAY,gBAAgB;AACrC,eAAS;AAAA,IACX;AAAA,EACF;AAEA,QAAM,eAAe,MAA8B;AACjD,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,MAAM,mDAAmD;AAAA,IACrE;AACA,WAAO;AAAA,MACL,aAAa,MAAM;AAAA,MACnB,kBAAkB,MAAM;AAAA,MACxB,qBAAqB,MAAM;AAAA,IAC7B;AAAA,EACF;AAEA,QAAM,mBAAmB,CAAC,SAAiB,SAAkB;AAC3D,QAAI,cAAc;AAChB;AAAA,IACF;AACA,YAAQ,UAAU,KAAK;AAAA,MACrB,MAAM;AAAA,MACN;AAAA,MACA,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,IACzB,CAAC;AAAA,EACH;AAEA,QAAM,oBAAoB,CAAC,eAAqC;AAC9D,QAAI,cAAc;AAChB;AAAA,IACF;AACA,UAAM,cAAc,2BAA2B,UAAU,UAAU;AACnE,QAAI,CAAC,YAAY,SAAS;AACxB;AAAA,QACE;AAAA,QACA;AAAA,MACF;AACA;AAAA,IACF;AACA,UAAM,UAAU,YAAY;AAC5B,UAAM,qBAAqB,MAAM,IAAI;AAErC,YAAQ,QAAQ,QAAQ,MAAM;AAAA,MAC5B,KAAK,gBAAgB;AACnB,kBAAU,QAAQ,QAAQ;AAC1B,sBAAc;AACd,gBAAQ,UAAU,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAChD,gBAAQ,UAAU,KAAK;AAAA,UACrB,MAAM;AAAA,UACN,UAAU,QAAQ;AAAA,UAClB;AAAA,QACF,CAAC;AACD;AAAA,MACF;AAAA,MACA,KAAK,kBAAkB;AACrB,gBAAQ,QAAQ,QAAQ;AACxB,oBAAY;AACZ,cAAM,kBAAkB,MAAM;AAC5B,cAAI,cAAc;AAChB;AAAA,UACF;AACA,kBAAQ,UAAU,KAAK;AAAA,YACrB,MAAM;AAAA,YACN,UAAU,QAAQ;AAAA,YAClB;AAAA,YACA,oBAAoB,MAAM,IAAI;AAAA,UAChC,CAAC;AAAA,QACH;AACA,YAAI,OAAO,0BAA0B,YAAY;AAC/C,gCAAsB,eAAe;AAAA,QACvC,OAAO;AACL,yBAAe,eAAe;AAAA,QAChC;AACA;AAAA,MACF;AAAA,MACA,KAAK,iCAAiC;AACpC,cAAM,UAAU,mBAAmB,IAAI,QAAQ,QAAQ,SAAS;AAChE,YAAI,SAAS;AACX,6BAAmB,OAAO,QAAQ,QAAQ,SAAS;AACnD,kBAAQ,QAAQ,QAAQ,MAAM;AAAA,QAChC;AACA;AAAA,MACF;AAAA,MACA,KAAK,6BAA6B;AAChC,cAAM,UAAU,mBAAmB,IAAI,QAAQ,QAAQ,SAAS;AAChE,YAAI,CAAC,SAAS;AACZ;AAAA,QACF;AACA,2BAAmB,OAAO,QAAQ,QAAQ,SAAS;AACnD,YAAI,QAAQ,QAAQ,OAAO,UAAU;AACnC,kBAAQ,QAAQ;AAAA,QAClB,OAAO;AACL,kBAAQ,OAAO,sBAAsB,QAAQ,QAAQ,MAAM,CAAC;AAAA,QAC9D;AACA;AAAA,MACF;AAAA,MACA,SAAS;AACP,cAAM,cAAqB,QAAQ;AACnC,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAEA,kBAAgB,QAAQ,UAAU,MAAM,iBAAiB;AAEzD,QAAM,gBAAgB,MAAM;AAC1B,eAAW,WAAW,mBAAmB,OAAO,GAAG;AACjD,cAAQ,6BAA6B,CAAC;AAAA,IACxC;AACA,uBAAmB,MAAM;AACzB,eAAW,WAAW,mBAAmB,OAAO,GAAG;AACjD,YAAM,QAAQ,IAAI,MAAM,6BAA6B;AAGrD,YAAM,OAAO;AACb,YAAM,YAAY;AAClB,cAAQ,OAAO,KAAK;AAAA,IACtB;AACA,uBAAmB,MAAM;AAAA,EAC3B;AAEA,SAAO;AAAA,IACL,YAAY,MAAM;AAAA,IAClB,kBAAkB,CAAC,aAAa;AAC9B,uBAAiB,IAAI,QAAQ;AAC7B,aAAO,MAAM;AACX,yBAAiB,OAAO,QAAQ;AAAA,MAClC;AAAA,IACF;AAAA,IACA,UAAU,MAAM;AAAA,IAChB,gBAAgB,CAAC,aAAa;AAC5B,qBAAe,IAAI,QAAQ;AAC3B,aAAO,MAAM;AACX,uBAAe,OAAO,QAAQ;AAAA,MAChC;AAAA,IACF;AAAA,IACA,qBAAqB,OAAO,eAAe,WACzC,IAAI,QAAQ,CAAC,YAAY;AACvB,UAAI,cAAc;AAChB,gBAAQ,6BAA6B,CAAC;AACtC;AAAA,MACF;AACA,UAAI;AACJ,UAAI;AACF,gBAAQ,aAAa;AAAA,MACvB,SAAS,OAAO;AACd,gBAAQ;AAAA,UACN,OAAO;AAAA,UACP,WAAW;AAAA,UACX,SACE,iBAAiB,QACb,MAAM,UACN;AAAA,QACR,CAAC;AACD;AAAA,MACF;AACA,YAAM,eAAe,kBAAkB,UAAU,MAAM;AACvD,UAAI,CAAC,aAAa,SAAS;AACzB,gBAAQ;AAAA,UACN,OAAO;AAAA,UACP,WAAW;AAAA,UACX,SAAS;AAAA,QACX,CAAC;AACD;AAAA,MACF;AACA,YAAM,YAAY,UAAU,OAAO,UAAU;AAC7C,yBAAmB,IAAI,WAAW,OAAO;AACzC,cAAQ,UAAU,KAAK;AAAA,QACrB,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA,QAAQ,aAAa;AAAA,MACvB,CAAC;AACD,iBAAW,MAAM;AACf,YAAI,CAAC,mBAAmB,OAAO,SAAS,GAAG;AACzC;AAAA,QACF;AACA,gBAAQ;AAAA,UACN,OAAO;AAAA,UACP,WAAW;AAAA,UACX,SAAS;AAAA,QACX,CAAC;AAAA,MACH,GAAG,gBAAgB;AAAA,IACrB,CAAC;AAAA,IACH,mBAAmB,OAAO,eAAe,WACvC,IAAI,QAAQ,CAAC,SAAS,WAAW;AAC/B,UAAI,cAAc;AAChB,cAAM,QAAQ,IAAI,MAAM,6BAA6B;AAGrD,cAAM,OAAO;AACb,cAAM,YAAY;AAClB,eAAO,KAAK;AACZ;AAAA,MACF;AACA,YAAM,eAAe,kBAAkB,UAAU,MAAM;AACvD,UAAI,CAAC,aAAa,SAAS;AACzB,cAAM,QAAQ,IAAI;AAAA,UAChB;AAAA,QACF;AACA,cAAM,OAAO;AACb,cAAM,YAAY;AAClB,eAAO,KAAK;AACZ;AAAA,MACF;AACA,UAAI;AACJ,UAAI;AACF,gBAAQ,aAAa;AAAA,MACvB,SAAS,OAAO;AACd,cAAM,kBAAkB,IAAI;AAAA,UAC1B,iBAAiB,QACb,MAAM,UACN;AAAA,QACN;AACA,wBAAgB,OAAO;AACvB,wBAAgB,YAAY;AAC5B,eAAO,eAAe;AACtB;AAAA,MACF;AACA,YAAM,YAAY,UAAU,OAAO,QAAQ;AAC3C,yBAAmB,IAAI,WAAW,EAAE,SAAS,OAAO,CAAC;AACrD,cAAQ,UAAU,KAAK;AAAA,QACrB,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA,QAAQ,aAAa;AAAA,MACvB,CAAC;AACD,iBAAW,MAAM;AACf,cAAM,UAAU,mBAAmB,IAAI,SAAS;AAChD,YAAI,CAAC,SAAS;AACZ;AAAA,QACF;AACA,2BAAmB,OAAO,SAAS;AACnC,cAAM,QAAQ,IAAI,MAAM,8BAA8B;AAGtD,cAAM,OAAO;AACb,cAAM,YAAY;AAClB,gBAAQ,OAAO,KAAK;AAAA,MACtB,GAAG,gBAAgB;AAAA,IACrB,CAAC;AAAA,IACH,YAAY,MAAM;AAChB,qBAAe;AACf,sBAAgB;AAChB,sBAAgB;AAChB,uBAAiB,MAAM;AACvB,qBAAe,MAAM;AACrB,oBAAc;AACd,gBAAU;AACV,cAAQ;AAAA,IACV;AAAA,EACF;AACF;;;ACzVA,SAAgB,eAAe;AA2CrB;AAhCV,SAAS,qBAAqB,SAA0C;AACtE,SAAO;AAAA,IACL,qBAAqB,CAAC,eAAe,WACnC,QAAQ,oBAAoB,eAAe,MAAM;AAAA,IACnD,mBAAmB,CAAC,eAAe,WACjC,QAAQ,kBAAkB,eAAe,MAAM;AAAA,IACjD,iBAAiB,MAAM;AACrB,YAAM,UAAU,QAAQ,WAAW;AACnC,YAAM,QAAQ,QAAQ,SAAS;AAC/B,aAAO;AAAA,QACL,QAAQ,UAAU,UAAU;AAAA,QAC5B,WAAW,SAAS,aAAa;AAAA,QACjC,qBAAqB,OAAO,uBAAuB;AAAA,MACrD;AAAA,IACF;AAAA,IACA,YAAY,MAAM,QAAQ,WAAW;AAAA,EACvC;AACF;AAEO,SAAS,sBAAsB;AAAA,EACpC;AAAA,EACA;AACF,GAGG;AACD,QAAM,aAAa,QAAQ,MAAM,qBAAqB,OAAO,GAAG,CAAC,OAAO,CAAC;AAEzE,SACE,oBAAC,eAAe,UAAf,EAAwB,OAAO,YAC9B,8BAAC,yBAAsB,SACrB,8BAAC,+BAA4B,SAC3B,8BAAC,sCACE,UACH,GACF,GACF,GACF;AAEJ;AAEA,SAAS,mCAAmC;AAAA,EAC1C;AACF,GAEG;AACD,QAAM,EAAE,oBAAoB,IAAI,iBAAiB;AACjD,SACE,oBAAC,yBACE,YADyB,uBAAuB,eAEnD;AAEJ;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/runtime/core/create-plugin-runtime-client.ts","../src/runtime/components/PluginRuntimeBoundary.tsx"],"sourcesContent":["import {\n HostToPluginEnvelopeSchema,\n RuntimeJsonSchema,\n type HostToPluginEnvelope,\n type PluginGameplayFrame,\n type PluginInteractionBasis,\n type PluginSessionDescriptor,\n type SubmissionResult,\n type ValidationResult,\n} from \"@dreamboard-games/plugin-runtime-contract\";\nimport type {\n PluginRuntimeClient,\n PluginRuntimeClientOptions,\n RuntimeClock,\n RuntimeIdFactory,\n} from \"./types.js\";\n\nconst defaultClock: RuntimeClock = {\n now: () => Date.now(),\n};\n\nconst defaultIdFactory: RuntimeIdFactory = {\n nextId: (prefix) => {\n const cryptoLike = (\n globalThis as typeof globalThis & {\n crypto?: { randomUUID?: () => string };\n }\n ).crypto;\n if (cryptoLike?.randomUUID) {\n try {\n return `${prefix}-${cryptoLike.randomUUID()}`;\n } catch {\n // Fall through to deterministic-enough fallback for older test DOMs.\n }\n }\n return `${prefix}-${Date.now().toString(16)}-${Math.random()\n .toString(16)\n .slice(2)}`;\n },\n};\n\nfunction createSubmissionError(\n result: Extract<SubmissionResult, { accepted: false }>,\n): Error & { errorCode?: string } {\n const error = new Error(result.message ?? \"Submission failed\") as Error & {\n errorCode?: string;\n };\n error.name = \"SubmissionError\";\n error.errorCode = result.errorCode;\n return error;\n}\n\nfunction disconnectedValidationResult(): ValidationResult {\n return {\n valid: false,\n errorCode: \"runtime-disconnected\",\n message: \"Plugin runtime disconnected\",\n };\n}\n\nexport function createPluginRuntimeClient(\n options: PluginRuntimeClientOptions,\n): PluginRuntimeClient {\n const clock = options.clock ?? defaultClock;\n const idFactory = options.idFactory ?? defaultIdFactory;\n const requestTimeoutMs = options.requestTimeoutMs ?? 10_000;\n let session: PluginSessionDescriptor | null = null;\n let frame: PluginGameplayFrame | null = null;\n let disconnected = false;\n let stopTransport: (() => void) | undefined;\n const sessionListeners = new Set<() => void>();\n const frameListeners = new Set<() => void>();\n const pendingValidations = new Map<\n string,\n (result: ValidationResult) => void\n >();\n const pendingSubmissions = new Map<\n string,\n {\n resolve: () => void;\n reject: (error: Error & { errorCode?: string }) => void;\n }\n >();\n\n const notifySession = () => {\n for (const listener of sessionListeners) {\n listener();\n }\n };\n\n const notifyFrame = () => {\n for (const listener of frameListeners) {\n listener();\n }\n };\n\n const currentBasis = (): PluginInteractionBasis => {\n if (!frame) {\n throw new Error(\"Plugin runtime has not received a gameplay frame.\");\n }\n return {\n gameVersion: frame.gameVersion,\n actionSetVersion: frame.actionSetVersion,\n perspectivePlayerId: frame.perspectivePlayerId,\n };\n };\n\n const sendRuntimeError = (message: string, code?: string) => {\n if (disconnected) {\n return;\n }\n options.transport.send({\n type: \"runtime.error\",\n message,\n ...(code ? { code } : {}),\n });\n };\n\n const handleHostMessage = (rawMessage: HostToPluginEnvelope) => {\n if (disconnected) {\n return;\n }\n const parseResult = HostToPluginEnvelopeSchema.safeParse(rawMessage);\n if (!parseResult.success) {\n sendRuntimeError(\n \"Invalid host-to-plugin protocol envelope.\",\n \"invalid-envelope\",\n );\n return;\n }\n const message = parseResult.data;\n const clientReceivedAtMs = clock.now();\n\n switch (message.payload.type) {\n case \"runtime.init\": {\n session = message.payload.session;\n notifySession();\n options.transport.send({ type: \"runtime.ready\" });\n options.transport.send({\n type: \"runtime.ack\",\n sequence: message.sequence,\n clientReceivedAtMs,\n });\n break;\n }\n case \"gameplay.frame\": {\n frame = message.payload.frame;\n notifyFrame();\n const sendRenderedAck = () => {\n if (disconnected) {\n return;\n }\n options.transport.send({\n type: \"runtime.ack\",\n sequence: message.sequence,\n clientReceivedAtMs,\n clientRenderedAtMs: clock.now(),\n });\n };\n if (typeof requestAnimationFrame === \"function\") {\n requestAnimationFrame(sendRenderedAck);\n } else {\n queueMicrotask(sendRenderedAck);\n }\n break;\n }\n case \"interaction.validation-result\": {\n const resolve = pendingValidations.get(message.payload.requestId);\n if (resolve) {\n pendingValidations.delete(message.payload.requestId);\n resolve(message.payload.result);\n }\n break;\n }\n case \"interaction.submit-result\": {\n const pending = pendingSubmissions.get(message.payload.requestId);\n if (!pending) {\n break;\n }\n pendingSubmissions.delete(message.payload.requestId);\n if (message.payload.result.accepted) {\n pending.resolve();\n } else {\n pending.reject(createSubmissionError(message.payload.result));\n }\n break;\n }\n default: {\n const _exhaustive: never = message.payload;\n return _exhaustive;\n }\n }\n };\n\n stopTransport = options.transport.start(handleHostMessage);\n\n const rejectPending = () => {\n for (const resolve of pendingValidations.values()) {\n resolve(disconnectedValidationResult());\n }\n pendingValidations.clear();\n for (const pending of pendingSubmissions.values()) {\n const error = new Error(\"Plugin runtime disconnected\") as Error & {\n errorCode?: string;\n };\n error.name = \"SubmissionError\";\n error.errorCode = \"runtime-disconnected\";\n pending.reject(error);\n }\n pendingSubmissions.clear();\n };\n\n return {\n getSession: () => session,\n subscribeSession: (listener) => {\n sessionListeners.add(listener);\n return () => {\n sessionListeners.delete(listener);\n };\n },\n getFrame: () => frame,\n subscribeFrame: (listener) => {\n frameListeners.add(listener);\n return () => {\n frameListeners.delete(listener);\n };\n },\n validateInteraction: async (interactionId, params) =>\n new Promise((resolve) => {\n if (disconnected) {\n resolve(disconnectedValidationResult());\n return;\n }\n let basis: PluginInteractionBasis;\n try {\n basis = currentBasis();\n } catch (error) {\n resolve({\n valid: false,\n errorCode: \"runtime-not-ready\",\n message:\n error instanceof Error\n ? error.message\n : \"Plugin runtime is not ready.\",\n });\n return;\n }\n const parsedParams = RuntimeJsonSchema.safeParse(params);\n if (!parsedParams.success) {\n resolve({\n valid: false,\n errorCode: \"invalid-runtime-json\",\n message: \"Interaction params must be runtime JSON.\",\n });\n return;\n }\n const requestId = idFactory.nextId(\"validate\");\n pendingValidations.set(requestId, resolve);\n options.transport.send({\n type: \"interaction.validate\",\n requestId,\n basis,\n interactionId,\n params: parsedParams.data,\n });\n setTimeout(() => {\n if (!pendingValidations.delete(requestId)) {\n return;\n }\n resolve({\n valid: false,\n errorCode: \"validation-timeout\",\n message: \"Validation request timed out\",\n });\n }, requestTimeoutMs);\n }),\n submitInteraction: async (interactionId, params) =>\n new Promise((resolve, reject) => {\n if (disconnected) {\n const error = new Error(\"Plugin runtime disconnected\") as Error & {\n errorCode?: string;\n };\n error.name = \"SubmissionError\";\n error.errorCode = \"runtime-disconnected\";\n reject(error);\n return;\n }\n const parsedParams = RuntimeJsonSchema.safeParse(params);\n if (!parsedParams.success) {\n const error = new Error(\n \"Interaction params must be runtime JSON.\",\n ) as Error & { errorCode?: string };\n error.name = \"SubmissionError\";\n error.errorCode = \"invalid-runtime-json\";\n reject(error);\n return;\n }\n let basis: PluginInteractionBasis;\n try {\n basis = currentBasis();\n } catch (error) {\n const submissionError = new Error(\n error instanceof Error\n ? error.message\n : \"Plugin runtime is not ready.\",\n ) as Error & { errorCode?: string };\n submissionError.name = \"SubmissionError\";\n submissionError.errorCode = \"runtime-not-ready\";\n reject(submissionError);\n return;\n }\n const requestId = idFactory.nextId(\"submit\");\n pendingSubmissions.set(requestId, { resolve, reject });\n options.transport.send({\n type: \"interaction.submit\",\n requestId,\n basis,\n interactionId,\n params: parsedParams.data,\n });\n setTimeout(() => {\n const pending = pendingSubmissions.get(requestId);\n if (!pending) {\n return;\n }\n pendingSubmissions.delete(requestId);\n const error = new Error(\"Submission request timed out\") as Error & {\n errorCode?: string;\n };\n error.name = \"SubmissionError\";\n error.errorCode = \"submission-timeout\";\n pending.reject(error);\n }, requestTimeoutMs);\n }),\n disconnect: () => {\n disconnected = true;\n stopTransport?.();\n stopTransport = undefined;\n sessionListeners.clear();\n frameListeners.clear();\n rejectPending();\n session = null;\n frame = null;\n },\n };\n}\n","import React, { useMemo } from \"react\";\nimport { InteractionUiProvider } from \"../context/InteractionDraftContext.js\";\nimport {\n PluginSessionProvider,\n usePluginSession,\n} from \"../context/PluginSessionContext.js\";\nimport { PluginGameplayFrameProvider } from \"../context/PluginGameplayFrameContext.js\";\nimport { RuntimeContext } from \"../context/RuntimeContext.js\";\nimport type { PluginRuntimeClient } from \"../core/types.js\";\nimport type { RuntimeAPI } from \"../types/runtime-api.js\";\n\nfunction runtimeApiFromClient(runtime: PluginRuntimeClient): RuntimeAPI {\n return {\n validateInteraction: (interactionId, params) =>\n runtime.validateInteraction(interactionId, params),\n submitInteraction: (interactionId, params) =>\n runtime.submitInteraction(interactionId, params),\n getSessionState: () => {\n const session = runtime.getSession();\n const frame = runtime.getFrame();\n return {\n status: session ? \"ready\" : \"loading\",\n sessionId: session?.sessionId ?? null,\n controllingPlayerId: frame?.perspectivePlayerId ?? null,\n };\n },\n disconnect: () => runtime.disconnect(),\n };\n}\n\nexport function PluginRuntimeBoundary({\n runtime,\n children,\n}: {\n runtime: PluginRuntimeClient;\n children: React.ReactNode;\n}) {\n const runtimeApi = useMemo(() => runtimeApiFromClient(runtime), [runtime]);\n\n return (\n <RuntimeContext.Provider value={runtimeApi}>\n <PluginSessionProvider runtime={runtime}>\n <PluginGameplayFrameProvider runtime={runtime}>\n <SessionScopedInteractionUiProvider>\n {children}\n </SessionScopedInteractionUiProvider>\n </PluginGameplayFrameProvider>\n </PluginSessionProvider>\n </RuntimeContext.Provider>\n );\n}\n\nfunction SessionScopedInteractionUiProvider({\n children,\n}: {\n children: React.ReactNode;\n}) {\n const { controllingPlayerId } = usePluginSession();\n return (\n <InteractionUiProvider key={controllingPlayerId ?? \"__no_player__\"}>\n {children}\n </InteractionUiProvider>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,575 @@
|
|
|
1
|
+
// ../plugin-runtime-contract/dist/chunk-GX5V4QL7.js
|
|
2
|
+
import { sha256 } from "@noble/hashes/sha2.js";
|
|
3
|
+
import { bytesToHex, utf8ToBytes } from "@noble/hashes/utils.js";
|
|
4
|
+
function canonicalizePluginRuntimeJson(value) {
|
|
5
|
+
assertRuntimeJson(value);
|
|
6
|
+
return canonicalizeJson(value);
|
|
7
|
+
}
|
|
8
|
+
function encodeCanonicalPluginRuntimeJson(value) {
|
|
9
|
+
return JSON.stringify(canonicalizePluginRuntimeJson(value));
|
|
10
|
+
}
|
|
11
|
+
function digestPluginRuntimeJson(value) {
|
|
12
|
+
return `sha256:${sha256Hex(encodeCanonicalPluginRuntimeJson(value))}`;
|
|
13
|
+
}
|
|
14
|
+
function canonicalizeJson(value) {
|
|
15
|
+
if (value === null || typeof value === "boolean" || typeof value === "string") {
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
if (typeof value === "number") {
|
|
19
|
+
if (!Number.isFinite(value)) {
|
|
20
|
+
throw new Error("canonical JSON contains a non-finite number");
|
|
21
|
+
}
|
|
22
|
+
return value;
|
|
23
|
+
}
|
|
24
|
+
if (Array.isArray(value)) {
|
|
25
|
+
return value.map((item) => canonicalizeJson(item));
|
|
26
|
+
}
|
|
27
|
+
return Object.fromEntries(
|
|
28
|
+
Object.entries(value).filter(([, item]) => item !== void 0).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0).map(([key, item]) => [key, canonicalizeJson(item)])
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
function assertRuntimeJson(value) {
|
|
32
|
+
if (value === null || typeof value === "boolean" || typeof value === "string") {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (typeof value === "number") {
|
|
36
|
+
if (!Number.isFinite(value)) {
|
|
37
|
+
throw new Error("runtime JSON contains a non-finite number");
|
|
38
|
+
}
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (Array.isArray(value)) {
|
|
42
|
+
value.forEach(assertRuntimeJson);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (typeof value === "object") {
|
|
46
|
+
Object.values(value).forEach((item) => {
|
|
47
|
+
if (item !== void 0) {
|
|
48
|
+
assertRuntimeJson(item);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
throw new Error(`runtime JSON contains unsupported ${typeof value} value`);
|
|
54
|
+
}
|
|
55
|
+
function sha256Hex(input) {
|
|
56
|
+
return bytesToHex(sha256(utf8ToBytes(input)));
|
|
57
|
+
}
|
|
58
|
+
function computePluginActionSetVersion(input) {
|
|
59
|
+
return digestPluginRuntimeJson({
|
|
60
|
+
digestVersion: "plugin-action-set@3",
|
|
61
|
+
gameVersion: input.gameVersion,
|
|
62
|
+
availableInteractions: input.availableInteractions
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
function digestPluginGameplayFrame(frame) {
|
|
66
|
+
return digestPluginRuntimeJson({
|
|
67
|
+
digestVersion: "plugin-gameplay-frame@3",
|
|
68
|
+
frame
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ../plugin-runtime-contract/dist/chunk-E4Y6SAWF.js
|
|
73
|
+
import { z } from "zod";
|
|
74
|
+
var DREAMBOARD_PLUGIN_PROTOCOL = "dreamboard-plugin";
|
|
75
|
+
var DREAMBOARD_PLUGIN_PROTOCOL_VERSION = 3;
|
|
76
|
+
var RuntimeJsonSchema = z.lazy(
|
|
77
|
+
() => z.union([
|
|
78
|
+
z.null(),
|
|
79
|
+
z.boolean(),
|
|
80
|
+
z.number().finite(),
|
|
81
|
+
z.string(),
|
|
82
|
+
z.array(RuntimeJsonSchema),
|
|
83
|
+
z.record(z.string(), RuntimeJsonSchema)
|
|
84
|
+
])
|
|
85
|
+
);
|
|
86
|
+
var BoardStaticProjectionSchema = z.object({
|
|
87
|
+
view: RuntimeJsonSchema,
|
|
88
|
+
hash: z.string().optional(),
|
|
89
|
+
manifestVersion: z.string().optional()
|
|
90
|
+
}).strict();
|
|
91
|
+
var SetupGuidanceStepSchema = z.object({
|
|
92
|
+
id: z.string().min(1),
|
|
93
|
+
label: z.string().min(1),
|
|
94
|
+
description: z.string().optional()
|
|
95
|
+
}).strict();
|
|
96
|
+
var GameGuidanceProjectionSchema = z.object({
|
|
97
|
+
phase: z.object({
|
|
98
|
+
id: z.string().min(1),
|
|
99
|
+
label: z.string().min(1),
|
|
100
|
+
summary: z.string().optional(),
|
|
101
|
+
objective: z.string().optional()
|
|
102
|
+
}).strict(),
|
|
103
|
+
setup: z.object({
|
|
104
|
+
profileId: z.string().min(1),
|
|
105
|
+
name: z.string().min(1),
|
|
106
|
+
summary: z.string().optional(),
|
|
107
|
+
steps: z.array(SetupGuidanceStepSchema)
|
|
108
|
+
}).strict().optional()
|
|
109
|
+
}).strict();
|
|
110
|
+
var GameEventDetailSchema = z.object({
|
|
111
|
+
label: z.string().min(1),
|
|
112
|
+
value: z.union([z.string(), z.number().finite(), z.boolean()])
|
|
113
|
+
}).strict();
|
|
114
|
+
var SystemActionEventSchema = z.object({
|
|
115
|
+
kind: z.literal("systemAction"),
|
|
116
|
+
procedureId: z.string().min(1),
|
|
117
|
+
title: z.string().min(1),
|
|
118
|
+
summary: z.string().optional(),
|
|
119
|
+
details: z.array(GameEventDetailSchema).optional()
|
|
120
|
+
}).strict();
|
|
121
|
+
var GameEventSchema = z.discriminatedUnion("kind", [
|
|
122
|
+
SystemActionEventSchema
|
|
123
|
+
]);
|
|
124
|
+
var ProjectedGameEventSchema = GameEventSchema.and(
|
|
125
|
+
z.object({
|
|
126
|
+
version: z.number().int().nonnegative(),
|
|
127
|
+
index: z.number().int().nonnegative()
|
|
128
|
+
}).strict()
|
|
129
|
+
);
|
|
130
|
+
var SeatProjectionBundleSchema = z.object({
|
|
131
|
+
currentStage: z.string().nullable().optional(),
|
|
132
|
+
stageSeats: z.array(z.string()).optional(),
|
|
133
|
+
simultaneousPhase: z.unknown().nullable().optional(),
|
|
134
|
+
guidance: GameGuidanceProjectionSchema.nullable().optional(),
|
|
135
|
+
recentEvents: z.array(ProjectedGameEventSchema).optional(),
|
|
136
|
+
interactionsByRef: z.record(z.string(), z.unknown()).optional(),
|
|
137
|
+
seats: z.record(
|
|
138
|
+
z.string(),
|
|
139
|
+
z.object({
|
|
140
|
+
view: z.unknown().optional(),
|
|
141
|
+
availableInteractionRefs: z.array(z.string()).optional(),
|
|
142
|
+
zones: z.unknown().optional()
|
|
143
|
+
}).strict()
|
|
144
|
+
)
|
|
145
|
+
}).strict();
|
|
146
|
+
var PlayerIdSchema = z.string().min(1);
|
|
147
|
+
var PluginPlayerSummarySchema = z.object({
|
|
148
|
+
playerId: PlayerIdSchema,
|
|
149
|
+
displayName: z.string(),
|
|
150
|
+
color: z.string().optional()
|
|
151
|
+
}).strict();
|
|
152
|
+
var PluginSessionDescriptorSchema = z.object({
|
|
153
|
+
sessionId: z.string().min(1),
|
|
154
|
+
players: z.array(PluginPlayerSummarySchema)
|
|
155
|
+
}).strict();
|
|
156
|
+
var InteractionCommitPolicySchema = z.discriminatedUnion("mode", [
|
|
157
|
+
z.object({ mode: z.literal("manual") }).strict(),
|
|
158
|
+
z.object({ mode: z.literal("autoWhenReady") }).strict()
|
|
159
|
+
]);
|
|
160
|
+
var InputSelectionSchema = z.discriminatedUnion("mode", [
|
|
161
|
+
z.object({ mode: z.literal("single") }).strict(),
|
|
162
|
+
z.object({
|
|
163
|
+
mode: z.literal("many"),
|
|
164
|
+
min: z.number().int(),
|
|
165
|
+
max: z.number().int().optional(),
|
|
166
|
+
distinct: z.boolean().optional()
|
|
167
|
+
}).strict()
|
|
168
|
+
]);
|
|
169
|
+
var InputDomainDependencyCaseSchema = z.lazy(
|
|
170
|
+
() => z.object({
|
|
171
|
+
when: z.record(z.string(), z.string()),
|
|
172
|
+
domain: InputDomainSchema
|
|
173
|
+
}).strict()
|
|
174
|
+
);
|
|
175
|
+
var InputDomainDependenciesSchema = z.discriminatedUnion("mode", [
|
|
176
|
+
z.object({
|
|
177
|
+
mode: z.literal("eager"),
|
|
178
|
+
dependentCases: z.array(InputDomainDependencyCaseSchema)
|
|
179
|
+
}).strict(),
|
|
180
|
+
z.object({
|
|
181
|
+
mode: z.literal("lazy"),
|
|
182
|
+
dependsOn: z.array(z.string()),
|
|
183
|
+
resolver: z.object({
|
|
184
|
+
interactionKey: z.string().optional(),
|
|
185
|
+
inputKey: z.string()
|
|
186
|
+
}).strict()
|
|
187
|
+
}).strict()
|
|
188
|
+
]);
|
|
189
|
+
var InputDomainSchema = z.object({
|
|
190
|
+
type: z.string(),
|
|
191
|
+
selection: InputSelectionSchema.optional(),
|
|
192
|
+
dependencies: InputDomainDependenciesSchema.optional()
|
|
193
|
+
}).catchall(RuntimeJsonSchema);
|
|
194
|
+
var InteractionChoiceOptionSchema = z.object({
|
|
195
|
+
value: z.string().nullable(),
|
|
196
|
+
label: z.string(),
|
|
197
|
+
icon: z.string().optional(),
|
|
198
|
+
badge: z.string().optional(),
|
|
199
|
+
description: z.string().optional(),
|
|
200
|
+
disabled: z.boolean().optional(),
|
|
201
|
+
disabledReason: z.string().optional()
|
|
202
|
+
}).strict();
|
|
203
|
+
var InteractionInputDescriptorSchema = z.object({
|
|
204
|
+
key: z.string().min(1),
|
|
205
|
+
kind: z.string().min(1),
|
|
206
|
+
domain: InputDomainSchema,
|
|
207
|
+
defaultValue: RuntimeJsonSchema.optional()
|
|
208
|
+
}).strict();
|
|
209
|
+
var InteractionAvailabilitySchema = z.discriminatedUnion("status", [
|
|
210
|
+
z.object({ status: z.literal("available") }).strict(),
|
|
211
|
+
z.object({ status: z.literal("notYourTurn"), reason: z.string() }).strict(),
|
|
212
|
+
z.object({
|
|
213
|
+
status: z.literal("insufficientResources"),
|
|
214
|
+
reason: z.string(),
|
|
215
|
+
missingResources: z.record(z.string(), z.number().finite())
|
|
216
|
+
}).strict(),
|
|
217
|
+
z.object({
|
|
218
|
+
status: z.literal("blocked"),
|
|
219
|
+
reason: z.string(),
|
|
220
|
+
code: z.string().optional()
|
|
221
|
+
}).strict()
|
|
222
|
+
]);
|
|
223
|
+
var InteractionBaseSchema = z.object({
|
|
224
|
+
phaseName: z.string().min(1),
|
|
225
|
+
interactionKey: z.string().min(1),
|
|
226
|
+
interactionId: z.string().min(1),
|
|
227
|
+
label: z.string().min(1),
|
|
228
|
+
help: z.string().optional(),
|
|
229
|
+
zoneId: z.string().optional(),
|
|
230
|
+
zoneIds: z.array(z.string()).optional(),
|
|
231
|
+
commit: InteractionCommitPolicySchema,
|
|
232
|
+
descriptorDigest: z.string().optional(),
|
|
233
|
+
actorSeat: z.number().int().optional(),
|
|
234
|
+
draftDigest: z.string().optional(),
|
|
235
|
+
inputs: z.array(InteractionInputDescriptorSchema),
|
|
236
|
+
cost: z.record(z.string(), RuntimeJsonSchema).optional(),
|
|
237
|
+
currentResources: z.record(z.string(), RuntimeJsonSchema).optional(),
|
|
238
|
+
availability: InteractionAvailabilitySchema,
|
|
239
|
+
reasons: z.array(
|
|
240
|
+
z.object({
|
|
241
|
+
ruleId: z.string(),
|
|
242
|
+
errorCode: z.string()
|
|
243
|
+
}).strict()
|
|
244
|
+
).optional()
|
|
245
|
+
}).strict();
|
|
246
|
+
var InteractionContextSchema = z.object({
|
|
247
|
+
to: z.string().min(1),
|
|
248
|
+
title: z.string().optional(),
|
|
249
|
+
payload: z.record(z.string(), RuntimeJsonSchema).optional(),
|
|
250
|
+
options: z.array(
|
|
251
|
+
z.object({
|
|
252
|
+
id: z.string(),
|
|
253
|
+
label: z.string().optional()
|
|
254
|
+
}).strict()
|
|
255
|
+
).optional()
|
|
256
|
+
}).strict();
|
|
257
|
+
var InteractionDescriptorSchema = z.discriminatedUnion("kind", [
|
|
258
|
+
InteractionBaseSchema.extend({ kind: z.literal("action") }).strict(),
|
|
259
|
+
InteractionBaseSchema.extend({
|
|
260
|
+
kind: z.literal("prompt"),
|
|
261
|
+
context: InteractionContextSchema
|
|
262
|
+
}).strict()
|
|
263
|
+
]);
|
|
264
|
+
var ZoneHandlesSnapshotSchema = z.object({
|
|
265
|
+
cardIds: z.array(z.string()),
|
|
266
|
+
cardViewsById: z.record(z.string(), z.string()),
|
|
267
|
+
playableByCardId: z.record(
|
|
268
|
+
z.string(),
|
|
269
|
+
z.array(InteractionDescriptorSchema)
|
|
270
|
+
)
|
|
271
|
+
}).strict();
|
|
272
|
+
var SimultaneousPhaseSnapshotSchema = z.object({
|
|
273
|
+
phaseName: z.string().min(1),
|
|
274
|
+
interactionId: z.string().min(1),
|
|
275
|
+
actorIds: z.array(PlayerIdSchema),
|
|
276
|
+
sealedPlayerIds: z.array(PlayerIdSchema),
|
|
277
|
+
pendingPlayerIds: z.array(PlayerIdSchema)
|
|
278
|
+
}).strict();
|
|
279
|
+
var PluginGameplayFrameSchema = z.object({
|
|
280
|
+
gameVersion: z.number().int().nonnegative(),
|
|
281
|
+
actionSetVersion: z.string().min(1),
|
|
282
|
+
perspectivePlayerId: PlayerIdSchema.nullable(),
|
|
283
|
+
view: RuntimeJsonSchema.nullable(),
|
|
284
|
+
flow: z.object({
|
|
285
|
+
currentPhase: z.string().nullable(),
|
|
286
|
+
currentStage: z.string().nullable(),
|
|
287
|
+
activePlayers: z.array(PlayerIdSchema),
|
|
288
|
+
simultaneousPhase: SimultaneousPhaseSnapshotSchema.nullable()
|
|
289
|
+
}).strict(),
|
|
290
|
+
availableInteractions: z.array(InteractionDescriptorSchema),
|
|
291
|
+
guidance: GameGuidanceProjectionSchema.nullable().optional(),
|
|
292
|
+
recentEvents: z.array(ProjectedGameEventSchema),
|
|
293
|
+
zones: z.record(z.string(), ZoneHandlesSnapshotSchema)
|
|
294
|
+
}).strict();
|
|
295
|
+
var ValidationResultSchema = z.object({
|
|
296
|
+
valid: z.boolean(),
|
|
297
|
+
errorCode: z.string().optional(),
|
|
298
|
+
message: z.string().optional()
|
|
299
|
+
}).strict();
|
|
300
|
+
var SubmissionResultSchema = z.discriminatedUnion("accepted", [
|
|
301
|
+
z.object({ accepted: z.literal(true) }).strict(),
|
|
302
|
+
z.object({
|
|
303
|
+
accepted: z.literal(false),
|
|
304
|
+
errorCode: z.string().min(1),
|
|
305
|
+
message: z.string().optional()
|
|
306
|
+
}).strict()
|
|
307
|
+
]);
|
|
308
|
+
var PluginInteractionBasisSchema = z.object({
|
|
309
|
+
gameVersion: z.number().int().nonnegative(),
|
|
310
|
+
actionSetVersion: z.string().min(1),
|
|
311
|
+
perspectivePlayerId: PlayerIdSchema.nullable()
|
|
312
|
+
}).strict();
|
|
313
|
+
var ValidateInteractionCommandSchema = z.object({
|
|
314
|
+
type: z.literal("interaction.validate"),
|
|
315
|
+
requestId: z.string().min(1),
|
|
316
|
+
basis: PluginInteractionBasisSchema,
|
|
317
|
+
interactionId: z.string().min(1),
|
|
318
|
+
params: RuntimeJsonSchema
|
|
319
|
+
}).strict();
|
|
320
|
+
var SubmitInteractionCommandSchema = z.object({
|
|
321
|
+
type: z.literal("interaction.submit"),
|
|
322
|
+
requestId: z.string().min(1),
|
|
323
|
+
basis: PluginInteractionBasisSchema,
|
|
324
|
+
interactionId: z.string().min(1),
|
|
325
|
+
params: RuntimeJsonSchema
|
|
326
|
+
}).strict();
|
|
327
|
+
var HostToPluginPayloadSchema = z.discriminatedUnion("type", [
|
|
328
|
+
z.object({
|
|
329
|
+
type: z.literal("runtime.init"),
|
|
330
|
+
session: PluginSessionDescriptorSchema
|
|
331
|
+
}).strict(),
|
|
332
|
+
z.object({
|
|
333
|
+
type: z.literal("gameplay.frame"),
|
|
334
|
+
frame: PluginGameplayFrameSchema
|
|
335
|
+
}).strict(),
|
|
336
|
+
z.object({
|
|
337
|
+
type: z.literal("interaction.validation-result"),
|
|
338
|
+
requestId: z.string().min(1),
|
|
339
|
+
result: ValidationResultSchema
|
|
340
|
+
}).strict(),
|
|
341
|
+
z.object({
|
|
342
|
+
type: z.literal("interaction.submit-result"),
|
|
343
|
+
requestId: z.string().min(1),
|
|
344
|
+
result: SubmissionResultSchema
|
|
345
|
+
}).strict()
|
|
346
|
+
]);
|
|
347
|
+
var PluginToHostPayloadSchema = z.discriminatedUnion("type", [
|
|
348
|
+
z.object({ type: z.literal("runtime.ready") }).strict(),
|
|
349
|
+
z.object({
|
|
350
|
+
type: z.literal("runtime.ack"),
|
|
351
|
+
sequence: z.number().int().nonnegative(),
|
|
352
|
+
clientReceivedAtMs: z.number().finite().optional(),
|
|
353
|
+
clientRenderedAtMs: z.number().finite().optional()
|
|
354
|
+
}).strict(),
|
|
355
|
+
ValidateInteractionCommandSchema,
|
|
356
|
+
SubmitInteractionCommandSchema,
|
|
357
|
+
z.object({
|
|
358
|
+
type: z.literal("runtime.error"),
|
|
359
|
+
message: z.string(),
|
|
360
|
+
code: z.string().optional()
|
|
361
|
+
}).strict()
|
|
362
|
+
]);
|
|
363
|
+
function createPluginProtocolEnvelopeSchema(payloadSchema) {
|
|
364
|
+
return z.object({
|
|
365
|
+
protocol: z.literal(DREAMBOARD_PLUGIN_PROTOCOL),
|
|
366
|
+
version: z.literal(DREAMBOARD_PLUGIN_PROTOCOL_VERSION),
|
|
367
|
+
channelId: z.string().min(1),
|
|
368
|
+
sequence: z.number().int().nonnegative(),
|
|
369
|
+
payload: payloadSchema
|
|
370
|
+
}).strict();
|
|
371
|
+
}
|
|
372
|
+
var HostToPluginEnvelopeSchema = createPluginProtocolEnvelopeSchema(
|
|
373
|
+
HostToPluginPayloadSchema
|
|
374
|
+
);
|
|
375
|
+
var PluginToHostEnvelopeSchema = createPluginProtocolEnvelopeSchema(
|
|
376
|
+
PluginToHostPayloadSchema
|
|
377
|
+
);
|
|
378
|
+
var PluginProtocolFrameSchema = z.object({
|
|
379
|
+
id: z.string().min(1),
|
|
380
|
+
frame: PluginGameplayFrameSchema,
|
|
381
|
+
projectionDigest: z.string().regex(/^sha256:[a-f0-9]{64}$/)
|
|
382
|
+
}).strict();
|
|
383
|
+
var PluginProtocolStepSchema = z.discriminatedUnion("kind", [
|
|
384
|
+
z.object({
|
|
385
|
+
id: z.string().min(1),
|
|
386
|
+
kind: z.literal("host.frame"),
|
|
387
|
+
frameId: z.string().min(1)
|
|
388
|
+
}).strict(),
|
|
389
|
+
z.object({
|
|
390
|
+
id: z.string().min(1),
|
|
391
|
+
kind: z.literal("client.validate"),
|
|
392
|
+
fromFrameId: z.string().min(1),
|
|
393
|
+
requestDigest: z.string().regex(/^sha256:[a-f0-9]{64}$/),
|
|
394
|
+
response: ValidationResultSchema
|
|
395
|
+
}).strict(),
|
|
396
|
+
z.object({
|
|
397
|
+
id: z.string().min(1),
|
|
398
|
+
kind: z.literal("client.submit"),
|
|
399
|
+
fromFrameId: z.string().min(1),
|
|
400
|
+
requestDigest: z.string().regex(/^sha256:[a-f0-9]{64}$/),
|
|
401
|
+
response: SubmissionResultSchema
|
|
402
|
+
}).strict()
|
|
403
|
+
]);
|
|
404
|
+
var PluginProtocolTapeSchema = z.object({
|
|
405
|
+
session: PluginSessionDescriptorSchema,
|
|
406
|
+
frames: z.array(PluginProtocolFrameSchema),
|
|
407
|
+
steps: z.array(PluginProtocolStepSchema)
|
|
408
|
+
}).strict();
|
|
409
|
+
|
|
410
|
+
// ../plugin-runtime-contract/dist/index.js
|
|
411
|
+
function materializePluginGameplayFrame(input) {
|
|
412
|
+
const dynamicProjection = SeatProjectionBundleSchema.parse(
|
|
413
|
+
canonicalizeReducerProjection(input.dynamicProjection)
|
|
414
|
+
);
|
|
415
|
+
const staticProjection = input.staticProjection == null ? null : BoardStaticProjectionSchema.parse(
|
|
416
|
+
canonicalizeReducerProjection(input.staticProjection)
|
|
417
|
+
);
|
|
418
|
+
const registry = parseInteractionRegistry(
|
|
419
|
+
dynamicProjection.interactionsByRef
|
|
420
|
+
);
|
|
421
|
+
const seat = input.perspectivePlayerId == null ? null : dynamicProjection.seats[input.perspectivePlayerId] ?? null;
|
|
422
|
+
const availableInteractions = seat == null ? [] : hydrateInteractionRefs(
|
|
423
|
+
registry,
|
|
424
|
+
seat.availableInteractionRefs,
|
|
425
|
+
"availableInteractionRefs"
|
|
426
|
+
);
|
|
427
|
+
const zones = seat?.zones == null ? {} : hydrateZones(registry, seat.zones, "zones");
|
|
428
|
+
const frame = {
|
|
429
|
+
gameVersion: input.gameVersion,
|
|
430
|
+
actionSetVersion: input.actionSetVersion,
|
|
431
|
+
perspectivePlayerId: input.perspectivePlayerId,
|
|
432
|
+
view: composeProjectionView(staticProjection, seat?.view),
|
|
433
|
+
flow: {
|
|
434
|
+
currentPhase: input.currentPhase,
|
|
435
|
+
currentStage: dynamicProjection.currentStage ?? null,
|
|
436
|
+
activePlayers: [...input.activePlayers],
|
|
437
|
+
simultaneousPhase: dynamicProjection.simultaneousPhase ?? null
|
|
438
|
+
},
|
|
439
|
+
availableInteractions,
|
|
440
|
+
guidance: dynamicProjection.guidance ?? null,
|
|
441
|
+
recentEvents: [...dynamicProjection.recentEvents ?? []],
|
|
442
|
+
zones
|
|
443
|
+
};
|
|
444
|
+
return PluginGameplayFrameSchema.parse(frame);
|
|
445
|
+
}
|
|
446
|
+
function canonicalizeReducerProjection(value) {
|
|
447
|
+
return canonicalizePluginRuntimeJson(value);
|
|
448
|
+
}
|
|
449
|
+
function parseInteractionRegistry(value) {
|
|
450
|
+
if (value == null) return {};
|
|
451
|
+
if (!isRecord(value)) {
|
|
452
|
+
throw new Error("Seat projection interactionsByRef must be an object.");
|
|
453
|
+
}
|
|
454
|
+
return Object.fromEntries(
|
|
455
|
+
Object.entries(value).map(([ref, descriptor]) => [
|
|
456
|
+
ref,
|
|
457
|
+
InteractionDescriptorSchema.parse(descriptor)
|
|
458
|
+
])
|
|
459
|
+
);
|
|
460
|
+
}
|
|
461
|
+
function hydrateZones(registry, value, path) {
|
|
462
|
+
if (!isRecord(value)) {
|
|
463
|
+
throw new Error(`Seat projection ${path} must be an object.`);
|
|
464
|
+
}
|
|
465
|
+
return Object.fromEntries(
|
|
466
|
+
Object.entries(value).map(([zoneId, zoneValue]) => [
|
|
467
|
+
zoneId,
|
|
468
|
+
hydrateZone(registry, zoneValue, `${path}.${zoneId}`)
|
|
469
|
+
])
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
function hydrateZone(registry, value, path) {
|
|
473
|
+
if (!isRecord(value)) {
|
|
474
|
+
throw new Error(`Seat projection ${path} must be an object.`);
|
|
475
|
+
}
|
|
476
|
+
const cardIds = arrayOfStrings(value.cardIds, `${path}.cardIds`);
|
|
477
|
+
const cardViewsById = stringRecord(
|
|
478
|
+
value.cardViewsById,
|
|
479
|
+
`${path}.cardViewsById`
|
|
480
|
+
);
|
|
481
|
+
if (!isRecord(value.playableByCardId)) {
|
|
482
|
+
throw new Error(
|
|
483
|
+
`Seat projection ${path}.playableByCardId must be an object.`
|
|
484
|
+
);
|
|
485
|
+
}
|
|
486
|
+
const playableByCardId = Object.fromEntries(
|
|
487
|
+
Object.entries(value.playableByCardId).map(([cardId, refs]) => [
|
|
488
|
+
cardId,
|
|
489
|
+
hydrateInteractionRefs(
|
|
490
|
+
registry,
|
|
491
|
+
refs,
|
|
492
|
+
`${path}.playableByCardId.${cardId}`
|
|
493
|
+
)
|
|
494
|
+
])
|
|
495
|
+
);
|
|
496
|
+
return ZoneHandlesSnapshotSchema.parse({
|
|
497
|
+
cardIds,
|
|
498
|
+
cardViewsById,
|
|
499
|
+
playableByCardId
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
function hydrateInteractionRefs(registry, value, path) {
|
|
503
|
+
if (!Array.isArray(value)) {
|
|
504
|
+
throw new Error(`Seat projection ${path} must be an array of refs.`);
|
|
505
|
+
}
|
|
506
|
+
return value.map((ref, index) => {
|
|
507
|
+
if (typeof ref !== "string") {
|
|
508
|
+
throw new Error(
|
|
509
|
+
`Seat projection ${path}[${index}] must be a ref string.`
|
|
510
|
+
);
|
|
511
|
+
}
|
|
512
|
+
const descriptor = registry[ref];
|
|
513
|
+
if (!descriptor) {
|
|
514
|
+
throw new Error(
|
|
515
|
+
`Seat projection ${path}[${index}] references '${ref}', which is missing from interactionsByRef.`
|
|
516
|
+
);
|
|
517
|
+
}
|
|
518
|
+
return descriptor;
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
function composeProjectionView(staticProjection, dynamicView) {
|
|
522
|
+
const normalizedDynamicView = dynamicView === void 0 ? null : dynamicView;
|
|
523
|
+
if (staticProjection == null) {
|
|
524
|
+
return normalizedDynamicView;
|
|
525
|
+
}
|
|
526
|
+
if (normalizedDynamicView == null) {
|
|
527
|
+
return staticProjection.view;
|
|
528
|
+
}
|
|
529
|
+
if (isRecord(staticProjection.view) && isRecord(normalizedDynamicView)) {
|
|
530
|
+
return {
|
|
531
|
+
...staticProjection.view,
|
|
532
|
+
...normalizedDynamicView
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
return {
|
|
536
|
+
static: staticProjection.view,
|
|
537
|
+
dynamic: normalizedDynamicView
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
function arrayOfStrings(value, path) {
|
|
541
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
|
|
542
|
+
throw new Error(`Seat projection ${path} must be an array of strings.`);
|
|
543
|
+
}
|
|
544
|
+
return value;
|
|
545
|
+
}
|
|
546
|
+
function stringRecord(value, path) {
|
|
547
|
+
if (!isRecord(value)) {
|
|
548
|
+
throw new Error(`Seat projection ${path} must be an object.`);
|
|
549
|
+
}
|
|
550
|
+
const result = {};
|
|
551
|
+
for (const [key, item] of Object.entries(value)) {
|
|
552
|
+
if (typeof item !== "string") {
|
|
553
|
+
throw new Error(`Seat projection ${path}.${key} must be a string.`);
|
|
554
|
+
}
|
|
555
|
+
result[key] = item;
|
|
556
|
+
}
|
|
557
|
+
return result;
|
|
558
|
+
}
|
|
559
|
+
function isRecord(value) {
|
|
560
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
export {
|
|
564
|
+
computePluginActionSetVersion,
|
|
565
|
+
digestPluginGameplayFrame,
|
|
566
|
+
DREAMBOARD_PLUGIN_PROTOCOL,
|
|
567
|
+
DREAMBOARD_PLUGIN_PROTOCOL_VERSION,
|
|
568
|
+
RuntimeJsonSchema,
|
|
569
|
+
HostToPluginEnvelopeSchema,
|
|
570
|
+
PluginProtocolFrameSchema,
|
|
571
|
+
PluginProtocolStepSchema,
|
|
572
|
+
PluginProtocolTapeSchema,
|
|
573
|
+
materializePluginGameplayFrame
|
|
574
|
+
};
|
|
575
|
+
//# sourceMappingURL=chunk-5IHU5CUK.js.map
|