@fzgame/kit 0.0.0-stage → 0.2.0
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/LICENSE +15 -0
- package/README.md +182 -2
- package/dist/index.cjs +435 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +127 -0
- package/dist/index.d.ts +127 -0
- package/dist/index.js +395 -0
- package/dist/index.js.map +1 -0
- package/package.json +62 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/lifecycle.ts","../src/kit.ts"],"sourcesContent":["export {\n createKit,\n FzGameKit,\n DEFAULT_TIMEOUT_MS,\n KitApiError,\n KitTimeoutError,\n EDITOR_SOURCE,\n HOST_SOURCE,\n KIT_SOURCE,\n postEditorSave,\n onHostInit,\n readQueryConfig,\n readFormSchema,\n isPreviewFlag,\n} from './kit'\nexport type {\n KitOptions,\n EmitType,\n GameInstancePayload,\n PlaySessionPayload,\n EditorSaveMessage,\n KitDebugMessage,\n} from './kit'\nexport {\n emptySnapshot,\n LIFECYCLE_EVENTS,\n PLAY_SESSION_STATUSES,\n} from './lifecycle'\nexport type { LifecycleEvent, Snapshot, PlaySessionStatusName } from './lifecycle'\n","export const PLAY_SESSION_STATUSES = [\n 'CREATED',\n 'READY',\n 'PLAYING',\n 'PAUSED',\n 'FINISHED',\n 'ABORTED',\n 'EXPIRED',\n] as const\n\nexport type PlaySessionStatusName = (typeof PLAY_SESSION_STATUSES)[number]\n\n/**\n * Event names the runtime `emit` route acts on. Mirrors `LIFECYCLE_EVENTS` in\n * `apps/server/src/game/lifecycle.ts` — the server spec compares the two lists, so\n * keep the members and their order identical when either side changes.\n */\nexport const LIFECYCLE_EVENTS = [\n 'ready',\n 'start',\n 'pause',\n 'finish',\n 'abort',\n 'score',\n 'snapshot',\n] as const\n\nexport type LifecycleEvent = (typeof LIFECYCLE_EVENTS)[number]\n\nexport type Snapshot = {\n status: PlaySessionStatusName\n score: number | null\n result: unknown\n state: unknown\n}\n\nexport function emptySnapshot(): Snapshot {\n return { status: 'CREATED', score: null, result: null, state: null }\n}\n","import { emptySnapshot, type LifecycleEvent, type Snapshot } from './lifecycle'\n\n/**\n * Event names the server acts on, plus any custom string: an unknown type leaves\n * the status alone and is stored server-side as the session's `lastEvent`. The\n * `(string & {})` member keeps the literals in editor autocomplete while still\n * accepting a free string.\n */\nexport type EmitType = LifecycleEvent | (string & {})\n\nexport type KitOptions = {\n apiUrl?: string\n gameInstanceId?: string\n playerToken?: string\n config?: Record<string, unknown>\n preview?: boolean\n /** Abort a request after this many milliseconds. `0` waits without a deadline. */\n timeoutMs?: number\n}\n\n/** A game's loading screen should not wait on a hung socket, so requests expire by default. */\nexport const DEFAULT_TIMEOUT_MS = 30_000\n\nexport type GameInstancePayload = {\n id: string\n name: string\n overrides?: Record<string, unknown> | null\n resolvedUrl?: string | null\n editorUrl?: string | null\n game?: {\n id: string\n name: string\n slug: string\n entryPointUrl?: string | null\n backendUrl?: string | null\n configSchema?: Record<string, unknown> | null\n }\n}\n\nexport type PlaySessionPayload = {\n id: string\n token: string\n status: Snapshot['status']\n score?: number | null\n result?: unknown\n metadata?: { snapshot?: unknown } | null\n}\n\nexport const KIT_SOURCE = 'fzgame-kit'\n\nexport type KitDebugMessage = {\n source: typeof KIT_SOURCE\n type: 'debug'\n event: string\n payload: unknown\n at: number\n}\n\n/** A credential-looking key never reaches a debug message. */\nconst SECRET_KEY = /(token|secret|password|authorization|api[-_]?key)/i\n\n/**\n * Replace every credential-looking value, then break reference cycles, so the\n * payload survives `postMessage`'s structured clone.\n */\nfunction redact(value: unknown, seen = new WeakSet<object>(), depth = 0): unknown {\n if (depth > 8 || value === null || typeof value !== 'object') return value\n if (seen.has(value)) return '[circular]'\n seen.add(value)\n const out: unknown = Array.isArray(value)\n ? value.map((item) => redact(item, seen, depth + 1))\n : Object.fromEntries(\n Object.entries(value as Record<string, unknown>).map(([key, item]) => [\n key,\n SECRET_KEY.test(key) ? '[redacted]' : redact(item, seen, depth + 1),\n ]),\n )\n // Only a real cycle should collapse: a shared reference is fine to repeat.\n seen.delete(value)\n return out\n}\n\n/** Thrown when the server answers a request with a non-OK status. */\nexport class KitApiError extends Error {\n readonly status: number\n readonly statusText: string\n readonly method: string\n readonly url: string\n /** Parsed response body, or the raw text when it is not JSON. */\n readonly body: unknown\n /** `body.code` when the server sends one. */\n readonly code?: string\n\n constructor(response: Response, body: unknown, method: string, url: string) {\n super(`${method} ${url} failed with ${response.status} ${response.statusText}`)\n this.name = 'KitApiError'\n this.status = response.status\n this.statusText = response.statusText\n this.method = method\n this.url = url\n this.body = body\n const code =\n body && typeof body === 'object' ? (body as Record<string, unknown>).code : undefined\n if (typeof code === 'string') this.code = code\n }\n}\n\n/** Thrown when a request outlives `timeoutMs`. */\nexport class KitTimeoutError extends Error {\n readonly timeoutMs: number\n readonly method: string\n readonly url: string\n\n constructor(timeoutMs: number, method: string, url: string) {\n super(`${method} ${url} did not answer within ${timeoutMs}ms`)\n this.name = 'KitTimeoutError'\n this.timeoutMs = timeoutMs\n this.method = method\n this.url = url\n }\n}\n\nexport class FzGameKit {\n readonly options: Required<\n Pick<KitOptions, 'apiUrl' | 'gameInstanceId' | 'playerToken' | 'timeoutMs' | 'preview'>\n > &\n Pick<KitOptions, 'config'>\n instance: GameInstancePayload | null = null\n session: PlaySessionPayload | null = null\n snapshot: Snapshot = emptySnapshot()\n private injectedConfig: Record<string, unknown>\n private connecting: Promise<PlaySessionPayload> | null = null\n\n constructor(options: KitOptions) {\n const preview = Boolean(options.preview)\n this.options = {\n apiUrl: (options.apiUrl || '').replace(/\\/$/, ''),\n gameInstanceId: options.gameInstanceId || (preview ? 'preview' : ''),\n playerToken: options.playerToken || (preview ? 'preview' : ''),\n timeoutMs: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n config: options.config,\n preview,\n }\n // Validated here and not in createKit, so `new FzGameKit({})` fails at the\n // call that got it wrong instead of at the first request.\n if (\n !preview &&\n (!this.options.apiUrl || !this.options.gameInstanceId || !this.options.playerToken)\n ) {\n throw new Error('FzGameKit requires apiUrl, gameInstanceId, and playerToken')\n }\n this.injectedConfig = options.config ?? readQueryConfig() ?? {}\n }\n\n get preview() {\n return this.options.preview\n }\n\n async load() {\n try {\n if (this.options.preview) {\n this.instance = {\n id: this.options.gameInstanceId,\n name: 'preview',\n overrides: this.injectedConfig,\n }\n this.debug('load', { instance: this.instance, preview: true })\n return this.instance\n }\n this.instance = await this.request<GameInstancePayload>(\n `/pub/game-instances/${this.options.gameInstanceId}`,\n )\n this.debug('load', { instance: this.instance })\n return this.instance\n } catch (error) {\n this.debug('load', { error: errorMessage(error) })\n throw error\n }\n }\n\n async connect() {\n // A game that mounts twice should still create one session, so concurrent\n // callers share the first in-flight POST.\n this.connecting ??= this.startSession().finally(() => {\n this.connecting = null\n })\n return this.connecting\n }\n\n private async startSession() {\n try {\n if (this.options.preview) {\n this.session = previewSession()\n this.hydrate()\n this.debug('connect', { session: this.session, preview: true })\n return this.session\n }\n this.session = await this.request<PlaySessionPayload>(\n '/games/runtime/sessions',\n {\n method: 'POST',\n body: JSON.stringify({\n gameInstanceId: this.options.gameInstanceId,\n playerToken: this.options.playerToken,\n }),\n },\n )\n this.hydrate()\n this.debug('connect', { session: this.session })\n return this.session\n } catch (error) {\n this.debug('connect', { error: errorMessage(error) })\n throw error\n }\n }\n\n async emit(type: EmitType, payload?: Record<string, unknown>) {\n try {\n if (this.options.preview) {\n this.session = this.session ?? previewSession()\n applyLocalEmit(this.session, type, payload)\n this.hydrate()\n this.debug('emit', { type, payload: payload ?? null, session: this.session, preview: true })\n return this.session\n }\n const token = this.requireToken()\n this.session = await this.request<PlaySessionPayload>(\n `/games/runtime/sessions/${token}/emit`,\n {\n method: 'POST',\n body: JSON.stringify({ type, payload }),\n },\n )\n this.hydrate()\n this.debug('emit', { type, payload: payload ?? null, session: this.session })\n return this.session\n } catch (error) {\n this.debug('emit', { type, payload: payload ?? null, error: errorMessage(error) })\n throw error\n }\n }\n\n async setState(state: unknown) {\n try {\n this.snapshot = { ...this.snapshot, state }\n if (this.options.preview) {\n this.session = this.session ?? previewSession()\n this.session.metadata = { snapshot: state }\n this.hydrate()\n this.debug('snapshot', { state, session: this.session, preview: true })\n return this.snapshot\n }\n const token = this.requireToken()\n this.session = await this.request<PlaySessionPayload>(\n `/games/runtime/sessions/${token}/snapshot`,\n {\n method: 'PUT',\n body: JSON.stringify({ state }),\n },\n )\n this.hydrate()\n this.debug('snapshot', { state, session: this.session })\n return this.snapshot\n } catch (error) {\n this.debug('snapshot', { state, error: errorMessage(error) })\n throw error\n }\n }\n\n config(): Record<string, unknown> {\n const schema = readFormSchema(this.instance?.game?.configSchema)\n const defaults = readDefaults(schema)\n return { ...defaults, ...(this.instance?.overrides ?? {}), ...this.injectedConfig }\n }\n\n private hydrate() {\n if (!this.session) return\n const meta = this.session.metadata\n this.snapshot = {\n status: this.session.status,\n score: this.session.score ?? null,\n result: this.session.result ?? null,\n state: meta && typeof meta === 'object' ? meta.snapshot ?? this.snapshot.state : this.snapshot.state,\n }\n }\n\n private requireToken() {\n if (!this.session?.token) {\n throw new Error('Call connect() before emit or setState')\n }\n return this.session.token\n }\n\n private debug(event: string, payload: unknown) {\n const w = typeof globalThis !== 'undefined' ? globalThis.window : undefined\n if (!w?.parent?.postMessage) return\n const message: KitDebugMessage = {\n source: KIT_SOURCE,\n type: 'debug',\n event,\n payload: redact(payload),\n at: Date.now(),\n }\n try {\n w.parent.postMessage(message, '*')\n } catch {\n /* host may be cross-origin or missing */\n }\n }\n\n private async request<T>(path: string, init: RequestInit = {}): Promise<T> {\n const url = `${this.options.apiUrl}${path}`\n const method = init.method ?? 'GET'\n const headers = new Headers(init.headers)\n if (init.body && !headers.has('content-type')) {\n headers.set('content-type', 'application/json')\n }\n const res = await this.fetchWithTimeout(url, { ...init, headers }, method)\n if (!res.ok) {\n throw new KitApiError(res, await readBody(res), method, url)\n }\n return (await res.json()) as T\n }\n\n private async fetchWithTimeout(\n url: string,\n init: RequestInit,\n method: string,\n ): Promise<Response> {\n const { timeoutMs } = this.options\n if (!timeoutMs || timeoutMs <= 0) return fetch(url, init)\n // AbortController rather than AbortSignal.timeout: the kit runs in whatever\n // browser the player has, so it avoids newer signal APIs.\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), timeoutMs)\n try {\n return await fetch(url, { ...init, signal: controller.signal })\n } catch (error) {\n if (controller.signal.aborted) throw new KitTimeoutError(timeoutMs, method, url)\n throw error\n } finally {\n clearTimeout(timer)\n }\n }\n}\n\n/** The error body, when there is one: parsed JSON, raw text, or nothing. */\nasync function readBody(res: Response): Promise<unknown> {\n const text = await res.text()\n if (!text) return undefined\n try {\n return JSON.parse(text) as unknown\n } catch {\n return text\n }\n}\n\nexport function createKit(options: Partial<KitOptions> = {}): FzGameKit {\n const params =\n typeof location !== 'undefined' ? new URLSearchParams(location.search) : new URLSearchParams()\n const preview = options.preview ?? isPreviewFlag(params.get('preview'))\n const apiUrl = options.apiUrl || params.get('apiUrl') || ''\n const gameInstanceId = options.gameInstanceId || params.get('gameInstanceId') || ''\n const playerToken = options.playerToken || params.get('playerToken') || ''\n const config = options.config ?? readQueryConfig()\n return new FzGameKit({\n apiUrl,\n gameInstanceId,\n playerToken,\n config,\n preview,\n timeoutMs: options.timeoutMs,\n })\n}\n\nexport function readQueryConfig(): Record<string, unknown> | undefined {\n if (typeof location === 'undefined') return undefined\n const params = new URLSearchParams(location.search)\n return parseConfigParam(params.get('gameSetting')) ?? parseConfigParam(params.get('config'))\n}\n\nexport function isPreviewFlag(raw: string | null | undefined): boolean {\n if (!raw) return false\n const value = raw.trim().toLowerCase()\n return value === 'true' || value === '1' || value === 'yes'\n}\n\nfunction parseConfigParam(raw: string | null): Record<string, unknown> | undefined {\n if (!raw) return undefined\n try {\n const parsed = JSON.parse(raw) as unknown\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>\n }\n } catch {\n /* ignore invalid config query */\n }\n return undefined\n}\n\nfunction previewSession(): PlaySessionPayload {\n return {\n id: 'preview',\n token: 'preview',\n status: 'CREATED',\n score: null,\n result: null,\n metadata: { snapshot: {} },\n }\n}\n\nfunction applyLocalEmit(\n session: PlaySessionPayload,\n type: EmitType,\n payload?: Record<string, unknown>,\n) {\n if (type === 'ready') session.status = 'READY'\n if (type === 'start') session.status = 'PLAYING'\n if (type === 'pause') session.status = 'PAUSED'\n if (type === 'finish') {\n session.status = 'FINISHED'\n if (typeof payload?.score === 'number') session.score = payload.score\n if (payload && 'result' in payload) session.result = payload.result\n }\n if (type === 'abort') session.status = 'ABORTED'\n if (type === 'score' && typeof payload?.score === 'number') session.score = payload.score\n if (type === 'snapshot') {\n session.metadata = { snapshot: payload?.state ?? payload ?? {} }\n }\n}\n\nfunction errorMessage(error: unknown) {\n return error instanceof Error ? error.message : String(error)\n}\n\nexport function readFormSchema(\n schema: Record<string, unknown> | null | undefined,\n): Record<string, unknown> {\n if (!schema) return {}\n const form = schema.formSchema\n if (form && typeof form === 'object' && !Array.isArray(form)) {\n return form as Record<string, unknown>\n }\n return schema\n}\n\nfunction readDefaults(schema: Record<string, unknown>): Record<string, unknown> {\n const properties = schema.properties\n if (!properties || typeof properties !== 'object') return {}\n const out: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(properties as Record<string, { default?: unknown }>)) {\n if (value && 'default' in value) out[key] = value.default\n }\n return out\n}\n\nexport const EDITOR_SOURCE = 'fzgame-editor'\nexport const HOST_SOURCE = 'fzgame-host'\n\nexport type EditorSaveMessage = {\n source: typeof EDITOR_SOURCE\n type: 'save'\n config: Record<string, unknown>\n}\n\nexport function postEditorSave(config: Record<string, unknown>, target: Window = window.parent) {\n const message: EditorSaveMessage = { source: EDITOR_SOURCE, type: 'save', config }\n target.postMessage(message, '*')\n}\n\nexport function onHostInit(\n handler: (payload: { config?: Record<string, unknown>; configSchema?: unknown; gameInstanceId?: string }) => void,\n) {\n const listener = (event: MessageEvent) => {\n const data = event.data\n if (!data || data.source !== HOST_SOURCE || data.type !== 'init') return\n handler(data)\n }\n window.addEventListener('message', listener)\n return () => window.removeEventListener('message', listener)\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAO,IAAM,wBAAwB;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AASO,IAAM,mBAAmB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAWO,SAAS,gBAA0B;AACxC,SAAO,EAAE,QAAQ,WAAW,OAAO,MAAM,QAAQ,MAAM,OAAO,KAAK;AACrE;;;ACjBO,IAAM,qBAAqB;AA2B3B,IAAM,aAAa;AAW1B,IAAM,aAAa;AAMnB,SAAS,OAAO,OAAgB,OAAO,oBAAI,QAAgB,GAAG,QAAQ,GAAY;AAChF,MAAI,QAAQ,KAAK,UAAU,QAAQ,OAAO,UAAU,SAAU,QAAO;AACrE,MAAI,KAAK,IAAI,KAAK,EAAG,QAAO;AAC5B,OAAK,IAAI,KAAK;AACd,QAAM,MAAe,MAAM,QAAQ,KAAK,IACpC,MAAM,IAAI,CAAC,SAAS,OAAO,MAAM,MAAM,QAAQ,CAAC,CAAC,IACjD,OAAO;AAAA,IACL,OAAO,QAAQ,KAAgC,EAAE,IAAI,CAAC,CAAC,KAAK,IAAI,MAAM;AAAA,MACpE;AAAA,MACA,WAAW,KAAK,GAAG,IAAI,eAAe,OAAO,MAAM,MAAM,QAAQ,CAAC;AAAA,IACpE,CAAC;AAAA,EACH;AAEJ,OAAK,OAAO,KAAK;AACjB,SAAO;AACT;AAGO,IAAM,cAAN,cAA0B,MAAM;AAAA,EAUrC,YAAY,UAAoB,MAAe,QAAgB,KAAa;AAC1E,UAAM,GAAG,MAAM,IAAI,GAAG,gBAAgB,SAAS,MAAM,IAAI,SAAS,UAAU,EAAE;AAVhF,wBAAS;AACT,wBAAS;AACT,wBAAS;AACT,wBAAS;AAET;AAAA,wBAAS;AAET;AAAA,wBAAS;AAIP,SAAK,OAAO;AACZ,SAAK,SAAS,SAAS;AACvB,SAAK,aAAa,SAAS;AAC3B,SAAK,SAAS;AACd,SAAK,MAAM;AACX,SAAK,OAAO;AACZ,UAAM,OACJ,QAAQ,OAAO,SAAS,WAAY,KAAiC,OAAO;AAC9E,QAAI,OAAO,SAAS,SAAU,MAAK,OAAO;AAAA,EAC5C;AACF;AAGO,IAAM,kBAAN,cAA8B,MAAM;AAAA,EAKzC,YAAY,WAAmB,QAAgB,KAAa;AAC1D,UAAM,GAAG,MAAM,IAAI,GAAG,0BAA0B,SAAS,IAAI;AAL/D,wBAAS;AACT,wBAAS;AACT,wBAAS;AAIP,SAAK,OAAO;AACZ,SAAK,YAAY;AACjB,SAAK,SAAS;AACd,SAAK,MAAM;AAAA,EACb;AACF;AAEO,IAAM,YAAN,MAAgB;AAAA,EAWrB,YAAY,SAAqB;AAVjC,wBAAS;AAIT,oCAAuC;AACvC,mCAAqC;AACrC,oCAAqB,cAAc;AACnC,wBAAQ;AACR,wBAAQ,cAAiD;AAGvD,UAAM,UAAU,QAAQ,QAAQ,OAAO;AACvC,SAAK,UAAU;AAAA,MACb,SAAS,QAAQ,UAAU,IAAI,QAAQ,OAAO,EAAE;AAAA,MAChD,gBAAgB,QAAQ,mBAAmB,UAAU,YAAY;AAAA,MACjE,aAAa,QAAQ,gBAAgB,UAAU,YAAY;AAAA,MAC3D,WAAW,QAAQ,aAAa;AAAA,MAChC,QAAQ,QAAQ;AAAA,MAChB;AAAA,IACF;AAGA,QACE,CAAC,YACA,CAAC,KAAK,QAAQ,UAAU,CAAC,KAAK,QAAQ,kBAAkB,CAAC,KAAK,QAAQ,cACvE;AACA,YAAM,IAAI,MAAM,4DAA4D;AAAA,IAC9E;AACA,SAAK,iBAAiB,QAAQ,UAAU,gBAAgB,KAAK,CAAC;AAAA,EAChE;AAAA,EAEA,IAAI,UAAU;AACZ,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA,EAEA,MAAM,OAAO;AACX,QAAI;AACF,UAAI,KAAK,QAAQ,SAAS;AACxB,aAAK,WAAW;AAAA,UACd,IAAI,KAAK,QAAQ;AAAA,UACjB,MAAM;AAAA,UACN,WAAW,KAAK;AAAA,QAClB;AACA,aAAK,MAAM,QAAQ,EAAE,UAAU,KAAK,UAAU,SAAS,KAAK,CAAC;AAC7D,eAAO,KAAK;AAAA,MACd;AACA,WAAK,WAAW,MAAM,KAAK;AAAA,QACzB,uBAAuB,KAAK,QAAQ,cAAc;AAAA,MACpD;AACA,WAAK,MAAM,QAAQ,EAAE,UAAU,KAAK,SAAS,CAAC;AAC9C,aAAO,KAAK;AAAA,IACd,SAAS,OAAO;AACd,WAAK,MAAM,QAAQ,EAAE,OAAO,aAAa,KAAK,EAAE,CAAC;AACjD,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,UAAU;AAGd,SAAK,eAAL,KAAK,aAAe,KAAK,aAAa,EAAE,QAAQ,MAAM;AACpD,WAAK,aAAa;AAAA,IACpB,CAAC;AACD,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAc,eAAe;AAC3B,QAAI;AACF,UAAI,KAAK,QAAQ,SAAS;AACxB,aAAK,UAAU,eAAe;AAC9B,aAAK,QAAQ;AACb,aAAK,MAAM,WAAW,EAAE,SAAS,KAAK,SAAS,SAAS,KAAK,CAAC;AAC9D,eAAO,KAAK;AAAA,MACd;AACA,WAAK,UAAU,MAAM,KAAK;AAAA,QACxB;AAAA,QACA;AAAA,UACE,QAAQ;AAAA,UACR,MAAM,KAAK,UAAU;AAAA,YACnB,gBAAgB,KAAK,QAAQ;AAAA,YAC7B,aAAa,KAAK,QAAQ;AAAA,UAC5B,CAAC;AAAA,QACH;AAAA,MACF;AACA,WAAK,QAAQ;AACb,WAAK,MAAM,WAAW,EAAE,SAAS,KAAK,QAAQ,CAAC;AAC/C,aAAO,KAAK;AAAA,IACd,SAAS,OAAO;AACd,WAAK,MAAM,WAAW,EAAE,OAAO,aAAa,KAAK,EAAE,CAAC;AACpD,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,KAAK,MAAgB,SAAmC;AAC5D,QAAI;AACF,UAAI,KAAK,QAAQ,SAAS;AACxB,aAAK,UAAU,KAAK,WAAW,eAAe;AAC9C,uBAAe,KAAK,SAAS,MAAM,OAAO;AAC1C,aAAK,QAAQ;AACb,aAAK,MAAM,QAAQ,EAAE,MAAM,SAAS,WAAW,MAAM,SAAS,KAAK,SAAS,SAAS,KAAK,CAAC;AAC3F,eAAO,KAAK;AAAA,MACd;AACA,YAAM,QAAQ,KAAK,aAAa;AAChC,WAAK,UAAU,MAAM,KAAK;AAAA,QACxB,2BAA2B,KAAK;AAAA,QAChC;AAAA,UACE,QAAQ;AAAA,UACR,MAAM,KAAK,UAAU,EAAE,MAAM,QAAQ,CAAC;AAAA,QACxC;AAAA,MACF;AACA,WAAK,QAAQ;AACb,WAAK,MAAM,QAAQ,EAAE,MAAM,SAAS,WAAW,MAAM,SAAS,KAAK,QAAQ,CAAC;AAC5E,aAAO,KAAK;AAAA,IACd,SAAS,OAAO;AACd,WAAK,MAAM,QAAQ,EAAE,MAAM,SAAS,WAAW,MAAM,OAAO,aAAa,KAAK,EAAE,CAAC;AACjF,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,SAAS,OAAgB;AAC7B,QAAI;AACF,WAAK,WAAW,EAAE,GAAG,KAAK,UAAU,MAAM;AAC1C,UAAI,KAAK,QAAQ,SAAS;AACxB,aAAK,UAAU,KAAK,WAAW,eAAe;AAC9C,aAAK,QAAQ,WAAW,EAAE,UAAU,MAAM;AAC1C,aAAK,QAAQ;AACb,aAAK,MAAM,YAAY,EAAE,OAAO,SAAS,KAAK,SAAS,SAAS,KAAK,CAAC;AACtE,eAAO,KAAK;AAAA,MACd;AACA,YAAM,QAAQ,KAAK,aAAa;AAChC,WAAK,UAAU,MAAM,KAAK;AAAA,QACxB,2BAA2B,KAAK;AAAA,QAChC;AAAA,UACE,QAAQ;AAAA,UACR,MAAM,KAAK,UAAU,EAAE,MAAM,CAAC;AAAA,QAChC;AAAA,MACF;AACA,WAAK,QAAQ;AACb,WAAK,MAAM,YAAY,EAAE,OAAO,SAAS,KAAK,QAAQ,CAAC;AACvD,aAAO,KAAK;AAAA,IACd,SAAS,OAAO;AACd,WAAK,MAAM,YAAY,EAAE,OAAO,OAAO,aAAa,KAAK,EAAE,CAAC;AAC5D,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,SAAkC;AAChC,UAAM,SAAS,eAAe,KAAK,UAAU,MAAM,YAAY;AAC/D,UAAM,WAAW,aAAa,MAAM;AACpC,WAAO,EAAE,GAAG,UAAU,GAAI,KAAK,UAAU,aAAa,CAAC,GAAI,GAAG,KAAK,eAAe;AAAA,EACpF;AAAA,EAEQ,UAAU;AAChB,QAAI,CAAC,KAAK,QAAS;AACnB,UAAM,OAAO,KAAK,QAAQ;AAC1B,SAAK,WAAW;AAAA,MACd,QAAQ,KAAK,QAAQ;AAAA,MACrB,OAAO,KAAK,QAAQ,SAAS;AAAA,MAC7B,QAAQ,KAAK,QAAQ,UAAU;AAAA,MAC/B,OAAO,QAAQ,OAAO,SAAS,WAAW,KAAK,YAAY,KAAK,SAAS,QAAQ,KAAK,SAAS;AAAA,IACjG;AAAA,EACF;AAAA,EAEQ,eAAe;AACrB,QAAI,CAAC,KAAK,SAAS,OAAO;AACxB,YAAM,IAAI,MAAM,wCAAwC;AAAA,IAC1D;AACA,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA,EAEQ,MAAM,OAAe,SAAkB;AAC7C,UAAM,IAAI,OAAO,eAAe,cAAc,WAAW,SAAS;AAClE,QAAI,CAAC,GAAG,QAAQ,YAAa;AAC7B,UAAM,UAA2B;AAAA,MAC/B,QAAQ;AAAA,MACR,MAAM;AAAA,MACN;AAAA,MACA,SAAS,OAAO,OAAO;AAAA,MACvB,IAAI,KAAK,IAAI;AAAA,IACf;AACA,QAAI;AACF,QAAE,OAAO,YAAY,SAAS,GAAG;AAAA,IACnC,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEA,MAAc,QAAW,MAAc,OAAoB,CAAC,GAAe;AACzE,UAAM,MAAM,GAAG,KAAK,QAAQ,MAAM,GAAG,IAAI;AACzC,UAAM,SAAS,KAAK,UAAU;AAC9B,UAAM,UAAU,IAAI,QAAQ,KAAK,OAAO;AACxC,QAAI,KAAK,QAAQ,CAAC,QAAQ,IAAI,cAAc,GAAG;AAC7C,cAAQ,IAAI,gBAAgB,kBAAkB;AAAA,IAChD;AACA,UAAM,MAAM,MAAM,KAAK,iBAAiB,KAAK,EAAE,GAAG,MAAM,QAAQ,GAAG,MAAM;AACzE,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,IAAI,YAAY,KAAK,MAAM,SAAS,GAAG,GAAG,QAAQ,GAAG;AAAA,IAC7D;AACA,WAAQ,MAAM,IAAI,KAAK;AAAA,EACzB;AAAA,EAEA,MAAc,iBACZ,KACA,MACA,QACmB;AACnB,UAAM,EAAE,UAAU,IAAI,KAAK;AAC3B,QAAI,CAAC,aAAa,aAAa,EAAG,QAAO,MAAM,KAAK,IAAI;AAGxD,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,SAAS;AAC5D,QAAI;AACF,aAAO,MAAM,MAAM,KAAK,EAAE,GAAG,MAAM,QAAQ,WAAW,OAAO,CAAC;AAAA,IAChE,SAAS,OAAO;AACd,UAAI,WAAW,OAAO,QAAS,OAAM,IAAI,gBAAgB,WAAW,QAAQ,GAAG;AAC/E,YAAM;AAAA,IACR,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF;AACF;AAGA,eAAe,SAAS,KAAiC;AACvD,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI;AACF,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,UAAU,UAA+B,CAAC,GAAc;AACtE,QAAM,SACJ,OAAO,aAAa,cAAc,IAAI,gBAAgB,SAAS,MAAM,IAAI,IAAI,gBAAgB;AAC/F,QAAM,UAAU,QAAQ,WAAW,cAAc,OAAO,IAAI,SAAS,CAAC;AACtE,QAAM,SAAS,QAAQ,UAAU,OAAO,IAAI,QAAQ,KAAK;AACzD,QAAM,iBAAiB,QAAQ,kBAAkB,OAAO,IAAI,gBAAgB,KAAK;AACjF,QAAM,cAAc,QAAQ,eAAe,OAAO,IAAI,aAAa,KAAK;AACxE,QAAM,SAAS,QAAQ,UAAU,gBAAgB;AACjD,SAAO,IAAI,UAAU;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,QAAQ;AAAA,EACrB,CAAC;AACH;AAEO,SAAS,kBAAuD;AACrE,MAAI,OAAO,aAAa,YAAa,QAAO;AAC5C,QAAM,SAAS,IAAI,gBAAgB,SAAS,MAAM;AAClD,SAAO,iBAAiB,OAAO,IAAI,aAAa,CAAC,KAAK,iBAAiB,OAAO,IAAI,QAAQ,CAAC;AAC7F;AAEO,SAAS,cAAc,KAAyC;AACrE,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,QAAQ,IAAI,KAAK,EAAE,YAAY;AACrC,SAAO,UAAU,UAAU,UAAU,OAAO,UAAU;AACxD;AAEA,SAAS,iBAAiB,KAAyD;AACjF,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,QAAI,UAAU,OAAO,WAAW,YAAY,CAAC,MAAM,QAAQ,MAAM,GAAG;AAClE,aAAO;AAAA,IACT;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAEA,SAAS,iBAAqC;AAC5C,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,UAAU,EAAE,UAAU,CAAC,EAAE;AAAA,EAC3B;AACF;AAEA,SAAS,eACP,SACA,MACA,SACA;AACA,MAAI,SAAS,QAAS,SAAQ,SAAS;AACvC,MAAI,SAAS,QAAS,SAAQ,SAAS;AACvC,MAAI,SAAS,QAAS,SAAQ,SAAS;AACvC,MAAI,SAAS,UAAU;AACrB,YAAQ,SAAS;AACjB,QAAI,OAAO,SAAS,UAAU,SAAU,SAAQ,QAAQ,QAAQ;AAChE,QAAI,WAAW,YAAY,QAAS,SAAQ,SAAS,QAAQ;AAAA,EAC/D;AACA,MAAI,SAAS,QAAS,SAAQ,SAAS;AACvC,MAAI,SAAS,WAAW,OAAO,SAAS,UAAU,SAAU,SAAQ,QAAQ,QAAQ;AACpF,MAAI,SAAS,YAAY;AACvB,YAAQ,WAAW,EAAE,UAAU,SAAS,SAAS,WAAW,CAAC,EAAE;AAAA,EACjE;AACF;AAEA,SAAS,aAAa,OAAgB;AACpC,SAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC9D;AAEO,SAAS,eACd,QACyB;AACzB,MAAI,CAAC,OAAQ,QAAO,CAAC;AACrB,QAAM,OAAO,OAAO;AACpB,MAAI,QAAQ,OAAO,SAAS,YAAY,CAAC,MAAM,QAAQ,IAAI,GAAG;AAC5D,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,aAAa,QAA0D;AAC9E,QAAM,aAAa,OAAO;AAC1B,MAAI,CAAC,cAAc,OAAO,eAAe,SAAU,QAAO,CAAC;AAC3D,QAAM,MAA+B,CAAC;AACtC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,UAAmD,GAAG;AAC9F,QAAI,SAAS,aAAa,MAAO,KAAI,GAAG,IAAI,MAAM;AAAA,EACpD;AACA,SAAO;AACT;AAEO,IAAM,gBAAgB;AACtB,IAAM,cAAc;AAQpB,SAAS,eAAe,QAAiC,SAAiB,OAAO,QAAQ;AAC9F,QAAM,UAA6B,EAAE,QAAQ,eAAe,MAAM,QAAQ,OAAO;AACjF,SAAO,YAAY,SAAS,GAAG;AACjC;AAEO,SAAS,WACd,SACA;AACA,QAAM,WAAW,CAAC,UAAwB;AACxC,UAAM,OAAO,MAAM;AACnB,QAAI,CAAC,QAAQ,KAAK,WAAW,eAAe,KAAK,SAAS,OAAQ;AAClE,YAAQ,IAAI;AAAA,EACd;AACA,SAAO,iBAAiB,WAAW,QAAQ;AAC3C,SAAO,MAAM,OAAO,oBAAoB,WAAW,QAAQ;AAC7D;","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
declare const PLAY_SESSION_STATUSES: readonly ["CREATED", "READY", "PLAYING", "PAUSED", "FINISHED", "ABORTED", "EXPIRED"];
|
|
2
|
+
type PlaySessionStatusName = (typeof PLAY_SESSION_STATUSES)[number];
|
|
3
|
+
/**
|
|
4
|
+
* Event names the runtime `emit` route acts on. Mirrors `LIFECYCLE_EVENTS` in
|
|
5
|
+
* `apps/server/src/game/lifecycle.ts` — the server spec compares the two lists, so
|
|
6
|
+
* keep the members and their order identical when either side changes.
|
|
7
|
+
*/
|
|
8
|
+
declare const LIFECYCLE_EVENTS: readonly ["ready", "start", "pause", "finish", "abort", "score", "snapshot"];
|
|
9
|
+
type LifecycleEvent = (typeof LIFECYCLE_EVENTS)[number];
|
|
10
|
+
type Snapshot = {
|
|
11
|
+
status: PlaySessionStatusName;
|
|
12
|
+
score: number | null;
|
|
13
|
+
result: unknown;
|
|
14
|
+
state: unknown;
|
|
15
|
+
};
|
|
16
|
+
declare function emptySnapshot(): Snapshot;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Event names the server acts on, plus any custom string: an unknown type leaves
|
|
20
|
+
* the status alone and is stored server-side as the session's `lastEvent`. The
|
|
21
|
+
* `(string & {})` member keeps the literals in editor autocomplete while still
|
|
22
|
+
* accepting a free string.
|
|
23
|
+
*/
|
|
24
|
+
type EmitType = LifecycleEvent | (string & {});
|
|
25
|
+
type KitOptions = {
|
|
26
|
+
apiUrl?: string;
|
|
27
|
+
gameInstanceId?: string;
|
|
28
|
+
playerToken?: string;
|
|
29
|
+
config?: Record<string, unknown>;
|
|
30
|
+
preview?: boolean;
|
|
31
|
+
/** Abort a request after this many milliseconds. `0` waits without a deadline. */
|
|
32
|
+
timeoutMs?: number;
|
|
33
|
+
};
|
|
34
|
+
/** A game's loading screen should not wait on a hung socket, so requests expire by default. */
|
|
35
|
+
declare const DEFAULT_TIMEOUT_MS = 30000;
|
|
36
|
+
type GameInstancePayload = {
|
|
37
|
+
id: string;
|
|
38
|
+
name: string;
|
|
39
|
+
overrides?: Record<string, unknown> | null;
|
|
40
|
+
resolvedUrl?: string | null;
|
|
41
|
+
editorUrl?: string | null;
|
|
42
|
+
game?: {
|
|
43
|
+
id: string;
|
|
44
|
+
name: string;
|
|
45
|
+
slug: string;
|
|
46
|
+
entryPointUrl?: string | null;
|
|
47
|
+
backendUrl?: string | null;
|
|
48
|
+
configSchema?: Record<string, unknown> | null;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
type PlaySessionPayload = {
|
|
52
|
+
id: string;
|
|
53
|
+
token: string;
|
|
54
|
+
status: Snapshot['status'];
|
|
55
|
+
score?: number | null;
|
|
56
|
+
result?: unknown;
|
|
57
|
+
metadata?: {
|
|
58
|
+
snapshot?: unknown;
|
|
59
|
+
} | null;
|
|
60
|
+
};
|
|
61
|
+
declare const KIT_SOURCE = "fzgame-kit";
|
|
62
|
+
type KitDebugMessage = {
|
|
63
|
+
source: typeof KIT_SOURCE;
|
|
64
|
+
type: 'debug';
|
|
65
|
+
event: string;
|
|
66
|
+
payload: unknown;
|
|
67
|
+
at: number;
|
|
68
|
+
};
|
|
69
|
+
/** Thrown when the server answers a request with a non-OK status. */
|
|
70
|
+
declare class KitApiError extends Error {
|
|
71
|
+
readonly status: number;
|
|
72
|
+
readonly statusText: string;
|
|
73
|
+
readonly method: string;
|
|
74
|
+
readonly url: string;
|
|
75
|
+
/** Parsed response body, or the raw text when it is not JSON. */
|
|
76
|
+
readonly body: unknown;
|
|
77
|
+
/** `body.code` when the server sends one. */
|
|
78
|
+
readonly code?: string;
|
|
79
|
+
constructor(response: Response, body: unknown, method: string, url: string);
|
|
80
|
+
}
|
|
81
|
+
/** Thrown when a request outlives `timeoutMs`. */
|
|
82
|
+
declare class KitTimeoutError extends Error {
|
|
83
|
+
readonly timeoutMs: number;
|
|
84
|
+
readonly method: string;
|
|
85
|
+
readonly url: string;
|
|
86
|
+
constructor(timeoutMs: number, method: string, url: string);
|
|
87
|
+
}
|
|
88
|
+
declare class FzGameKit {
|
|
89
|
+
readonly options: Required<Pick<KitOptions, 'apiUrl' | 'gameInstanceId' | 'playerToken' | 'timeoutMs' | 'preview'>> & Pick<KitOptions, 'config'>;
|
|
90
|
+
instance: GameInstancePayload | null;
|
|
91
|
+
session: PlaySessionPayload | null;
|
|
92
|
+
snapshot: Snapshot;
|
|
93
|
+
private injectedConfig;
|
|
94
|
+
private connecting;
|
|
95
|
+
constructor(options: KitOptions);
|
|
96
|
+
get preview(): boolean;
|
|
97
|
+
load(): Promise<GameInstancePayload>;
|
|
98
|
+
connect(): Promise<PlaySessionPayload>;
|
|
99
|
+
private startSession;
|
|
100
|
+
emit(type: EmitType, payload?: Record<string, unknown>): Promise<PlaySessionPayload>;
|
|
101
|
+
setState(state: unknown): Promise<Snapshot>;
|
|
102
|
+
config(): Record<string, unknown>;
|
|
103
|
+
private hydrate;
|
|
104
|
+
private requireToken;
|
|
105
|
+
private debug;
|
|
106
|
+
private request;
|
|
107
|
+
private fetchWithTimeout;
|
|
108
|
+
}
|
|
109
|
+
declare function createKit(options?: Partial<KitOptions>): FzGameKit;
|
|
110
|
+
declare function readQueryConfig(): Record<string, unknown> | undefined;
|
|
111
|
+
declare function isPreviewFlag(raw: string | null | undefined): boolean;
|
|
112
|
+
declare function readFormSchema(schema: Record<string, unknown> | null | undefined): Record<string, unknown>;
|
|
113
|
+
declare const EDITOR_SOURCE = "fzgame-editor";
|
|
114
|
+
declare const HOST_SOURCE = "fzgame-host";
|
|
115
|
+
type EditorSaveMessage = {
|
|
116
|
+
source: typeof EDITOR_SOURCE;
|
|
117
|
+
type: 'save';
|
|
118
|
+
config: Record<string, unknown>;
|
|
119
|
+
};
|
|
120
|
+
declare function postEditorSave(config: Record<string, unknown>, target?: Window): void;
|
|
121
|
+
declare function onHostInit(handler: (payload: {
|
|
122
|
+
config?: Record<string, unknown>;
|
|
123
|
+
configSchema?: unknown;
|
|
124
|
+
gameInstanceId?: string;
|
|
125
|
+
}) => void): () => void;
|
|
126
|
+
|
|
127
|
+
export { DEFAULT_TIMEOUT_MS, EDITOR_SOURCE, type EditorSaveMessage, type EmitType, FzGameKit, type GameInstancePayload, HOST_SOURCE, KIT_SOURCE, KitApiError, type KitDebugMessage, type KitOptions, KitTimeoutError, LIFECYCLE_EVENTS, type LifecycleEvent, PLAY_SESSION_STATUSES, type PlaySessionPayload, type PlaySessionStatusName, type Snapshot, createKit, emptySnapshot, isPreviewFlag, onHostInit, postEditorSave, readFormSchema, readQueryConfig };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
declare const PLAY_SESSION_STATUSES: readonly ["CREATED", "READY", "PLAYING", "PAUSED", "FINISHED", "ABORTED", "EXPIRED"];
|
|
2
|
+
type PlaySessionStatusName = (typeof PLAY_SESSION_STATUSES)[number];
|
|
3
|
+
/**
|
|
4
|
+
* Event names the runtime `emit` route acts on. Mirrors `LIFECYCLE_EVENTS` in
|
|
5
|
+
* `apps/server/src/game/lifecycle.ts` — the server spec compares the two lists, so
|
|
6
|
+
* keep the members and their order identical when either side changes.
|
|
7
|
+
*/
|
|
8
|
+
declare const LIFECYCLE_EVENTS: readonly ["ready", "start", "pause", "finish", "abort", "score", "snapshot"];
|
|
9
|
+
type LifecycleEvent = (typeof LIFECYCLE_EVENTS)[number];
|
|
10
|
+
type Snapshot = {
|
|
11
|
+
status: PlaySessionStatusName;
|
|
12
|
+
score: number | null;
|
|
13
|
+
result: unknown;
|
|
14
|
+
state: unknown;
|
|
15
|
+
};
|
|
16
|
+
declare function emptySnapshot(): Snapshot;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Event names the server acts on, plus any custom string: an unknown type leaves
|
|
20
|
+
* the status alone and is stored server-side as the session's `lastEvent`. The
|
|
21
|
+
* `(string & {})` member keeps the literals in editor autocomplete while still
|
|
22
|
+
* accepting a free string.
|
|
23
|
+
*/
|
|
24
|
+
type EmitType = LifecycleEvent | (string & {});
|
|
25
|
+
type KitOptions = {
|
|
26
|
+
apiUrl?: string;
|
|
27
|
+
gameInstanceId?: string;
|
|
28
|
+
playerToken?: string;
|
|
29
|
+
config?: Record<string, unknown>;
|
|
30
|
+
preview?: boolean;
|
|
31
|
+
/** Abort a request after this many milliseconds. `0` waits without a deadline. */
|
|
32
|
+
timeoutMs?: number;
|
|
33
|
+
};
|
|
34
|
+
/** A game's loading screen should not wait on a hung socket, so requests expire by default. */
|
|
35
|
+
declare const DEFAULT_TIMEOUT_MS = 30000;
|
|
36
|
+
type GameInstancePayload = {
|
|
37
|
+
id: string;
|
|
38
|
+
name: string;
|
|
39
|
+
overrides?: Record<string, unknown> | null;
|
|
40
|
+
resolvedUrl?: string | null;
|
|
41
|
+
editorUrl?: string | null;
|
|
42
|
+
game?: {
|
|
43
|
+
id: string;
|
|
44
|
+
name: string;
|
|
45
|
+
slug: string;
|
|
46
|
+
entryPointUrl?: string | null;
|
|
47
|
+
backendUrl?: string | null;
|
|
48
|
+
configSchema?: Record<string, unknown> | null;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
type PlaySessionPayload = {
|
|
52
|
+
id: string;
|
|
53
|
+
token: string;
|
|
54
|
+
status: Snapshot['status'];
|
|
55
|
+
score?: number | null;
|
|
56
|
+
result?: unknown;
|
|
57
|
+
metadata?: {
|
|
58
|
+
snapshot?: unknown;
|
|
59
|
+
} | null;
|
|
60
|
+
};
|
|
61
|
+
declare const KIT_SOURCE = "fzgame-kit";
|
|
62
|
+
type KitDebugMessage = {
|
|
63
|
+
source: typeof KIT_SOURCE;
|
|
64
|
+
type: 'debug';
|
|
65
|
+
event: string;
|
|
66
|
+
payload: unknown;
|
|
67
|
+
at: number;
|
|
68
|
+
};
|
|
69
|
+
/** Thrown when the server answers a request with a non-OK status. */
|
|
70
|
+
declare class KitApiError extends Error {
|
|
71
|
+
readonly status: number;
|
|
72
|
+
readonly statusText: string;
|
|
73
|
+
readonly method: string;
|
|
74
|
+
readonly url: string;
|
|
75
|
+
/** Parsed response body, or the raw text when it is not JSON. */
|
|
76
|
+
readonly body: unknown;
|
|
77
|
+
/** `body.code` when the server sends one. */
|
|
78
|
+
readonly code?: string;
|
|
79
|
+
constructor(response: Response, body: unknown, method: string, url: string);
|
|
80
|
+
}
|
|
81
|
+
/** Thrown when a request outlives `timeoutMs`. */
|
|
82
|
+
declare class KitTimeoutError extends Error {
|
|
83
|
+
readonly timeoutMs: number;
|
|
84
|
+
readonly method: string;
|
|
85
|
+
readonly url: string;
|
|
86
|
+
constructor(timeoutMs: number, method: string, url: string);
|
|
87
|
+
}
|
|
88
|
+
declare class FzGameKit {
|
|
89
|
+
readonly options: Required<Pick<KitOptions, 'apiUrl' | 'gameInstanceId' | 'playerToken' | 'timeoutMs' | 'preview'>> & Pick<KitOptions, 'config'>;
|
|
90
|
+
instance: GameInstancePayload | null;
|
|
91
|
+
session: PlaySessionPayload | null;
|
|
92
|
+
snapshot: Snapshot;
|
|
93
|
+
private injectedConfig;
|
|
94
|
+
private connecting;
|
|
95
|
+
constructor(options: KitOptions);
|
|
96
|
+
get preview(): boolean;
|
|
97
|
+
load(): Promise<GameInstancePayload>;
|
|
98
|
+
connect(): Promise<PlaySessionPayload>;
|
|
99
|
+
private startSession;
|
|
100
|
+
emit(type: EmitType, payload?: Record<string, unknown>): Promise<PlaySessionPayload>;
|
|
101
|
+
setState(state: unknown): Promise<Snapshot>;
|
|
102
|
+
config(): Record<string, unknown>;
|
|
103
|
+
private hydrate;
|
|
104
|
+
private requireToken;
|
|
105
|
+
private debug;
|
|
106
|
+
private request;
|
|
107
|
+
private fetchWithTimeout;
|
|
108
|
+
}
|
|
109
|
+
declare function createKit(options?: Partial<KitOptions>): FzGameKit;
|
|
110
|
+
declare function readQueryConfig(): Record<string, unknown> | undefined;
|
|
111
|
+
declare function isPreviewFlag(raw: string | null | undefined): boolean;
|
|
112
|
+
declare function readFormSchema(schema: Record<string, unknown> | null | undefined): Record<string, unknown>;
|
|
113
|
+
declare const EDITOR_SOURCE = "fzgame-editor";
|
|
114
|
+
declare const HOST_SOURCE = "fzgame-host";
|
|
115
|
+
type EditorSaveMessage = {
|
|
116
|
+
source: typeof EDITOR_SOURCE;
|
|
117
|
+
type: 'save';
|
|
118
|
+
config: Record<string, unknown>;
|
|
119
|
+
};
|
|
120
|
+
declare function postEditorSave(config: Record<string, unknown>, target?: Window): void;
|
|
121
|
+
declare function onHostInit(handler: (payload: {
|
|
122
|
+
config?: Record<string, unknown>;
|
|
123
|
+
configSchema?: unknown;
|
|
124
|
+
gameInstanceId?: string;
|
|
125
|
+
}) => void): () => void;
|
|
126
|
+
|
|
127
|
+
export { DEFAULT_TIMEOUT_MS, EDITOR_SOURCE, type EditorSaveMessage, type EmitType, FzGameKit, type GameInstancePayload, HOST_SOURCE, KIT_SOURCE, KitApiError, type KitDebugMessage, type KitOptions, KitTimeoutError, LIFECYCLE_EVENTS, type LifecycleEvent, PLAY_SESSION_STATUSES, type PlaySessionPayload, type PlaySessionStatusName, type Snapshot, createKit, emptySnapshot, isPreviewFlag, onHostInit, postEditorSave, readFormSchema, readQueryConfig };
|