zero-com 1.13.2 → 1.13.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
@@ -229,6 +229,21 @@ When called outside `handle()`, the function executes directly with no context.
229
229
  Error: context() called outside of a server function
230
230
  ```
231
231
 
232
+ Use `runWithContext` to provide a context in those cases:
233
+
234
+ ```typescript
235
+ import { runWithContext } from 'zero-com'
236
+
237
+ const authorize = async (credentials) => {
238
+ return runWithContext({}, async () => {
239
+ const user = await getUserByCredentials(credentials.email, credentials.password)
240
+ return user ?? null
241
+ })
242
+ }
243
+ ```
244
+
245
+ `runWithContext` accepts any object as the context value, which will be returned by `context()` inside any server function called within the callback.
246
+
232
247
  When called inside `handle()`, context is propagated automatically to the function and any nested `func()` calls, same as the normal RPC path.
233
248
 
234
249
  ## File boundary rule
@@ -0,0 +1 @@
1
+ export declare const asyncLocalStorage: undefined;
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.asyncLocalStorage = void 0;
4
+ exports.asyncLocalStorage = undefined;
@@ -0,0 +1,2 @@
1
+ import { AsyncLocalStorage } from 'async_hooks';
2
+ export declare const asyncLocalStorage: AsyncLocalStorage<any> | undefined;
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.asyncLocalStorage = void 0;
4
+ const async_hooks_1 = require("async_hooks");
5
+ exports.asyncLocalStorage = new async_hooks_1.AsyncLocalStorage();
package/lib/runtime.d.ts CHANGED
@@ -3,12 +3,9 @@ declare global {
3
3
  [funcId: string]: (...args: any[]) => any;
4
4
  };
5
5
  var ZERO_COM_CLIENT_CALL: (funcId: string, args: any[]) => any;
6
- var ZERO_COM_CONTEXT_STORAGE: {
7
- run: <T>(ctx: any, fn: () => T) => T;
8
- getStore: () => any;
9
- } | undefined;
10
6
  }
11
7
  export declare function context<T = unknown>(): T;
12
8
  export declare function func<F extends (...args: any[]) => any>(fn: F): F;
13
9
  export declare const handle: (funcId: string, ctx: any, args: any[]) => any;
10
+ export declare const runWithContext: <T>(ctx: any, fn: () => T) => T;
14
11
  export declare const call: (fn: (funcId: string, args: any[]) => any) => void;
package/lib/runtime.js CHANGED
@@ -1,40 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.call = exports.handle = void 0;
3
+ exports.call = exports.runWithContext = exports.handle = void 0;
4
4
  exports.context = context;
5
5
  exports.func = func;
6
- // Context storage - only available on server (Node.js)
7
- // Lazily initialized to avoid importing async_hooks on client
8
- function getContextStorage() {
9
- if (!globalThis.ZERO_COM_CONTEXT_STORAGE) {
10
- try {
11
- // Dynamic require to avoid bundling async_hooks for browser.
12
- // Falls back to process.getBuiltinModule() for ESM contexts (e.g. Vite SSR)
13
- // where require() is not available.
14
- const mod = typeof require === 'function'
15
- ? require('async_hooks')
16
- : process.getBuiltinModule('node:async_hooks');
17
- globalThis.ZERO_COM_CONTEXT_STORAGE = new mod.AsyncLocalStorage();
18
- }
19
- catch (_a) {
20
- // Browser environment - context storage not available
21
- globalThis.ZERO_COM_CONTEXT_STORAGE = undefined;
22
- }
23
- }
24
- return globalThis.ZERO_COM_CONTEXT_STORAGE;
25
- }
26
- // Get the current context - call this inside server functions
27
- function context() {
28
- const storage = getContextStorage();
29
- if (!storage) {
30
- throw new Error('context() is only available on the server');
31
- }
32
- const ctx = storage.getStore();
33
- if (ctx === undefined) {
34
- throw new Error('context() called outside of a server function');
35
- }
36
- return ctx;
37
- }
6
+ const async_local_storage_1 = require("./async-local-storage");
38
7
  // Default server-side implementation: call directly from registry
39
8
  // This enables server functions to call other server functions without transport.
40
9
  // If a request context exists (set by handle()), it is propagated automatically.
@@ -44,20 +13,30 @@ function context() {
44
13
  if (typeof globalThis.ZERO_COM_CLIENT_CALL === 'undefined') {
45
14
  globalThis.ZERO_COM_CLIENT_CALL = (funcId, args) => {
46
15
  var _a;
47
- const storage = getContextStorage();
48
- if (!storage) {
16
+ if (!async_local_storage_1.asyncLocalStorage) {
49
17
  throw new Error('Server function called on client without transport configured. Call call() first.');
50
18
  }
51
19
  const fn = (_a = globalThis.ZERO_COM_SERVER_REGISTRY) === null || _a === void 0 ? void 0 : _a[funcId];
52
20
  if (!fn)
53
21
  throw new Error(`Function not found: ${funcId}`);
54
- const ctx = storage.getStore();
22
+ const ctx = async_local_storage_1.asyncLocalStorage.getStore();
55
23
  if (ctx !== undefined) {
56
- return storage.run(ctx, () => fn(...args));
24
+ return async_local_storage_1.asyncLocalStorage.run(ctx, () => fn(...args));
57
25
  }
58
26
  return fn(...args);
59
27
  };
60
28
  }
29
+ // Get the current context - call this inside server functions
30
+ function context() {
31
+ if (!async_local_storage_1.asyncLocalStorage) {
32
+ throw new Error('context() is only available on the server');
33
+ }
34
+ const ctx = async_local_storage_1.asyncLocalStorage.getStore();
35
+ if (ctx === undefined) {
36
+ throw new Error('context() called outside of a server function');
37
+ }
38
+ return ctx;
39
+ }
61
40
  // func() just returns the function as-is
62
41
  // In production mode: transformed by plugin to just the inner function
63
42
  function func(fn) {
@@ -71,13 +50,20 @@ const handle = (funcId, ctx, args) => {
71
50
  if (!fn) {
72
51
  throw new Error(`Function not found in registry: ${funcId}`);
73
52
  }
74
- const storage = getContextStorage();
75
- if (!storage) {
53
+ if (!async_local_storage_1.asyncLocalStorage) {
76
54
  throw new Error('handle() is only available on the server');
77
55
  }
78
- return storage.run(ctx, () => fn(...args));
56
+ return async_local_storage_1.asyncLocalStorage.run(ctx, () => fn(...args));
79
57
  };
80
58
  exports.handle = handle;
59
+ // Run a callback within a context, making context() available inside it.
60
+ // Use this in server-only code that does not go through handle() (e.g. auth callbacks).
61
+ const runWithContext = (ctx, fn) => {
62
+ if (!async_local_storage_1.asyncLocalStorage)
63
+ throw new Error('runWithContext() is only available on the server');
64
+ return async_local_storage_1.asyncLocalStorage.run(ctx, fn);
65
+ };
66
+ exports.runWithContext = runWithContext;
81
67
  // Client calls this to set up transport (overrides default server-side behavior)
82
68
  // In production mode: transformed by plugin to assignment
83
69
  const call = (fn) => {
package/package.json CHANGED
@@ -1,7 +1,10 @@
1
1
  {
2
2
  "name": "zero-com",
3
- "version": "1.13.2",
3
+ "version": "1.13.4",
4
4
  "main": "index.js",
5
+ "browser": {
6
+ "./lib/async-local-storage.js": "./lib/async-local-storage.browser.js"
7
+ },
5
8
  "repository": "https://github.com/yosbelms/zero-com",
6
9
  "keywords": [
7
10
  "webpack",