@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 CHANGED
@@ -3,6 +3,10 @@ var __defProp = Object.defineProperty;
3
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
6
10
  var __copyProps = (to, from, except, desc) => {
7
11
  if (from && typeof from === "object" || typeof from === "function") {
8
12
  for (let key of __getOwnPropNames(from))
@@ -15,5 +19,256 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
15
19
 
16
20
  // src/index.ts
17
21
  var index_exports = {};
22
+ __export(index_exports, {
23
+ IndexBuilder: () => IndexBuilder,
24
+ collection: () => collection,
25
+ extractFieldIndexes: () => extractFieldIndexes,
26
+ getIndexMetadata: () => getIndexMetadata,
27
+ getRefMetadata: () => getRefMetadata,
28
+ index: () => index,
29
+ installExtensions: () => installExtensions,
30
+ installRefExtension: () => installRefExtension,
31
+ isOid: () => isOid,
32
+ objectId: () => objectId,
33
+ oid: () => oid
34
+ });
18
35
  module.exports = __toCommonJS(index_exports);
36
+
37
+ // src/collection/collection.ts
38
+ var import_zod4 = require("zod");
39
+
40
+ // src/schema/extensions.ts
41
+ var import_zod2 = require("zod");
42
+
43
+ // src/schema/ref.ts
44
+ var import_zod = require("zod");
45
+ var refMetadata = /* @__PURE__ */ new WeakMap();
46
+ function getRefMetadata(schema) {
47
+ if (typeof schema !== "object" || schema === null) return void 0;
48
+ return refMetadata.get(schema);
49
+ }
50
+ var REF_GUARD = /* @__PURE__ */ Symbol.for("zodmon_ref");
51
+ function installRefExtension() {
52
+ const proto = import_zod.z.ZodType.prototype;
53
+ if (REF_GUARD in proto) return;
54
+ Object.defineProperty(proto, "ref", {
55
+ value(collection2) {
56
+ refMetadata.set(this, { collection: collection2 });
57
+ return this;
58
+ },
59
+ enumerable: true,
60
+ configurable: true,
61
+ writable: true
62
+ });
63
+ Object.defineProperty(proto, REF_GUARD, {
64
+ value: true,
65
+ enumerable: false,
66
+ configurable: false,
67
+ writable: false
68
+ });
69
+ }
70
+
71
+ // src/schema/extensions.ts
72
+ var indexMetadata = /* @__PURE__ */ new WeakMap();
73
+ function getIndexMetadata(schema) {
74
+ if (typeof schema !== "object" || schema === null) return void 0;
75
+ return indexMetadata.get(schema);
76
+ }
77
+ var GUARD = /* @__PURE__ */ Symbol.for("zodmon_extensions");
78
+ function installExtensions() {
79
+ const proto = import_zod2.z.ZodType.prototype;
80
+ if (GUARD in proto) return;
81
+ Object.defineProperty(proto, "index", {
82
+ /**
83
+ * Declares a MongoDB index on this field. Accepts optional
84
+ * {@link IndexOptions} to configure uniqueness, sparseness, text search,
85
+ * sort direction, TTL, or partial filters.
86
+ *
87
+ * @param options - Index configuration. Omit for a standard ascending index.
88
+ * @returns The same schema instance for chainability.
89
+ *
90
+ * @example
91
+ * ```ts
92
+ * const name = z.string().index()
93
+ * const email = z.string().index({ unique: true, sparse: true })
94
+ * ```
95
+ */
96
+ value(options) {
97
+ indexMetadata.set(this, { indexed: true, ...options });
98
+ return this;
99
+ },
100
+ enumerable: true,
101
+ configurable: true,
102
+ writable: true
103
+ });
104
+ Object.defineProperty(proto, "unique", {
105
+ /**
106
+ * Shorthand for `.index({ unique: true })`. Marks this field as requiring
107
+ * a unique index in MongoDB, preventing duplicate values.
108
+ *
109
+ * @returns The same schema instance for chainability.
110
+ *
111
+ * @example
112
+ * ```ts
113
+ * const email = z.string().unique()
114
+ * ```
115
+ */
116
+ value() {
117
+ indexMetadata.set(this, { indexed: true, unique: true });
118
+ return this;
119
+ },
120
+ enumerable: true,
121
+ configurable: true,
122
+ writable: true
123
+ });
124
+ Object.defineProperty(proto, "text", {
125
+ /**
126
+ * Shorthand for `.index({ text: true })`. Creates a MongoDB text index on
127
+ * this field, enabling full-text search queries with `$text`.
128
+ *
129
+ * @returns The same schema instance for chainability.
130
+ *
131
+ * @example
132
+ * ```ts
133
+ * const bio = z.string().text()
134
+ * ```
135
+ */
136
+ value() {
137
+ indexMetadata.set(this, { indexed: true, text: true });
138
+ return this;
139
+ },
140
+ enumerable: true,
141
+ configurable: true,
142
+ writable: true
143
+ });
144
+ Object.defineProperty(proto, "expireAfter", {
145
+ /**
146
+ * Shorthand for `.index({ expireAfter: seconds })`. Creates a TTL index on
147
+ * a `Date` field. MongoDB will automatically remove documents once the field
148
+ * value is older than the specified number of seconds.
149
+ *
150
+ * @param seconds - TTL in seconds after which documents expire.
151
+ * @returns The same schema instance for chainability.
152
+ *
153
+ * @example
154
+ * ```ts
155
+ * const expiresAt = z.date().expireAfter(86400) // 24 hours
156
+ * ```
157
+ */
158
+ value(seconds) {
159
+ indexMetadata.set(this, { indexed: true, expireAfter: seconds });
160
+ return this;
161
+ },
162
+ enumerable: true,
163
+ configurable: true,
164
+ writable: true
165
+ });
166
+ installRefExtension();
167
+ Object.defineProperty(proto, GUARD, {
168
+ value: true,
169
+ enumerable: false,
170
+ configurable: false,
171
+ writable: false
172
+ });
173
+ }
174
+ installExtensions();
175
+
176
+ // src/schema/object-id.ts
177
+ var import_mongodb = require("mongodb");
178
+ var import_zod3 = require("zod");
179
+ var OBJECT_ID_HEX = /^[a-f\d]{24}$/i;
180
+ function objectId() {
181
+ return import_zod3.z.custom((val) => {
182
+ if (val instanceof import_mongodb.ObjectId) return true;
183
+ return typeof val === "string" && OBJECT_ID_HEX.test(val);
184
+ }, "Invalid ObjectId").transform((val) => val instanceof import_mongodb.ObjectId ? val : import_mongodb.ObjectId.createFromHexString(val));
185
+ }
186
+
187
+ // src/collection/collection.ts
188
+ function extractFieldIndexes(shape) {
189
+ const result = [];
190
+ for (const [field, schema] of Object.entries(shape)) {
191
+ const meta = getIndexMetadata(schema);
192
+ if (meta) {
193
+ result.push({ field, ...meta });
194
+ }
195
+ }
196
+ return result;
197
+ }
198
+ function collection(name, shape, options) {
199
+ const resolvedShape = "_id" in shape ? shape : { _id: objectId(), ...shape };
200
+ const schema = import_zod4.z.object(resolvedShape);
201
+ const fieldIndexes = extractFieldIndexes(shape);
202
+ const { indexes: compoundIndexes, validation, ...rest } = options ?? {};
203
+ return {
204
+ name,
205
+ // Zod v4's z.object() returns ZodObject<{ -readonly [P in keyof T]: T[P] }> which
206
+ // strips readonly modifiers. With exactOptionalPropertyTypes this mapped type is
207
+ // not assignable to ZodObject<ResolvedShape<TShape>>. The cast is safe because
208
+ // the runtime shape is correct — only the readonly modifier differs.
209
+ schema,
210
+ shape,
211
+ fieldIndexes,
212
+ compoundIndexes: compoundIndexes ?? [],
213
+ options: {
214
+ validation: validation ?? "strict",
215
+ ...rest
216
+ }
217
+ };
218
+ }
219
+
220
+ // src/collection/index-def.ts
221
+ var IndexBuilder = class _IndexBuilder {
222
+ // Typed as Partial for structural compatibility with CompoundIndexDefinition.
223
+ // The constructor guarantees all keys are present at runtime.
224
+ fields;
225
+ options;
226
+ constructor(fields) {
227
+ this.fields = fields;
228
+ this.options = {};
229
+ }
230
+ _clone(options) {
231
+ return Object.assign(Object.create(_IndexBuilder.prototype), {
232
+ fields: this.fields,
233
+ options
234
+ });
235
+ }
236
+ unique() {
237
+ return this._clone({ ...this.options, unique: true });
238
+ }
239
+ sparse() {
240
+ return this._clone({ ...this.options, sparse: true });
241
+ }
242
+ name(name) {
243
+ return this._clone({ ...this.options, name });
244
+ }
245
+ };
246
+ function index(fields) {
247
+ return new IndexBuilder(fields);
248
+ }
249
+
250
+ // src/helpers/oid.ts
251
+ var import_mongodb2 = require("mongodb");
252
+ function oid(value) {
253
+ if (value === void 0) return new import_mongodb2.ObjectId();
254
+ if (value instanceof import_mongodb2.ObjectId) return value;
255
+ return import_mongodb2.ObjectId.createFromHexString(value);
256
+ }
257
+ function isOid(value) {
258
+ return value instanceof import_mongodb2.ObjectId;
259
+ }
260
+ // Annotate the CommonJS export names for ESM import in node:
261
+ 0 && (module.exports = {
262
+ IndexBuilder,
263
+ collection,
264
+ extractFieldIndexes,
265
+ getIndexMetadata,
266
+ getRefMetadata,
267
+ index,
268
+ installExtensions,
269
+ installRefExtension,
270
+ isOid,
271
+ objectId,
272
+ oid
273
+ });
19
274
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { } // placeholder — will re-export public API\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/collection/collection.ts","../src/schema/extensions.ts","../src/schema/ref.ts","../src/schema/object-id.ts","../src/collection/index-def.ts","../src/helpers/oid.ts"],"sourcesContent":["export type {\n\tAnyCollection,\n\tCollectionDefinition,\n\tCollectionOptions,\n\tCompoundIndexDefinition,\n\tFieldIndexDefinition,\n\tInferDocument,\n\tResolvedShape,\n} from './collection'\nexport { collection, extractFieldIndexes, IndexBuilder, index } from './collection'\nexport { isOid, oid } from './helpers/oid'\nexport {\n\tgetIndexMetadata,\n\tgetRefMetadata,\n\ttype IndexMetadata,\n\ttype IndexOptions,\n\tinstallExtensions,\n\tinstallRefExtension,\n\tobjectId,\n\ttype RefMarker,\n\ttype RefMetadata,\n\ttype ZodObjectId,\n} from './schema'\n","import { z } from 'zod'\nimport { getIndexMetadata } from '../schema/extensions'\nimport { objectId } from '../schema/object-id'\nimport type {\n\tCollectionDefinition,\n\tCollectionOptions,\n\tFieldIndexDefinition,\n\tResolvedShape,\n} from './types'\n\n/**\n * Walk a Zod shape and extract field-level index metadata from each field.\n *\n * Returns an array of {@link FieldIndexDefinition} for every field that has\n * been marked with `.index()`, `.unique()`, `.text()`, or `.expireAfter()`.\n * Fields without index metadata are silently skipped.\n *\n * @param shape - A Zod shape object (the value passed to `z.object()`).\n * @returns An array of field index definitions with the field name attached.\n */\nexport function extractFieldIndexes(shape: z.core.$ZodShape): FieldIndexDefinition[] {\n\tconst result: FieldIndexDefinition[] = []\n\tfor (const [field, schema] of Object.entries(shape)) {\n\t\tconst meta = getIndexMetadata(schema)\n\t\tif (meta) {\n\t\t\tresult.push({ field, ...meta })\n\t\t}\n\t}\n\treturn result\n}\n\n/**\n * Define a MongoDB collection with a Zod schema.\n *\n * Creates a {@link CollectionDefinition} that:\n * - Adds `_id: objectId()` if the shape doesn't already include `_id`\n * - Uses the user-provided `_id` schema if one is present (e.g. nanoid, UUID)\n * - Extracts field-level index metadata from the shape\n * - Separates compound indexes from the rest of the options\n * - Returns an immutable definition object\n *\n * @param name - The MongoDB collection name.\n * @param shape - A Zod shape object defining the document fields. May include a custom `_id`.\n * @param options - Optional collection-level configuration including compound indexes.\n * @returns A {@link CollectionDefinition} ready for use with `createClient()`.\n *\n * @example\n * ```ts\n * const Users = collection('users', {\n * email: z.string().unique(),\n * name: z.string().index(),\n * age: z.number().optional(),\n * })\n * ```\n */\nexport function collection<TShape extends z.core.$ZodShape>(\n\tname: string,\n\tshape: TShape,\n\toptions?: CollectionOptions<Extract<keyof TShape, string>>,\n): CollectionDefinition<TShape> {\n\t// TypeScript cannot narrow generic conditional types through control flow,\n\t// so the assertion is needed here. Both branches are provably correct:\n\t// - when _id is in shape: ResolvedShape<TShape> = TShape\n\t// - when _id is absent: ResolvedShape<TShape> = { _id: ZodObjectId } & TShape\n\tconst resolvedShape = (\n\t\t'_id' in shape ? shape : { _id: objectId(), ...shape }\n\t) as ResolvedShape<TShape>\n\tconst schema = z.object(resolvedShape)\n\n\tconst fieldIndexes = extractFieldIndexes(shape)\n\n\tconst { indexes: compoundIndexes, validation, ...rest } = options ?? {}\n\n\treturn {\n\t\tname,\n\t\t// Zod v4's z.object() returns ZodObject<{ -readonly [P in keyof T]: T[P] }> which\n\t\t// strips readonly modifiers. With exactOptionalPropertyTypes this mapped type is\n\t\t// not assignable to ZodObject<ResolvedShape<TShape>>. The cast is safe because\n\t\t// the runtime shape is correct — only the readonly modifier differs.\n\t\tschema: schema as CollectionDefinition<TShape>['schema'],\n\t\tshape,\n\t\tfieldIndexes,\n\t\tcompoundIndexes: compoundIndexes ?? [],\n\t\toptions: {\n\t\t\tvalidation: validation ?? 'strict',\n\t\t\t...rest,\n\t\t},\n\t}\n}\n","import { z } from 'zod'\nimport { installRefExtension } from './ref'\n\n/**\n * Options controlling how a field-level MongoDB index is created.\n *\n * Passed to the `.index()` Zod extension method. Every property is optional;\n * omitting all of them creates a standard ascending, non-unique index.\n */\nexport type IndexOptions = {\n\t/** When `true`, MongoDB enforces a unique constraint on this field. */\n\tunique?: boolean\n\t/**\n\t * When `true`, the index skips documents where the field is `null` or missing.\n\t * Useful for optional fields that should be indexed only when present.\n\t */\n\tsparse?: boolean\n\t/** When `true`, creates a MongoDB text index for full-text search on this field. */\n\ttext?: boolean\n\t/**\n\t * When `true`, the index is created in descending order (`-1`).\n\t * Defaults to ascending (`1`) when omitted.\n\t */\n\tdescending?: boolean\n\t/**\n\t * TTL in seconds. MongoDB will automatically delete documents once the\n\t * indexed `Date` field is older than this many seconds. Only valid on\n\t * fields whose runtime type is `Date`.\n\t */\n\texpireAfter?: number\n\t/**\n\t * A partial filter expression. Only documents matching this filter are\n\t * included in the index. Maps directly to MongoDB's `partialFilterExpression`.\n\t */\n\tpartial?: Record<string, unknown>\n}\n\n/**\n * Metadata stored in the WeakMap sidecar for every schema that has been\n * marked with `.index()`. Always contains `indexed: true` plus any\n * {@link IndexOptions} the caller provided.\n */\nexport type IndexMetadata = {\n\t/** Always `true` — acts as a discriminator for \"this field is indexed\". */\n\tindexed: true\n} & IndexOptions\n\ndeclare module 'zod' {\n\tinterface ZodType {\n\t\t/**\n\t\t * Mark this field for indexing when `syncIndexes()` is called.\n\t\t *\n\t\t * Stores {@link IndexOptions} in a WeakMap sidecar so the collection\n\t\t * factory can later introspect each field and build the appropriate\n\t\t * MongoDB index specification.\n\t\t *\n\t\t * @param options - Optional index configuration (unique, sparse, etc.).\n\t\t * @returns The same schema instance for chaining.\n\t\t *\n\t\t * @example\n\t\t * ```ts\n\t\t * const UserSchema = z.object({\n\t\t * email: z.string().index({ unique: true }),\n\t\t * age: z.number().index({ sparse: true }),\n\t\t * })\n\t\t * ```\n\t\t */\n\t\tindex(options?: IndexOptions): this\n\n\t\t/**\n\t\t * Shorthand for `.index({ unique: true })`.\n\t\t *\n\t\t * Creates a unique index on this field, causing MongoDB to reject\n\t\t * duplicate values.\n\t\t *\n\t\t * @returns The same schema instance for chaining.\n\t\t *\n\t\t * @example\n\t\t * ```ts\n\t\t * const UserSchema = z.object({\n\t\t * email: z.string().unique(),\n\t\t * })\n\t\t * ```\n\t\t */\n\t\tunique(): this\n\n\t\t/**\n\t\t * Shorthand for `.index({ text: true })`.\n\t\t *\n\t\t * Creates a MongoDB text index on this field, enabling `$text` queries\n\t\t * for full-text search.\n\t\t *\n\t\t * @returns The same schema instance for chaining.\n\t\t *\n\t\t * @example\n\t\t * ```ts\n\t\t * const PostSchema = z.object({\n\t\t * body: z.string().text(),\n\t\t * })\n\t\t * ```\n\t\t */\n\t\ttext(): this\n\n\t\t/**\n\t\t * Shorthand for `.index({ expireAfter: seconds })`.\n\t\t *\n\t\t * Creates a TTL (Time-To-Live) index. MongoDB will automatically\n\t\t * remove documents once the indexed `Date` field is older than\n\t\t * the specified number of seconds.\n\t\t *\n\t\t * @param seconds - Number of seconds after which documents expire.\n\t\t * @returns The same schema instance for chaining.\n\t\t *\n\t\t * @example\n\t\t * ```ts\n\t\t * const SessionSchema = z.object({\n\t\t * createdAt: z.date().expireAfter(3600), // 1 hour TTL\n\t\t * })\n\t\t * ```\n\t\t */\n\t\texpireAfter(seconds: number): this\n\t}\n}\n\n/**\n * WeakMap sidecar that associates a Zod schema instance with its\n * {@link IndexMetadata}.\n *\n * A WeakMap is used so that index metadata does not prevent garbage collection\n * of schema instances. The keys are the Zod schema objects themselves, and\n * the values are the corresponding `IndexMetadata` descriptors.\n */\nconst indexMetadata = new WeakMap<object, IndexMetadata>()\n\n/**\n * Retrieve the index metadata attached to a Zod schema, if any.\n *\n * Returns `undefined` when the schema was never marked with an index\n * extension (`.index()`, `.unique()`, `.text()`, or `.expireAfter()`).\n *\n * @param schema - The Zod schema to inspect. Accepts `unknown` for\n * convenience; non-object values safely return `undefined`.\n * @returns The {@link IndexMetadata} for the schema, or `undefined`.\n *\n * @example\n * ```ts\n * const email = z.string().index({ unique: true })\n * const meta = getIndexMetadata(email)\n * // => { indexed: true, unique: true }\n * ```\n */\nexport function getIndexMetadata(schema: unknown): IndexMetadata | undefined {\n\tif (typeof schema !== 'object' || schema === null) return undefined\n\treturn indexMetadata.get(schema)\n}\n\n/**\n * Symbol used as a guard property on `ZodType.prototype` to prevent\n * double-registration of Zodmon extension methods. The symbol is created\n * with `Symbol.for` so it is shared across realms / duplicate module loads.\n */\nconst GUARD = Symbol.for('zodmon_extensions')\n\n/**\n * Monkey-patch Zod's `ZodType.prototype` with Zodmon extension methods\n * (`.index()`, `.unique()`, `.text()`, `.expireAfter()`).\n *\n * In Zod v4, methods are copied from `ZodType.prototype` to each instance\n * during construction via the internal `init` loop (`Object.keys(proto)` ->\n * copy to instance). Extension methods use `enumerable: true` so they are\n * picked up by this loop for every schema created after installation.\n *\n * The function is idempotent: calling it more than once is a safe no-op,\n * guarded by a non-enumerable `Symbol.for('zodmon_extensions')` property\n * on the prototype.\n *\n * This function is called at module level when `extensions.ts` is first\n * imported, so consumers never need to call it manually. It is exported\n * primarily for use in tests.\n *\n * @example\n * ```ts\n * import { installExtensions } from '@zodmon/core/schema/extensions'\n * installExtensions() // safe to call multiple times\n *\n * const indexed = z.string().index({ unique: true })\n * ```\n */\nexport function installExtensions(): void {\n\tconst proto = z.ZodType.prototype\n\tif (GUARD in proto) return\n\n\tObject.defineProperty(proto, 'index', {\n\t\t/**\n\t\t * Declares a MongoDB index on this field. Accepts optional\n\t\t * {@link IndexOptions} to configure uniqueness, sparseness, text search,\n\t\t * sort direction, TTL, or partial filters.\n\t\t *\n\t\t * @param options - Index configuration. Omit for a standard ascending index.\n\t\t * @returns The same schema instance for chainability.\n\t\t *\n\t\t * @example\n\t\t * ```ts\n\t\t * const name = z.string().index()\n\t\t * const email = z.string().index({ unique: true, sparse: true })\n\t\t * ```\n\t\t */\n\t\tvalue(this: typeof proto, options?: IndexOptions): typeof proto {\n\t\t\tindexMetadata.set(this, { indexed: true, ...options })\n\t\t\treturn this\n\t\t},\n\t\tenumerable: true,\n\t\tconfigurable: true,\n\t\twritable: true,\n\t})\n\n\tObject.defineProperty(proto, 'unique', {\n\t\t/**\n\t\t * Shorthand for `.index({ unique: true })`. Marks this field as requiring\n\t\t * a unique index in MongoDB, preventing duplicate values.\n\t\t *\n\t\t * @returns The same schema instance for chainability.\n\t\t *\n\t\t * @example\n\t\t * ```ts\n\t\t * const email = z.string().unique()\n\t\t * ```\n\t\t */\n\t\tvalue(this: typeof proto): typeof proto {\n\t\t\tindexMetadata.set(this, { indexed: true, unique: true })\n\t\t\treturn this\n\t\t},\n\t\tenumerable: true,\n\t\tconfigurable: true,\n\t\twritable: true,\n\t})\n\n\tObject.defineProperty(proto, 'text', {\n\t\t/**\n\t\t * Shorthand for `.index({ text: true })`. Creates a MongoDB text index on\n\t\t * this field, enabling full-text search queries with `$text`.\n\t\t *\n\t\t * @returns The same schema instance for chainability.\n\t\t *\n\t\t * @example\n\t\t * ```ts\n\t\t * const bio = z.string().text()\n\t\t * ```\n\t\t */\n\t\tvalue(this: typeof proto): typeof proto {\n\t\t\tindexMetadata.set(this, { indexed: true, text: true })\n\t\t\treturn this\n\t\t},\n\t\tenumerable: true,\n\t\tconfigurable: true,\n\t\twritable: true,\n\t})\n\n\tObject.defineProperty(proto, 'expireAfter', {\n\t\t/**\n\t\t * Shorthand for `.index({ expireAfter: seconds })`. Creates a TTL index on\n\t\t * a `Date` field. MongoDB will automatically remove documents once the field\n\t\t * value is older than the specified number of seconds.\n\t\t *\n\t\t * @param seconds - TTL in seconds after which documents expire.\n\t\t * @returns The same schema instance for chainability.\n\t\t *\n\t\t * @example\n\t\t * ```ts\n\t\t * const expiresAt = z.date().expireAfter(86400) // 24 hours\n\t\t * ```\n\t\t */\n\t\tvalue(this: typeof proto, seconds: number): typeof proto {\n\t\t\tindexMetadata.set(this, { indexed: true, expireAfter: seconds })\n\t\t\treturn this\n\t\t},\n\t\tenumerable: true,\n\t\tconfigurable: true,\n\t\twritable: true,\n\t})\n\n\tinstallRefExtension()\n\n\tObject.defineProperty(proto, GUARD, {\n\t\tvalue: true,\n\t\tenumerable: false,\n\t\tconfigurable: false,\n\t\twritable: false,\n\t})\n}\n\ninstallExtensions()\n","import { z } from 'zod'\nimport type { AnyCollection, InferDocument } from '../collection/types'\n\n/**\n * Type-level marker that carries the target collection type through the\n * type system. Intersected with the schema return type by `.ref()` so\n * that `RefFields<T>` (future) can extract ref relationships.\n *\n * This is a phantom brand — no runtime value has this property.\n */\nexport type RefMarker<TCollection extends AnyCollection = AnyCollection> = {\n\treadonly _ref: TCollection\n}\n\n/**\n * Metadata stored in the WeakMap sidecar for schemas marked with `.ref()`.\n * Holds a reference to the target collection definition object.\n */\nexport type RefMetadata = {\n\treadonly collection: AnyCollection\n}\n\n/**\n * Module augmentation: adds `.ref()` to all `ZodType` schemas.\n *\n * The intersection constraint `this['_zod']['output'] extends InferDocument<TCollection>['_id']`\n * ensures compile-time type safety: the field's output type must match the\n * target collection's `_id` type. Mismatches produce a type error.\n *\n * Supports both default ObjectId `_id` and custom `_id` types (string, nanoid, etc.):\n * - `objectId().ref(Users)` compiles when Users has ObjectId `_id`\n * - `z.string().ref(Orgs)` compiles when Orgs has string `_id`\n * - `z.string().ref(Users)` is a type error (string ≠ ObjectId)\n * - `objectId().ref(Orgs)` is a type error (ObjectId ≠ string)\n */\ndeclare module 'zod' {\n\tinterface ZodType {\n\t\t/**\n\t\t * Declare a typed foreign key reference to another collection.\n\t\t *\n\t\t * Stores the target collection definition in metadata for runtime\n\t\t * populate resolution, and brands the return type with\n\t\t * `RefMarker<TCollection>` so `RefFields<T>` can extract refs\n\t\t * at the type level.\n\t\t *\n\t\t * The field's output type must match the target collection's `_id` type.\n\t\t * Mismatched types produce a compile error.\n\t\t *\n\t\t * Apply `.ref()` before wrapper methods like `.optional()` or `.nullable()`:\n\t\t * `objectId().ref(Users).optional()` — not `objectId().optional().ref(Users)`.\n\t\t *\n\t\t * @param collection - The target collection definition object.\n\t\t * @returns The same schema instance, branded with the ref marker.\n\t\t *\n\t\t * @example\n\t\t * ```ts\n\t\t * const Posts = collection('posts', {\n\t\t * authorId: objectId().ref(Users),\n\t\t * title: z.string(),\n\t\t * })\n\t\t * ```\n\t\t */\n\t\tref<TCollection extends AnyCollection>(\n\t\t\tcollection: TCollection &\n\t\t\t\t(this['_zod']['output'] extends InferDocument<TCollection>['_id'] ? unknown : never),\n\t\t): this & RefMarker<TCollection>\n\t}\n}\n\n/**\n * WeakMap sidecar that associates a Zod schema instance with its\n * {@link RefMetadata}. Uses WeakMap so ref metadata does not prevent\n * garbage collection of schema instances.\n */\nconst refMetadata = new WeakMap<object, RefMetadata>()\n\n/**\n * Retrieve the ref metadata attached to a Zod schema, if any.\n *\n * Returns `undefined` when the schema was never marked with `.ref()`.\n *\n * @param schema - The Zod schema to inspect. Accepts `unknown` for\n * convenience; non-object values safely return `undefined`.\n * @returns The {@link RefMetadata} for the schema, or `undefined`.\n *\n * @example\n * ```ts\n * const authorId = objectId().ref(Users)\n * const meta = getRefMetadata(authorId)\n * // => { collection: Users }\n * ```\n */\nexport function getRefMetadata(schema: unknown): RefMetadata | undefined {\n\tif (typeof schema !== 'object' || schema === null) return undefined\n\treturn refMetadata.get(schema)\n}\n\n/**\n * Symbol guard to prevent double-registration of the `.ref()` extension.\n * Uses `Symbol.for` so it is shared across realms / duplicate module loads.\n */\nconst REF_GUARD = Symbol.for('zodmon_ref')\n\n/**\n * Install the `.ref()` extension method on `ZodType.prototype`.\n *\n * Idempotent — safe to call multiple times.\n */\nexport function installRefExtension(): void {\n\tconst proto = z.ZodType.prototype\n\tif (REF_GUARD in proto) return\n\n\tObject.defineProperty(proto, 'ref', {\n\t\tvalue(this: typeof proto, collection: AnyCollection): typeof proto {\n\t\t\trefMetadata.set(this, { collection })\n\t\t\treturn this\n\t\t},\n\t\tenumerable: true,\n\t\tconfigurable: true,\n\t\twritable: true,\n\t})\n\n\tObject.defineProperty(proto, REF_GUARD, {\n\t\tvalue: true,\n\t\tenumerable: false,\n\t\tconfigurable: false,\n\t\twritable: false,\n\t})\n}\n","import { ObjectId } from 'mongodb'\nimport { type ZodCustom, type ZodPipe, type ZodTransform, z } from 'zod'\n\n/** Matches a 24-character hexadecimal string (case-insensitive). */\nconst OBJECT_ID_HEX = /^[a-f\\d]{24}$/i\n\n/**\n * The Zod type produced by {@link objectId}. A pipeline that validates an\n * input as either a `string` (24-char hex) or an `ObjectId` instance, then\n * transforms it into a concrete `ObjectId`.\n *\n * Use `z.infer<ZodObjectId>` to extract the output type (`ObjectId`) and\n * `z.input<ZodObjectId>` for the input type (`string | ObjectId`).\n */\nexport type ZodObjectId = ZodPipe<\n\tZodCustom<string | ObjectId, string | ObjectId>,\n\tZodTransform<ObjectId, string | ObjectId>\n>\n\n/**\n * Create a Zod schema that validates and coerces values into MongoDB\n * `ObjectId` instances.\n *\n * Accepts either:\n * - An existing `ObjectId` instance (passed through unchanged).\n * - A 24-character hexadecimal string (coerced to `ObjectId`).\n *\n * All other inputs are rejected with the message `\"Invalid ObjectId\"`.\n *\n * @returns A {@link ZodObjectId} schema.\n *\n * @example\n * ```ts\n * const schema = objectId()\n *\n * schema.parse(new ObjectId()) // OK — pass-through\n * schema.parse('64f1a2b3c4d5e6f7a8b9c0d1') // OK — coerced to ObjectId\n * schema.parse('not-valid') // throws ZodError\n * ```\n *\n * @example Inside a z.object() shape:\n * ```ts\n * const UserSchema = z.object({\n * _id: objectId(),\n * name: z.string(),\n * })\n * ```\n */\nexport function objectId(): ZodObjectId {\n\treturn z\n\t\t.custom<string | ObjectId>((val): val is string | ObjectId => {\n\t\t\tif (val instanceof ObjectId) return true\n\t\t\treturn typeof val === 'string' && OBJECT_ID_HEX.test(val)\n\t\t}, 'Invalid ObjectId')\n\t\t.transform((val) => (val instanceof ObjectId ? val : ObjectId.createFromHexString(val)))\n}\n","/**\n * A builder for compound index definitions.\n *\n * Provides a fluent API for declaring compound indexes with options like\n * `unique`, `sparse`, and custom `name`. Each method returns a new\n * IndexBuilder instance (immutable pattern — the original is never mutated).\n *\n * IndexBuilder is structurally compatible with {@link CompoundIndexDefinition}\n * so instances can be used directly in `CollectionOptions.indexes`.\n *\n * Dot-notation paths like `'address.city'` are accepted at the value level\n * (any string satisfies `TKeys`), but type-level validation against nested\n * schema paths is deferred to a future release.\n *\n * @example\n * ```ts\n * index({ email: 1, role: -1 }).unique().name('email_role_idx')\n * ```\n */\n\nimport type { CompoundIndexDefinition } from './types'\n\ntype IndexDirection = 1 | -1\n\ntype CompoundIndexOptions = NonNullable<CompoundIndexDefinition['options']>\n\nexport class IndexBuilder<TKeys extends string> {\n\t// Typed as Partial for structural compatibility with CompoundIndexDefinition.\n\t// The constructor guarantees all keys are present at runtime.\n\treadonly fields: Partial<Record<TKeys, IndexDirection>>\n\treadonly options: CompoundIndexOptions\n\n\tconstructor(fields: Record<TKeys, IndexDirection>) {\n\t\tthis.fields = fields\n\t\tthis.options = {}\n\t}\n\n\tprivate _clone(options: CompoundIndexOptions): IndexBuilder<TKeys> {\n\t\t// Object.create returns `any`; cast is safe because we assign the correct shape\n\t\treturn Object.assign(Object.create(IndexBuilder.prototype) as IndexBuilder<TKeys>, {\n\t\t\tfields: this.fields,\n\t\t\toptions,\n\t\t})\n\t}\n\n\tunique(): IndexBuilder<TKeys> {\n\t\treturn this._clone({ ...this.options, unique: true })\n\t}\n\n\tsparse(): IndexBuilder<TKeys> {\n\t\treturn this._clone({ ...this.options, sparse: true })\n\t}\n\n\tname(name: string): IndexBuilder<TKeys> {\n\t\treturn this._clone({ ...this.options, name })\n\t}\n}\n\n/**\n * Create a compound index definition with a fluent builder API.\n *\n * Returns an {@link IndexBuilder} that is structurally compatible with\n * `CompoundIndexDefinition`, so it can be used directly in\n * `CollectionOptions.indexes` alongside plain objects.\n *\n * @param fields - An object mapping field names to sort direction (1 or -1).\n * @returns An {@link IndexBuilder} instance.\n *\n * @example\n * ```ts\n * collection('users', { email: z.string(), role: z.string() }, {\n * indexes: [\n * index({ email: 1, role: -1 }).unique(),\n * { fields: { role: 1 } },\n * ],\n * })\n * ```\n */\nexport function index<TKeys extends string>(\n\tfields: Record<TKeys, IndexDirection>,\n): IndexBuilder<TKeys> {\n\treturn new IndexBuilder(fields)\n}\n","import { ObjectId } from 'mongodb'\n\n/**\n * Create or coerce a MongoDB `ObjectId`.\n *\n * - Called with **no arguments**: generates a brand-new `ObjectId`.\n * - Called with a **hex string**: coerces it to an `ObjectId` via\n * `ObjectId.createFromHexString`.\n * - Called with an **existing `ObjectId`**: returns it unchanged.\n *\n * This is a convenience wrapper that removes the need for `new ObjectId()`\n * boilerplate throughout application code.\n *\n * @param value - Optional hex string or `ObjectId` to coerce. Omit to\n * generate a new `ObjectId`.\n * @returns An `ObjectId` instance.\n *\n * @example\n * ```ts\n * oid() // new random ObjectId\n * oid('64f1a2b3c4d5e6f7a8b9c0d1') // coerce hex string\n * oid(existingId) // pass-through\n * ```\n */\nexport function oid(): ObjectId\nexport function oid(value: string): ObjectId\nexport function oid(value: ObjectId): ObjectId\nexport function oid(value?: string | ObjectId): ObjectId {\n\tif (value === undefined) return new ObjectId()\n\tif (value instanceof ObjectId) return value\n\treturn ObjectId.createFromHexString(value)\n}\n\n/**\n * Type guard that narrows an `unknown` value to `ObjectId`.\n *\n * Uses `instanceof` internally, so it works with any value without risk\n * of throwing.\n *\n * @param value - The value to check.\n * @returns `true` if `value` is an `ObjectId` instance.\n *\n * @example\n * ```ts\n * const raw: unknown = getFromDb()\n * if (isOid(raw)) {\n * console.log(raw.toHexString()) // raw is narrowed to ObjectId\n * }\n * ```\n */\nexport function isOid(value: unknown): value is ObjectId {\n\treturn value instanceof ObjectId\n}\n"],"mappings":"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","names":["import_zod","import_zod","collection","import_zod","import_mongodb"]}