@atolljs/core 0.1.4 → 0.1.6

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.
Files changed (45) hide show
  1. package/dist/contract/listSchema.d.ts +2 -2
  2. package/dist/contract/msgpackrCodec.d.ts +1 -1
  3. package/dist/contract/reef.d.ts +140 -80
  4. package/dist/contract/sharedMemory.d.ts +2 -2
  5. package/dist/contract/types.d.ts +1 -1
  6. package/dist/contract/zod.d.ts +114 -14
  7. package/dist/index.d.ts +31 -29
  8. package/dist/index.js +18 -17
  9. package/dist/index10.js +0 -2
  10. package/dist/index11.js +0 -2
  11. package/dist/index12.js +0 -2
  12. package/dist/index13.js +0 -2
  13. package/dist/index14.js +0 -2
  14. package/dist/index15.js +0 -2
  15. package/dist/index16.js +46 -38
  16. package/dist/index17.js +20 -21
  17. package/dist/index18.js +64 -37
  18. package/dist/index19.js +0 -2
  19. package/dist/index2.js +0 -2
  20. package/dist/index20.js +0 -2
  21. package/dist/index3.js +101 -43
  22. package/dist/index4.js +0 -2
  23. package/dist/index5.js +0 -2
  24. package/dist/index6.js +0 -2
  25. package/dist/index7.js +0 -2
  26. package/dist/index8.js +0 -2
  27. package/dist/index9.js +0 -2
  28. package/dist/observable.d.ts +2 -2
  29. package/dist/pool/memory.d.ts +1 -1
  30. package/dist/pool/workerClient.d.ts +6 -6
  31. package/dist/pool/workerPool.d.ts +2 -2
  32. package/dist/reactive.d.ts +1 -1
  33. package/dist/service.d.ts +1 -1
  34. package/dist/shared/sharedWorkerClient.d.ts +2 -2
  35. package/dist/task.d.ts +1 -1
  36. package/dist/testing/inProcessWorker.d.ts +27 -0
  37. package/dist/worker/defineWorker.d.ts +3 -4
  38. package/dist/worker/registry.d.ts +1 -1
  39. package/dist/worker/workerBootstrap.d.ts +9 -1
  40. package/package.json +6 -3
  41. package/src/contract/zod.ts +130 -14
  42. package/src/index.ts +2 -0
  43. package/src/reactive.ts +107 -42
  44. package/src/worker/defineWorker.ts +6 -2
  45. package/src/worker/workerBootstrap.ts +53 -37
package/dist/index3.js CHANGED
@@ -93,16 +93,16 @@ var e = (e, t) => ({
93
93
  inner(e) {
94
94
  return typeof e == "bigint" ? e : _("bigint");
95
95
  }
96
- }, S = class extends g {
96
+ }, ee = class extends g {
97
97
  inner(e) {
98
98
  return e;
99
99
  }
100
- }, C = class extends g {
100
+ }, S = class extends g {
101
101
  inner(e) {
102
102
  let t = this._zod.def.cls;
103
103
  return e instanceof t ? e : _(t.name ?? "instance");
104
104
  }
105
- }, w = class extends g {
105
+ }, C = class extends g {
106
106
  get shape() {
107
107
  return this._zod.def.shape;
108
108
  }
@@ -112,55 +112,109 @@ var e = (e, t) => ({
112
112
  for (let [n, r] of Object.entries(this.shape)) t[n] = r.parse(e[n]);
113
113
  return t;
114
114
  }
115
- }, T = class extends g {
115
+ }, w = class extends g {
116
116
  inner(e) {
117
117
  if (!Array.isArray(e)) return _("array");
118
118
  let t = this._zod.def.element;
119
119
  return e.map((e) => t.parse(e));
120
120
  }
121
- }, E = () => new v({ type: "number" }), D = () => new y({ type: "string" }), O = () => new b({ type: "boolean" }), k = () => new x({ type: "bigint" }), A = () => new S({ type: "unknown" }), j = (e) => new C({
121
+ }, T = class extends g {
122
+ inner(e) {
123
+ return e === void 0 ? void 0 : this._zod.def.element.parse(e);
124
+ }
125
+ }, E = class extends g {
126
+ inner(e) {
127
+ return e === null ? null : this._zod.def.element.parse(e);
128
+ }
129
+ }, D = class extends g {
130
+ inner(e) {
131
+ return e === this._zod.def.literal ? e : _(JSON.stringify(this._zod.def.literal));
132
+ }
133
+ }, O = class extends g {
134
+ inner(e) {
135
+ for (let t of this._zod.def.options) {
136
+ let n = t.safeParse(e);
137
+ if (n.success) return n.data;
138
+ }
139
+ return _("a union member");
140
+ }
141
+ }, k = class extends g {
142
+ inner(e) {
143
+ (typeof e != "object" || !e || Array.isArray(e)) && _("object");
144
+ let t = this._zod.def.element, n = {};
145
+ for (let [r, i] of Object.entries(e)) n[r] = t.parse(i);
146
+ return n;
147
+ }
148
+ }, A = class extends g {
149
+ inner(e) {
150
+ return typeof e == "function" ? e : _("function");
151
+ }
152
+ }, j = () => $(new v({ type: "number" })), M = () => $(new y({ type: "string" })), N = () => $(new b({ type: "boolean" })), P = () => $(new x({ type: "bigint" })), F = () => $(new ee({ type: "unknown" })), I = (e) => $(new S({
122
153
  type: "instanceof",
123
154
  cls: e
124
- }), M = (e) => new w({
155
+ })), L = (e) => $(new C({
125
156
  type: "object",
126
157
  shape: e
127
- }), N = (e) => new T({
158
+ })), R = (e) => $(new w({
128
159
  type: "array",
129
160
  element: e
130
- }), P = () => new v({
161
+ })), z = (e) => $(new T({
162
+ type: "optional",
163
+ element: e
164
+ })), B = (e) => $(new E({
165
+ type: "nullable",
166
+ element: e
167
+ })), V = (e) => $(new D({
168
+ type: "literal",
169
+ literal: e
170
+ })), H = (e) => $(new O({
171
+ type: "union",
172
+ options: e
173
+ })), U = (e) => $(new k({
174
+ type: "record",
175
+ element: e
176
+ })), W = () => $(new A({ type: "function" })), G = () => new v({
131
177
  type: "number",
132
178
  format: "int32"
133
- }).check(d("int32", t, n)), F = () => new v({
179
+ }).check(d("int32", t, n)), K = () => new v({
134
180
  type: "number",
135
181
  format: "uint32"
136
- }).check(d("uint32", 0, 4294967295)), I = () => new v({
182
+ }).check(d("uint32", 0, 4294967295)), q = () => new v({
137
183
  type: "number",
138
184
  format: "float32"
139
- }), L = () => new v({
185
+ }), J = () => new v({
140
186
  type: "number",
141
187
  format: "float64"
142
- }), R = () => new x({
188
+ }), Y = () => new x({
143
189
  type: "bigint",
144
190
  format: "int64"
145
- }).check(f("int64", -(2n ** 63n), 2n ** 63n - 1n)), z = () => new x({
191
+ }).check(f("int64", -(2n ** 63n), 2n ** 63n - 1n)), X = () => new x({
146
192
  type: "bigint",
147
193
  format: "uint64"
148
- }).check(f("uint64", 0n, 2n ** 64n - 1n)), B = /* @__PURE__ */ new Set([
194
+ }).check(f("uint64", 0n, 2n ** 64n - 1n)), Z = /* @__PURE__ */ new Set([
149
195
  "string",
150
196
  "array",
151
197
  "set"
152
- ]), V = (e, t, n) => {
153
- let r = B.has(e._zod.def.type);
198
+ ]), Q = (e, t, n) => {
199
+ let r = Z.has(e._zod.def.type);
154
200
  return t === "min" ? r ? u(n) : i(n) : r ? l(n) : a(n);
155
201
  };
156
- function H(e) {
202
+ function $(e) {
157
203
  let t = e.check.bind(e), n = e.register.bind(e), i = {
158
- refine: (e, n) => H(t(s(e, n))),
159
- meta: (t) => t === void 0 ? m.get(e) : H(n(m, t)),
160
- min: (n) => H(t(V(e, "min", n))),
161
- max: (n) => H(t(V(e, "max", n))),
162
- length: (e) => H(t(c(e))),
163
- int: () => H(t(r()))
204
+ refine: (e, n) => $(t(s(e, n))),
205
+ meta: (t) => t === void 0 ? m.get(e) : $(n(m, t)),
206
+ min: (n) => $(t(Q(e, "min", n))),
207
+ max: (n) => $(t(Q(e, "max", n))),
208
+ length: (e) => $(t(c(e))),
209
+ int: () => $(t(r())),
210
+ optional: () => $(new T({
211
+ type: "optional",
212
+ element: e
213
+ })),
214
+ nullable: () => $(new E({
215
+ type: "nullable",
216
+ element: e
217
+ }))
164
218
  };
165
219
  for (let [t, n] of Object.entries(i)) Object.defineProperty(e, t, {
166
220
  value: n,
@@ -169,21 +223,27 @@ function H(e) {
169
223
  });
170
224
  return e;
171
225
  }
172
- var U = {
173
- number: E,
174
- string: D,
175
- boolean: O,
176
- bigint: k,
177
- object: M,
178
- array: N,
179
- instanceof: j,
180
- unknown: A,
181
- int32: P,
182
- uint32: F,
183
- float32: I,
184
- float64: L,
185
- int64: R,
186
- uint64: z,
226
+ var te = {
227
+ number: j,
228
+ string: M,
229
+ boolean: N,
230
+ bigint: P,
231
+ object: L,
232
+ array: R,
233
+ instanceof: I,
234
+ unknown: F,
235
+ optional: z,
236
+ nullable: B,
237
+ literal: V,
238
+ union: H,
239
+ record: U,
240
+ callback: W,
241
+ int32: G,
242
+ uint32: K,
243
+ float32: q,
244
+ float64: J,
245
+ int64: Y,
246
+ uint64: X,
187
247
  int: r,
188
248
  gte: i,
189
249
  lte: a,
@@ -194,11 +254,9 @@ var U = {
194
254
  minLength: u,
195
255
  globalRegistry: m,
196
256
  ZodType: g,
197
- ZodObject: w,
198
- ZodArray: T,
257
+ ZodObject: C,
258
+ ZodArray: w,
199
259
  ZodString: y
200
260
  };
201
261
  //#endregion
202
- export { h as SchemaError, g as ZodType, H as fluent, m as globalRegistry, U as z };
203
-
204
- //# sourceMappingURL=index3.js.map
262
+ export { h as SchemaError, g as ZodType, $ as fluent, m as globalRegistry, te as z };
package/dist/index4.js CHANGED
@@ -123,5 +123,3 @@ function v(e) {
123
123
  }
124
124
  //#endregion
125
125
  export { o as listSchema, m as memberToSpec, g as zodArrayInfo, h as zodObjectShape, v as zodStringBytes };
126
-
127
- //# sourceMappingURL=index4.js.map
package/dist/index5.js CHANGED
@@ -36,5 +36,3 @@ function l(e) {
36
36
  var u = (e) => e >= 1 << 20 ? `${(e / (1 << 20)).toFixed(1)}MB` : e >= 1024 ? `${(e / 1024).toFixed(1)}KB` : `${e}B`;
37
37
  //#endregion
38
38
  export { u as fmtBytes, o as getLogLevel, c as log, l as scoped, a as setLogLevel, s as setLogSink };
39
-
40
- //# sourceMappingURL=index5.js.map
package/dist/index6.js CHANGED
@@ -489,5 +489,3 @@ function F() {
489
489
  }
490
490
  //#endregion
491
491
  export { M as SharedMemory, P as bindSharedMemories, N as defineSharedMemory, w as field, F as getDefinedSharedMemoryCount, _ as jsonCodec, y as registerConnectorFactory };
492
-
493
- //# sourceMappingURL=index6.js.map
package/dist/index7.js CHANGED
@@ -19,5 +19,3 @@ var n = new TextEncoder(), r = {
19
19
  };
20
20
  //#endregion
21
21
  export { r as reef };
22
-
23
- //# sourceMappingURL=index7.js.map
package/dist/index8.js CHANGED
@@ -33,5 +33,3 @@ var e = class {
33
33
  };
34
34
  //#endregion
35
35
  export { e as MemoryManager };
36
-
37
- //# sourceMappingURL=index8.js.map
package/dist/index9.js CHANGED
@@ -18,5 +18,3 @@ var e = class extends Error {
18
18
  };
19
19
  //#endregion
20
20
  export { e as PoolQueueFullError, t as TaskAbortedError, n as TaskTimeoutError, r as WorkerCrashedError };
21
-
22
- //# sourceMappingURL=index9.js.map
@@ -1,5 +1,5 @@
1
- import type { Connector, PathConnector, SharedMemory, SharedSpec, SpecPath } from './contract/sharedMemory';
2
- import { type SliceOptions } from './reactive';
1
+ import type { Connector, PathConnector, SharedMemory, SharedSpec, SpecPath } from './contract/sharedMemory.js';
2
+ import { type SliceOptions } from './reactive.js';
3
3
  /**
4
4
  * A minimal subscribable snapshot — `get()` plus `subscribe()`. This is the
5
5
  * interface every framework binding adapts (useSyncExternalStore, refs,
@@ -1,4 +1,4 @@
1
- import { MemoryConfig, ViewType } from '../contract/types';
1
+ import { MemoryConfig, ViewType } from '../contract/types.js';
2
2
  export declare class MemoryManager {
3
3
  memory: WebAssembly.Memory;
4
4
  private maxPages;
@@ -1,8 +1,8 @@
1
- import type { ServiceMethod, TaskRunner } from '../service';
2
- import type { SharedAccess, SharedMemory, SharedSpec } from '../contract/sharedMemory';
3
- import type { MemoryConfig, Prettify } from '../contract/types';
4
- import { WorkerPool, type RunOptions } from './workerPool';
5
- import type { WorkerDefinition, WorkerMethodMap } from '../worker/defineWorker';
1
+ import type { ServiceMethod, TaskRunner } from '../service.js';
2
+ import type { SharedAccess, SharedMemory, SharedSpec } from '../contract/sharedMemory.js';
3
+ import type { MemoryConfig, Prettify } from '../contract/types.js';
4
+ import { WorkerPool, type RunOptions } from './workerPool.js';
5
+ import type { WorkerDefinition, WorkerMethodMap } from '../worker/defineWorker.js';
6
6
  /** Maps a worker method's declared type to its async client signature. */
7
7
  type Sig<F> = F extends ServiceMethod<infer A extends any[], infer R> ? (...args: A) => Promise<R> : F extends {
8
8
  run: (...args: infer A extends any[]) => infer R;
@@ -62,7 +62,7 @@ export type WorkerClient<W extends WorkerDefinition, S extends SharedSpec> = Wor
62
62
  * One-line worker hookup for the main thread — the WorkerPool boilerplate
63
63
  * (worker factory, shared memory, sizing) collapses into the client itself:
64
64
  *
65
- * import type { IncidentsWorker } from './worker/incidents.worker';
65
+ * import type { IncidentsWorker } from './worker/incidents.worker.js';
66
66
  *
67
67
  * export const incidents = connectWorker<IncidentsWorker>({
68
68
  * sharedMemory: incidentsMemory,
@@ -1,5 +1,5 @@
1
- import { SharedAccess, SharedMemory, SharedSpec } from '../contract/sharedMemory';
2
- import { MemoryPersistence, PoolTasks, TaskContract, TaskMap, WorkerPoolConfig } from '../contract/types';
1
+ import { SharedAccess, SharedMemory, SharedSpec } from '../contract/sharedMemory.js';
2
+ import { MemoryPersistence, PoolTasks, TaskContract, TaskMap, WorkerPoolConfig } from '../contract/types.js';
3
3
  /** Per-call dispatch controls. */
4
4
  export interface RunOptions {
5
5
  /**
@@ -1,4 +1,4 @@
1
- import { Connector } from './contract/sharedMemory';
1
+ import { Connector } from './contract/sharedMemory.js';
2
2
  /** Emission control for slices — return `true` when `next` should be treated
3
3
  * as unchanged (no emit). Defaults to `Object.is`. */
4
4
  export type EqualityFn<T> = (prev: T, next: T) => boolean;
package/dist/service.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Schema, TaskContract, ViewType } from './contract/types';
1
+ import type { Schema, TaskContract, ViewType } from './contract/types.js';
2
2
  /**
3
3
  * One RPC method's declaration. Identical fields to {@link TaskContract}
4
4
  * except `taskId` is optional — when omitted the wire id is derived as
@@ -1,5 +1,5 @@
1
- import { SharedAccess, SharedMemory, SharedSpec } from '../contract/sharedMemory';
2
- import { PoolTasks, TaskContract, TaskMap, SharedWorkerConfig } from '../contract/types';
1
+ import { SharedAccess, SharedMemory, SharedSpec } from '../contract/sharedMemory.js';
2
+ import { PoolTasks, TaskContract, TaskMap, SharedWorkerConfig } from '../contract/types.js';
3
3
  declare class SharedWorkerClientImpl<S extends SharedSpec = SharedSpec> {
4
4
  readonly clientIndex: number;
5
5
  readonly sharedMemory: SharedMemory<S> & SharedAccess<S>;
package/dist/task.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ObservableValue } from './observable';
1
+ import type { ObservableValue } from './observable.js';
2
2
  /**
3
3
  * Point-in-time state of an {@link AsyncTask}. Replaced wholesale on every
4
4
  * transition so `get()` stays stable for `useSyncExternalStore`-style
@@ -0,0 +1,27 @@
1
+ export declare class InProcessWorker {
2
+ url: URL;
3
+ options?: any;
4
+ static created: InProcessWorker[];
5
+ static handlerModules: Array<() => Promise<unknown>>;
6
+ executed: any[];
7
+ terminated: boolean;
8
+ private listeners;
9
+ private ready;
10
+ /** Module-load failure — a crashed worker never executes another task. */
11
+ private dead;
12
+ constructor(url: URL, options?: any);
13
+ postMessage(data: any): void;
14
+ /** Imports the registered handler modules — what a real worker's entry does at boot. */
15
+ private boot;
16
+ /** Module-load failure = a real worker's 'error' event. */
17
+ private crashOnBoot;
18
+ private handle;
19
+ private emit;
20
+ /** Simulates a worker crash: fires 'error' listeners like a real worker's error event. */
21
+ crash(message?: string): void;
22
+ addEventListener(type: string, l: (event: any) => void): void;
23
+ removeEventListener(type: string, l: (event: any) => void): void;
24
+ terminate(): void;
25
+ }
26
+ /** Flushes microtasks + the waitAsync observer loop after a shared write. */
27
+ export declare const flushObservers: () => Promise<unknown>;
@@ -1,6 +1,5 @@
1
- import './workerBootstrap';
2
- import type { ServiceMethod } from '../service';
3
- import type { SharedMemory, SharedSpec } from '../contract/sharedMemory';
1
+ import type { ServiceMethod } from '../service.js';
2
+ import type { SharedMemory, SharedSpec } from '../contract/sharedMemory.js';
4
3
  /**
5
4
  * One worker-exposed method: a plain function (siblings reachable via `this`)
6
5
  * or a {@link ServiceMethod} unit (`{ def, run }` — schemas enforced on the
@@ -38,7 +37,7 @@ export interface WorkerDefinition<S extends SharedSpec = SharedSpec, M extends W
38
37
  export declare const RESERVED_CLIENT_KEYS: readonly ['start', 'terminate', 'pool', 'sharedMemory', 'then', 'with'];
39
38
  /**
40
39
  * The worker-side half of the tRPC-style pair: the worker script owns the
41
- * runtime (importing this module wires `self.onmessage` via workerBootstrap)
40
+ * runtime (calling this wires `self.onmessage` via workerBootstrap)
42
41
  * and the method list — the main thread imports only `typeof` the returned
43
42
  * definition and drives it through a {@link connectWorker} Proxy client.
44
43
  *
@@ -1,4 +1,4 @@
1
- import { TaskContract } from '../contract/types';
1
+ import { TaskContract } from '../contract/types.js';
2
2
  export type TaskHandler<Args extends any[] = any[], Result = any> = (...args: Args) => Result | Promise<Result>;
3
3
  export declare class TaskRegistry {
4
4
  private static tasks;
@@ -1 +1,9 @@
1
- export {};
1
+ /**
2
+ * Wire `self.onmessage` to the pool protocol (INIT / INIT_MEMORY /
3
+ * EXECUTE_TASK). Runs automatically on import for the public
4
+ * `import '@atolljs/core/worker/workerBootstrap'` entry, and is also called
5
+ * from `defineWorker()` — an explicit call survives bundler tree-shaking,
6
+ * unlike a bare side-effect import whose `sideEffects` glob can miss
7
+ * renamed dist chunks. Idempotent: safe on repeated defineWorker() calls.
8
+ */
9
+ export declare function installWorkerListener(): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atolljs/core",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Typed shared-memory worker pools — defineWorker/connectWorker, SharedArrayBuffer contracts, cross-thread reactivity",
5
5
  "homepage": "https://jwhenry3.github.io/atolljs/consumer/quickstart/",
6
6
  "type": "module",
@@ -12,7 +12,10 @@
12
12
  "import": "./dist/index.js"
13
13
  },
14
14
  "./package.json": "./package.json",
15
- "./*": "./src/*"
15
+ "./*": {
16
+ "types": "./dist/*.d.ts",
17
+ "default": "./src/*"
18
+ }
16
19
  },
17
20
  "files": [
18
21
  "dist",
@@ -29,7 +32,7 @@
29
32
  "kill:all": "node scripts/kill-all.mjs",
30
33
  "atoll": "node packages/cli/src/cli.ts",
31
34
  "serve:all": "node scripts/serve-all.mjs",
32
- "build": "tsc --noEmit && vite build",
35
+ "build": "tsc --noEmit && vite build && node scripts/core-dts.mjs",
33
36
  "test": "vitest run",
34
37
  "test:coverage": "vitest run --coverage",
35
38
  "stats": "node scripts/bundle-stats.mjs",
@@ -98,6 +98,10 @@ export interface SchemaDef {
98
98
  format?: string;
99
99
  shape?: Record<string, ZodLike>;
100
100
  element?: ZodLike;
101
+ /** union members. */
102
+ options?: readonly ZodLike[];
103
+ /** literal value. */
104
+ literal?: unknown;
101
105
  cls?: abstract new (...args: any[]) => unknown;
102
106
  }
103
107
 
@@ -205,9 +209,24 @@ class ZodInstanceof<T> extends ZodType<T> {
205
209
  }
206
210
  }
207
211
 
208
- type ShapeOutput<S extends Record<string, ZodLike>> = {
209
- [K in keyof S]: S[K] extends { _zod: { output: infer O } } ? O : never;
210
- };
212
+ /** Members whose output admits `undefined` become optional keys — mirroring
213
+ * zod's `z.optional()` object-member semantics (message-domain schemas like
214
+ * island prop contracts need this; reef's fixed-width members never produce
215
+ * it, so the split preserves their all-required output). */
216
+ type IsOptional<S, K extends keyof S> =
217
+ S[K] extends { _zod: { output: infer O } }
218
+ ? undefined extends O
219
+ ? true
220
+ : false
221
+ : false;
222
+
223
+ type Flatten<T> = { [K in keyof T]: T[K] };
224
+
225
+ type ShapeOutput<S extends Record<string, ZodLike>> = Flatten<
226
+ { [K in keyof S as IsOptional<S, K> extends true ? never : K]: OutputOf<S[K]> } & {
227
+ [K in keyof S as IsOptional<S, K> extends true ? K : never]?: OutputOf<S[K]>;
228
+ }
229
+ >;
211
230
 
212
231
  /** Strips unknown keys like zod's object parse — output is the shape only. */
213
232
  class ZodObjectSchema<S extends Record<string, ZodLike>> extends ZodType<ShapeOutput<S>> {
@@ -242,21 +261,111 @@ class ZodArraySchema<E extends ZodLike> extends ZodType<OutputOf<E>[]> {
242
261
 
243
262
  type OutputOf<S> = S extends { _zod: { output: infer O } } ? O : never;
244
263
 
245
- /* ------------------------------------------------------------------ */
246
- /* Factories — the vendored `zod/mini` spelling */
247
- /* ------------------------------------------------------------------ */
264
+ /* ── Message-domain kinds ────────────────────────────────────────────────
265
+ * Layout-free members for contracts that ride postMessage instead of the
266
+ * shared buffer — island prop/event schemas (defineIslandContract). The
267
+ * layout compiler doesn't understand these def.types and rejects them with
268
+ * "can't lay out" if they ever appear inside a fixed-width field — that
269
+ * loud failure is intended: they have no byte width.
270
+ */
271
+
272
+ class ZodOptional<E extends ZodLike> extends ZodType<OutputOf<E> | undefined> {
273
+ declare readonly _zod: {
274
+ output: OutputOf<E> | undefined; input: OutputOf<E> | undefined;
275
+ def: SchemaDef & { type: 'optional'; element: E };
276
+ };
277
+ inner(v: unknown): OutputOf<E> | undefined {
278
+ // The intersected def narrows element to E; read it as the element's
279
+ // output type so the wrapper's output lines up.
280
+ return v === undefined
281
+ ? undefined
282
+ : (this._zod.def.element as ZodLike<OutputOf<E>>).parse(v);
283
+ }
284
+ }
285
+ class ZodNullable<E extends ZodLike> extends ZodType<OutputOf<E> | null> {
286
+ declare readonly _zod: {
287
+ output: OutputOf<E> | null; input: OutputOf<E> | null;
288
+ def: SchemaDef & { type: 'nullable'; element: E };
289
+ };
290
+ inner(v: unknown): OutputOf<E> | null {
291
+ return v === null
292
+ ? null
293
+ : (this._zod.def.element as ZodLike<OutputOf<E>>).parse(v);
294
+ }
295
+ }
296
+ class ZodLiteral<V extends string | number | boolean> extends ZodType<V> {
297
+ declare readonly _zod: { output: V; input: V; def: SchemaDef & { type: 'literal' } };
298
+ inner(v: unknown): V {
299
+ return v === this._zod.def.literal ? (v as V) : fail(JSON.stringify(this._zod.def.literal));
300
+ }
301
+ }
302
+ class ZodUnion<O extends readonly ZodLike[]> extends ZodType<OutputOf<O[number]>> {
303
+ declare readonly _zod: {
304
+ output: OutputOf<O[number]>; input: OutputOf<O[number]>;
305
+ def: SchemaDef & { type: 'union'; options: O };
306
+ };
307
+ inner(v: unknown): OutputOf<O[number]> {
308
+ for (const option of this._zod.def.options as readonly ZodLike<OutputOf<O[number]>>[]) {
309
+ const r = option.safeParse(v);
310
+ if (r.success) return r.data;
311
+ }
312
+ return fail('a union member');
313
+ }
314
+ }
315
+ class ZodRecord<E extends ZodLike> extends ZodType<Record<string, OutputOf<E>>> {
316
+ declare readonly _zod: {
317
+ output: Record<string, OutputOf<E>>; input: Record<string, OutputOf<E>>;
318
+ def: SchemaDef & { type: 'record'; element: E };
319
+ };
320
+ inner(v: unknown): Record<string, OutputOf<E>> {
321
+ if (typeof v !== 'object' || v === null || Array.isArray(v)) fail('object');
322
+ const el = this._zod.def.element;
323
+ const out: Record<string, unknown> = {};
324
+ for (const [k, value] of Object.entries(v as Record<string, unknown>)) {
325
+ out[k] = el.parse(value);
326
+ }
327
+ return out as Record<string, OutputOf<E>>;
328
+ }
329
+ }
330
+ /**
331
+ * Function-typed members — how a props schema declares a `callbackProp`
332
+ * slot: the wire carries a `{__cb:id}` handle that `unmarshalCallbackProps`
333
+ * restores to a callable BEFORE contract validation runs, so at parse time
334
+ * the member is a real function.
335
+ */
336
+ class ZodCallback<F extends (...args: any[]) => any = (...args: unknown[]) => unknown>
337
+ extends ZodType<F> {
338
+ declare readonly _zod: { output: F; input: F; def: SchemaDef & { type: 'function' } };
339
+ inner(v: unknown): F {
340
+ return typeof v === 'function' ? (v as F) : fail('function');
341
+ }
342
+ }
248
343
 
249
- const number = () => new ZodNumber({ type: 'number' });
250
- const string = () => new ZodString({ type: 'string' });
251
- const boolean_ = () => new ZodBoolean({ type: 'boolean' });
252
- const bigint_ = () => new ZodBigint({ type: 'bigint' });
253
- const unknown_ = () => new ZodUnknown({ type: 'unknown' });
344
+ // z factories return FLUENT schemas — `z.string().optional()` chains like
345
+ // classic zod; the mini spellings (`z.optional(z.string())`) stay valid.
346
+ const number = () => fluent(new ZodNumber({ type: 'number' }));
347
+ const string = () => fluent(new ZodString({ type: 'string' }));
348
+ const boolean_ = () => fluent(new ZodBoolean({ type: 'boolean' }));
349
+ const bigint_ = () => fluent(new ZodBigint({ type: 'bigint' }));
350
+ const unknown_ = () => fluent(new ZodUnknown({ type: 'unknown' }));
254
351
  const instanceof_ = <T extends abstract new (...args: any[]) => any>(cls: T) =>
255
- new ZodInstanceof<InstanceType<T>>({ type: 'instanceof', cls });
352
+ fluent(new ZodInstanceof<InstanceType<T>>({ type: 'instanceof', cls }));
256
353
  const object_ = <S extends Record<string, ZodLike>>(shape: S) =>
257
- new ZodObjectSchema<S>({ type: 'object', shape });
354
+ fluent(new ZodObjectSchema<S>({ type: 'object', shape }));
258
355
  const array = <E extends ZodLike>(element: E) =>
259
- new ZodArraySchema<E>({ type: 'array', element });
356
+ fluent(new ZodArraySchema<E>({ type: 'array', element }));
357
+ const optional = <E extends ZodLike>(element: E) =>
358
+ fluent(new ZodOptional<E>({ type: 'optional', element }));
359
+ const nullable = <E extends ZodLike>(element: E) =>
360
+ fluent(new ZodNullable<E>({ type: 'nullable', element }));
361
+ const literal = <V extends string | number | boolean>(value: V) =>
362
+ fluent(new ZodLiteral<V>({ type: 'literal', literal: value }));
363
+ const union = <O extends readonly [ZodLike, ...ZodLike[]]>(options: O) =>
364
+ fluent(new ZodUnion<O>({ type: 'union', options }));
365
+ const record = <E extends ZodLike>(element: E) =>
366
+ fluent(new ZodRecord<E>({ type: 'record', element }));
367
+ const callback = <F extends (...args: any[]) => any = (...args: unknown[]) => unknown>() =>
368
+ fluent(new ZodCallback<F>({ type: 'function' }));
260
369
 
261
370
  const int32 = () => new ZodNumber({ type: 'number', format: 'int32' }).check(intRange('int32', int32min, int32max));
262
371
  const uint32 = () => new ZodNumber({ type: 'number', format: 'uint32' }).check(intRange('uint32', 0, 4294967295));
@@ -288,6 +397,10 @@ export type Fluent<S extends ZodLike> = S & {
288
397
  max(value: number | bigint): Fluent<S>;
289
398
  length(n: number): Fluent<S>;
290
399
  int(): Fluent<S>;
400
+ /** Wraps in an optional member — the `label?: string` spelling. */
401
+ optional(): Fluent<ZodOptional<S>>;
402
+ /** Wraps in a nullable member — `T | null`. */
403
+ nullable(): Fluent<ZodNullable<S>>;
291
404
  };
292
405
 
293
406
  /** Attaches the `Fluent` methods as non-enumerable own properties. */
@@ -302,6 +415,8 @@ export function fluent<S extends ZodType>(schema: S): Fluent<S> {
302
415
  max: (v: number | bigint) => fluent(boundCheck_(boundCheck(schema, 'max', v))),
303
416
  length: (n: number) => fluent(boundCheck_(length(n))),
304
417
  int: () => fluent(boundCheck_(int())),
418
+ optional: () => fluent(new ZodOptional({ type: 'optional', element: schema })),
419
+ nullable: () => fluent(new ZodNullable({ type: 'nullable', element: schema })),
305
420
  };
306
421
  for (const [key, fn] of Object.entries(own)) {
307
422
  Object.defineProperty(schema, key, { value: fn, enumerable: false, configurable: true });
@@ -316,6 +431,7 @@ export function fluent<S extends ZodType>(schema: S): Fluent<S> {
316
431
  export const z = {
317
432
  number, string, boolean: boolean_, bigint: bigint_, object: object_, array,
318
433
  instanceof: instanceof_, unknown: unknown_,
434
+ optional, nullable, literal, union, record, callback,
319
435
  int32, uint32, float32, float64, int64, uint64,
320
436
  int, gte, lte, nonnegative, refine, length, maxLength, minLength,
321
437
  globalRegistry,
package/src/index.ts CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  export { bindSharedMemories, defineSharedMemory, field, getDefinedSharedMemoryCount, jsonCodec, registerConnectorFactory } from './contract/sharedMemory';
4
4
  export { reef } from './contract/reef';
5
+ export { z, SchemaError } from './contract/zod';
6
+ export type { ZodLike } from './contract/zod';
5
7
  export type {
6
8
  Codec,
7
9
  Connector,