@zodmon/core 0.0.0 → 0.2.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/dist/index.cjs +255 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +491 -1
- package/dist/index.d.ts +491 -1
- package/dist/index.js +236 -0
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.d.cts
CHANGED
|
@@ -1,2 +1,492 @@
|
|
|
1
|
+
import { ZodPipe, ZodCustom, ZodTransform, z } from 'zod';
|
|
2
|
+
import { ObjectId } from 'mongodb';
|
|
1
3
|
|
|
2
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Options controlling how a field-level MongoDB index is created.
|
|
6
|
+
*
|
|
7
|
+
* Passed to the `.index()` Zod extension method. Every property is optional;
|
|
8
|
+
* omitting all of them creates a standard ascending, non-unique index.
|
|
9
|
+
*/
|
|
10
|
+
type IndexOptions = {
|
|
11
|
+
/** When `true`, MongoDB enforces a unique constraint on this field. */
|
|
12
|
+
unique?: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* When `true`, the index skips documents where the field is `null` or missing.
|
|
15
|
+
* Useful for optional fields that should be indexed only when present.
|
|
16
|
+
*/
|
|
17
|
+
sparse?: boolean;
|
|
18
|
+
/** When `true`, creates a MongoDB text index for full-text search on this field. */
|
|
19
|
+
text?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* When `true`, the index is created in descending order (`-1`).
|
|
22
|
+
* Defaults to ascending (`1`) when omitted.
|
|
23
|
+
*/
|
|
24
|
+
descending?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* TTL in seconds. MongoDB will automatically delete documents once the
|
|
27
|
+
* indexed `Date` field is older than this many seconds. Only valid on
|
|
28
|
+
* fields whose runtime type is `Date`.
|
|
29
|
+
*/
|
|
30
|
+
expireAfter?: number;
|
|
31
|
+
/**
|
|
32
|
+
* A partial filter expression. Only documents matching this filter are
|
|
33
|
+
* included in the index. Maps directly to MongoDB's `partialFilterExpression`.
|
|
34
|
+
*/
|
|
35
|
+
partial?: Record<string, unknown>;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Metadata stored in the WeakMap sidecar for every schema that has been
|
|
39
|
+
* marked with `.index()`. Always contains `indexed: true` plus any
|
|
40
|
+
* {@link IndexOptions} the caller provided.
|
|
41
|
+
*/
|
|
42
|
+
type IndexMetadata = {
|
|
43
|
+
/** Always `true` — acts as a discriminator for "this field is indexed". */
|
|
44
|
+
indexed: true;
|
|
45
|
+
} & IndexOptions;
|
|
46
|
+
declare module 'zod' {
|
|
47
|
+
interface ZodType {
|
|
48
|
+
/**
|
|
49
|
+
* Mark this field for indexing when `syncIndexes()` is called.
|
|
50
|
+
*
|
|
51
|
+
* Stores {@link IndexOptions} in a WeakMap sidecar so the collection
|
|
52
|
+
* factory can later introspect each field and build the appropriate
|
|
53
|
+
* MongoDB index specification.
|
|
54
|
+
*
|
|
55
|
+
* @param options - Optional index configuration (unique, sparse, etc.).
|
|
56
|
+
* @returns The same schema instance for chaining.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```ts
|
|
60
|
+
* const UserSchema = z.object({
|
|
61
|
+
* email: z.string().index({ unique: true }),
|
|
62
|
+
* age: z.number().index({ sparse: true }),
|
|
63
|
+
* })
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
index(options?: IndexOptions): this;
|
|
67
|
+
/**
|
|
68
|
+
* Shorthand for `.index({ unique: true })`.
|
|
69
|
+
*
|
|
70
|
+
* Creates a unique index on this field, causing MongoDB to reject
|
|
71
|
+
* duplicate values.
|
|
72
|
+
*
|
|
73
|
+
* @returns The same schema instance for chaining.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```ts
|
|
77
|
+
* const UserSchema = z.object({
|
|
78
|
+
* email: z.string().unique(),
|
|
79
|
+
* })
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
unique(): this;
|
|
83
|
+
/**
|
|
84
|
+
* Shorthand for `.index({ text: true })`.
|
|
85
|
+
*
|
|
86
|
+
* Creates a MongoDB text index on this field, enabling `$text` queries
|
|
87
|
+
* for full-text search.
|
|
88
|
+
*
|
|
89
|
+
* @returns The same schema instance for chaining.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```ts
|
|
93
|
+
* const PostSchema = z.object({
|
|
94
|
+
* body: z.string().text(),
|
|
95
|
+
* })
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
text(): this;
|
|
99
|
+
/**
|
|
100
|
+
* Shorthand for `.index({ expireAfter: seconds })`.
|
|
101
|
+
*
|
|
102
|
+
* Creates a TTL (Time-To-Live) index. MongoDB will automatically
|
|
103
|
+
* remove documents once the indexed `Date` field is older than
|
|
104
|
+
* the specified number of seconds.
|
|
105
|
+
*
|
|
106
|
+
* @param seconds - Number of seconds after which documents expire.
|
|
107
|
+
* @returns The same schema instance for chaining.
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```ts
|
|
111
|
+
* const SessionSchema = z.object({
|
|
112
|
+
* createdAt: z.date().expireAfter(3600), // 1 hour TTL
|
|
113
|
+
* })
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
expireAfter(seconds: number): this;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Retrieve the index metadata attached to a Zod schema, if any.
|
|
121
|
+
*
|
|
122
|
+
* Returns `undefined` when the schema was never marked with an index
|
|
123
|
+
* extension (`.index()`, `.unique()`, `.text()`, or `.expireAfter()`).
|
|
124
|
+
*
|
|
125
|
+
* @param schema - The Zod schema to inspect. Accepts `unknown` for
|
|
126
|
+
* convenience; non-object values safely return `undefined`.
|
|
127
|
+
* @returns The {@link IndexMetadata} for the schema, or `undefined`.
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```ts
|
|
131
|
+
* const email = z.string().index({ unique: true })
|
|
132
|
+
* const meta = getIndexMetadata(email)
|
|
133
|
+
* // => { indexed: true, unique: true }
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
declare function getIndexMetadata(schema: unknown): IndexMetadata | undefined;
|
|
137
|
+
/**
|
|
138
|
+
* Monkey-patch Zod's `ZodType.prototype` with Zodmon extension methods
|
|
139
|
+
* (`.index()`, `.unique()`, `.text()`, `.expireAfter()`).
|
|
140
|
+
*
|
|
141
|
+
* In Zod v4, methods are copied from `ZodType.prototype` to each instance
|
|
142
|
+
* during construction via the internal `init` loop (`Object.keys(proto)` ->
|
|
143
|
+
* copy to instance). Extension methods use `enumerable: true` so they are
|
|
144
|
+
* picked up by this loop for every schema created after installation.
|
|
145
|
+
*
|
|
146
|
+
* The function is idempotent: calling it more than once is a safe no-op,
|
|
147
|
+
* guarded by a non-enumerable `Symbol.for('zodmon_extensions')` property
|
|
148
|
+
* on the prototype.
|
|
149
|
+
*
|
|
150
|
+
* This function is called at module level when `extensions.ts` is first
|
|
151
|
+
* imported, so consumers never need to call it manually. It is exported
|
|
152
|
+
* primarily for use in tests.
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```ts
|
|
156
|
+
* import { installExtensions } from '@zodmon/core/schema/extensions'
|
|
157
|
+
* installExtensions() // safe to call multiple times
|
|
158
|
+
*
|
|
159
|
+
* const indexed = z.string().index({ unique: true })
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
declare function installExtensions(): void;
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* The Zod type produced by {@link objectId}. A pipeline that validates an
|
|
166
|
+
* input as either a `string` (24-char hex) or an `ObjectId` instance, then
|
|
167
|
+
* transforms it into a concrete `ObjectId`.
|
|
168
|
+
*
|
|
169
|
+
* Use `z.infer<ZodObjectId>` to extract the output type (`ObjectId`) and
|
|
170
|
+
* `z.input<ZodObjectId>` for the input type (`string | ObjectId`).
|
|
171
|
+
*/
|
|
172
|
+
type ZodObjectId = ZodPipe<ZodCustom<string | ObjectId, string | ObjectId>, ZodTransform<ObjectId, string | ObjectId>>;
|
|
173
|
+
/**
|
|
174
|
+
* Create a Zod schema that validates and coerces values into MongoDB
|
|
175
|
+
* `ObjectId` instances.
|
|
176
|
+
*
|
|
177
|
+
* Accepts either:
|
|
178
|
+
* - An existing `ObjectId` instance (passed through unchanged).
|
|
179
|
+
* - A 24-character hexadecimal string (coerced to `ObjectId`).
|
|
180
|
+
*
|
|
181
|
+
* All other inputs are rejected with the message `"Invalid ObjectId"`.
|
|
182
|
+
*
|
|
183
|
+
* @returns A {@link ZodObjectId} schema.
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* ```ts
|
|
187
|
+
* const schema = objectId()
|
|
188
|
+
*
|
|
189
|
+
* schema.parse(new ObjectId()) // OK — pass-through
|
|
190
|
+
* schema.parse('64f1a2b3c4d5e6f7a8b9c0d1') // OK — coerced to ObjectId
|
|
191
|
+
* schema.parse('not-valid') // throws ZodError
|
|
192
|
+
* ```
|
|
193
|
+
*
|
|
194
|
+
* @example Inside a z.object() shape:
|
|
195
|
+
* ```ts
|
|
196
|
+
* const UserSchema = z.object({
|
|
197
|
+
* _id: objectId(),
|
|
198
|
+
* name: z.string(),
|
|
199
|
+
* })
|
|
200
|
+
* ```
|
|
201
|
+
*/
|
|
202
|
+
declare function objectId(): ZodObjectId;
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* A compound index definition declared at the collection level.
|
|
206
|
+
* Maps field paths to sort direction (1 ascending, -1 descending)
|
|
207
|
+
* with optional index-level configuration.
|
|
208
|
+
*
|
|
209
|
+
* Generic over `TKeys` so that only fields present in the collection
|
|
210
|
+
* schema are accepted — referencing a nonexistent field is a type error.
|
|
211
|
+
*/
|
|
212
|
+
type CompoundIndexDefinition<TKeys extends string = string> = {
|
|
213
|
+
fields: Partial<Record<TKeys, 1 | -1>>;
|
|
214
|
+
options?: {
|
|
215
|
+
unique?: boolean;
|
|
216
|
+
sparse?: boolean;
|
|
217
|
+
partial?: Record<string, unknown>;
|
|
218
|
+
name?: string;
|
|
219
|
+
};
|
|
220
|
+
};
|
|
221
|
+
/**
|
|
222
|
+
* A resolved field-level index extracted from schema metadata.
|
|
223
|
+
* Produced by walking the shape and calling getIndexMetadata() on each field.
|
|
224
|
+
*/
|
|
225
|
+
type FieldIndexDefinition = {
|
|
226
|
+
field: string;
|
|
227
|
+
} & IndexOptions;
|
|
228
|
+
/** Options passed to collection() as the third argument. */
|
|
229
|
+
type CollectionOptions<TKeys extends string = string> = {
|
|
230
|
+
indexes?: CompoundIndexDefinition<TKeys>[];
|
|
231
|
+
validation?: 'strict' | 'strip' | 'passthrough';
|
|
232
|
+
warnUnindexedQueries?: boolean;
|
|
233
|
+
schemaVersion?: number;
|
|
234
|
+
migrate?: (doc: Record<string, unknown>, version: number) => Record<string, unknown>;
|
|
235
|
+
writeback?: boolean;
|
|
236
|
+
};
|
|
237
|
+
/**
|
|
238
|
+
* Resolves the final shape for a collection schema.
|
|
239
|
+
*
|
|
240
|
+
* If the user-provided shape already contains `_id`, it is used as-is.
|
|
241
|
+
* Otherwise, `_id: ZodObjectId` is prepended automatically.
|
|
242
|
+
* This allows custom id types (nanoid, UUID, etc.) when needed.
|
|
243
|
+
*/
|
|
244
|
+
type ResolvedShape<TShape extends z.core.$ZodShape> = '_id' extends keyof TShape ? TShape : {
|
|
245
|
+
_id: ZodObjectId;
|
|
246
|
+
} & TShape;
|
|
247
|
+
/**
|
|
248
|
+
* The document type inferred from a collection definition.
|
|
249
|
+
* Uses the compiled schema directly, so it reflects whatever `_id`
|
|
250
|
+
* type was provided (custom or default ObjectId).
|
|
251
|
+
*
|
|
252
|
+
* Uses a structural constraint (`{ schema: z.ZodType }`) instead of
|
|
253
|
+
* `CollectionDefinition<z.core.$ZodShape>` because the conditional
|
|
254
|
+
* `ResolvedShape` type creates variance issues with index signatures.
|
|
255
|
+
*/
|
|
256
|
+
type InferDocument<TDef extends {
|
|
257
|
+
readonly schema: z.ZodType;
|
|
258
|
+
}> = z.infer<TDef['schema']>;
|
|
259
|
+
/**
|
|
260
|
+
* The immutable definition object returned by collection().
|
|
261
|
+
* Holds everything needed to later create a live collection handle.
|
|
262
|
+
*/
|
|
263
|
+
type CollectionDefinition<TShape extends z.core.$ZodShape = z.core.$ZodShape> = {
|
|
264
|
+
readonly name: string;
|
|
265
|
+
readonly schema: z.ZodObject<ResolvedShape<TShape>>;
|
|
266
|
+
readonly shape: TShape;
|
|
267
|
+
readonly fieldIndexes: FieldIndexDefinition[];
|
|
268
|
+
readonly compoundIndexes: CompoundIndexDefinition<Extract<keyof TShape, string>>[];
|
|
269
|
+
readonly options: Required<Pick<CollectionOptions, 'validation'>> & Omit<CollectionOptions, 'indexes' | 'validation'>;
|
|
270
|
+
};
|
|
271
|
+
/** Erased collection type for use in generic contexts. */
|
|
272
|
+
type AnyCollection = CollectionDefinition<z.core.$ZodShape>;
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Walk a Zod shape and extract field-level index metadata from each field.
|
|
276
|
+
*
|
|
277
|
+
* Returns an array of {@link FieldIndexDefinition} for every field that has
|
|
278
|
+
* been marked with `.index()`, `.unique()`, `.text()`, or `.expireAfter()`.
|
|
279
|
+
* Fields without index metadata are silently skipped.
|
|
280
|
+
*
|
|
281
|
+
* @param shape - A Zod shape object (the value passed to `z.object()`).
|
|
282
|
+
* @returns An array of field index definitions with the field name attached.
|
|
283
|
+
*/
|
|
284
|
+
declare function extractFieldIndexes(shape: z.core.$ZodShape): FieldIndexDefinition[];
|
|
285
|
+
/**
|
|
286
|
+
* Define a MongoDB collection with a Zod schema.
|
|
287
|
+
*
|
|
288
|
+
* Creates a {@link CollectionDefinition} that:
|
|
289
|
+
* - Adds `_id: objectId()` if the shape doesn't already include `_id`
|
|
290
|
+
* - Uses the user-provided `_id` schema if one is present (e.g. nanoid, UUID)
|
|
291
|
+
* - Extracts field-level index metadata from the shape
|
|
292
|
+
* - Separates compound indexes from the rest of the options
|
|
293
|
+
* - Returns an immutable definition object
|
|
294
|
+
*
|
|
295
|
+
* @param name - The MongoDB collection name.
|
|
296
|
+
* @param shape - A Zod shape object defining the document fields. May include a custom `_id`.
|
|
297
|
+
* @param options - Optional collection-level configuration including compound indexes.
|
|
298
|
+
* @returns A {@link CollectionDefinition} ready for use with `createClient()`.
|
|
299
|
+
*
|
|
300
|
+
* @example
|
|
301
|
+
* ```ts
|
|
302
|
+
* const Users = collection('users', {
|
|
303
|
+
* email: z.string().unique(),
|
|
304
|
+
* name: z.string().index(),
|
|
305
|
+
* age: z.number().optional(),
|
|
306
|
+
* })
|
|
307
|
+
* ```
|
|
308
|
+
*/
|
|
309
|
+
declare function collection<TShape extends z.core.$ZodShape>(name: string, shape: TShape, options?: CollectionOptions<Extract<keyof TShape, string>>): CollectionDefinition<TShape>;
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* A builder for compound index definitions.
|
|
313
|
+
*
|
|
314
|
+
* Provides a fluent API for declaring compound indexes with options like
|
|
315
|
+
* `unique`, `sparse`, and custom `name`. Each method returns a new
|
|
316
|
+
* IndexBuilder instance (immutable pattern — the original is never mutated).
|
|
317
|
+
*
|
|
318
|
+
* IndexBuilder is structurally compatible with {@link CompoundIndexDefinition}
|
|
319
|
+
* so instances can be used directly in `CollectionOptions.indexes`.
|
|
320
|
+
*
|
|
321
|
+
* Dot-notation paths like `'address.city'` are accepted at the value level
|
|
322
|
+
* (any string satisfies `TKeys`), but type-level validation against nested
|
|
323
|
+
* schema paths is deferred to a future release.
|
|
324
|
+
*
|
|
325
|
+
* @example
|
|
326
|
+
* ```ts
|
|
327
|
+
* index({ email: 1, role: -1 }).unique().name('email_role_idx')
|
|
328
|
+
* ```
|
|
329
|
+
*/
|
|
330
|
+
|
|
331
|
+
type IndexDirection = 1 | -1;
|
|
332
|
+
type CompoundIndexOptions = NonNullable<CompoundIndexDefinition['options']>;
|
|
333
|
+
declare class IndexBuilder<TKeys extends string> {
|
|
334
|
+
readonly fields: Partial<Record<TKeys, IndexDirection>>;
|
|
335
|
+
readonly options: CompoundIndexOptions;
|
|
336
|
+
constructor(fields: Record<TKeys, IndexDirection>);
|
|
337
|
+
private _clone;
|
|
338
|
+
unique(): IndexBuilder<TKeys>;
|
|
339
|
+
sparse(): IndexBuilder<TKeys>;
|
|
340
|
+
name(name: string): IndexBuilder<TKeys>;
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Create a compound index definition with a fluent builder API.
|
|
344
|
+
*
|
|
345
|
+
* Returns an {@link IndexBuilder} that is structurally compatible with
|
|
346
|
+
* `CompoundIndexDefinition`, so it can be used directly in
|
|
347
|
+
* `CollectionOptions.indexes` alongside plain objects.
|
|
348
|
+
*
|
|
349
|
+
* @param fields - An object mapping field names to sort direction (1 or -1).
|
|
350
|
+
* @returns An {@link IndexBuilder} instance.
|
|
351
|
+
*
|
|
352
|
+
* @example
|
|
353
|
+
* ```ts
|
|
354
|
+
* collection('users', { email: z.string(), role: z.string() }, {
|
|
355
|
+
* indexes: [
|
|
356
|
+
* index({ email: 1, role: -1 }).unique(),
|
|
357
|
+
* { fields: { role: 1 } },
|
|
358
|
+
* ],
|
|
359
|
+
* })
|
|
360
|
+
* ```
|
|
361
|
+
*/
|
|
362
|
+
declare function index<TKeys extends string>(fields: Record<TKeys, IndexDirection>): IndexBuilder<TKeys>;
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Create or coerce a MongoDB `ObjectId`.
|
|
366
|
+
*
|
|
367
|
+
* - Called with **no arguments**: generates a brand-new `ObjectId`.
|
|
368
|
+
* - Called with a **hex string**: coerces it to an `ObjectId` via
|
|
369
|
+
* `ObjectId.createFromHexString`.
|
|
370
|
+
* - Called with an **existing `ObjectId`**: returns it unchanged.
|
|
371
|
+
*
|
|
372
|
+
* This is a convenience wrapper that removes the need for `new ObjectId()`
|
|
373
|
+
* boilerplate throughout application code.
|
|
374
|
+
*
|
|
375
|
+
* @param value - Optional hex string or `ObjectId` to coerce. Omit to
|
|
376
|
+
* generate a new `ObjectId`.
|
|
377
|
+
* @returns An `ObjectId` instance.
|
|
378
|
+
*
|
|
379
|
+
* @example
|
|
380
|
+
* ```ts
|
|
381
|
+
* oid() // new random ObjectId
|
|
382
|
+
* oid('64f1a2b3c4d5e6f7a8b9c0d1') // coerce hex string
|
|
383
|
+
* oid(existingId) // pass-through
|
|
384
|
+
* ```
|
|
385
|
+
*/
|
|
386
|
+
declare function oid(): ObjectId;
|
|
387
|
+
declare function oid(value: string): ObjectId;
|
|
388
|
+
declare function oid(value: ObjectId): ObjectId;
|
|
389
|
+
/**
|
|
390
|
+
* Type guard that narrows an `unknown` value to `ObjectId`.
|
|
391
|
+
*
|
|
392
|
+
* Uses `instanceof` internally, so it works with any value without risk
|
|
393
|
+
* of throwing.
|
|
394
|
+
*
|
|
395
|
+
* @param value - The value to check.
|
|
396
|
+
* @returns `true` if `value` is an `ObjectId` instance.
|
|
397
|
+
*
|
|
398
|
+
* @example
|
|
399
|
+
* ```ts
|
|
400
|
+
* const raw: unknown = getFromDb()
|
|
401
|
+
* if (isOid(raw)) {
|
|
402
|
+
* console.log(raw.toHexString()) // raw is narrowed to ObjectId
|
|
403
|
+
* }
|
|
404
|
+
* ```
|
|
405
|
+
*/
|
|
406
|
+
declare function isOid(value: unknown): value is ObjectId;
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Type-level marker that carries the target collection type through the
|
|
410
|
+
* type system. Intersected with the schema return type by `.ref()` so
|
|
411
|
+
* that `RefFields<T>` (future) can extract ref relationships.
|
|
412
|
+
*
|
|
413
|
+
* This is a phantom brand — no runtime value has this property.
|
|
414
|
+
*/
|
|
415
|
+
type RefMarker<TCollection extends AnyCollection = AnyCollection> = {
|
|
416
|
+
readonly _ref: TCollection;
|
|
417
|
+
};
|
|
418
|
+
/**
|
|
419
|
+
* Metadata stored in the WeakMap sidecar for schemas marked with `.ref()`.
|
|
420
|
+
* Holds a reference to the target collection definition object.
|
|
421
|
+
*/
|
|
422
|
+
type RefMetadata = {
|
|
423
|
+
readonly collection: AnyCollection;
|
|
424
|
+
};
|
|
425
|
+
/**
|
|
426
|
+
* Module augmentation: adds `.ref()` to all `ZodType` schemas.
|
|
427
|
+
*
|
|
428
|
+
* The intersection constraint `this['_zod']['output'] extends InferDocument<TCollection>['_id']`
|
|
429
|
+
* ensures compile-time type safety: the field's output type must match the
|
|
430
|
+
* target collection's `_id` type. Mismatches produce a type error.
|
|
431
|
+
*
|
|
432
|
+
* Supports both default ObjectId `_id` and custom `_id` types (string, nanoid, etc.):
|
|
433
|
+
* - `objectId().ref(Users)` compiles when Users has ObjectId `_id`
|
|
434
|
+
* - `z.string().ref(Orgs)` compiles when Orgs has string `_id`
|
|
435
|
+
* - `z.string().ref(Users)` is a type error (string ≠ ObjectId)
|
|
436
|
+
* - `objectId().ref(Orgs)` is a type error (ObjectId ≠ string)
|
|
437
|
+
*/
|
|
438
|
+
declare module 'zod' {
|
|
439
|
+
interface ZodType {
|
|
440
|
+
/**
|
|
441
|
+
* Declare a typed foreign key reference to another collection.
|
|
442
|
+
*
|
|
443
|
+
* Stores the target collection definition in metadata for runtime
|
|
444
|
+
* populate resolution, and brands the return type with
|
|
445
|
+
* `RefMarker<TCollection>` so `RefFields<T>` can extract refs
|
|
446
|
+
* at the type level.
|
|
447
|
+
*
|
|
448
|
+
* The field's output type must match the target collection's `_id` type.
|
|
449
|
+
* Mismatched types produce a compile error.
|
|
450
|
+
*
|
|
451
|
+
* Apply `.ref()` before wrapper methods like `.optional()` or `.nullable()`:
|
|
452
|
+
* `objectId().ref(Users).optional()` — not `objectId().optional().ref(Users)`.
|
|
453
|
+
*
|
|
454
|
+
* @param collection - The target collection definition object.
|
|
455
|
+
* @returns The same schema instance, branded with the ref marker.
|
|
456
|
+
*
|
|
457
|
+
* @example
|
|
458
|
+
* ```ts
|
|
459
|
+
* const Posts = collection('posts', {
|
|
460
|
+
* authorId: objectId().ref(Users),
|
|
461
|
+
* title: z.string(),
|
|
462
|
+
* })
|
|
463
|
+
* ```
|
|
464
|
+
*/
|
|
465
|
+
ref<TCollection extends AnyCollection>(collection: TCollection & (this['_zod']['output'] extends InferDocument<TCollection>['_id'] ? unknown : never)): this & RefMarker<TCollection>;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Retrieve the ref metadata attached to a Zod schema, if any.
|
|
470
|
+
*
|
|
471
|
+
* Returns `undefined` when the schema was never marked with `.ref()`.
|
|
472
|
+
*
|
|
473
|
+
* @param schema - The Zod schema to inspect. Accepts `unknown` for
|
|
474
|
+
* convenience; non-object values safely return `undefined`.
|
|
475
|
+
* @returns The {@link RefMetadata} for the schema, or `undefined`.
|
|
476
|
+
*
|
|
477
|
+
* @example
|
|
478
|
+
* ```ts
|
|
479
|
+
* const authorId = objectId().ref(Users)
|
|
480
|
+
* const meta = getRefMetadata(authorId)
|
|
481
|
+
* // => { collection: Users }
|
|
482
|
+
* ```
|
|
483
|
+
*/
|
|
484
|
+
declare function getRefMetadata(schema: unknown): RefMetadata | undefined;
|
|
485
|
+
/**
|
|
486
|
+
* Install the `.ref()` extension method on `ZodType.prototype`.
|
|
487
|
+
*
|
|
488
|
+
* Idempotent — safe to call multiple times.
|
|
489
|
+
*/
|
|
490
|
+
declare function installRefExtension(): void;
|
|
491
|
+
|
|
492
|
+
export { type AnyCollection, type CollectionDefinition, type CollectionOptions, type CompoundIndexDefinition, type FieldIndexDefinition, IndexBuilder, type IndexMetadata, type IndexOptions, type InferDocument, type RefMarker, type RefMetadata, type ResolvedShape, type ZodObjectId, collection, extractFieldIndexes, getIndexMetadata, getRefMetadata, index, installExtensions, installRefExtension, isOid, objectId, oid };
|