@atolljs/core 0.1.5 → 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.
@@ -24,7 +24,7 @@ import { z } from './zod.js';
24
24
  * `_zod.def`, so `reef.object({ id: z.uint32() })` mixes freely.
25
25
  */
26
26
  export declare const reef: {
27
- i8: () => import("./zod.js").Fluent<{
27
+ i8: () => import("./zod.js").Fluent<import("./zod.js").Fluent<{
28
28
  readonly _zod: {
29
29
  output: number;
30
30
  input: number;
@@ -43,8 +43,8 @@ export declare const reef: {
43
43
  };
44
44
  check(...checks: import("./zod.js").Check[]): /*elided*/ any;
45
45
  register(registry: import("./zod.js").Registry, meta: Record<string, unknown>): /*elided*/ any;
46
- }>;
47
- u8: () => import("./zod.js").Fluent<{
46
+ }>>;
47
+ u8: () => import("./zod.js").Fluent<import("./zod.js").Fluent<{
48
48
  readonly _zod: {
49
49
  output: number;
50
50
  input: number;
@@ -63,8 +63,8 @@ export declare const reef: {
63
63
  };
64
64
  check(...checks: import("./zod.js").Check[]): any;
65
65
  register(registry: import("./zod.js").Registry, meta: Record<string, unknown>): any;
66
- }>;
67
- i16: () => import("./zod.js").Fluent<{
66
+ }>>;
67
+ i16: () => import("./zod.js").Fluent<import("./zod.js").Fluent<{
68
68
  readonly _zod: {
69
69
  output: number;
70
70
  input: number;
@@ -83,8 +83,8 @@ export declare const reef: {
83
83
  };
84
84
  check(...checks: import("./zod.js").Check[]): any;
85
85
  register(registry: import("./zod.js").Registry, meta: Record<string, unknown>): any;
86
- }>;
87
- u16: () => import("./zod.js").Fluent<{
86
+ }>>;
87
+ u16: () => import("./zod.js").Fluent<import("./zod.js").Fluent<{
88
88
  readonly _zod: {
89
89
  output: number;
90
90
  input: number;
@@ -103,7 +103,7 @@ export declare const reef: {
103
103
  };
104
104
  check(...checks: import("./zod.js").Check[]): any;
105
105
  register(registry: import("./zod.js").Registry, meta: Record<string, unknown>): any;
106
- }>;
106
+ }>>;
107
107
  i32: () => import("./zod.js").Fluent<{
108
108
  readonly _zod: {
109
109
  output: number;
@@ -225,7 +225,7 @@ export declare const reef: {
225
225
  register(registry: import("./zod.js").Registry, meta: Record<string, unknown>): any;
226
226
  }>;
227
227
  /** Bounded int — compiles to the narrowest covering kind (0..3 → u8). */
228
- int: (min: number, max: number) => import("./zod.js").Fluent<{
228
+ int: (min: number, max: number) => import("./zod.js").Fluent<import("./zod.js").Fluent<{
229
229
  readonly _zod: {
230
230
  output: number;
231
231
  input: number;
@@ -244,9 +244,9 @@ export declare const reef: {
244
244
  };
245
245
  check(...checks: import("./zod.js").Check[]): /*elided*/ any;
246
246
  register(registry: import("./zod.js").Registry, meta: Record<string, unknown>): /*elided*/ any;
247
- }>;
247
+ }>>;
248
248
  /** A flag byte — reads and writes as boolean. */
249
- boolean: () => import("./zod.js").Fluent<{
249
+ boolean: () => import("./zod.js").Fluent<import("./zod.js").Fluent<{
250
250
  readonly _zod: {
251
251
  output: boolean;
252
252
  input: boolean;
@@ -265,11 +265,11 @@ export declare const reef: {
265
265
  };
266
266
  check(...checks: import("./zod.js").Check[]): /*elided*/ any;
267
267
  register(registry: import("./zod.js").Registry, meta: Record<string, unknown>): /*elided*/ any;
268
- }>;
268
+ }>>;
269
269
  /** Fixed-capacity inline UTF-8 string — `bytes` is the byte budget. The
270
270
  * schema itself refuses over-budget values, so `.parse` and connector
271
271
  * writes enforce the same limit. */
272
- string: (bytes: number) => import("./zod.js").Fluent<{
272
+ string: (bytes: number) => import("./zod.js").Fluent<import("./zod.js").Fluent<{
273
273
  readonly _zod: {
274
274
  output: string;
275
275
  input: string;
@@ -288,52 +288,112 @@ export declare const reef: {
288
288
  };
289
289
  check(...checks: import("./zod.js").Check[]): /*elided*/ any;
290
290
  register(registry: import("./zod.js").Registry, meta: Record<string, unknown>): /*elided*/ any;
291
- }>;
291
+ }>>;
292
292
  /** A fixed-layout record shape — every member must be a fixed-width schema. */
293
- object: <S extends z.ZodRawShape>(shape: S) => import("./zod.js").Fluent<{
293
+ object: <S extends z.ZodRawShape>(shape: S) => import("./zod.js").Fluent<import("./zod.js").Fluent<{
294
294
  readonly _zod: {
295
- output: { [K in keyof S]: S[K] extends {
295
+ output: { [K in keyof S as (S[K] extends {
296
+ _zod: {
297
+ output: infer O;
298
+ };
299
+ } ? undefined extends O ? true : false : false) extends true ? never : K]: S[K] extends infer T_1 ? T_1 extends S[K] ? T_1 extends {
300
+ _zod: {
301
+ output: infer O_1;
302
+ };
303
+ } ? O_1 : never : never : never; } & { [K in keyof S as (S[K] extends {
296
304
  _zod: {
297
305
  output: infer O;
298
306
  };
299
- } ? O : never; };
300
- input: { [K in keyof S]: S[K] extends {
307
+ } ? undefined extends O ? true : false : false) extends true ? K : never]?: (S[K] extends infer T_1 ? T_1 extends S[K] ? T_1 extends {
308
+ _zod: {
309
+ output: infer O_1;
310
+ };
311
+ } ? O : never : never : never) | undefined; } extends infer T ? { [K in keyof T]: T[K]; } : never;
312
+ input: { [K in keyof S as (S[K] extends {
301
313
  _zod: {
302
314
  output: infer O;
303
315
  };
304
- } ? O : never; };
316
+ } ? undefined extends O ? true : false : false) extends true ? never : K]: S[K] extends infer T_1 ? T_1 extends S[K] ? T_1 extends {
317
+ _zod: {
318
+ output: infer O_1;
319
+ };
320
+ } ? O_1 : never : never : never; } & { [K in keyof S as (S[K] extends {
321
+ _zod: {
322
+ output: infer O;
323
+ };
324
+ } ? undefined extends O ? true : false : false) extends true ? K : never]?: (S[K] extends infer T_1 ? T_1 extends S[K] ? T_1 extends {
325
+ _zod: {
326
+ output: infer O_1;
327
+ };
328
+ } ? O : never : never : never) | undefined; } extends infer T ? { [K in keyof T]: T[K]; } : never;
305
329
  def: import("./zod.js").SchemaDef & {
306
330
  type: 'object';
307
331
  shape: S;
308
332
  };
309
333
  };
310
334
  get shape(): S;
311
- inner(v: unknown): { [K in keyof S]: S[K] extends {
335
+ inner(v: unknown): { [K in keyof S as (S[K] extends {
336
+ _zod: {
337
+ output: infer O;
338
+ };
339
+ } ? undefined extends O ? true : false : false) extends true ? never : K]: S[K] extends infer T_1 ? T_1 extends S[K] ? T_1 extends {
340
+ _zod: {
341
+ output: infer O_1;
342
+ };
343
+ } ? O_1 : never : never : never; } & { [K in keyof S as (S[K] extends {
312
344
  _zod: {
313
345
  output: infer O;
314
346
  };
315
- } ? O : never; };
316
- parse(value: unknown): { [K in keyof S]: S[K] extends {
347
+ } ? undefined extends O ? true : false : false) extends true ? K : never]?: (S[K] extends infer T_1 ? T_1 extends S[K] ? T_1 extends {
348
+ _zod: {
349
+ output: infer O_1;
350
+ };
351
+ } ? O : never : never : never) | undefined; } extends infer T ? { [K in keyof T]: T[K]; } : never;
352
+ parse(value: unknown): { [K in keyof S as (S[K] extends {
353
+ _zod: {
354
+ output: infer O;
355
+ };
356
+ } ? undefined extends O ? true : false : false) extends true ? never : K]: S[K] extends infer T_1 ? T_1 extends S[K] ? T_1 extends {
357
+ _zod: {
358
+ output: infer O_1;
359
+ };
360
+ } ? O_1 : never : never : never; } & { [K in keyof S as (S[K] extends {
317
361
  _zod: {
318
362
  output: infer O;
319
363
  };
320
- } ? O : never; };
364
+ } ? undefined extends O ? true : false : false) extends true ? K : never]?: (S[K] extends infer T_1 ? T_1 extends S[K] ? T_1 extends {
365
+ _zod: {
366
+ output: infer O_1;
367
+ };
368
+ } ? O : never : never : never) | undefined; } extends infer T ? { [K in keyof T]: T[K]; } : never;
321
369
  safeParse(value: unknown): {
322
370
  success: true;
323
- data: { [K in keyof S]: S[K] extends {
371
+ data: { [K in keyof S as (S[K] extends {
324
372
  _zod: {
325
373
  output: infer O;
326
374
  };
327
- } ? O : never; };
375
+ } ? undefined extends O ? true : false : false) extends true ? never : K]: S[K] extends infer T_1 ? T_1 extends S[K] ? T_1 extends {
376
+ _zod: {
377
+ output: infer O_1;
378
+ };
379
+ } ? O_1 : never : never : never; } & { [K in keyof S as (S[K] extends {
380
+ _zod: {
381
+ output: infer O;
382
+ };
383
+ } ? undefined extends O ? true : false : false) extends true ? K : never]?: (S[K] extends infer T_1 ? T_1 extends S[K] ? T_1 extends {
384
+ _zod: {
385
+ output: infer O_1;
386
+ };
387
+ } ? O : never : never : never) | undefined; } extends infer T ? { [K in keyof T]: T[K]; } : never;
328
388
  } | {
329
389
  success: false;
330
390
  error: unknown;
331
391
  };
332
392
  check(...checks: import("./zod.js").Check[]): /*elided*/ any;
333
393
  register(registry: import("./zod.js").Registry, meta: Record<string, unknown>): /*elided*/ any;
334
- }>;
394
+ }>>;
335
395
  /** A fixed-stride element — bound it with `.max(n)` or `.length(n)` before field.array. */
336
- array: <E extends z.ZodTypeAny>(element: E) => import("./zod.js").Fluent<{
396
+ array: <E extends z.ZodTypeAny>(element: E) => import("./zod.js").Fluent<import("./zod.js").Fluent<{
337
397
  readonly _zod: {
338
398
  output: (E extends {
339
399
  _zod: {
@@ -373,5 +433,5 @@ export declare const reef: {
373
433
  };
374
434
  check(...checks: import("./zod.js").Check[]): /*elided*/ any;
375
435
  register(registry: import("./zod.js").Registry, meta: Record<string, unknown>): /*elided*/ any;
376
- }>;
436
+ }>>;
377
437
  };
@@ -52,6 +52,10 @@ export interface SchemaDef {
52
52
  format?: string;
53
53
  shape?: Record<string, ZodLike>;
54
54
  element?: ZodLike;
55
+ /** union members. */
56
+ options?: readonly ZodLike[];
57
+ /** literal value. */
58
+ literal?: unknown;
55
59
  cls?: abstract new (...args: any[]) => unknown;
56
60
  }
57
61
  export declare class SchemaError extends Error {
@@ -143,13 +147,23 @@ declare class ZodUnknown extends ZodType<unknown> {
143
147
  declare class ZodInstanceof<T> extends ZodType<T> {
144
148
  inner(v: unknown): T;
145
149
  }
146
- type ShapeOutput<S extends Record<string, ZodLike>> = {
147
- [K in keyof S]: S[K] extends {
148
- _zod: {
149
- output: infer O;
150
- };
151
- } ? O : never;
150
+ /** Members whose output admits `undefined` become optional keys — mirroring
151
+ * zod's `z.optional()` object-member semantics (message-domain schemas like
152
+ * island prop contracts need this; reef's fixed-width members never produce
153
+ * it, so the split preserves their all-required output). */
154
+ type IsOptional<S, K extends keyof S> = S[K] extends {
155
+ _zod: {
156
+ output: infer O;
157
+ };
158
+ } ? undefined extends O ? true : false : false;
159
+ type Flatten<T> = {
160
+ [K in keyof T]: T[K];
152
161
  };
162
+ type ShapeOutput<S extends Record<string, ZodLike>> = Flatten<{
163
+ [K in keyof S as IsOptional<S, K> extends true ? never : K]: OutputOf<S[K]>;
164
+ } & {
165
+ [K in keyof S as IsOptional<S, K> extends true ? K : never]?: OutputOf<S[K]>;
166
+ }>;
153
167
  /** Strips unknown keys like zod's object parse — output is the shape only. */
154
168
  declare class ZodObjectSchema<S extends Record<string, ZodLike>> extends ZodType<ShapeOutput<S>> {
155
169
  readonly _zod: {
@@ -179,14 +193,90 @@ type OutputOf<S> = S extends {
179
193
  output: infer O;
180
194
  };
181
195
  } ? O : never;
182
- declare const number: () => ZodNumber;
183
- declare const string: () => ZodString;
184
- declare const boolean_: () => ZodBoolean;
185
- declare const bigint_: () => ZodBigint;
186
- declare const unknown_: () => ZodUnknown;
187
- declare const instanceof_: <T extends abstract new (...args: any[]) => any>(cls: T) => ZodInstanceof<InstanceType<T>>;
188
- declare const object_: <S extends Record<string, ZodLike>>(shape: S) => ZodObjectSchema<S>;
189
- declare const array: <E extends ZodLike>(element: E) => ZodArraySchema<E>;
196
+ declare class ZodOptional<E extends ZodLike> extends ZodType<OutputOf<E> | undefined> {
197
+ readonly _zod: {
198
+ output: OutputOf<E> | undefined;
199
+ input: OutputOf<E> | undefined;
200
+ def: SchemaDef & {
201
+ type: 'optional';
202
+ element: E;
203
+ };
204
+ };
205
+ inner(v: unknown): OutputOf<E> | undefined;
206
+ }
207
+ declare class ZodNullable<E extends ZodLike> extends ZodType<OutputOf<E> | null> {
208
+ readonly _zod: {
209
+ output: OutputOf<E> | null;
210
+ input: OutputOf<E> | null;
211
+ def: SchemaDef & {
212
+ type: 'nullable';
213
+ element: E;
214
+ };
215
+ };
216
+ inner(v: unknown): OutputOf<E> | null;
217
+ }
218
+ declare class ZodLiteral<V extends string | number | boolean> extends ZodType<V> {
219
+ readonly _zod: {
220
+ output: V;
221
+ input: V;
222
+ def: SchemaDef & {
223
+ type: 'literal';
224
+ };
225
+ };
226
+ inner(v: unknown): V;
227
+ }
228
+ declare class ZodUnion<O extends readonly ZodLike[]> extends ZodType<OutputOf<O[number]>> {
229
+ readonly _zod: {
230
+ output: OutputOf<O[number]>;
231
+ input: OutputOf<O[number]>;
232
+ def: SchemaDef & {
233
+ type: 'union';
234
+ options: O;
235
+ };
236
+ };
237
+ inner(v: unknown): OutputOf<O[number]>;
238
+ }
239
+ declare class ZodRecord<E extends ZodLike> extends ZodType<Record<string, OutputOf<E>>> {
240
+ readonly _zod: {
241
+ output: Record<string, OutputOf<E>>;
242
+ input: Record<string, OutputOf<E>>;
243
+ def: SchemaDef & {
244
+ type: 'record';
245
+ element: E;
246
+ };
247
+ };
248
+ inner(v: unknown): Record<string, OutputOf<E>>;
249
+ }
250
+ /**
251
+ * Function-typed members — how a props schema declares a `callbackProp`
252
+ * slot: the wire carries a `{__cb:id}` handle that `unmarshalCallbackProps`
253
+ * restores to a callable BEFORE contract validation runs, so at parse time
254
+ * the member is a real function.
255
+ */
256
+ declare class ZodCallback<F extends (...args: any[]) => any = (...args: unknown[]) => unknown> extends ZodType<F> {
257
+ readonly _zod: {
258
+ output: F;
259
+ input: F;
260
+ def: SchemaDef & {
261
+ type: 'function';
262
+ };
263
+ };
264
+ inner(v: unknown): F;
265
+ }
266
+ declare const number: () => Fluent<ZodNumber>;
267
+ declare const string: () => Fluent<ZodString>;
268
+ declare const boolean_: () => Fluent<ZodBoolean>;
269
+ declare const bigint_: () => Fluent<ZodBigint>;
270
+ declare const unknown_: () => Fluent<ZodUnknown>;
271
+ declare const instanceof_: <T extends abstract new (...args: any[]) => any>(cls: T) => Fluent<ZodInstanceof<InstanceType<T>>>;
272
+ declare const object_: <S extends Record<string, ZodLike>>(shape: S) => Fluent<ZodObjectSchema<S>>;
273
+ declare const array: <E extends ZodLike>(element: E) => Fluent<ZodArraySchema<E>>;
274
+ declare const optional: <E extends ZodLike>(element: E) => Fluent<ZodOptional<E>>;
275
+ declare const nullable: <E extends ZodLike>(element: E) => Fluent<ZodNullable<E>>;
276
+ declare const literal: <V extends string | number | boolean>(value: V) => Fluent<ZodLiteral<V>>;
277
+ declare const union: <O extends readonly [ZodLike, ...ZodLike[]]>(options: O) => Fluent<ZodUnion<O>>;
278
+ declare const record: <E extends ZodLike>(element: E) => Fluent<ZodRecord<E>>;
279
+ declare const callback: <F extends (...args: any[]) => any = (...args: unknown[]) => unknown>() => Fluent<ZodCallback<F>>;
190
280
  declare const int32: () => ZodNumber;
191
281
  declare const uint32: () => ZodNumber;
192
282
  declare const float32: () => ZodNumber;
@@ -204,6 +294,10 @@ export type Fluent<S extends ZodLike> = S & {
204
294
  max(value: number | bigint): Fluent<S>;
205
295
  length(n: number): Fluent<S>;
206
296
  int(): Fluent<S>;
297
+ /** Wraps in an optional member — the `label?: string` spelling. */
298
+ optional(): Fluent<ZodOptional<S>>;
299
+ /** Wraps in a nullable member — `T | null`. */
300
+ nullable(): Fluent<ZodNullable<S>>;
207
301
  };
208
302
  /** Attaches the `Fluent` methods as non-enumerable own properties. */
209
303
  export declare function fluent<S extends ZodType>(schema: S): Fluent<S>;
@@ -216,6 +310,12 @@ export declare const z: {
216
310
  array: typeof array;
217
311
  instanceof: typeof instanceof_;
218
312
  unknown: typeof unknown_;
313
+ optional: typeof optional;
314
+ nullable: typeof nullable;
315
+ literal: typeof literal;
316
+ union: typeof union;
317
+ record: typeof record;
318
+ callback: typeof callback;
219
319
  int32: typeof int32;
220
320
  uint32: typeof uint32;
221
321
  float32: typeof float32;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  export { bindSharedMemories, defineSharedMemory, field, getDefinedSharedMemoryCount, jsonCodec, registerConnectorFactory } from './contract/sharedMemory.js';
2
2
  export { reef } from './contract/reef.js';
3
+ export { z, SchemaError } from './contract/zod.js';
4
+ export type { ZodLike } from './contract/zod.js';
3
5
  export type { Codec, Connector, ConnectorContext, ConnectorFactory, FieldDescriptor, FieldGroup, FieldSchema, FixedArrayDescriptor, FixedObjectDescriptor, FlatKey, InferField, PathConnector, SpecPath, SpecSchemas, SharedAccess, SharedMemory, SharedMemoryOptions, SharedSpec, ScalarKind, ListConnector, ListDescriptor, ListFieldSpec, ListFields, ListMember, ListRecord, ListSpec, } from './contract/sharedMemory.js';
4
6
  export { msgpackrCodec } from './contract/msgpackrCodec.js';
5
7
  export { listSchema } from './contract/listSchema.js';
package/dist/index.js CHANGED
@@ -1,18 +1,19 @@
1
1
  import { msgpackrCodec as e } from "./index2.js";
2
- import { listSchema as t } from "./index4.js";
3
- import { getLogLevel as n, log as r, scoped as i, setLogLevel as a, setLogSink as o } from "./index5.js";
4
- import { bindSharedMemories as s, defineSharedMemory as c, field as l, getDefinedSharedMemoryCount as u, jsonCodec as d, registerConnectorFactory as f } from "./index6.js";
5
- import { reef as p } from "./index7.js";
6
- import { MemoryManager as m } from "./index8.js";
7
- import { PoolQueueFullError as h, TaskAbortedError as g, TaskTimeoutError as _, WorkerCrashedError as v } from "./index9.js";
8
- import { WorkerPool as y } from "./index10.js";
9
- import { connectWorker as b, workerClient as x } from "./index11.js";
10
- import { connectSharedWorker as S } from "./index12.js";
11
- import { TaskRegistry as C } from "./index13.js";
12
- import { sharedWorkerHost as w } from "./index14.js";
13
- import { createClient as T, defineService as E, implementService as D, rpc as O, serviceMethod as k } from "./index15.js";
14
- import { RESERVED_CLIENT_KEYS as A, defineWorker as j } from "./index17.js";
15
- import { reactive as M, shallowEqual as N, watch as P } from "./index18.js";
16
- import { observe as F } from "./index19.js";
17
- import { defineTask as I, isAsyncTask as L, toTask as R } from "./index20.js";
18
- export { m as MemoryManager, h as PoolQueueFullError, A as RESERVED_CLIENT_KEYS, g as TaskAbortedError, C as TaskRegistry, _ as TaskTimeoutError, v as WorkerCrashedError, y as WorkerPool, s as bindSharedMemories, S as connectSharedWorker, b as connectWorker, T as createClient, E as defineService, c as defineSharedMemory, I as defineTask, j as defineWorker, l as field, u as getDefinedSharedMemoryCount, n as getLogLevel, D as implementService, L as isAsyncTask, d as jsonCodec, t as listSchema, r as log, e as msgpackrCodec, F as observe, M as reactive, p as reef, f as registerConnectorFactory, O as rpc, i as scoped, k as serviceMethod, a as setLogLevel, o as setLogSink, N as shallowEqual, w as sharedWorkerHost, R as toTask, P as watch, x as workerClient };
2
+ import { SchemaError as t, z as n } from "./index3.js";
3
+ import { listSchema as r } from "./index4.js";
4
+ import { getLogLevel as i, log as a, scoped as o, setLogLevel as s, setLogSink as c } from "./index5.js";
5
+ import { bindSharedMemories as l, defineSharedMemory as u, field as d, getDefinedSharedMemoryCount as f, jsonCodec as p, registerConnectorFactory as m } from "./index6.js";
6
+ import { reef as h } from "./index7.js";
7
+ import { MemoryManager as g } from "./index8.js";
8
+ import { PoolQueueFullError as _, TaskAbortedError as v, TaskTimeoutError as y, WorkerCrashedError as b } from "./index9.js";
9
+ import { WorkerPool as x } from "./index10.js";
10
+ import { connectWorker as S, workerClient as C } from "./index11.js";
11
+ import { connectSharedWorker as w } from "./index12.js";
12
+ import { TaskRegistry as T } from "./index13.js";
13
+ import { sharedWorkerHost as E } from "./index14.js";
14
+ import { createClient as D, defineService as O, implementService as k, rpc as A, serviceMethod as j } from "./index15.js";
15
+ import { RESERVED_CLIENT_KEYS as M, defineWorker as N } from "./index17.js";
16
+ import { reactive as P, shallowEqual as F, watch as I } from "./index18.js";
17
+ import { observe as L } from "./index19.js";
18
+ import { defineTask as R, isAsyncTask as z, toTask as B } from "./index20.js";
19
+ export { g as MemoryManager, _ as PoolQueueFullError, M as RESERVED_CLIENT_KEYS, t as SchemaError, v as TaskAbortedError, T as TaskRegistry, y as TaskTimeoutError, b as WorkerCrashedError, x as WorkerPool, l as bindSharedMemories, w as connectSharedWorker, S as connectWorker, D as createClient, O as defineService, u as defineSharedMemory, R as defineTask, N as defineWorker, d as field, f as getDefinedSharedMemoryCount, i as getLogLevel, k as implementService, z as isAsyncTask, p as jsonCodec, r as listSchema, a as log, e as msgpackrCodec, L as observe, P as reactive, h as reef, m as registerConnectorFactory, A as rpc, o as scoped, j as serviceMethod, s as setLogLevel, c as setLogSink, F as shallowEqual, E as sharedWorkerHost, B as toTask, I as watch, C as workerClient, n as z };
package/dist/index18.js CHANGED
@@ -1,59 +1,88 @@
1
1
  import { scoped as e } from "./index5.js";
2
- import { createEffect as t, createMemo as n, createRoot as r, createSignal as i } from "solid-js";
2
+ import { createEffect as t, createMemo as n, createRenderEffect as r, createRoot as i, createSignal as a } from "solid-js";
3
3
  //#region src/reactive.ts
4
- var a = e("reactive");
5
- function o(e, t) {
4
+ var o = e("reactive");
5
+ function s(e, t) {
6
6
  if (e === t) return !0;
7
7
  if (e == null || t == null) return !1;
8
8
  let n = Object.keys(e), r = Object.keys(t);
9
9
  return n.length === r.length && n.every((n) => Object.is(e[n], t[n]));
10
10
  }
11
- function s(e) {
12
- let [t, n] = i(e.read(), { equals: !1 }), r = () => n(() => e.read());
11
+ var c = (e, t) => {
12
+ let n = e._version;
13
+ if (!n) throw Error("This connector does not support remote observation.");
14
+ let r = !1, i = Atomics.load(n.view, n.index);
15
+ if (typeof Atomics.waitAsync == "function") return o.debug(`observing remote writes (offset ${e.byteOffset}, waitAsync)`), (async () => {
16
+ for (; !r;) {
17
+ let a = Atomics.waitAsync(n.view, n.index, i);
18
+ a.async && await a.value, i = Atomics.load(n.view, n.index), r || (o.trace(`remote write observed (offset ${e.byteOffset})`), t());
19
+ }
20
+ o.debug(`stopped observing (offset ${e.byteOffset})`);
21
+ })(), () => {
22
+ r = !0;
23
+ };
24
+ o.warn(`Atomics.waitAsync unavailable — observing via 50ms poll (offset ${e.byteOffset})`);
25
+ let a = setInterval(() => {
26
+ let e = Atomics.load(n.view, n.index);
27
+ e !== i && (i = e, t());
28
+ }, 50);
29
+ return () => {
30
+ r = !0, clearInterval(a);
31
+ };
32
+ }, l = null, u = () => {
33
+ if (l !== null) return l;
34
+ try {
35
+ let e = 0, t;
36
+ i(() => {
37
+ let [n, i] = a(0);
38
+ t = i, r(() => {
39
+ n(), e++;
40
+ });
41
+ }), t?.(1), l = e > 1;
42
+ } catch {
43
+ l = !1;
44
+ }
45
+ return l || o.warn("solid-js resolved to the SSR build — watch() falls back to direct version watching"), l;
46
+ };
47
+ function d(e) {
48
+ let [t, n] = a(e.read(), { equals: !1 }), r = () => n(() => e.read());
13
49
  return {
14
50
  get: t,
15
51
  peek: () => e.read(),
16
52
  set: (t) => {
17
53
  e.write(t), r();
18
54
  },
19
- observeRemote: () => {
20
- let t = e._version;
21
- if (!t) throw Error("This connector does not support remote observation.");
22
- let n = !1, i = Atomics.load(t.view, t.index);
23
- if (typeof Atomics.waitAsync == "function") return a.debug(`observing remote writes (offset ${e.byteOffset}, waitAsync)`), (async () => {
24
- for (; !n;) {
25
- let o = Atomics.waitAsync(t.view, t.index, i);
26
- o.async && await o.value, i = Atomics.load(t.view, t.index), n || (a.trace(`remote write observed (offset ${e.byteOffset})`), r());
27
- }
28
- a.debug(`stopped observing (offset ${e.byteOffset})`);
29
- })(), () => {
30
- n = !0;
31
- };
32
- a.warn(`Atomics.waitAsync unavailable — observing via 50ms poll (offset ${e.byteOffset})`);
33
- let o = setInterval(() => {
34
- let e = Atomics.load(t.view, t.index);
35
- e !== i && (i = e, r());
36
- }, 50);
37
- return () => {
38
- n = !0, clearInterval(o);
39
- };
40
- }
55
+ observeRemote: () => c(e, r)
41
56
  };
42
57
  }
43
- function c(e, i, o, c) {
44
- let l = o ? i : ((e) => e), u = o ?? i, d = s(e), f = d.observeRemote(), p = r((e) => {
58
+ function f(e, r, a, s) {
59
+ let l = a ? r : ((e) => e), f = a ?? r;
60
+ if (!u()) {
61
+ let t = (e, t) => e === void 0 || t === void 0 ? e === t : (s?.equals ?? Object.is)(e, t), n, r = () => {
62
+ let r = e.read(), i = r == null ? void 0 : l(r);
63
+ if (i === void 0 || t(n, i)) return;
64
+ let a = n;
65
+ n = i, f(i, a);
66
+ };
67
+ r();
68
+ let i = c(e, r);
69
+ return o.debug(`watching connector at offset ${e.byteOffset} (direct)`), () => {
70
+ o.debug(`watch stopped (offset ${e.byteOffset})`), i();
71
+ };
72
+ }
73
+ let p = d(e), m = p.observeRemote(), h = i((e) => {
45
74
  let r = n(() => {
46
- let e = d.get();
75
+ let e = p.get();
47
76
  return e == null ? void 0 : l(e);
48
- }, void 0, c?.equals ? { equals: (e, t) => e === void 0 || t === void 0 ? e === t : c.equals(e, t) } : void 0);
77
+ }, void 0, s?.equals ? { equals: (e, t) => e === void 0 || t === void 0 ? e === t : s.equals(e, t) } : void 0);
49
78
  return t((e) => {
50
79
  let t = r();
51
- return t !== void 0 && u(t, e), t;
80
+ return t !== void 0 && f(t, e), t;
52
81
  }), e;
53
82
  });
54
- return a.debug(`watching connector at offset ${e.byteOffset}`), () => {
55
- a.debug(`watch stopped (offset ${e.byteOffset})`), f(), p();
83
+ return o.debug(`watching connector at offset ${e.byteOffset}`), () => {
84
+ o.debug(`watch stopped (offset ${e.byteOffset})`), m(), h();
56
85
  };
57
86
  }
58
87
  //#endregion
59
- export { s as reactive, o as shallowEqual, c as watch };
88
+ export { d as reactive, s as shallowEqual, f as watch };
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,9 +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 };
262
+ export { h as SchemaError, g as ZodType, $ as fluent, m as globalRegistry, te as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atolljs/core",
3
- "version": "0.1.5",
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",
@@ -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,
package/src/reactive.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { createEffect, createMemo, createRoot, createSignal } from 'solid-js';
1
+ import { createEffect, createMemo, createRenderEffect, createRoot, createSignal } from 'solid-js';
2
2
  import { Connector } from './contract/sharedMemory';
3
3
  import { scoped } from './log';
4
4
 
@@ -40,6 +40,87 @@ export interface ReactiveConnector<T> {
40
40
  observeRemote(): () => void;
41
41
  }
42
42
 
43
+ /**
44
+ * Park on the connector's shared version counter and invoke `onBump` on each
45
+ * write — local or remote, both bump it. waitAsync when available, 50ms poll
46
+ * otherwise. No solid-js involved: this is the whole remote-write mechanism.
47
+ */
48
+ const watchVersion = <T>(connector: Connector<T>, onBump: () => void): (() => void) => {
49
+ const version = connector._version;
50
+ if (!version) {
51
+ throw new Error('This connector does not support remote observation.');
52
+ }
53
+ let stopped = false;
54
+ let last = Atomics.load(version.view, version.index);
55
+
56
+ if (typeof Atomics.waitAsync === 'function') {
57
+ reactiveLog.debug(`observing remote writes (offset ${connector.byteOffset}, waitAsync)`);
58
+ void (async () => {
59
+ while (!stopped) {
60
+ const result = Atomics.waitAsync(version.view, version.index, last);
61
+ if (result.async) {
62
+ await result.value;
63
+ }
64
+ last = Atomics.load(version.view, version.index);
65
+ if (!stopped) {
66
+ reactiveLog.trace(`remote write observed (offset ${connector.byteOffset})`);
67
+ onBump();
68
+ }
69
+ }
70
+ reactiveLog.debug(`stopped observing (offset ${connector.byteOffset})`);
71
+ })();
72
+ return () => { stopped = true; };
73
+ }
74
+
75
+ reactiveLog.warn(`Atomics.waitAsync unavailable — observing via 50ms poll (offset ${connector.byteOffset})`);
76
+ const timer = setInterval(() => {
77
+ const current = Atomics.load(version.view, version.index);
78
+ if (current !== last) {
79
+ last = current;
80
+ onBump();
81
+ }
82
+ }, 50);
83
+ return () => {
84
+ stopped = true;
85
+ clearInterval(timer);
86
+ };
87
+ };
88
+
89
+ /**
90
+ * Under `node`/`worker`/`deno` export conditions, `solid-js` resolves to the
91
+ * SSR build — `createEffect` is a no-op, so signal-driven `watch`/`observe`
92
+ * die silently. Probe once. `createRenderEffect` is the discriminator: it
93
+ * runs synchronously at creation in BOTH builds but only re-fires on `set`
94
+ * in the client build. `createEffect` can't be used — the client build
95
+ * defers it past the synchronous `set` below, probing a false negative.
96
+ * The write must land AFTER the root's create pass returns for the same
97
+ * reason (a set issued mid-subscription is swallowed).
98
+ */
99
+ let solidLive: boolean | null = null;
100
+ const solidIsLive = (): boolean => {
101
+ if (solidLive !== null) return solidLive;
102
+ try {
103
+ let runs = 0;
104
+ let bump: ((v: number) => number) | undefined;
105
+ createRoot(() => {
106
+ const [get, set] = createSignal(0);
107
+ bump = set;
108
+ createRenderEffect(() => {
109
+ get();
110
+ runs++;
111
+ });
112
+ });
113
+ bump?.(1);
114
+ solidLive = runs > 1;
115
+ } catch {
116
+ solidLive = false;
117
+ }
118
+ if (!solidLive) {
119
+ reactiveLog.warn('solid-js resolved to the SSR build — watch() falls back to direct version watching');
120
+ }
121
+ return solidLive;
122
+ };
123
+
43
124
  export function reactive<T>(connector: Connector<T>): ReactiveConnector<T> {
44
125
  const [value, setValue] = createSignal<T>(connector.read(), { equals: false });
45
126
  const bump = () => setValue(() => connector.read());
@@ -51,47 +132,7 @@ export function reactive<T>(connector: Connector<T>): ReactiveConnector<T> {
51
132
  connector.write(v);
52
133
  bump();
53
134
  },
54
- observeRemote: () => {
55
- const version = connector._version;
56
- if (!version) {
57
- throw new Error('This connector does not support remote observation.');
58
- }
59
- let stopped = false;
60
- let last = Atomics.load(version.view, version.index);
61
-
62
- if (typeof Atomics.waitAsync === 'function') {
63
- reactiveLog.debug(`observing remote writes (offset ${connector.byteOffset}, waitAsync)`);
64
- void (async () => {
65
- while (!stopped) {
66
- const result = Atomics.waitAsync(version.view, version.index, last);
67
- if (result.async) {
68
- await result.value;
69
- }
70
- last = Atomics.load(version.view, version.index);
71
- if (!stopped) {
72
- reactiveLog.trace(`remote write observed (offset ${connector.byteOffset})`);
73
- bump();
74
- }
75
- }
76
- reactiveLog.debug(`stopped observing (offset ${connector.byteOffset})`);
77
- })();
78
- return () => { stopped = true; };
79
- }
80
-
81
- // Fallback for environments without Atomics.waitAsync
82
- reactiveLog.warn(`Atomics.waitAsync unavailable — observing via 50ms poll (offset ${connector.byteOffset})`);
83
- const timer = setInterval(() => {
84
- const current = Atomics.load(version.view, version.index);
85
- if (current !== last) {
86
- last = current;
87
- bump();
88
- }
89
- }, 50);
90
- return () => {
91
- stopped = true;
92
- clearInterval(timer);
93
- };
94
- },
135
+ observeRemote: () => watchVersion(connector, bump),
95
136
  };
96
137
  }
97
138
 
@@ -127,6 +168,30 @@ export function watch<T, S = T>(
127
168
  const select = onChange ? (selOrCb as (value: T) => S) : ((v: T) => v as unknown as S);
128
169
  const cb = (onChange ?? selOrCb) as (slice: S, previous: S | undefined) => void;
129
170
 
171
+ // SSR solid build (node/worker conditions): effects never re-run, so the
172
+ // signal pipeline below would silently never emit. Same semantics, driven
173
+ // straight off the version counter instead.
174
+ if (!solidIsLive()) {
175
+ const eq = (a: S | undefined, b: S | undefined): boolean =>
176
+ a === undefined || b === undefined ? a === b : (options?.equals ?? Object.is)(a, b);
177
+ let prev: S | undefined;
178
+ const emit = () => {
179
+ const v = connector.read() as T | null | undefined;
180
+ const s = v == null ? undefined : select(v);
181
+ if (s === undefined || eq(prev, s)) return;
182
+ const old = prev;
183
+ prev = s;
184
+ cb(s, old);
185
+ };
186
+ emit();
187
+ const stop = watchVersion(connector, emit);
188
+ reactiveLog.debug(`watching connector at offset ${connector.byteOffset} (direct)`);
189
+ return () => {
190
+ reactiveLog.debug(`watch stopped (offset ${connector.byteOffset})`);
191
+ stop();
192
+ };
193
+ }
194
+
130
195
  const sig = reactive(connector);
131
196
  const stopRemote = sig.observeRemote();
132
197
  const dispose = createRoot((d) => {