motely-wasm 17.4.3 → 17.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -11,87 +11,106 @@ npm install motely-wasm
11
11
  ## Quick start
12
12
 
13
13
  ```js
14
- import motely from "motely-wasm";
15
- import { Motely } from "motely-wasm/index";
16
-
17
- // Boot the runtime, pointing at wherever your package assets are served
18
- await motely.boot("/node_modules/motely-wasm");
19
-
20
- // Subscribe to results before starting
21
- Motely.onSeedMatch.subscribe(seed => console.log("match:", seed));
14
+ import bootsharp, { Motely } from "motely-wasm";
15
+
16
+ // Boot the .NET WASM runtime. The argument is the URL path to the package's
17
+ // `bin/` directory (where dotnet.native.wasm is served from).
18
+ await bootsharp.boot("/node_modules/motely-wasm/bin");
19
+
20
+ // A JAML filter see https://github.com/OptimusPi/MotelyJAML for the language.
21
+ const jaml = `
22
+ name: WeeMonday
23
+ deck: Erratic
24
+ stake: Black
25
+ must:
26
+ - joker: WeeJoker
27
+ antes: [1]
28
+ `;
29
+
30
+ // Validate before searching — returns "valid" or an error message.
31
+ const status = Motely.validateJaml(jaml);
32
+ if (status !== "valid") throw new Error(status);
33
+
34
+ // Subscribe to results before starting.
35
+ Motely.onScoredResult.subscribe(r => console.log("match:", r.seed, r.score));
22
36
  Motely.onProgress.subscribe(p => console.log(`${p.percentComplete.toFixed(1)}%`));
23
37
 
24
- // Build and run a search
25
- const search = Motely.createSearch(`
26
- ante-1:
27
- jokers:
28
- - Joker
29
- `).withSequentialSearch()
30
- .createSearch();
38
+ // Build, start, and await a search.
39
+ const search = Motely.createSearch(jaml)
40
+ .withSequentialSearch()
41
+ .start();
31
42
 
32
- search.runSearchUntilCompletion();
43
+ await search.waitForCompletionAsync();
44
+ console.log("done:", search.totalSeedsSearched, "searched,", search.matchingSeeds, "matched");
33
45
  ```
34
46
 
35
47
  ## Booting
36
48
 
37
- `boot(resources, options?)` initializes the .NET WASM runtime. Call it once before any `Motely.*` API.
49
+ `bootsharp.boot(binUrl)` initializes the .NET WASM runtime. Call it once before any
50
+ `Motely.*` API. The argument is the URL path to the `bin/` directory that serves
51
+ `dotnet.native.wasm` — e.g. `/node_modules/motely-wasm/bin`, or wherever your bundler
52
+ copies the package's `bin/` folder.
38
53
 
39
54
  ```js
40
- import motely, { BootStatus } from "motely-wasm";
55
+ import bootsharp, { BootStatus } from "motely-wasm";
41
56
 
42
- // From a URL base path (all .wasm / assembly files served from there)
43
- await motely.boot("/assets/motely-wasm");
57
+ if (bootsharp.getStatus() === bootsharp.BootStatus.Standby) {
58
+ await bootsharp.boot("/node_modules/motely-wasm/bin");
59
+ }
44
60
 
45
- // Check status
46
- console.log(motely.getStatus()); // BootStatus.Booted
61
+ console.log(bootsharp.getStatus()); // BootStatus.Booted
47
62
  ```
48
63
 
49
64
  ## JAML API
50
65
 
51
66
  ```js
52
- import { Motely } from "motely-wasm/index";
67
+ import { Motely } from "motely-wasm";
53
68
 
54
- // Validate a JAML filter string — returns "" on success, error message on failure
55
- const error = Motely.validateJaml(jaml);
69
+ // Validate a JAML filter string — returns "valid" on success, an error message on failure.
70
+ const status = Motely.validateJaml(jaml);
56
71
 
57
- // Get a human-readable explanation of what a JAML filter does
72
+ // Human-readable explanation of what a JAML filter does.
58
73
  const explanation = Motely.explainJaml(jaml);
59
74
 
60
- // Inspect the search plan (tally column count, CSV header, labels)
75
+ // Inspect the search plan (tally column count, CSV header, labels).
61
76
  const plan = Motely.createPlan(jaml);
62
77
 
63
- // Analyze specific seeds against a JAML filter
78
+ // Analyze specific seeds against a JAML filter.
64
79
  const result = Motely.analyzeJamlSeeds(jaml, ["ABCD1234", "XYZ99"]);
65
80
 
66
- // Engine version string
81
+ // Engine version string.
67
82
  console.log(Motely.version());
68
83
  ```
69
84
 
70
85
  ## Running a search
71
86
 
87
+ `Motely.createSearch(jaml)` returns a settings builder. Chain a search-mode method,
88
+ then call `.start()` to get a running `IMotelySearch`.
89
+
72
90
  ```js
73
- import { Motely } from "motely-wasm/index";
74
- import { MotelyDeck, MotelyStake } from "motely-wasm/motely";
91
+ import { Motely } from "motely-wasm";
75
92
 
76
- Motely.onSeedMatch.subscribe(seed => { /* handle match */ });
77
- Motely.onScoredResult.subscribe(result => { /* result.seed, result.score, result.tallies */ });
78
- Motely.onProgress.subscribe(progress => { /* progress.percentComplete, .seedsPerMillisecond, … */ });
93
+ Motely.onSeedMatch.subscribe(seed => { /* matching seed string */ });
94
+ Motely.onScoredResult.subscribe(r => { /* r.seed, r.score, r.tallies */ });
95
+ Motely.onProgress.subscribe(p => { /* p.percentComplete, p.seedsSearched, p.seedsPerMillisecond, … */ });
79
96
 
80
- const settings = Motely.createSearchSettings()
81
- .withDeck(MotelyDeck.Red)
82
- .withStake(MotelyStake.White)
97
+ const settings = Motely.createSearch(jaml)
83
98
  .withSequentialSearch() // enumerate all seeds in order
84
99
  // .withRandomSearch(10_000) // or pick N random seeds
85
- // .withListSearch(seeds, count) // or supply a seed list
100
+ // .withListSearch(seeds, seeds.length) // or supply a seed list
101
+ // .withAestheticSearch(0) // or a JamlAesthetic mode
86
102
  .withProgressReportIntervalMs(500n);
87
103
 
88
- const search = settings.createSearch();
104
+ const search = settings.start();
89
105
 
90
- // Synchronous (blocks until donefine in a Worker)
91
- search.runSearchUntilCompletion();
106
+ // Async (yields between batchesgood on the main thread or in a Worker)
107
+ await search.waitForCompletionAsync();
92
108
 
93
- // Async (yields between batches)
94
- await search.runSearchAsync(undefined);
109
+ // or synchronous (blocks until done — only inside a Worker)
110
+ // search.runSearchUntilCompletion();
111
+
112
+ console.log(search.isCompleted, search.totalSeedsSearched, search.matchingSeeds);
113
+ search.cancel(); // stop early
95
114
  ```
96
115
 
97
116
  ## Events
@@ -100,45 +119,93 @@ await search.runSearchAsync(undefined);
100
119
  |---|---|
101
120
  | `Motely.onSeedMatch` | `string` — matching seed |
102
121
  | `Motely.onScoredResult` | `{ seed, score, tallies }` |
103
- | `Motely.onProgress` | `MotelyProgress` |
104
- | `Motely.onFileChanges` | `FileSystem.Change[]` |
122
+ | `Motely.onProgress` | `MotelyProgress` — `percentComplete`, `seedsSearched`, `matchingSeeds`, `seedsPerMillisecond`, `elapsedMilliseconds` |
123
+ | `Motely.onFileChanges` | `Change[]` (browser file-system mounts) |
105
124
 
106
125
  Subscribe and unsubscribe:
107
126
 
108
127
  ```js
109
- const handler = seed => console.log(seed);
110
- Motely.onSeedMatch.subscribe(handler);
111
- Motely.onSeedMatch.unsubscribe(handler);
128
+ const handler = r => console.log(r.seed);
129
+ Motely.onScoredResult.subscribe(handler);
130
+ Motely.onScoredResult.unsubscribe(handler);
112
131
  ```
113
132
 
114
133
  ## Submodule exports
115
134
 
116
135
  | Import path | Contents |
117
136
  |---|---|
118
- | `motely-wasm` | `boot`, `exit`, `getStatus`, `BootStatus`, `manifest` |
119
- | `motely-wasm/index` | `Motely` namespace (main API) |
120
- | `motely-wasm/motely` | Types: `MotelyDeck`, `MotelyStake`, `MotelyTag`, `MotelyVoucher`, `MotelyBossBlind`, `MotelyBoosterPack`, enums |
137
+ | `motely-wasm` | Default export: `boot`, `getStatus`, `BootStatus`. Named export: `Motely` (main API) |
138
+ | `motely-wasm/motely` | Types: `IMotelySearch`, `IMotelySearchSettingsInterop`, `MotelyProgress`, `MotelyScoredSeedResult`, `MotelyDeck`, `MotelyStake`, enums |
121
139
  | `motely-wasm/motely/filters` | `JamlAesthetic`, `JamlSearchPlan` |
122
- | `motely-wasm/motely/analysis` | `MotelyJamlyzerResult` |
123
- | `motely-wasm/bootsharp/file-system` | File system interop (browser OPFS) |
140
+ | `motely-wasm/motely/analysis` | `MotelyJamlyzerResult`, `MotelySeedAnalysis` |
141
+ | `motely-wasm/bootsharp/file-system` | File-system interop (browser OPFS) — `PermissionMode`, `IFileMounter` |
124
142
 
125
143
  ## Using in a Web Worker
126
144
 
127
- The WASM runtime is single-threaded. For non-blocking UI, run searches in a Worker:
145
+ The WASM runtime is single-threaded. For a non-blocking UI, boot a runtime inside a
146
+ Worker and drive it with messages. This mirrors the proven setup in the `jaml-ui`
147
+ package's `searchWorker.ts`.
128
148
 
129
149
  ```js
130
- // worker.js
131
- import motely from "motely-wasm";
132
- import { Motely } from "motely-wasm/index";
133
-
134
- await motely.boot("/assets/motely-wasm");
150
+ // search-worker.js
151
+ import bootsharp, { Motely } from "motely-wasm";
135
152
 
136
- Motely.onSeedMatch.subscribe(seed => postMessage({ type: "match", seed }));
137
- Motely.onProgress.subscribe(p => postMessage({ type: "progress", p }));
153
+ let currentSearch = null;
138
154
 
139
155
  self.onmessage = async ({ data }) => {
140
- const search = Motely.createSearch(data.jaml).withSequentialSearch().createSearch();
141
- await search.runSearchAsync(undefined);
142
- postMessage({ type: "done" });
156
+ if (data.type === "stop") {
157
+ currentSearch?.cancel();
158
+ self.postMessage({ type: "cancelled" });
159
+ return;
160
+ }
161
+ if (data.type !== "start") return;
162
+
163
+ try {
164
+ if (bootsharp.getStatus() === bootsharp.BootStatus.Standby) {
165
+ await bootsharp.boot("/node_modules/motely-wasm/bin");
166
+ }
167
+
168
+ const onResult = r =>
169
+ self.postMessage({ type: "result", seed: r.seed, score: r.score });
170
+ const onProgress = p =>
171
+ self.postMessage({ type: "progress", percent: p.percentComplete });
172
+ Motely.onScoredResult.subscribe(onResult);
173
+ Motely.onProgress.subscribe(onProgress);
174
+
175
+ try {
176
+ currentSearch = Motely.createSearch(data.jaml)
177
+ .withThreadCount(1)
178
+ .withSequentialSearch()
179
+ .start();
180
+ await currentSearch.waitForCompletionAsync();
181
+ self.postMessage({
182
+ type: "complete",
183
+ total: Number(currentSearch.totalSeedsSearched),
184
+ matched: Number(currentSearch.matchingSeeds),
185
+ });
186
+ } finally {
187
+ Motely.onScoredResult.unsubscribe(onResult);
188
+ Motely.onProgress.unsubscribe(onProgress);
189
+ currentSearch = null;
190
+ }
191
+ } catch (error) {
192
+ self.postMessage({ type: "error", message: String(error?.message ?? error) });
193
+ }
194
+ };
195
+
196
+ self.postMessage({ type: "ready" });
197
+ ```
198
+
199
+ ```js
200
+ // main thread
201
+ const worker = new Worker(new URL("./search-worker.js", import.meta.url), { type: "module" });
202
+
203
+ worker.onmessage = ({ data }) => {
204
+ if (data.type === "result") console.log("match:", data.seed, data.score);
205
+ if (data.type === "progress") console.log(`${data.percent.toFixed(1)}%`);
206
+ if (data.type === "complete") console.log("done:", data.total, data.matched);
143
207
  };
208
+
209
+ worker.postMessage({ type: "start", jaml });
210
+ // worker.postMessage({ type: "stop" }); // cancel early
144
211
  ```
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "motely-wasm",
3
- "version": "17.4.3",
3
+ "version": "17.4.4",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dist/index.mjs",