jaml-ui 2.2.1 → 2.3.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,2 +1,2 @@
1
- import{Program as e}from"motely-wasm/motely/wasm";import t from"motely-wasm";import{IFileMounter as n}from"motely-wasm/bootsharp/file-system";let r=()=>!0;e.jimmolatePredicate=e=>r(e);function i(e){r=e}function a(){r=()=>!0}let o=null;async function s(){if(o)return o;if(t.getStatus()===t.BootStatus.Standby)return o=(async()=>{try{(await import(`@rewaffle/bootsharp-file-system`)).init(n)}catch{}await t.boot()})(),o}const c=globalThis;let l=null,u=[],d=0;function f(){for(let e of u)e();u=[]}function p(){f();let t=e=>{c.postMessage({type:`result`,workerIndex:d,seed:e.seed,score:e.score,tallyColumns:Array.from(e.tallies)})};e.onScoredResult.subscribe(t),u.push(()=>e.onScoredResult.unsubscribe(t));let n=e=>{c.postMessage({type:`progress`,workerIndex:d,searched:Number(e.seedsSearched),matching:Number(e.matchingSeeds),percent:e.percentComplete,seedsPerMs:e.seedsPerMillisecond})};e.onProgress.subscribe(n),u.push(()=>e.onProgress.unsubscribe(n));let r=e=>{c.postMessage({type:`match`,workerIndex:d,seed:e})};e.onSeedMatch.subscribe(r),u.push(()=>e.onSeedMatch.unsubscribe(r))}function m(e,t){return typeof t.deck==`number`&&(e.deck=t.deck),typeof t.stake==`number`&&(e.stake=t.stake),e}function h(t){let n=m(e.fromJaml(t.jaml),t);switch(t.mode){case`aesthetic`:return e.runAestheticSearch(n,t.aesthetic??0);case`seedlist`:return n.seeds=t.seeds??[],e.runSeedListSearch(n);case`random`:{let r=typeof t.count==`number`&&t.count>0?t.count:0;return e.runRandomSearch(n,r)}case`sequential`:{let r=typeof t.startBatchIndex==`string`?BigInt(t.startBatchIndex):void 0,i=typeof t.endBatchIndex==`string`?BigInt(t.endBatchIndex):void 0,a=typeof t.batchCharacterCount==`number`?t.batchCharacterCount:void 0;return e.runSequentialSearch(n,r,i,a)}default:return e.runAestheticSearch(n,0)}}c.onmessage=async t=>{let n=t.data;if(n.type===`stop`){l?.cancel(),f(),c.postMessage({type:`cancelled`,workerIndex:d});return}if(n.type===`start`){d=n.workerIndex;try{await s();let t=!!n.predicateStr;if(n.predicateStr)try{let t=Function(`result`,`return (${n.predicateStr})(result);`);i(e=>t(e)),e.jimmolateEnabled=!0}catch(e){console.error(`Failed to compile worker Jimmolate predicate:`,e)}p();try{let e=h(n);l=e,c.postMessage({type:`complete`,workerIndex:d,status:e.isCompleted?`Completed`:`Cancelled`,total:Number(e.totalSeedsSearched),matched:Number(e.matchingSeeds)})}finally{t&&(e.jimmolateEnabled=!1,a()),f(),l=null}}catch(e){f(),l=null,c.postMessage({type:`error`,workerIndex:d,message:e instanceof Error?e.message:String(e)})}}},c.postMessage({type:`ready`});
2
- //# sourceMappingURL=searchPoolWorker-BVUnMwk8.js.map
1
+ import{Program as e}from"motely-wasm/motely/wasm";import t from"motely-wasm";import{IFileMounter as n}from"motely-wasm/bootsharp/file-system";let r=()=>!0;e.jimmolatePredicate=e=>r(e);function i(e){r=e}function a(){r=()=>!0}let o=null;async function s(){if(o)return o;if(t.getStatus()===t.BootStatus.Standby)return o=(async()=>{try{(await import(`@rewaffle/bootsharp-file-system`)).init(n)}catch{}await t.boot()})(),o}const c=globalThis;let l=null,u=[],d=0;function f(){for(let e of u)e();u=[]}function p(){f();let t=e=>{c.postMessage({type:`result`,workerIndex:d,seed:e.seed,score:e.score,tallyColumns:Array.from(e.tallies)})};e.onScoredResult.subscribe(t),u.push(()=>e.onScoredResult.unsubscribe(t));let n=e=>{c.postMessage({type:`progress`,workerIndex:d,searched:Number(e.seedsSearched),matching:Number(e.matchingSeeds),percent:e.percentComplete,seedsPerMs:e.seedsPerMillisecond})};e.onProgress.subscribe(n),u.push(()=>e.onProgress.unsubscribe(n));let r=e=>{c.postMessage({type:`match`,workerIndex:d,seed:e})};e.onSeedMatch.subscribe(r),u.push(()=>e.onSeedMatch.unsubscribe(r))}function m(e,t){return typeof t.deck==`number`&&(e.deck=t.deck),typeof t.stake==`number`&&(e.stake=t.stake),e}function h(t){let n=m(e.fromYaml(t.jaml),t);switch(t.mode){case`aesthetic`:return e.runAestheticSearch(n,t.aesthetic??0);case`seedlist`:return n.seeds=t.seeds??[],e.runSeedListSearch(n);case`random`:{let r=typeof t.count==`number`&&t.count>0?t.count:0;return e.runRandomSearch(n,r)}case`sequential`:{let r=typeof t.startBatchIndex==`string`?BigInt(t.startBatchIndex):void 0,i=typeof t.endBatchIndex==`string`?BigInt(t.endBatchIndex):void 0,a=typeof t.batchCharacterCount==`number`?t.batchCharacterCount:void 0;return e.runSequentialSearch(n,r,i,a)}default:return e.runAestheticSearch(n,0)}}c.onmessage=async t=>{let n=t.data;if(n.type===`stop`){l?.cancel(),f(),c.postMessage({type:`cancelled`,workerIndex:d});return}if(n.type===`start`){d=n.workerIndex;try{await s();let t=!!n.predicateStr;if(n.predicateStr)try{let t=Function(`result`,`return (${n.predicateStr})(result);`);i(e=>t(e)),e.jimmolateEnabled=!0}catch(e){console.error(`Failed to compile worker Jimmolate predicate:`,e)}p();try{let e=h(n);l=e,c.postMessage({type:`complete`,workerIndex:d,status:e.isCompleted?`Completed`:`Cancelled`,total:Number(e.totalSeedsSearched),matched:Number(e.matchingSeeds)})}finally{t&&(e.jimmolateEnabled=!1,a()),f(),l=null}}catch(e){f(),l=null,c.postMessage({type:`error`,workerIndex:d,message:e instanceof Error?e.message:String(e)})}}},c.postMessage({type:`ready`});
2
+ //# sourceMappingURL=searchPoolWorker-BdrYmnig.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"searchPoolWorker-BVUnMwk8.js","names":[],"sources":["../../src/lib/motely/runtime.ts","../../src/hooks/searchPoolWorker.ts"],"sourcesContent":["import bootsharp from \"motely-wasm\";\nimport { Program as Motely } from \"motely-wasm/motely/wasm\";\nimport type { MotelyScoredSeedResult } from \"motely-wasm/motely\";\nimport { IFileMounter } from \"motely-wasm/bootsharp/file-system\";\n\nexport type MotelyRuntimeStatus = \"idle\" | \"booting\" | \"ready\" | \"error\";\n\n// Jimmolate probe dispatcher.\n//\n// Bootsharp snapshots [Import] bindings at boot() — assigning\n// `Motely.jimmolatePredicate` AFTER boot is a silent no-op, so we bind a STABLE\n// dispatcher here at module load (always before any ensureMotelyReady()/boot()\n// call) and swap the inner predicate per search via setJimmolateProbe().\n// `Motely.jimmolateEnabled` is a plain settable, fine to flip after boot.\n//\n// motely-wasm 21.1 reshaped the probe: it now receives the scored result\n// ({seed, score, tallies}) instead of a search context.\nexport type JimmolateProbe = (result: MotelyScoredSeedResult) => boolean;\nlet currentProbe: JimmolateProbe = () => true;\nMotely.jimmolatePredicate = (result: MotelyScoredSeedResult) => currentProbe(result);\n\n/** Swap the active Jimmolate predicate. Safe before or after boot. */\nexport function setJimmolateProbe(pred: JimmolateProbe): void {\n currentProbe = pred;\n}\n\n/** Reset the probe to pass-through (the engine's default: every survivor matches). */\nexport function clearJimmolateProbe(): void {\n currentProbe = () => true;\n}\n\n// Must match the path the host serves motely-wasm's bin/ at.\n// Used by main-thread hooks, workers, and Storybook staticDir alike.\n// The Storybook staticDir in .storybook/main.ts serves it here.\n// Next.js consumers must serve it at this path too (e.g. via a catch-all route).\n// A bare \"/bin\" would 404 in every deployment context.\nexport const MOTELY_BIN_PATH = \"/motely-wasm/bin\";\n\n// File System extension (optional peer `@rewaffle/bootsharp-file-system`).\n//\n// fs.init() binds the IFileMounter [Import], which — like the Jimmolate probe\n// above and EVERY Bootsharp [Import] — must be assigned BEFORE boot()\n// (Bootsharp docs: extensions/file-system). The package is an OPTIONAL peer, so\n// we dynamically import it and swallow its absence: consumers without it simply\n// get no library mount (useJamlLibrary reports status \"unsupported\").\n//\n// This MUST live in the one centralized boot path, not in a component effect.\n// ~8 callers (useSearch, the workers, useAnalyzer, Jamlyzer, …) each trigger\n// boot via ensureMotelyReady(); whichever fires first wins. If fs.init() sat in\n// useJamlLibrary's useEffect it would lose that race and the mounter would never\n// be bound pre-boot — which is exactly why the library mount silently failed.\nlet fileSystemReady = false;\nlet fileSystemError: unknown = null;\n\n/** True once the optional File System extension was bound before boot. */\nexport function isFileSystemReady(): boolean {\n return fileSystemReady;\n}\n\n/** The error from a failed or absent File System init, if any. */\nexport function getFileSystemError(): unknown {\n return fileSystemError;\n}\n\n// Single boot promise: fs.init() (pre-boot) → boot(), run exactly once and\n// awaited by every caller, so the ordering holds no matter who boots first.\nlet bootPromise: Promise<void> | null = null;\n\nexport async function ensureMotelyReady(): Promise<void> {\n if (bootPromise) return bootPromise;\n if (bootsharp.getStatus() !== bootsharp.BootStatus.Standby) return;\n bootPromise = (async () => {\n // Pre-boot: bind the optional File System mounter if it's installed.\n try {\n // @vite-ignore — optional peer; may be absent on disk. Keep it a\n // runtime import() so Vite's dev import-analysis (Storybook, demo)\n // doesn't try to resolve it at transform time and hard-fail. When\n // missing it throws here and is swallowed → status \"unsupported\".\n // (The library build externalizes it via PEER_EXTERNALS regardless.)\n const fs = await import(/* @vite-ignore */ \"@rewaffle/bootsharp-file-system\");\n fs.init(IFileMounter);\n fileSystemReady = true;\n } catch (error) {\n fileSystemError = error;\n }\n // motely-wasm is an EMBEDDED build (the runtime is inlined into the JS as\n // base64 — see dist/generated/resources.g.mjs), so boot() takes no args and\n // needs no served binaries. The old boot(\"/motely-wasm/bin\") was leftover\n // sideloaded config and 404'd in every context.\n await bootsharp.boot();\n })();\n return bootPromise;\n}\n","/// <reference lib=\"webworker\" />\n\n// Pool worker. Each instance boots its own motely-wasm runtime (single-threaded\n// per Bootsharp 0.8 post-#203 — no SAB, no COOP/COEP). The owning `useSearchPool`\n// hook is responsible for partitioning the input space and assigning each worker\n// a disjoint slice via the fields on PoolStartMessage. This worker just runs\n// what it is told.\nimport { Program as Motely } from \"motely-wasm/motely/wasm\";\nimport type { IMotelySearch, MotelyProgress, MotelyScoredSeedResult } from \"motely-wasm/motely\";\nimport type { MotelyDeck, MotelyStake } from \"motely-wasm/motely/enums\";\nimport type { JamlAesthetic, JamlConfig } from \"motely-wasm/motely/filters/jaml\";\nimport { ensureMotelyReady, setJimmolateProbe, clearJimmolateProbe } from \"../lib/motely/runtime.js\";\n\nconst self = globalThis as typeof globalThis & DedicatedWorkerGlobalScope;\n\nexport type PoolSearchMode = \"random\" | \"seedlist\" | \"sequential\" | \"aesthetic\";\n\nexport interface PoolStartMessage {\n type: \"start\";\n workerIndex: number;\n workerCount: number;\n mode: PoolSearchMode;\n jaml: string;\n count?: number;\n seeds?: string[];\n batchCharacterCount?: number;\n startBatchIndex?: string;\n endBatchIndex?: string;\n aesthetic?: number;\n deck?: number;\n stake?: number;\n predicateStr?: string;\n}\n\nexport interface PoolStopMessage {\n type: \"stop\";\n}\n\nexport type PoolInboundMessage = PoolStartMessage | PoolStopMessage;\n\nexport interface PoolReadyMessage {\n type: \"ready\";\n}\n\nexport interface PoolResultMessage {\n type: \"result\";\n workerIndex: number;\n seed: string;\n score: number;\n tallyColumns: number[];\n}\n\nexport interface PoolMatchMessage {\n type: \"match\";\n workerIndex: number;\n seed: string;\n}\n\nexport interface PoolProgressMessage {\n type: \"progress\";\n workerIndex: number;\n searched: number;\n matching: number;\n percent: number;\n seedsPerMs: number;\n}\n\nexport interface PoolCompleteMessage {\n type: \"complete\";\n workerIndex: number;\n status: \"Completed\" | \"Cancelled\";\n total: number;\n matched: number;\n}\n\nexport interface PoolCancelledMessage {\n type: \"cancelled\";\n workerIndex: number;\n}\n\nexport interface PoolErrorMessage {\n type: \"error\";\n workerIndex: number;\n message: string;\n}\n\nexport type PoolOutboundMessage =\n | PoolReadyMessage\n | PoolResultMessage\n | PoolMatchMessage\n | PoolProgressMessage\n | PoolCompleteMessage\n | PoolCancelledMessage\n | PoolErrorMessage;\n\nlet currentSearch: IMotelySearch | null = null;\nlet unsubscribers: Array<() => void> = [];\nlet workerIndex = 0;\n\nfunction detachListeners(): void {\n for (const off of unsubscribers) off();\n unsubscribers = [];\n}\n\nfunction attachListeners(): void {\n detachListeners();\n\n const onResult = (result: MotelyScoredSeedResult) => {\n self.postMessage({\n type: \"result\",\n workerIndex,\n seed: result.seed,\n score: result.score,\n tallyColumns: Array.from(result.tallies),\n } satisfies PoolResultMessage);\n };\n Motely.onScoredResult.subscribe(onResult);\n unsubscribers.push(() => Motely.onScoredResult.unsubscribe(onResult));\n\n const onProgress = (progress: MotelyProgress) => {\n self.postMessage({\n type: \"progress\",\n workerIndex,\n searched: Number(progress.seedsSearched),\n matching: Number(progress.matchingSeeds),\n percent: progress.percentComplete,\n seedsPerMs: progress.seedsPerMillisecond,\n } satisfies PoolProgressMessage);\n };\n Motely.onProgress.subscribe(onProgress);\n unsubscribers.push(() => Motely.onProgress.unsubscribe(onProgress));\n\n const onSeedMatch = (seed: string) => {\n self.postMessage({\n type: \"match\",\n workerIndex,\n seed,\n } satisfies PoolMatchMessage);\n };\n Motely.onSeedMatch.subscribe(onSeedMatch);\n unsubscribers.push(() => Motely.onSeedMatch.unsubscribe(onSeedMatch));\n}\n\n// deck/stake are config fields now; the worker is single-threaded, so the old\n// withThreadCount(1) is dropped (it was a no-op here).\nfunction applyCommonOverrides(config: JamlConfig, message: PoolStartMessage): JamlConfig {\n if (typeof message.deck === \"number\") {\n config.deck = message.deck as MotelyDeck;\n }\n if (typeof message.stake === \"number\") {\n config.stake = message.stake as MotelyStake;\n }\n return config;\n}\n\n// motely-wasm 21: Program.run*Search executes synchronously to completion and\n// returns the finished IMotelySearch — this RUNS the search, not just configures.\nfunction runConfigured(message: PoolStartMessage): IMotelySearch {\n const config = applyCommonOverrides(Motely.fromJaml(message.jaml), message);\n\n switch (message.mode) {\n case \"aesthetic\":\n return Motely.runAestheticSearch(config, (message.aesthetic ?? 0) as JamlAesthetic);\n case \"seedlist\": {\n config.seeds = message.seeds ?? [];\n return Motely.runSeedListSearch(config);\n }\n case \"random\": {\n const count = typeof message.count === \"number\" && message.count > 0 ? message.count : 0;\n return Motely.runRandomSearch(config, count);\n }\n case \"sequential\": {\n const start = typeof message.startBatchIndex === \"string\" ? BigInt(message.startBatchIndex) : undefined;\n const end = typeof message.endBatchIndex === \"string\" ? BigInt(message.endBatchIndex) : undefined;\n const batchChars = typeof message.batchCharacterCount === \"number\" ? message.batchCharacterCount : undefined;\n return Motely.runSequentialSearch(config, start, end, batchChars);\n }\n default:\n return Motely.runAestheticSearch(config, 0 as JamlAesthetic);\n }\n}\n\nself.onmessage = async (event: MessageEvent) => {\n const data = event.data as PoolInboundMessage;\n\n if (data.type === \"stop\") {\n currentSearch?.cancel();\n detachListeners();\n self.postMessage({ type: \"cancelled\", workerIndex } satisfies PoolCancelledMessage);\n return;\n }\n\n if (data.type !== \"start\") return;\n\n workerIndex = data.workerIndex;\n\n try {\n await ensureMotelyReady();\n\n // motely-wasm 21.1 jimmolate shape: predicate receives the scored\n // result ({seed, score, tallies}), not (seed, deck, stake).\n const useJimmolate = Boolean(data.predicateStr);\n if (data.predicateStr) {\n try {\n const pred = new Function(\"result\", `return (${data.predicateStr})(result);`) as (result: MotelyScoredSeedResult) => boolean;\n setJimmolateProbe((result) => pred(result));\n Motely.jimmolateEnabled = true;\n } catch (err) {\n console.error(\"Failed to compile worker Jimmolate predicate:\", err);\n }\n }\n\n attachListeners();\n\n try {\n const search = runConfigured(data);\n currentSearch = search;\n self.postMessage({\n type: \"complete\",\n workerIndex,\n status: search.isCompleted ? \"Completed\" : \"Cancelled\",\n total: Number(search.totalSeedsSearched),\n matched: Number(search.matchingSeeds),\n } satisfies PoolCompleteMessage);\n } finally {\n if (useJimmolate) {\n Motely.jimmolateEnabled = false;\n clearJimmolateProbe();\n }\n detachListeners();\n currentSearch = null;\n }\n } catch (error) {\n detachListeners();\n currentSearch = null;\n self.postMessage({\n type: \"error\",\n workerIndex,\n message: error instanceof Error ? error.message : String(error),\n } satisfies PoolErrorMessage);\n }\n};\n\nself.postMessage({ type: \"ready\" } satisfies PoolReadyMessage);\n"],"mappings":"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"}
1
+ {"version":3,"file":"searchPoolWorker-BdrYmnig.js","names":[],"sources":["../../src/lib/motely/runtime.ts","../../src/hooks/searchPoolWorker.ts"],"sourcesContent":["import bootsharp from \"motely-wasm\";\nimport { Program as Motely } from \"motely-wasm/motely/wasm\";\nimport type { MotelyScoredSeedResult } from \"motely-wasm/motely\";\nimport { IFileMounter } from \"motely-wasm/bootsharp/file-system\";\n\nexport type MotelyRuntimeStatus = \"idle\" | \"booting\" | \"ready\" | \"error\";\n\n// Jimmolate probe dispatcher.\n//\n// Bootsharp snapshots [Import] bindings at boot() — assigning\n// `Motely.jimmolatePredicate` AFTER boot is a silent no-op, so we bind a STABLE\n// dispatcher here at module load (always before any ensureMotelyReady()/boot()\n// call) and swap the inner predicate per search via setJimmolateProbe().\n// `Motely.jimmolateEnabled` is a plain settable, fine to flip after boot.\n//\n// motely-wasm 21.1 reshaped the probe: it now receives the scored result\n// ({seed, score, tallies}) instead of a search context.\nexport type JimmolateProbe = (result: MotelyScoredSeedResult) => boolean;\nlet currentProbe: JimmolateProbe = () => true;\nMotely.jimmolatePredicate = (result: MotelyScoredSeedResult) => currentProbe(result);\n\n/** Swap the active Jimmolate predicate. Safe before or after boot. */\nexport function setJimmolateProbe(pred: JimmolateProbe): void {\n currentProbe = pred;\n}\n\n/** Reset the probe to pass-through (the engine's default: every survivor matches). */\nexport function clearJimmolateProbe(): void {\n currentProbe = () => true;\n}\n\n// Must match the path the host serves motely-wasm's bin/ at.\n// Used by main-thread hooks, workers, and Storybook staticDir alike.\n// The Storybook staticDir in .storybook/main.ts serves it here.\n// Next.js consumers must serve it at this path too (e.g. via a catch-all route).\n// A bare \"/bin\" would 404 in every deployment context.\nexport const MOTELY_BIN_PATH = \"/motely-wasm/bin\";\n\n// File System extension (optional peer `@rewaffle/bootsharp-file-system`).\n//\n// fs.init() binds the IFileMounter [Import], which — like the Jimmolate probe\n// above and EVERY Bootsharp [Import] — must be assigned BEFORE boot()\n// (Bootsharp docs: extensions/file-system). The package is an OPTIONAL peer, so\n// we dynamically import it and swallow its absence: consumers without it simply\n// get no library mount (useJamlLibrary reports status \"unsupported\").\n//\n// This MUST live in the one centralized boot path, not in a component effect.\n// ~8 callers (useSearch, the workers, useAnalyzer, Jamlyzer, …) each trigger\n// boot via ensureMotelyReady(); whichever fires first wins. If fs.init() sat in\n// useJamlLibrary's useEffect it would lose that race and the mounter would never\n// be bound pre-boot — which is exactly why the library mount silently failed.\nlet fileSystemReady = false;\nlet fileSystemError: unknown = null;\n\n/** True once the optional File System extension was bound before boot. */\nexport function isFileSystemReady(): boolean {\n return fileSystemReady;\n}\n\n/** The error from a failed or absent File System init, if any. */\nexport function getFileSystemError(): unknown {\n return fileSystemError;\n}\n\n// Single boot promise: fs.init() (pre-boot) → boot(), run exactly once and\n// awaited by every caller, so the ordering holds no matter who boots first.\nlet bootPromise: Promise<void> | null = null;\n\nexport async function ensureMotelyReady(): Promise<void> {\n if (bootPromise) return bootPromise;\n if (bootsharp.getStatus() !== bootsharp.BootStatus.Standby) return;\n bootPromise = (async () => {\n // Pre-boot: bind the optional File System mounter if it's installed.\n try {\n // @vite-ignore — optional peer; may be absent on disk. Keep it a\n // runtime import() so Vite's dev import-analysis (Storybook, demo)\n // doesn't try to resolve it at transform time and hard-fail. When\n // missing it throws here and is swallowed → status \"unsupported\".\n // (The library build externalizes it via PEER_EXTERNALS regardless.)\n const fs = await import(/* @vite-ignore */ \"@rewaffle/bootsharp-file-system\");\n fs.init(IFileMounter);\n fileSystemReady = true;\n } catch (error) {\n fileSystemError = error;\n }\n // motely-wasm is an EMBEDDED build (the runtime is inlined into the JS as\n // base64 — see dist/generated/resources.g.mjs), so boot() takes no args and\n // needs no served binaries. The old boot(\"/motely-wasm/bin\") was leftover\n // sideloaded config and 404'd in every context.\n await bootsharp.boot();\n })();\n return bootPromise;\n}\n","/// <reference lib=\"webworker\" />\n\n// Pool worker. Each instance boots its own motely-wasm runtime (single-threaded\n// per Bootsharp 0.8 post-#203 — no SAB, no COOP/COEP). The owning `useSearchPool`\n// hook is responsible for partitioning the input space and assigning each worker\n// a disjoint slice via the fields on PoolStartMessage. This worker just runs\n// what it is told.\nimport { Program as Motely } from \"motely-wasm/motely/wasm\";\nimport type { IMotelySearch, MotelyProgress, MotelyScoredSeedResult } from \"motely-wasm/motely\";\nimport type { MotelyDeck, MotelyStake } from \"motely-wasm/motely/enums\";\nimport type { JamlAesthetic, JamlConfig } from \"motely-wasm/motely/filters/jaml\";\nimport { ensureMotelyReady, setJimmolateProbe, clearJimmolateProbe } from \"../lib/motely/runtime.js\";\n\nconst self = globalThis as typeof globalThis & DedicatedWorkerGlobalScope;\n\nexport type PoolSearchMode = \"random\" | \"seedlist\" | \"sequential\" | \"aesthetic\";\n\nexport interface PoolStartMessage {\n type: \"start\";\n workerIndex: number;\n workerCount: number;\n mode: PoolSearchMode;\n jaml: string;\n count?: number;\n seeds?: string[];\n batchCharacterCount?: number;\n startBatchIndex?: string;\n endBatchIndex?: string;\n aesthetic?: number;\n deck?: number;\n stake?: number;\n predicateStr?: string;\n}\n\nexport interface PoolStopMessage {\n type: \"stop\";\n}\n\nexport type PoolInboundMessage = PoolStartMessage | PoolStopMessage;\n\nexport interface PoolReadyMessage {\n type: \"ready\";\n}\n\nexport interface PoolResultMessage {\n type: \"result\";\n workerIndex: number;\n seed: string;\n score: number;\n tallyColumns: number[];\n}\n\nexport interface PoolMatchMessage {\n type: \"match\";\n workerIndex: number;\n seed: string;\n}\n\nexport interface PoolProgressMessage {\n type: \"progress\";\n workerIndex: number;\n searched: number;\n matching: number;\n percent: number;\n seedsPerMs: number;\n}\n\nexport interface PoolCompleteMessage {\n type: \"complete\";\n workerIndex: number;\n status: \"Completed\" | \"Cancelled\";\n total: number;\n matched: number;\n}\n\nexport interface PoolCancelledMessage {\n type: \"cancelled\";\n workerIndex: number;\n}\n\nexport interface PoolErrorMessage {\n type: \"error\";\n workerIndex: number;\n message: string;\n}\n\nexport type PoolOutboundMessage =\n | PoolReadyMessage\n | PoolResultMessage\n | PoolMatchMessage\n | PoolProgressMessage\n | PoolCompleteMessage\n | PoolCancelledMessage\n | PoolErrorMessage;\n\nlet currentSearch: IMotelySearch | null = null;\nlet unsubscribers: Array<() => void> = [];\nlet workerIndex = 0;\n\nfunction detachListeners(): void {\n for (const off of unsubscribers) off();\n unsubscribers = [];\n}\n\nfunction attachListeners(): void {\n detachListeners();\n\n const onResult = (result: MotelyScoredSeedResult) => {\n self.postMessage({\n type: \"result\",\n workerIndex,\n seed: result.seed,\n score: result.score,\n tallyColumns: Array.from(result.tallies),\n } satisfies PoolResultMessage);\n };\n Motely.onScoredResult.subscribe(onResult);\n unsubscribers.push(() => Motely.onScoredResult.unsubscribe(onResult));\n\n const onProgress = (progress: MotelyProgress) => {\n self.postMessage({\n type: \"progress\",\n workerIndex,\n searched: Number(progress.seedsSearched),\n matching: Number(progress.matchingSeeds),\n percent: progress.percentComplete,\n seedsPerMs: progress.seedsPerMillisecond,\n } satisfies PoolProgressMessage);\n };\n Motely.onProgress.subscribe(onProgress);\n unsubscribers.push(() => Motely.onProgress.unsubscribe(onProgress));\n\n const onSeedMatch = (seed: string) => {\n self.postMessage({\n type: \"match\",\n workerIndex,\n seed,\n } satisfies PoolMatchMessage);\n };\n Motely.onSeedMatch.subscribe(onSeedMatch);\n unsubscribers.push(() => Motely.onSeedMatch.unsubscribe(onSeedMatch));\n}\n\n// deck/stake are config fields now; the worker is single-threaded, so the old\n// withThreadCount(1) is dropped (it was a no-op here).\nfunction applyCommonOverrides(config: JamlConfig, message: PoolStartMessage): JamlConfig {\n if (typeof message.deck === \"number\") {\n config.deck = message.deck as MotelyDeck;\n }\n if (typeof message.stake === \"number\") {\n config.stake = message.stake as MotelyStake;\n }\n return config;\n}\n\n// motely-wasm 21: Program.run*Search executes synchronously to completion and\n// returns the finished IMotelySearch — this RUNS the search, not just configures.\nfunction runConfigured(message: PoolStartMessage): IMotelySearch {\n const config = applyCommonOverrides(Motely.fromYaml(message.jaml), message);\n\n switch (message.mode) {\n case \"aesthetic\":\n return Motely.runAestheticSearch(config, (message.aesthetic ?? 0) as JamlAesthetic);\n case \"seedlist\": {\n config.seeds = message.seeds ?? [];\n return Motely.runSeedListSearch(config);\n }\n case \"random\": {\n const count = typeof message.count === \"number\" && message.count > 0 ? message.count : 0;\n return Motely.runRandomSearch(config, count);\n }\n case \"sequential\": {\n const start = typeof message.startBatchIndex === \"string\" ? BigInt(message.startBatchIndex) : undefined;\n const end = typeof message.endBatchIndex === \"string\" ? BigInt(message.endBatchIndex) : undefined;\n const batchChars = typeof message.batchCharacterCount === \"number\" ? message.batchCharacterCount : undefined;\n return Motely.runSequentialSearch(config, start, end, batchChars);\n }\n default:\n return Motely.runAestheticSearch(config, 0 as JamlAesthetic);\n }\n}\n\nself.onmessage = async (event: MessageEvent) => {\n const data = event.data as PoolInboundMessage;\n\n if (data.type === \"stop\") {\n currentSearch?.cancel();\n detachListeners();\n self.postMessage({ type: \"cancelled\", workerIndex } satisfies PoolCancelledMessage);\n return;\n }\n\n if (data.type !== \"start\") return;\n\n workerIndex = data.workerIndex;\n\n try {\n await ensureMotelyReady();\n\n // motely-wasm 21.1 jimmolate shape: predicate receives the scored\n // result ({seed, score, tallies}), not (seed, deck, stake).\n const useJimmolate = Boolean(data.predicateStr);\n if (data.predicateStr) {\n try {\n const pred = new Function(\"result\", `return (${data.predicateStr})(result);`) as (result: MotelyScoredSeedResult) => boolean;\n setJimmolateProbe((result) => pred(result));\n Motely.jimmolateEnabled = true;\n } catch (err) {\n console.error(\"Failed to compile worker Jimmolate predicate:\", err);\n }\n }\n\n attachListeners();\n\n try {\n const search = runConfigured(data);\n currentSearch = search;\n self.postMessage({\n type: \"complete\",\n workerIndex,\n status: search.isCompleted ? \"Completed\" : \"Cancelled\",\n total: Number(search.totalSeedsSearched),\n matched: Number(search.matchingSeeds),\n } satisfies PoolCompleteMessage);\n } finally {\n if (useJimmolate) {\n Motely.jimmolateEnabled = false;\n clearJimmolateProbe();\n }\n detachListeners();\n currentSearch = null;\n }\n } catch (error) {\n detachListeners();\n currentSearch = null;\n self.postMessage({\n type: \"error\",\n workerIndex,\n message: error instanceof Error ? error.message : String(error),\n } satisfies PoolErrorMessage);\n }\n};\n\nself.postMessage({ type: \"ready\" } satisfies PoolReadyMessage);\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  //#region src/hooks/searchPoolWorker.ts?worker
2
2
  function e(e) {
3
- return new Worker("/assets/searchPoolWorker-BVUnMwk8.js", {
3
+ return new Worker("/assets/searchPoolWorker-BdrYmnig.js", {
4
4
  type: "module",
5
5
  name: e?.name
6
6
  });
@@ -8,4 +8,4 @@ function e(e) {
8
8
  //#endregion
9
9
  export { e as default };
10
10
 
11
- //# sourceMappingURL=searchPoolWorker-Dx7DqN-S.js.map
11
+ //# sourceMappingURL=searchPoolWorker-CEK2FyxS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"searchPoolWorker-CEK2FyxS.js","names":[],"sources":[],"mappings":""}