@aeptus/aexeo-emdash 0.8.7 → 0.8.9

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/CHANGELOG.md CHANGED
@@ -6,6 +6,92 @@ and the project follows [Semantic Versioning](https://semver.org/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.8.9] - 2026-05-04
10
+
11
+ ### Fixed
12
+
13
+ - **`wasm_error: unreachable` on refresh in Astro dev.** v0.8.8
14
+ fixed the Astro/Vite startup regression but a second issue
15
+ remained: refresh evaluation traps with bare
16
+ `wasm_error: unreachable` in Node-loaded WASM. Root cause is
17
+ `std::time::Instant::now()` panicking on
18
+ `wasm32-unknown-unknown` ("time not implemented on this
19
+ platform"). Cloudflare Workers' workerd runtime appears to
20
+ provide a clock shim that masks the panic in production; Node's
21
+ experimental WASM ESM runner does not.
22
+
23
+ Fixed by adding `aexeo_core::time_shim::Instant` — a transparent
24
+ re-export of `std::time::Instant` on non-wasm targets, and a
25
+ no-op `Duration::ZERO` returner on `wasm32-unknown-unknown`.
26
+ Eval-path callers (`static_check.rs` + the intelligence
27
+ modules) swap their import; CLI and native tests still report
28
+ real timings on real OSes. The `RuleTiming` `elapsed_us` value
29
+ in `SiteCheckProfile` is `0` when the bridge runs in the
30
+ plugin, but no host consumes that field from the bridge today.
31
+
32
+ ### Added
33
+
34
+ - **`console_error_panic_hook` in the bridge.** Future Rust
35
+ panics inside the bridge surface as console errors with
36
+ `file:line` + message instead of bare `unreachable` traps.
37
+ Installed lazily at every `#[wasm_bindgen]` entry point;
38
+ `set_once` is idempotent so repeated calls are cheap. Without
39
+ this, the v0.8.7→v0.8.8 `Instant::now()` panic was effectively
40
+ undebuggable from the host side — every future bridge bug now
41
+ carries its own diagnostic.
42
+
43
+ ### Notes for hosts upgrading from 0.8.8
44
+
45
+ - No code changes required. Bump the package; refresh should
46
+ stop trapping in `pnpm dev` / `astro dev`.
47
+ - Production behavior unchanged — the shim is only active on
48
+ the wasm32 build path.
49
+
50
+ ## [0.8.8] - 2026-05-04
51
+
52
+ ### Fixed
53
+
54
+ - **Astro dev mode no longer 500s on every request.** v0.8.7's
55
+ configured runtime relied on a synchronous default `.wasm`
56
+ import that Cloudflare Workers resolved to a
57
+ `WebAssembly.Module`, but Node ESM (Astro 6.1.3 + Vite 7.3.1
58
+ SSR runner) rejected at parse time with
59
+ `SyntaxError: The requested module ... does not provide an
60
+ export named 'default'`. The static import is gone; the plugin
61
+ now uses a dual-path runtime loader:
62
+ - Path A (Cloudflare Workers): dynamic `import()` of the
63
+ `.wasm` resolves to `{ default: WebAssembly.Module }` via
64
+ Wrangler's bundler integration; we use it synchronously.
65
+ - Path B (Node / Astro dev / Vite SSR): when Path A throws or
66
+ yields something that isn't a Module, fall back to
67
+ `node:fs/promises` `readFile` + `WebAssembly.compile`.
68
+ - Path C (browser-like edges): `fetch` + `compileStreaming` as
69
+ a last resort.
70
+
71
+ Production deploys to Cloudflare were unaffected by the v0.8.7
72
+ bug — only `pnpm dev` / `astro dev` workflows hit it. The fix
73
+ preserves the synchronous-Module path on Workers (Path A) so
74
+ there's no production regression.
75
+
76
+ ### Changed
77
+
78
+ - **`vite-plugin-wasm` is no longer required.** With the dual-path
79
+ loader, Vite hosts can drop `vite-plugin-wasm` from dev deps and
80
+ `plugins: [wasm()]` from `vite.plugins`. INSTALL.md updated. The
81
+ plugins remain harmless if left in place — backwards-compatible.
82
+ - **`optimizeDeps: { exclude: ["@aeptus/aexeo-emdash"] }`** is
83
+ still recommended (avoids Vite optimizer churn on dev start) but
84
+ no longer load-bearing.
85
+
86
+ ### Notes for hosts upgrading from 0.8.7
87
+
88
+ - No code changes required for the fix to take effect; just bump
89
+ the package version. Astro dev should work on the next
90
+ `pnpm dev` / `astro dev` run.
91
+ - If you want to clean up after the upgrade: `pnpm remove
92
+ vite-plugin-wasm` and remove `plugins: [wasm()]` + the
93
+ `wasm()` import from `astro.config.mjs`.
94
+
9
95
  ## [0.8.7] - 2026-05-04
10
96
 
11
97
  Picks up upstream aexeo-core 0.0.13 — three quality fixes from
@@ -822,7 +908,9 @@ First public release.
822
908
  `astro.config.mjs` for the WASM import to resolve to a
823
909
  precompiled `WebAssembly.Module`. Not optional.
824
910
 
825
- [Unreleased]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.8.7...HEAD
911
+ [Unreleased]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.8.9...HEAD
912
+ [0.8.9]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.8.8...aexeo-emdash-v0.8.9
913
+ [0.8.8]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.8.7...aexeo-emdash-v0.8.8
826
914
  [0.8.7]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.8.6...aexeo-emdash-v0.8.7
827
915
  [0.8.6]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.8.5...aexeo-emdash-v0.8.6
828
916
  [0.8.5]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.8.4...aexeo-emdash-v0.8.5
package/INSTALL.md CHANGED
@@ -36,14 +36,16 @@ when it's actually needed.
36
36
  ### Install
37
37
 
38
38
  ```bash
39
- npm install @aeptus/aexeo-emdash vite-plugin-wasm
39
+ npm install @aeptus/aexeo-emdash
40
40
  ```
41
41
 
42
- `vite-plugin-wasm` is required because Vite's defaults treat `.wasm`
43
- imports as static-asset URLs, but Cloudflare Workers can only run
44
- WASM as precompiled `WebAssembly.Module` instances. The plugin
45
- bridges the two; without it, the Aexeo plugin's first call throws
46
- "WASM module did not resolve to a WebAssembly.Module."
42
+ Starting in v0.8.8 the plugin loads its WASM internally with a
43
+ dual-path runtime that tries the bundler-resolved import first
44
+ (Cloudflare Workers) and falls back to `node:fs/promises` +
45
+ `WebAssembly.compile` (Astro dev / Node ESM / Vite SSR runner).
46
+ Earlier versions required `vite-plugin-wasm` because the plugin's
47
+ single static `.wasm` import broke Astro dev mode with a
48
+ SyntaxError; that's no longer needed.
47
49
 
48
50
  > **If installing from a private git remote or as a vendored
49
51
  > directory** — see the "Alternative install sources" section at the
@@ -57,19 +59,15 @@ import { d1, r2 } from "@emdash-cms/cloudflare";
57
59
  import { aexeoPlugin } from "@aeptus/aexeo-emdash";
58
60
  import { defineConfig } from "astro/config";
59
61
  import emdash from "emdash/astro";
60
- import wasm from "vite-plugin-wasm";
61
62
 
62
63
  export default defineConfig({
63
64
  output: "server",
64
65
  adapter: cloudflare(),
65
66
  vite: {
66
- // Required: makes `import x from "./foo.wasm"` resolve to a
67
- // precompiled WebAssembly.Module. Cloudflare Workers /
68
- // workerd disallow runtime WebAssembly.instantiate from raw
69
- // bytes, so the bundler has to do the compilation.
70
- plugins: [wasm()],
71
- // The Aexeo plugin's WASM import confuses Vite's dep
72
- // optimizer when it tries to pre-bundle the package.
67
+ // Recommended: prevents Vite's dep optimizer from trying to
68
+ // pre-bundle the package, which churns on every dev start.
69
+ // The plugin itself works without this — but the optimizer
70
+ // chatter is annoying.
73
71
  optimizeDeps: { exclude: ["@aeptus/aexeo-emdash"] },
74
72
  },
75
73
  integrations: [
@@ -82,6 +80,12 @@ export default defineConfig({
82
80
  });
83
81
  ```
84
82
 
83
+ > **Upgrading from 0.8.7 or earlier?** You can drop `vite-plugin-wasm`
84
+ > from your dev dependencies and `plugins: [wasm()]` from the Vite
85
+ > config; the new dual-path loader handles both runtimes internally.
86
+ > Leaving them in place is harmless if you'd rather not touch the
87
+ > config right away.
88
+
85
89
  That's it for code. No environment variables, no secrets to manage,
86
90
  no sidecar to deploy.
87
91
 
@@ -233,7 +233,10 @@ async function readFindings(kv, route) {
233
233
  var aexeo_emdash_bridge_bg_exports = {};
234
234
  __export(aexeo_emdash_bridge_bg_exports, {
235
235
  __wbg_Error_960c155d3d49e4c2: () => __wbg_Error_960c155d3d49e4c2,
236
+ __wbg_error_a6fa202b58aa1cd3: () => __wbg_error_a6fa202b58aa1cd3,
237
+ __wbg_new_227d7c05414eb861: () => __wbg_new_227d7c05414eb861,
236
238
  __wbg_set_wasm: () => __wbg_set_wasm,
239
+ __wbg_stack_3b0d974bbf31e44f: () => __wbg_stack_3b0d974bbf31e44f,
237
240
  __wbindgen_init_externref_table: () => __wbindgen_init_externref_table,
238
241
  evaluateDocuments: () => evaluateDocuments,
239
242
  generateFactsPrompt: () => generateFactsPrompt,
@@ -334,6 +337,28 @@ function __wbg_Error_960c155d3d49e4c2(arg0, arg1) {
334
337
  const ret = Error(getStringFromWasm0(arg0, arg1));
335
338
  return ret;
336
339
  }
340
+ function __wbg_error_a6fa202b58aa1cd3(arg0, arg1) {
341
+ let deferred0_0;
342
+ let deferred0_1;
343
+ try {
344
+ deferred0_0 = arg0;
345
+ deferred0_1 = arg1;
346
+ console.error(getStringFromWasm0(arg0, arg1));
347
+ } finally {
348
+ wasm.__wbindgen_free(deferred0_0, deferred0_1, 1);
349
+ }
350
+ }
351
+ function __wbg_new_227d7c05414eb861() {
352
+ const ret = new Error();
353
+ return ret;
354
+ }
355
+ function __wbg_stack_3b0d974bbf31e44f(arg0, arg1) {
356
+ const ret = arg1.stack;
357
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
358
+ const len1 = WASM_VECTOR_LEN;
359
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
360
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
361
+ }
337
362
  function __wbindgen_init_externref_table() {
338
363
  const table = wasm.__wbindgen_externrefs;
339
364
  const offset = table.grow(4);
@@ -343,6 +368,13 @@ function __wbindgen_init_externref_table() {
343
368
  table.set(offset + 2, true);
344
369
  table.set(offset + 3, false);
345
370
  }
371
+ var cachedDataViewMemory0 = null;
372
+ function getDataViewMemory0() {
373
+ if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || cachedDataViewMemory0.buffer.detached === void 0 && cachedDataViewMemory0.buffer !== wasm.memory.buffer) {
374
+ cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
375
+ }
376
+ return cachedDataViewMemory0;
377
+ }
346
378
  function getStringFromWasm0(ptr, len) {
347
379
  ptr = ptr >>> 0;
348
380
  return decodeText(ptr, len);
@@ -423,17 +455,40 @@ function __wbg_set_wasm(val) {
423
455
  }
424
456
 
425
457
  // src/wasm-init.ts
426
- import bridgeModule from "../wasm/aexeo_emdash_bridge_bg.wasm";
458
+ var WASM_SPECIFIER = "../wasm/aexeo_emdash_bridge_bg.wasm";
427
459
  var initialized = false;
428
- function ensureInitialized() {
460
+ var cachedModule = null;
461
+ async function loadBridgeModule() {
462
+ if (cachedModule !== null) {
463
+ return cachedModule;
464
+ }
465
+ try {
466
+ const mod = await import(WASM_SPECIFIER);
467
+ if (mod.default instanceof WebAssembly.Module) {
468
+ cachedModule = mod.default;
469
+ return cachedModule;
470
+ }
471
+ } catch {
472
+ }
473
+ const wasmUrl = new URL(WASM_SPECIFIER, import.meta.url);
474
+ if (wasmUrl.protocol === "file:") {
475
+ const [{ readFile }, { fileURLToPath }] = await Promise.all([
476
+ import("node:fs/promises"),
477
+ import("node:url")
478
+ ]);
479
+ const bytes = await readFile(fileURLToPath(wasmUrl));
480
+ cachedModule = await WebAssembly.compile(bytes);
481
+ return cachedModule;
482
+ }
483
+ const response = await fetch(wasmUrl);
484
+ cachedModule = await WebAssembly.compileStreaming(response);
485
+ return cachedModule;
486
+ }
487
+ async function ensureInitialized() {
429
488
  if (initialized) {
430
489
  return;
431
490
  }
432
- if (!(bridgeModule instanceof WebAssembly.Module)) {
433
- throw new Error(
434
- "aexeo: WASM module did not resolve to a WebAssembly.Module \u2014 the consumer's bundler isn't configured for .wasm imports. Add the .wasm loader to your Vite/wrangler config; see @aeptus/aexeo-emdash INSTALL.md for the recipe."
435
- );
436
- }
491
+ const bridgeModule = await loadBridgeModule();
437
492
  const instance = new WebAssembly.Instance(bridgeModule, {
438
493
  "./aexeo_emdash_bridge_bg.js": aexeo_emdash_bridge_bg_exports
439
494
  });
@@ -442,19 +497,19 @@ function ensureInitialized() {
442
497
  initialized = true;
443
498
  }
444
499
  async function evaluateDocuments2(documentsJson, configJson) {
445
- ensureInitialized();
500
+ await ensureInitialized();
446
501
  return evaluateDocuments(documentsJson, configJson);
447
502
  }
448
503
  async function scoreIntelligence2(documentsJson, manifestJson) {
449
- ensureInitialized();
504
+ await ensureInitialized();
450
505
  return scoreIntelligence(documentsJson, manifestJson ?? void 0);
451
506
  }
452
507
  async function generateFactsPrompt2(documentsJson) {
453
- ensureInitialized();
508
+ await ensureInitialized();
454
509
  return generateFactsPrompt(documentsJson);
455
510
  }
456
511
  async function validateFactsManifest2(manifestJson, documentsJson) {
457
- ensureInitialized();
512
+ await ensureInitialized();
458
513
  return validateFactsManifest(manifestJson, documentsJson);
459
514
  }
460
515
 
@@ -1160,7 +1215,7 @@ function globToMatcher(pattern) {
1160
1215
  }
1161
1216
 
1162
1217
  // src/version.ts
1163
- var PACKAGE_VERSION = "0.8.7";
1218
+ var PACKAGE_VERSION = "0.8.9";
1164
1219
 
1165
1220
  // src/configured.ts
1166
1221
  import { definePlugin } from "emdash";
package/dist/index.js CHANGED
@@ -23,7 +23,7 @@ function buildAllowedHosts(evaluatorHost) {
23
23
  }
24
24
 
25
25
  // src/version.ts
26
- var PACKAGE_VERSION = "0.8.7";
26
+ var PACKAGE_VERSION = "0.8.9";
27
27
 
28
28
  // src/sandbox.ts
29
29
  function aexeoPluginSandboxed(options = {}) {
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const PACKAGE_VERSION = "0.8.7";
1
+ export declare const PACKAGE_VERSION = "0.8.9";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"wasm-init.d.ts","sourceRoot":"","sources":["../src/wasm-init.ts"],"names":[],"mappings":"AAmDA,wBAAsB,iBAAiB,CACrC,aAAa,EAAE,MAAM,EACrB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,GACzB,OAAO,CAAC,MAAM,CAAC,CAGjB;AAED,wBAAsB,iBAAiB,CACrC,aAAa,EAAE,MAAM,EACrB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,GAC3B,OAAO,CAAC,MAAM,CAAC,CAGjB;AAID,wBAAsB,mBAAmB,CACvC,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,CAAC,CAGjB;AAKD,wBAAsB,qBAAqB,CACzC,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,CAAC,CAGjB"}
1
+ {"version":3,"file":"wasm-init.d.ts","sourceRoot":"","sources":["../src/wasm-init.ts"],"names":[],"mappings":"AA0GA,wBAAsB,iBAAiB,CACrC,aAAa,EAAE,MAAM,EACrB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,GACzB,OAAO,CAAC,MAAM,CAAC,CAGjB;AAED,wBAAsB,iBAAiB,CACrC,aAAa,EAAE,MAAM,EACrB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,GAC3B,OAAO,CAAC,MAAM,CAAC,CAGjB;AAID,wBAAsB,mBAAmB,CACvC,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,CAAC,CAGjB;AAKD,wBAAsB,qBAAqB,CACzC,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,CAAC,CAGjB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aeptus/aexeo-emdash",
3
- "version": "0.8.7",
3
+ "version": "0.8.9",
4
4
  "description": "Aexeo SEO/GEO content evaluator as an emdash plugin",
5
5
  "license": "MIT",
6
6
  "author": "Aeptus",
@@ -117,6 +117,28 @@ export function __wbg_Error_960c155d3d49e4c2(arg0, arg1) {
117
117
  const ret = Error(getStringFromWasm0(arg0, arg1));
118
118
  return ret;
119
119
  }
120
+ export function __wbg_error_a6fa202b58aa1cd3(arg0, arg1) {
121
+ let deferred0_0;
122
+ let deferred0_1;
123
+ try {
124
+ deferred0_0 = arg0;
125
+ deferred0_1 = arg1;
126
+ console.error(getStringFromWasm0(arg0, arg1));
127
+ } finally {
128
+ wasm.__wbindgen_free(deferred0_0, deferred0_1, 1);
129
+ }
130
+ }
131
+ export function __wbg_new_227d7c05414eb861() {
132
+ const ret = new Error();
133
+ return ret;
134
+ }
135
+ export function __wbg_stack_3b0d974bbf31e44f(arg0, arg1) {
136
+ const ret = arg1.stack;
137
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
138
+ const len1 = WASM_VECTOR_LEN;
139
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
140
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
141
+ }
120
142
  export function __wbindgen_init_externref_table() {
121
143
  const table = wasm.__wbindgen_externrefs;
122
144
  const offset = table.grow(4);
@@ -126,6 +148,14 @@ export function __wbindgen_init_externref_table() {
126
148
  table.set(offset + 2, true);
127
149
  table.set(offset + 3, false);
128
150
  }
151
+ let cachedDataViewMemory0 = null;
152
+ function getDataViewMemory0() {
153
+ if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
154
+ cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
155
+ }
156
+ return cachedDataViewMemory0;
157
+ }
158
+
129
159
  function getStringFromWasm0(ptr, len) {
130
160
  ptr = ptr >>> 0;
131
161
  return decodeText(ptr, len);
Binary file
@@ -5,9 +5,9 @@ export const evaluateDocuments: (a: number, b: number, c: number, d: number) =>
5
5
  export const generateFactsPrompt: (a: number, b: number) => [number, number, number, number];
6
6
  export const scoreIntelligence: (a: number, b: number, c: number, d: number) => [number, number, number, number];
7
7
  export const validateFactsManifest: (a: number, b: number, c: number, d: number) => [number, number, number, number];
8
- export const __wbindgen_externrefs: WebAssembly.Table;
8
+ export const __wbindgen_free: (a: number, b: number, c: number) => void;
9
9
  export const __wbindgen_malloc: (a: number, b: number) => number;
10
10
  export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
11
+ export const __wbindgen_externrefs: WebAssembly.Table;
11
12
  export const __externref_table_dealloc: (a: number) => void;
12
- export const __wbindgen_free: (a: number, b: number, c: number) => void;
13
13
  export const __wbindgen_start: () => void;