zerodrift 1.0.3 → 1.1.0
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 +15 -3
- package/dist/core/BaseModel.d.ts +2 -2
- package/dist/core/BaseModel.js +4 -4
- package/dist/core/BaseSSEConnection.d.ts +9 -3
- package/dist/core/BaseSSEConnection.js +23 -3
- package/dist/core/CompoundIndexFetcher.d.ts +2 -2
- package/dist/core/CompoundIndexFetcher.js +3 -3
- package/dist/core/Database.d.ts +2 -1
- package/dist/core/Database.js +1 -1
- package/dist/core/LazyCollection.d.ts +2 -2
- package/dist/core/LazyCollection.js +1 -1
- package/dist/core/LazyOwnedCollection.d.ts +2 -2
- package/dist/core/LazyOwnedCollection.js +1 -1
- package/dist/core/MemoryAdapter.d.ts +1 -1
- package/dist/core/MemoryAdapter.js +1 -1
- package/dist/core/ModelRegistry.d.ts +1 -1
- package/dist/core/ModelRegistry.js +2 -2
- package/dist/core/ModelStream.d.ts +4 -4
- package/dist/core/ModelStream.js +3 -3
- package/dist/core/ObjectPool.d.ts +2 -2
- package/dist/core/ObjectPool.js +2 -2
- package/dist/core/Store.d.ts +4 -4
- package/dist/core/Store.js +1 -1
- package/dist/core/StoreManager.d.ts +23 -12
- package/dist/core/StoreManager.js +25 -13
- package/dist/core/SyncConnection.d.ts +6 -6
- package/dist/core/SyncConnection.js +11 -10
- package/dist/core/Transaction.d.ts +2 -2
- package/dist/core/Transaction.js +1 -1
- package/dist/core/TransactionQueue.d.ts +6 -6
- package/dist/core/TransactionQueue.js +4 -4
- package/dist/core/decorators.d.ts +1 -1
- package/dist/core/decorators.js +4 -4
- package/dist/core/index.d.ts +16 -16
- package/dist/core/index.js +9 -9
- package/dist/core/internal.d.ts +13 -13
- package/dist/core/internal.js +11 -11
- package/dist/core/observability.js +1 -1
- package/dist/core/refAccessors.d.ts +2 -2
- package/dist/core/types.d.ts +1 -1
- package/dist/react/index.d.ts +22 -12
- package/dist/react/index.js +31 -23
- package/dist/schema/builders.d.ts +1 -1
- package/dist/schema/builders.js +1 -1
- package/dist/schema/compile.d.ts +1 -1
- package/dist/schema/compile.js +6 -6
- package/dist/schema/createStore.d.ts +5 -5
- package/dist/schema/createStore.js +4 -4
- package/dist/schema/extend.d.ts +2 -2
- package/dist/schema/index.d.ts +13 -13
- package/dist/schema/index.js +7 -7
- package/dist/schema/infer.d.ts +10 -1
- package/dist/schema/types.d.ts +1 -1
- package/dist/schema/zod.d.ts +125 -12
- package/dist/schema/zod.js +24 -2
- package/package.json +1 -1
package/dist/schema/zod.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { z } from "zod";
|
|
2
|
-
import type { AnyFieldBuilder, EntityDef, FieldBuilder } from "./types";
|
|
2
|
+
import type { AnyFieldBuilder, EntityDef, FieldBuilder, FieldKind, FieldMeta } from "./types.js";
|
|
3
3
|
/**
|
|
4
4
|
* Convert any Zod schema into the equivalent schema-first `FieldBuilder`.
|
|
5
5
|
* Handles the common nullable / optional / default modifiers; anything more
|
|
@@ -10,31 +10,111 @@ import type { AnyFieldBuilder, EntityDef, FieldBuilder } from "./types";
|
|
|
10
10
|
* caller to have installed `zod`.
|
|
11
11
|
*/
|
|
12
12
|
export declare function fromZod<Z extends z.ZodType>(zSchema: Z): FieldBuilder<z.infer<Z>>;
|
|
13
|
+
/**
|
|
14
|
+
* Maps Zod's `_zod.def.type` discriminator to a schema `FieldKind`. Mirrors
|
|
15
|
+
* the runtime `PRIMITIVE_KIND` map; anything not covered collapses to `"json"`,
|
|
16
|
+
* matching `fromZod`'s fallback.
|
|
17
|
+
*/
|
|
18
|
+
type ZodKindFromTypeName<T> = T extends "string" ? "string" : T extends "number" | "int" ? "number" : T extends "boolean" ? "boolean" : T extends "date" ? "date" : "json";
|
|
19
|
+
/**
|
|
20
|
+
* Type-level analogue of `fromZod`'s runtime walker: peels off `nullable` /
|
|
21
|
+
* `optional` / `default` wrappers, stamping each on the accumulator, then
|
|
22
|
+
* collapses the leaf to a kind via `ZodKindFromTypeName`. The result is
|
|
23
|
+
* intersected with `FieldMeta` so `IsOptionalCreateField` sees the same
|
|
24
|
+
* `{kind, optional, default}` flags the runtime produces — keeping
|
|
25
|
+
* create-input optionality aligned for `.optional()` and `.default(...)`
|
|
26
|
+
* Zod fields, not just `id`.
|
|
27
|
+
*/
|
|
28
|
+
type ZodToFieldMeta<Z, Accum = Record<never, never>> = Z extends {
|
|
29
|
+
_zod: {
|
|
30
|
+
def: {
|
|
31
|
+
type: "nullable";
|
|
32
|
+
innerType: infer I;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
} ? ZodToFieldMeta<I, Accum & {
|
|
36
|
+
nullable: true;
|
|
37
|
+
}> : Z extends {
|
|
38
|
+
_zod: {
|
|
39
|
+
def: {
|
|
40
|
+
type: "optional";
|
|
41
|
+
innerType: infer I;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
} ? ZodToFieldMeta<I, Accum & {
|
|
45
|
+
optional: true;
|
|
46
|
+
}> : Z extends {
|
|
47
|
+
_zod: {
|
|
48
|
+
def: {
|
|
49
|
+
type: "default";
|
|
50
|
+
innerType: infer I;
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
} ? ZodToFieldMeta<I, Accum & {
|
|
54
|
+
default: unknown;
|
|
55
|
+
}> : Z extends {
|
|
56
|
+
_zod: {
|
|
57
|
+
def: {
|
|
58
|
+
type: infer T extends string;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
} ? Accum & {
|
|
62
|
+
kind: ZodKindFromTypeName<T>;
|
|
63
|
+
} : Accum;
|
|
64
|
+
/** Empty meta marker — convention-driven flags (autoIndex) layer on top.
|
|
65
|
+
* `id` is excluded because the storage layer treats the PK specially and
|
|
66
|
+
* never materializes a secondary index for it; the empty-string suffix is
|
|
67
|
+
* excluded so a defaulted/blank config value doesn't index every field. */
|
|
68
|
+
type AutoIndexMeta<K, AI extends string | undefined> = K extends "id" ? Record<never, never> : AI extends "" ? Record<never, never> : AI extends string ? K extends `${string}${AI}` ? {
|
|
69
|
+
indexed: true;
|
|
70
|
+
} : Record<never, never> : Record<never, never>;
|
|
71
|
+
/**
|
|
72
|
+
* Auto-derived `FieldBuilder` type for a Zod-object key. The `id` key is
|
|
73
|
+
* special-cased to carry `{kind: "id"}` (the runtime routes `id` through
|
|
74
|
+
* `fields.id()` regardless of the Zod-declared id type). Every other key
|
|
75
|
+
* walks its Zod schema via `ZodToFieldMeta` so PK, optional, and default
|
|
76
|
+
* flags all flow into the field's create-input optionality the same way.
|
|
77
|
+
* `AI` is the opts.autoIndex suffix — matching keys pick up `{indexed: true}`.
|
|
78
|
+
*/
|
|
79
|
+
type AutoFieldFromZod<K, ZS, AI extends string | undefined = undefined> = K extends "id" ? FieldBuilder<string, FieldMeta & {
|
|
80
|
+
kind: "id";
|
|
81
|
+
} & AutoIndexMeta<K, AI>> : ZS extends z.ZodType ? FieldBuilder<z.infer<ZS>, FieldMeta & ZodToFieldMeta<ZS> & AutoIndexMeta<K, AI>> : FieldBuilder<unknown, FieldMeta & {
|
|
82
|
+
kind: FieldKind;
|
|
83
|
+
}>;
|
|
13
84
|
/**
|
|
14
85
|
* Per-field override for `entityFromZod`. Either a chaining function
|
|
15
86
|
* (modifies the auto-derived `FieldBuilder`) or a full `FieldBuilder`
|
|
16
87
|
* (replaces it — useful for FKs and other shapes Zod can't model).
|
|
17
88
|
*/
|
|
18
89
|
export type EntityFromZodFieldOverride<AutoT = unknown> = AnyFieldBuilder | ((auto: FieldBuilder<AutoT>) => AnyFieldBuilder);
|
|
19
|
-
type EntityFromZodFieldOverrides<Z extends z.ZodObject> = {
|
|
20
|
-
[K in keyof
|
|
90
|
+
type EntityFromZodFieldOverrides<Z extends z.ZodObject, AI extends string | undefined = undefined> = {
|
|
91
|
+
[K in keyof Z["shape"] & string]?: AnyFieldBuilder | ((auto: AutoFieldFromZod<K, Z["shape"][K], AI>) => unknown);
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Maps any `opts.fields` key that isn't declared on the Zod object to a
|
|
95
|
+
* branded error-string type. The intersection with the override map then
|
|
96
|
+
* forces TS to surface "is not assignable to type \"Error: 'foo' is not a
|
|
97
|
+
* field…\"" — naming the offender — instead of the bare "not assignable to
|
|
98
|
+
* type 'never'" the previous `Record<…, never>` form produced.
|
|
99
|
+
*/
|
|
100
|
+
type NoExtraZodFieldKeys<Z extends z.ZodObject, F> = {
|
|
101
|
+
[K in keyof F as K extends keyof Z["shape"] ? never : K]: `Error: '${K & string}' is not a field declared on the Zod object passed to entityFromZod`;
|
|
21
102
|
};
|
|
22
|
-
type NoExtraZodFieldKeys<Z extends z.ZodObject, F> = Record<Exclude<keyof F, keyof z.infer<Z> & string>, never>;
|
|
23
103
|
/**
|
|
24
104
|
* Resolve the field type contributed by an override entry. Functions are
|
|
25
105
|
* unwrapped via their inferred return type so chained modifiers like
|
|
26
106
|
* `.indexed()` carry their narrowed `M` into the entity's inferred fields;
|
|
27
107
|
* direct `FieldBuilder` overrides are used as-is. When no override is
|
|
28
|
-
* provided the auto-derived `
|
|
108
|
+
* provided the auto-derived `Auto` field stands.
|
|
29
109
|
*/
|
|
30
|
-
type FieldFromOverride<O,
|
|
110
|
+
type FieldFromOverride<O, Auto> = O extends (...args: never[]) => infer R ? R extends FieldBuilder<infer RT, infer RM> ? [unknown] extends [RT] ? Auto extends FieldBuilder<infer AT, FieldMeta> ? FieldBuilder<AT, RM> : never : R : Auto : O extends AnyFieldBuilder ? O : Auto;
|
|
31
111
|
/**
|
|
32
112
|
* Per-key merge of the Zod-inferred fields with `opts.fields` overrides.
|
|
33
113
|
* Override metadata (`.indexed()`, refId target, …) propagates into the
|
|
34
114
|
* entity's TS type so downstream helpers like `IndexedFieldKeys` see them.
|
|
35
115
|
*/
|
|
36
|
-
type MergedFieldsFromZodObject<Z extends z.ZodObject, F> = {
|
|
37
|
-
[K in keyof
|
|
116
|
+
type MergedFieldsFromZodObject<Z extends z.ZodObject, F, Om extends readonly string[] = readonly [], AI extends string | undefined = undefined> = {
|
|
117
|
+
[K in keyof Z["shape"] as K extends Om[number] ? never : K]: K extends keyof F ? FieldFromOverride<F[K], AutoFieldFromZod<K, Z["shape"][K], AI>> : AutoFieldFromZod<K, Z["shape"][K], AI>;
|
|
38
118
|
};
|
|
39
119
|
/** Non-`fields` portion of the opts — shared across the public type and
|
|
40
120
|
* the function's inferred-`F` signature. Tracks `EntityDef` so any new
|
|
@@ -56,8 +136,15 @@ export interface EntityFromZodOpts<Z extends z.ZodObject = z.ZodObject> extends
|
|
|
56
136
|
* });
|
|
57
137
|
*/
|
|
58
138
|
fields?: {
|
|
59
|
-
[K in keyof
|
|
139
|
+
[K in keyof Z["shape"] & string]?: AnyFieldBuilder | ((auto: AutoFieldFromZod<K, Z["shape"][K]>) => AnyFieldBuilder);
|
|
60
140
|
};
|
|
141
|
+
/** Fields whose Zod name ends with this suffix pick up `.indexed()` —
|
|
142
|
+
* intended for the common FK-naming convention (`/ID$/` → `autoIndex: "ID"`).
|
|
143
|
+
* Suppressed for any key that supplies a builder-form override. */
|
|
144
|
+
autoIndex?: string;
|
|
145
|
+
/** Field names to drop entirely from the produced entity. Common when the
|
|
146
|
+
* source Zod was generated from a DTO that carries transport-only keys. */
|
|
147
|
+
omit?: readonly string[];
|
|
61
148
|
}
|
|
62
149
|
/**
|
|
63
150
|
* Convert a `z.object({ ... })` into an `EntityDef`. Each key on the Zod
|
|
@@ -84,7 +171,33 @@ export interface EntityFromZodOpts<Z extends z.ZodObject = z.ZodObject> extends
|
|
|
84
171
|
* shape and validation; `link(...)` remains the source of truth for the
|
|
85
172
|
* graph.
|
|
86
173
|
*/
|
|
87
|
-
export declare function entityFromZod<Z extends z.ZodObject, const F = Record<never, never
|
|
88
|
-
fields?: F & EntityFromZodFieldOverrides<Z> & NoExtraZodFieldKeys<Z, F>;
|
|
89
|
-
|
|
174
|
+
export declare function entityFromZod<Z extends z.ZodObject, const F = Record<never, never>, const Om extends readonly (keyof Z["shape"] & string)[] = readonly [], const AI extends string | undefined = undefined>(zSchema: Z, opts: EntityFromZodOptsBase & {
|
|
175
|
+
fields?: F & EntityFromZodFieldOverrides<Z, AI> & NoExtraZodFieldKeys<Z, F>;
|
|
176
|
+
autoIndex?: AI;
|
|
177
|
+
omit?: Om;
|
|
178
|
+
}): EntityDef<MergedFieldsFromZodObject<Z, F, Om, AI>>;
|
|
179
|
+
/**
|
|
180
|
+
* Map a whole `{key: ZodObject}` module (e.g. an OpenAPI-generated barrel)
|
|
181
|
+
* into an entities record by calling `entityFromZod` per key with shared
|
|
182
|
+
* opts. The entity key in the returned record is the input key; the registry
|
|
183
|
+
* name is auto-derived (PascalCase of the key) by `compileSchema` — no need
|
|
184
|
+
* to spell `name` per entity.
|
|
185
|
+
*
|
|
186
|
+
* const entities = entitiesFromZod(generatedZods, {
|
|
187
|
+
* loadStrategy: LoadStrategy.Eager,
|
|
188
|
+
* autoIndex: "ID",
|
|
189
|
+
* omit: ["createdAt", "updatedAt"],
|
|
190
|
+
* });
|
|
191
|
+
* const schema = defineSchema({ entities, links: { ... } });
|
|
192
|
+
*
|
|
193
|
+
* Per-entity overrides are not threaded — drop down to `entityFromZod` for
|
|
194
|
+
* the handful that need a custom `fields` map or distinct `loadStrategy`.
|
|
195
|
+
*/
|
|
196
|
+
type EntitiesFromZodResult<Zods extends Record<string, z.ZodObject>, Om extends readonly string[], AI extends string | undefined> = {
|
|
197
|
+
[K in keyof Zods]: EntityDef<MergedFieldsFromZodObject<Zods[K], Record<never, never>, Om, AI>>;
|
|
198
|
+
};
|
|
199
|
+
export declare function entitiesFromZod<Zods extends Record<string, z.ZodObject>, const Om extends readonly string[] = readonly [], const AI extends string | undefined = undefined>(zods: Zods, opts: Pick<EntityFromZodOptsBase, "loadStrategy" | "usedForPartialIndexes"> & {
|
|
200
|
+
autoIndex?: AI;
|
|
201
|
+
omit?: Om;
|
|
202
|
+
}): EntitiesFromZodResult<Zods, Om, AI>;
|
|
90
203
|
export {};
|
package/dist/schema/zod.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { fields, entity, rebuildFieldBuilder } from "./builders";
|
|
1
|
+
import { fields, entity, rebuildFieldBuilder } from "./builders.js";
|
|
2
2
|
const PRIMITIVE_KIND = new Map([
|
|
3
3
|
["string", fields.string],
|
|
4
4
|
["number", fields.number],
|
|
@@ -82,9 +82,19 @@ export function fromZod(zSchema) {
|
|
|
82
82
|
*/
|
|
83
83
|
export function entityFromZod(zSchema, opts) {
|
|
84
84
|
const overrides = (opts.fields ?? {});
|
|
85
|
+
const omitted = new Set(opts.omit ?? []);
|
|
86
|
+
const autoIndexSuffix = opts.autoIndex != null && opts.autoIndex !== "" ? opts.autoIndex : null;
|
|
85
87
|
const fieldsRecord = {};
|
|
86
88
|
for (const [key, fieldSchema] of Object.entries(zSchema.shape)) {
|
|
87
|
-
|
|
89
|
+
if (omitted.has(key)) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
let auto = key === "id" ? fields.id() : fromZod(fieldSchema);
|
|
93
|
+
if (autoIndexSuffix != null &&
|
|
94
|
+
key !== "id" &&
|
|
95
|
+
key.endsWith(autoIndexSuffix)) {
|
|
96
|
+
auto = auto.indexed();
|
|
97
|
+
}
|
|
88
98
|
const override = overrides[key];
|
|
89
99
|
fieldsRecord[key] =
|
|
90
100
|
typeof override === "function"
|
|
@@ -99,3 +109,15 @@ export function entityFromZod(zSchema, opts) {
|
|
|
99
109
|
fields: fieldsRecord,
|
|
100
110
|
});
|
|
101
111
|
}
|
|
112
|
+
export function entitiesFromZod(zods, opts) {
|
|
113
|
+
const out = {};
|
|
114
|
+
for (const [key, zod] of Object.entries(zods)) {
|
|
115
|
+
out[key] = entityFromZod(zod, {
|
|
116
|
+
loadStrategy: opts.loadStrategy,
|
|
117
|
+
usedForPartialIndexes: opts.usedForPartialIndexes,
|
|
118
|
+
autoIndex: opts.autoIndex,
|
|
119
|
+
omit: opts.omit,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
return out;
|
|
123
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zerodrift",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A TypeScript local-first sync engine: synchronous in-memory reads, optimistic writes, realtime SSE sync, offline IndexedDB persistence. Runs in the browser and in Node.",
|
|
6
6
|
"license": "MIT",
|