quantum-forge 2.7.0 → 3.0.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/quantum/QuantumForgeLoader.ts","../../src/quantum/QuantumPropertyManager.ts","../../src/quantum/QuantumRecorder.ts","../../src/quantum/index.ts"],"sourcesContent":["/**\n * Quantum Forge Loader - Lazy loader for Quantum Forge WASM module\n *\n * Defers WASM loading from the critical path while preloading in background\n * so it's ready when needed. If not ready, callers can show loading UI.\n * \n * IMPORTANT: Quantum Forge is built from source and copied to dist/ as\n * quantum-forge-web-api.mjs (not an npm package). Run 'npm run setup' to build.\n */\n\nimport type { LoggerInterface } from \"../logging/Logger\";\n\n// Type for the quantum forge module\ntype QuantumForgeModuleType = typeof import(\"./quantum-forge-api.mjs\");\n\n// Configurable base path for WASM artifacts\nlet wasmBasePath = \"/quantum-forge\";\n\n/**\n * Set the base URL path where Quantum Forge WASM files are served.\n * Default is \"/quantum-forge\" which matches the Vite plugin's serve path.\n * Consumers using the Vite plugin don't need to call this.\n */\nexport function setWasmBasePath(path: string): void {\n wasmBasePath = path.endsWith(\"/\") ? path.slice(0, -1) : path;\n}\n\n/**\n * Select a named WASM build variant (e.g. \"d7n10\").\n * Sugar for `setWasmBasePath(\"/quantum-forge-{name}\")`.\n *\n * Must be called before `ensureLoaded()`. If the module is already loaded,\n * a warning is logged and the call is ignored.\n */\nexport function useQuantumForgeBuild(name: string): void {\n if (isInitialized) {\n logger?.warn?.(\n `useQuantumForgeBuild(\"${name}\") called after module already loaded — ignoring. Call before ensureLoaded().`,\n \"QuantumForgeLoader\",\n );\n return;\n }\n setWasmBasePath(`/quantum-forge-${name}`);\n}\n\n// Cache the module and initialization state\nlet quantumForgeModule: QuantumForgeModuleType | null = null;\nlet initPromise: Promise<void> | null = null;\nlet isInitialized = false;\nlet loadStarted = false;\n\n// Logger reference (set during startBackgroundLoad)\nlet logger: LoggerInterface | undefined;\n\n/**\n * Start loading the WASM module in the background.\n * Call this after the page has rendered (e.g., after DOMContentLoaded or initial paint).\n */\nexport function startBackgroundLoad(loggerRef?: LoggerInterface): void {\n if (loadStarted) return;\n loadStarted = true;\n logger = loggerRef;\n\n // Use requestIdleCallback if available, otherwise setTimeout\n const scheduleLoad = (callback: () => void) => {\n if (typeof requestIdleCallback === \"function\") {\n requestIdleCallback(callback, { timeout: 2000 });\n } else {\n setTimeout(callback, 100);\n }\n };\n\n scheduleLoad(() => {\n logger?.info?.(\"Starting background Quantum Forge load\", \"QuantumForgeLoader\");\n // Trigger the load but don't await - let it happen in background\n ensureLoaded().catch((err) => {\n logger?.warn?.(\n `Background Quantum Forge load failed: ${err?.message ?? err}`,\n \"QuantumForgeLoader\",\n );\n });\n });\n}\n\n/**\n * Ensure Quantum Forge is loaded and initialized.\n * Returns a promise that resolves when the module is ready.\n * Can be called multiple times - will return the same promise.\n */\nexport async function ensureLoaded(): Promise<void> {\n if (isInitialized) return;\n\n if (initPromise) {\n await initPromise;\n return;\n }\n\n initPromise = (async () => {\n const startTime = performance.now();\n logger?.info?.(\"Loading Quantum Forge WASM module...\", \"QuantumForgeLoader\");\n\n // Dynamic import of Quantum Forge WASM module from the configured base path\n const modulePath = `${wasmBasePath}/quantum-forge-web-api.mjs`;\n const mod = (await import(/* @vite-ignore */ modulePath)) as QuantumForgeModuleType;\n quantumForgeModule = mod;\n\n // Initialize the WASM, routing stderr through the logger\n await mod.QuantumForge.initialize({\n printErr: (text: string) => logger?.warn?.(text, \"QuantumForge/WASM\"),\n });\n\n const version = mod.QuantumForge.getVersion();\n const maxDim = mod.QuantumForge.getMaxDimension();\n const maxQudits = mod.QuantumForge.getMaxQudits();\n const elapsed = (performance.now() - startTime).toFixed(0);\n\n logger?.info?.(\n `Quantum Forge v${version} ready in ${elapsed}ms (max dim: ${maxDim}, max qudits: ${maxQudits})`,\n \"QuantumForgeLoader\",\n );\n\n console.log(\n \"%c\\u269B Powered by Quantum Forge %c quantumnative.io \",\n \"background: #6366f1; color: white; padding: 2px 6px; border-radius: 3px 0 0 3px; font-weight: bold;\",\n \"background: #1e1b4b; color: #c7d2fe; padding: 2px 6px; border-radius: 0 3px 3px 0;\",\n );\n\n isInitialized = true;\n })();\n\n // Handle errors by clearing the promise so retry is possible\n initPromise.catch(() => {\n initPromise = null;\n });\n\n await initPromise;\n}\n\n/**\n * Check if Quantum Forge is ready to use (non-blocking).\n */\nexport function isReady(): boolean {\n return isInitialized;\n}\n\n/**\n * Get the loaded module. Throws if not loaded.\n * For synchronous access after ensuring it's loaded.\n */\nexport function getModule(): typeof import(\"./quantum-forge-api.mjs\") {\n if (!quantumForgeModule || !isInitialized) {\n throw new Error(\"QuantumForge not loaded. Call ensureLoaded() first and await it.\");\n }\n return quantumForgeModule;\n}\n\n/**\n * Get the QuantumForge class from the loaded module.\n */\nexport function getQuantumForge(): typeof import(\"./quantum-forge-api.mjs\").QuantumForge {\n return getModule().QuantumForge;\n}\n\n/**\n * Convenience re-exports for common operations.\n * These will throw if module not loaded.\n */\nexport function getVersion(): string {\n return getQuantumForge().getVersion();\n}\n\nexport function getMaxDimension(): number {\n return getQuantumForge().getMaxDimension();\n}\n\nexport function getMaxQudits(): number {\n return getQuantumForge().getMaxQudits();\n}\n\nexport function getMaxStateSize(): number {\n return getQuantumForge().getMaxStateSize();\n}\n\n/**\n * Get the WASM memory bytes (for analytics).\n */\nexport function getWasmMemoryBytes(): number | null {\n if (!isInitialized) return null;\n try {\n const qf = getQuantumForge() as any;\n return typeof qf.getMemoryBytes === \"function\" ? qf.getMemoryBytes() : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Get the required attribution text for display in your application.\n * Include this in a user-visible location (credits screen, about page, etc.).\n */\nexport function getAttribution(): string {\n return \"Powered by Quantum Forge \\u2014 \\u00A9 Quantum Native \\u2014 quantumnative.io\";\n}\n\n/**\n * Register the Quantum Forge service worker for offline WASM caching.\n * Call once from your game controller after page load.\n * The SW caches WASM artifacts on first fetch so subsequent loads work offline.\n *\n * @param swPath - Path to the service worker file. Default: \"/quantum-forge-sw.js\"\n */\nexport async function registerServiceWorker(\n swPath = \"/quantum-forge-sw.js\",\n): Promise<ServiceWorkerRegistration | null> {\n if (!(\"serviceWorker\" in navigator)) return null;\n try {\n const reg = await navigator.serviceWorker.register(swPath);\n logger?.info?.(`Service worker registered (scope: ${reg.scope})`, \"QuantumForgeLoader\");\n return reg;\n } catch (err) {\n logger?.warn?.(\n `Service worker registration failed: ${err instanceof Error ? err.message : err}`,\n \"QuantumForgeLoader\",\n );\n return null;\n }\n}\n","/**\n * QuantumPropertyManager — manages quantum property lifecycles.\n *\n * Handles the common pattern of acquiring, pooling, and releasing WASM\n * QuantumProperty handles. Games either extend this class or compose it\n * to add game-specific quantum operations via getModule().\n *\n * Property pooling is critical: measured/removed properties are recycled\n * to avoid growing the tensor product and hitting qudit limits.\n *\n * For opt-in operation recording, attach a QuantumRecorder via setRecorder().\n */\n\nimport { getModule } from \"./QuantumForgeLoader\";\nimport type { LoggerInterface } from \"../logging/Logger\";\nimport type { QuantumProperty as QFProperty } from \"./quantum-forge-api.mjs\";\n\nexport interface PredicateSpec {\n property: QFProperty;\n value: number;\n isEqual: boolean;\n}\n\nexport interface QuantumRecorderHook {\n onAcquire?(prop: QFProperty): void;\n onRelease?(prop: QFProperty, value: number): void;\n onSetProperty?(id: string, prop: QFProperty): void;\n onDeleteProperty?(id: string): void;\n}\n\nexport class QuantumPropertyManager {\n readonly dimension: number;\n private properties: Map<string, QFProperty> = new Map();\n private pool: QFProperty[] = [];\n protected logger?: LoggerInterface;\n private _recorder?: QuantumRecorderHook;\n\n constructor(options: { dimension?: number; logger?: LoggerInterface } = {}) {\n this.dimension = options.dimension ?? 2;\n this.logger = options.logger;\n }\n\n // -- Recorder hook --\n\n /** Attach an optional recorder for operation logging. */\n setRecorder(recorder: QuantumRecorderHook | undefined): void {\n this._recorder = recorder;\n }\n\n /** Get the currently attached recorder, if any. */\n getRecorder(): QuantumRecorderHook | undefined {\n return this._recorder;\n }\n\n // -- Property lifecycle --\n\n /**\n * Get a property at |0⟩ — reuses a pooled one if available,\n * otherwise creates a fresh standalone property.\n */\n acquireProperty(): QFProperty {\n let prop: QFProperty;\n if (this.pool.length > 0) {\n prop = this.pool.pop()!;\n } else {\n prop = getModule().QuantumForge.createQuantumProperty(this.dimension);\n }\n this._recorder?.onAcquire?.(prop);\n return prop;\n }\n\n /**\n * Return a property to the pool after resetting it to |0⟩.\n * Uses the `reset` primitive which applies non-fractional cycles —\n * correct for all dimensions (no superposition created).\n */\n releaseProperty(prop: QFProperty, measuredValue: number): void {\n this._recorder?.onRelease?.(prop, measuredValue);\n getModule().reset(prop, measuredValue);\n this.pool.push(prop);\n }\n\n // -- ID mapping --\n\n setProperty(id: string, prop: QFProperty): void {\n this._recorder?.onSetProperty?.(id, prop);\n this.properties.set(id, prop);\n }\n\n getProperty(id: string): QFProperty | undefined {\n return this.properties.get(id);\n }\n\n deleteProperty(id: string): void {\n this._recorder?.onDeleteProperty?.(id);\n this.properties.delete(id);\n }\n\n hasProperty(id: string): boolean {\n return this.properties.has(id);\n }\n\n // -- Public operations --\n\n /**\n * Remove a property by ID: measure it, pool the handle, delete the mapping.\n */\n removeProperty(id: string): void {\n const prop = this.properties.get(id);\n if (prop) {\n const [value] = getModule().measure_properties([prop]);\n this.releaseProperty(prop, value);\n }\n this.deleteProperty(id);\n }\n\n /** Clear all properties, pool, and recorder. */\n clear(): void {\n this.properties.clear();\n this.pool = [];\n }\n\n get size(): number {\n return this.properties.size;\n }\n\n get poolSize(): number {\n return this.pool.length;\n }\n\n // -- WASM module access --\n\n getModule(): ReturnType<typeof getModule> {\n return getModule();\n }\n\n // -- Internal access for QuantumRecorder replay --\n\n /** @internal — used by QuantumRecorder.replayLog() to restore pool state. */\n _setPool(pool: QFProperty[]): void {\n this.pool = pool;\n }\n\n /** @internal — used by QuantumRecorder to enumerate live handles. */\n _getProperties(): Map<string, QFProperty> {\n return this.properties;\n }\n\n /** @internal — used by QuantumRecorder to enumerate pool handles. */\n _getPool(): QFProperty[] {\n return this.pool;\n }\n}\n","/**\n * QuantumRecorder — opt-in recording and replay of quantum operations.\n *\n * Attach to a QuantumPropertyManager via `manager.setRecorder(recorder)`.\n * When recording is active, lifecycle hooks log every state-mutating\n * operation. The log can be replayed via replayLog() to recreate\n * identical quantum state — measurements are forced to their recorded\n * outcomes using forced_measure_properties.\n *\n * For gate recording, call wrapGate() around each WASM gate call.\n */\n\nimport { getModule } from \"./QuantumForgeLoader\";\nimport type { QuantumPropertyManager, QuantumRecorderHook } from \"./QuantumPropertyManager\";\nimport type { QuantumOperation, SerializedPredicate } from \"./QuantumOperationLog\";\nimport type { QuantumProperty as QFProperty, Predicate as QFPredicate } from \"./quantum-forge-api.mjs\";\n\nexport interface PredicateSpec {\n property: QFProperty;\n value: number;\n isEqual: boolean;\n}\n\nexport class QuantumRecorder implements QuantumRecorderHook {\n private _recording = false;\n private _log: QuantumOperation[] = [];\n private _handleToIndex: Map<QFProperty, number> = new Map();\n private _nextIndex = 0;\n private readonly _manager: QuantumPropertyManager;\n\n constructor(manager: QuantumPropertyManager) {\n this._manager = manager;\n }\n\n // -- QuantumRecorderHook implementation --\n\n onAcquire(prop: QFProperty): void {\n if (!this._recording) return;\n const index = this._nextIndex++;\n this._handleToIndex.set(prop, index);\n this._log.push({ op: \"acquire\", index });\n }\n\n onRelease(prop: QFProperty, value: number): void {\n if (!this._recording) return;\n const index = this._handleToIndex.get(prop);\n if (index !== undefined) {\n this._log.push({ op: \"release\", index, value });\n }\n }\n\n onSetProperty(id: string, prop: QFProperty): void {\n if (!this._recording) return;\n const index = this._handleToIndex.get(prop);\n if (index !== undefined) {\n this._log.push({ op: \"assign\", index, id });\n }\n }\n\n onDeleteProperty(id: string): void {\n if (!this._recording) return;\n this._log.push({ op: \"unassign\", id });\n }\n\n // -- Gate recording --\n\n /**\n * Build WASM predicate objects from PredicateSpec array.\n */\n buildWasmPredicates(specs: PredicateSpec[]): QFPredicate[] {\n return specs.map((s) =>\n s.isEqual ? s.property.is(s.value) : s.property.is_not(s.value),\n );\n }\n\n /**\n * Serialize predicates for the operation log.\n */\n serializePredicates(specs: PredicateSpec[]): SerializedPredicate[] | undefined {\n if (specs.length === 0) return undefined;\n return specs.map((s) => {\n const index = this._handleToIndex.get(s.property);\n return {\n propertyIndex: index ?? -1,\n value: s.value,\n isEqual: s.isEqual,\n };\n });\n }\n\n /**\n * Record a gate operation. Call this when recording is active\n * and you want to log a gate call for replay.\n */\n recordOp(op: QuantumOperation): void {\n if (!this._recording) return;\n this._log.push(op);\n }\n\n /**\n * Get the recorded index for a property handle.\n */\n getIndex(prop: QFProperty): number | undefined {\n return this._handleToIndex.get(prop);\n }\n\n // -- Recording API --\n\n /** Begin recording quantum operations. Resets any existing log. */\n startRecording(): void {\n this._recording = true;\n this._log = [];\n this._handleToIndex.clear();\n this._nextIndex = 0;\n\n // Assign indices to all currently-live handles so operations\n // on pre-existing properties are tracked correctly.\n for (const prop of this._manager._getProperties().values()) {\n const index = this._nextIndex++;\n this._handleToIndex.set(prop, index);\n }\n for (const prop of this._manager._getPool()) {\n const index = this._nextIndex++;\n this._handleToIndex.set(prop, index);\n }\n }\n\n /** Stop recording and return the captured log. */\n stopRecording(): QuantumOperation[] {\n this._recording = false;\n return [...this._log];\n }\n\n /** Whether recording is currently active. */\n isRecording(): boolean {\n return this._recording;\n }\n\n /** Get a copy of the current operation log (even while recording). */\n getOperationLog(): QuantumOperation[] {\n return [...this._log];\n }\n\n /**\n * Replay an operation log to recreate quantum state from scratch.\n * Clears all existing state on the manager first. Measurements are\n * forced to their recorded outcomes via forced_measure_properties.\n */\n replayLog(operations: QuantumOperation[]): void {\n // Clear manager state\n this._manager.clear();\n this._recording = false;\n this._log = [];\n this._handleToIndex.clear();\n this._nextIndex = 0;\n\n const module = getModule();\n const dimension = this._manager.dimension;\n const indexToHandle = new Map<number, QFProperty>();\n const replayPool: QFProperty[] = [];\n\n for (const entry of operations) {\n switch (entry.op) {\n case \"acquire\": {\n let prop: QFProperty;\n if (replayPool.length > 0) {\n prop = replayPool.pop()!;\n } else {\n prop = module.QuantumForge.createQuantumProperty(dimension);\n }\n indexToHandle.set(entry.index, prop);\n break;\n }\n\n case \"release\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n module.reset(prop, entry.value);\n replayPool.push(prop);\n }\n break;\n }\n\n case \"assign\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n this._manager._getProperties().set(entry.id, prop);\n }\n break;\n }\n\n case \"unassign\": {\n this._manager._getProperties().delete(entry.id);\n break;\n }\n\n case \"cycle\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n if (entry.fraction === 1 && !preds) {\n module.cycle(prop);\n } else {\n module.cycle(prop, entry.fraction, preds);\n }\n }\n break;\n }\n\n case \"shift\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n if (entry.fraction === 1 && !preds) {\n module.shift(prop);\n } else {\n module.shift(prop, entry.fraction, preds);\n }\n }\n break;\n }\n\n case \"i_swap\": {\n const prop1 = indexToHandle.get(entry.index1);\n const prop2 = indexToHandle.get(entry.index2);\n if (prop1 && prop2) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n module.i_swap(prop1, prop2, entry.fraction, preds);\n }\n break;\n }\n\n case \"clock\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n module.clock(prop, entry.fraction, preds);\n }\n break;\n }\n\n case \"y\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n if (entry.fraction === 1 && !preds) {\n module.y(prop);\n } else {\n module.y(prop, entry.fraction, preds);\n }\n }\n break;\n }\n\n case \"hadamard\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n if (entry.fraction === 1 && !preds) {\n module.hadamard(prop);\n } else {\n module.hadamard(prop, entry.fraction, preds);\n }\n }\n break;\n }\n\n case \"inverse_hadamard\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n module.inverse_hadamard(prop, preds);\n }\n break;\n }\n\n case \"swap\": {\n const prop1 = indexToHandle.get(entry.index1);\n const prop2 = indexToHandle.get(entry.index2);\n if (prop1 && prop2) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n module.swap(prop1, prop2, preds);\n }\n break;\n }\n\n case \"phase_rotate\": {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n if (preds) {\n module.phase_rotate(preds, entry.angle);\n }\n break;\n }\n\n case \"measure_predicate\": {\n // During replay, we don't force measure_predicate outcomes —\n // the state should be deterministic from prior forced measurements.\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n if (preds) {\n module.measure_predicate(preds);\n }\n break;\n }\n\n case \"reset\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n module.reset(prop, entry.value);\n }\n break;\n }\n\n case \"measure\": {\n const props = entry.indices.map((i) => indexToHandle.get(i)).filter(Boolean) as QFProperty[];\n if (props.length === entry.indices.length) {\n module.forced_measure_properties(props, entry.outcomes);\n }\n break;\n }\n }\n }\n\n // Restore internal pool from replay pool\n this._manager._setPool(replayPool);\n\n // Rebuild _handleToIndex from indexToHandle for future recording\n this._handleToIndex.clear();\n for (const [index, handle] of indexToHandle) {\n this._handleToIndex.set(handle, index);\n }\n this._nextIndex = operations.reduce((max, op) => {\n if (\"index\" in op && typeof op.index === \"number\") return Math.max(max, op.index + 1);\n if (\"index1\" in op) {\n const dualOp = op as { index1: number; index2: number };\n return Math.max(max, dualOp.index1 + 1, dualOp.index2 + 1);\n }\n if (\"indices\" in op) {\n const measureOp = op as { indices: number[] };\n const maxIdx = Math.max(...measureOp.indices);\n return Math.max(max, maxIdx + 1);\n }\n return max;\n }, 0);\n }\n\n // -- Private helpers --\n\n private _replayPredicates(\n serialized: SerializedPredicate[] | undefined,\n indexToHandle: Map<number, QFProperty>,\n ): QFPredicate[] | undefined {\n if (!serialized || serialized.length === 0) return undefined;\n const preds: QFPredicate[] = [];\n for (const sp of serialized) {\n const prop = indexToHandle.get(sp.propertyIndex);\n if (!prop) return undefined;\n preds.push(sp.isEqual ? prop.is(sp.value) : prop.is_not(sp.value));\n }\n return preds;\n }\n}\n","export {\n startBackgroundLoad,\n ensureLoaded,\n isReady,\n getModule,\n getQuantumForge,\n getVersion,\n getMaxDimension,\n getMaxQudits,\n getMaxStateSize,\n getWasmMemoryBytes,\n setWasmBasePath,\n useQuantumForgeBuild,\n getAttribution,\n registerServiceWorker,\n} from \"./QuantumForgeLoader\";\nexport { QuantumPropertyManager } from \"./QuantumPropertyManager\";\nexport type { PredicateSpec, QuantumRecorderHook } from \"./QuantumPropertyManager\";\nexport { QuantumRecorder } from \"./QuantumRecorder\";\nexport type { QuantumOperation, SerializedPredicate } from \"./QuantumOperationLog\";\nexport type { OpCode, BatchOp, BatchResult, OpNum } from \"./quantum-forge-api.mjs\";\n\n/** Numeric opcode constants for tape encoding. Matches C++ OpCode enum. */\nexport const OP = {\n CYCLE: 0, SHIFT: 1, CLOCK: 2,\n X: 3, Z: 4, Y: 5,\n HADAMARD: 6, INVERSE_HADAMARD: 7,\n SWAP: 8, I_SWAP: 9,\n PHASE_ROTATE: 10,\n ROTATE_BASIS_PAIR: 11,\n} as const;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/quantum/QuantumForgeLoader.ts","../../src/quantum/Quantum.ts","../../src/quantum/QuantumPropertyManager.ts","../../src/quantum/QuantumRecorder.ts","../../src/quantum/LegacyQuantumRecorder.ts","../../src/quantum/index.ts"],"sourcesContent":["/**\n * Quantum Forge Loader - Lazy loader for Quantum Forge WASM module\n *\n * Defers WASM loading from the critical path while preloading in background\n * so it's ready when needed. If not ready, callers can show loading UI.\n * \n * IMPORTANT: Quantum Forge is built from source and copied to dist/ as\n * quantum-forge-web-api.mjs (not an npm package). Run 'npm run setup' to build.\n */\n\nimport type { LoggerInterface } from \"../logging/Logger\";\n\n// Type for the quantum forge module\ntype QuantumForgeModuleType = typeof import(\"./quantum-forge-api.mjs\");\n\n// Where the WASM comes from.\n//\n// In a page it is a URL path the Vite plugin serves: \"/quantum-forge\" for the\n// default build, \"/quantum-forge-<name>\" for a variant. In Node there is no\n// server, so the loader resolves the files inside this package instead: dist/\n// for the default build, dist/quantum-forge-<name>/ for a variant. Either way\n// the consumer calls useQuantumForgeBuild() and ensureLoaded() the same way.\nlet explicitBasePath: string | null = null;\nlet variant: string | null = null;\n\n/**\n * Set the base URL path where Quantum Forge WASM files are served.\n * Default is \"/quantum-forge\" which matches the Vite plugin's serve path.\n * Consumers using the Vite plugin don't need to call this. In Node the default\n * is this package's own dist/ directory, so a file URL is only needed when the\n * WASM lives somewhere else.\n */\nexport function setWasmBasePath(path: string): void {\n explicitBasePath = path.endsWith(\"/\") ? path.slice(0, -1) : path;\n}\n\n/**\n * Select a named WASM build variant (e.g. \"qubit\").\n * In a page this loads from \"/quantum-forge-{name}\"; in Node it loads from\n * this package's dist/quantum-forge-{name}/. Replaces any earlier\n * setWasmBasePath() call.\n *\n * Must be called before `ensureLoaded()`. If the module is already loaded,\n * a warning is logged and the call is ignored.\n */\nexport function useQuantumForgeBuild(name: string): void {\n if (isInitialized) {\n logger?.warn?.(\n `useQuantumForgeBuild(\"${name}\") called after module already loaded — ignoring. Call before ensureLoaded().`,\n \"QuantumForgeLoader\",\n );\n return;\n }\n variant = name;\n explicitBasePath = null;\n}\n\n/** True when this module was loaded from disk (Node, vitest), not served over HTTP. */\nfunction runningFromDisk(): boolean {\n return (\n typeof process !== \"undefined\" &&\n typeof process.versions?.node === \"string\" &&\n import.meta.url.startsWith(\"file:\")\n );\n}\n\n/** The base path ensureLoaded() imports from, resolved at load time. */\nexport function getWasmBasePath(): string {\n if (explicitBasePath !== null) return explicitBasePath;\n if (runningFromDisk()) {\n // Built layout: dist/lib/quantum.js next to dist/quantum-forge-web-api.mjs\n // and dist/quantum-forge-<variant>/quantum-forge-web-api.mjs. Under vitest\n // the monorepo aliases straight to this .ts file in src/quantum/, two\n // levels above the same dist/.\n const dist = import.meta.url.endsWith(\".ts\") ? \"../../dist/\" : \"../\";\n const dir = variant ? `${dist}quantum-forge-${variant}/` : dist;\n return new URL(dir, import.meta.url).href.replace(/\\/$/, \"\");\n }\n return variant ? `/quantum-forge-${variant}` : \"/quantum-forge\";\n}\n\n// Cache the module and initialization state\nlet quantumForgeModule: QuantumForgeModuleType | null = null;\nlet initPromise: Promise<void> | null = null;\nlet isInitialized = false;\nlet loadStarted = false;\n\n// Logger reference (set during startBackgroundLoad)\nlet logger: LoggerInterface | undefined;\n\n/**\n * Start loading the WASM module in the background.\n * Call this after the page has rendered (e.g., after DOMContentLoaded or initial paint).\n */\nexport function startBackgroundLoad(loggerRef?: LoggerInterface): void {\n if (loadStarted) return;\n loadStarted = true;\n logger = loggerRef;\n\n // Use requestIdleCallback if available, otherwise setTimeout\n const scheduleLoad = (callback: () => void) => {\n if (typeof requestIdleCallback === \"function\") {\n requestIdleCallback(callback, { timeout: 2000 });\n } else {\n setTimeout(callback, 100);\n }\n };\n\n scheduleLoad(() => {\n logger?.info?.(\"Starting background Quantum Forge load\", \"QuantumForgeLoader\");\n // Trigger the load but don't await - let it happen in background\n ensureLoaded().catch((err) => {\n logger?.warn?.(\n `Background Quantum Forge load failed: ${err?.message ?? err}`,\n \"QuantumForgeLoader\",\n );\n });\n });\n}\n\n/**\n * Ensure Quantum Forge is loaded and initialized.\n * Returns a promise that resolves when the module is ready.\n * Can be called multiple times - will return the same promise.\n */\nexport async function ensureLoaded(): Promise<void> {\n if (isInitialized) return;\n\n if (initPromise) {\n await initPromise;\n return;\n }\n\n initPromise = (async () => {\n const startTime = performance.now();\n logger?.info?.(\"Loading Quantum Forge WASM module...\", \"QuantumForgeLoader\");\n\n // Dynamic import of Quantum Forge WASM module from the configured base path\n const modulePath = `${getWasmBasePath()}/quantum-forge-web-api.mjs`;\n const mod = (await import(/* @vite-ignore */ modulePath)) as QuantumForgeModuleType;\n quantumForgeModule = mod;\n\n // Initialize the WASM, routing stderr through the logger\n await mod.QuantumForge.initialize({\n printErr: (text: string) => logger?.warn?.(text, \"QuantumForge/WASM\"),\n });\n\n const version = mod.QuantumForge.getVersion();\n const maxDim = mod.QuantumForge.getMaxDimension();\n const maxQudits = mod.QuantumForge.getMaxQudits();\n const elapsed = (performance.now() - startTime).toFixed(0);\n\n logger?.info?.(\n `Quantum Forge v${version} ready in ${elapsed}ms (max dim: ${maxDim}, max qudits: ${maxQudits})`,\n \"QuantumForgeLoader\",\n );\n\n console.log(\n \"%c\\u269B Powered by Quantum Forge %c quantumnative.io \",\n \"background: #6366f1; color: white; padding: 2px 6px; border-radius: 3px 0 0 3px; font-weight: bold;\",\n \"background: #1e1b4b; color: #c7d2fe; padding: 2px 6px; border-radius: 0 3px 3px 0;\",\n );\n\n isInitialized = true;\n })();\n\n // Handle errors by clearing the promise so retry is possible\n initPromise.catch(() => {\n initPromise = null;\n });\n\n await initPromise;\n}\n\n/**\n * Check if Quantum Forge is ready to use (non-blocking).\n */\nexport function isReady(): boolean {\n return isInitialized;\n}\n\n/**\n * Get the loaded module. Throws if not loaded.\n * For synchronous access after ensuring it's loaded.\n */\nexport function getModule(): typeof import(\"./quantum-forge-api.mjs\") {\n if (!quantumForgeModule || !isInitialized) {\n throw new Error(\"QuantumForge not loaded. Call ensureLoaded() first and await it.\");\n }\n return quantumForgeModule;\n}\n\n/**\n * Get the QuantumForge class from the loaded module.\n */\nexport function getQuantumForge(): typeof import(\"./quantum-forge-api.mjs\").QuantumForge {\n return getModule().QuantumForge;\n}\n\n/**\n * Convenience re-exports for common operations.\n * These will throw if module not loaded.\n */\nexport function getVersion(): string {\n return getQuantumForge().getVersion();\n}\n\nexport function getMaxDimension(): number {\n return getQuantumForge().getMaxDimension();\n}\n\nexport function getMaxQudits(): number {\n return getQuantumForge().getMaxQudits();\n}\n\nexport function getMaxStateSize(): number {\n return getQuantumForge().getMaxStateSize();\n}\n\n/**\n * Get the WASM memory bytes (for analytics).\n */\nexport function getWasmMemoryBytes(): number | null {\n if (!isInitialized) return null;\n try {\n const qf = getQuantumForge() as any;\n return typeof qf.getMemoryBytes === \"function\" ? qf.getMemoryBytes() : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Get the required attribution text for display in your application.\n * Include this in a user-visible location (credits screen, about page, etc.).\n */\nexport function getAttribution(): string {\n return \"Powered by Quantum Forge \\u2014 \\u00A9 Quantum Native \\u2014 quantumnative.io\";\n}\n\n/**\n * Register the Quantum Forge service worker for offline WASM caching.\n * Call once from your game controller after page load.\n * The SW caches WASM artifacts on first fetch so subsequent loads work offline.\n *\n * @param swPath - Path to the service worker file. Default: \"/quantum-forge-sw.js\"\n */\nexport async function registerServiceWorker(\n swPath = \"/quantum-forge-sw.js\",\n): Promise<ServiceWorkerRegistration | null> {\n if (!(\"serviceWorker\" in navigator)) return null;\n try {\n const reg = await navigator.serviceWorker.register(swPath);\n logger?.info?.(`Service worker registered (scope: ${reg.scope})`, \"QuantumForgeLoader\");\n return reg;\n } catch (err) {\n logger?.warn?.(\n `Service worker registration failed: ${err instanceof Error ? err.message : err}`,\n \"QuantumForgeLoader\",\n );\n return null;\n }\n}\n","/**\n * Quantum — one handle per quantum property.\n *\n * Declare a property by the values it can take, call gates on it as methods,\n * and end its life with `dispose()` (or a `using` declaration). There is no\n * manager and no `getModule()` in game code.\n *\n * ```typescript\n * import { quantum, measure, ensureLoaded } from \"quantum-forge/quantum\";\n *\n * await ensureLoaded();\n * const color = quantum([\"red\", \"green\", \"blue\"]); // a qutrit, starts \"red\"\n * color.superpose(); // alias for hadamard()\n * color.probability(\"green\"); // 1/3, no collapse\n * const c = color.measure(); // \"red\" | \"green\" | \"blue\"\n *\n * const alive = quantum([false, true]);\n * const twin = quantum([false, true]);\n * alive.superpose();\n * twin.flip({ when: [alive.is(true)] }); // CNOT: the pair is now entangled\n * measure(alive, twin); // [false, false] or [true, true]\n * ```\n *\n * `dispose()` always measures the property first. What happens to the WASM\n * property next depends on whether it still shares a state with others:\n *\n * - Alone in its state: it is reset to |0⟩ and kept in a private\n * per-dimension cache, and the next `quantum()` at that dimension reuses it.\n * - Still in a shared state with other qudits: it is destroyed, which factors\n * it out of that state, and it is not cached. Reusing it would hand the next\n * `quantum()` a qudit that still counts against the old state's size.\n *\n * Either way a disposed handle never grows anyone's tensor product.\n */\n\nimport { getMaxDimension, getModule } from \"./QuantumForgeLoader\";\nimport type {\n QuantumProperty as WasmQuantumProperty,\n Predicate as WasmPredicate,\n} from \"./quantum-forge-api.mjs\";\n\n// `using` needs Symbol.dispose. Node 20.4+ defines it; older runtimes get the\n// well-known registry symbol TypeScript's downlevel helpers also look for.\n(Symbol as any).dispose ??= Symbol.for(\"Symbol.dispose\");\n\n// The same augmentation @types/node ships. It lets the emitted .d.ts, which\n// declares `[Symbol.dispose]()`, type-check in a consumer whose `lib` has no\n// ESNext.Disposable (TS 5.0/5.1 cannot add that lib at all). It merges cleanly\n// with lib.esnext.disposable where that is present.\ndeclare global {\n interface SymbolConstructor {\n readonly dispose: unique symbol;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/** A value a quantum property can be declared with: a game word, a number or a boolean. */\nexport type QuantumValue = string | number | boolean;\n\n/** Options accepted by every gate method. */\nexport interface GateOptions {\n /**\n * Predicates that condition the gate. The gate acts only on the part of the\n * state where every predicate holds. A predicate on another property makes\n * the gate an interaction, which entangles the two.\n */\n when?: QuantumPredicate[];\n}\n\n/**\n * A condition on one property's value, built by `is()` or `isNot()`.\n * Used in `{ when: [...] }` on gates and by the `*When` free functions.\n */\nexport interface QuantumPredicate<V extends QuantumValue = QuantumValue> {\n /** The property this predicate tests. */\n readonly property: Quantum<V>;\n /** The declared value being tested. */\n readonly value: V;\n /** The basis index of `value`. */\n readonly index: number;\n /** True for `is()`, false for `isNot()`. */\n readonly isEqual: boolean;\n /** @internal The WASM predicate. */\n readonly raw: WasmPredicate;\n}\n\n/** A predicate as it appears in observer events: handle id, basis index, polarity. */\nexport interface SerializedQuantumPredicate {\n id: number;\n index: number;\n isEqual: boolean;\n}\n\n/**\n * A gate that ran, as reported to observers.\n *\n * `op` is always the physics operation in the WASM `OpCode` spelling\n * (`\"hadamard\"`, `\"inverse_hadamard\"`, `\"i_swap\"`, ...). Aliases report as the\n * operation they alias: `superpose()` reports `\"hadamard\"`, `flip()` and\n * `next()` report `\"cycle\"`, and so on. `fraction` is the value sent to WASM,\n * and is `undefined` when the discrete gate ran.\n */\nexport type QuantumGateEvent =\n | {\n op: \"hadamard\" | \"cycle\" | \"shift\" | \"clock\" | \"x\" | \"y\" | \"z\";\n target: number;\n fraction: number | undefined;\n predicates: SerializedQuantumPredicate[];\n }\n | { op: \"inverse_hadamard\"; target: number; predicates: SerializedQuantumPredicate[] }\n | { op: \"swap\"; targets: [number, number]; predicates: SerializedQuantumPredicate[] }\n | {\n op: \"i_swap\";\n targets: [number, number];\n fraction: number;\n predicates: SerializedQuantumPredicate[];\n }\n | { op: \"phase_rotate\"; angle: number; predicates: SerializedQuantumPredicate[] };\n\n/**\n * A measurement that ran, as reported to observers. Outcomes are basis\n * indices; predicate outcomes are 1 (all predicates held) or 0.\n *\n * - `\"measure\"`: `Quantum.measure()` and the free `measure()`.\n * - `\"forced_measure\"`: `Quantum.forcedMeasure()` and the free `forcedMeasure()`.\n * - `\"measure_predicate\"`: `measureWhen()`.\n * - `\"forced_measure_predicate\"`: `forcedMeasureWhen()`.\n *\n * In both forced events the outcome always equals `forced`: forcing an\n * outcome with zero probability throws and reports no event.\n */\nexport type QuantumMeasureEvent =\n | { op: \"measure\"; targets: number[]; outcomes: number[] }\n | { op: \"forced_measure\"; targets: number[]; forced: number[]; outcomes: number[] }\n | { op: \"measure_predicate\"; predicates: SerializedQuantumPredicate[]; outcome: number }\n | {\n op: \"forced_measure_predicate\";\n predicates: SerializedQuantumPredicate[];\n forced: number;\n outcome: number;\n };\n\n/**\n * Receives every quantum operation after it succeeds in WASM. Attach with\n * `observeQuantum()`. The measurement `dispose()` makes internally is not\n * reported through `onMeasure`; `onDispose` carries its outcome instead.\n *\n * Delivery rules:\n * - An observer that throws does not stop the others from seeing the event,\n * and the error never reaches the code that ran the operation. It is\n * reported with `reportError()` where the runtime has it, else `console.error`.\n * - Events arrive in execution order. An operation run from inside an\n * observer callback is queued, and its event is delivered once the current\n * event has reached every observer.\n * - Each event goes to the observers attached when the operation ran. An\n * observer attached or detached from inside a callback changes who sees\n * later operations, not operations already queued.\n * - Gate and measurement events are deeply frozen, and every observer gets\n * the same object. Copy before changing one. `onCreate` and `onDispose`\n * receive the live handle, which is not frozen.\n */\nexport interface QuantumObserver {\n /** A handle was created by `quantum()`. */\n onCreate?(prop: Quantum<any>): void;\n /** A gate ran. */\n onGate?(event: QuantumGateEvent): void;\n /** A measurement ran. */\n onMeasure?(event: QuantumMeasureEvent): void;\n /** A handle was disposed; `value` is the declared value it measured to. */\n onDispose?(prop: Quantum<any>, value: QuantumValue): void;\n}\n\n// ---------------------------------------------------------------------------\n// Module state\n// ---------------------------------------------------------------------------\n\n/**\n * Marker present on every `Quantum` instance as an own, non-enumerable,\n * read-only data property with value `true`. The engine uses it to find\n * handles on an entity without walking objects it does not understand. It is\n * a registry symbol so two copies of core still recognize each other's\n * handles, and non-enumerable so a spread copy `{ ...handle }` is not a handle.\n */\nexport const QUANTUM_HANDLE: unique symbol = Symbol.for(\"quantum-forge.quantum-handle\");\n\nlet nextId = 1;\nconst cache = new Map<number, WasmQuantumProperty[]>();\nconst observers = new Set<QuantumObserver>();\n\n/**\n * Events waiting for delivery, oldest first. Each carries the observers\n * attached when its operation ran, so detaching an observer from inside a\n * callback cannot drop an operation that callback already ran.\n */\nconst pending: Array<{ deliver: (o: QuantumObserver) => void; to: QuantumObserver[] }> = [];\nlet delivering = false;\n\nfunction reportObserverError(err: unknown): void {\n try {\n const report = (globalThis as { reportError?: (e: unknown) => void }).reportError;\n if (typeof report === \"function\") report(err);\n else console.error(\"A quantum observer threw:\", err);\n } catch {\n // Reporting must never break delivery.\n }\n}\n\n/**\n * Deliver one event to the observers attached now. The set is captured here,\n * when the operation ran, not when the event is delivered. Each observer call\n * is isolated, so a throw reaches neither the other observers nor the caller.\n * Delivery is not re-entrant: an event raised from inside an observer waits in\n * `pending` until the current one has reached everyone, so all observers see\n * events in execution order.\n */\nfunction notify(deliver: (o: QuantumObserver) => void): void {\n if (observers.size === 0) return;\n pending.push({ deliver, to: [...observers] });\n if (delivering) return;\n delivering = true;\n try {\n for (let next = pending.shift(); next; next = pending.shift()) {\n for (const o of next.to) {\n try {\n next.deliver(o);\n } catch (err) {\n reportObserverError(err);\n }\n }\n }\n } finally {\n delivering = false;\n }\n}\n\n/** Freeze an event and everything inside it. Events hold only plain data, never handles. */\nfunction deepFreeze<T>(value: T): T {\n if (typeof value === \"object\" && value !== null && !Object.isFrozen(value)) {\n Object.freeze(value);\n for (const child of Object.values(value)) deepFreeze(child);\n }\n return value;\n}\n\n/**\n * Report a gate. Every observer receives the same frozen event, so one\n * observer cannot rewrite what a later one (a recorder) sees.\n */\nfunction notifyGate(event: QuantumGateEvent): void {\n if (observers.size === 0) return;\n deepFreeze(event);\n notify((o) => o.onGate?.(event));\n}\n\n/** Report a measurement, frozen as `notifyGate()` does. */\nfunction notifyMeasure(event: QuantumMeasureEvent): void {\n if (observers.size === 0) return;\n deepFreeze(event);\n notify((o) => o.onMeasure?.(event));\n}\n\n/**\n * Below this a forced outcome counts as impossible. The WASM's predicate\n * forced measurement uses the same threshold.\n */\nconst IMPOSSIBLE = 1e-10;\n\n/**\n * Run a WASM call, rewriting the errors a game can cause into game-facing\n * messages that name the method the game called.\n */\nfunction wasm<T>(method: string, call: () => T): T {\n try {\n return call();\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n const limit = /num_qudits (\\d+) exceeds compile-time MAX_NUM_QUDITS \\((\\d+)\\)/.exec(message);\n if (limit) {\n throw new Error(\n `${method}(): this would put ${limit[1]} qudits in one entangled state, and the loaded build holds at most ${limit[2]}. Dispose handles you no longer need to free qudits.`,\n { cause: err },\n );\n }\n throw err;\n }\n}\n\nfunction describeValue(v: QuantumValue): string {\n return typeof v === \"string\" ? JSON.stringify(v) : String(v);\n}\n\nfunction describeValues(values: readonly QuantumValue[]): string {\n return `[${values.map(describeValue).join(\", \")}]`;\n}\n\nfunction assertLive(prop: Quantum<any>): void {\n if (prop.disposed) {\n throw new Error(`Quantum property #${prop.id} was disposed and can no longer be used.`);\n }\n}\n\n/**\n * Check predicates and return their WASM form. When the call is a gate,\n * `gate` names the method the game called and its targets, so a predicate on\n * a target gets an error in the game's words rather than the WASM's.\n */\nfunction checkPredicates(\n preds: readonly QuantumPredicate[] | undefined,\n gate?: { method: string; targets: readonly Quantum<any>[] },\n): WasmPredicate[] {\n if (!preds) return [];\n return preds.map((p) => {\n if (p.property.disposed) {\n throw new Error(\n `Predicate on quantum property #${p.property.id} cannot be used: the property was disposed.`,\n );\n }\n if (gate?.targets.includes(p.property)) {\n throw new Error(\n `${gate.method}(): a gate on quantum property #${p.property.id} cannot be conditioned on that same property. A when predicate must read a different property.`,\n );\n }\n return p.raw;\n });\n}\n\n/** One predicate of a forced outcome, with the handle it reads. */\ninterface ForcedTerm {\n prop: Quantum<any>;\n raw: WasmPredicate;\n}\n\n/**\n * Throw before any state change when \"every term holds\" (or, with `holds`\n * false, \"not every term holds\") has zero probability.\n *\n * A probability over predicates on handles in different states tensors those\n * states together, and a throw here must leave them apart. So:\n *\n * 1. Each term's own probability comes first. A one-predicate probability\n * reads a single state and tensors nothing. When holding, one impossible\n * term makes the whole outcome impossible; when not holding, one term that\n * can fail makes the outcome possible.\n * 2. Only then the joint probability, and only over terms that may be\n * correlated with another term: a handle that appears once and is alone in\n * its state (one active qudit) is independent of everything else, so its\n * own probability multiplies in and it never reaches a joint call. The\n * joint call can still tensor two multi-qudit states it had no way to tell\n * apart; the forced measurement that follows a passing check tensors them\n * anyway.\n */\nfunction assertPossible(method: string, terms: readonly ForcedTerm[], holds: boolean, what: string): void {\n const m = getModule();\n const probability = (preds: WasmPredicate[]): number =>\n wasm(method, () => m.predicate_probability(preds));\n const impossible = (): Error =>\n new Error(\n `${method}(): ${what} has zero probability in the current state, so it cannot be forced. Force only an outcome a measurement could give.`,\n );\n\n const own = terms.map((t) => probability([t.raw]));\n if (holds && own.some((p) => p <= IMPOSSIBLE)) throw impossible();\n if (!holds && own.some((p) => 1 - p > IMPOSSIBLE)) return;\n\n const uses = new Map<Quantum<any>, number>();\n for (const t of terms) uses.set(t.prop, (uses.get(t.prop) ?? 0) + 1);\n let all = 1;\n const correlated: number[] = [];\n terms.forEach((t, i) => {\n if (uses.get(t.prop) === 1 && t.prop.raw.num_active_qudits() === 1) all *= own[i];\n else correlated.push(i);\n });\n if (correlated.length === 1) all *= own[correlated[0]];\n else if (correlated.length > 1) all *= probability(correlated.map((i) => terms[i].raw));\n if ((holds ? all : 1 - all) <= IMPOSSIBLE) throw impossible();\n}\n\nfunction serialize(preds: readonly QuantumPredicate[] | undefined): SerializedQuantumPredicate[] {\n return (preds ?? []).map((p) => ({ id: p.property.id, index: p.index, isEqual: p.isEqual }));\n}\n\n/**\n * Resolve a declared value or basis index to a basis index. A declared value\n * wins when a number could be both.\n */\nfunction indexIn(prop: Quantum<any>, value: QuantumValue): number {\n const declared = prop.values.indexOf(value);\n if (declared !== -1) return declared;\n if (typeof value === \"number\" && Number.isInteger(value) && value >= 0 && value < prop.dimension) {\n return value;\n }\n throw new RangeError(\n `${describeValue(value)} is not a value of quantum property #${prop.id}; its values are ${describeValues(prop.values)} (or an index 0..${prop.dimension - 1}).`,\n );\n}\n\ntype FractionalOp = \"hadamard\" | \"cycle\" | \"shift\" | \"clock\" | \"x\" | \"y\" | \"z\";\n\n/** A NaN or infinite number reaches the WASM as NaN amplitudes; stop it at the door. */\nfunction finite(n: number, what: string): number {\n if (typeof n !== \"number\" || !Number.isFinite(n)) {\n throw new RangeError(`${what} must be a finite number, got ${String(n)}.`);\n }\n return n;\n}\n\n// ---------------------------------------------------------------------------\n// The handle\n// ---------------------------------------------------------------------------\n\n/** Module-private: only `quantum()` can build a handle. */\nconst CONSTRUCT = Symbol(\"Quantum.construct\");\n\n/** Set by `Quantum`'s static block; the only path to its private constructor. */\nlet construct: <V extends QuantumValue>(raw: WasmQuantumProperty, values: readonly V[]) => Quantum<V>;\n\n/**\n * One quantum property, declared by its values. Create with `quantum()`; the\n * constructor is private and throws a TypeError when called directly.\n *\n * Every gate returns `this` so calls chain. A gate on one property is\n * evolution; a gate that takes a second property, or whose `when` predicate\n * reads another property, is an interaction and leaves the two entangled.\n *\n * Gates that take a fraction take it as an optional leading number: omit it,\n * or pass exactly 1, for the discrete gate. Options may follow the fraction or\n * stand in its place: `b.flip({ when: [a.is(true)] })` and\n * `b.flip(0.5, { when: [a.is(true)] })` both work.\n *\n * Wherever a value is accepted, pass either a declared value or its basis\n * index. A declared value wins when a number could be both.\n *\n * A bare `Quantum` means `Quantum<QuantumValue>`, so a field typed `Quantum`\n * holds any handle, named or numeric.\n */\nexport class Quantum<V extends QuantumValue = QuantumValue> {\n static {\n construct = (raw, values) => new Quantum(CONSTRUCT, raw, values);\n }\n\n /**\n * Marker for `isQuantum()`. Always `true`. Defined in the constructor as a\n * non-enumerable data property, so it survives neither a spread nor\n * `Object.assign({}, handle)`.\n */\n declare readonly [QUANTUM_HANDLE]: true;\n /** Unique per `quantum()` call, increasing, never reused. */\n readonly id: number;\n /** Declared values in basis order. Index 0 is the starting value. */\n readonly values: readonly V[];\n /** Number of declared values. */\n readonly dimension: number;\n private readonly _raw: WasmQuantumProperty;\n // An ES private field, not a property: `Object.freeze()` on the handle\n // (deep-freeze helpers on game state do this) cannot stop dispose() from\n // setting it.\n #disposed = false;\n\n /**\n * The WASM property behind this handle, for the batch API (`executeBatch`,\n * `executeBatchTape`), which has no handle-level form yet.\n *\n * Caveats:\n * - Operations run through `.raw` are invisible to observers, so a\n * `QuantumRecorder` log will not contain them and a replay will diverge.\n * - Never call `destroy()` on it. The handle still owns it, and its\n * `dispose()` would then fail.\n * - It is valid only while the handle is live. After `dispose()` it may back\n * a different handle, so this getter throws.\n * @throws Error once the handle is disposed.\n */\n get raw(): WasmQuantumProperty {\n assertLive(this);\n return this._raw;\n }\n\n private constructor(token: typeof CONSTRUCT, raw: WasmQuantumProperty, values: readonly V[]) {\n if (token !== CONSTRUCT) {\n throw new TypeError(\"Quantum handles are created with quantum(); the constructor is private.\");\n }\n Object.defineProperty(this, QUANTUM_HANDLE, { value: true });\n this.id = nextId++;\n this._raw = raw;\n this.values = Object.freeze([...values]);\n this.dimension = values.length;\n }\n\n /** True once `dispose()` has run. Every other call then throws. */\n get disposed(): boolean {\n return this.#disposed;\n }\n\n // -- Evolution --\n\n /**\n * Hadamard gate: spread the property evenly across every value.\n * @param fraction Omit (or pass exactly 1) for the discrete gate; any other number runs the fractional gate.\n */\n hadamard(fraction?: number | GateOptions, opts?: GateOptions): this {\n return this._gate(\"hadamard\", \"hadamard\", fraction, opts);\n }\n\n /** Inverse Hadamard gate. Undoes `hadamard()`. */\n inverseHadamard(opts?: GateOptions): this {\n assertLive(this);\n const preds = checkPredicates(opts?.when, { method: \"inverseHadamard\", targets: [this] });\n const m = getModule();\n wasm(\"inverseHadamard\", () => {\n if (preds.length) m.inverse_hadamard(this.raw, preds);\n else m.inverse_hadamard(this.raw);\n });\n const event: QuantumGateEvent = {\n op: \"inverse_hadamard\",\n target: this.id,\n predicates: serialize(opts?.when),\n };\n notifyGate(event);\n return this;\n }\n\n /**\n * Cycle gate: move to the next value, wrapping (index + 1 mod dimension).\n * @param fraction Omit (or pass exactly 1) for the discrete gate; any other number runs the fractional gate.\n */\n cycle(fraction?: number | GateOptions, opts?: GateOptions): this {\n return this._gate(\"cycle\", \"cycle\", fraction, opts);\n }\n\n /**\n * Shift gate: move to the previous value, wrapping (index - 1 mod dimension).\n * @param fraction Omit (or pass exactly 1) for the discrete gate; any other number runs the fractional gate.\n */\n shift(fraction?: number | GateOptions, opts?: GateOptions): this {\n return this._gate(\"shift\", \"shift\", fraction, opts);\n }\n\n /**\n * Clock gate: rotate the phase of each value by its index.\n * @param fraction Omit (or pass exactly 1) for the discrete gate; any other number runs the fractional gate.\n */\n clock(fraction?: number | GateOptions, opts?: GateOptions): this {\n return this._gate(\"clock\", \"clock\", fraction, opts);\n }\n\n /**\n * Pauli X gate. Same as `shift()`; at dimension 2 also the same as `cycle()`.\n * @param fraction Omit (or pass exactly 1) for the discrete gate; any other number runs the fractional gate.\n */\n x(fraction?: number | GateOptions, opts?: GateOptions): this {\n return this._gate(\"x\", \"x\", fraction, opts);\n }\n\n /**\n * Pauli Y gate. Dimension 2 only; throws on any other dimension.\n * @param fraction Omit (or pass exactly 1) for the discrete gate; any other number runs the fractional gate.\n */\n y(fraction?: number | GateOptions, opts?: GateOptions): this {\n return this._gate(\"y\", \"y\", fraction, opts);\n }\n\n /**\n * Pauli Z gate. Same as `clock()`.\n * @param fraction Omit (or pass exactly 1) for the discrete gate; any other number runs the fractional gate.\n */\n z(fraction?: number | GateOptions, opts?: GateOptions): this {\n return this._gate(\"z\", \"z\", fraction, opts);\n }\n\n // -- Game-word aliases --\n\n /**\n * Alias for `hadamard()`.\n * Spread the property evenly across every value.\n */\n superpose(fraction?: number | GateOptions, opts?: GateOptions): this {\n return this._gate(\"hadamard\", \"superpose\", fraction, opts);\n }\n\n /**\n * Alias for `cycle()`.\n * Move to the next value, wrapping. `next(0.5)` is half a step.\n */\n next(fraction?: number | GateOptions, opts?: GateOptions): this {\n return this._gate(\"cycle\", \"next\", fraction, opts);\n }\n\n /**\n * Alias for `shift()`.\n * Move to the previous value, wrapping.\n */\n previous(fraction?: number | GateOptions, opts?: GateOptions): this {\n return this._gate(\"shift\", \"previous\", fraction, opts);\n }\n\n /**\n * Alias for `clock()`.\n * Turn the phase dial.\n */\n phase(fraction?: number | GateOptions, opts?: GateOptions): this {\n return this._gate(\"clock\", \"phase\", fraction, opts);\n }\n\n /**\n * Alias for `cycle()`, restricted to dimension 2.\n * Swap the two values. `flip(0.5)` is the square root of NOT. Throws on any\n * other dimension.\n */\n flip(fraction?: number | GateOptions, opts?: GateOptions): this {\n assertLive(this);\n if (this.dimension !== 2) {\n throw new Error(\n `flip() needs a property with 2 values; quantum property #${this.id} has ${this.dimension}. Use next() or cycle() instead.`,\n );\n }\n return this._gate(\"cycle\", \"flip\", fraction, opts);\n }\n\n // -- Interaction --\n\n /**\n * Swap the states of this property and `other`.\n * @throws Error when `other` is this property, or has a different number of values.\n */\n swap(other: Quantum<any>, opts?: GateOptions): this {\n const preds = this._pair(\"swap\", other, opts);\n const m = getModule();\n wasm(\"swap\", () => {\n if (preds.length) m.swap(this.raw, other.raw, preds);\n else m.swap(this.raw, other.raw);\n });\n const event: QuantumGateEvent = {\n op: \"swap\",\n targets: [this.id, other.id],\n predicates: serialize(opts?.when),\n };\n notifyGate(event);\n return this;\n }\n\n /**\n * iSwap gate between this property and `other`. `iSwap(other, 0.5)` on\n * a pair where one is set leaves them entangled.\n * @param fraction Required; 1 is a full iSwap.\n * @throws Error when `other` is this property, or has a different number of values.\n */\n iSwap(other: Quantum<any>, fraction: number, opts?: GateOptions): this {\n const preds = this._pair(\"iSwap\", other, opts);\n finite(fraction, \"iSwap fraction\");\n const m = getModule();\n wasm(\"iSwap\", () => {\n if (preds.length) m.i_swap(this.raw, other.raw, fraction, preds);\n else m.i_swap(this.raw, other.raw, fraction);\n });\n const event: QuantumGateEvent = {\n op: \"i_swap\",\n targets: [this.id, other.id],\n fraction,\n predicates: serialize(opts?.when),\n };\n notifyGate(event);\n return this;\n }\n\n // -- Predicates --\n\n /**\n * A predicate that holds when this property equals `value`.\n * @param value A declared value or its basis index.\n * @throws RangeError when `value` is neither.\n */\n is(value: V | number): QuantumPredicate<V> {\n return this._predicate(value, true);\n }\n\n /**\n * A predicate that holds when this property does not equal `value`.\n * @param value A declared value or its basis index.\n * @throws RangeError when `value` is neither.\n */\n isNot(value: V | number): QuantumPredicate<V> {\n return this._predicate(value, false);\n }\n\n // -- Measurement and inspection --\n\n /** Measure this property, collapsing it and every entangled partner. Returns the declared value. */\n measure(): V {\n assertLive(this);\n const [outcome] = wasm(\"measure\", () => getModule().measure_properties([this.raw]));\n const event: QuantumMeasureEvent = { op: \"measure\", targets: [this.id], outcomes: [outcome] };\n notifyMeasure(event);\n return this.values[outcome];\n }\n\n /**\n * Measure this property with the outcome forced to `value`. For replays and tests.\n * @param value A declared value or its basis index.\n * @throws Error when `value` has zero probability in the current state. The\n * state is left unchanged.\n */\n forcedMeasure(value: V | number): V {\n assertLive(this);\n const index = indexIn(this, value);\n assertPossible(\n \"forcedMeasure\",\n [{ prop: this, raw: this.raw.is(index) }],\n true,\n `value ${describeValue(this.values[index])} of quantum property #${this.id}`,\n );\n const [outcome] = wasm(\"forcedMeasure\", () =>\n getModule().forced_measure_properties([this.raw], [index]),\n );\n const event: QuantumMeasureEvent = {\n op: \"forced_measure\",\n targets: [this.id],\n forced: [index],\n outcomes: [outcome],\n };\n notifyMeasure(event);\n return this.values[outcome];\n }\n\n /**\n * Probability that a measurement would give `value`. Does not collapse the state.\n * @param value A declared value or its basis index.\n */\n probability(value: V | number): number {\n assertLive(this);\n const index = indexIn(this, value);\n return wasm(\"probability\", () => getModule().predicate_probability([this.raw.is(index)]));\n }\n\n /** Probability of every declared value, in basis order. Does not collapse the state. */\n probabilities(): Array<{ value: V; probability: number }> {\n assertLive(this);\n const probs = new Array<number>(this.dimension).fill(0);\n for (const entry of wasm(\"probabilities\", () => getModule().probabilities([this.raw]))) {\n probs[entry.qudit_values[0]] += entry.probability;\n }\n return this.values.map((value, i) => ({ value, probability: probs[i] }));\n }\n\n // -- Lifecycle --\n\n /**\n * End this property's life. Measures it first, which collapses any\n * entangled partners. Then:\n *\n * - If it is alone in its state, it is reset to its first value and its\n * WASM property goes to a private cache for the next `quantum()` at this\n * dimension.\n * - If it still shares a state with other qudits, its WASM property is\n * destroyed, which factors it out of that state, and it is not cached.\n * A partner left on its own shrinks back to one qudit.\n *\n * Calling it again does nothing. Works on a frozen handle.\n */\n dispose(): void {\n if (this.#disposed) return;\n const m = getModule();\n const raw = this._raw;\n const [outcome] = wasm(\"dispose\", () => m.measure_properties([raw]));\n // Flag first: nothing below may leave a live handle on a cached raw.\n this.#disposed = true;\n if (raw.num_active_qudits() === 1) {\n m.reset(raw, outcome);\n let bucket = cache.get(this.dimension);\n if (!bucket) {\n bucket = [];\n cache.set(this.dimension, bucket);\n }\n bucket.push(raw);\n } else {\n raw.destroy();\n }\n const value = this.values[outcome];\n notify((o) => o.onDispose?.(this, value));\n }\n\n /** Same as `dispose()`, so a `using` declaration disposes the handle at scope exit. */\n [Symbol.dispose](): void {\n this.dispose();\n }\n\n // -- Diagnostics --\n\n /** Number of qudits in the shared state this property belongs to. */\n numActiveQudits(): number {\n assertLive(this);\n return this.raw.num_active_qudits();\n }\n\n /** Number of basis amplitudes in the shared state vector. */\n stateVectorSize(): number {\n assertLive(this);\n return this.raw.state_vector_size();\n }\n\n // -- Internals --\n\n private _predicate(value: V | number, isEqual: boolean): QuantumPredicate<V> {\n assertLive(this);\n const index = indexIn(this, value);\n const raw = isEqual ? this.raw.is(index) : this.raw.is_not(index);\n return Object.freeze({ property: this, value: this.values[index], index, isEqual, raw });\n }\n\n /** Checks shared by swap() and iSwap(). Returns the WASM predicates. */\n private _pair(method: string, other: Quantum<any>, opts: GateOptions | undefined): WasmPredicate[] {\n assertLive(this);\n assertLive(other);\n if (other === this) {\n throw new Error(`${method}(): quantum property #${this.id} cannot ${method} with itself.`);\n }\n if (other.dimension !== this.dimension) {\n throw new Error(\n `${method}(): quantum property #${this.id} has ${this.dimension} values and #${other.id} has ${other.dimension}. Both need the same number of values.`,\n );\n }\n return checkPredicates(opts?.when, { method, targets: [this, other] });\n }\n\n private _gate(\n op: FractionalOp,\n method: string,\n fractionOrOpts: number | GateOptions | undefined,\n maybeOpts?: GateOptions,\n ): this {\n assertLive(this);\n // The fraction is optional and leads, so `b.flip({ when: [...] })` puts\n // the options where the fraction would go.\n const [fraction, opts] =\n typeof fractionOrOpts === \"object\" ? [undefined, fractionOrOpts] : [fractionOrOpts, maybeOpts];\n const preds = checkPredicates(opts?.when, { method, targets: [this] });\n // Omitted or exactly 1 is the discrete gate. The fractional call at 1.0\n // gives the same state on a slower path, so it is never sent.\n const sent = fraction === undefined || fraction === 1 ? undefined : finite(fraction, `${method} fraction`);\n const fn = getModule()[op] as (\n prop: WasmQuantumProperty,\n fraction?: number,\n predicates?: WasmPredicate[],\n ) => void;\n wasm(method, () => {\n if (preds.length) fn(this.raw, sent, preds);\n else if (sent !== undefined) fn(this.raw, sent);\n else fn(this.raw);\n });\n const event: QuantumGateEvent = {\n op,\n target: this.id,\n fraction: sent,\n predicates: serialize(opts?.when),\n };\n notifyGate(event);\n return this;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Factories\n// ---------------------------------------------------------------------------\n\n/**\n * @internal Not exported from the package. Why `values` cannot declare a\n * quantum property, or undefined when it can. `quantum()` throws with it and\n * `QuantumRecorder` rejects a `create` entry with it, so a log that\n * deserializes also replays. The build's maximum dimension is checked by\n * `quantum()` alone: it depends on which build is loaded.\n */\nexport function declaredValuesProblem(\n values: readonly unknown[],\n): { reason: string; ErrorType: typeof Error } | undefined {\n if (values.length < 2) {\n return { reason: \"a quantum property needs at least 2 values\", ErrorType: RangeError };\n }\n const seen = new Set<unknown>();\n for (const v of values) {\n if (typeof v !== \"string\" && typeof v !== \"number\" && typeof v !== \"boolean\") {\n return {\n reason: `${String(v)} is not a string, number or boolean`,\n ErrorType: TypeError,\n };\n }\n if (typeof v === \"number\" && !Number.isFinite(v)) {\n return { reason: `${describeValue(v)} is not a finite number`, ErrorType: RangeError };\n }\n if (seen.has(v)) {\n return { reason: `value ${describeValue(v)} is declared twice`, ErrorType: Error };\n }\n seen.add(v);\n }\n return undefined;\n}\n\n/**\n * Create a quantum property declared by its values. The dimension is the\n * number of values, and the property starts at the first one.\n *\n * @example\n * const color = quantum([\"red\", \"green\", \"blue\"]);\n * const alive = quantum([false, true]);\n * @throws RangeError when `values` has fewer than 2 entries or a non-finite number.\n * @throws Error when `values` has duplicates, or more entries than the loaded build's maximum dimension.\n */\nexport function quantum<V extends QuantumValue>(values: readonly V[]): Quantum<V>;\n/**\n * Create a quantum property with `dimension` values `0..dimension-1`, starting at 0.\n * @throws RangeError when `dimension` is not an integer, or is less than 2.\n * @throws Error when `dimension` exceeds the loaded build's maximum dimension.\n */\nexport function quantum(dimension: number): Quantum<number>;\nexport function quantum(arg: readonly QuantumValue[] | number): Quantum<any> {\n let values: readonly QuantumValue[];\n if (typeof arg === \"number\") {\n if (!Number.isInteger(arg)) {\n throw new RangeError(`quantum(${arg}): dimension must be an integer.`);\n }\n if (arg < 2) {\n throw new RangeError(`quantum(${arg}): a quantum property needs at least 2 values.`);\n }\n values = Array.from({ length: arg }, (_, i) => i);\n } else {\n const problem = declaredValuesProblem(arg);\n if (problem) {\n throw new problem.ErrorType(`quantum(${describeValues(arg)}): ${problem.reason}.`);\n }\n values = arg;\n }\n\n const dimension = values.length;\n const max = getMaxDimension();\n if (dimension > max) {\n throw new Error(\n `quantum(): a property with ${dimension} values exceeds the loaded build's maximum of ${max} values per property.`,\n );\n }\n\n const raw = cache.get(dimension)?.pop() ?? getModule().QuantumForge.createQuantumProperty(dimension);\n const prop = construct(raw, values);\n // Only a fully built handle is announced.\n notify((o) => o.onCreate?.(prop));\n return prop;\n}\n\n/**\n * True when `x` is a `Quantum` handle: it has an own `QUANTUM_HANDLE` data\n * property whose value is `true`. The marker is read through its descriptor,\n * so a getter under that key is never invoked, and a spread copy of a handle\n * (which drops the non-enumerable marker) is not a handle.\n */\nexport function isQuantum(x: unknown): x is Quantum<any> {\n if (typeof x !== \"object\" || x === null) return false;\n const marker = Object.getOwnPropertyDescriptor(x, QUANTUM_HANDLE);\n return marker !== undefined && \"value\" in marker && marker.value === true;\n}\n\n/**\n * Destroy every cached WASM property and empty the cache. Live handles are not\n * affected. Meant for tests and for freeing memory between scenes.\n */\nexport function clearQuantumCache(): void {\n for (const bucket of cache.values()) {\n for (const raw of bucket) raw.destroy();\n }\n cache.clear();\n}\n\n/**\n * Attach an observer that sees every quantum operation after it succeeds.\n * @returns A function that detaches the observer.\n */\nexport function observeQuantum(observer: QuantumObserver): () => void {\n observers.add(observer);\n return () => {\n observers.delete(observer);\n };\n}\n\n// ---------------------------------------------------------------------------\n// Joint operations\n// ---------------------------------------------------------------------------\n\nfunction requireProps(fn: string, props: readonly Quantum<any>[]): void {\n if (props.length === 0) throw new Error(`${fn}() needs at least one quantum property.`);\n props.forEach(assertLive);\n}\n\n/**\n * Measure several properties together. Returns each one's declared value, in argument order.\n * @example const [a, b] = measure(alive, twin);\n */\nexport function measure(...props: Quantum<any>[]): QuantumValue[] {\n requireProps(\"measure\", props);\n const outcomes = wasm(\"measure\", () => getModule().measure_properties(props.map((p) => p.raw)));\n const event: QuantumMeasureEvent = {\n op: \"measure\",\n targets: props.map((p) => p.id),\n outcomes: [...outcomes],\n };\n notifyMeasure(event);\n return outcomes.map((index, i) => props[i].values[index]);\n}\n\n/**\n * Measure several properties together with each outcome forced. For replays and tests.\n * @param values One declared value or basis index per property.\n * @throws Error when the combination of values has zero probability in the\n * current state. The state is left unchanged.\n */\nexport function forcedMeasure(props: Quantum<any>[], values: QuantumValue[]): QuantumValue[] {\n requireProps(\"forcedMeasure\", props);\n if (values.length !== props.length) {\n throw new Error(\n `forcedMeasure(): got ${props.length} properties but ${values.length} values.`,\n );\n }\n const forced = props.map((p, i) => indexIn(p, values[i]));\n assertPossible(\n \"forcedMeasure\",\n props.map((p, i) => ({ prop: p, raw: p.raw.is(forced[i]) })),\n true,\n `the outcome ${describeValues(props.map((p, i) => p.values[forced[i]]))} for quantum properties ${props.map((p) => `#${p.id}`).join(\", \")}`,\n );\n const outcomes = wasm(\"forcedMeasure\", () =>\n getModule().forced_measure_properties(\n props.map((p) => p.raw),\n forced,\n ),\n );\n const event: QuantumMeasureEvent = {\n op: \"forced_measure\",\n targets: props.map((p) => p.id),\n forced,\n outcomes: [...outcomes],\n };\n notifyMeasure(event);\n return outcomes.map((index, i) => props[i].values[index]);\n}\n\n/**\n * Joint probabilities over several properties. Each entry lists one declared\n * value per property, in argument order. Does not collapse the state.\n */\nexport function probabilities(\n ...props: Quantum<any>[]\n): Array<{ values: QuantumValue[]; probability: number }> {\n requireProps(\"probabilities\", props);\n return wasm(\"probabilities\", () => getModule().probabilities(props.map((p) => p.raw))).map((entry) => ({\n values: entry.qudit_values.map((index, i) => props[i].values[index]),\n probability: entry.probability,\n }));\n}\n\n/**\n * Reduced density matrix over several properties. Rows and columns are\n * labelled with one declared value per property. Does not collapse the state.\n */\nexport function densityMatrix(\n ...props: Quantum<any>[]\n): Array<{ row: QuantumValue[]; col: QuantumValue[]; real: number; imag: number }> {\n requireProps(\"densityMatrix\", props);\n return wasm(\"densityMatrix\", () =>\n getModule().reduced_density_matrix(props.map((p) => p.raw)),\n ).map((entry) => ({\n row: entry.row_values.map((index, i) => props[i].values[index]),\n col: entry.col_values.map((index, i) => props[i].values[index]),\n real: entry.value.real,\n imag: entry.value.imag,\n }));\n}\n\n/** Measure whether every predicate holds, collapsing the state to agree. */\nexport function measureWhen(preds: QuantumPredicate[]): boolean {\n const raw = checkPredicates(preds);\n const outcome = wasm(\"measureWhen\", () => getModule().measure_predicate(raw));\n const event: QuantumMeasureEvent = {\n op: \"measure_predicate\",\n predicates: serialize(preds),\n outcome,\n };\n notifyMeasure(event);\n return outcome !== 0;\n}\n\n/**\n * Measure whether every predicate holds, with the outcome forced. For replays\n * and tests. Returns `outcome`.\n * @throws Error when the forced outcome has zero probability in the current\n * state. The state is left unchanged.\n */\nexport function forcedMeasureWhen(preds: QuantumPredicate[], outcome: boolean): boolean {\n const raw = checkPredicates(preds);\n const forced = outcome ? 1 : 0;\n const what = `${outcome ? \"every\" : \"not every\"} predicate holding`;\n assertPossible(\n \"forcedMeasureWhen\",\n preds.map((p, i) => ({ prop: p.property, raw: raw[i] })),\n outcome,\n what,\n );\n const actual = wasm(\"forcedMeasureWhen\", () => getModule().forced_measure_predicate(raw, forced));\n const event: QuantumMeasureEvent = {\n op: \"forced_measure_predicate\",\n predicates: serialize(preds),\n forced,\n outcome: actual,\n };\n notifyMeasure(event);\n // The WASM falls back to a normal measurement when the forced outcome is\n // impossible. The check above uses the same threshold, so this only fires if\n // the two disagree at the edge. The state has changed by now, so the event\n // above still went out.\n if (actual !== forced) {\n throw new Error(`forcedMeasureWhen(): ${what} has zero probability in the current state, so it cannot be forced.`);\n }\n return actual !== 0;\n}\n\n/** Probability that every predicate holds at once. Does not collapse the state. */\nexport function probabilityWhen(preds: QuantumPredicate[]): number {\n const raw = checkPredicates(preds);\n return wasm(\"probabilityWhen\", () => getModule().predicate_probability(raw));\n}\n\n/**\n * Rotate the phase of the part of the state where every predicate holds by `angle` radians.\n * @example phaseRotate(Math.PI, { when: [a.is(1), b.is(1)] });\n */\nexport function phaseRotate(angle: number, opts: { when: QuantumPredicate[] }): void {\n finite(angle, \"phaseRotate angle\");\n const raw = checkPredicates(opts.when);\n wasm(\"phaseRotate\", () => getModule().phase_rotate(raw, angle));\n const event: QuantumGateEvent = { op: \"phase_rotate\", angle, predicates: serialize(opts.when) };\n notifyGate(event);\n}\n","/**\n * QuantumPropertyManager — manages quantum property lifecycles.\n *\n * Handles the common pattern of acquiring, pooling, and releasing WASM\n * QuantumProperty handles. Games either extend this class or compose it\n * to add game-specific quantum operations via getModule().\n *\n * Property pooling is critical: measured/removed properties are recycled\n * to avoid growing the tensor product and hitting qudit limits.\n *\n * For opt-in operation recording, attach a LegacyQuantumRecorder via setRecorder().\n */\n\nimport { getModule } from \"./QuantumForgeLoader\";\nimport type { LoggerInterface } from \"../logging/Logger\";\nimport type { QuantumProperty as QFProperty } from \"./quantum-forge-api.mjs\";\n\nexport interface PredicateSpec {\n property: QFProperty;\n value: number;\n isEqual: boolean;\n}\n\nexport interface QuantumRecorderHook {\n onAcquire?(prop: QFProperty): void;\n onRelease?(prop: QFProperty, value: number): void;\n onSetProperty?(id: string, prop: QFProperty): void;\n onDeleteProperty?(id: string): void;\n}\n\n/**\n * Pools raw WASM properties behind string ids.\n *\n * @deprecated Use `quantum()` handles from the same entry point; see\n * docs/QUANTUM_INTEGRATION.md. Removed in 4.0.\n */\nexport class QuantumPropertyManager {\n readonly dimension: number;\n private properties: Map<string, QFProperty> = new Map();\n private pool: QFProperty[] = [];\n protected logger?: LoggerInterface;\n private _recorder?: QuantumRecorderHook;\n\n constructor(options: { dimension?: number; logger?: LoggerInterface } = {}) {\n this.dimension = options.dimension ?? 2;\n this.logger = options.logger;\n }\n\n // -- Recorder hook --\n\n /** Attach an optional recorder for operation logging. */\n setRecorder(recorder: QuantumRecorderHook | undefined): void {\n this._recorder = recorder;\n }\n\n /** Get the currently attached recorder, if any. */\n getRecorder(): QuantumRecorderHook | undefined {\n return this._recorder;\n }\n\n // -- Property lifecycle --\n\n /**\n * Get a property at |0⟩ — reuses a pooled one if available,\n * otherwise creates a fresh standalone property.\n */\n acquireProperty(): QFProperty {\n let prop: QFProperty;\n if (this.pool.length > 0) {\n prop = this.pool.pop()!;\n } else {\n prop = getModule().QuantumForge.createQuantumProperty(this.dimension);\n }\n this._recorder?.onAcquire?.(prop);\n return prop;\n }\n\n /**\n * Return a property to the pool after resetting it to |0⟩.\n * Uses the `reset` primitive which applies non-fractional cycles —\n * correct for all dimensions (no superposition created).\n */\n releaseProperty(prop: QFProperty, measuredValue: number): void {\n this._recorder?.onRelease?.(prop, measuredValue);\n getModule().reset(prop, measuredValue);\n this.pool.push(prop);\n }\n\n // -- ID mapping --\n\n setProperty(id: string, prop: QFProperty): void {\n this._recorder?.onSetProperty?.(id, prop);\n this.properties.set(id, prop);\n }\n\n getProperty(id: string): QFProperty | undefined {\n return this.properties.get(id);\n }\n\n deleteProperty(id: string): void {\n this._recorder?.onDeleteProperty?.(id);\n this.properties.delete(id);\n }\n\n hasProperty(id: string): boolean {\n return this.properties.has(id);\n }\n\n // -- Public operations --\n\n /**\n * Remove a property by ID: measure it, pool the handle, delete the mapping.\n */\n removeProperty(id: string): void {\n const prop = this.properties.get(id);\n if (prop) {\n const [value] = getModule().measure_properties([prop]);\n this.releaseProperty(prop, value);\n }\n this.deleteProperty(id);\n }\n\n /** Clear all properties, pool, and recorder. */\n clear(): void {\n this.properties.clear();\n this.pool = [];\n }\n\n get size(): number {\n return this.properties.size;\n }\n\n get poolSize(): number {\n return this.pool.length;\n }\n\n // -- WASM module access --\n\n getModule(): ReturnType<typeof getModule> {\n return getModule();\n }\n\n // -- Internal access for LegacyQuantumRecorder replay --\n\n /** @internal — used by LegacyQuantumRecorder.replayLog() to restore pool state. */\n _setPool(pool: QFProperty[]): void {\n this.pool = pool;\n }\n\n /** @internal — used by LegacyQuantumRecorder to enumerate live handles. */\n _getProperties(): Map<string, QFProperty> {\n return this.properties;\n }\n\n /** @internal — used by LegacyQuantumRecorder to enumerate pool handles. */\n _getPool(): QFProperty[] {\n return this.pool;\n }\n}\n","/**\n * QuantumRecorder — opt-in recording and replay of `quantum()` handles.\n *\n * The recorder attaches through `observeQuantum()`, so every gate, measurement,\n * creation and disposal is logged without the game calling anything extra.\n * Entries name handles by their `id` and values by basis index, and the log is\n * plain JSON: `{ \"version\": 1, \"entries\": [...] }`.\n *\n * ```typescript\n * const recorder = new QuantumRecorder();\n * recorder.startRecording();\n * const a = quantum([false, true]);\n * const b = quantum([false, true]);\n * a.superpose();\n * b.flip({ when: [a.is(true)] });\n * measure(a, b);\n * const text = QuantumRecorder.serialize(recorder.stopRecording());\n *\n * const handles = QuantumRecorder.replay(QuantumRecorder.deserialize(text));\n * handles.get(a.id); // the replayed `a`, collapsed to the recorded outcome\n * ```\n */\n\nimport {\n quantum,\n observeQuantum,\n forcedMeasure,\n forcedMeasureWhen,\n phaseRotate,\n declaredValuesProblem,\n type Quantum,\n type QuantumValue,\n type QuantumPredicate,\n type SerializedQuantumPredicate,\n type QuantumGateEvent,\n type QuantumMeasureEvent,\n} from \"./Quantum\";\n\n// ---------------------------------------------------------------------------\n// Log entry types\n// ---------------------------------------------------------------------------\n\ntype FractionalGateOp = \"hadamard\" | \"cycle\" | \"shift\" | \"clock\" | \"x\" | \"y\" | \"z\";\n\n/**\n * One recorded operation. Handles are named by `id`, values by basis index.\n *\n * Gate and measurement entries mirror `QuantumGateEvent` and\n * `QuantumMeasureEvent` one to one, with op names in the WASM spelling\n * (`\"hadamard\"`, `\"cycle\"`, `\"i_swap\"`, ...). A gate's `fraction` is omitted\n * when the discrete gate ran.\n */\nexport type QuantumLogEntry =\n | { op: \"create\"; id: number; values: QuantumValue[] }\n | { op: \"dispose\"; id: number; outcome: number }\n | {\n op: FractionalGateOp;\n target: number;\n fraction?: number;\n predicates: SerializedQuantumPredicate[];\n }\n | { op: \"inverse_hadamard\"; target: number; predicates: SerializedQuantumPredicate[] }\n | { op: \"swap\"; targets: [number, number]; predicates: SerializedQuantumPredicate[] }\n | {\n op: \"i_swap\";\n targets: [number, number];\n fraction: number;\n predicates: SerializedQuantumPredicate[];\n }\n | { op: \"phase_rotate\"; angle: number; predicates: SerializedQuantumPredicate[] }\n | { op: \"measure\"; targets: number[]; outcomes: number[] }\n | { op: \"forced_measure\"; targets: number[]; forced: number[]; outcomes: number[] }\n | { op: \"measure_predicate\"; predicates: SerializedQuantumPredicate[]; outcome: number }\n | {\n op: \"forced_measure_predicate\";\n predicates: SerializedQuantumPredicate[];\n forced: number;\n outcome: number;\n };\n\n/** The log format version `serialize()` writes and `deserialize()` accepts. */\nconst LOG_VERSION = 1;\n\n/**\n * A recorded session: `{ version: 1, entries: [...] }`. `getLog()`,\n * `stopRecording()` and `deserialize()` return this shape, and `serialize()`\n * and `replay()` take it.\n *\n * `untrackedIds` is present only when the recording touched handles created\n * before `startRecording()`. Such a log cannot be replayed: `replay()` throws.\n */\nexport interface QuantumLog {\n version: typeof LOG_VERSION;\n entries: QuantumLogEntry[];\n /** Ids of handles the log references but never creates, in ascending order. */\n untrackedIds?: number[];\n}\n\n// Compile-time check: every observer event op has a log entry op.\ntype MissingOps = Exclude<(QuantumGateEvent | QuantumMeasureEvent)[\"op\"], QuantumLogEntry[\"op\"]>;\nconst _allOpsCovered: [MissingOps] extends [never] ? true : MissingOps = true;\nvoid _allOpsCovered;\n\n// ---------------------------------------------------------------------------\n// Event to entry\n// ---------------------------------------------------------------------------\n\nfunction copyPredicates(preds: readonly SerializedQuantumPredicate[]): SerializedQuantumPredicate[] {\n return preds.map((p) => ({ id: p.id, index: p.index, isEqual: p.isEqual }));\n}\n\nfunction gateEntry(e: QuantumGateEvent): QuantumLogEntry {\n const predicates = copyPredicates(e.predicates);\n switch (e.op) {\n case \"inverse_hadamard\":\n return { op: e.op, target: e.target, predicates };\n case \"swap\":\n return { op: e.op, targets: [e.targets[0], e.targets[1]], predicates };\n case \"i_swap\":\n return { op: e.op, targets: [e.targets[0], e.targets[1]], fraction: e.fraction, predicates };\n case \"phase_rotate\":\n return { op: e.op, angle: e.angle, predicates };\n default:\n return e.fraction === undefined\n ? { op: e.op, target: e.target, predicates }\n : { op: e.op, target: e.target, fraction: e.fraction, predicates };\n }\n}\n\nfunction measureEntry(e: QuantumMeasureEvent): QuantumLogEntry {\n switch (e.op) {\n case \"measure\":\n return { op: e.op, targets: [...e.targets], outcomes: [...e.outcomes] };\n case \"forced_measure\":\n return {\n op: e.op,\n targets: [...e.targets],\n forced: [...e.forced],\n outcomes: [...e.outcomes],\n };\n case \"measure_predicate\":\n return { op: e.op, predicates: copyPredicates(e.predicates), outcome: e.outcome };\n case \"forced_measure_predicate\":\n return {\n op: e.op,\n predicates: copyPredicates(e.predicates),\n forced: e.forced,\n outcome: e.outcome,\n };\n }\n}\n\n/** Every handle id an entry operates on or tests, `create` excluded. */\nfunction referencedIds(e: QuantumLogEntry): number[] {\n if (e.op === \"create\") return [];\n const ids: number[] = [];\n if (\"id\" in e) ids.push(e.id);\n if (\"target\" in e) ids.push(e.target);\n if (\"targets\" in e) ids.push(...e.targets);\n if (\"predicates\" in e) ids.push(...e.predicates.map((p) => p.id));\n return ids;\n}\n\n// ---------------------------------------------------------------------------\n// Validation\n// ---------------------------------------------------------------------------\n\nconst isObj = (x: unknown): x is Record<string, unknown> =>\n typeof x === \"object\" && x !== null && !Array.isArray(x);\nconst isInt = (x: unknown): x is number => typeof x === \"number\" && Number.isInteger(x);\nconst isNum = (x: unknown): x is number => typeof x === \"number\" && Number.isFinite(x);\nconst isIntArray = (x: unknown): x is number[] => Array.isArray(x) && x.every(isInt);\nconst isPair = (x: unknown): x is [number, number] => isIntArray(x) && x.length === 2;\nconst isBit = (x: unknown): boolean => x === 0 || x === 1;\nconst isPredicates = (x: unknown): x is SerializedQuantumPredicate[] =>\n Array.isArray(x) &&\n x.every((p) => isObj(p) && isInt(p.id) && isInt(p.index) && typeof p.isEqual === \"boolean\");\n\n/** Dimension of each handle a `create` entry has declared so far, by id. */\ntype Dimensions = Map<number, number>;\n\n/**\n * Reason `index` is not a basis index of handle `id`, or undefined. An id with\n * no earlier `create` has no known dimension; replay reports that case itself.\n */\nfunction indexReason(dims: Dimensions, id: number, index: number, what: string): string | undefined {\n if (index < 0) return `${what} ${index} is negative`;\n const dim = dims.get(id);\n if (dim !== undefined && index >= dim) {\n return `${what} ${index} is out of range for quantum property #${id}, which has ${dim} values`;\n }\n return undefined;\n}\n\nfunction predicatesReason(dims: Dimensions, preds: unknown): string | undefined {\n if (!isPredicates(preds)) return \"predicates are malformed\";\n for (const p of preds) {\n const reason = indexReason(dims, p.id, p.index, \"predicate index\");\n if (reason) return reason;\n }\n return undefined;\n}\n\nfunction indicesReason(\n dims: Dimensions,\n targets: number[],\n indices: number[],\n what: string,\n): string | undefined {\n for (let i = 0; i < targets.length; i++) {\n const reason = indexReason(dims, targets[i], indices[i], what);\n if (reason) return reason;\n }\n return undefined;\n}\n\n/** Returns a reason the entry is malformed, or undefined when it is valid. */\nfunction invalidReason(e: Record<string, unknown>, dims: Dimensions): string | undefined {\n switch (e.op) {\n case \"create\":\n if (!isInt(e.id)) return \"id must be an integer\";\n if (!Array.isArray(e.values)) return \"values must be an array\";\n // The same check quantum() makes, so a create that validates also replays.\n return declaredValuesProblem(e.values)?.reason;\n case \"dispose\":\n if (!isInt(e.id) || !isInt(e.outcome)) return \"id and outcome must be integers\";\n return indexReason(dims, e.id, e.outcome, \"outcome\");\n case \"hadamard\":\n case \"cycle\":\n case \"shift\":\n case \"clock\":\n case \"x\":\n case \"y\":\n case \"z\":\n if (!isInt(e.target)) return \"target must be an integer\";\n if (e.fraction !== undefined && !isNum(e.fraction)) return \"fraction must be a number\";\n return predicatesReason(dims, e.predicates);\n case \"inverse_hadamard\":\n if (!isInt(e.target)) return \"target must be an integer\";\n return predicatesReason(dims, e.predicates);\n case \"swap\":\n if (!isPair(e.targets)) return \"targets must be two integers\";\n return predicatesReason(dims, e.predicates);\n case \"i_swap\":\n if (!isPair(e.targets)) return \"targets must be two integers\";\n if (!isNum(e.fraction)) return \"fraction must be a number\";\n return predicatesReason(dims, e.predicates);\n case \"phase_rotate\":\n if (!isNum(e.angle)) return \"angle must be a number\";\n return predicatesReason(dims, e.predicates);\n case \"measure\":\n if (!isIntArray(e.targets) || !isIntArray(e.outcomes)) {\n return \"targets and outcomes must be integer arrays\";\n }\n if (e.targets.length !== e.outcomes.length) return \"targets and outcomes differ in length\";\n return indicesReason(dims, e.targets, e.outcomes, \"outcome\");\n case \"forced_measure\":\n if (!isIntArray(e.targets) || !isIntArray(e.forced) || !isIntArray(e.outcomes)) {\n return \"targets, forced and outcomes must be integer arrays\";\n }\n if (e.targets.length !== e.outcomes.length) return \"targets and outcomes differ in length\";\n if (e.targets.length !== e.forced.length) return \"targets and forced differ in length\";\n return (\n indicesReason(dims, e.targets, e.forced, \"forced outcome\") ??\n indicesReason(dims, e.targets, e.outcomes, \"outcome\")\n );\n case \"measure_predicate\":\n if (!isBit(e.outcome)) return \"outcome must be 0 or 1\";\n return predicatesReason(dims, e.predicates);\n case \"forced_measure_predicate\":\n if (!isBit(e.outcome) || !isBit(e.forced)) return \"forced and outcome must be 0 or 1\";\n return predicatesReason(dims, e.predicates);\n default:\n return typeof e.op === \"string\" ? `unknown op ${JSON.stringify(e.op)}` : \"missing op\";\n }\n}\n\n/**\n * Check a log's envelope and every entry, and return a fresh envelope whose\n * `entries` array is a snapshot of the input's.\n * @param where Prefix for error messages, e.g. `\"QuantumRecorder.deserialize\"`.\n */\nfunction validateLog(input: unknown, where: string): QuantumLog {\n if (!isObj(input)) {\n throw new Error(\n `${where}: expected a log object { \"version\": ${LOG_VERSION}, \"entries\": [...] }.`,\n );\n }\n if (input.version !== LOG_VERSION) {\n const got = input.version === undefined ? \"no version\" : `version ${JSON.stringify(input.version)}`;\n throw new Error(\n `${where}: unsupported log format (${got}). This build reads version ${LOG_VERSION}.`,\n );\n }\n if (!Array.isArray(input.entries)) {\n throw new Error(`${where}: the log's \"entries\" must be an array.`);\n }\n if (input.untrackedIds !== undefined && !isIntArray(input.untrackedIds)) {\n throw new Error(`${where}: the log's \"untrackedIds\" must be an array of integers.`);\n }\n const dims: Dimensions = new Map();\n input.entries.forEach((entry: unknown, position: number) => {\n const reason = isObj(entry) ? invalidReason(entry, dims) : \"not an object\";\n if (reason) {\n throw new Error(`${where}: entry ${position} is invalid: ${reason}.`);\n }\n const valid = entry as QuantumLogEntry;\n if (valid.op === \"create\") dims.set(valid.id, valid.values.length);\n });\n const entries = [...(input.entries as QuantumLogEntry[])];\n const log: QuantumLog = { version: LOG_VERSION, entries };\n if (input.untrackedIds !== undefined) log.untrackedIds = [...input.untrackedIds];\n return log;\n}\n\n// ---------------------------------------------------------------------------\n// The recorder\n// ---------------------------------------------------------------------------\n\n/**\n * Records every operation on `quantum()` handles into a JSON-safe log, and\n * replays a log into fresh handles with the same state.\n *\n * Start recording before creating the handles you want replayed. When a\n * recorded operation touches a handle created before `startRecording()`, the\n * recorder warns once per handle through `console.warn`, keeps recording, and\n * lists the handle's id in the log's `untrackedIds`. `replay()` refuses such a\n * log.\n *\n * Replay runs every measurement as its forced variant with the recorded\n * outcomes, so the replayed state matches the recorded one. A recorder that is\n * running during a replay records what the replay did: the fresh handles'\n * `create` entries and the forced measurements. So \"load a save, keep\n * recording\" yields a log that replays on its own.\n */\nexport class QuantumRecorder {\n private _entries: QuantumLogEntry[] = [];\n private _seen = new Set<number>();\n private _untracked = new Set<number>();\n private _detach: (() => void) | undefined;\n\n /**\n * @throws TypeError when given any argument. The 2.x recorder took a\n * `QuantumPropertyManager`; that one is now `LegacyQuantumRecorder`.\n */\n constructor(...args: []) {\n if (args.length > 0) {\n throw new TypeError(\n \"new QuantumRecorder() takes no arguments: it records quantum() handles through observeQuantum(). To record a QuantumPropertyManager, use new LegacyQuantumRecorder(manager).\",\n );\n }\n }\n\n /** Begin recording. Clears the log. Calling it while recording restarts with an empty log. */\n startRecording(): void {\n this._detach?.();\n this._entries = [];\n this._seen = new Set();\n this._untracked = new Set();\n const push = (entry: QuantumLogEntry): void => {\n this._track(entry);\n this._entries.push(entry);\n };\n this._detach = observeQuantum({\n onCreate: (prop) => push({ op: \"create\", id: prop.id, values: [...prop.values] }),\n onGate: (event) => push(gateEntry(event)),\n onMeasure: (event) => push(measureEntry(event)),\n onDispose: (prop, value) =>\n push({ op: \"dispose\", id: prop.id, outcome: prop.values.indexOf(value) }),\n });\n }\n\n /** Note created ids, and warn the first time an entry touches a handle this recording never saw created. */\n private _track(entry: QuantumLogEntry): void {\n if (entry.op === \"create\") {\n this._seen.add(entry.id);\n return;\n }\n for (const id of referencedIds(entry)) {\n if (this._seen.has(id) || this._untracked.has(id)) continue;\n this._untracked.add(id);\n console.warn(\n `QuantumRecorder: ${entry.op} touched quantum property #${id}, which was created before startRecording(). The log cannot be replayed. Start recording before creating the handles you want replayed.`,\n );\n }\n }\n\n /**\n * Stop recording and return the log, `{ version: 1, entries }`. The log\n * carries `untrackedIds` when it touched handles created before recording.\n */\n stopRecording(): QuantumLog {\n this._detach?.();\n this._detach = undefined;\n return this.getLog();\n }\n\n /** True between `startRecording()` and `stopRecording()`. */\n isRecording(): boolean {\n return this._detach !== undefined;\n }\n\n /** A copy of the log so far, `{ version: 1, entries }`. Works while recording. */\n getLog(): QuantumLog {\n const log: QuantumLog = { version: LOG_VERSION, entries: structuredClone(this._entries) };\n if (this._untracked.size > 0) log.untrackedIds = [...this._untracked].sort((a, b) => a - b);\n return log;\n }\n\n /**\n * Replay a log into new handles. Each `create` makes a fresh handle with a\n * new id; the returned map is keyed by the id in the log. Handles the log\n * disposes are removed from the map, so it holds the handles still live at\n * the end of the log.\n *\n * The log is validated first, as `deserialize()` does. A recorder running\n * during the replay records it (see the class docs); the log passed in is\n * never modified.\n *\n * @throws Error when the log is malformed, lists `untrackedIds`, or an entry\n * references an id with no earlier `create` entry. No handle survives a throw.\n */\n static replay(log: QuantumLog): Map<number, Quantum<any>> {\n const { entries, untrackedIds } = validateLog(log, \"QuantumRecorder.replay\");\n if (untrackedIds && untrackedIds.length > 0) {\n throw new Error(\n `QuantumRecorder.replay: the log touches ${untrackedIds.map((id) => `#${id}`).join(\", \")}, created before recording started, so it has no state to rebuild them from. Start recording before creating the handles you want replayed.`,\n );\n }\n const handles = new Map<number, Quantum<any>>();\n const created: Quantum<any>[] = [];\n try {\n entries.forEach((entry, position) => replayEntry(entry, position, handles, created));\n } catch (error) {\n // A partial replay leaves no handle behind: every handle this call made\n // goes back to the cache before the error reaches the caller.\n for (const h of created) {\n try {\n h.dispose();\n } catch {\n // dispose is idempotent; a second failure has nothing left to release.\n }\n }\n throw error;\n }\n return handles;\n }\n\n /** Serialize a log to JSON: `{ \"version\": 1, \"entries\": [...] }`. */\n static serialize(log: QuantumLog): string {\n return JSON.stringify(log);\n }\n\n /**\n * Parse a log serialized by `serialize()`.\n * @throws Error when the text is not JSON, the version is missing or\n * unsupported, or any entry is malformed or names a basis index outside its\n * handle's declared values.\n */\n static deserialize(text: string): QuantumLog {\n return validateLog(JSON.parse(text), \"QuantumRecorder.deserialize\");\n }\n}\n\nfunction replayEntry(\n entry: QuantumLogEntry,\n position: number,\n handles: Map<number, Quantum<any>>,\n created: Quantum<any>[],\n): void {\n const get = (id: number): Quantum<any> => {\n const h = handles.get(id);\n if (!h) {\n throw new Error(\n `QuantumRecorder.replay: entry ${position} (${entry.op}) references quantum property #${id}, which no earlier create entry in the log made. Start recording before creating the handles you want replayed.`,\n );\n }\n return h;\n };\n // Rebuild by declared value: a number passed to is() resolves as a declared\n // value first, which would misread a basis index on a numeric declaration.\n const preds = (list: SerializedQuantumPredicate[]): QuantumPredicate[] =>\n list.map((p) => {\n const h = get(p.id);\n const value = h.values[p.index];\n return p.isEqual ? h.is(value) : h.isNot(value);\n });\n const force = (ids: number[], outcomes: number[]): void => {\n const props = ids.map(get);\n forcedMeasure(\n props,\n props.map((h, i) => h.values[outcomes[i]]),\n );\n };\n\n switch (entry.op) {\n case \"create\": {\n if (handles.has(entry.id)) {\n throw new Error(\n `QuantumRecorder.replay: entry ${position} creates quantum property #${entry.id}, which an earlier create entry already made and the log has not disposed.`,\n );\n }\n const h = quantum(entry.values);\n handles.set(entry.id, h);\n created.push(h);\n return;\n }\n case \"dispose\": {\n const h = get(entry.id);\n // dispose() measures; force that measurement to the recorded outcome first.\n force([entry.id], [entry.outcome]);\n h.dispose();\n handles.delete(entry.id);\n return;\n }\n case \"hadamard\":\n case \"cycle\":\n case \"shift\":\n case \"clock\":\n case \"x\":\n case \"y\":\n case \"z\":\n get(entry.target)[entry.op](entry.fraction, { when: preds(entry.predicates) });\n return;\n case \"inverse_hadamard\":\n get(entry.target).inverseHadamard({ when: preds(entry.predicates) });\n return;\n case \"swap\":\n get(entry.targets[0]).swap(get(entry.targets[1]), { when: preds(entry.predicates) });\n return;\n case \"i_swap\":\n get(entry.targets[0]).iSwap(get(entry.targets[1]), entry.fraction, {\n when: preds(entry.predicates),\n });\n return;\n case \"phase_rotate\":\n phaseRotate(entry.angle, { when: preds(entry.predicates) });\n return;\n case \"measure\":\n case \"forced_measure\":\n force(entry.targets, entry.outcomes);\n return;\n case \"measure_predicate\":\n case \"forced_measure_predicate\":\n forcedMeasureWhen(preds(entry.predicates), entry.outcome !== 0);\n return;\n }\n}\n","/**\n * LegacyQuantumRecorder — opt-in recording and replay of quantum operations\n * for QuantumPropertyManager. Superseded by QuantumRecorder, which records\n * `quantum()` handles.\n *\n * Attach to a QuantumPropertyManager via `manager.setRecorder(recorder)`.\n * When recording is active, lifecycle hooks log every state-mutating\n * operation. The log can be replayed via replayLog() to recreate\n * identical quantum state — measurements are forced to their recorded\n * outcomes using forced_measure_properties.\n *\n * For gate recording, call wrapGate() around each WASM gate call.\n */\n\nimport { getModule } from \"./QuantumForgeLoader\";\nimport type { QuantumPropertyManager, QuantumRecorderHook } from \"./QuantumPropertyManager\";\nimport type { QuantumOperation, SerializedPredicate } from \"./QuantumOperationLog\";\nimport type { QuantumProperty as QFProperty, Predicate as QFPredicate } from \"./quantum-forge-api.mjs\";\n\nexport interface PredicateSpec {\n property: QFProperty;\n value: number;\n isEqual: boolean;\n}\n\n/**\n * Records and replays operations on a QuantumPropertyManager's pooled properties.\n *\n * @deprecated Use QuantumRecorder with quantum() handles. Removed in 4.0.\n */\nexport class LegacyQuantumRecorder implements QuantumRecorderHook {\n private _recording = false;\n private _log: QuantumOperation[] = [];\n private _handleToIndex: Map<QFProperty, number> = new Map();\n private _nextIndex = 0;\n private readonly _manager: QuantumPropertyManager;\n\n constructor(manager: QuantumPropertyManager) {\n this._manager = manager;\n }\n\n // -- QuantumRecorderHook implementation --\n\n onAcquire(prop: QFProperty): void {\n if (!this._recording) return;\n const index = this._nextIndex++;\n this._handleToIndex.set(prop, index);\n this._log.push({ op: \"acquire\", index });\n }\n\n onRelease(prop: QFProperty, value: number): void {\n if (!this._recording) return;\n const index = this._handleToIndex.get(prop);\n if (index !== undefined) {\n this._log.push({ op: \"release\", index, value });\n }\n }\n\n onSetProperty(id: string, prop: QFProperty): void {\n if (!this._recording) return;\n const index = this._handleToIndex.get(prop);\n if (index !== undefined) {\n this._log.push({ op: \"assign\", index, id });\n }\n }\n\n onDeleteProperty(id: string): void {\n if (!this._recording) return;\n this._log.push({ op: \"unassign\", id });\n }\n\n // -- Gate recording --\n\n /**\n * Build WASM predicate objects from PredicateSpec array.\n */\n buildWasmPredicates(specs: PredicateSpec[]): QFPredicate[] {\n return specs.map((s) =>\n s.isEqual ? s.property.is(s.value) : s.property.is_not(s.value),\n );\n }\n\n /**\n * Serialize predicates for the operation log.\n */\n serializePredicates(specs: PredicateSpec[]): SerializedPredicate[] | undefined {\n if (specs.length === 0) return undefined;\n return specs.map((s) => {\n const index = this._handleToIndex.get(s.property);\n return {\n propertyIndex: index ?? -1,\n value: s.value,\n isEqual: s.isEqual,\n };\n });\n }\n\n /**\n * Record a gate operation. Call this when recording is active\n * and you want to log a gate call for replay.\n */\n recordOp(op: QuantumOperation): void {\n if (!this._recording) return;\n this._log.push(op);\n }\n\n /**\n * Get the recorded index for a property handle.\n */\n getIndex(prop: QFProperty): number | undefined {\n return this._handleToIndex.get(prop);\n }\n\n // -- Recording API --\n\n /** Begin recording quantum operations. Resets any existing log. */\n startRecording(): void {\n this._recording = true;\n this._log = [];\n this._handleToIndex.clear();\n this._nextIndex = 0;\n\n // Assign indices to all currently-live handles so operations\n // on pre-existing properties are tracked correctly.\n for (const prop of this._manager._getProperties().values()) {\n const index = this._nextIndex++;\n this._handleToIndex.set(prop, index);\n }\n for (const prop of this._manager._getPool()) {\n const index = this._nextIndex++;\n this._handleToIndex.set(prop, index);\n }\n }\n\n /** Stop recording and return the captured log. */\n stopRecording(): QuantumOperation[] {\n this._recording = false;\n return [...this._log];\n }\n\n /** Whether recording is currently active. */\n isRecording(): boolean {\n return this._recording;\n }\n\n /** Get a copy of the current operation log (even while recording). */\n getOperationLog(): QuantumOperation[] {\n return [...this._log];\n }\n\n /**\n * Replay an operation log to recreate quantum state from scratch.\n * Clears all existing state on the manager first. Measurements are\n * forced to their recorded outcomes via forced_measure_properties.\n */\n replayLog(operations: QuantumOperation[]): void {\n // Clear manager state\n this._manager.clear();\n this._recording = false;\n this._log = [];\n this._handleToIndex.clear();\n this._nextIndex = 0;\n\n const module = getModule();\n const dimension = this._manager.dimension;\n const indexToHandle = new Map<number, QFProperty>();\n const replayPool: QFProperty[] = [];\n\n for (const entry of operations) {\n switch (entry.op) {\n case \"acquire\": {\n let prop: QFProperty;\n if (replayPool.length > 0) {\n prop = replayPool.pop()!;\n } else {\n prop = module.QuantumForge.createQuantumProperty(dimension);\n }\n indexToHandle.set(entry.index, prop);\n break;\n }\n\n case \"release\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n module.reset(prop, entry.value);\n replayPool.push(prop);\n }\n break;\n }\n\n case \"assign\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n this._manager._getProperties().set(entry.id, prop);\n }\n break;\n }\n\n case \"unassign\": {\n this._manager._getProperties().delete(entry.id);\n break;\n }\n\n case \"cycle\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n if (entry.fraction === 1 && !preds) {\n module.cycle(prop);\n } else {\n module.cycle(prop, entry.fraction, preds);\n }\n }\n break;\n }\n\n case \"shift\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n if (entry.fraction === 1 && !preds) {\n module.shift(prop);\n } else {\n module.shift(prop, entry.fraction, preds);\n }\n }\n break;\n }\n\n case \"i_swap\": {\n const prop1 = indexToHandle.get(entry.index1);\n const prop2 = indexToHandle.get(entry.index2);\n if (prop1 && prop2) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n module.i_swap(prop1, prop2, entry.fraction, preds);\n }\n break;\n }\n\n case \"clock\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n module.clock(prop, entry.fraction, preds);\n }\n break;\n }\n\n case \"y\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n if (entry.fraction === 1 && !preds) {\n module.y(prop);\n } else {\n module.y(prop, entry.fraction, preds);\n }\n }\n break;\n }\n\n case \"hadamard\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n if (entry.fraction === 1 && !preds) {\n module.hadamard(prop);\n } else {\n module.hadamard(prop, entry.fraction, preds);\n }\n }\n break;\n }\n\n case \"inverse_hadamard\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n module.inverse_hadamard(prop, preds);\n }\n break;\n }\n\n case \"swap\": {\n const prop1 = indexToHandle.get(entry.index1);\n const prop2 = indexToHandle.get(entry.index2);\n if (prop1 && prop2) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n module.swap(prop1, prop2, preds);\n }\n break;\n }\n\n case \"phase_rotate\": {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n if (preds) {\n module.phase_rotate(preds, entry.angle);\n }\n break;\n }\n\n case \"measure_predicate\": {\n // During replay, we don't force measure_predicate outcomes —\n // the state should be deterministic from prior forced measurements.\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n if (preds) {\n module.measure_predicate(preds);\n }\n break;\n }\n\n case \"reset\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n module.reset(prop, entry.value);\n }\n break;\n }\n\n case \"measure\": {\n const props = entry.indices.map((i) => indexToHandle.get(i)).filter(Boolean) as QFProperty[];\n if (props.length === entry.indices.length) {\n module.forced_measure_properties(props, entry.outcomes);\n }\n break;\n }\n }\n }\n\n // Restore internal pool from replay pool\n this._manager._setPool(replayPool);\n\n // Rebuild _handleToIndex from indexToHandle for future recording\n this._handleToIndex.clear();\n for (const [index, handle] of indexToHandle) {\n this._handleToIndex.set(handle, index);\n }\n this._nextIndex = operations.reduce((max, op) => {\n if (\"index\" in op && typeof op.index === \"number\") return Math.max(max, op.index + 1);\n if (\"index1\" in op) {\n const dualOp = op as { index1: number; index2: number };\n return Math.max(max, dualOp.index1 + 1, dualOp.index2 + 1);\n }\n if (\"indices\" in op) {\n const measureOp = op as { indices: number[] };\n const maxIdx = Math.max(...measureOp.indices);\n return Math.max(max, maxIdx + 1);\n }\n return max;\n }, 0);\n }\n\n // -- Private helpers --\n\n private _replayPredicates(\n serialized: SerializedPredicate[] | undefined,\n indexToHandle: Map<number, QFProperty>,\n ): QFPredicate[] | undefined {\n if (!serialized || serialized.length === 0) return undefined;\n const preds: QFPredicate[] = [];\n for (const sp of serialized) {\n const prop = indexToHandle.get(sp.propertyIndex);\n if (!prop) return undefined;\n preds.push(sp.isEqual ? prop.is(sp.value) : prop.is_not(sp.value));\n }\n return preds;\n }\n}\n","export {\n startBackgroundLoad,\n ensureLoaded,\n isReady,\n getModule,\n getQuantumForge,\n getVersion,\n getMaxDimension,\n getMaxQudits,\n getMaxStateSize,\n getWasmMemoryBytes,\n setWasmBasePath,\n getWasmBasePath,\n useQuantumForgeBuild,\n getAttribution,\n registerServiceWorker,\n} from \"./QuantumForgeLoader\";\nexport {\n Quantum,\n quantum,\n measure,\n forcedMeasure,\n probabilities,\n densityMatrix,\n measureWhen,\n forcedMeasureWhen,\n probabilityWhen,\n phaseRotate,\n QUANTUM_HANDLE,\n isQuantum,\n observeQuantum,\n clearQuantumCache,\n} from \"./Quantum\";\nexport type {\n QuantumValue,\n GateOptions,\n QuantumPredicate,\n SerializedQuantumPredicate,\n QuantumGateEvent,\n QuantumMeasureEvent,\n QuantumObserver,\n} from \"./Quantum\";\nexport { QuantumPropertyManager } from \"./QuantumPropertyManager\";\nexport type { PredicateSpec, QuantumRecorderHook } from \"./QuantumPropertyManager\";\nexport { QuantumRecorder } from \"./QuantumRecorder\";\nexport type { QuantumLog, QuantumLogEntry } from \"./QuantumRecorder\";\nexport { LegacyQuantumRecorder } from \"./LegacyQuantumRecorder\";\nexport type { QuantumOperation, SerializedPredicate } from \"./QuantumOperationLog\";\nexport type { OpCode, BatchOp, BatchResult, OpNum } from \"./quantum-forge-api.mjs\";\nimport type {\n QuantumProperty as WasmQuantumProperty,\n Predicate as WasmPredicate,\n} from \"./quantum-forge-api.mjs\";\n// Aliases rather than re-exports: the bundled .d.ts would otherwise list the\n// WASM classes as value exports, which the built JS does not have.\n/** The WASM property `Quantum.raw` returns, for the batch API (`executeBatch`, `executeBatchTape`). */\nexport type QuantumProperty = WasmQuantumProperty;\n/** The WASM predicate behind `QuantumPredicate.raw`. */\nexport type Predicate = WasmPredicate;\n\n/** Numeric opcode constants for tape encoding. Matches C++ OpCode enum. */\nexport const OP = {\n CYCLE: 0, SHIFT: 1, CLOCK: 2,\n X: 3, Z: 4, Y: 5,\n HADAMARD: 6, INVERSE_HADAMARD: 7,\n SWAP: 8, I_SWAP: 9,\n PHASE_ROTATE: 10,\n ROTATE_BASIS_PAIR: 11,\n} as const;\n"],"mappings":"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","names":[]}
@@ -21,7 +21,7 @@ interface QuantumForgePluginOptions {
21
21
  *
22
22
  * Usage:
23
23
  * ```ts
24
- * import { quantumForgeVitePlugin } from "@quantum-native/quantum-forge/vite-plugin";
24
+ * import { quantumForgeVitePlugin } from "quantum-forge/vite-plugin";
25
25
  * export default defineConfig({
26
26
  * plugins: [quantumForgeVitePlugin()],
27
27
  * });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/vite-plugin.ts"],"sourcesContent":["import { type Plugin } from \"vite\";\nimport { resolve, join } from \"path\";\nimport fs from \"fs\";\n\nexport interface QuantumForgePluginOptions {\n /**\n * Directory containing the WASM build artifacts.\n * Default: \"dist\" (relative to project root)\n */\n wasmDir?: string;\n\n /**\n * URL path prefix where WASM files are served during dev.\n * Default: \"/quantum-forge\"\n */\n servePath?: string;\n}\n\n/**\n * Vite plugin that serves Quantum Forge WASM artifacts during development.\n *\n * During dev, intercepts requests to `servePath/*` and serves matching\n * `quantum-forge-web-*` files from `wasmDir/`. Also excludes the WASM\n * module from Vite's dependency optimization.\n *\n * Usage:\n * ```ts\n * import { quantumForgeVitePlugin } from \"@quantum-native/quantum-forge/vite-plugin\";\n * export default defineConfig({\n * plugins: [quantumForgeVitePlugin()],\n * });\n * ```\n */\nexport function quantumForgeVitePlugin(\n options: QuantumForgePluginOptions = {},\n): Plugin {\n const wasmDir = options.wasmDir ?? \"dist\";\n const servePath = options.servePath ?? \"/quantum-forge\";\n const prefix = servePath.endsWith(\"/\") ? servePath : servePath + \"/\";\n\n return {\n name: \"quantum-forge\",\n\n config() {\n return {\n optimizeDeps: {\n exclude: [\"quantum-forge-web-api.mjs\"],\n },\n };\n },\n\n configureServer(server) {\n server.middlewares.use((req, res, next) => {\n if (!req.url) return next();\n\n // Strip query string for matching\n const urlPath = req.url.split(\"?\")[0];\n\n // Match requests under the serve path (default and variant builds).\n // Default: /quantum-forge/file → dist/file\n // Variant: /quantum-forge-{name}/file → dist/quantum-forge-{name}/file\n if (!urlPath.startsWith(prefix) && !urlPath.startsWith(servePath + \"-\"))\n return next();\n\n let filename: string;\n let subdir: string;\n\n if (urlPath.startsWith(prefix)) {\n // Default build: /quantum-forge/file\n filename = urlPath.slice(prefix.length);\n subdir = \"\";\n } else {\n // Variant build: /quantum-forge-{name}/file\n // Extract variant name from path segment after servePath-\n const rest = urlPath.slice(servePath.length + 1); // strip \"/quantum-forge-\"\n const slashIdx = rest.indexOf(\"/\");\n if (slashIdx === -1) return next();\n const variantName = rest.slice(0, slashIdx);\n filename = rest.slice(slashIdx + 1);\n subdir = `quantum-forge-${variantName}`;\n }\n\n // Only serve quantum-forge files\n if (!filename.startsWith(\"quantum-forge-web-\")) return next();\n\n // Check project-local dist/ first, then fall back to the framework's\n // dist/ inside node_modules (consumer installs via registry)\n const localDir = subdir\n ? resolve(process.cwd(), wasmDir, subdir)\n : resolve(process.cwd(), wasmDir);\n const nmPkgNames = [\"quantum-forge\", \"@quantum-native/quantum-forge\"];\n const candidates = [resolve(localDir, filename)];\n for (const pkg of nmPkgNames) {\n const nmDir = subdir\n ? resolve(process.cwd(), \"node_modules\", ...pkg.split(\"/\"), \"dist\", subdir)\n : resolve(process.cwd(), \"node_modules\", ...pkg.split(\"/\"), \"dist\");\n candidates.push(resolve(nmDir, filename));\n }\n const filePath = candidates.find((p) => fs.existsSync(p));\n if (!filePath) return next();\n\n const ext = filename.split(\".\").pop();\n const mimeTypes: Record<string, string> = {\n mjs: \"application/javascript\",\n wasm: \"application/wasm\",\n mts: \"application/javascript\",\n };\n res.setHeader(\n \"Content-Type\",\n mimeTypes[ext || \"\"] || \"application/octet-stream\",\n );\n fs.createReadStream(filePath).pipe(res);\n });\n },\n\n writeBundle(options) {\n const outDir = options.dir ?? resolve(process.cwd(), \"dist\");\n\n const wasmFiles = [\n \"quantum-forge-web-esm.mjs\",\n \"quantum-forge-web-esm.wasm\",\n \"quantum-forge-web-api.mjs\",\n ];\n\n const localBase = resolve(process.cwd(), wasmDir);\n const nmBases = [\n resolve(process.cwd(), \"node_modules\", \"quantum-forge\", \"dist\"),\n resolve(process.cwd(), \"node_modules\", \"@quantum-native\", \"quantum-forge\", \"dist\"),\n ];\n const allBases = [localBase, ...nmBases];\n\n // Copy a set of WASM files from a source dir to a dest dir\n const copyBuild = (srcDirs: string[], destDir: string) => {\n const resolved = wasmFiles\n .map((f) => {\n for (const dir of srcDirs) {\n const p = resolve(dir, f);\n if (fs.existsSync(p)) return p;\n }\n return null;\n })\n .filter((p): p is string => p !== null);\n\n if (resolved.length === 0) return;\n\n fs.mkdirSync(destDir, { recursive: true });\n for (const src of resolved) {\n const filename = src.split(\"/\").pop()!;\n fs.copyFileSync(src, join(destDir, filename));\n }\n };\n\n // Copy default build\n copyBuild(allBases, join(outDir, \"quantum-forge\"));\n\n // Copy any variant builds (e.g. quantum-forge-qubit/)\n for (const base of allBases) {\n if (!fs.existsSync(base)) continue;\n for (const entry of fs.readdirSync(base, { withFileTypes: true })) {\n if (entry.isDirectory() && entry.name.startsWith(\"quantum-forge-\")) {\n const variantSrc = resolve(base, entry.name);\n copyBuild([variantSrc], join(outDir, entry.name));\n }\n }\n }\n },\n };\n}\n"],"mappings":"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","names":["options"]}
1
+ {"version":3,"sources":["../../src/vite-plugin.ts"],"sourcesContent":["import { type Plugin } from \"vite\";\nimport { resolve, join } from \"path\";\nimport fs from \"fs\";\n\nexport interface QuantumForgePluginOptions {\n /**\n * Directory containing the WASM build artifacts.\n * Default: \"dist\" (relative to project root)\n */\n wasmDir?: string;\n\n /**\n * URL path prefix where WASM files are served during dev.\n * Default: \"/quantum-forge\"\n */\n servePath?: string;\n}\n\n/**\n * Vite plugin that serves Quantum Forge WASM artifacts during development.\n *\n * During dev, intercepts requests to `servePath/*` and serves matching\n * `quantum-forge-web-*` files from `wasmDir/`. Also excludes the WASM\n * module from Vite's dependency optimization.\n *\n * Usage:\n * ```ts\n * import { quantumForgeVitePlugin } from \"quantum-forge/vite-plugin\";\n * export default defineConfig({\n * plugins: [quantumForgeVitePlugin()],\n * });\n * ```\n */\nexport function quantumForgeVitePlugin(\n options: QuantumForgePluginOptions = {},\n): Plugin {\n const wasmDir = options.wasmDir ?? \"dist\";\n const servePath = options.servePath ?? \"/quantum-forge\";\n const prefix = servePath.endsWith(\"/\") ? servePath : servePath + \"/\";\n\n return {\n name: \"quantum-forge\",\n\n config() {\n return {\n optimizeDeps: {\n exclude: [\"quantum-forge-web-api.mjs\"],\n },\n };\n },\n\n configureServer(server) {\n server.middlewares.use((req, res, next) => {\n if (!req.url) return next();\n\n // Strip query string for matching\n const urlPath = req.url.split(\"?\")[0];\n\n // Match requests under the serve path (default and variant builds).\n // Default: /quantum-forge/file → dist/file\n // Variant: /quantum-forge-{name}/file → dist/quantum-forge-{name}/file\n if (!urlPath.startsWith(prefix) && !urlPath.startsWith(servePath + \"-\"))\n return next();\n\n let filename: string;\n let subdir: string;\n\n if (urlPath.startsWith(prefix)) {\n // Default build: /quantum-forge/file\n filename = urlPath.slice(prefix.length);\n subdir = \"\";\n } else {\n // Variant build: /quantum-forge-{name}/file\n // Extract variant name from path segment after servePath-\n const rest = urlPath.slice(servePath.length + 1); // strip \"/quantum-forge-\"\n const slashIdx = rest.indexOf(\"/\");\n if (slashIdx === -1) return next();\n const variantName = rest.slice(0, slashIdx);\n filename = rest.slice(slashIdx + 1);\n subdir = `quantum-forge-${variantName}`;\n }\n\n // Only serve quantum-forge files\n if (!filename.startsWith(\"quantum-forge-web-\")) return next();\n\n // Check project-local dist/ first, then fall back to the framework's\n // dist/ inside node_modules (consumer installs via registry)\n const localDir = subdir\n ? resolve(process.cwd(), wasmDir, subdir)\n : resolve(process.cwd(), wasmDir);\n const nmPkgNames = [\"quantum-forge\", \"quantum-forge\"];\n const candidates = [resolve(localDir, filename)];\n for (const pkg of nmPkgNames) {\n const nmDir = subdir\n ? resolve(process.cwd(), \"node_modules\", ...pkg.split(\"/\"), \"dist\", subdir)\n : resolve(process.cwd(), \"node_modules\", ...pkg.split(\"/\"), \"dist\");\n candidates.push(resolve(nmDir, filename));\n }\n const filePath = candidates.find((p) => fs.existsSync(p));\n if (!filePath) return next();\n\n const ext = filename.split(\".\").pop();\n const mimeTypes: Record<string, string> = {\n mjs: \"application/javascript\",\n wasm: \"application/wasm\",\n mts: \"application/javascript\",\n };\n res.setHeader(\n \"Content-Type\",\n mimeTypes[ext || \"\"] || \"application/octet-stream\",\n );\n fs.createReadStream(filePath).pipe(res);\n });\n },\n\n writeBundle(options) {\n const outDir = options.dir ?? resolve(process.cwd(), \"dist\");\n\n const wasmFiles = [\n \"quantum-forge-web-esm.mjs\",\n \"quantum-forge-web-esm.wasm\",\n \"quantum-forge-web-api.mjs\",\n ];\n\n const localBase = resolve(process.cwd(), wasmDir);\n const nmBases = [\n resolve(process.cwd(), \"node_modules\", \"quantum-forge\", \"dist\"),\n resolve(process.cwd(), \"node_modules\", \"@quantum-native\", \"quantum-forge\", \"dist\"),\n ];\n const allBases = [localBase, ...nmBases];\n\n // Copy a set of WASM files from a source dir to a dest dir\n const copyBuild = (srcDirs: string[], destDir: string) => {\n const resolved = wasmFiles\n .map((f) => {\n for (const dir of srcDirs) {\n const p = resolve(dir, f);\n if (fs.existsSync(p)) return p;\n }\n return null;\n })\n .filter((p): p is string => p !== null);\n\n if (resolved.length === 0) return;\n\n fs.mkdirSync(destDir, { recursive: true });\n for (const src of resolved) {\n const filename = src.split(\"/\").pop()!;\n fs.copyFileSync(src, join(destDir, filename));\n }\n };\n\n // Copy default build\n copyBuild(allBases, join(outDir, \"quantum-forge\"));\n\n // Copy any variant builds (e.g. quantum-forge-qubit/)\n for (const base of allBases) {\n if (!fs.existsSync(base)) continue;\n for (const entry of fs.readdirSync(base, { withFileTypes: true })) {\n if (entry.isDirectory() && entry.name.startsWith(\"quantum-forge-\")) {\n const variantSrc = resolve(base, entry.name);\n copyBuild([variantSrc], join(outDir, entry.name));\n }\n }\n }\n },\n };\n}\n"],"mappings":"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","names":["options"]}
Binary file
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "quantum-forge",
3
- "version": "2.7.0",
4
- "description": "Quantum Forge WASM loader, property manager, and Vite plugin for quantum game development (Qutrit Edition d3n12 + Qubit Edition d2n20).",
3
+ "version": "3.0.0",
4
+ "description": "Quantum Forge WASM loader, quantum() handle API, and Vite plugin for quantum game development (Qutrit Edition d3n12 + Qubit Edition d2n20).",
5
5
  "type": "module",
6
6
  "exports": {
7
7
  "./quantum": {
@@ -22,6 +22,7 @@
22
22
  },
23
23
  "files": [
24
24
  "dist/",
25
+ "!**/*.tgz",
25
26
  "scripts/cli.mjs",
26
27
  "scripts/prepare.mjs",
27
28
  "scripts/copy-quantum-forge.mjs",
@@ -32,7 +33,7 @@
32
33
  ],
33
34
  "scripts": {
34
35
  "prepare": "node scripts/prepare.mjs",
35
- "prepublishOnly": "node scripts/stamp-service-worker.mjs",
36
+ "prepublishOnly": "node scripts/stamp-service-worker.mjs && node ../../scripts/finish-public-package.mjs",
36
37
  "build:lib": "tsup",
37
38
  "build:quantum-forge": "cd ../../wrappers/web && npm install && npm run build:medium && cd ../../framework/packages/core && node scripts/copy-quantum-forge.mjs",
38
39
  "build:quantum-forge:small": "cd ../../wrappers/web && npm install && npm run build:small && cd ../../framework/packages/core && node scripts/copy-quantum-forge.mjs",
@@ -64,12 +65,12 @@
64
65
  "url": "https://github.com/quantum-native/quantum-forge.git"
65
66
  },
66
67
  "author": "Chris Cantwell",
67
- "license": "MIT",
68
+ "license": "SEE LICENSE IN LICENSE.md",
68
69
  "publishConfig": {
69
70
  "registry": "https://registry.npmjs.org",
70
71
  "access": "public"
71
72
  },
72
73
  "engines": {
73
- "node": ">=18.0.0"
74
+ "node": ">=22.0.0"
74
75
  }
75
76
  }
@@ -6,11 +6,11 @@
6
6
  * `quantum-forge init` copies this file to your project's public/ directory.
7
7
  * For an existing project, copy it yourself:
8
8
  *
9
- * cp node_modules/@quantum-native/quantum-forge/quantum-forge-sw.js public/
9
+ * cp node_modules/quantum-forge/quantum-forge-sw.js public/
10
10
  *
11
11
  * Then register it from your game controller:
12
12
  *
13
- * import { registerServiceWorker } from "@quantum-native/quantum-forge/quantum";
13
+ * import { registerServiceWorker } from "quantum-forge/quantum";
14
14
  * await registerServiceWorker();
15
15
  *
16
16
  * Or manually: navigator.serviceWorker.register("/quantum-forge-sw.js");
@@ -20,7 +20,7 @@
20
20
  // published. An unprocessed copy falls back to "dev", which still works — the
21
21
  // fetch handler revalidates in the background, so a deployment cannot pin old
22
22
  // artifacts forever even when the cache name never changes.
23
- const QF_VERSION = "2.7.0";
23
+ const QF_VERSION = "3.0.0";
24
24
 
25
25
  // Scope the cache to this registration so two Quantum Forge games served from
26
26
  // the same origin (e.g. /game1/ and /game2/ on GitHub Pages) cannot delete
@@ -63,6 +63,18 @@ function buildLib() {
63
63
  log(" TypeScript library built.", "green");
64
64
  }
65
65
 
66
+ // ─── Public names ────────────────────────────────────────────────────────────
67
+
68
+ function finishPublicPackage() {
69
+ const finisher = path.resolve(ROOT, "..", "..", "scripts", "finish-public-package.mjs");
70
+ if (!fs.existsSync(finisher)) return;
71
+ const result = spawnSync(process.execPath, [finisher, ROOT], { stdio: "inherit" });
72
+ if (result.status !== 0) {
73
+ log(" Public-name check failed.", "red");
74
+ process.exit(result.status ?? 1);
75
+ }
76
+ }
77
+
66
78
  // ─── Dev detection ───────────────────────────────────────────────────────────
67
79
 
68
80
  function isDevRepo() {
@@ -282,6 +294,10 @@ async function main() {
282
294
  if (isDevRepo()) {
283
295
  log(" Dev repository detected (monorepo).", "dim");
284
296
  buildLib();
297
+ // `prepare` runs after prepublishOnly during `npm publish`, so a public
298
+ // publish's rewritten declarations have just been rebuilt with the scoped
299
+ // names. Redo the rewrite (and its check) when the finisher exists.
300
+ finishPublicPackage();
285
301
  return;
286
302
  }
287
303