@opensaas/stack-core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/.turbo/turbo-build.log +4 -0
  2. package/README.md +447 -0
  3. package/dist/access/engine.d.ts +73 -0
  4. package/dist/access/engine.d.ts.map +1 -0
  5. package/dist/access/engine.js +244 -0
  6. package/dist/access/engine.js.map +1 -0
  7. package/dist/access/field-transforms.d.ts +47 -0
  8. package/dist/access/field-transforms.d.ts.map +1 -0
  9. package/dist/access/field-transforms.js +2 -0
  10. package/dist/access/field-transforms.js.map +1 -0
  11. package/dist/access/index.d.ts +3 -0
  12. package/dist/access/index.d.ts.map +1 -0
  13. package/dist/access/index.js +2 -0
  14. package/dist/access/index.js.map +1 -0
  15. package/dist/access/types.d.ts +83 -0
  16. package/dist/access/types.d.ts.map +1 -0
  17. package/dist/access/types.js +2 -0
  18. package/dist/access/types.js.map +1 -0
  19. package/dist/config/index.d.ts +39 -0
  20. package/dist/config/index.d.ts.map +1 -0
  21. package/dist/config/index.js +38 -0
  22. package/dist/config/index.js.map +1 -0
  23. package/dist/config/types.d.ts +413 -0
  24. package/dist/config/types.d.ts.map +1 -0
  25. package/dist/config/types.js +2 -0
  26. package/dist/config/types.js.map +1 -0
  27. package/dist/context/index.d.ts +31 -0
  28. package/dist/context/index.d.ts.map +1 -0
  29. package/dist/context/index.js +524 -0
  30. package/dist/context/index.js.map +1 -0
  31. package/dist/context/nested-operations.d.ts +10 -0
  32. package/dist/context/nested-operations.d.ts.map +1 -0
  33. package/dist/context/nested-operations.js +261 -0
  34. package/dist/context/nested-operations.js.map +1 -0
  35. package/dist/fields/index.d.ts +78 -0
  36. package/dist/fields/index.d.ts.map +1 -0
  37. package/dist/fields/index.js +381 -0
  38. package/dist/fields/index.js.map +1 -0
  39. package/dist/hooks/index.d.ts +58 -0
  40. package/dist/hooks/index.d.ts.map +1 -0
  41. package/dist/hooks/index.js +79 -0
  42. package/dist/hooks/index.js.map +1 -0
  43. package/dist/index.d.ts +11 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +12 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/lib/case-utils.d.ts +49 -0
  48. package/dist/lib/case-utils.d.ts.map +1 -0
  49. package/dist/lib/case-utils.js +68 -0
  50. package/dist/lib/case-utils.js.map +1 -0
  51. package/dist/lib/case-utils.test.d.ts +2 -0
  52. package/dist/lib/case-utils.test.d.ts.map +1 -0
  53. package/dist/lib/case-utils.test.js +101 -0
  54. package/dist/lib/case-utils.test.js.map +1 -0
  55. package/dist/utils/password.d.ts +81 -0
  56. package/dist/utils/password.d.ts.map +1 -0
  57. package/dist/utils/password.js +132 -0
  58. package/dist/utils/password.js.map +1 -0
  59. package/dist/validation/schema.d.ts +17 -0
  60. package/dist/validation/schema.d.ts.map +1 -0
  61. package/dist/validation/schema.js +42 -0
  62. package/dist/validation/schema.js.map +1 -0
  63. package/dist/validation/schema.test.d.ts +2 -0
  64. package/dist/validation/schema.test.d.ts.map +1 -0
  65. package/dist/validation/schema.test.js +143 -0
  66. package/dist/validation/schema.test.js.map +1 -0
  67. package/docs/type-distribution-fix.md +136 -0
  68. package/package.json +48 -0
  69. package/src/access/engine.ts +360 -0
  70. package/src/access/field-transforms.ts +99 -0
  71. package/src/access/index.ts +20 -0
  72. package/src/access/types.ts +103 -0
  73. package/src/config/index.ts +71 -0
  74. package/src/config/types.ts +478 -0
  75. package/src/context/index.ts +814 -0
  76. package/src/context/nested-operations.ts +412 -0
  77. package/src/fields/index.ts +438 -0
  78. package/src/hooks/index.ts +132 -0
  79. package/src/index.ts +62 -0
  80. package/src/lib/case-utils.test.ts +127 -0
  81. package/src/lib/case-utils.ts +74 -0
  82. package/src/utils/password.ts +147 -0
  83. package/src/validation/schema.test.ts +171 -0
  84. package/src/validation/schema.ts +59 -0
  85. package/tests/access-relationships.test.ts +613 -0
  86. package/tests/access.test.ts +499 -0
  87. package/tests/config.test.ts +195 -0
  88. package/tests/context.test.ts +248 -0
  89. package/tests/hooks.test.ts +417 -0
  90. package/tests/password-type-distribution.test.ts +155 -0
  91. package/tests/password-types.test.ts +147 -0
  92. package/tests/password.test.ts +249 -0
  93. package/tsconfig.json +12 -0
  94. package/tsconfig.tsbuildinfo +1 -0
  95. package/vitest.config.ts +27 -0
@@ -0,0 +1,381 @@
1
+ import { z } from 'zod';
2
+ import { hashPassword, isHashedPassword, HashedPassword } from '../utils/password.js';
3
+ /**
4
+ * Format field name for display in error messages
5
+ */
6
+ function formatFieldName(fieldName) {
7
+ return fieldName
8
+ .replace(/([A-Z])/g, ' $1')
9
+ .replace(/^./, (str) => str.toUpperCase())
10
+ .trim();
11
+ }
12
+ /**
13
+ * Text field
14
+ */
15
+ export function text(options) {
16
+ return {
17
+ type: 'text',
18
+ ...options,
19
+ getZodSchema: (fieldName, operation) => {
20
+ const validation = options?.validation;
21
+ const isRequired = validation?.isRequired;
22
+ const length = validation?.length;
23
+ const minLength = length?.min && length.min > 0 ? length.min : 1;
24
+ const baseSchema = z.string({
25
+ message: `${formatFieldName(fieldName)} must be text`,
26
+ });
27
+ const withMin = isRequired || length?.min !== undefined
28
+ ? baseSchema.min(minLength, {
29
+ message: minLength > 1
30
+ ? `${formatFieldName(fieldName)} must be at least ${minLength} characters`
31
+ : `${formatFieldName(fieldName)} is required`,
32
+ })
33
+ : baseSchema;
34
+ const withMax = length?.max !== undefined
35
+ ? withMin.max(length.max, {
36
+ message: `${formatFieldName(fieldName)} must be at most ${length.max} characters`,
37
+ })
38
+ : withMin;
39
+ if (isRequired && operation === 'update') {
40
+ return z.union([withMax, z.undefined()]);
41
+ }
42
+ return !isRequired ? withMax.optional() : withMax;
43
+ },
44
+ getPrismaType: () => {
45
+ const validation = options?.validation;
46
+ const isRequired = validation?.isRequired;
47
+ let modifiers = '';
48
+ // Optional modifier
49
+ if (!isRequired) {
50
+ modifiers += '?';
51
+ }
52
+ // Unique/index modifiers
53
+ if (options?.isIndexed === 'unique') {
54
+ modifiers += ' @unique';
55
+ }
56
+ else if (options?.isIndexed === true) {
57
+ modifiers += ' @index';
58
+ }
59
+ return {
60
+ type: 'String',
61
+ modifiers: modifiers || undefined,
62
+ };
63
+ },
64
+ getTypeScriptType: () => {
65
+ const validation = options?.validation;
66
+ const isRequired = validation?.isRequired;
67
+ return {
68
+ type: 'string',
69
+ optional: !isRequired,
70
+ };
71
+ },
72
+ };
73
+ }
74
+ /**
75
+ * Integer field
76
+ */
77
+ export function integer(options) {
78
+ return {
79
+ type: 'integer',
80
+ ...options,
81
+ getZodSchema: (fieldName, operation) => {
82
+ const baseSchema = z.number({
83
+ message: `${formatFieldName(fieldName)} must be a number`,
84
+ });
85
+ const withMin = options?.validation?.min !== undefined
86
+ ? baseSchema.min(options.validation.min, {
87
+ message: `${formatFieldName(fieldName)} must be at least ${options.validation.min}`,
88
+ })
89
+ : baseSchema;
90
+ const withMax = options?.validation?.max !== undefined
91
+ ? withMin.max(options.validation.max, {
92
+ message: `${formatFieldName(fieldName)} must be at most ${options.validation.max}`,
93
+ })
94
+ : withMin;
95
+ return !options?.validation?.isRequired || operation === 'update'
96
+ ? withMax.optional()
97
+ : withMax;
98
+ },
99
+ getPrismaType: () => {
100
+ const isRequired = options?.validation?.isRequired;
101
+ return {
102
+ type: 'Int',
103
+ modifiers: isRequired ? undefined : '?',
104
+ };
105
+ },
106
+ getTypeScriptType: () => {
107
+ const isRequired = options?.validation?.isRequired;
108
+ return {
109
+ type: 'number',
110
+ optional: !isRequired,
111
+ };
112
+ },
113
+ };
114
+ }
115
+ /**
116
+ * Checkbox (boolean) field
117
+ */
118
+ export function checkbox(options) {
119
+ return {
120
+ type: 'checkbox',
121
+ ...options,
122
+ getZodSchema: () => {
123
+ return z.boolean().optional();
124
+ },
125
+ getPrismaType: () => {
126
+ const hasDefault = options?.defaultValue !== undefined;
127
+ let modifiers = '';
128
+ if (hasDefault) {
129
+ modifiers = ` @default(${options.defaultValue})`;
130
+ }
131
+ return {
132
+ type: 'Boolean',
133
+ modifiers: modifiers || undefined,
134
+ };
135
+ },
136
+ getTypeScriptType: () => {
137
+ return {
138
+ type: 'boolean',
139
+ optional: options?.defaultValue === undefined,
140
+ };
141
+ },
142
+ };
143
+ }
144
+ /**
145
+ * Timestamp (DateTime) field
146
+ */
147
+ export function timestamp(options) {
148
+ return {
149
+ type: 'timestamp',
150
+ ...options,
151
+ getZodSchema: () => {
152
+ return z.union([z.date(), z.iso.datetime()]).optional();
153
+ },
154
+ getPrismaType: () => {
155
+ let modifiers = '?';
156
+ // Check for default value
157
+ if (options?.defaultValue &&
158
+ typeof options.defaultValue === 'object' &&
159
+ 'kind' in options.defaultValue &&
160
+ options.defaultValue.kind === 'now') {
161
+ modifiers = ' @default(now())';
162
+ }
163
+ return {
164
+ type: 'DateTime',
165
+ modifiers,
166
+ };
167
+ },
168
+ getTypeScriptType: () => {
169
+ const hasDefault = options?.defaultValue &&
170
+ typeof options.defaultValue === 'object' &&
171
+ 'kind' in options.defaultValue &&
172
+ options.defaultValue.kind === 'now';
173
+ return {
174
+ type: 'Date',
175
+ optional: !hasDefault,
176
+ };
177
+ },
178
+ };
179
+ }
180
+ /**
181
+ * Password field (automatically hashed using bcrypt)
182
+ *
183
+ * **Security Features:**
184
+ * - Passwords are automatically hashed during create/update operations
185
+ * - Uses bcrypt with cost factor 10 (good balance of security and performance)
186
+ * - Already-hashed passwords are not re-hashed (idempotent)
187
+ * - Password values in query results include a `compare()` method for authentication
188
+ *
189
+ * **Usage Example:**
190
+ * ```typescript
191
+ * // In opensaas.config.ts
192
+ * fields: {
193
+ * password: password({
194
+ * validation: { isRequired: true }
195
+ * })
196
+ * }
197
+ *
198
+ * // Creating a user - password is automatically hashed
199
+ * const user = await context.db.user.create({
200
+ * data: {
201
+ * email: 'user@example.com',
202
+ * password: 'plaintextPassword' // Automatically hashed before storage
203
+ * }
204
+ * })
205
+ *
206
+ * // Authenticating - use the compare() method
207
+ * const user = await context.db.user.findUnique({
208
+ * where: { email: 'user@example.com' }
209
+ * })
210
+ *
211
+ * if (user && await user.password.compare('plaintextPassword')) {
212
+ * // Password is correct - login successful
213
+ * }
214
+ * ```
215
+ *
216
+ * **Important Notes:**
217
+ * - Password fields are excluded from read operations by default in access control
218
+ * - Always use the `compare()` method to verify passwords - never compare strings directly
219
+ * - The password field value has type `HashedPassword` which extends string with compare()
220
+ * - Empty strings and undefined values are skipped (not hashed) to allow partial updates
221
+ *
222
+ * **Implementation Details:**
223
+ * - Uses field-level hooks (`resolveInput` and `resolveOutput`) for automatic transformations
224
+ * - The hashing happens via `hooks.resolveInput` during create/update operations
225
+ * - The wrapping happens via `hooks.resolveOutput` during read operations
226
+ * - This pattern allows third-party field types to define their own transformations
227
+ *
228
+ * @param options - Field configuration options
229
+ * @returns Password field configuration
230
+ */
231
+ export function password(options) {
232
+ return {
233
+ type: 'password',
234
+ ...options,
235
+ typePatch: {
236
+ resultType: "import('@opensaas/stack-core').HashedPassword",
237
+ patchScope: 'scalars-only',
238
+ },
239
+ ui: {
240
+ ...options?.ui,
241
+ valueForClientSerialization: ({ value }) => ({ isSet: !!value }),
242
+ },
243
+ hooks: {
244
+ // Hash password before writing to database
245
+ resolveInput: async ({ inputValue }) => {
246
+ // Skip if undefined or null (allows partial updates)
247
+ if (inputValue === undefined || inputValue === null) {
248
+ return inputValue;
249
+ }
250
+ // Skip if not a string
251
+ if (typeof inputValue !== 'string') {
252
+ return inputValue;
253
+ }
254
+ // Skip empty strings (let validation handle this)
255
+ if (inputValue.length === 0) {
256
+ return inputValue;
257
+ }
258
+ // Skip if already hashed (idempotent)
259
+ if (isHashedPassword(inputValue)) {
260
+ return inputValue;
261
+ }
262
+ // Hash the password
263
+ return await hashPassword(inputValue);
264
+ },
265
+ // Wrap password with HashedPassword class after reading from database
266
+ resolveOutput: ({ value }) => {
267
+ // Only wrap string values (hashed passwords)
268
+ if (typeof value === 'string' && value.length > 0) {
269
+ return new HashedPassword(value);
270
+ }
271
+ return undefined;
272
+ },
273
+ // Merge with user-provided hooks if any
274
+ ...options?.hooks,
275
+ },
276
+ getZodSchema: (fieldName, operation) => {
277
+ const validation = options?.validation;
278
+ const isRequired = validation?.isRequired;
279
+ if (isRequired && operation === 'create') {
280
+ // Required in create mode: reject undefined and empty strings
281
+ return z
282
+ .string({
283
+ message: `${formatFieldName(fieldName)} must be text`,
284
+ })
285
+ .min(1, {
286
+ message: `${formatFieldName(fieldName)} is required`,
287
+ });
288
+ }
289
+ else if (isRequired && operation === 'update') {
290
+ // Required in update mode: if provided, reject empty strings
291
+ return z.union([
292
+ z.string().min(1, {
293
+ message: `${formatFieldName(fieldName)} is required`,
294
+ }),
295
+ z.undefined(),
296
+ ]);
297
+ }
298
+ else {
299
+ // Not required: can be undefined or any string
300
+ return z
301
+ .string({
302
+ message: `${formatFieldName(fieldName)} must be text`,
303
+ })
304
+ .optional();
305
+ }
306
+ },
307
+ getPrismaType: () => {
308
+ const isRequired = options?.validation?.isRequired;
309
+ return {
310
+ type: 'String',
311
+ modifiers: isRequired ? undefined : '?',
312
+ };
313
+ },
314
+ getTypeScriptType: () => {
315
+ const isRequired = options?.validation?.isRequired;
316
+ return {
317
+ type: 'string',
318
+ optional: !isRequired,
319
+ };
320
+ },
321
+ };
322
+ }
323
+ /**
324
+ * Select field (enum-like)
325
+ */
326
+ export function select(options) {
327
+ if (!options.options || options.options.length === 0) {
328
+ throw new Error('Select field must have at least one option');
329
+ }
330
+ return {
331
+ type: 'select',
332
+ ...options,
333
+ getZodSchema: (fieldName, operation) => {
334
+ const values = options.options.map((opt) => opt.value);
335
+ let schema = z.enum(values, {
336
+ message: `${formatFieldName(fieldName)} must be one of: ${values.join(', ')}`,
337
+ });
338
+ if (!options.validation?.isRequired || operation === 'update') {
339
+ schema = schema.optional();
340
+ }
341
+ return schema;
342
+ },
343
+ getPrismaType: () => {
344
+ let modifiers = '?';
345
+ // Add default value if provided
346
+ if (options.defaultValue !== undefined) {
347
+ modifiers = ` @default("${options.defaultValue}")`;
348
+ }
349
+ return {
350
+ type: 'String',
351
+ modifiers,
352
+ };
353
+ },
354
+ getTypeScriptType: () => {
355
+ // Generate union type from options
356
+ const unionType = options.options.map((opt) => `'${opt.value}'`).join(' | ');
357
+ return {
358
+ type: unionType,
359
+ optional: !options.validation?.isRequired || options.defaultValue !== undefined,
360
+ };
361
+ },
362
+ };
363
+ }
364
+ /**
365
+ * Relationship field
366
+ */
367
+ export function relationship(options) {
368
+ if (!options.ref) {
369
+ throw new Error('Relationship field must have a ref');
370
+ }
371
+ // Validate ref format: 'ListName.fieldName'
372
+ const refParts = options.ref.split('.');
373
+ if (refParts.length !== 2) {
374
+ throw new Error(`Invalid relationship ref format: "${options.ref}". Expected format: "ListName.fieldName"`);
375
+ }
376
+ return {
377
+ type: 'relationship',
378
+ ...options,
379
+ };
380
+ }
381
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/fields/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ import type { Hooks } from '../config/types.js';
2
+ import type { AccessContext } from '../access/types.js';
3
+ import type { FieldConfig } from '../config/types.js';
4
+ /**
5
+ * Validation error collection
6
+ */
7
+ export declare class ValidationError extends Error {
8
+ errors: string[];
9
+ fieldErrors: Record<string, string>;
10
+ constructor(errors: string[], fieldErrors?: Record<string, string>);
11
+ }
12
+ /**
13
+ * Execute resolveInput hook
14
+ * Allows modification of input data before validation
15
+ */
16
+ export declare function executeResolveInput<T = Record<string, unknown>>(hooks: Hooks<T> | undefined, args: {
17
+ operation: 'create' | 'update';
18
+ resolvedData: Partial<T>;
19
+ item?: T;
20
+ context: AccessContext;
21
+ }): Promise<Partial<T>>;
22
+ /**
23
+ * Execute validateInput hook
24
+ * Allows custom validation logic
25
+ */
26
+ export declare function executeValidateInput<T = Record<string, unknown>>(hooks: Hooks<T> | undefined, args: {
27
+ operation: 'create' | 'update';
28
+ resolvedData: Partial<T>;
29
+ item?: T;
30
+ context: AccessContext;
31
+ }): Promise<void>;
32
+ /**
33
+ * Execute beforeOperation hook
34
+ * Runs before database operation (cannot modify data)
35
+ */
36
+ export declare function executeBeforeOperation<T = Record<string, unknown>>(hooks: Hooks<T> | undefined, args: {
37
+ operation: 'create' | 'update' | 'delete';
38
+ item?: T;
39
+ context: AccessContext;
40
+ }): Promise<void>;
41
+ /**
42
+ * Execute afterOperation hook
43
+ * Runs after database operation
44
+ */
45
+ export declare function executeAfterOperation<T = Record<string, unknown>>(hooks: Hooks<T> | undefined, args: {
46
+ operation: 'create' | 'update' | 'delete';
47
+ item: T;
48
+ context: AccessContext;
49
+ }): Promise<void>;
50
+ /**
51
+ * Validate field-level validation rules using Zod
52
+ * Checks isRequired, length constraints, etc.
53
+ */
54
+ export declare function validateFieldRules(data: Record<string, unknown>, fieldConfigs: Record<string, FieldConfig>, operation?: 'create' | 'update'): {
55
+ errors: string[];
56
+ fieldErrors: Record<string, string>;
57
+ };
58
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AAC/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAGrD;;GAEG;AACH,qBAAa,eAAgB,SAAQ,KAAK;IACjC,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;gBAE9B,MAAM,EAAE,MAAM,EAAE,EAAE,WAAW,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM;CAMvE;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,SAAS,EAC3B,IAAI,EAAE;IACJ,SAAS,EAAE,QAAQ,GAAG,QAAQ,CAAA;IAC9B,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;IACxB,IAAI,CAAC,EAAE,CAAC,CAAA;IACR,OAAO,EAAE,aAAa,CAAA;CACvB,GACA,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAOrB;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,SAAS,EAC3B,IAAI,EAAE;IACJ,SAAS,EAAE,QAAQ,GAAG,QAAQ,CAAA;IAC9B,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;IACxB,IAAI,CAAC,EAAE,CAAC,CAAA;IACR,OAAO,EAAE,aAAa,CAAA;CACvB,GACA,OAAO,CAAC,IAAI,CAAC,CAmBf;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACtE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,SAAS,EAC3B,IAAI,EAAE;IACJ,SAAS,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAA;IACzC,IAAI,CAAC,EAAE,CAAC,CAAA;IACR,OAAO,EAAE,aAAa,CAAA;CACvB,GACA,OAAO,CAAC,IAAI,CAAC,CAMf;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,SAAS,EAC3B,IAAI,EAAE;IACJ,SAAS,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAA;IACzC,IAAI,EAAE,CAAC,CAAA;IACP,OAAO,EAAE,aAAa,CAAA;CACvB,GACA,OAAO,CAAC,IAAI,CAAC,CAMf;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACzC,SAAS,GAAE,QAAQ,GAAG,QAAmB,GACxC;IAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAW3D"}
@@ -0,0 +1,79 @@
1
+ import { validateWithZod } from '../validation/schema.js';
2
+ /**
3
+ * Validation error collection
4
+ */
5
+ export class ValidationError extends Error {
6
+ errors;
7
+ fieldErrors;
8
+ constructor(errors, fieldErrors = {}) {
9
+ super(`Validation failed: ${errors.join(', ')}`);
10
+ this.name = 'ValidationError';
11
+ this.errors = errors;
12
+ this.fieldErrors = fieldErrors;
13
+ }
14
+ }
15
+ /**
16
+ * Execute resolveInput hook
17
+ * Allows modification of input data before validation
18
+ */
19
+ export async function executeResolveInput(hooks, args) {
20
+ if (!hooks?.resolveInput) {
21
+ return args.resolvedData;
22
+ }
23
+ const result = await hooks.resolveInput(args);
24
+ return result;
25
+ }
26
+ /**
27
+ * Execute validateInput hook
28
+ * Allows custom validation logic
29
+ */
30
+ export async function executeValidateInput(hooks, args) {
31
+ if (!hooks?.validateInput) {
32
+ return;
33
+ }
34
+ const errors = [];
35
+ const addValidationError = (msg) => {
36
+ errors.push(msg);
37
+ };
38
+ await hooks.validateInput({
39
+ ...args,
40
+ addValidationError,
41
+ });
42
+ if (errors.length > 0) {
43
+ throw new ValidationError(errors);
44
+ }
45
+ }
46
+ /**
47
+ * Execute beforeOperation hook
48
+ * Runs before database operation (cannot modify data)
49
+ */
50
+ export async function executeBeforeOperation(hooks, args) {
51
+ if (!hooks?.beforeOperation) {
52
+ return;
53
+ }
54
+ await hooks.beforeOperation(args);
55
+ }
56
+ /**
57
+ * Execute afterOperation hook
58
+ * Runs after database operation
59
+ */
60
+ export async function executeAfterOperation(hooks, args) {
61
+ if (!hooks?.afterOperation) {
62
+ return;
63
+ }
64
+ await hooks.afterOperation(args);
65
+ }
66
+ /**
67
+ * Validate field-level validation rules using Zod
68
+ * Checks isRequired, length constraints, etc.
69
+ */
70
+ export function validateFieldRules(data, fieldConfigs, operation = 'create') {
71
+ const result = validateWithZod(data, fieldConfigs, operation);
72
+ if (result.success) {
73
+ return { errors: [], fieldErrors: {} };
74
+ }
75
+ // Convert field errors to array of error messages
76
+ const errors = Object.entries(result.errors).map(([_field, message]) => message);
77
+ return { errors, fieldErrors: result.errors };
78
+ }
79
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAEzD;;GAEG;AACH,MAAM,OAAO,eAAgB,SAAQ,KAAK;IACjC,MAAM,CAAU;IAChB,WAAW,CAAwB;IAE1C,YAAY,MAAgB,EAAE,cAAsC,EAAE;QACpE,KAAK,CAAC,sBAAsB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAChD,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAA;QAC7B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QACpB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAA;IAChC,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,KAA2B,EAC3B,IAKC;IAED,IAAI,CAAC,KAAK,EAAE,YAAY,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC,YAAY,CAAA;IAC1B,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAA;IAC7C,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,KAA2B,EAC3B,IAKC;IAED,IAAI,CAAC,KAAK,EAAE,aAAa,EAAE,CAAC;QAC1B,OAAM;IACR,CAAC;IAED,MAAM,MAAM,GAAa,EAAE,CAAA;IAE3B,MAAM,kBAAkB,GAAG,CAAC,GAAW,EAAE,EAAE;QACzC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAClB,CAAC,CAAA;IAED,MAAM,KAAK,CAAC,aAAa,CAAC;QACxB,GAAG,IAAI;QACP,kBAAkB;KACnB,CAAC,CAAA;IAEF,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,eAAe,CAAC,MAAM,CAAC,CAAA;IACnC,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,KAA2B,EAC3B,IAIC;IAED,IAAI,CAAC,KAAK,EAAE,eAAe,EAAE,CAAC;QAC5B,OAAM;IACR,CAAC;IAED,MAAM,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,CAAA;AACnC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,KAA2B,EAC3B,IAIC;IAED,IAAI,CAAC,KAAK,EAAE,cAAc,EAAE,CAAC;QAC3B,OAAM;IACR,CAAC;IAED,MAAM,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,CAAA;AAClC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAChC,IAA6B,EAC7B,YAAyC,EACzC,YAAiC,QAAQ;IAEzC,MAAM,MAAM,GAAG,eAAe,CAAC,IAAI,EAAE,YAAY,EAAE,SAAS,CAAC,CAAA;IAE7D,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,CAAA;IACxC,CAAC;IAED,kDAAkD;IAClD,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAA;IAEhF,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,CAAA;AAC/C,CAAC"}
@@ -0,0 +1,11 @@
1
+ export { config, list } from './config/index.js';
2
+ export type { OpenSaasConfig, ListConfig, FieldConfig, BaseFieldConfig, TextField, IntegerField, CheckboxField, TimestampField, PasswordField, SelectField, RelationshipField, OperationAccess, Hooks, FieldHooks, DatabaseConfig, SessionConfig, UIConfig, ThemeConfig, ThemePreset, ThemeColors, } from './config/index.js';
3
+ export type { AccessControl, FieldAccess, Session, AccessContext, PrismaFilter, AccessControlledDB, } from './access/index.js';
4
+ export { getContext } from './context/index.js';
5
+ export type { PrismaClientLike } from './access/types.js';
6
+ export type { ServerActionProps } from './context/index.js';
7
+ export { getDbKey, getUrlKey, getListKeyFromUrl, pascalToCamel, pascalToKebab, kebabToPascal, kebabToCamel, } from './lib/case-utils.js';
8
+ export { ValidationError } from './hooks/index.js';
9
+ export { validateWithZod, generateZodSchema } from './validation/schema.js';
10
+ export { hashPassword, comparePassword, isHashedPassword, HashedPassword, } from './utils/password.js';
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAA;AAChD,YAAY,EACV,cAAc,EACd,UAAU,EACV,WAAW,EACX,eAAe,EACf,SAAS,EACT,YAAY,EACZ,aAAa,EACb,cAAc,EACd,aAAa,EACb,WAAW,EACX,iBAAiB,EACjB,eAAe,EACf,KAAK,EACL,UAAU,EACV,cAAc,EACd,aAAa,EACb,QAAQ,EACR,WAAW,EACX,WAAW,EACX,WAAW,GACZ,MAAM,mBAAmB,CAAA;AAG1B,YAAY,EACV,aAAa,EACb,WAAW,EACX,OAAO,EACP,aAAa,EACb,YAAY,EACZ,kBAAkB,GACnB,MAAM,mBAAmB,CAAA;AAG1B,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAC/C,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACzD,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAG3D,OAAO,EACL,QAAQ,EACR,SAAS,EACT,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,aAAa,EACb,YAAY,GACb,MAAM,qBAAqB,CAAA;AAG5B,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAG3E,OAAO,EACL,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,cAAc,GACf,MAAM,qBAAqB,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,12 @@
1
+ // Config system
2
+ export { config, list } from './config/index.js';
3
+ // Context
4
+ export { getContext } from './context/index.js';
5
+ // Utilities
6
+ export { getDbKey, getUrlKey, getListKeyFromUrl, pascalToCamel, pascalToKebab, kebabToPascal, kebabToCamel, } from './lib/case-utils.js';
7
+ // Hooks and validation
8
+ export { ValidationError } from './hooks/index.js';
9
+ export { validateWithZod, generateZodSchema } from './validation/schema.js';
10
+ // Password utilities
11
+ export { hashPassword, comparePassword, isHashedPassword, HashedPassword, } from './utils/password.js';
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,gBAAgB;AAChB,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAA;AAkChD,UAAU;AACV,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAI/C,YAAY;AACZ,OAAO,EACL,QAAQ,EACR,SAAS,EACT,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,aAAa,EACb,YAAY,GACb,MAAM,qBAAqB,CAAA;AAE5B,uBAAuB;AACvB,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAE3E,qBAAqB;AACrB,OAAO,EACL,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,cAAc,GACf,MAAM,qBAAqB,CAAA"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Case conversion utilities for consistent naming across the stack
3
+ *
4
+ * - Config list names: PascalCase (e.g., "AuthUser", "BlogPost")
5
+ * - Prisma models: PascalCase (e.g., "AuthUser", "BlogPost")
6
+ * - Prisma client properties: camelCase (e.g., "authUser", "blogPost")
7
+ * - Context db properties: camelCase (e.g., "authUser", "blogPost")
8
+ * - URLs: kebab-case (e.g., "auth-user", "blog-post")
9
+ */
10
+ /**
11
+ * Convert PascalCase to camelCase
12
+ * AuthUser -> authUser
13
+ * BlogPost -> blogPost
14
+ */
15
+ export declare function pascalToCamel(str: string): string;
16
+ /**
17
+ * Convert PascalCase to kebab-case
18
+ * AuthUser -> auth-user
19
+ * BlogPost -> blog-post
20
+ */
21
+ export declare function pascalToKebab(str: string): string;
22
+ /**
23
+ * Convert kebab-case to PascalCase
24
+ * auth-user -> AuthUser
25
+ * blog-post -> BlogPost
26
+ */
27
+ export declare function kebabToPascal(str: string): string;
28
+ /**
29
+ * Convert kebab-case to camelCase
30
+ * auth-user -> authUser
31
+ * blog-post -> blogPost
32
+ */
33
+ export declare function kebabToCamel(str: string): string;
34
+ /**
35
+ * Get the database key for a list (camelCase)
36
+ * Used for accessing context.db and prisma client
37
+ */
38
+ export declare function getDbKey(listKey: string): string;
39
+ /**
40
+ * Get the URL segment for a list (kebab-case)
41
+ * Used for constructing admin URLs
42
+ */
43
+ export declare function getUrlKey(listKey: string): string;
44
+ /**
45
+ * Get the list key from a URL segment (PascalCase)
46
+ * Used for parsing admin URLs
47
+ */
48
+ export declare function getListKeyFromUrl(urlSegment: string): string;
49
+ //# sourceMappingURL=case-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"case-utils.d.ts","sourceRoot":"","sources":["../../src/lib/case-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAIjD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKjD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE5D"}