@wooksjs/event-core 0.7.22 → 0.7.23

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/dist/index.cjs CHANGED
@@ -3,7 +3,20 @@ let node_async_hooks = require("node:async_hooks");
3
3
  let node_crypto = require("node:crypto");
4
4
 
5
5
  //#region packages/event-core/src/key.ts
6
- let nextId = 0;
6
+ const COUNTER_KEY = Symbol.for("wooks.core.keyCounter");
7
+ /**
8
+ * Slot ids are handed out from a counter living on `globalThis`.
9
+ *
10
+ * Two copies of `@wooksjs/event-core` loaded side by side share a single
11
+ * `AsyncLocalStorage` (see `./storage`), and `EventContext.slots` is keyed by
12
+ * the numeric `_id`. A module-scoped counter would restart at `0` in the
13
+ * second copy, so its slots would collide with unrelated slots of the first
14
+ * one and silently read/overwrite each other's values. A global counter keeps
15
+ * ids unique across every loaded copy.
16
+ */
17
+ const _g = globalThis;
18
+ if (!_g[COUNTER_KEY]) _g[COUNTER_KEY] = { next: 0 };
19
+ const counter = _g[COUNTER_KEY];
7
20
  /**
8
21
  * Creates a typed, writable context slot. Use `ctx.set(k, value)` to store
9
22
  * and `ctx.get(k)` to retrieve. Throws if read before being set.
@@ -19,7 +32,7 @@ let nextId = 0;
19
32
  */
20
33
  function key(name) {
21
34
  return {
22
- _id: nextId++,
35
+ _id: counter.next++,
23
36
  _name: name
24
37
  };
25
38
  }
@@ -38,9 +51,10 @@ function key(name) {
38
51
  * ```
39
52
  */
40
53
  function cached(fn) {
54
+ const id = counter.next++;
41
55
  return {
42
- _id: nextId++,
43
- _name: `cached:${nextId}`,
56
+ _id: id,
57
+ _name: `cached:${id}`,
44
58
  _fn: fn
45
59
  };
46
60
  }
@@ -278,15 +292,40 @@ function resetContextInjector() {
278
292
  //#region packages/event-core/src/storage.ts
279
293
  const STORAGE_KEY = Symbol.for("wooks.core.asyncStorage");
280
294
  const VERSION_KEY = Symbol.for("wooks.core.asyncStorage.version");
281
- const CURRENT_VERSION = "0.7.21";
282
- const _g = globalThis;
283
- if (_g[STORAGE_KEY]) {
284
- if (_g[VERSION_KEY] !== CURRENT_VERSION) throw new Error(`[wooks] Incompatible versions of @wooksjs/event-core detected: existing v${_g[VERSION_KEY]}, loading v${CURRENT_VERSION}. All packages must use the same @wooksjs/event-core version.`);
285
- } else {
286
- _g[STORAGE_KEY] = new node_async_hooks.AsyncLocalStorage();
287
- _g[VERSION_KEY] = CURRENT_VERSION;
295
+ const PATH_KEY = Symbol.for("wooks.core.asyncStorage.path");
296
+ const CURRENT_VERSION = "0.7.23";
297
+ function describePath(path) {
298
+ return typeof path === "string" && path ? path : "unknown path";
299
+ }
300
+ /**
301
+ * Registers this copy of `@wooksjs/event-core` on the global object and
302
+ * returns the shared `AsyncLocalStorage`.
303
+ *
304
+ * A different version throws — the context layout is not compatible. The same
305
+ * version is survivable (both copies then share one storage), but it still
306
+ * means the bundler resolved the runtime twice, so we warn: the packages built
307
+ * on top of event-core are duplicated too, and their slots do not cross over.
308
+ *
309
+ * @internal Exported for tests; invoked once at module scope.
310
+ */
311
+ function registerCoreCopy(identity, globalObject = globalThis) {
312
+ const holder = globalObject;
313
+ const existing = holder[STORAGE_KEY];
314
+ if (!existing) {
315
+ const storage = new node_async_hooks.AsyncLocalStorage();
316
+ holder[STORAGE_KEY] = storage;
317
+ holder[VERSION_KEY] = identity.version;
318
+ holder[PATH_KEY] = identity.path;
319
+ return storage;
320
+ }
321
+ if (holder[VERSION_KEY] !== identity.version) throw new Error(`[wooks] Incompatible versions of @wooksjs/event-core detected: existing v${holder[VERSION_KEY]}, loading v${identity.version}. All packages must use the same @wooksjs/event-core version.`);
322
+ console.warn(`[wooks] A second copy of @wooksjs/event-core v${identity.version} was loaded (first: ${describePath(holder[PATH_KEY])}, now: ${describePath(identity.path)}). The copies share the event-context storage, but packages built on them (@wooksjs/event-http, moost, …) are most likely duplicated too, and a slot seeded by one copy is invisible to composables from the other — typical symptom: "Cannot read properties of undefined (reading 'headers')". Make your bundler resolve the whole wooks/moost runtime once: either bundle it entirely or keep it entirely external, together with every package that depends on it.`);
323
+ return existing;
288
324
  }
289
- const storage = _g[STORAGE_KEY];
325
+ const storage = registerCoreCopy({
326
+ version: CURRENT_VERSION,
327
+ path: typeof __filename === "string" ? __filename : require("url").pathToFileURL(__filename).href
328
+ });
290
329
  /**
291
330
  * Runs a callback with the given `EventContext` as the active context.
292
331
  * All composables and `current()` calls inside `fn` will resolve to `ctx`.
package/dist/index.mjs CHANGED
@@ -2,7 +2,20 @@ import { AsyncLocalStorage } from "node:async_hooks";
2
2
  import { randomUUID } from "node:crypto";
3
3
 
4
4
  //#region packages/event-core/src/key.ts
5
- let nextId = 0;
5
+ const COUNTER_KEY = Symbol.for("wooks.core.keyCounter");
6
+ /**
7
+ * Slot ids are handed out from a counter living on `globalThis`.
8
+ *
9
+ * Two copies of `@wooksjs/event-core` loaded side by side share a single
10
+ * `AsyncLocalStorage` (see `./storage`), and `EventContext.slots` is keyed by
11
+ * the numeric `_id`. A module-scoped counter would restart at `0` in the
12
+ * second copy, so its slots would collide with unrelated slots of the first
13
+ * one and silently read/overwrite each other's values. A global counter keeps
14
+ * ids unique across every loaded copy.
15
+ */
16
+ const _g = globalThis;
17
+ if (!_g[COUNTER_KEY]) _g[COUNTER_KEY] = { next: 0 };
18
+ const counter = _g[COUNTER_KEY];
6
19
  /**
7
20
  * Creates a typed, writable context slot. Use `ctx.set(k, value)` to store
8
21
  * and `ctx.get(k)` to retrieve. Throws if read before being set.
@@ -18,7 +31,7 @@ let nextId = 0;
18
31
  */
19
32
  function key(name) {
20
33
  return {
21
- _id: nextId++,
34
+ _id: counter.next++,
22
35
  _name: name
23
36
  };
24
37
  }
@@ -37,9 +50,10 @@ function key(name) {
37
50
  * ```
38
51
  */
39
52
  function cached(fn) {
53
+ const id = counter.next++;
40
54
  return {
41
- _id: nextId++,
42
- _name: `cached:${nextId}`,
55
+ _id: id,
56
+ _name: `cached:${id}`,
43
57
  _fn: fn
44
58
  };
45
59
  }
@@ -277,15 +291,40 @@ function resetContextInjector() {
277
291
  //#region packages/event-core/src/storage.ts
278
292
  const STORAGE_KEY = Symbol.for("wooks.core.asyncStorage");
279
293
  const VERSION_KEY = Symbol.for("wooks.core.asyncStorage.version");
280
- const CURRENT_VERSION = "0.7.21";
281
- const _g = globalThis;
282
- if (_g[STORAGE_KEY]) {
283
- if (_g[VERSION_KEY] !== CURRENT_VERSION) throw new Error(`[wooks] Incompatible versions of @wooksjs/event-core detected: existing v${_g[VERSION_KEY]}, loading v${CURRENT_VERSION}. All packages must use the same @wooksjs/event-core version.`);
284
- } else {
285
- _g[STORAGE_KEY] = new AsyncLocalStorage();
286
- _g[VERSION_KEY] = CURRENT_VERSION;
294
+ const PATH_KEY = Symbol.for("wooks.core.asyncStorage.path");
295
+ const CURRENT_VERSION = "0.7.23";
296
+ function describePath(path) {
297
+ return typeof path === "string" && path ? path : "unknown path";
298
+ }
299
+ /**
300
+ * Registers this copy of `@wooksjs/event-core` on the global object and
301
+ * returns the shared `AsyncLocalStorage`.
302
+ *
303
+ * A different version throws — the context layout is not compatible. The same
304
+ * version is survivable (both copies then share one storage), but it still
305
+ * means the bundler resolved the runtime twice, so we warn: the packages built
306
+ * on top of event-core are duplicated too, and their slots do not cross over.
307
+ *
308
+ * @internal Exported for tests; invoked once at module scope.
309
+ */
310
+ function registerCoreCopy(identity, globalObject = globalThis) {
311
+ const holder = globalObject;
312
+ const existing = holder[STORAGE_KEY];
313
+ if (!existing) {
314
+ const storage = new AsyncLocalStorage();
315
+ holder[STORAGE_KEY] = storage;
316
+ holder[VERSION_KEY] = identity.version;
317
+ holder[PATH_KEY] = identity.path;
318
+ return storage;
319
+ }
320
+ if (holder[VERSION_KEY] !== identity.version) throw new Error(`[wooks] Incompatible versions of @wooksjs/event-core detected: existing v${holder[VERSION_KEY]}, loading v${identity.version}. All packages must use the same @wooksjs/event-core version.`);
321
+ console.warn(`[wooks] A second copy of @wooksjs/event-core v${identity.version} was loaded (first: ${describePath(holder[PATH_KEY])}, now: ${describePath(identity.path)}). The copies share the event-context storage, but packages built on them (@wooksjs/event-http, moost, …) are most likely duplicated too, and a slot seeded by one copy is invisible to composables from the other — typical symptom: "Cannot read properties of undefined (reading 'headers')". Make your bundler resolve the whole wooks/moost runtime once: either bundle it entirely or keep it entirely external, together with every package that depends on it.`);
322
+ return existing;
287
323
  }
288
- const storage = _g[STORAGE_KEY];
324
+ const storage = registerCoreCopy({
325
+ version: CURRENT_VERSION,
326
+ path: typeof __filename === "string" ? __filename : import.meta.url
327
+ });
289
328
  /**
290
329
  * Runs a callback with the given `EventContext` as the active context.
291
330
  * All composables and `current()` calls inside `fn` will resolve to `ctx`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wooksjs/event-core",
3
- "version": "0.7.22",
3
+ "version": "0.7.23",
4
4
  "description": "@wooksjs/event-core",
5
5
  "keywords": [
6
6
  "composables",