opacacms 0.1.12 → 0.1.13

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 (217) hide show
  1. package/dist/admin/index.js +0 -4
  2. package/dist/admin/webcomponent.d.ts +0 -1
  3. package/dist/admin/webcomponent.js +0 -4
  4. package/dist/admin.css +1 -0
  5. package/package.json +8 -2
  6. package/bun.lock +0 -34
  7. package/dist/admin/index.css +0 -47
  8. package/dist/admin/webcomponent.css +0 -47
  9. package/global.d.ts +0 -11
  10. package/src/admin/api-client.ts +0 -63
  11. package/src/admin/auth-client.ts +0 -40
  12. package/src/admin/custom-field.ts +0 -179
  13. package/src/admin/index.ts +0 -15
  14. package/src/admin/react.tsx +0 -72
  15. package/src/admin/router.ts +0 -9
  16. package/src/admin/stores/admin-queries.ts +0 -121
  17. package/src/admin/stores/auth.ts +0 -61
  18. package/src/admin/stores/column-visibility.ts +0 -67
  19. package/src/admin/stores/config.ts +0 -15
  20. package/src/admin/stores/media.ts +0 -95
  21. package/src/admin/stores/query.ts +0 -13
  22. package/src/admin/stores/ui.ts +0 -29
  23. package/src/admin/ui/admin-client.tsx +0 -283
  24. package/src/admin/ui/admin-layout.tsx +0 -276
  25. package/src/admin/ui/components/ColumnVisibilityToggle.tsx +0 -141
  26. package/src/admin/ui/components/DataDetailSheet.tsx +0 -141
  27. package/src/admin/ui/components/DataDetailView.tsx +0 -175
  28. package/src/admin/ui/components/Table.tsx +0 -67
  29. package/src/admin/ui/components/fields/ArrayField.tsx +0 -166
  30. package/src/admin/ui/components/fields/BlocksField.tsx +0 -202
  31. package/src/admin/ui/components/fields/BooleanField.tsx +0 -50
  32. package/src/admin/ui/components/fields/CollapsibleField.tsx +0 -75
  33. package/src/admin/ui/components/fields/DateField.tsx +0 -45
  34. package/src/admin/ui/components/fields/FileField.tsx +0 -322
  35. package/src/admin/ui/components/fields/GroupField.tsx +0 -50
  36. package/src/admin/ui/components/fields/JoinField.tsx +0 -23
  37. package/src/admin/ui/components/fields/NumberField.tsx +0 -46
  38. package/src/admin/ui/components/fields/RadioField.tsx +0 -62
  39. package/src/admin/ui/components/fields/RelationshipField.tsx +0 -278
  40. package/src/admin/ui/components/fields/RowField.tsx +0 -40
  41. package/src/admin/ui/components/fields/SelectField.tsx +0 -59
  42. package/src/admin/ui/components/fields/TabsField.tsx +0 -101
  43. package/src/admin/ui/components/fields/TextAreaField.tsx +0 -54
  44. package/src/admin/ui/components/fields/TextField.tsx +0 -49
  45. package/src/admin/ui/components/fields/VirtualField.tsx +0 -53
  46. package/src/admin/ui/components/fields/index.tsx +0 -371
  47. package/src/admin/ui/components/fields/richtext-editor/index.tsx +0 -211
  48. package/src/admin/ui/components/fields/richtext-editor/nodes/ImageComponent.tsx +0 -142
  49. package/src/admin/ui/components/fields/richtext-editor/nodes/ImageNode.tsx +0 -95
  50. package/src/admin/ui/components/fields/richtext-editor/plugins/ComponentPickerPlugin.tsx +0 -226
  51. package/src/admin/ui/components/fields/richtext-editor/plugins/EditableSyncPlugin.tsx +0 -16
  52. package/src/admin/ui/components/fields/richtext-editor/plugins/NotionToolbarPlugin.tsx +0 -184
  53. package/src/admin/ui/components/fields/richtext-editor/plugins/SimpleToolbarPlugin.tsx +0 -240
  54. package/src/admin/ui/components/fields/richtext-editor/plugins/ValueSyncPlugin.tsx +0 -40
  55. package/src/admin/ui/components/fields/utils.ts +0 -1
  56. package/src/admin/ui/components/link.tsx +0 -41
  57. package/src/admin/ui/components/media/AssetManagerModal.tsx +0 -334
  58. package/src/admin/ui/components/toast.tsx +0 -72
  59. package/src/admin/ui/components/ui/accordion.tsx +0 -51
  60. package/src/admin/ui/components/ui/alert-dialog.tsx +0 -98
  61. package/src/admin/ui/components/ui/blocks.tsx +0 -32
  62. package/src/admin/ui/components/ui/breadcrumbs.tsx +0 -59
  63. package/src/admin/ui/components/ui/button.tsx +0 -26
  64. package/src/admin/ui/components/ui/collapsible.tsx +0 -124
  65. package/src/admin/ui/components/ui/dialog.tsx +0 -79
  66. package/src/admin/ui/components/ui/group.tsx +0 -20
  67. package/src/admin/ui/components/ui/index.ts +0 -17
  68. package/src/admin/ui/components/ui/input.tsx +0 -12
  69. package/src/admin/ui/components/ui/join.tsx +0 -53
  70. package/src/admin/ui/components/ui/label.tsx +0 -11
  71. package/src/admin/ui/components/ui/radio-group.tsx +0 -75
  72. package/src/admin/ui/components/ui/relationship-detail-sheet.tsx +0 -122
  73. package/src/admin/ui/components/ui/relationship.tsx +0 -58
  74. package/src/admin/ui/components/ui/scroll-area.tsx +0 -19
  75. package/src/admin/ui/components/ui/select.tsx +0 -187
  76. package/src/admin/ui/components/ui/separator.tsx +0 -21
  77. package/src/admin/ui/components/ui/sheet.tsx +0 -106
  78. package/src/admin/ui/components/ui/tabs.tsx +0 -116
  79. package/src/admin/ui/components/ui/utils.ts +0 -3
  80. package/src/admin/ui/hooks/use-debounce.ts +0 -15
  81. package/src/admin/ui/styles/_locale-switcher.scss +0 -33
  82. package/src/admin/ui/styles/accordion.scss +0 -60
  83. package/src/admin/ui/styles/animations.scss +0 -41
  84. package/src/admin/ui/styles/asset-manager.scss +0 -547
  85. package/src/admin/ui/styles/badge.scss +0 -13
  86. package/src/admin/ui/styles/base.scss +0 -22
  87. package/src/admin/ui/styles/button.scss +0 -161
  88. package/src/admin/ui/styles/card.scss +0 -13
  89. package/src/admin/ui/styles/collapsible.scss +0 -75
  90. package/src/admin/ui/styles/data-detail.scss +0 -92
  91. package/src/admin/ui/styles/dialog.scss +0 -102
  92. package/src/admin/ui/styles/empty-state.scss +0 -22
  93. package/src/admin/ui/styles/group.scss +0 -19
  94. package/src/admin/ui/styles/index.scss +0 -33
  95. package/src/admin/ui/styles/input.scss +0 -80
  96. package/src/admin/ui/styles/label.scss +0 -12
  97. package/src/admin/ui/styles/layout.scss +0 -56
  98. package/src/admin/ui/styles/lexical.scss +0 -469
  99. package/src/admin/ui/styles/loading.scss +0 -102
  100. package/src/admin/ui/styles/media-registry.scss +0 -597
  101. package/src/admin/ui/styles/pagination.scss +0 -20
  102. package/src/admin/ui/styles/radio-group.scss +0 -66
  103. package/src/admin/ui/styles/row.scss +0 -17
  104. package/src/admin/ui/styles/scrollbar.scss +0 -36
  105. package/src/admin/ui/styles/select.scss +0 -121
  106. package/src/admin/ui/styles/separator.scss +0 -14
  107. package/src/admin/ui/styles/sheet.scss +0 -152
  108. package/src/admin/ui/styles/sidebar.scss +0 -148
  109. package/src/admin/ui/styles/switch.scss +0 -59
  110. package/src/admin/ui/styles/table.scss +0 -207
  111. package/src/admin/ui/styles/tabs.scss +0 -62
  112. package/src/admin/ui/styles/toast.scss +0 -45
  113. package/src/admin/ui/styles/variables.scss +0 -24
  114. package/src/admin/ui/views/collection-list-view.tsx +0 -720
  115. package/src/admin/ui/views/dashboard-view.tsx +0 -263
  116. package/src/admin/ui/views/document-edit-view.tsx +0 -384
  117. package/src/admin/ui/views/global-edit-view.tsx +0 -226
  118. package/src/admin/ui/views/init-view.tsx +0 -182
  119. package/src/admin/ui/views/login-view.tsx +0 -123
  120. package/src/admin/ui/views/media-registry-view.tsx +0 -1104
  121. package/src/admin/ui/views/settings-view.tsx +0 -729
  122. package/src/admin/webcomponent.tsx +0 -15
  123. package/src/auth/index.ts +0 -194
  124. package/src/auth/migrations.ts +0 -87
  125. package/src/auth/premissions.ts +0 -46
  126. package/src/cli/commands/generate-types.ts +0 -116
  127. package/src/cli/commands/init.ts +0 -95
  128. package/src/cli/commands/migrate-commands.ts +0 -160
  129. package/src/cli/commands/seed-command.ts +0 -11
  130. package/src/cli/d1-mock.ts +0 -101
  131. package/src/cli/index.test.ts +0 -84
  132. package/src/cli/index.ts +0 -183
  133. package/src/cli/r2-mock.ts +0 -217
  134. package/src/cli/seeding.ts +0 -409
  135. package/src/client.ts +0 -181
  136. package/src/config-utils.ts +0 -102
  137. package/src/config.ts +0 -49
  138. package/src/db/adapter.ts +0 -53
  139. package/src/db/better-sqlite.ts +0 -657
  140. package/src/db/bun-sqlite.ts +0 -666
  141. package/src/db/d1.ts +0 -721
  142. package/src/db/index.ts +0 -10
  143. package/src/db/kysely/data-mapper.ts +0 -142
  144. package/src/db/kysely/field-mapper.ts +0 -149
  145. package/src/db/kysely/migration-generator.ts +0 -223
  146. package/src/db/kysely/query-builder.ts +0 -92
  147. package/src/db/kysely/schema-builder.ts +0 -439
  148. package/src/db/kysely/sql-utils.ts +0 -13
  149. package/src/db/postgres.ts +0 -631
  150. package/src/db/sqlite.ts +0 -670
  151. package/src/db/system-schema.ts +0 -121
  152. package/src/index.ts +0 -13
  153. package/src/runtimes/README.md +0 -59
  154. package/src/runtimes/bun.ts +0 -49
  155. package/src/runtimes/cloudflare-workers.ts +0 -38
  156. package/src/runtimes/next.ts +0 -26
  157. package/src/runtimes/node.ts +0 -52
  158. package/src/schema/collection.ts +0 -184
  159. package/src/schema/fields/base.ts +0 -164
  160. package/src/schema/fields/index.ts +0 -427
  161. package/src/schema/global.ts +0 -145
  162. package/src/schema/index.ts +0 -4
  163. package/src/schema/infer.ts +0 -72
  164. package/src/server/admin-router.ts +0 -20
  165. package/src/server/admin.ts +0 -142
  166. package/src/server/assets.ts +0 -306
  167. package/src/server/collection-router.ts +0 -55
  168. package/src/server/handlers.ts +0 -722
  169. package/src/server/middlewares/admin.ts +0 -27
  170. package/src/server/middlewares/auth.ts +0 -89
  171. package/src/server/middlewares/context.ts +0 -17
  172. package/src/server/middlewares/cors.ts +0 -24
  173. package/src/server/middlewares/database-init.ts +0 -74
  174. package/src/server/middlewares/rate-limit.ts +0 -77
  175. package/src/server/router.ts +0 -47
  176. package/src/server/setup-middlewares.ts +0 -58
  177. package/src/server/system-router.ts +0 -35
  178. package/src/server.ts +0 -9
  179. package/src/storage/adapters/cloudflare-r2.ts +0 -136
  180. package/src/storage/adapters/local.ts +0 -146
  181. package/src/storage/adapters/s3.ts +0 -186
  182. package/src/storage/errors.ts +0 -46
  183. package/src/storage/index.ts +0 -5
  184. package/src/storage/types.ts +0 -39
  185. package/src/types.ts +0 -577
  186. package/src/utils/lexical.ts +0 -37
  187. package/src/utils/logger.ts +0 -73
  188. package/src/validation.ts +0 -429
  189. package/src/validator.ts +0 -179
  190. package/test/admin-custom-field.test.ts +0 -162
  191. package/test/admin-react-field.test.tsx +0 -134
  192. package/test/api-features.test.ts +0 -78
  193. package/test/api.test.ts +0 -178
  194. package/test/auth.test.ts +0 -62
  195. package/test/cli-integration.test.ts +0 -148
  196. package/test/cli.test.ts +0 -25
  197. package/test/db/postgres.test.ts +0 -95
  198. package/test/db/sqlite-filter.test.ts +0 -53
  199. package/test/db/sqlite.test.ts +0 -82
  200. package/test/engine-features.test.ts +0 -79
  201. package/test/globals.test.ts +0 -74
  202. package/test/integration-tmp/db-app/opacacms.config.ts +0 -15
  203. package/test/integration-tmp/my-sqlite-app/opacacms.config.ts +0 -25
  204. package/test/integration-tmp/my-test-app/index.ts +0 -8
  205. package/test/integration-tmp/my-test-app/opacacms.config.ts +0 -16
  206. package/test/integration-tmp/my-test-app/package.json +0 -12
  207. package/test/populate.test.ts +0 -79
  208. package/test/runtimes.test.ts +0 -43
  209. package/test/schema-builder.test.ts +0 -107
  210. package/test/schema-features.test.ts +0 -63
  211. package/test/seeding.test.ts +0 -68
  212. package/test/storage/local.test.ts +0 -72
  213. package/test/storage/s3.test.ts +0 -60
  214. package/test/structural-data.test.ts +0 -100
  215. package/test/test-setup.ts +0 -11
  216. package/test/validation.test.ts +0 -162
  217. package/tsconfig.json +0 -42
package/src/validation.ts DELETED
@@ -1,429 +0,0 @@
1
- import { z } from "zod";
2
-
3
- export const FieldTypeSchema = z.enum([
4
- "text",
5
- "slug",
6
- "textarea",
7
- "number",
8
- "richtext",
9
- "relationship",
10
- "select",
11
- "radio",
12
- "date",
13
- "boolean",
14
- "json",
15
- "file",
16
- "blocks",
17
- "group",
18
- "row",
19
- "collapsible",
20
- "tabs",
21
- "join",
22
- "array",
23
- "virtual",
24
- ]);
25
-
26
- export type FieldType = z.infer<typeof FieldTypeSchema>;
27
-
28
- const BaseFieldSchema = z.object({
29
- name: z.string(),
30
- label: z.string().optional(),
31
- required: z.boolean().optional().default(false),
32
- unique: z.boolean().optional().default(false),
33
- localized: z.boolean().optional(),
34
- defaultValue: z.any().optional(),
35
- validate: z.function().optional(),
36
- admin: z
37
- .object({
38
- description: z.string().optional(),
39
- condition: z.function().optional(),
40
- hidden: z.boolean().optional(),
41
- readOnly: z.boolean().optional(),
42
- width: z.string().optional(),
43
- style: z.any().optional(),
44
- className: z.string().optional(),
45
- components: z
46
- .object({
47
- Field: z.string().optional(),
48
- Cell: z.string().optional(),
49
- })
50
- .optional(),
51
- })
52
- .optional(),
53
- });
54
-
55
- export const FieldSchema: z.ZodType<unknown> = z.lazy(() =>
56
- z.discriminatedUnion("type", [
57
- // Simple types
58
- BaseFieldSchema.extend({ type: z.literal("text") }),
59
- BaseFieldSchema.extend({
60
- type: z.literal("slug"),
61
- from: z.string(),
62
- format: z.function().optional(),
63
- }),
64
- BaseFieldSchema.extend({ type: z.literal("textarea") }),
65
- BaseFieldSchema.extend({ type: z.literal("number") }),
66
- BaseFieldSchema.extend({ type: z.literal("date") }),
67
- BaseFieldSchema.extend({
68
- type: z.literal("boolean"),
69
- options: z
70
- .object({
71
- display: z.enum(["switch", "toggle", "checkbox", "select"]).optional().default("switch"),
72
- })
73
- .loose()
74
- .optional(),
75
- }),
76
-
77
- // Complex types
78
- BaseFieldSchema.extend({
79
- type: z.literal("richtext"),
80
- options: z
81
- .object({
82
- defaultMode: z.enum(["simple", "notion"]).optional(),
83
- })
84
- .loose()
85
- .optional(),
86
- }),
87
-
88
- BaseFieldSchema.extend({
89
- type: z.literal("relationship"),
90
- relationTo: z.string(),
91
- hasMany: z.boolean().optional(),
92
- displayField: z.string().optional(),
93
- references: z
94
- .object({
95
- table: z.string(),
96
- column: z.string(),
97
- onDelete: z.enum(["cascade", "set null", "restrict", "no action"]).optional(),
98
- })
99
- .optional(),
100
- }),
101
-
102
- BaseFieldSchema.extend({
103
- type: z.literal("select"),
104
- options: z
105
- .object({
106
- choices: z.array(
107
- z.union([z.string(), z.object({ label: z.string(), value: z.string() })]),
108
- ),
109
- })
110
- .loose()
111
- .optional(),
112
- }),
113
-
114
- BaseFieldSchema.extend({
115
- type: z.literal("radio"),
116
- options: z
117
- .object({
118
- choices: z.array(
119
- z.union([z.string(), z.object({ label: z.string(), value: z.string() })]),
120
- ),
121
- })
122
- .loose(),
123
- }),
124
-
125
- BaseFieldSchema.extend({
126
- type: z.literal("file"),
127
- bucket: z.string().optional(),
128
- options: z
129
- .object({
130
- allowedmime_types: z.array(z.string()).optional(),
131
- maxFileSize: z.number().optional(),
132
- metaFields: z.array(z.lazy(() => FieldSchema)).optional(),
133
- })
134
- .loose()
135
- .optional(),
136
- }),
137
-
138
- BaseFieldSchema.extend({
139
- type: z.literal("json"),
140
- fields: z.array(z.lazy(() => FieldSchema)).optional(),
141
- }),
142
-
143
- BaseFieldSchema.extend({
144
- type: z.literal("blocks"),
145
- blocks: z.array(
146
- z.object({
147
- slug: z.string(),
148
- fields: z.array(z.lazy(() => FieldSchema)),
149
- label: z.string().optional(),
150
- }),
151
- ),
152
- }),
153
-
154
- BaseFieldSchema.extend({
155
- type: z.literal("group"),
156
- fields: z.array(z.lazy(() => FieldSchema)),
157
- }),
158
-
159
- // Layout Types
160
- z.object({
161
- name: z.string().optional(),
162
- type: z.literal("row"),
163
- fields: z.array(z.lazy(() => FieldSchema)),
164
- label: z.string().optional(),
165
- }),
166
-
167
- z.object({
168
- name: z.string().optional(),
169
- type: z.literal("collapsible"),
170
- fields: z.array(z.lazy(() => FieldSchema)),
171
- label: z.string().optional(),
172
- options: z
173
- .object({
174
- initiallyCollapsed: z.boolean().optional(),
175
- })
176
- .loose()
177
- .optional(),
178
- }),
179
-
180
- z.object({
181
- name: z.string().optional(),
182
- type: z.literal("tabs"),
183
- tabs: z.array(
184
- z.object({
185
- label: z.string(),
186
- fields: z.array(z.lazy(() => FieldSchema)),
187
- }),
188
- ),
189
- }),
190
-
191
- // Virtual Types
192
- z.object({
193
- name: z
194
- .string()
195
- .optional()
196
- .refine((val) => val === undefined, {
197
- message:
198
- "Join fields are virtual and should not have a 'name' property. They are mapped dynamically via the API.",
199
- })
200
- .or(z.string()),
201
- type: z.literal("join"),
202
- collection: z.string(),
203
- on: z.string(),
204
- label: z.string().optional(),
205
- }),
206
-
207
- BaseFieldSchema.extend({
208
- type: z.literal("array"),
209
- fields: z.array(z.lazy(() => FieldSchema)).optional(),
210
- }),
211
- BaseFieldSchema.extend({
212
- type: z.literal("virtual"),
213
- resolve: z.function(),
214
- returnType: z.string().optional(),
215
- }),
216
- ]),
217
- );
218
-
219
- export type Field = z.infer<typeof FieldSchema>;
220
-
221
- export const AccessConfigSchema = z.object({
222
- read: z.union([z.boolean(), z.function()]).optional(),
223
- create: z.union([z.boolean(), z.function()]).optional(),
224
- update: z.union([z.boolean(), z.function()]).optional(),
225
- delete: z.union([z.boolean(), z.function()]).optional(),
226
- requireApiKey: z.boolean().optional(),
227
- });
228
-
229
- export type AccessConfig = z.infer<typeof AccessConfigSchema>;
230
-
231
- export const CollectionHooksSchema = z.object({
232
- beforeCreate: z.function().optional(),
233
- afterCreate: z.function().optional(),
234
- beforeUpdate: z.function().optional(),
235
- afterUpdate: z.function().optional(),
236
- beforeDelete: z.function().optional(),
237
- afterDelete: z.function().optional(),
238
- });
239
-
240
- export type CollectionHooks = z.infer<typeof CollectionHooksSchema>;
241
-
242
- export const CollectionSchema = z.object({
243
- slug: z.string(),
244
- label: z.string().optional(),
245
- icon: z.string().optional(),
246
- apiPath: z.string().optional(),
247
- fields: z.array(FieldSchema),
248
- timestamps: z
249
- .union([
250
- z.boolean(),
251
- z.object({
252
- createdAt: z.string().optional(),
253
- updatedAt: z.string().optional(),
254
- }),
255
- ])
256
- .optional(),
257
- auth: z.boolean().optional(),
258
- hooks: CollectionHooksSchema.optional(),
259
- access: AccessConfigSchema.optional(),
260
- versions: z
261
- .object({
262
- drafts: z.boolean().optional(),
263
- maxRevisions: z.number().optional(),
264
- autosave: z.boolean().optional(),
265
- })
266
- .optional(),
267
- webhooks: z
268
- .array(
269
- z.object({
270
- events: z.array(z.string()),
271
- url: z.string(),
272
- headers: z.record(z.string(), z.string()).optional(),
273
- }),
274
- )
275
- .optional(),
276
- admin: z
277
- .union([
278
- z.boolean(),
279
- z.object({
280
- defaultColumns: z.array(z.string()).optional(),
281
- useAsTitle: z.string().optional(),
282
- hidden: z.boolean().optional(),
283
- disableAdmin: z.boolean().optional(),
284
- views: z
285
- .array(
286
- z.object({
287
- name: z.string(),
288
- filter: z.record(z.string(), z.any()),
289
- defaultColumns: z.array(z.string()).optional(),
290
- }),
291
- )
292
- .optional(),
293
- bulkActions: z
294
- .array(
295
- z.object({
296
- label: z.string(),
297
- action: z.function(),
298
- }),
299
- )
300
- .optional(),
301
- }),
302
- ])
303
- .optional(),
304
- hidden: z.boolean().optional(),
305
- });
306
-
307
- export type Collection = z.infer<typeof CollectionSchema>;
308
-
309
- export const GlobalSchema = z.object({
310
- slug: z.string(),
311
- label: z.string().optional(),
312
- icon: z.string().optional(),
313
- fields: z.array(FieldSchema),
314
- timestamps: z
315
- .union([
316
- z.boolean(),
317
- z.object({
318
- createdAt: z.string().optional(),
319
- updatedAt: z.string().optional(),
320
- }),
321
- ])
322
- .optional(),
323
- access: AccessConfigSchema.optional(),
324
- });
325
-
326
- export type Global = z.infer<typeof GlobalSchema>;
327
-
328
- export const AdminConfigSchema = z.object({
329
- userCollection: z.string().optional(),
330
- disableAdmin: z.boolean().optional(),
331
- route: z.string().optional(),
332
- });
333
-
334
- export type AdminConfig = z.infer<typeof AdminConfigSchema>;
335
-
336
- export const OpacaAuthConfigSchema = z.object({
337
- strategies: z
338
- .object({
339
- emailPassword: z.boolean().optional(),
340
- magicLink: z
341
- .object({
342
- enabled: z.boolean(),
343
- sendEmail: z.function(),
344
- })
345
- .optional(),
346
- })
347
- .optional(),
348
- socialProviders: z
349
- .object({
350
- github: z
351
- .object({
352
- clientId: z.string(),
353
- clientSecret: z.string(),
354
- })
355
- .optional(),
356
- google: z
357
- .object({
358
- clientId: z.string(),
359
- clientSecret: z.string(),
360
- })
361
- .optional(),
362
- })
363
- .optional(),
364
- session: z
365
- .object({
366
- expiresInDays: z.number().optional(),
367
- updateAgeSeconds: z.number().optional(),
368
- })
369
- .optional(),
370
- features: z
371
- .object({
372
- apiKeys: z
373
- .object({
374
- enabled: z.boolean(),
375
- })
376
- .optional(),
377
- mfa: z
378
- .object({
379
- enabled: z.boolean(),
380
- issuer: z.string(),
381
- })
382
- .optional(),
383
- })
384
- .optional(),
385
- });
386
-
387
- export const ApiConfigSchema = z.object({
388
- maxLimit: z.number().optional(),
389
- rateLimit: z
390
- .object({
391
- windowMs: z.number().optional(),
392
- limit: z.number().optional(),
393
- enabled: z.boolean().optional(),
394
- store: z.any().optional(),
395
- provider: z.function().optional(),
396
- keyGenerator: z.function().optional(),
397
- })
398
- .optional(),
399
- });
400
-
401
- export type ApiConfig = z.infer<typeof ApiConfigSchema>;
402
-
403
- export const OpacaConfigSchema = z.object({
404
- collections: z.array(CollectionSchema),
405
- globals: z.array(GlobalSchema).optional(),
406
- db: z.any(),
407
- storages: z.record(z.string(), z.any()).optional(),
408
- runMigrationsOnStartup: z.boolean().optional(),
409
- admin: AdminConfigSchema.optional(),
410
- serverURL: z.string().optional(),
411
- appName: z.string().optional(),
412
- secret: z.string().optional(),
413
- trustedOrigins: z.union([z.array(z.string()), z.function()]).optional(),
414
- auth: OpacaAuthConfigSchema.optional(),
415
- api: ApiConfigSchema.optional(),
416
- access: z
417
- .object({
418
- roles: z.record(z.string(), z.record(z.string(), z.array(z.string()))).optional(),
419
- })
420
- .optional(),
421
- i18n: z
422
- .object({
423
- locales: z.array(z.string()),
424
- defaultLocale: z.string(),
425
- })
426
- .optional(),
427
- });
428
-
429
- export type OpacaConfig = z.infer<typeof OpacaConfigSchema>;
package/src/validator.ts DELETED
@@ -1,179 +0,0 @@
1
- import { z } from "zod";
2
- import type { Collection, Field } from "./types";
3
-
4
- export function generateSchemaForCollection(
5
- collection: { fields: Field[]; versions?: any; timestamps?: any },
6
- isUpdate: boolean = false,
7
- ) {
8
- const shape = mapFieldsToShape(collection.fields, isUpdate);
9
-
10
- if (collection.versions) {
11
- shape._status = z.enum(["draft", "published"]).optional().nullable();
12
- }
13
-
14
- const ts = collection.timestamps;
15
- if (ts !== false && ts !== undefined) {
16
- const config = typeof ts === "object" ? ts : {};
17
- const createdField = config.createdAt || "createdAt";
18
- const updatedField = config.updatedAt || "updatedAt";
19
- shape[createdField] = z.union([z.string(), z.date()]).optional().nullable();
20
- shape[updatedField] = z.union([z.string(), z.date()]).optional().nullable();
21
- }
22
-
23
- return z.object(shape);
24
- }
25
-
26
- function mapFieldsToShape(
27
- fields: Field[],
28
- isUpdate: boolean = false,
29
- ): Record<string, z.ZodTypeAny> {
30
- const shape: Record<string, z.ZodTypeAny> = {};
31
-
32
- for (const field of fields) {
33
- // Layout fields without name merge their fields into the current level
34
- if (!field.name) {
35
- if (field.type === "tabs" && field.tabs) {
36
- for (const tab of field.tabs) {
37
- Object.assign(shape, mapFieldsToShape(tab.fields, isUpdate));
38
- }
39
- } else if (field.type === "group" && field.fields) {
40
- Object.assign(shape, mapFieldsToShape(field.fields, isUpdate));
41
- } else if (field.type === "row" && field.fields) {
42
- Object.assign(shape, mapFieldsToShape(field.fields, isUpdate));
43
- } else if (field.type === "collapsible" && field.fields) {
44
- Object.assign(shape, mapFieldsToShape(field.fields, isUpdate));
45
- }
46
- continue;
47
- }
48
-
49
- const fieldName = field.name;
50
- let schema: z.ZodTypeAny;
51
-
52
- if (field.type === "group" && field.fields) {
53
- schema = z.object(mapFieldsToShape(field.fields, isUpdate));
54
- } else if (field.type === "blocks" && field.blocks) {
55
- const blockSchemas = field.blocks.map((block) =>
56
- z.object({
57
- blockType: z.literal(block.slug),
58
- ...mapFieldsToShape(block.fields, isUpdate),
59
- }),
60
- );
61
- schema = z.array(z.union(blockSchemas));
62
- } else if (field.type === "row" || field.type === "collapsible") {
63
- // If a row/collapsible HAS a name (unusual but possible), treat it as a group
64
- if (field.fields) {
65
- schema = z.object(mapFieldsToShape(field.fields, isUpdate));
66
- } else {
67
- schema = z.any();
68
- }
69
- } else {
70
- schema = mapFieldToZod(field);
71
- }
72
-
73
- if (field.localized) {
74
- schema = z.union([z.record(z.string(), schema), schema]);
75
- }
76
-
77
- if (field.required && !isUpdate) {
78
- // Slugs with a 'from' source are not required during input as they are auto-generated
79
- if (field.type === "slug" && (field as any).from) {
80
- schema = schema.optional().nullable();
81
- }
82
- } else {
83
- schema = schema.optional().nullable();
84
- }
85
-
86
- if (field.defaultValue !== undefined && !isUpdate) {
87
- schema = schema.default(field.defaultValue);
88
- }
89
-
90
- if (field.validate) {
91
- schema = schema.superRefine((val, ctx) => {
92
- if (val === undefined || val === null) return;
93
- const result = field.validate!(val);
94
- if (result !== true) {
95
- ctx.addIssue({
96
- code: z.ZodIssueCode.custom,
97
- message: typeof result === "string" ? result : "Invalid field",
98
- });
99
- }
100
- });
101
- }
102
-
103
- shape[fieldName] = schema;
104
- }
105
-
106
- return shape;
107
- }
108
-
109
- function mapFieldToZod(field: Field): z.ZodTypeAny {
110
- switch (field.type) {
111
- case "text":
112
- case "slug":
113
- case "richtext":
114
- case "textarea":
115
- return z.string();
116
-
117
- case "relationship": {
118
- const isHasMany = "hasMany" in field && field.hasMany;
119
- const base = z.union([z.string(), z.number(), z.undefined(), z.null()]);
120
-
121
- const schema = isHasMany ? z.array(base.optional().nullable()) : base;
122
-
123
- if (isHasMany) {
124
- return z.preprocess((val) => {
125
- if (val === undefined || val === null || val === "") return [];
126
- if (Array.isArray(val)) return val;
127
- return [val];
128
- }, schema);
129
- }
130
- return schema;
131
- }
132
-
133
- case "number":
134
- return z.preprocess(
135
- (val) => {
136
- if (val === "" || val === undefined || val === null) return undefined;
137
- if (typeof val === "string") {
138
- const num = Number(val);
139
- return Number.isNaN(num) ? undefined : num;
140
- }
141
- return val;
142
- },
143
- z.union([z.number(), z.undefined(), z.null()]),
144
- );
145
-
146
- case "boolean":
147
- return z.preprocess((val) => {
148
- if (typeof val === "string") return val === "true";
149
- return val;
150
- }, z.boolean());
151
-
152
- case "date":
153
- return z.preprocess(
154
- (val) => {
155
- if (val === "" || val === undefined || val === null) return undefined;
156
- return val;
157
- },
158
- z.union([
159
- z.string().regex(/^\d{4}-\d{2}-\d{2}/, "Invalid date format"),
160
- z.date(),
161
- z.undefined(),
162
- z.null(),
163
- ]),
164
- );
165
-
166
- case "select":
167
- return z.string();
168
-
169
- case "array":
170
- return z.preprocess((val) => {
171
- if (val === undefined || val === null || val === "") return [];
172
- if (Array.isArray(val)) return val;
173
- return [val];
174
- }, z.array(z.any()));
175
-
176
- default:
177
- return z.any();
178
- }
179
- }