pocketbase-zod-schema 0.1.4 → 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.
Files changed (43) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +233 -98
  3. package/dist/cli/index.cjs +43 -6
  4. package/dist/cli/index.cjs.map +1 -1
  5. package/dist/cli/index.js +43 -6
  6. package/dist/cli/index.js.map +1 -1
  7. package/dist/cli/migrate.cjs +43 -6
  8. package/dist/cli/migrate.cjs.map +1 -1
  9. package/dist/cli/migrate.js +43 -6
  10. package/dist/cli/migrate.js.map +1 -1
  11. package/dist/index.cjs +84 -22
  12. package/dist/index.cjs.map +1 -1
  13. package/dist/index.d.cts +2 -2
  14. package/dist/index.d.ts +2 -2
  15. package/dist/index.js +79 -21
  16. package/dist/index.js.map +1 -1
  17. package/dist/migration/analyzer.cjs +44 -6
  18. package/dist/migration/analyzer.cjs.map +1 -1
  19. package/dist/migration/analyzer.d.cts +11 -1
  20. package/dist/migration/analyzer.d.ts +11 -1
  21. package/dist/migration/analyzer.js +44 -7
  22. package/dist/migration/analyzer.js.map +1 -1
  23. package/dist/migration/index.cjs +43 -6
  24. package/dist/migration/index.cjs.map +1 -1
  25. package/dist/migration/index.js +43 -6
  26. package/dist/migration/index.js.map +1 -1
  27. package/dist/mutator.cjs +20 -21
  28. package/dist/mutator.cjs.map +1 -1
  29. package/dist/mutator.d.cts +2 -2
  30. package/dist/mutator.d.ts +2 -2
  31. package/dist/mutator.js +20 -21
  32. package/dist/mutator.js.map +1 -1
  33. package/dist/schema.cjs +41 -16
  34. package/dist/schema.cjs.map +1 -1
  35. package/dist/schema.d.cts +98 -8
  36. package/dist/schema.d.ts +98 -8
  37. package/dist/schema.js +36 -15
  38. package/dist/schema.js.map +1 -1
  39. package/dist/types.d.cts +1 -1
  40. package/dist/types.d.ts +1 -1
  41. package/dist/{user-_AM523hb.d.cts → user-DTJQIj4K.d.cts} +31 -5
  42. package/dist/{user-_AM523hb.d.ts → user-DTJQIj4K.d.ts} +31 -5
  43. package/package.json +2 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.2.0](https://github.com/dastron/pocketbase-zod-schema/compare/pocketbase-zod-schema-v0.1.4...pocketbase-zod-schema-v0.2.0) (2025-12-20)
4
+
5
+
6
+ ### Features
7
+
8
+ * Add `defineCollection` to wrap schema definition ([8dbcbfa](https://github.com/dastron/pocketbase-zod-schema/commit/8dbcbfae1833509578a63e942847349cceea6cf3))
9
+
3
10
  ## [0.1.4](https://github.com/dastron/pocketbase-zod-schema/compare/pocketbase-zod-schema-v0.1.3...pocketbase-zod-schema-v0.1.4) (2025-12-20)
4
11
 
5
12
 
package/README.md CHANGED
@@ -30,31 +30,36 @@ Create a schema file in your project (e.g., `src/schema/post.ts`):
30
30
  ```typescript
31
31
  import { z } from "zod";
32
32
  import {
33
- relationField,
34
- relationsField,
35
- withPermissions,
33
+ defineCollection,
34
+ RelationField,
35
+ RelationsField,
36
36
  } from "pocketbase-zod-schema/schema";
37
37
 
38
- export const PostSchema = withPermissions(
39
- z.object({
40
- title: z.string().min(1).max(200),
41
- content: z.string(),
42
- published: z.boolean().default(false),
43
-
44
- // Single relation to users collection
45
- author: relationField({ collection: "users" }),
46
-
47
- // Multiple relations to tags collection
48
- tags: relationsField({ collection: "tags", maxSelect: 10 }),
49
- }),
50
- {
38
+ // Define the Zod schema
39
+ export const PostSchema = z.object({
40
+ title: z.string().min(1).max(200),
41
+ content: z.string(),
42
+ published: z.boolean().default(false),
43
+
44
+ // Single relation to users collection
45
+ author: RelationField({ collection: "users" }),
46
+
47
+ // Multiple relations to tags collection
48
+ tags: RelationsField({ collection: "tags", maxSelect: 10 }),
49
+ });
50
+
51
+ // Define the collection with permissions
52
+ export const PostCollection = defineCollection({
53
+ collectionName: "posts",
54
+ schema: PostSchema,
55
+ permissions: {
51
56
  listRule: '@request.auth.id != ""',
52
57
  viewRule: "",
53
58
  createRule: '@request.auth.id != ""',
54
59
  updateRule: "author = @request.auth.id",
55
60
  deleteRule: "author = @request.auth.id",
56
- }
57
- );
61
+ },
62
+ });
58
63
  ```
59
64
 
60
65
  ### 2. Configure the CLI
@@ -81,10 +86,69 @@ npx pocketbase-migrate generate
81
86
 
82
87
  This will create a migration file in your PocketBase migrations directory.
83
88
 
89
+ **TypeScript Support:** You can use TypeScript (`.ts`) schema files directly - no compilation needed! The tool automatically handles TypeScript files using `tsx`.
90
+
84
91
  ---
85
92
 
86
93
  ## Schema Definition
87
94
 
95
+ ### High-Level Collection Definition
96
+
97
+ The recommended way to define collections is using `defineCollection()`, which provides a single entry point for collection name, schema, permissions, indexes, and future features:
98
+
99
+ ```typescript
100
+ import { z } from "zod";
101
+ import { defineCollection, RelationField } from "pocketbase-zod-schema/schema";
102
+
103
+ export const PostCollectionSchema = z.object({
104
+ title: z.string(),
105
+ content: z.string(),
106
+ author: RelationField({ collection: "users" }),
107
+ });
108
+
109
+ export const PostCollection = defineCollection({
110
+ collectionName: "posts",
111
+ schema: PostCollectionSchema,
112
+ permissions: {
113
+ template: "owner-only",
114
+ ownerField: "author",
115
+ },
116
+ indexes: [
117
+ "CREATE INDEX idx_posts_author ON posts (author)",
118
+ ],
119
+ });
120
+ ```
121
+
122
+ **Benefits of `defineCollection()`:**
123
+ - **Explicit collection name** - No need to rely on filename conventions
124
+ - **All metadata in one place** - Schema, permissions, indexes together
125
+ - **Future-proof** - Easy to extend with new features
126
+ - **Cleaner syntax** - No nested function calls
127
+
128
+ **Export Pattern:** It's recommended to export both the schema and collection definition:
129
+
130
+ ```typescript
131
+ // Define the Zod schema (for type inference and validation)
132
+ export const PostSchema = z.object({
133
+ title: z.string(),
134
+ content: z.string(),
135
+ author: RelationField({ collection: "users" }),
136
+ });
137
+
138
+ // Define the collection (used by migration generator, includes metadata)
139
+ export const PostCollection = defineCollection({
140
+ collectionName: "posts",
141
+ schema: PostSchema,
142
+ permissions: { /* ... */ },
143
+ });
144
+ ```
145
+
146
+ This pattern allows:
147
+ - `PostSchema` - Used for type inference (`z.infer<typeof PostSchema>`) and validation
148
+ - `PostCollection` - Used by the migration generator (has collection metadata)
149
+
150
+ **Note:** You can still use `withPermissions()` and `withIndexes()` separately if you prefer, but `defineCollection()` is recommended for new code.
151
+
88
152
  ### Field Types
89
153
 
90
154
  The library maps Zod types to PocketBase field types automatically:
@@ -99,33 +163,33 @@ The library maps Zod types to PocketBase field types automatically:
99
163
  | `z.date()` | date | `birthdate: z.date()` |
100
164
  | `z.enum([...])` | select | `status: z.enum(["draft", "published"])` |
101
165
  | `z.instanceof(File)` | file | `avatar: z.instanceof(File)` |
102
- | `relationField()` | relation | `author: relationField({ collection: "users" })` |
103
- | `relationsField()` | relation | `tags: relationsField({ collection: "tags" })` |
166
+ | `RelationField()` | relation | `author: RelationField({ collection: "users" })` |
167
+ | `RelationsField()` | relation | `tags: RelationsField({ collection: "tags" })` |
104
168
 
105
169
  ### Defining Relations
106
170
 
107
- Use `relationField()` for single relations and `relationsField()` for multiple relations:
171
+ Use `RelationField()` for single relations and `RelationsField()` for multiple relations:
108
172
 
109
173
  ```typescript
110
- import { relationField, relationsField } from "pocketbase-zod-schema/schema";
174
+ import { RelationField, RelationsField } from "pocketbase-zod-schema/schema";
111
175
 
112
176
  const ProjectSchema = z.object({
113
177
  name: z.string(),
114
178
 
115
179
  // Single relation (maxSelect: 1)
116
- owner: relationField({ collection: "users" }),
180
+ owner: RelationField({ collection: "users" }),
117
181
 
118
182
  // Single relation with cascade delete
119
- category: relationField({
183
+ category: RelationField({
120
184
  collection: "categories",
121
185
  cascadeDelete: true,
122
186
  }),
123
187
 
124
188
  // Multiple relations (maxSelect: 999 by default)
125
- collaborators: relationsField({ collection: "users" }),
189
+ collaborators: RelationsField({ collection: "users" }),
126
190
 
127
191
  // Multiple relations with constraints
128
- tags: relationsField({
192
+ tags: RelationsField({
129
193
  collection: "tags",
130
194
  minSelect: 1,
131
195
  maxSelect: 5,
@@ -135,11 +199,11 @@ const ProjectSchema = z.object({
135
199
 
136
200
  #### Relation Options
137
201
 
138
- **`relationField(config)`** - Single relation
202
+ **`RelationField(config)`** - Single relation
139
203
  - `collection: string` - Target collection name (required)
140
204
  - `cascadeDelete?: boolean` - Delete related records when this record is deleted (default: `false`)
141
205
 
142
- **`relationsField(config)`** - Multiple relations
206
+ **`RelationsField(config)`** - Multiple relations
143
207
  - `collection: string` - Target collection name (required)
144
208
  - `cascadeDelete?: boolean` - Delete related records when this record is deleted (default: `false`)
145
209
  - `minSelect?: number` - Minimum number of relations required (default: `0`)
@@ -147,29 +211,43 @@ const ProjectSchema = z.object({
147
211
 
148
212
  ### Defining Permissions
149
213
 
150
- Use `withPermissions()` to attach API rules to your schema:
214
+ Use `defineCollection()` with permissions, or `withPermissions()` to attach API rules to your schema:
151
215
 
152
216
  ```typescript
153
- import { withPermissions } from "pocketbase-zod-schema/schema";
217
+ import { defineCollection, withPermissions } from "pocketbase-zod-schema/schema";
154
218
 
155
- // Using direct rules
156
- const PostSchema = withPermissions(
157
- z.object({ title: z.string() }),
158
- {
219
+ // Using defineCollection (recommended)
220
+ const PostCollection = defineCollection({
221
+ collectionName: "posts",
222
+ schema: z.object({ title: z.string() }),
223
+ permissions: {
159
224
  listRule: '@request.auth.id != ""', // Authenticated users can list
160
225
  viewRule: "", // Anyone can view (public)
161
226
  createRule: '@request.auth.id != ""', // Authenticated users can create
162
227
  updateRule: "author = @request.auth.id", // Only author can update
163
228
  deleteRule: "author = @request.auth.id", // Only author can delete
164
- }
165
- );
229
+ },
230
+ });
166
231
 
167
- // Using templates
168
- const ProjectSchema = withPermissions(
169
- z.object({ title: z.string(), owner: relationField({ collection: "users" }) }),
170
- {
232
+ // Using templates with defineCollection
233
+ const ProjectCollection = defineCollection({
234
+ collectionName: "projects",
235
+ schema: z.object({ title: z.string(), owner: RelationField({ collection: "users" }) }),
236
+ permissions: {
171
237
  template: "owner-only",
172
238
  ownerField: "owner",
239
+ },
240
+ });
241
+
242
+ // Using withPermissions (alternative approach)
243
+ const PostSchemaAlt = withPermissions(
244
+ z.object({ title: z.string() }),
245
+ {
246
+ listRule: '@request.auth.id != ""',
247
+ viewRule: "",
248
+ createRule: '@request.auth.id != ""',
249
+ updateRule: "author = @request.auth.id",
250
+ deleteRule: "author = @request.auth.id",
173
251
  }
174
252
  );
175
253
  ```
@@ -185,24 +263,56 @@ const ProjectSchema = withPermissions(
185
263
  #### Template with Custom Overrides
186
264
 
187
265
  ```typescript
188
- const PostSchema = withPermissions(schema, {
266
+ // Using defineCollection (recommended)
267
+ const PostCollection = defineCollection({
268
+ collectionName: "posts",
269
+ schema: z.object({ title: z.string(), author: RelationField({ collection: "users" }) }),
270
+ permissions: {
271
+ template: "owner-only",
272
+ ownerField: "author",
273
+ customRules: {
274
+ listRule: '@request.auth.id != ""', // Override just the list rule
275
+ viewRule: "", // Make viewing public
276
+ },
277
+ },
278
+ });
279
+
280
+ // Using withPermissions (alternative)
281
+ const PostSchemaAlt = withPermissions(schema, {
189
282
  template: "owner-only",
190
283
  ownerField: "author",
191
284
  customRules: {
192
- listRule: '@request.auth.id != ""', // Override just the list rule
193
- viewRule: "", // Make viewing public
285
+ listRule: '@request.auth.id != ""',
286
+ viewRule: "",
194
287
  },
195
288
  });
196
289
  ```
197
290
 
198
291
  ### Defining Indexes
199
292
 
200
- Use `withIndexes()` to define database indexes:
293
+ Use `defineCollection()` with indexes, or `withIndexes()` to define database indexes:
201
294
 
202
295
  ```typescript
203
- import { withIndexes, withPermissions } from "pocketbase-zod-schema/schema";
296
+ import { defineCollection, withIndexes, withPermissions } from "pocketbase-zod-schema/schema";
297
+
298
+ // Using defineCollection (recommended)
299
+ const UserCollection = defineCollection({
300
+ collectionName: "users",
301
+ schema: z.object({
302
+ email: z.string().email(),
303
+ username: z.string(),
304
+ }),
305
+ permissions: {
306
+ template: "authenticated",
307
+ },
308
+ indexes: [
309
+ 'CREATE UNIQUE INDEX idx_users_email ON users (email)',
310
+ 'CREATE INDEX idx_users_username ON users (username)',
311
+ ],
312
+ });
204
313
 
205
- const UserSchema = withIndexes(
314
+ // Using withIndexes (alternative)
315
+ const UserSchemaAlt = withIndexes(
206
316
  withPermissions(
207
317
  z.object({
208
318
  email: z.string().email(),
@@ -310,84 +420,109 @@ Here's a complete example of a blog schema with users, posts, and comments:
310
420
  ```typescript
311
421
  // src/schema/user.ts
312
422
  import { z } from "zod";
313
- import { withPermissions, withIndexes } from "pocketbase-zod-schema/schema";
423
+ import { baseSchema, defineCollection } from "pocketbase-zod-schema/schema";
424
+
425
+ // Input schema for forms (includes passwordConfirm for validation)
426
+ export const UserInputSchema = z.object({
427
+ name: z.string().optional(),
428
+ email: z.string().email(),
429
+ password: z.string().min(8),
430
+ passwordConfirm: z.string(),
431
+ avatar: z.instanceof(File).optional(),
432
+ });
314
433
 
315
- export const UserSchema = withIndexes(
316
- withPermissions(
317
- z.object({
318
- name: z.string().optional(),
319
- email: z.string().email(),
320
- password: z.string().min(8),
321
- avatar: z.instanceof(File).optional(),
322
- }),
323
- {
324
- listRule: "id = @request.auth.id",
325
- viewRule: "id = @request.auth.id",
326
- createRule: "",
327
- updateRule: "id = @request.auth.id",
328
- deleteRule: "id = @request.auth.id",
329
- }
330
- ),
331
- [
434
+ // Database schema (excludes passwordConfirm)
435
+ const UserCollectionSchema = z.object({
436
+ name: z.string().optional(),
437
+ email: z.string().email(),
438
+ password: z.string().min(8),
439
+ avatar: z.instanceof(File).optional(),
440
+ });
441
+
442
+ // Full schema with base fields for type inference (includes id, collectionId, etc.)
443
+ export const UserSchema = UserCollectionSchema.extend(baseSchema);
444
+
445
+ // Collection definition with permissions and indexes
446
+ export const UserCollection = defineCollection({
447
+ collectionName: "Users",
448
+ schema: UserSchema,
449
+ permissions: {
450
+ listRule: "id = @request.auth.id",
451
+ viewRule: "id = @request.auth.id",
452
+ createRule: "",
453
+ updateRule: "id = @request.auth.id",
454
+ deleteRule: "id = @request.auth.id",
455
+ },
456
+ indexes: [
332
457
  'CREATE UNIQUE INDEX idx_users_email ON users (email)',
333
- ]
334
- );
458
+ ],
459
+ });
335
460
  ```
336
461
 
337
462
  ```typescript
338
463
  // src/schema/post.ts
339
464
  import { z } from "zod";
340
465
  import {
341
- relationField,
342
- relationsField,
343
- withPermissions
466
+ defineCollection,
467
+ RelationField,
468
+ RelationsField,
344
469
  } from "pocketbase-zod-schema/schema";
345
470
 
346
- export const PostSchema = withPermissions(
347
- z.object({
348
- title: z.string().min(1).max(200),
349
- slug: z.string(),
350
- content: z.string(),
351
- excerpt: z.string().optional(),
352
- published: z.boolean().default(false),
353
- publishedAt: z.date().optional(),
354
-
355
- // Relations
356
- author: relationField({ collection: "users" }),
357
- category: relationField({ collection: "categories" }),
358
- tags: relationsField({ collection: "tags", maxSelect: 10 }),
359
- }),
360
- {
471
+ // Define the Zod schema
472
+ export const PostSchema = z.object({
473
+ title: z.string().min(1).max(200),
474
+ slug: z.string(),
475
+ content: z.string(),
476
+ excerpt: z.string().optional(),
477
+ published: z.boolean().default(false),
478
+ publishedAt: z.date().optional(),
479
+
480
+ // Relations
481
+ author: RelationField({ collection: "users" }),
482
+ category: RelationField({ collection: "categories" }),
483
+ tags: RelationsField({ collection: "tags", maxSelect: 10 }),
484
+ });
485
+
486
+ // Define the collection with permissions
487
+ export const PostCollection = defineCollection({
488
+ collectionName: "posts",
489
+ schema: PostSchema,
490
+ permissions: {
361
491
  listRule: 'published = true || author = @request.auth.id',
362
492
  viewRule: 'published = true || author = @request.auth.id',
363
493
  createRule: '@request.auth.id != ""',
364
494
  updateRule: "author = @request.auth.id",
365
495
  deleteRule: "author = @request.auth.id",
366
- }
367
- );
496
+ },
497
+ });
368
498
  ```
369
499
 
370
500
  ```typescript
371
501
  // src/schema/comment.ts
372
502
  import { z } from "zod";
373
- import { relationField, withPermissions } from "pocketbase-zod-schema/schema";
503
+ import { defineCollection, RelationField } from "pocketbase-zod-schema/schema";
374
504
 
375
- export const CommentSchema = withPermissions(
376
- z.object({
377
- content: z.string().min(1),
378
-
379
- // Relations with cascade delete
380
- post: relationField({ collection: "posts", cascadeDelete: true }),
381
- author: relationField({ collection: "users" }),
382
- }),
383
- {
505
+ // Define the Zod schema
506
+ export const CommentSchema = z.object({
507
+ content: z.string().min(1),
508
+
509
+ // Relations with cascade delete
510
+ post: RelationField({ collection: "posts", cascadeDelete: true }),
511
+ author: RelationField({ collection: "users" }),
512
+ });
513
+
514
+ // Define the collection with permissions
515
+ export const CommentCollection = defineCollection({
516
+ collectionName: "comments",
517
+ schema: CommentSchema,
518
+ permissions: {
384
519
  listRule: "",
385
520
  viewRule: "",
386
521
  createRule: '@request.auth.id != ""',
387
522
  updateRule: "author = @request.auth.id",
388
523
  deleteRule: "author = @request.auth.id || @request.auth.role = 'admin'",
389
- }
390
- );
524
+ },
525
+ });
391
526
  ```
392
527
 
393
528
  ---
@@ -1076,6 +1076,16 @@ function isFieldRequired(zodType) {
1076
1076
  }
1077
1077
 
1078
1078
  // src/migration/analyzer.ts
1079
+ var tsxLoaderRegistered = false;
1080
+ async function ensureTsxLoader() {
1081
+ if (tsxLoaderRegistered) return;
1082
+ try {
1083
+ await import('tsx/esm');
1084
+ tsxLoaderRegistered = true;
1085
+ } catch {
1086
+ tsxLoaderRegistered = false;
1087
+ }
1088
+ }
1079
1089
  var DEFAULT_CONFIG = {
1080
1090
  workspaceRoot: process.cwd(),
1081
1091
  excludePatterns: [
@@ -1173,24 +1183,37 @@ async function importSchemaModule(filePath, config) {
1173
1183
  } else {
1174
1184
  resolvedPath = jsPath;
1175
1185
  }
1186
+ if (resolvedPath.endsWith(".ts")) {
1187
+ await ensureTsxLoader();
1188
+ if (!tsxLoaderRegistered) {
1189
+ throw new SchemaParsingError(
1190
+ `Failed to import TypeScript schema file. The 'tsx' package is required to load TypeScript files.
1191
+ Please install tsx: npm install tsx (or yarn add tsx, or pnpm add tsx)
1192
+ Alternatively, compile your schema files to JavaScript first.`,
1193
+ filePath
1194
+ );
1195
+ }
1196
+ }
1176
1197
  const fileUrl = new URL(`file://${path5__namespace.resolve(resolvedPath)}`);
1177
1198
  const module = await import(fileUrl.href);
1178
1199
  return module;
1179
1200
  } catch (error) {
1180
1201
  const tsPath = `${filePath}.ts`;
1181
1202
  const isTypeScriptFile = fs5__namespace.existsSync(tsPath);
1203
+ if (isTypeScriptFile && error instanceof SchemaParsingError) {
1204
+ throw error;
1205
+ }
1182
1206
  if (isTypeScriptFile) {
1183
1207
  throw new SchemaParsingError(
1184
- `Failed to import TypeScript schema file. Node.js cannot import TypeScript files directly.
1185
- Please either:
1186
- 1. Compile your schema files to JavaScript first, or
1187
- 2. Use tsx to run the migration tool (e.g., "npx tsx package/dist/cli/migrate.js status" or "tsx package/dist/cli/migrate.js status")`,
1208
+ `Failed to import TypeScript schema file. The 'tsx' package is required to load TypeScript files.
1209
+ Please install tsx: npm install tsx (or yarn add tsx, or pnpm add tsx)
1210
+ Alternatively, compile your schema files to JavaScript first.`,
1188
1211
  filePath,
1189
1212
  error
1190
1213
  );
1191
1214
  }
1192
1215
  throw new SchemaParsingError(
1193
- `Failed to import schema module. Make sure the schema files are compiled to JavaScript.`,
1216
+ `Failed to import schema module. Make sure the schema files exist and are valid.`,
1194
1217
  filePath,
1195
1218
  error
1196
1219
  );
@@ -1200,6 +1223,19 @@ function getCollectionNameFromFile(filePath) {
1200
1223
  const filename = path5__namespace.basename(filePath).replace(/\.(ts|js)$/, "");
1201
1224
  return toCollectionName(filename);
1202
1225
  }
1226
+ function extractCollectionNameFromSchema(zodSchema) {
1227
+ if (!zodSchema.description) {
1228
+ return null;
1229
+ }
1230
+ try {
1231
+ const metadata = JSON.parse(zodSchema.description);
1232
+ if (metadata.collectionName && typeof metadata.collectionName === "string") {
1233
+ return metadata.collectionName;
1234
+ }
1235
+ } catch {
1236
+ }
1237
+ return null;
1238
+ }
1203
1239
  function extractSchemaDefinitions(module, patterns = ["Schema", "InputSchema"]) {
1204
1240
  const result = {};
1205
1241
  for (const [key, value] of Object.entries(module)) {
@@ -1375,7 +1411,8 @@ async function buildSchemaDefinition(config) {
1375
1411
  console.warn(`No valid schema found in ${filePath}, skipping...`);
1376
1412
  continue;
1377
1413
  }
1378
- const collectionName = getCollectionNameFromFile(filePath);
1414
+ const collectionNameFromSchema = extractCollectionNameFromSchema(zodSchema);
1415
+ const collectionName = collectionNameFromSchema ?? getCollectionNameFromFile(filePath);
1379
1416
  const collectionSchema = convertZodSchemaToCollectionSchema(collectionName, zodSchema);
1380
1417
  collections.set(collectionName, collectionSchema);
1381
1418
  } catch (error) {