pocketbase-zod-schema 0.1.4 → 0.2.1

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 (45) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +233 -98
  3. package/dist/cli/index.cjs +45 -11
  4. package/dist/cli/index.cjs.map +1 -1
  5. package/dist/cli/index.js +45 -11
  6. package/dist/cli/index.js.map +1 -1
  7. package/dist/cli/migrate.cjs +45 -11
  8. package/dist/cli/migrate.cjs.map +1 -1
  9. package/dist/cli/migrate.js +45 -11
  10. package/dist/cli/migrate.js.map +1 -1
  11. package/dist/index.cjs +86 -27
  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 +81 -26
  16. package/dist/index.js.map +1 -1
  17. package/dist/migration/analyzer.cjs +46 -11
  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 +46 -12
  22. package/dist/migration/analyzer.js.map +1 -1
  23. package/dist/migration/index.cjs +45 -11
  24. package/dist/migration/index.cjs.map +1 -1
  25. package/dist/migration/index.js +45 -11
  26. package/dist/migration/index.js.map +1 -1
  27. package/dist/migration/snapshot.cjs.map +1 -1
  28. package/dist/migration/snapshot.js.map +1 -1
  29. package/dist/mutator.cjs +20 -21
  30. package/dist/mutator.cjs.map +1 -1
  31. package/dist/mutator.d.cts +2 -2
  32. package/dist/mutator.d.ts +2 -2
  33. package/dist/mutator.js +20 -21
  34. package/dist/mutator.js.map +1 -1
  35. package/dist/schema.cjs +41 -16
  36. package/dist/schema.cjs.map +1 -1
  37. package/dist/schema.d.cts +98 -8
  38. package/dist/schema.d.ts +98 -8
  39. package/dist/schema.js +36 -15
  40. package/dist/schema.js.map +1 -1
  41. package/dist/types.d.cts +1 -1
  42. package/dist/types.d.ts +1 -1
  43. package/dist/{user-_AM523hb.d.cts → user-DTJQIj4K.d.cts} +31 -5
  44. package/dist/{user-_AM523hb.d.ts → user-DTJQIj4K.d.ts} +31 -5
  45. package/package.json +2 -1
package/dist/schema.cjs CHANGED
@@ -66,7 +66,7 @@ function filesField(options) {
66
66
  return schema;
67
67
  }
68
68
  var RELATION_METADATA_KEY = "__pocketbase_relation__";
69
- function relationField(config) {
69
+ function RelationField(config) {
70
70
  const metadata = {
71
71
  [RELATION_METADATA_KEY]: {
72
72
  type: "single",
@@ -78,7 +78,7 @@ function relationField(config) {
78
78
  };
79
79
  return zod.z.string().describe(JSON.stringify(metadata));
80
80
  }
81
- function relationsField(config) {
81
+ function RelationsField(config) {
82
82
  const metadata = {
83
83
  [RELATION_METADATA_KEY]: {
84
84
  type: "multiple",
@@ -137,6 +137,22 @@ function withIndexes(schema, indexes) {
137
137
  };
138
138
  return schema.describe(JSON.stringify(metadata));
139
139
  }
140
+ function defineCollection(config) {
141
+ const { collectionName, schema, permissions, indexes, ...futureOptions } = config;
142
+ const metadata = {
143
+ collectionName
144
+ };
145
+ if (permissions) {
146
+ metadata.permissions = permissions;
147
+ }
148
+ if (indexes) {
149
+ metadata.indexes = indexes;
150
+ }
151
+ if (Object.keys(futureOptions).length > 0) {
152
+ Object.assign(metadata, futureOptions);
153
+ }
154
+ return schema.describe(JSON.stringify(metadata));
155
+ }
140
156
 
141
157
  // src/utils/permission-templates.ts
142
158
  var PermissionTemplates = {
@@ -375,12 +391,14 @@ var ProjectInputSchema = zod.z.object({
375
391
  content: zod.z.string(),
376
392
  status: StatusEnum,
377
393
  summary: zod.z.string().optional(),
378
- OwnerUser: relationField({ collection: "Users" }),
379
- SubscriberUsers: relationsField({ collection: "Users" })
394
+ OwnerUser: RelationField({ collection: "Users" }),
395
+ SubscriberUsers: RelationsField({ collection: "Users" })
380
396
  }).extend(inputImageFileSchema);
381
- var ProjectSchema = withPermissions(
382
- ProjectInputSchema.omit(omitImageFilesSchema).extend(baseImageFileSchema),
383
- {
397
+ var ProjectSchema = ProjectInputSchema.omit(omitImageFilesSchema).extend(baseImageFileSchema);
398
+ var ProjectCollection = defineCollection({
399
+ collectionName: "Projects",
400
+ schema: ProjectSchema,
401
+ permissions: {
384
402
  template: "owner-only",
385
403
  ownerField: "OwnerUser",
386
404
  customRules: {
@@ -388,7 +406,7 @@ var ProjectSchema = withPermissions(
388
406
  viewRule: '@request.auth.id != "" && (OwnerUser = @request.auth.id || SubscriberUsers ?= @request.auth.id)'
389
407
  }
390
408
  }
391
- );
409
+ });
392
410
  var UserInputSchema = zod.z.object({
393
411
  name: zod.z.string().optional(),
394
412
  email: zod.z.string().email(),
@@ -396,14 +414,17 @@ var UserInputSchema = zod.z.object({
396
414
  passwordConfirm: zod.z.string(),
397
415
  avatar: zod.z.instanceof(File).optional()
398
416
  });
399
- var UserDatabaseSchema = zod.z.object({
417
+ var UserCollectionSchema = zod.z.object({
400
418
  name: zod.z.string().optional(),
401
419
  email: zod.z.string().email(),
402
420
  password: zod.z.string().min(8, "Password must be at least 8 characters"),
403
421
  avatar: zod.z.instanceof(File).optional()
404
422
  });
405
- var UserSchema = withIndexes(
406
- withPermissions(UserDatabaseSchema.extend(baseSchema), {
423
+ var UserSchema = UserCollectionSchema.extend(baseSchema);
424
+ var UserCollection = defineCollection({
425
+ collectionName: "Users",
426
+ schema: UserSchema,
427
+ permissions: {
407
428
  // Users can list their own profile
408
429
  listRule: "id = @request.auth.id",
409
430
  // Users can view their own profile
@@ -415,17 +436,22 @@ var UserSchema = withIndexes(
415
436
  // Users can only delete their own account
416
437
  deleteRule: "id = @request.auth.id"
417
438
  // manageRule is null in PocketBase default (not set)
418
- }),
419
- [
439
+ },
440
+ indexes: [
420
441
  // PocketBase's default indexes for auth collections
421
442
  "CREATE UNIQUE INDEX `idx_tokenKey__pb_users_auth_` ON `users` (`tokenKey`)",
422
443
  "CREATE UNIQUE INDEX `idx_email__pb_users_auth_` ON `users` (`email`) WHERE `email` != ''"
423
444
  ]
424
- );
445
+ });
425
446
 
426
447
  exports.PermissionTemplates = PermissionTemplates;
448
+ exports.ProjectCollection = ProjectCollection;
427
449
  exports.ProjectInputSchema = ProjectInputSchema;
428
450
  exports.ProjectSchema = ProjectSchema;
451
+ exports.RelationField = RelationField;
452
+ exports.RelationsField = RelationsField;
453
+ exports.UserCollection = UserCollection;
454
+ exports.UserCollectionSchema = UserCollectionSchema;
429
455
  exports.UserInputSchema = UserInputSchema;
430
456
  exports.UserSchema = UserSchema;
431
457
  exports.baseImageFileSchema = baseImageFileSchema;
@@ -434,6 +460,7 @@ exports.baseSchemaWithTimestamps = baseSchemaWithTimestamps;
434
460
  exports.boolField = boolField;
435
461
  exports.createPermissions = createPermissions;
436
462
  exports.dateField = dateField;
463
+ exports.defineCollection = defineCollection;
437
464
  exports.editorField = editorField;
438
465
  exports.emailField = emailField;
439
466
  exports.extractRelationMetadata = extractRelationMetadata;
@@ -447,8 +474,6 @@ exports.jsonField = jsonField;
447
474
  exports.mergePermissions = mergePermissions;
448
475
  exports.numberField = numberField;
449
476
  exports.omitImageFilesSchema = omitImageFilesSchema;
450
- exports.relationField = relationField;
451
- exports.relationsField = relationsField;
452
477
  exports.resolveTemplate = resolveTemplate;
453
478
  exports.selectField = selectField;
454
479
  exports.textField = textField;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/schema/base.ts","../src/utils/permission-templates.ts","../src/enums.ts","../src/schema/project.ts","../src/schema/user.ts"],"names":["z"],"mappings":"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","file":"schema.cjs","sourcesContent":["import { z } from \"zod\";\nimport type { PermissionSchema, PermissionTemplateConfig } from \"../utils/permissions\";\n\n/**\n * Base schema fields that PocketBase automatically adds to all records\n * These fields are managed by PocketBase and should not be set manually\n */\nexport const baseSchema = {\n id: z.string().describe(\"unique id\"),\n collectionId: z.string().describe(\"collection id\"),\n collectionName: z.string().describe(\"collection name\"),\n expand: z.record(z.any()).describe(\"expandable fields\"),\n};\n\n/**\n * Extended base schema with timestamp fields\n * Includes created and updated autodate fields\n */\nexport const baseSchemaWithTimestamps = {\n ...baseSchema,\n created: z.string().describe(\"creation timestamp\"),\n updated: z.string().describe(\"last update timestamp\"),\n};\n\n/**\n * Base schema for image file collections\n * Extends base schema with thumbnail URL and image files array\n */\nexport const baseImageFileSchema = {\n ...baseSchema,\n thumbnailURL: z.string().optional(),\n imageFiles: z.array(z.string()),\n};\n\n/**\n * Input schema for image file uploads\n * Used in forms where users upload File objects\n * Requires Node.js 20+ or browser environment with File API\n */\nexport const inputImageFileSchema = {\n imageFiles: z.array(z.instanceof(File)),\n};\n\n/**\n * Helper constant for omitting image files from schemas\n * Used with Zod's .omit() method\n */\nexport const omitImageFilesSchema = {\n imageFiles: true,\n} as const;\n\n// ============================================================================\n// Common PocketBase Field Type Patterns\n// ============================================================================\n\n/**\n * Creates a text field schema with optional constraints\n * @param options - Optional constraints for the text field\n */\nexport function textField(options?: { min?: number; max?: number; pattern?: RegExp }) {\n let schema = z.string();\n if (options?.min !== undefined) schema = schema.min(options.min);\n if (options?.max !== undefined) schema = schema.max(options.max);\n if (options?.pattern !== undefined) schema = schema.regex(options.pattern);\n return schema;\n}\n\n/**\n * Creates an email field schema\n * Maps to PocketBase 'email' field type\n */\nexport function emailField() {\n return z.string().email();\n}\n\n/**\n * Creates a URL field schema\n * Maps to PocketBase 'url' field type\n */\nexport function urlField() {\n return z.string().url();\n}\n\n/**\n * Creates a number field schema with optional constraints\n * @param options - Optional constraints for the number field\n */\nexport function numberField(options?: { min?: number; max?: number }) {\n let schema = z.number();\n if (options?.min !== undefined) schema = schema.min(options.min);\n if (options?.max !== undefined) schema = schema.max(options.max);\n return schema;\n}\n\n/**\n * Creates a boolean field schema\n * Maps to PocketBase 'bool' field type\n */\nexport function boolField() {\n return z.boolean();\n}\n\n/**\n * Creates a date field schema\n * Maps to PocketBase 'date' field type\n */\nexport function dateField() {\n return z.date();\n}\n\n/**\n * Creates a select field schema from enum values\n * Maps to PocketBase 'select' field type\n * @param values - Array of allowed string values\n */\nexport function selectField<T extends [string, ...string[]]>(values: T) {\n return z.enum(values);\n}\n\n/**\n * Creates a JSON field schema\n * Maps to PocketBase 'json' field type\n * @param schema - Optional Zod schema for the JSON structure\n */\nexport function jsonField<T extends z.ZodTypeAny>(schema?: T) {\n return schema ?? z.record(z.any());\n}\n\n/**\n * Creates a single file field schema for form input\n * Maps to PocketBase 'file' field type with maxSelect=1\n * Requires Node.js 20+ or browser environment with File API\n */\nexport function fileField() {\n return z.instanceof(File);\n}\n\n/**\n * Creates a multiple file field schema for form input\n * Maps to PocketBase 'file' field type with maxSelect>1\n * Requires Node.js 20+ or browser environment with File API\n * @param options - Optional constraints for the file field\n */\nexport function filesField(options?: { min?: number; max?: number }) {\n let schema = z.array(z.instanceof(File));\n if (options?.min !== undefined) schema = schema.min(options.min);\n if (options?.max !== undefined) schema = schema.max(options.max);\n return schema;\n}\n\n// ============================================================================\n// Relation Field Helpers - Explicit Relationship Definitions\n// ============================================================================\n\n/**\n * Relation field configuration options\n */\nexport interface RelationConfig {\n /**\n * Target collection name (e.g., 'users', 'posts', 'tags')\n * This is the PocketBase collection that the relation points to\n */\n collection: string;\n\n /**\n * Whether to cascade delete related records when this record is deleted\n * @default false\n */\n cascadeDelete?: boolean;\n}\n\n/**\n * Multiple relation field configuration options\n */\nexport interface RelationsConfig extends RelationConfig {\n /**\n * Minimum number of relations required\n * @default 0\n */\n minSelect?: number;\n\n /**\n * Maximum number of relations allowed\n * @default 999\n */\n maxSelect?: number;\n}\n\n/**\n * Internal marker for relation metadata\n * Used by the analyzer to detect explicit relation definitions\n */\nconst RELATION_METADATA_KEY = \"__pocketbase_relation__\";\n\n/**\n * Creates a single relation field schema with explicit collection target\n * Maps to PocketBase 'relation' field type with maxSelect=1\n *\n * This is the recommended way to define relations - it's explicit and doesn't\n * rely on naming conventions.\n *\n * @param config - Relation configuration with target collection\n * @returns Zod string schema with relation metadata\n *\n * @example\n * // Single relation to users collection\n * const PostSchema = z.object({\n * title: z.string(),\n * author: relationField({ collection: 'users' }),\n * });\n *\n * @example\n * // Relation with cascade delete\n * const CommentSchema = z.object({\n * content: z.string(),\n * post: relationField({ collection: 'posts', cascadeDelete: true }),\n * });\n */\nexport function relationField(config: RelationConfig) {\n const metadata = {\n [RELATION_METADATA_KEY]: {\n type: \"single\",\n collection: config.collection,\n cascadeDelete: config.cascadeDelete ?? false,\n maxSelect: 1,\n minSelect: 0,\n },\n };\n\n return z.string().describe(JSON.stringify(metadata));\n}\n\n/**\n * Creates a multiple relation field schema with explicit collection target\n * Maps to PocketBase 'relation' field type with maxSelect>1\n *\n * This is the recommended way to define multi-relations - it's explicit and\n * doesn't rely on naming conventions.\n *\n * @param config - Relations configuration with target collection and limits\n * @returns Zod array of strings schema with relation metadata\n *\n * @example\n * // Multiple relations to tags collection\n * const PostSchema = z.object({\n * title: z.string(),\n * tags: relationsField({ collection: 'tags' }),\n * });\n *\n * @example\n * // Relations with min/max constraints\n * const ProjectSchema = z.object({\n * title: z.string(),\n * collaborators: relationsField({\n * collection: 'users',\n * minSelect: 1,\n * maxSelect: 10,\n * }),\n * });\n */\nexport function relationsField(config: RelationsConfig) {\n const metadata = {\n [RELATION_METADATA_KEY]: {\n type: \"multiple\",\n collection: config.collection,\n cascadeDelete: config.cascadeDelete ?? false,\n maxSelect: config.maxSelect ?? 999,\n minSelect: config.minSelect ?? 0,\n },\n };\n\n let schema = z.array(z.string());\n\n // Apply array constraints for Zod validation\n if (config.minSelect !== undefined) {\n schema = schema.min(config.minSelect);\n }\n if (config.maxSelect !== undefined) {\n schema = schema.max(config.maxSelect);\n }\n\n return schema.describe(JSON.stringify(metadata));\n}\n\n/**\n * Extracts relation metadata from a Zod type's description\n * Used internally by the analyzer to detect explicit relation definitions\n *\n * @param description - The Zod type's description string\n * @returns Relation metadata if present, null otherwise\n */\nexport function extractRelationMetadata(description: string | undefined): {\n type: \"single\" | \"multiple\";\n collection: string;\n cascadeDelete: boolean;\n maxSelect: number;\n minSelect: number;\n} | null {\n if (!description) return null;\n\n try {\n const parsed = JSON.parse(description);\n if (parsed[RELATION_METADATA_KEY]) {\n return parsed[RELATION_METADATA_KEY];\n }\n } catch {\n // Not JSON, ignore\n }\n\n return null;\n}\n\n/**\n * Creates an editor field schema (rich text)\n * Maps to PocketBase 'editor' field type\n */\nexport function editorField() {\n return z.string();\n}\n\n/**\n * Creates a geo point field schema\n * Maps to PocketBase 'geoPoint' field type\n */\nexport function geoPointField() {\n return z.object({\n lon: z.number(),\n lat: z.number(),\n });\n}\n\n/**\n * Attach permission metadata to a Zod schema\n *\n * This helper function allows you to define PocketBase API rules alongside your\n * entity schema definitions. The permissions are stored as metadata using Zod's\n * describe() method and will be extracted during migration generation.\n *\n * @param schema - The Zod schema to attach permissions to\n * @param config - Either a PermissionTemplateConfig (for template-based permissions)\n * or a PermissionSchema (for custom permissions)\n * @returns The schema with permission metadata attached\n *\n * @example\n * // Using a template\n * const ProjectSchema = withPermissions(\n * z.object({ title: z.string(), User: z.string() }),\n * { template: 'owner-only', ownerField: 'User' }\n * );\n *\n * @example\n * // Using custom rules\n * const ProjectSchema = withPermissions(\n * z.object({ title: z.string() }),\n * { listRule: '@request.auth.id != \"\"', viewRule: '' }\n * );\n *\n * @example\n * // Using template with custom rule overrides\n * const ProjectSchema = withPermissions(\n * z.object({ title: z.string(), User: z.string() }),\n * {\n * template: 'owner-only',\n * ownerField: 'User',\n * customRules: { listRule: '@request.auth.id != \"\"' }\n * }\n * );\n */\nexport function withPermissions<T extends z.ZodTypeAny>(\n schema: T,\n config: PermissionTemplateConfig | PermissionSchema\n): T {\n // Create metadata object with permissions config directly\n // The PermissionAnalyzer will handle resolving templates vs direct schemas\n const metadata = {\n permissions: config,\n };\n\n // Attach permission metadata to schema using Zod's describe() method\n // The metadata is serialized as JSON and stored in the schema's description\n return schema.describe(JSON.stringify(metadata)) as T;\n}\n\n/**\n * Attach index definitions to a Zod schema\n *\n * This helper function allows you to define PocketBase indexes alongside your\n * entity schema definitions. The indexes are stored as metadata using Zod's\n * describe() method and will be extracted during migration generation.\n *\n * @param schema - The Zod schema to attach indexes to\n * @param indexes - Array of PocketBase index SQL statements\n * @returns The schema with index metadata attached\n *\n * @example\n * // Define indexes for a user schema\n * const UserSchema = withIndexes(\n * withPermissions(\n * z.object({ name: z.string(), email: z.string().email() }),\n * userPermissions\n * ),\n * [\n * 'CREATE UNIQUE INDEX idx_users_email ON users (email)',\n * 'CREATE INDEX idx_users_name ON users (name)'\n * ]\n * );\n *\n * @example\n * // Single index\n * const ProjectSchema = withIndexes(\n * ProjectDatabaseSchema,\n * ['CREATE INDEX idx_projects_status ON projects (status)']\n * );\n */\nexport function withIndexes<T extends z.ZodTypeAny>(schema: T, indexes: string[]): T {\n // Extract existing metadata if present\n let existingMetadata: any = {};\n\n if (schema.description) {\n try {\n existingMetadata = JSON.parse(schema.description);\n } catch {\n // If description is not JSON, ignore it\n }\n }\n\n // Merge indexes with existing metadata\n const metadata = {\n ...existingMetadata,\n indexes,\n };\n\n // Attach metadata to schema using Zod's describe() method\n return schema.describe(JSON.stringify(metadata)) as T;\n}\n","import type { PermissionSchema, PermissionTemplateConfig, RuleExpression } from \"../utils/permissions\";\n\n/**\n * Predefined permission templates for common access control patterns\n */\nexport const PermissionTemplates = {\n /**\n * Public access - anyone can perform all operations\n */\n public: (): PermissionSchema => ({\n listRule: \"\",\n viewRule: \"\",\n createRule: \"\",\n updateRule: \"\",\n deleteRule: \"\",\n }),\n\n /**\n * Authenticated users only - requires valid authentication for all operations\n */\n authenticated: (): PermissionSchema => ({\n listRule: '@request.auth.id != \"\"',\n viewRule: '@request.auth.id != \"\"',\n createRule: '@request.auth.id != \"\"',\n updateRule: '@request.auth.id != \"\"',\n deleteRule: '@request.auth.id != \"\"',\n }),\n\n /**\n * Owner-only access - users can only manage their own records\n * @param ownerField - Name of the relation field pointing to user (default: 'User')\n */\n ownerOnly: (ownerField: string = \"User\"): PermissionSchema => ({\n listRule: `@request.auth.id != \"\" && ${ownerField} = @request.auth.id`,\n viewRule: `@request.auth.id != \"\" && ${ownerField} = @request.auth.id`,\n createRule: '@request.auth.id != \"\"',\n updateRule: `@request.auth.id != \"\" && ${ownerField} = @request.auth.id`,\n deleteRule: `@request.auth.id != \"\" && ${ownerField} = @request.auth.id`,\n }),\n\n /**\n * Admin/superuser only access\n * Assumes a 'role' field exists with 'admin' value\n * @param roleField - Name of the role field (default: 'role')\n */\n adminOnly: (roleField: string = \"role\"): PermissionSchema => ({\n listRule: `@request.auth.id != \"\" && @request.auth.${roleField} = \"admin\"`,\n viewRule: `@request.auth.id != \"\" && @request.auth.${roleField} = \"admin\"`,\n createRule: `@request.auth.id != \"\" && @request.auth.${roleField} = \"admin\"`,\n updateRule: `@request.auth.id != \"\" && @request.auth.${roleField} = \"admin\"`,\n deleteRule: `@request.auth.id != \"\" && @request.auth.${roleField} = \"admin\"`,\n }),\n\n /**\n * Public read, authenticated write\n * Anyone can list/view, but only authenticated users can create/update/delete\n */\n readPublic: (): PermissionSchema => ({\n listRule: \"\",\n viewRule: \"\",\n createRule: '@request.auth.id != \"\"',\n updateRule: '@request.auth.id != \"\"',\n deleteRule: '@request.auth.id != \"\"',\n }),\n\n /**\n * Locked access - only superusers can perform operations\n * All rules are set to null (locked)\n */\n locked: (): PermissionSchema => ({\n listRule: null,\n viewRule: null,\n createRule: null,\n updateRule: null,\n deleteRule: null,\n }),\n\n /**\n * Read-only authenticated - authenticated users can read, no write access\n */\n readOnlyAuthenticated: (): PermissionSchema => ({\n listRule: '@request.auth.id != \"\"',\n viewRule: '@request.auth.id != \"\"',\n createRule: null,\n updateRule: null,\n deleteRule: null,\n }),\n};\n\n/**\n * Resolve template configuration to concrete permission schema\n * @param config - Template configuration or direct permission schema\n * @returns Resolved permission schema with all rules defined\n */\nexport function resolveTemplate(config: PermissionTemplateConfig): PermissionSchema {\n let baseRules: PermissionSchema;\n\n switch (config.template) {\n case \"public\":\n baseRules = PermissionTemplates.public();\n break;\n case \"authenticated\":\n baseRules = PermissionTemplates.authenticated();\n break;\n case \"owner-only\":\n baseRules = PermissionTemplates.ownerOnly(config.ownerField);\n break;\n case \"admin-only\":\n baseRules = PermissionTemplates.adminOnly(config.roleField);\n break;\n case \"read-public\":\n baseRules = PermissionTemplates.readPublic();\n break;\n case \"custom\":\n baseRules = {};\n break;\n default: {\n // Exhaustive check - TypeScript will error if we miss a template type\n const _exhaustive: never = config.template;\n throw new Error(`Unknown template type: ${_exhaustive}`);\n }\n }\n\n // Merge with custom rules if provided (custom rules override template rules)\n return {\n ...baseRules,\n ...config.customRules,\n };\n}\n\n/**\n * Check if a configuration is a template config or direct permission schema\n * @param config - Configuration to check\n * @returns True if it's a template configuration\n */\nexport function isTemplateConfig(\n config: PermissionTemplateConfig | PermissionSchema\n): config is PermissionTemplateConfig {\n return \"template\" in config;\n}\n\n/**\n * Check if a configuration is a direct permission schema\n * @param config - Configuration to check\n * @returns True if it's a direct permission schema\n */\nexport function isPermissionSchema(config: PermissionTemplateConfig | PermissionSchema): config is PermissionSchema {\n return (\n \"listRule\" in config ||\n \"viewRule\" in config ||\n \"createRule\" in config ||\n \"updateRule\" in config ||\n \"deleteRule\" in config ||\n \"manageRule\" in config\n );\n}\n\n/**\n * Validation result for permission configuration\n */\nexport interface PermissionValidationResult {\n valid: boolean;\n errors: string[];\n warnings: string[];\n}\n\n/**\n * Validate a permission configuration\n * @param config - Permission configuration to validate\n * @param isAuthCollection - Whether this is for an auth collection\n * @returns Validation result\n */\nexport function validatePermissionConfig(\n config: PermissionTemplateConfig | PermissionSchema,\n isAuthCollection: boolean = false\n): PermissionValidationResult {\n const result: PermissionValidationResult = {\n valid: true,\n errors: [],\n warnings: [],\n };\n\n // Resolve to permission schema\n let permissions: PermissionSchema;\n if (isTemplateConfig(config)) {\n // Validate template config\n if (config.template === \"owner-only\" && !config.ownerField) {\n result.warnings.push(\"owner-only template without ownerField specified - using default 'User'\");\n }\n if (config.template === \"admin-only\" && !config.roleField) {\n result.warnings.push(\"admin-only template without roleField specified - using default 'role'\");\n }\n permissions = resolveTemplate(config);\n } else {\n permissions = config;\n }\n\n // Validate manageRule usage\n if (permissions.manageRule !== undefined && !isAuthCollection) {\n result.errors.push(\"manageRule is only valid for auth collections\");\n result.valid = false;\n }\n\n // Validate rule expressions\n const ruleTypes: (keyof PermissionSchema)[] = [\"listRule\", \"viewRule\", \"createRule\", \"updateRule\", \"deleteRule\"];\n if (isAuthCollection) {\n ruleTypes.push(\"manageRule\");\n }\n\n for (const ruleType of ruleTypes) {\n const rule = permissions[ruleType];\n if (rule !== undefined && rule !== null && rule !== \"\") {\n const ruleValidation = validateRuleExpression(rule);\n if (!ruleValidation.valid) {\n result.errors.push(`${ruleType}: ${ruleValidation.errors.join(\", \")}`);\n result.valid = false;\n }\n result.warnings.push(...ruleValidation.warnings.map((w) => `${ruleType}: ${w}`));\n }\n }\n\n return result;\n}\n\n/**\n * Validate a single rule expression for basic syntax\n * @param expression - Rule expression to validate\n * @returns Validation result\n */\nexport function validateRuleExpression(expression: RuleExpression): PermissionValidationResult {\n const result: PermissionValidationResult = {\n valid: true,\n errors: [],\n warnings: [],\n };\n\n // Null and empty string are always valid\n if (expression === null || expression === \"\") {\n return result;\n }\n\n // Check for balanced parentheses\n let parenCount = 0;\n for (const char of expression) {\n if (char === \"(\") parenCount++;\n if (char === \")\") parenCount--;\n if (parenCount < 0) {\n result.errors.push(\"Unbalanced parentheses\");\n result.valid = false;\n return result;\n }\n }\n if (parenCount !== 0) {\n result.errors.push(\"Unbalanced parentheses\");\n result.valid = false;\n }\n\n // Check for common mistakes\n if (expression.includes(\"==\")) {\n result.warnings.push(\"Use '=' instead of '==' for equality comparison\");\n }\n\n // Check for valid @request references\n const requestRefs = expression.match(/@request\\.[a-zA-Z_][a-zA-Z0-9_.]*/g) || [];\n for (const ref of requestRefs) {\n const isValid =\n ref.startsWith(\"@request.auth.\") ||\n ref === \"@request.method\" ||\n ref === \"@request.context\" ||\n ref.startsWith(\"@request.body.\") ||\n ref.startsWith(\"@request.query.\") ||\n ref.startsWith(\"@request.headers.\");\n\n if (!isValid) {\n result.errors.push(`Invalid @request reference: '${ref}'`);\n result.valid = false;\n }\n }\n\n return result;\n}\n\n/**\n * Create a custom permission schema with type safety\n * @param permissions - Partial permission schema\n * @returns Complete permission schema with null defaults\n */\nexport function createPermissions(permissions: Partial<PermissionSchema>): PermissionSchema {\n return {\n listRule: permissions.listRule ?? null,\n viewRule: permissions.viewRule ?? null,\n createRule: permissions.createRule ?? null,\n updateRule: permissions.updateRule ?? null,\n deleteRule: permissions.deleteRule ?? null,\n manageRule: permissions.manageRule ?? null,\n };\n}\n\n/**\n * Merge multiple permission schemas, with later schemas taking precedence\n * @param schemas - Permission schemas to merge\n * @returns Merged permission schema\n */\nexport function mergePermissions(...schemas: Partial<PermissionSchema>[]): PermissionSchema {\n const merged: PermissionSchema = {\n listRule: null,\n viewRule: null,\n createRule: null,\n updateRule: null,\n deleteRule: null,\n manageRule: null,\n };\n\n for (const schema of schemas) {\n if (schema.listRule !== undefined) merged.listRule = schema.listRule;\n if (schema.viewRule !== undefined) merged.viewRule = schema.viewRule;\n if (schema.createRule !== undefined) merged.createRule = schema.createRule;\n if (schema.updateRule !== undefined) merged.updateRule = schema.updateRule;\n if (schema.deleteRule !== undefined) merged.deleteRule = schema.deleteRule;\n if (schema.manageRule !== undefined) merged.manageRule = schema.manageRule;\n }\n\n return merged;\n}\n","import { z } from \"zod\";\n\nexport const StatusEnum = z.enum([\n \"draft\", // Initial proposal stage (RequestDraft, ProjectDraft)\n \"active\", // Work in progress\n \"complete\", // Fully completed project\n \"fail\", // Failed project at any stage\n]);\nexport type StatusEnumType = z.infer<typeof StatusEnum>;\n","import { z } from \"zod\";\nimport { StatusEnum } from \"../enums\";\nimport {\n baseImageFileSchema,\n inputImageFileSchema,\n omitImageFilesSchema,\n relationField,\n relationsField,\n withPermissions,\n} from \"./base\";\n\nexport const ProjectInputSchema = z\n .object({\n // Required fields\n title: z.string(),\n content: z.string(),\n status: StatusEnum,\n summary: z.string().optional(),\n\n OwnerUser: relationField({ collection: \"Users\" }),\n SubscriberUsers: relationsField({ collection: \"Users\" }),\n })\n .extend(inputImageFileSchema);\n\n// Apply permissions using template with custom overrides\n// Uses 'owner-only' template but allows all authenticated users to list projects\n// This allows users to see all projects but only manage their own\nexport const ProjectSchema = withPermissions(\n ProjectInputSchema.omit(omitImageFilesSchema).extend(baseImageFileSchema),\n {\n template: \"owner-only\",\n ownerField: \"OwnerUser\",\n customRules: {\n listRule: '@request.auth.id != \"\"',\n viewRule: '@request.auth.id != \"\" && (OwnerUser = @request.auth.id || SubscriberUsers ?= @request.auth.id)',\n },\n }\n);\n","import { z } from \"zod\";\nimport { baseSchema, withIndexes, withPermissions } from \"./base\";\n\n/** -- User Collections -- */\n// Input schema for forms (includes passwordConfirm for validation)\nexport const UserInputSchema = z.object({\n name: z.string().optional(),\n email: z.string().email(),\n password: z.string().min(8, \"Password must be at least 8 characters\"),\n passwordConfirm: z.string(),\n avatar: z.instanceof(File).optional(),\n});\n\n// Database schema (excludes passwordConfirm, includes avatar as file field)\n// Matches PocketBase's default users auth collection structure\n// Note: PocketBase has min: 0, max: 255 for name, but our snapshot loader\n// doesn't extract field-level options properly yet (TODO: fix snapshot loader)\nconst UserDatabaseSchema = z.object({\n name: z.string().optional(),\n email: z.string().email(),\n password: z.string().min(8, \"Password must be at least 8 characters\"),\n avatar: z.instanceof(File).optional(),\n});\n\n// Apply permissions and indexes for auth collection\n// Matches PocketBase's default users collection configuration\nexport const UserSchema = withIndexes(\n withPermissions(UserDatabaseSchema.extend(baseSchema), {\n // Users can list their own profile\n listRule: \"id = @request.auth.id\",\n // Users can view their own profile\n viewRule: \"id = @request.auth.id\",\n // Anyone can create an account (sign up)\n createRule: \"\",\n // Users can only update their own profile\n updateRule: \"id = @request.auth.id\",\n // Users can only delete their own account\n deleteRule: \"id = @request.auth.id\",\n // manageRule is null in PocketBase default (not set)\n }),\n [\n // PocketBase's default indexes for auth collections\n \"CREATE UNIQUE INDEX `idx_tokenKey__pb_users_auth_` ON `users` (`tokenKey`)\",\n \"CREATE UNIQUE INDEX `idx_email__pb_users_auth_` ON `users` (`email`) WHERE `email` != ''\",\n ]\n);\n"]}
1
+ {"version":3,"sources":["../src/schema/base.ts","../src/utils/permission-templates.ts","../src/enums.ts","../src/schema/project.ts","../src/schema/user.ts"],"names":["z"],"mappings":"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","file":"schema.cjs","sourcesContent":["import { z } from \"zod\";\nimport type { PermissionSchema, PermissionTemplateConfig } from \"../utils/permissions\";\n\n/**\n * Base schema fields that PocketBase automatically adds to all records\n * These fields are managed by PocketBase and should not be set manually\n */\nexport const baseSchema = {\n id: z.string().describe(\"unique id\"),\n collectionId: z.string().describe(\"collection id\"),\n collectionName: z.string().describe(\"collection name\"),\n expand: z.record(z.any()).describe(\"expandable fields\"),\n};\n\n/**\n * Extended base schema with timestamp fields\n * Includes created and updated autodate fields\n */\nexport const baseSchemaWithTimestamps = {\n ...baseSchema,\n created: z.string().describe(\"creation timestamp\"),\n updated: z.string().describe(\"last update timestamp\"),\n};\n\n/**\n * Base schema for image file collections\n * Extends base schema with thumbnail URL and image files array\n */\nexport const baseImageFileSchema = {\n ...baseSchema,\n thumbnailURL: z.string().optional(),\n imageFiles: z.array(z.string()),\n};\n\n/**\n * Input schema for image file uploads\n * Used in forms where users upload File objects\n * Requires Node.js 20+ or browser environment with File API\n */\nexport const inputImageFileSchema = {\n imageFiles: z.array(z.instanceof(File)),\n};\n\n/**\n * Helper constant for omitting image files from schemas\n * Used with Zod's .omit() method\n */\nexport const omitImageFilesSchema = {\n imageFiles: true,\n} as const;\n\n// ============================================================================\n// Common PocketBase Field Type Patterns\n// ============================================================================\n\n/**\n * Creates a text field schema with optional constraints\n * @param options - Optional constraints for the text field\n */\nexport function textField(options?: { min?: number; max?: number; pattern?: RegExp }) {\n let schema = z.string();\n if (options?.min !== undefined) schema = schema.min(options.min);\n if (options?.max !== undefined) schema = schema.max(options.max);\n if (options?.pattern !== undefined) schema = schema.regex(options.pattern);\n return schema;\n}\n\n/**\n * Creates an email field schema\n * Maps to PocketBase 'email' field type\n */\nexport function emailField() {\n return z.string().email();\n}\n\n/**\n * Creates a URL field schema\n * Maps to PocketBase 'url' field type\n */\nexport function urlField() {\n return z.string().url();\n}\n\n/**\n * Creates a number field schema with optional constraints\n * @param options - Optional constraints for the number field\n */\nexport function numberField(options?: { min?: number; max?: number }) {\n let schema = z.number();\n if (options?.min !== undefined) schema = schema.min(options.min);\n if (options?.max !== undefined) schema = schema.max(options.max);\n return schema;\n}\n\n/**\n * Creates a boolean field schema\n * Maps to PocketBase 'bool' field type\n */\nexport function boolField() {\n return z.boolean();\n}\n\n/**\n * Creates a date field schema\n * Maps to PocketBase 'date' field type\n */\nexport function dateField() {\n return z.date();\n}\n\n/**\n * Creates a select field schema from enum values\n * Maps to PocketBase 'select' field type\n * @param values - Array of allowed string values\n */\nexport function selectField<T extends [string, ...string[]]>(values: T) {\n return z.enum(values);\n}\n\n/**\n * Creates a JSON field schema\n * Maps to PocketBase 'json' field type\n * @param schema - Optional Zod schema for the JSON structure\n */\nexport function jsonField<T extends z.ZodTypeAny>(schema?: T) {\n return schema ?? z.record(z.any());\n}\n\n/**\n * Creates a single file field schema for form input\n * Maps to PocketBase 'file' field type with maxSelect=1\n * Requires Node.js 20+ or browser environment with File API\n */\nexport function fileField() {\n return z.instanceof(File);\n}\n\n/**\n * Creates a multiple file field schema for form input\n * Maps to PocketBase 'file' field type with maxSelect>1\n * Requires Node.js 20+ or browser environment with File API\n * @param options - Optional constraints for the file field\n */\nexport function filesField(options?: { min?: number; max?: number }) {\n let schema = z.array(z.instanceof(File));\n if (options?.min !== undefined) schema = schema.min(options.min);\n if (options?.max !== undefined) schema = schema.max(options.max);\n return schema;\n}\n\n// ============================================================================\n// Relation Field Helpers - Explicit Relationship Definitions\n// ============================================================================\n\n/**\n * Relation field configuration options\n */\nexport interface RelationConfig {\n /**\n * Target collection name (e.g., 'users', 'posts', 'tags')\n * This is the PocketBase collection that the relation points to\n */\n collection: string;\n\n /**\n * Whether to cascade delete related records when this record is deleted\n * @default false\n */\n cascadeDelete?: boolean;\n}\n\n/**\n * Multiple relation field configuration options\n */\nexport interface RelationsConfig extends RelationConfig {\n /**\n * Minimum number of relations required\n * @default 0\n */\n minSelect?: number;\n\n /**\n * Maximum number of relations allowed\n * @default 999\n */\n maxSelect?: number;\n}\n\n/**\n * Internal marker for relation metadata\n * Used by the analyzer to detect explicit relation definitions\n */\nconst RELATION_METADATA_KEY = \"__pocketbase_relation__\";\n\n/**\n * Creates a single relation field schema with explicit collection target\n * Maps to PocketBase 'relation' field type with maxSelect=1\n *\n * This is the recommended way to define relations - it's explicit and doesn't\n * rely on naming conventions.\n *\n * @param config - Relation configuration with target collection\n * @returns Zod string schema with relation metadata\n *\n * @example\n * // Single relation to users collection\n * const PostSchema = z.object({\n * title: z.string(),\n * author: RelationField({ collection: 'users' }),\n * });\n *\n * @example\n * // Relation with cascade delete\n * const CommentSchema = z.object({\n * content: z.string(),\n * post: RelationField({ collection: 'posts', cascadeDelete: true }),\n * });\n */\nexport function RelationField(config: RelationConfig) {\n const metadata = {\n [RELATION_METADATA_KEY]: {\n type: \"single\",\n collection: config.collection,\n cascadeDelete: config.cascadeDelete ?? false,\n maxSelect: 1,\n minSelect: 0,\n },\n };\n\n return z.string().describe(JSON.stringify(metadata));\n}\n\n/**\n * Creates a multiple relation field schema with explicit collection target\n * Maps to PocketBase 'relation' field type with maxSelect>1\n *\n * This is the recommended way to define multi-relations - it's explicit and\n * doesn't rely on naming conventions.\n *\n * @param config - Relations configuration with target collection and limits\n * @returns Zod array of strings schema with relation metadata\n *\n * @example\n * // Multiple relations to tags collection\n * const PostSchema = z.object({\n * title: z.string(),\n * tags: RelationsField({ collection: 'tags' }),\n * });\n *\n * @example\n * // Relations with min/max constraints\n * const ProjectSchema = z.object({\n * title: z.string(),\n * collaborators: RelationsField({\n * collection: 'users',\n * minSelect: 1,\n * maxSelect: 10,\n * }),\n * });\n */\nexport function RelationsField(config: RelationsConfig) {\n const metadata = {\n [RELATION_METADATA_KEY]: {\n type: \"multiple\",\n collection: config.collection,\n cascadeDelete: config.cascadeDelete ?? false,\n maxSelect: config.maxSelect ?? 999,\n minSelect: config.minSelect ?? 0,\n },\n };\n\n let schema = z.array(z.string());\n\n // Apply array constraints for Zod validation\n if (config.minSelect !== undefined) {\n schema = schema.min(config.minSelect);\n }\n if (config.maxSelect !== undefined) {\n schema = schema.max(config.maxSelect);\n }\n\n return schema.describe(JSON.stringify(metadata));\n}\n\n/**\n * Extracts relation metadata from a Zod type's description\n * Used internally by the analyzer to detect explicit relation definitions\n *\n * @param description - The Zod type's description string\n * @returns Relation metadata if present, null otherwise\n */\nexport function extractRelationMetadata(description: string | undefined): {\n type: \"single\" | \"multiple\";\n collection: string;\n cascadeDelete: boolean;\n maxSelect: number;\n minSelect: number;\n} | null {\n if (!description) return null;\n\n try {\n const parsed = JSON.parse(description);\n if (parsed[RELATION_METADATA_KEY]) {\n return parsed[RELATION_METADATA_KEY];\n }\n } catch {\n // Not JSON, ignore\n }\n\n return null;\n}\n\n/**\n * Creates an editor field schema (rich text)\n * Maps to PocketBase 'editor' field type\n */\nexport function editorField() {\n return z.string();\n}\n\n/**\n * Creates a geo point field schema\n * Maps to PocketBase 'geoPoint' field type\n */\nexport function geoPointField() {\n return z.object({\n lon: z.number(),\n lat: z.number(),\n });\n}\n\n/**\n * Attach permission metadata to a Zod schema\n *\n * This helper function allows you to define PocketBase API rules alongside your\n * entity schema definitions. The permissions are stored as metadata using Zod's\n * describe() method and will be extracted during migration generation.\n *\n * @param schema - The Zod schema to attach permissions to\n * @param config - Either a PermissionTemplateConfig (for template-based permissions)\n * or a PermissionSchema (for custom permissions)\n * @returns The schema with permission metadata attached\n *\n * @example\n * // Using a template\n * const ProjectSchema = withPermissions(\n * z.object({ title: z.string(), User: z.string() }),\n * { template: 'owner-only', ownerField: 'User' }\n * );\n *\n * @example\n * // Using custom rules\n * const ProjectSchema = withPermissions(\n * z.object({ title: z.string() }),\n * { listRule: '@request.auth.id != \"\"', viewRule: '' }\n * );\n *\n * @example\n * // Using template with custom rule overrides\n * const ProjectSchema = withPermissions(\n * z.object({ title: z.string(), User: z.string() }),\n * {\n * template: 'owner-only',\n * ownerField: 'User',\n * customRules: { listRule: '@request.auth.id != \"\"' }\n * }\n * );\n */\nexport function withPermissions<T extends z.ZodTypeAny>(\n schema: T,\n config: PermissionTemplateConfig | PermissionSchema\n): T {\n // Create metadata object with permissions config directly\n // The PermissionAnalyzer will handle resolving templates vs direct schemas\n const metadata = {\n permissions: config,\n };\n\n // Attach permission metadata to schema using Zod's describe() method\n // The metadata is serialized as JSON and stored in the schema's description\n return schema.describe(JSON.stringify(metadata)) as T;\n}\n\n/**\n * Attach index definitions to a Zod schema\n *\n * This helper function allows you to define PocketBase indexes alongside your\n * entity schema definitions. The indexes are stored as metadata using Zod's\n * describe() method and will be extracted during migration generation.\n *\n * @param schema - The Zod schema to attach indexes to\n * @param indexes - Array of PocketBase index SQL statements\n * @returns The schema with index metadata attached\n *\n * @example\n * // Define indexes for a user schema\n * const UserSchema = withIndexes(\n * withPermissions(\n * z.object({ name: z.string(), email: z.string().email() }),\n * userPermissions\n * ),\n * [\n * 'CREATE UNIQUE INDEX idx_users_email ON users (email)',\n * 'CREATE INDEX idx_users_name ON users (name)'\n * ]\n * );\n *\n * @example\n * // Single index\n * const ProjectSchema = withIndexes(\n * ProjectDatabaseSchema,\n * ['CREATE INDEX idx_projects_status ON projects (status)']\n * );\n */\nexport function withIndexes<T extends z.ZodTypeAny>(schema: T, indexes: string[]): T {\n // Extract existing metadata if present\n let existingMetadata: any = {};\n\n if (schema.description) {\n try {\n existingMetadata = JSON.parse(schema.description);\n } catch {\n // If description is not JSON, ignore it\n }\n }\n\n // Merge indexes with existing metadata\n const metadata = {\n ...existingMetadata,\n indexes,\n };\n\n // Attach metadata to schema using Zod's describe() method\n return schema.describe(JSON.stringify(metadata)) as T;\n}\n\n/**\n * Configuration options for defining a collection\n */\nexport interface CollectionConfig {\n /**\n * The name of the PocketBase collection\n * This will be used when generating migrations\n */\n collectionName: string;\n\n /**\n * The Zod schema definition for the collection\n */\n schema: z.ZodObject<any>;\n\n /**\n * Optional permission configuration\n * Can be a template-based config or custom permission rules\n */\n permissions?: PermissionTemplateConfig | PermissionSchema;\n\n /**\n * Optional array of index SQL statements\n * Example: ['CREATE UNIQUE INDEX idx_users_email ON users (email)']\n */\n indexes?: string[];\n\n /**\n * Future extensibility - additional options can be added here\n */\n [key: string]: unknown;\n}\n\n/**\n * High-level wrapper for defining a PocketBase collection with all metadata\n *\n * This is the recommended way to define collections as it provides a single\n * entry point for collection name, schema, permissions, indexes, and future features.\n *\n * @param config - Collection configuration object\n * @returns The schema with all metadata attached\n *\n * @example\n * // Basic collection with permissions\n * export const PostSchema = defineCollection({\n * collectionName: \"posts\",\n * schema: z.object({\n * title: z.string(),\n * content: z.string(),\n * author: RelationField({ collection: \"users\" }),\n * }),\n * permissions: {\n * template: \"owner-only\",\n * ownerField: \"author\",\n * },\n * });\n *\n * @example\n * // Collection with permissions and indexes\n * export const UserSchema = defineCollection({\n * collectionName: \"users\",\n * schema: z.object({\n * name: z.string(),\n * email: z.string().email(),\n * }),\n * permissions: {\n * listRule: \"id = @request.auth.id\",\n * viewRule: \"id = @request.auth.id\",\n * createRule: \"\",\n * updateRule: \"id = @request.auth.id\",\n * deleteRule: \"id = @request.auth.id\",\n * },\n * indexes: [\n * \"CREATE UNIQUE INDEX idx_users_email ON users (email)\",\n * ],\n * });\n *\n * @example\n * // Collection with template and custom rule overrides\n * export const ProjectSchema = defineCollection({\n * collectionName: \"projects\",\n * schema: z.object({\n * title: z.string(),\n * owner: RelationField({ collection: \"users\" }),\n * }),\n * permissions: {\n * template: \"owner-only\",\n * ownerField: \"owner\",\n * customRules: {\n * listRule: '@request.auth.id != \"\"',\n * },\n * },\n * });\n */\nexport function defineCollection(config: CollectionConfig): z.ZodObject<any> {\n const { collectionName, schema, permissions, indexes, ...futureOptions } = config;\n\n // Build metadata object\n const metadata: any = {\n collectionName,\n };\n\n // Add permissions if provided\n if (permissions) {\n metadata.permissions = permissions;\n }\n\n // Add indexes if provided\n if (indexes) {\n metadata.indexes = indexes;\n }\n\n // Add any future options\n if (Object.keys(futureOptions).length > 0) {\n Object.assign(metadata, futureOptions);\n }\n\n // Attach all metadata to schema using Zod's describe() method\n return schema.describe(JSON.stringify(metadata)) as z.ZodObject<any>;\n}\n","import type { PermissionSchema, PermissionTemplateConfig, RuleExpression } from \"../utils/permissions\";\n\n/**\n * Predefined permission templates for common access control patterns\n */\nexport const PermissionTemplates = {\n /**\n * Public access - anyone can perform all operations\n */\n public: (): PermissionSchema => ({\n listRule: \"\",\n viewRule: \"\",\n createRule: \"\",\n updateRule: \"\",\n deleteRule: \"\",\n }),\n\n /**\n * Authenticated users only - requires valid authentication for all operations\n */\n authenticated: (): PermissionSchema => ({\n listRule: '@request.auth.id != \"\"',\n viewRule: '@request.auth.id != \"\"',\n createRule: '@request.auth.id != \"\"',\n updateRule: '@request.auth.id != \"\"',\n deleteRule: '@request.auth.id != \"\"',\n }),\n\n /**\n * Owner-only access - users can only manage their own records\n * @param ownerField - Name of the relation field pointing to user (default: 'User')\n */\n ownerOnly: (ownerField: string = \"User\"): PermissionSchema => ({\n listRule: `@request.auth.id != \"\" && ${ownerField} = @request.auth.id`,\n viewRule: `@request.auth.id != \"\" && ${ownerField} = @request.auth.id`,\n createRule: '@request.auth.id != \"\"',\n updateRule: `@request.auth.id != \"\" && ${ownerField} = @request.auth.id`,\n deleteRule: `@request.auth.id != \"\" && ${ownerField} = @request.auth.id`,\n }),\n\n /**\n * Admin/superuser only access\n * Assumes a 'role' field exists with 'admin' value\n * @param roleField - Name of the role field (default: 'role')\n */\n adminOnly: (roleField: string = \"role\"): PermissionSchema => ({\n listRule: `@request.auth.id != \"\" && @request.auth.${roleField} = \"admin\"`,\n viewRule: `@request.auth.id != \"\" && @request.auth.${roleField} = \"admin\"`,\n createRule: `@request.auth.id != \"\" && @request.auth.${roleField} = \"admin\"`,\n updateRule: `@request.auth.id != \"\" && @request.auth.${roleField} = \"admin\"`,\n deleteRule: `@request.auth.id != \"\" && @request.auth.${roleField} = \"admin\"`,\n }),\n\n /**\n * Public read, authenticated write\n * Anyone can list/view, but only authenticated users can create/update/delete\n */\n readPublic: (): PermissionSchema => ({\n listRule: \"\",\n viewRule: \"\",\n createRule: '@request.auth.id != \"\"',\n updateRule: '@request.auth.id != \"\"',\n deleteRule: '@request.auth.id != \"\"',\n }),\n\n /**\n * Locked access - only superusers can perform operations\n * All rules are set to null (locked)\n */\n locked: (): PermissionSchema => ({\n listRule: null,\n viewRule: null,\n createRule: null,\n updateRule: null,\n deleteRule: null,\n }),\n\n /**\n * Read-only authenticated - authenticated users can read, no write access\n */\n readOnlyAuthenticated: (): PermissionSchema => ({\n listRule: '@request.auth.id != \"\"',\n viewRule: '@request.auth.id != \"\"',\n createRule: null,\n updateRule: null,\n deleteRule: null,\n }),\n};\n\n/**\n * Resolve template configuration to concrete permission schema\n * @param config - Template configuration or direct permission schema\n * @returns Resolved permission schema with all rules defined\n */\nexport function resolveTemplate(config: PermissionTemplateConfig): PermissionSchema {\n let baseRules: PermissionSchema;\n\n switch (config.template) {\n case \"public\":\n baseRules = PermissionTemplates.public();\n break;\n case \"authenticated\":\n baseRules = PermissionTemplates.authenticated();\n break;\n case \"owner-only\":\n baseRules = PermissionTemplates.ownerOnly(config.ownerField);\n break;\n case \"admin-only\":\n baseRules = PermissionTemplates.adminOnly(config.roleField);\n break;\n case \"read-public\":\n baseRules = PermissionTemplates.readPublic();\n break;\n case \"custom\":\n baseRules = {};\n break;\n default: {\n // Exhaustive check - TypeScript will error if we miss a template type\n const _exhaustive: never = config.template;\n throw new Error(`Unknown template type: ${_exhaustive}`);\n }\n }\n\n // Merge with custom rules if provided (custom rules override template rules)\n return {\n ...baseRules,\n ...config.customRules,\n };\n}\n\n/**\n * Check if a configuration is a template config or direct permission schema\n * @param config - Configuration to check\n * @returns True if it's a template configuration\n */\nexport function isTemplateConfig(\n config: PermissionTemplateConfig | PermissionSchema\n): config is PermissionTemplateConfig {\n return \"template\" in config;\n}\n\n/**\n * Check if a configuration is a direct permission schema\n * @param config - Configuration to check\n * @returns True if it's a direct permission schema\n */\nexport function isPermissionSchema(config: PermissionTemplateConfig | PermissionSchema): config is PermissionSchema {\n return (\n \"listRule\" in config ||\n \"viewRule\" in config ||\n \"createRule\" in config ||\n \"updateRule\" in config ||\n \"deleteRule\" in config ||\n \"manageRule\" in config\n );\n}\n\n/**\n * Validation result for permission configuration\n */\nexport interface PermissionValidationResult {\n valid: boolean;\n errors: string[];\n warnings: string[];\n}\n\n/**\n * Validate a permission configuration\n * @param config - Permission configuration to validate\n * @param isAuthCollection - Whether this is for an auth collection\n * @returns Validation result\n */\nexport function validatePermissionConfig(\n config: PermissionTemplateConfig | PermissionSchema,\n isAuthCollection: boolean = false\n): PermissionValidationResult {\n const result: PermissionValidationResult = {\n valid: true,\n errors: [],\n warnings: [],\n };\n\n // Resolve to permission schema\n let permissions: PermissionSchema;\n if (isTemplateConfig(config)) {\n // Validate template config\n if (config.template === \"owner-only\" && !config.ownerField) {\n result.warnings.push(\"owner-only template without ownerField specified - using default 'User'\");\n }\n if (config.template === \"admin-only\" && !config.roleField) {\n result.warnings.push(\"admin-only template without roleField specified - using default 'role'\");\n }\n permissions = resolveTemplate(config);\n } else {\n permissions = config;\n }\n\n // Validate manageRule usage\n if (permissions.manageRule !== undefined && !isAuthCollection) {\n result.errors.push(\"manageRule is only valid for auth collections\");\n result.valid = false;\n }\n\n // Validate rule expressions\n const ruleTypes: (keyof PermissionSchema)[] = [\"listRule\", \"viewRule\", \"createRule\", \"updateRule\", \"deleteRule\"];\n if (isAuthCollection) {\n ruleTypes.push(\"manageRule\");\n }\n\n for (const ruleType of ruleTypes) {\n const rule = permissions[ruleType];\n if (rule !== undefined && rule !== null && rule !== \"\") {\n const ruleValidation = validateRuleExpression(rule);\n if (!ruleValidation.valid) {\n result.errors.push(`${ruleType}: ${ruleValidation.errors.join(\", \")}`);\n result.valid = false;\n }\n result.warnings.push(...ruleValidation.warnings.map((w) => `${ruleType}: ${w}`));\n }\n }\n\n return result;\n}\n\n/**\n * Validate a single rule expression for basic syntax\n * @param expression - Rule expression to validate\n * @returns Validation result\n */\nexport function validateRuleExpression(expression: RuleExpression): PermissionValidationResult {\n const result: PermissionValidationResult = {\n valid: true,\n errors: [],\n warnings: [],\n };\n\n // Null and empty string are always valid\n if (expression === null || expression === \"\") {\n return result;\n }\n\n // Check for balanced parentheses\n let parenCount = 0;\n for (const char of expression) {\n if (char === \"(\") parenCount++;\n if (char === \")\") parenCount--;\n if (parenCount < 0) {\n result.errors.push(\"Unbalanced parentheses\");\n result.valid = false;\n return result;\n }\n }\n if (parenCount !== 0) {\n result.errors.push(\"Unbalanced parentheses\");\n result.valid = false;\n }\n\n // Check for common mistakes\n if (expression.includes(\"==\")) {\n result.warnings.push(\"Use '=' instead of '==' for equality comparison\");\n }\n\n // Check for valid @request references\n const requestRefs = expression.match(/@request\\.[a-zA-Z_][a-zA-Z0-9_.]*/g) || [];\n for (const ref of requestRefs) {\n const isValid =\n ref.startsWith(\"@request.auth.\") ||\n ref === \"@request.method\" ||\n ref === \"@request.context\" ||\n ref.startsWith(\"@request.body.\") ||\n ref.startsWith(\"@request.query.\") ||\n ref.startsWith(\"@request.headers.\");\n\n if (!isValid) {\n result.errors.push(`Invalid @request reference: '${ref}'`);\n result.valid = false;\n }\n }\n\n return result;\n}\n\n/**\n * Create a custom permission schema with type safety\n * @param permissions - Partial permission schema\n * @returns Complete permission schema with null defaults\n */\nexport function createPermissions(permissions: Partial<PermissionSchema>): PermissionSchema {\n return {\n listRule: permissions.listRule ?? null,\n viewRule: permissions.viewRule ?? null,\n createRule: permissions.createRule ?? null,\n updateRule: permissions.updateRule ?? null,\n deleteRule: permissions.deleteRule ?? null,\n manageRule: permissions.manageRule ?? null,\n };\n}\n\n/**\n * Merge multiple permission schemas, with later schemas taking precedence\n * @param schemas - Permission schemas to merge\n * @returns Merged permission schema\n */\nexport function mergePermissions(...schemas: Partial<PermissionSchema>[]): PermissionSchema {\n const merged: PermissionSchema = {\n listRule: null,\n viewRule: null,\n createRule: null,\n updateRule: null,\n deleteRule: null,\n manageRule: null,\n };\n\n for (const schema of schemas) {\n if (schema.listRule !== undefined) merged.listRule = schema.listRule;\n if (schema.viewRule !== undefined) merged.viewRule = schema.viewRule;\n if (schema.createRule !== undefined) merged.createRule = schema.createRule;\n if (schema.updateRule !== undefined) merged.updateRule = schema.updateRule;\n if (schema.deleteRule !== undefined) merged.deleteRule = schema.deleteRule;\n if (schema.manageRule !== undefined) merged.manageRule = schema.manageRule;\n }\n\n return merged;\n}\n","import { z } from \"zod\";\n\nexport const StatusEnum = z.enum([\n \"draft\", // Initial proposal stage (RequestDraft, ProjectDraft)\n \"active\", // Work in progress\n \"complete\", // Fully completed project\n \"fail\", // Failed project at any stage\n]);\nexport type StatusEnumType = z.infer<typeof StatusEnum>;\n","import { z } from \"zod\";\nimport { StatusEnum } from \"../enums\";\nimport {\n baseImageFileSchema,\n defineCollection,\n inputImageFileSchema,\n omitImageFilesSchema,\n RelationField,\n RelationsField,\n} from \"./base\";\n\nexport const ProjectInputSchema = z\n .object({\n // Required fields\n title: z.string(),\n content: z.string(),\n status: StatusEnum,\n summary: z.string().optional(),\n\n OwnerUser: RelationField({ collection: \"Users\" }),\n SubscriberUsers: RelationsField({ collection: \"Users\" }),\n })\n .extend(inputImageFileSchema);\n\nexport const ProjectSchema = ProjectInputSchema.omit(omitImageFilesSchema).extend(baseImageFileSchema);\n\n// Define collection with permissions using template and custom overrides\n// Uses 'owner-only' template but allows all authenticated users to list projects\n// This allows users to see all projects but only manage their own\nexport const ProjectCollection = defineCollection({\n collectionName: \"Projects\",\n schema: ProjectSchema,\n permissions: {\n template: \"owner-only\",\n ownerField: \"OwnerUser\",\n customRules: {\n listRule: '@request.auth.id != \"\"',\n viewRule: '@request.auth.id != \"\" && (OwnerUser = @request.auth.id || SubscriberUsers ?= @request.auth.id)',\n },\n },\n});\n","import { z } from \"zod\";\nimport { baseSchema, defineCollection } from \"./base\";\n\n/** -- User Collections -- */\n// Input schema for forms (includes passwordConfirm for validation)\nexport const UserInputSchema = z.object({\n name: z.string().optional(),\n email: z.string().email(),\n password: z.string().min(8, \"Password must be at least 8 characters\"),\n passwordConfirm: z.string(),\n avatar: z.instanceof(File).optional(),\n});\n\n// Database schema (excludes passwordConfirm, includes avatar as file field)\nexport const UserCollectionSchema = z.object({\n name: z.string().optional(),\n email: z.string().email(),\n password: z.string().min(8, \"Password must be at least 8 characters\"),\n avatar: z.instanceof(File).optional(),\n});\n\n// Full schema with base fields for type inference (used in types.ts)\n// This includes id, collectionId, collectionName from baseSchema\nexport const UserSchema = UserCollectionSchema.extend(baseSchema);\n\n// Matches PocketBase's default users collection configuration\nexport const UserCollection = defineCollection({\n collectionName: \"Users\",\n schema: UserSchema,\n permissions: {\n // Users can list their own profile\n listRule: \"id = @request.auth.id\",\n // Users can view their own profile\n viewRule: \"id = @request.auth.id\",\n // Anyone can create an account (sign up)\n createRule: \"\",\n // Users can only update their own profile\n updateRule: \"id = @request.auth.id\",\n // Users can only delete their own account\n deleteRule: \"id = @request.auth.id\",\n // manageRule is null in PocketBase default (not set)\n },\n indexes: [\n // PocketBase's default indexes for auth collections\n \"CREATE UNIQUE INDEX `idx_tokenKey__pb_users_auth_` ON `users` (`tokenKey`)\",\n \"CREATE UNIQUE INDEX `idx_email__pb_users_auth_` ON `users` (`email`) WHERE `email` != ''\",\n ],\n});\n"]}
package/dist/schema.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  import { b as PermissionTemplateConfig, P as PermissionSchema, R as RuleExpression } from './permissions-ZHafVSIx.cjs';
3
3
  export { A as APIRuleType, a as PermissionTemplate } from './permissions-ZHafVSIx.cjs';
4
- export { P as ProjectInputSchema, a as ProjectSchema, U as UserInputSchema, b as UserSchema } from './user-_AM523hb.cjs';
4
+ export { b as ProjectCollection, P as ProjectInputSchema, a as ProjectSchema, e as UserCollection, c as UserCollectionSchema, U as UserInputSchema, d as UserSchema } from './user-DTJQIj4K.cjs';
5
5
 
6
6
  /**
7
7
  * Base schema fields that PocketBase automatically adds to all records
@@ -161,17 +161,17 @@ interface RelationsConfig extends RelationConfig {
161
161
  * // Single relation to users collection
162
162
  * const PostSchema = z.object({
163
163
  * title: z.string(),
164
- * author: relationField({ collection: 'users' }),
164
+ * author: RelationField({ collection: 'users' }),
165
165
  * });
166
166
  *
167
167
  * @example
168
168
  * // Relation with cascade delete
169
169
  * const CommentSchema = z.object({
170
170
  * content: z.string(),
171
- * post: relationField({ collection: 'posts', cascadeDelete: true }),
171
+ * post: RelationField({ collection: 'posts', cascadeDelete: true }),
172
172
  * });
173
173
  */
174
- declare function relationField(config: RelationConfig): z.ZodString;
174
+ declare function RelationField(config: RelationConfig): z.ZodString;
175
175
  /**
176
176
  * Creates a multiple relation field schema with explicit collection target
177
177
  * Maps to PocketBase 'relation' field type with maxSelect>1
@@ -186,21 +186,21 @@ declare function relationField(config: RelationConfig): z.ZodString;
186
186
  * // Multiple relations to tags collection
187
187
  * const PostSchema = z.object({
188
188
  * title: z.string(),
189
- * tags: relationsField({ collection: 'tags' }),
189
+ * tags: RelationsField({ collection: 'tags' }),
190
190
  * });
191
191
  *
192
192
  * @example
193
193
  * // Relations with min/max constraints
194
194
  * const ProjectSchema = z.object({
195
195
  * title: z.string(),
196
- * collaborators: relationsField({
196
+ * collaborators: RelationsField({
197
197
  * collection: 'users',
198
198
  * minSelect: 1,
199
199
  * maxSelect: 10,
200
200
  * }),
201
201
  * });
202
202
  */
203
- declare function relationsField(config: RelationsConfig): z.ZodArray<z.ZodString, "many">;
203
+ declare function RelationsField(config: RelationsConfig): z.ZodArray<z.ZodString, "many">;
204
204
  /**
205
205
  * Extracts relation metadata from a Zod type's description
206
206
  * Used internally by the analyzer to detect explicit relation definitions
@@ -304,6 +304,96 @@ declare function withPermissions<T extends z.ZodTypeAny>(schema: T, config: Perm
304
304
  * );
305
305
  */
306
306
  declare function withIndexes<T extends z.ZodTypeAny>(schema: T, indexes: string[]): T;
307
+ /**
308
+ * Configuration options for defining a collection
309
+ */
310
+ interface CollectionConfig {
311
+ /**
312
+ * The name of the PocketBase collection
313
+ * This will be used when generating migrations
314
+ */
315
+ collectionName: string;
316
+ /**
317
+ * The Zod schema definition for the collection
318
+ */
319
+ schema: z.ZodObject<any>;
320
+ /**
321
+ * Optional permission configuration
322
+ * Can be a template-based config or custom permission rules
323
+ */
324
+ permissions?: PermissionTemplateConfig | PermissionSchema;
325
+ /**
326
+ * Optional array of index SQL statements
327
+ * Example: ['CREATE UNIQUE INDEX idx_users_email ON users (email)']
328
+ */
329
+ indexes?: string[];
330
+ /**
331
+ * Future extensibility - additional options can be added here
332
+ */
333
+ [key: string]: unknown;
334
+ }
335
+ /**
336
+ * High-level wrapper for defining a PocketBase collection with all metadata
337
+ *
338
+ * This is the recommended way to define collections as it provides a single
339
+ * entry point for collection name, schema, permissions, indexes, and future features.
340
+ *
341
+ * @param config - Collection configuration object
342
+ * @returns The schema with all metadata attached
343
+ *
344
+ * @example
345
+ * // Basic collection with permissions
346
+ * export const PostSchema = defineCollection({
347
+ * collectionName: "posts",
348
+ * schema: z.object({
349
+ * title: z.string(),
350
+ * content: z.string(),
351
+ * author: RelationField({ collection: "users" }),
352
+ * }),
353
+ * permissions: {
354
+ * template: "owner-only",
355
+ * ownerField: "author",
356
+ * },
357
+ * });
358
+ *
359
+ * @example
360
+ * // Collection with permissions and indexes
361
+ * export const UserSchema = defineCollection({
362
+ * collectionName: "users",
363
+ * schema: z.object({
364
+ * name: z.string(),
365
+ * email: z.string().email(),
366
+ * }),
367
+ * permissions: {
368
+ * listRule: "id = @request.auth.id",
369
+ * viewRule: "id = @request.auth.id",
370
+ * createRule: "",
371
+ * updateRule: "id = @request.auth.id",
372
+ * deleteRule: "id = @request.auth.id",
373
+ * },
374
+ * indexes: [
375
+ * "CREATE UNIQUE INDEX idx_users_email ON users (email)",
376
+ * ],
377
+ * });
378
+ *
379
+ * @example
380
+ * // Collection with template and custom rule overrides
381
+ * export const ProjectSchema = defineCollection({
382
+ * collectionName: "projects",
383
+ * schema: z.object({
384
+ * title: z.string(),
385
+ * owner: RelationField({ collection: "users" }),
386
+ * }),
387
+ * permissions: {
388
+ * template: "owner-only",
389
+ * ownerField: "owner",
390
+ * customRules: {
391
+ * listRule: '@request.auth.id != ""',
392
+ * },
393
+ * },
394
+ * });
395
+ */
396
+ declare function defineCollection(config: CollectionConfig): z.ZodObject<any>;
307
397
 
308
398
  /**
309
399
  * Predefined permission templates for common access control patterns
@@ -395,4 +485,4 @@ declare function createPermissions(permissions: Partial<PermissionSchema>): Perm
395
485
  */
396
486
  declare function mergePermissions(...schemas: Partial<PermissionSchema>[]): PermissionSchema;
397
487
 
398
- export { PermissionSchema, PermissionTemplateConfig, PermissionTemplates, type PermissionValidationResult, type RelationConfig, type RelationsConfig, RuleExpression, baseImageFileSchema, baseSchema, baseSchemaWithTimestamps, boolField, createPermissions, dateField, editorField, emailField, extractRelationMetadata, fileField, filesField, geoPointField, inputImageFileSchema, isPermissionSchema, isTemplateConfig, jsonField, mergePermissions, numberField, omitImageFilesSchema, relationField, relationsField, resolveTemplate, selectField, textField, urlField, validatePermissionConfig, validateRuleExpression, withIndexes, withPermissions };
488
+ export { type CollectionConfig, PermissionSchema, PermissionTemplateConfig, PermissionTemplates, type PermissionValidationResult, type RelationConfig, RelationField, type RelationsConfig, RelationsField, RuleExpression, baseImageFileSchema, baseSchema, baseSchemaWithTimestamps, boolField, createPermissions, dateField, defineCollection, editorField, emailField, extractRelationMetadata, fileField, filesField, geoPointField, inputImageFileSchema, isPermissionSchema, isTemplateConfig, jsonField, mergePermissions, numberField, omitImageFilesSchema, resolveTemplate, selectField, textField, urlField, validatePermissionConfig, validateRuleExpression, withIndexes, withPermissions };
package/dist/schema.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  import { b as PermissionTemplateConfig, P as PermissionSchema, R as RuleExpression } from './permissions-ZHafVSIx.js';
3
3
  export { A as APIRuleType, a as PermissionTemplate } from './permissions-ZHafVSIx.js';
4
- export { P as ProjectInputSchema, a as ProjectSchema, U as UserInputSchema, b as UserSchema } from './user-_AM523hb.js';
4
+ export { b as ProjectCollection, P as ProjectInputSchema, a as ProjectSchema, e as UserCollection, c as UserCollectionSchema, U as UserInputSchema, d as UserSchema } from './user-DTJQIj4K.js';
5
5
 
6
6
  /**
7
7
  * Base schema fields that PocketBase automatically adds to all records
@@ -161,17 +161,17 @@ interface RelationsConfig extends RelationConfig {
161
161
  * // Single relation to users collection
162
162
  * const PostSchema = z.object({
163
163
  * title: z.string(),
164
- * author: relationField({ collection: 'users' }),
164
+ * author: RelationField({ collection: 'users' }),
165
165
  * });
166
166
  *
167
167
  * @example
168
168
  * // Relation with cascade delete
169
169
  * const CommentSchema = z.object({
170
170
  * content: z.string(),
171
- * post: relationField({ collection: 'posts', cascadeDelete: true }),
171
+ * post: RelationField({ collection: 'posts', cascadeDelete: true }),
172
172
  * });
173
173
  */
174
- declare function relationField(config: RelationConfig): z.ZodString;
174
+ declare function RelationField(config: RelationConfig): z.ZodString;
175
175
  /**
176
176
  * Creates a multiple relation field schema with explicit collection target
177
177
  * Maps to PocketBase 'relation' field type with maxSelect>1
@@ -186,21 +186,21 @@ declare function relationField(config: RelationConfig): z.ZodString;
186
186
  * // Multiple relations to tags collection
187
187
  * const PostSchema = z.object({
188
188
  * title: z.string(),
189
- * tags: relationsField({ collection: 'tags' }),
189
+ * tags: RelationsField({ collection: 'tags' }),
190
190
  * });
191
191
  *
192
192
  * @example
193
193
  * // Relations with min/max constraints
194
194
  * const ProjectSchema = z.object({
195
195
  * title: z.string(),
196
- * collaborators: relationsField({
196
+ * collaborators: RelationsField({
197
197
  * collection: 'users',
198
198
  * minSelect: 1,
199
199
  * maxSelect: 10,
200
200
  * }),
201
201
  * });
202
202
  */
203
- declare function relationsField(config: RelationsConfig): z.ZodArray<z.ZodString, "many">;
203
+ declare function RelationsField(config: RelationsConfig): z.ZodArray<z.ZodString, "many">;
204
204
  /**
205
205
  * Extracts relation metadata from a Zod type's description
206
206
  * Used internally by the analyzer to detect explicit relation definitions
@@ -304,6 +304,96 @@ declare function withPermissions<T extends z.ZodTypeAny>(schema: T, config: Perm
304
304
  * );
305
305
  */
306
306
  declare function withIndexes<T extends z.ZodTypeAny>(schema: T, indexes: string[]): T;
307
+ /**
308
+ * Configuration options for defining a collection
309
+ */
310
+ interface CollectionConfig {
311
+ /**
312
+ * The name of the PocketBase collection
313
+ * This will be used when generating migrations
314
+ */
315
+ collectionName: string;
316
+ /**
317
+ * The Zod schema definition for the collection
318
+ */
319
+ schema: z.ZodObject<any>;
320
+ /**
321
+ * Optional permission configuration
322
+ * Can be a template-based config or custom permission rules
323
+ */
324
+ permissions?: PermissionTemplateConfig | PermissionSchema;
325
+ /**
326
+ * Optional array of index SQL statements
327
+ * Example: ['CREATE UNIQUE INDEX idx_users_email ON users (email)']
328
+ */
329
+ indexes?: string[];
330
+ /**
331
+ * Future extensibility - additional options can be added here
332
+ */
333
+ [key: string]: unknown;
334
+ }
335
+ /**
336
+ * High-level wrapper for defining a PocketBase collection with all metadata
337
+ *
338
+ * This is the recommended way to define collections as it provides a single
339
+ * entry point for collection name, schema, permissions, indexes, and future features.
340
+ *
341
+ * @param config - Collection configuration object
342
+ * @returns The schema with all metadata attached
343
+ *
344
+ * @example
345
+ * // Basic collection with permissions
346
+ * export const PostSchema = defineCollection({
347
+ * collectionName: "posts",
348
+ * schema: z.object({
349
+ * title: z.string(),
350
+ * content: z.string(),
351
+ * author: RelationField({ collection: "users" }),
352
+ * }),
353
+ * permissions: {
354
+ * template: "owner-only",
355
+ * ownerField: "author",
356
+ * },
357
+ * });
358
+ *
359
+ * @example
360
+ * // Collection with permissions and indexes
361
+ * export const UserSchema = defineCollection({
362
+ * collectionName: "users",
363
+ * schema: z.object({
364
+ * name: z.string(),
365
+ * email: z.string().email(),
366
+ * }),
367
+ * permissions: {
368
+ * listRule: "id = @request.auth.id",
369
+ * viewRule: "id = @request.auth.id",
370
+ * createRule: "",
371
+ * updateRule: "id = @request.auth.id",
372
+ * deleteRule: "id = @request.auth.id",
373
+ * },
374
+ * indexes: [
375
+ * "CREATE UNIQUE INDEX idx_users_email ON users (email)",
376
+ * ],
377
+ * });
378
+ *
379
+ * @example
380
+ * // Collection with template and custom rule overrides
381
+ * export const ProjectSchema = defineCollection({
382
+ * collectionName: "projects",
383
+ * schema: z.object({
384
+ * title: z.string(),
385
+ * owner: RelationField({ collection: "users" }),
386
+ * }),
387
+ * permissions: {
388
+ * template: "owner-only",
389
+ * ownerField: "owner",
390
+ * customRules: {
391
+ * listRule: '@request.auth.id != ""',
392
+ * },
393
+ * },
394
+ * });
395
+ */
396
+ declare function defineCollection(config: CollectionConfig): z.ZodObject<any>;
307
397
 
308
398
  /**
309
399
  * Predefined permission templates for common access control patterns
@@ -395,4 +485,4 @@ declare function createPermissions(permissions: Partial<PermissionSchema>): Perm
395
485
  */
396
486
  declare function mergePermissions(...schemas: Partial<PermissionSchema>[]): PermissionSchema;
397
487
 
398
- export { PermissionSchema, PermissionTemplateConfig, PermissionTemplates, type PermissionValidationResult, type RelationConfig, type RelationsConfig, RuleExpression, baseImageFileSchema, baseSchema, baseSchemaWithTimestamps, boolField, createPermissions, dateField, editorField, emailField, extractRelationMetadata, fileField, filesField, geoPointField, inputImageFileSchema, isPermissionSchema, isTemplateConfig, jsonField, mergePermissions, numberField, omitImageFilesSchema, relationField, relationsField, resolveTemplate, selectField, textField, urlField, validatePermissionConfig, validateRuleExpression, withIndexes, withPermissions };
488
+ export { type CollectionConfig, PermissionSchema, PermissionTemplateConfig, PermissionTemplates, type PermissionValidationResult, type RelationConfig, RelationField, type RelationsConfig, RelationsField, RuleExpression, baseImageFileSchema, baseSchema, baseSchemaWithTimestamps, boolField, createPermissions, dateField, defineCollection, editorField, emailField, extractRelationMetadata, fileField, filesField, geoPointField, inputImageFileSchema, isPermissionSchema, isTemplateConfig, jsonField, mergePermissions, numberField, omitImageFilesSchema, resolveTemplate, selectField, textField, urlField, validatePermissionConfig, validateRuleExpression, withIndexes, withPermissions };