zero-com 1.13.0 → 1.13.2

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
@@ -212,6 +212,56 @@ When `getFullName` is called from the client:
212
212
  4. `getFirstName` executes directly (no transport) with the same context
213
213
  5. Both functions can access `context()` with the same data
214
214
 
215
+ ## Calling server functions outside handle()
216
+
217
+ Server functions can be called from any server-side code, not only through the RPC path. This is useful for server-side-only integrations like authentication callbacks, cron jobs, or webhook handlers.
218
+
219
+ ```typescript
220
+ // pages/api/auth/[...nextauth].ts (Next.js example)
221
+ import { getUserByCredentials } from '../../../server/auth/funcs'
222
+
223
+ const user = await getUserByCredentials(email, password)
224
+ ```
225
+
226
+ When called outside `handle()`, the function executes directly with no context. If the function calls `context()` internally, it throws:
227
+
228
+ ```
229
+ Error: context() called outside of a server function
230
+ ```
231
+
232
+ When called inside `handle()`, context is propagated automatically to the function and any nested `func()` calls, same as the normal RPC path.
233
+
234
+ ## File boundary rule
235
+
236
+ Any file that contains `func()` exports is treated as a **server-only module**. On the client build the plugin replaces the **entire file** with lightweight RPC stubs — only the `func()` exports survive, everything else in that file is discarded.
237
+
238
+ This means you must not mix `func()` declarations with client-side code (state, UI utilities, etc.) in the same file. The pattern is the same as Next.js `"use server"` files: one side of the boundary per file.
239
+
240
+ **Wrong** — `connect` will be `undefined` on the client because the whole file is replaced:
241
+
242
+ ```ts
243
+ // store.ts ❌
244
+ import { func } from 'zero-com'
245
+ import { createStore } from './create-store'
246
+
247
+ export const { connect, useStore } = createStore(...) // lost on client
248
+
249
+ export const getPhones = func(async () => { ... })
250
+ ```
251
+
252
+ **Right** — separate the RPC calls from client state:
253
+
254
+ ```ts
255
+ // funcs.ts ✅ (replaced with stubs on client)
256
+ import { func } from 'zero-com'
257
+ export const getPhones = func(async () => { ... })
258
+
259
+ // store.ts ✅ (untouched on client)
260
+ import { createStore } from './create-store'
261
+ export const { connect, useStore } = createStore(...)
262
+ export * from './funcs'
263
+ ```
264
+
215
265
  ## Plugin options
216
266
 
217
267
  | Option | Type | Description |
@@ -301,7 +351,8 @@ export const getPhones = func(async (name: string) => {
301
351
  // server.ts
302
352
  import express from 'express';
303
353
  import { handle } from 'zero-com';
304
- import './src/server/api/phones.js'; // Make sure to import the server-side modules
354
+ // No manual imports needed the plugin automatically registers all func() files
355
+ // when it transforms any file that calls handle()
305
356
 
306
357
  const app = express();
307
358
  app.use(express.json());
package/lib/runtime.js CHANGED
@@ -36,7 +36,11 @@ function context() {
36
36
  return ctx;
37
37
  }
38
38
  // Default server-side implementation: call directly from registry
39
- // This enables server functions to call other server functions without transport
39
+ // This enables server functions to call other server functions without transport.
40
+ // If a request context exists (set by handle()), it is propagated automatically.
41
+ // If there is no context (e.g. called from NextAuth or other server-only code that
42
+ // does not go through handle()), the function is called directly — context() will
43
+ // throw inside the function only if the function actually tries to use it.
40
44
  if (typeof globalThis.ZERO_COM_CLIENT_CALL === 'undefined') {
41
45
  globalThis.ZERO_COM_CLIENT_CALL = (funcId, args) => {
42
46
  var _a;
@@ -44,13 +48,13 @@ if (typeof globalThis.ZERO_COM_CLIENT_CALL === 'undefined') {
44
48
  if (!storage) {
45
49
  throw new Error('Server function called on client without transport configured. Call call() first.');
46
50
  }
47
- const ctx = storage.getStore();
48
- if (ctx === undefined) {
49
- throw new Error('Server function called outside of request context');
50
- }
51
51
  const fn = (_a = globalThis.ZERO_COM_SERVER_REGISTRY) === null || _a === void 0 ? void 0 : _a[funcId];
52
52
  if (!fn)
53
53
  throw new Error(`Function not found: ${funcId}`);
54
+ const ctx = storage.getStore();
55
+ if (ctx !== undefined) {
56
+ return storage.run(ctx, () => fn(...args));
57
+ }
54
58
  return fn(...args);
55
59
  };
56
60
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zero-com",
3
- "version": "1.13.0",
3
+ "version": "1.13.2",
4
4
  "main": "index.js",
5
5
  "repository": "https://github.com/yosbelms/zero-com",
6
6
  "keywords": [