opacacms 0.2.0 → 0.3.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 (187) hide show
  1. package/README.md +31 -22
  2. package/dist/admin/auth-client.d.ts +39 -39
  3. package/dist/admin/index.d.ts +2 -2
  4. package/dist/admin/index.js +15 -10520
  5. package/dist/admin/plugin-client.d.ts +65 -0
  6. package/dist/admin/react.d.ts +2 -2
  7. package/dist/admin/react.js +34 -4
  8. package/dist/admin/stores/ui.d.ts +19 -4
  9. package/dist/admin/ui/components/PluginSettingsForm.d.ts +2 -2
  10. package/dist/admin/ui/components/custom-alert.d.ts +7 -0
  11. package/dist/admin/ui/components/{DetailSheet.d.ts → detail-sheet.d.ts} +1 -2
  12. package/dist/admin/ui/components/fields/FieldLabel.d.ts +1 -1
  13. package/dist/admin/ui/components/fields/RelationshipField.d.ts +1 -1
  14. package/dist/admin/ui/components/media/AssetManagerModal.d.ts +2 -2
  15. package/dist/admin/ui/components/plugin-iframe.d.ts +7 -0
  16. package/dist/admin/ui/components/ui/accordion.d.ts +17 -7
  17. package/dist/admin/ui/components/ui/alert-dialog.d.ts +16 -12
  18. package/dist/admin/ui/components/ui/button.d.ts +11 -7
  19. package/dist/admin/ui/components/ui/relationship.d.ts +1 -1
  20. package/dist/admin/ui/components/ui/sheet.d.ts +14 -27
  21. package/dist/admin/ui/components/ui/tooltip.d.ts +7 -0
  22. package/dist/admin/ui/components/versions-sheet.d.ts +4 -5
  23. package/dist/admin/ui/views/collection-list-view.d.ts +1 -1
  24. package/dist/admin/ui/views/dashboard-view.d.ts +1 -1
  25. package/dist/admin/ui/views/media-registry-view.d.ts +3 -3
  26. package/dist/admin/ui/views/settings-view.d.ts +2 -2
  27. package/dist/admin/vue.js +27 -4
  28. package/dist/admin/webcomponent.js +20 -2
  29. package/dist/admin.css +1 -1
  30. package/dist/auth/index.d.ts +43 -43
  31. package/dist/{chunk-7y1nbmw6.js → chunk-1bd7fz7n.js} +32 -2
  32. package/dist/chunk-1qm0m8r8.js +413 -0
  33. package/dist/chunk-2k3ysje3.js +31 -0
  34. package/dist/chunk-3j9zjfmn.js +376 -0
  35. package/dist/{chunk-byq8g0rd.js → chunk-48ywpd0a.js} +16 -22
  36. package/dist/{chunk-esrg9qj0.js → chunk-5422w4eq.js} +70 -54
  37. package/dist/chunk-56n342hs.js +95 -0
  38. package/dist/chunk-5b8r0v8c.js +47 -0
  39. package/dist/chunk-63yg00vx.js +263 -0
  40. package/dist/{chunk-8sqjbsgt.js → chunk-6bywt602.js} +26 -1
  41. package/dist/{chunk-v9z61v3g.js → chunk-6qs0g65f.js} +43 -3
  42. package/dist/chunk-7rr5p01g.js +581 -0
  43. package/dist/{chunk-51z3x7kq.js → chunk-a3qae86h.js} +1 -1
  44. package/dist/{chunk-3rdhbedb.js → chunk-adq2b75c.js} +2 -2
  45. package/dist/chunk-d0tb1xjw.js +93 -0
  46. package/dist/chunk-d7cgd6vn.js +318 -0
  47. package/dist/{chunk-0bq155dy.js → chunk-e0g6gn7n.js} +89 -100
  48. package/dist/chunk-ec4jhybj.js +1137 -0
  49. package/dist/chunk-fatyf6f7.js +221 -0
  50. package/dist/{chunk-526a3gqx.js → chunk-fnsf1dfm.js} +1 -1
  51. package/dist/chunk-g9bxb6h0.js +205 -0
  52. package/dist/chunk-gyaf5kgf.js +10 -0
  53. package/dist/{chunk-9kxpbcb1.js → chunk-h6dhexzr.js} +16 -7
  54. package/dist/{chunk-dykn5hr6.js → chunk-j8js1y0h.js} +31 -74
  55. package/dist/{chunk-t0zg026p.js → chunk-jq1drsen.js} +12 -1
  56. package/dist/{chunk-b3kr8w41.js → chunk-m24yqkeq.js} +38 -26
  57. package/dist/chunk-m5ems3hh.js +410 -0
  58. package/dist/{chunk-8scgdznr.js → chunk-m83ybzf8.js} +15 -18
  59. package/dist/chunk-majsbncm.js +98 -0
  60. package/dist/chunk-mp2gt9yh.js +237 -0
  61. package/dist/chunk-n1twhqmf.js +54 -0
  62. package/dist/{chunk-gmee4mdc.js → chunk-naqcqj8n.js} +92 -106
  63. package/dist/chunk-q5sb5dcr.js +15 -0
  64. package/dist/{chunk-d1asgtke.js → chunk-qhdsjek6.js} +90 -121
  65. package/dist/{chunk-0gtxnxmd.js → chunk-qsh2nqz3.js} +85 -105
  66. package/dist/chunk-r0ms5tk1.js +76 -0
  67. package/dist/chunk-rwqwsanx.js +75 -0
  68. package/dist/chunk-sqsfk9p4.js +700 -0
  69. package/dist/{chunk-5gvbp2qa.js → chunk-x7bnzswh.js} +25 -18
  70. package/dist/{chunk-kc4jfnv7.js → chunk-z3ffn2b7.js} +851 -324
  71. package/dist/cli/commands/dev.d.ts +8 -0
  72. package/dist/cli/commands/doctor.d.ts +8 -0
  73. package/dist/cli/commands/generate.d.ts +26 -0
  74. package/dist/cli/commands/init.d.ts +13 -1
  75. package/dist/cli/commands/migrate.d.ts +33 -0
  76. package/dist/cli/commands/plugin.d.ts +13 -0
  77. package/dist/cli/commands/seed.d.ts +21 -0
  78. package/dist/cli/{commands/migrate-commands.d.ts → core/migrations/migrate-logic.d.ts} +2 -2
  79. package/dist/cli/core/migrations/schema-diff-engine.d.ts +12 -0
  80. package/dist/cli/core/migrations/schema-diff.d.ts +11 -0
  81. package/dist/cli/{seeding.d.ts → core/seeding/auto-seed.d.ts} +7 -4
  82. package/dist/cli/core/seeding/seed-logic.d.ts +2 -0
  83. package/dist/cli/index.d.ts +4 -0
  84. package/dist/cli/index.js +6 -170
  85. package/dist/client/RichText.d.ts +5 -0
  86. package/dist/client/rich-text-utils.d.ts +5 -0
  87. package/dist/client.js +3 -2
  88. package/dist/config.d.ts +3 -3
  89. package/dist/db/adapter.d.ts +2 -2
  90. package/dist/db/better-sqlite.d.ts +3 -3
  91. package/dist/db/better-sqlite.js +6 -5
  92. package/dist/db/bun-sqlite.d.ts +3 -3
  93. package/dist/db/bun-sqlite.js +6 -5
  94. package/dist/db/d1.d.ts +13 -7
  95. package/dist/db/d1.js +6 -5
  96. package/dist/db/index.d.ts +2 -2
  97. package/dist/db/index.js +10 -12
  98. package/dist/db/kysely/factory.d.ts +29 -0
  99. package/dist/db/kysely/plugins/audit-logging.d.ts +48 -0
  100. package/dist/db/kysely/plugins/auto-timestamps.d.ts +38 -0
  101. package/dist/db/kysely/plugins/cursor-pagination.d.ts +42 -0
  102. package/dist/db/kysely/plugins/deadlock-handler.d.ts +47 -0
  103. package/dist/db/kysely/plugins/draft-swapper.d.ts +33 -0
  104. package/dist/db/kysely/plugins/field-masking.d.ts +45 -0
  105. package/dist/db/kysely/plugins/fts-normalizer.d.ts +38 -0
  106. package/dist/db/kysely/plugins/i18n-fallback.d.ts +48 -0
  107. package/dist/db/kysely/plugins/id-generation.d.ts +42 -0
  108. package/dist/db/kysely/plugins/index.d.ts +16 -0
  109. package/dist/db/kysely/plugins/json-flattener.d.ts +38 -0
  110. package/dist/db/kysely/plugins/relationship-preloading.d.ts +39 -0
  111. package/dist/db/kysely/plugins/slug-generation.d.ts +37 -0
  112. package/dist/db/kysely/plugins/soft-delete.d.ts +42 -0
  113. package/dist/db/kysely/plugins/tree-resolver.d.ts +39 -0
  114. package/dist/db/kysely/plugins/virtual-field-resolver.d.ts +54 -0
  115. package/dist/db/kysely/plugins/zod-coercion.d.ts +34 -0
  116. package/dist/db/kysely/snapshot/snapshot-manager.d.ts +18 -0
  117. package/dist/db/postgres.d.ts +4 -4
  118. package/dist/db/postgres.js +6 -5
  119. package/dist/db/sqlite.d.ts +3 -3
  120. package/dist/db/sqlite.js +6 -5
  121. package/dist/index.d.ts +3 -0
  122. package/dist/index.js +161 -7
  123. package/dist/runtimes/bun.js +9 -6
  124. package/dist/runtimes/cloudflare-workers.d.ts +3 -1
  125. package/dist/runtimes/cloudflare-workers.js +36 -7
  126. package/dist/runtimes/next.js +8 -5
  127. package/dist/runtimes/node.js +9 -6
  128. package/dist/schema/collection.d.ts +116 -70
  129. package/dist/schema/compiler.d.ts +6 -0
  130. package/dist/schema/global.d.ts +38 -71
  131. package/dist/schema/index.d.ts +5 -4
  132. package/dist/schema/index.js +35 -550
  133. package/dist/schema/zod.d.ts +564 -0
  134. package/dist/server/admin-router.d.ts +1 -1
  135. package/dist/server/collection-router.d.ts +1 -1
  136. package/dist/server/graphql.d.ts +6 -0
  137. package/dist/server/handlers.d.ts +25 -7
  138. package/dist/server/middlewares/auth.d.ts +1 -1
  139. package/dist/server/plugins-loader.d.ts +1 -1
  140. package/dist/server/router.d.ts +2 -2
  141. package/dist/server/routers/admin.d.ts +1 -1
  142. package/dist/server/routers/auth.d.ts +1 -1
  143. package/dist/server/routers/collections.d.ts +4 -1
  144. package/dist/server/routers/plugins.d.ts +2 -2
  145. package/dist/server/setup-middlewares.d.ts +1 -1
  146. package/dist/server/system-router.d.ts +1 -1
  147. package/dist/server.js +11 -6
  148. package/dist/storage/adapters/cloudflare-r2.d.ts +11 -2
  149. package/dist/storage/index.js +39 -30
  150. package/dist/types.d.ts +255 -44
  151. package/dist/utils/context.d.ts +14 -0
  152. package/dist/utils/logger.d.ts +2 -0
  153. package/dist/utils/string.d.ts +10 -0
  154. package/dist/utils/webhooks-engine.d.ts +24 -0
  155. package/dist/validation.d.ts +67 -1
  156. package/dist/validator.d.ts +1 -0
  157. package/package.json +36 -33
  158. package/src/cli/index.ts +117 -0
  159. package/dist/chunk-6qq3ne6b.js +0 -288
  160. package/dist/chunk-6v1fw7q7.js +0 -126
  161. package/dist/chunk-7a9kn0np.js +0 -116
  162. package/dist/chunk-bexcv7xe.js +0 -36
  163. package/dist/chunk-d3ffeqp9.js +0 -87
  164. package/dist/chunk-fj19qccp.js +0 -78
  165. package/dist/chunk-j53pz21t.js +0 -20
  166. package/dist/chunk-mkn49zmy.js +0 -102
  167. package/dist/chunk-qb6ztvw9.js +0 -17
  168. package/dist/chunk-r39em4yj.js +0 -29
  169. package/dist/chunk-rsf0tpy1.js +0 -8
  170. package/dist/chunk-srsac177.js +0 -85
  171. package/dist/chunk-swtcpvhf.js +0 -2442
  172. package/dist/chunk-twpvxfce.js +0 -64
  173. package/dist/chunk-ywm4t2gm.js +0 -19
  174. package/dist/cli/commands/plugin-sync.d.ts +0 -1
  175. package/dist/cli/commands/seed-command.d.ts +0 -2
  176. package/dist/plugins/ui-bridge.d.ts +0 -12
  177. package/dist/schema/fields/base.d.ts +0 -84
  178. package/dist/schema/fields/index.d.ts +0 -147
  179. package/dist/schema/infer.d.ts +0 -55
  180. /package/dist/admin/ui/components/{ColumnVisibilityToggle.d.ts → column-visibility-toggle.d.ts} +0 -0
  181. /package/dist/admin/ui/components/{DataDetailView.d.ts → data-detail-view.d.ts} +0 -0
  182. /package/dist/cli/{d1-mock.d.ts → core/mocks/d1-mock.d.ts} +0 -0
  183. /package/dist/cli/{r2-mock.d.ts → core/mocks/r2-mock.d.ts} +0 -0
  184. /package/dist/cli/{commands → core/plugins}/plugin-build.d.ts +0 -0
  185. /package/dist/cli/{commands → core/plugins}/plugin-init.d.ts +0 -0
  186. /package/dist/cli/{commands → core/types}/generate-types.d.ts +0 -0
  187. /package/dist/{schema/fields/validation.test.d.ts → cli/seeding.test.d.ts} +0 -0
package/dist/types.d.ts CHANGED
@@ -1,8 +1,9 @@
1
- import type { z } from "zod";
1
+ import type { Faker } from "@faker-js/faker";
2
2
  import type { Session as BetterAuthSession, User as BetterAuthUser, Prettify } from "better-auth";
3
3
  import type { Context } from "hono";
4
4
  import type { icons } from "lucide-react";
5
- import type { AdminConfig, CollectionHooks, FieldType, AccessConfig as ValidationAccessConfig } from "./validation";
5
+ import type { z } from "zod";
6
+ import type { AdminConfig, FieldType } from "./validation";
6
7
  export type { FieldType };
7
8
  export type Session = BetterAuthSession;
8
9
  export type User = Prettify<BetterAuthUser & {
@@ -11,53 +12,95 @@ export type User = Prettify<BetterAuthUser & {
11
12
  banReason?: string | null;
12
13
  bannedUntil?: Date | null;
13
14
  }>;
14
- export type IconName = keyof typeof icons;
15
+ export type LucideIcons = keyof typeof icons;
16
+ /**
17
+ * Base properties shared by all field types in OpacaCMS.
18
+ */
15
19
  export interface BaseField {
20
+ /** The unique identifier for the field within the collection. Used as the database column name. */
16
21
  name: string;
22
+ /** The human-readable label displayed in the Admin UI. */
17
23
  label?: string;
24
+ /** Informational text displayed inside the input field when empty. */
18
25
  placeholder?: string;
26
+ /** Whether the field is required to have a value. */
19
27
  required?: boolean;
28
+ /** Whether the field's value must be unique across all records in the collection. */
20
29
  unique?: boolean;
30
+ /** Whether the field supports localized values (multi-language). */
21
31
  localized?: boolean;
32
+ /** The default value assigned to the field when a new record is created. */
22
33
  defaultValue?: unknown;
34
+ /** Custom validation logic or Zod schema for the field. */
23
35
  validate?: ((value: unknown) => boolean | string) | z.ZodTypeAny;
36
+ /** Access control configuration for this specific field. */
24
37
  access?: FieldAccessConfig;
38
+ /** Configuration for the Admin UI representation of the field. */
25
39
  admin?: {
40
+ /** Optional description displayed below the field in the Admin UI. */
26
41
  description?: string;
42
+ /** Logical condition that determines if the field should be visible in the Admin UI. */
27
43
  condition?: (data: Record<string, unknown>, siblingData: Record<string, unknown>) => boolean;
44
+ /** Logical condition that determines if the field should be marked as required in the Admin UI. */
45
+ requiredCondition?: (data: Record<string, unknown>, siblingData: Record<string, unknown>) => boolean;
46
+ /** If true, the field is hidden from the Admin UI forms but still accessible via API. */
28
47
  hidden?: boolean;
48
+ /** If true, the field is visible but cannot be edited in the Admin UI. */
29
49
  readOnly?: boolean;
50
+ /** The preferred width of the field in the Admin UI grid (e.g., '50%', '33%'). */
30
51
  width?: string;
52
+ /** Custom CSS styles for the field's container in the Admin UI. */
31
53
  style?: any;
54
+ /** Additional CSS class names for the field's container. */
32
55
  className?: string;
56
+ /** Custom UI components to override the default field and cell rendering. */
33
57
  components?: {
58
+ /** Path or name of a custom React component for the field input. */
34
59
  Field?: string;
60
+ /** Path or name of a custom React component for the table cell. */
35
61
  Cell?: string;
36
62
  };
63
+ /** Arbitrary props passed to the custom field component. */
37
64
  customProps?: Record<string, unknown>;
38
65
  };
66
+ /** Deprecated: Use admin.requiredCondition instead. */
67
+ requiredCondition?: (data: any) => boolean;
68
+ /** Deprecated: Use admin.condition instead. */
69
+ condition?: (data: any) => boolean;
70
+ /** Database reference configuration for foreign keys. */
39
71
  references?: {
72
+ /** Target table/collection name. */
40
73
  table: string;
74
+ /** Target column name (usually 'id'). */
41
75
  column: string;
76
+ /** Referential integrity action on record deletion. */
42
77
  onDelete?: "cascade" | "set null" | "restrict" | "no action";
43
78
  };
44
79
  }
80
+ /** A simple single-line text input field. */
45
81
  export interface TextField extends BaseField {
46
82
  type: "text";
47
83
  }
84
+ /** A URL-friendly string field, often generated from another field. */
48
85
  export interface SlugField extends BaseField {
49
86
  type: "slug";
87
+ /** The field name to generate the slug from (e.g., 'title'). */
50
88
  from: string;
89
+ /** Custom function to format the slug value. */
51
90
  format?: (value: string) => string;
52
91
  }
53
92
  export interface TextAreaField extends BaseField {
54
93
  type: "textarea";
55
94
  }
95
+ /** A numeric input field with optional constraints. */
56
96
  export interface NumberField extends BaseField {
57
97
  type: "number";
58
98
  options?: {
99
+ /** Minimum allowed value. */
59
100
  min?: number;
101
+ /** Maximum allowed value. */
60
102
  max?: number;
103
+ /** Stepping interval for the numeric input. */
61
104
  step?: number;
62
105
  [key: string]: any;
63
106
  };
@@ -69,15 +112,21 @@ export interface RichTextField extends BaseField {
69
112
  [key: string]: any;
70
113
  };
71
114
  }
115
+ /** A field for linking records from another collection. */
72
116
  export interface RelationshipField extends BaseField {
73
117
  type: "relationship";
118
+ /** The slug of the target collection to relate to. */
74
119
  relationTo: string;
120
+ /** If true, allows selecting multiple related records. */
75
121
  hasMany?: boolean;
122
+ /** The field from the target collection to use as the display label. */
76
123
  displayField?: string;
77
124
  }
125
+ /** A dropdown or multi-select field with predefined choices. */
78
126
  export interface SelectField extends BaseField {
79
127
  type: "select";
80
128
  options?: {
129
+ /** The list of available options. Can be simple strings or label/value objects. */
81
130
  choices: (string | {
82
131
  label: string;
83
132
  value: string;
@@ -85,9 +134,11 @@ export interface SelectField extends BaseField {
85
134
  [key: string]: any;
86
135
  };
87
136
  }
137
+ /** A set of radio buttons for selecting a single option from a list. */
88
138
  export interface RadioField extends BaseField {
89
139
  type: "radio";
90
140
  options: {
141
+ /** The list of available options. */
91
142
  choices: (string | {
92
143
  label: string;
93
144
  value: string;
@@ -98,9 +149,11 @@ export interface RadioField extends BaseField {
98
149
  export interface DateField extends BaseField {
99
150
  type: "date";
100
151
  }
152
+ /** A simple true/false toggle or checkbox field. */
101
153
  export interface BooleanField extends BaseField {
102
154
  type: "boolean";
103
155
  options?: {
156
+ /** How to render the field in the Admin UI. */
104
157
  display?: "switch" | "toggle" | "checkbox" | "select";
105
158
  [key: string]: unknown;
106
159
  };
@@ -108,65 +161,98 @@ export interface BooleanField extends BaseField {
108
161
  export interface JSONField extends BaseField {
109
162
  type: "json";
110
163
  }
164
+ /** A field for uploading and managing files. */
111
165
  export interface FileField extends BaseField {
112
166
  type: "file";
167
+ /** The storage bucket to use for this field. */
113
168
  bucket?: string;
114
169
  options?: {
170
+ /** Allowed MIME types (e.g., ['image/jpeg', 'application/pdf']). */
115
171
  allowedmime_types?: string[];
172
+ /** Maximum file size in bytes. */
116
173
  maxFileSize?: number;
174
+ /** Additional metadata fields to store alongside the file. */
117
175
  metaFields?: Field[];
118
176
  [key: string]: unknown;
119
177
  };
120
178
  }
179
+ /** A dynamic field that allows users to add multiple blocks of different types. */
121
180
  export interface BlocksField extends BaseField {
122
181
  type: "blocks";
182
+ /** The list of available block types for this field. */
123
183
  blocks: {
184
+ /** Unique identifier for the block type. */
124
185
  slug: string;
186
+ /** The fields that compose this block. */
125
187
  fields: Field[];
188
+ /** Human-readable label for the block type. */
126
189
  label?: string;
127
190
  }[];
128
191
  }
192
+ /** A logical grouping of fields. If a name is provided, the data will be nested under that key. */
129
193
  export interface GroupField extends BaseField {
130
194
  type: "group";
195
+ /** The fields that belong to this group. */
131
196
  fields: Field[];
132
197
  }
198
+ /** A layout field that renders its children in a single horizontal row. */
133
199
  export interface RowField extends Omit<BaseField, "name"> {
134
200
  type: "row";
201
+ /** Optional name. If provided, the row's data will be nested. */
135
202
  name?: string;
203
+ /** The fields to render in this row. */
136
204
  fields: Field[];
205
+ /** Optional label for the row header. */
137
206
  label?: string;
138
207
  }
208
+ /** A layout field that allows sections to be expanded or collapsed. */
139
209
  export interface CollapsibleField extends Omit<BaseField, "name"> {
140
210
  type: "collapsible";
211
+ /** Optional name. If provided, the data will be nested. */
141
212
  name?: string;
213
+ /** The human-readable label for the collapsible header. */
142
214
  label: string;
215
+ /** The fields to render inside the collapsible section. */
143
216
  fields: Field[];
144
217
  options?: {
218
+ /** Whether the section starts collapsed or expanded. */
145
219
  initiallyCollapsed?: boolean;
146
- useAsTitle?: string;
147
220
  [key: string]: any;
148
221
  };
149
222
  }
223
+ /** A field that allows users to add multiple instances of a set of fields. */
150
224
  export interface ArrayField extends BaseField {
151
225
  type: "array";
226
+ /** The fields that each array item will contain. */
152
227
  fields: Field[];
153
228
  }
229
+ /** A layout field that organizes child fields into clickable tabs. */
154
230
  export interface TabsField extends Omit<BaseField, "name"> {
155
231
  type: "tabs";
232
+ /** Optional name. If provided, the data will be nested. */
156
233
  name?: string;
234
+ /** The list of tabs to render. */
157
235
  tabs: {
236
+ /** The human-readable label for the tab. */
158
237
  label: string;
238
+ /** The fields to render within this tab. */
159
239
  fields: Field[];
160
240
  }[];
161
241
  }
242
+ /** A field that allows joining data from another collection based on a shared key. */
162
243
  export interface JoinField extends Omit<BaseField, "name"> {
163
244
  type: "join";
245
+ /** Optional name for the join mapping. */
164
246
  name?: string;
247
+ /** The slug of the target collection to join with. */
165
248
  collection: string;
249
+ /** The field name on the target collection to join on. */
166
250
  on: string;
167
251
  }
252
+ /** A read-only field whose value is computed dynamically at runtime. */
168
253
  export interface VirtualField extends BaseField {
169
254
  type: "virtual";
255
+ /** Function to resolve the field's value. */
170
256
  resolve: (args: {
171
257
  data: any;
172
258
  req: any;
@@ -174,6 +260,7 @@ export interface VirtualField extends BaseField {
174
260
  session: Session;
175
261
  apiKey?: ApiKey;
176
262
  }) => any | Promise<any>;
263
+ /** The data type of the resolved value. */
177
264
  returnType?: "string" | "number" | "boolean" | "json";
178
265
  }
179
266
  export interface UIField extends BaseField {
@@ -191,8 +278,20 @@ export interface AccessArgs {
191
278
  user: User | null;
192
279
  session: Session | null;
193
280
  apiKey?: ApiKey | null;
194
- data?: unknown;
195
- operation?: "read" | "create" | "update" | "delete";
281
+ data?: any;
282
+ id?: string;
283
+ operation: "read" | "create" | "update" | "delete";
284
+ }
285
+ export interface CollectionHookArgs<T = any> {
286
+ req: Context;
287
+ user: User | null;
288
+ session: Session | null;
289
+ apiKey?: ApiKey | null;
290
+ data: T;
291
+ originalDoc?: T;
292
+ query?: any;
293
+ id?: string;
294
+ operation: "create" | "update" | "delete";
196
295
  }
197
296
  export interface FieldAccessConfig {
198
297
  /** If true, the field is removed from API and UI. */
@@ -202,35 +301,98 @@ export interface FieldAccessConfig {
202
301
  /** If true, the input is visually disabled. */
203
302
  disabled?: boolean | ((args: AccessArgs) => boolean | Promise<boolean>);
204
303
  }
205
- export interface AccessConfig extends Omit<ValidationAccessConfig, "read" | "create" | "update" | "delete"> {
304
+ export interface AccessConfig {
206
305
  read?: boolean | ((args: AccessArgs) => boolean | Promise<boolean>);
207
306
  create?: boolean | ((args: AccessArgs) => boolean | Promise<boolean>);
208
307
  update?: boolean | ((args: AccessArgs) => boolean | Promise<boolean>);
209
308
  delete?: boolean | ((args: AccessArgs) => boolean | Promise<boolean>);
210
- }
211
- export type { CollectionHooks };
212
- export interface Collection {
309
+ requireApiKey?: boolean;
310
+ }
311
+ export interface CollectionHooks<T = any> {
312
+ beforeCreate?: (args: CollectionHookArgs<T>) => T | Promise<T> | void;
313
+ afterCreate?: (args: CollectionHookArgs<T>) => void | Promise<void>;
314
+ beforeUpdate?: (args: CollectionHookArgs<T>) => T | Promise<T> | void;
315
+ afterUpdate?: (args: CollectionHookArgs<T>) => void | Promise<void>;
316
+ beforeDelete?: (args: CollectionHookArgs<T>) => void | Promise<void>;
317
+ afterDelete?: (args: CollectionHookArgs<T>) => void | Promise<void>;
318
+ }
319
+ /** Configuration for an outgoing webhook triggered by CMS events. */
320
+ export interface OutgoingWebhookConfig<T = any> {
321
+ /** Outgoing webhooks are triggered by CMS events like 'after:create'. */
322
+ type: "outgoing";
323
+ /** The list of events that trigger this webhook. */
324
+ events: Array<"after:create" | "after:update" | "after:delete">;
325
+ /** The destination URL for the webhook payload. */
326
+ url: string;
327
+ /** Optional custom HTTP headers to include in the request. */
328
+ headers?: Record<string, string>;
329
+ /** Number of retry attempts in case of failure (uses exponential backoff). */
330
+ retries?: number;
331
+ /** Request timeout in milliseconds. */
332
+ timeoutMs?: number;
333
+ /** Function to reshape the payload data before sending. */
334
+ transform?: (data: T) => any;
335
+ }
336
+ /** Configuration for an incoming webhook providing a public API endpoint. */
337
+ export interface IncomingWebhookConfig<T = any> {
338
+ /** Incoming webhooks provide a public endpoint for third-party integrations (e.g., Stripe). */
339
+ type: "incoming";
340
+ /** The public URL path where OpacaCMS will listen for requests. */
341
+ path: string;
342
+ /** Secret or function used to verify the request signature (HMAC-SHA256). */
343
+ verifySignature?: string | ((req: Request) => boolean | Promise<boolean>);
344
+ /** The HTTP header that contains the signature (defaults to 'x-opaca-signature'). */
345
+ signatureHeader?: string;
346
+ /** Function to map the third-party payload to your CMS collection fields. */
347
+ mapPayload?: (payload: any) => Partial<T> | Promise<Partial<T>>;
348
+ /** Callback executed after a successful record synchronization. */
349
+ onSuccess?: (args: {
350
+ data: T;
351
+ payload: any;
352
+ operation: "create" | "update";
353
+ }) => void | Promise<void>;
354
+ }
355
+ /** Represents any webhook configuration supported by OpacaCMS. */
356
+ export type WebhookConfig<T = any> = OutgoingWebhookConfig<T> | IncomingWebhookConfig<T>;
357
+ /**
358
+ * Configuration for an OpacaCMS collection.
359
+ */
360
+ export interface Collection<T = any> {
361
+ /** Unique URL-friendly identifier for the collection. */
213
362
  slug: string;
363
+ /** Human-readable name for the collection. */
214
364
  label?: string;
215
- icon?: IconName;
365
+ /** Lucide icon displayed in the Admin UI sidebar. */
366
+ icon?: LucideIcons;
367
+ /** Custom base path for the collection's API endpoints. */
216
368
  apiPath?: string;
369
+ /** List of fields that define the collection's schema. */
217
370
  fields: Field[];
218
- hooks?: CollectionHooks;
371
+ /** Lifecycle hooks for custom logic before/after database operations. */
372
+ hooks?: CollectionHooks<T>;
373
+ /** Access control configuration for the collection. */
219
374
  access?: AccessConfig;
375
+ /** Versioning and draft support configuration. */
220
376
  versions?: {
377
+ /** Enable draft/published states for records. */
221
378
  drafts?: boolean;
379
+ /** Maximum number of historical versions to retain per record. */
222
380
  maxRevisions?: number;
381
+ /** Enable automatic background saving of drafts. */
223
382
  autosave?: boolean;
383
+ /** Whether records must be explicitly published to be visible via standard 'read' operations. */
384
+ requirePublish?: boolean;
224
385
  };
386
+ /** Automatically manage createdAt and updatedAt fields. */
225
387
  timestamps?: boolean | {
226
388
  createdAt?: string;
227
389
  updatedAt?: string;
228
390
  };
229
- webhooks?: {
230
- events: string[];
231
- url: string;
232
- headers?: Record<string, string>;
233
- }[];
391
+ /**
392
+ * Configuration for external webhooks.
393
+ * Supports both 'outgoing' (triggered by events) and 'incoming' (public endpoints).
394
+ */
395
+ webhooks?: WebhookConfig<T>[];
234
396
  auth?: boolean;
235
397
  admin?: {
236
398
  /**
@@ -262,22 +424,26 @@ export interface Collection {
262
424
  }[];
263
425
  } | boolean;
264
426
  hidden?: boolean;
427
+ seed?: (faker: Faker) => Partial<T> | Promise<Partial<T>>;
265
428
  }
266
429
  export interface Global {
267
430
  slug: string;
268
431
  fields: Field[];
269
432
  access?: AccessConfig;
270
433
  label?: string;
271
- icon?: IconName;
434
+ icon?: LucideIcons;
272
435
  timestamps?: boolean | {
273
436
  createdAt?: string;
274
437
  updatedAt?: string;
275
438
  };
439
+ seed?: (faker: Faker) => any | Promise<any>;
276
440
  }
277
441
  export interface OpacaPluginContext {
278
442
  config: OpacaConfig;
279
443
  logger: typeof import("./utils/logger").logger;
280
444
  settings?: Record<string, any>;
445
+ /** Environment variables (e.g. c.env in Cloudflare) */
446
+ env?: any;
281
447
  }
282
448
  export interface OpacaPlugin {
283
449
  /**
@@ -307,7 +473,7 @@ export interface OpacaPlugin {
307
473
  /**
308
474
  * Lucide icon name for the plugin
309
475
  */
310
- icon?: IconName;
476
+ icon?: LucideIcons;
311
477
  /**
312
478
  * Callback fired during OpacaCMS initialization.
313
479
  * Use this to extend the schema (collections, globals).
@@ -352,41 +518,59 @@ export interface OpacaPlugin {
352
518
  * Defines a configuration schema for the plugin.
353
519
  * This will be used to generate a settings form in the Admin UI.
354
520
  */
355
- configSchema?: Field[];
521
+ configSchema?: Field[] | z.ZodObject<any>;
356
522
  /**
357
523
  * Defines the administrative UI for the plugin.
358
- * This can point to local files during development or contain inlined source for production.
359
524
  */
360
525
  adminUI?: {
361
- /** The name of the custom element/component to render */
362
- component?: string;
363
- /** Absolute path to the source file (.tsx) - Used in dev/Node/Bun */
364
- filePath?: string;
365
- /** The inlined transpiled source code - Used in Workers/Production */
366
- source?: string;
526
+ /** The type of rendering to use. 'iframe' or 'ssr' both result in an iframe in the Admin UI. */
527
+ type: "iframe" | "ssr";
528
+ /** The path to the plugin's administrative UI. */
529
+ path: string;
367
530
  };
368
531
  /** Runtime settings for the plugin */
369
532
  settings?: Record<string, any>;
370
533
  }
534
+ /**
535
+ * Root configuration for an OpacaCMS instance.
536
+ */
371
537
  export interface OpacaConfig<Resource extends string = string> {
538
+ /** The name of your application, displayed in the Admin UI and emails. */
372
539
  appName?: string;
540
+ /** The base URL where the CMS server is hosted. */
373
541
  serverURL?: string;
542
+ /** A secure random string used for signing cookies and tokens. */
374
543
  secret?: string;
544
+ /** The database adapter used for data persistence (e.g., Drizzle, SQLite). */
375
545
  db: DatabaseAdapter;
546
+ /** Configuration for the internal logger. */
376
547
  logger?: OpacaLoggerConfig;
548
+ /** List of collections that define your content models. */
377
549
  collections: Collection[];
550
+ /** List of global singletons for site-wide settings. */
378
551
  globals?: Global[];
552
+ /** Configuration for the Admin UI dashboard and layout. */
379
553
  admin?: AdminConfig;
554
+ /** Configuration for the REST and GraphQL APIs. */
380
555
  api?: ApiConfig;
556
+ /** Root access control configuration for roles and permissions. */
381
557
  access?: OpacaAccessConfig<Resource>;
558
+ /** List of origins allowed to make cross-origin requests. */
382
559
  trustedOrigins?: string[] | ((request?: Request) => string[] | Promise<string[]>);
560
+ /** Configuration for authentication strategies and social providers. */
383
561
  auth?: OpacaAuthConfig;
562
+ /** Internationalization settings for multi-language support. */
384
563
  i18n?: {
564
+ /** List of supported locale codes. */
385
565
  locales: string[];
566
+ /** The default locale code for the application. */
386
567
  defaultLocale: string;
387
568
  };
569
+ /** Configuration for file storage backends (e.g., S3, local). */
388
570
  storages?: Record<string, any>;
571
+ /** Automatically run database migrations on server startup. */
389
572
  runMigrationsOnStartup?: boolean;
573
+ /** List of plugins to extend CMS functionality. */
390
574
  plugins?: OpacaPlugin[];
391
575
  }
392
576
  export interface OpacaLoggerConfig {
@@ -453,6 +637,14 @@ export interface OpacaAccessConfig<Resource extends string = string> {
453
637
  }
454
638
  export interface ApiConfig {
455
639
  maxLimit?: number;
640
+ rest?: {
641
+ enabled?: boolean;
642
+ };
643
+ graphql?: {
644
+ enabled?: boolean;
645
+ path?: string;
646
+ graphiql?: boolean;
647
+ };
456
648
  rateLimit?: {
457
649
  windowMs?: number;
458
650
  limit?: number;
@@ -464,7 +656,7 @@ export interface ApiConfig {
464
656
  openAPI?: {
465
657
  enabled?: boolean;
466
658
  path?: string;
467
- theme?: "alternate" | "default" | "moon" | "purple" | "solarized" | "bluePlanet" | "saturn" | "kepler" | "mars" | "deepSpace" | "none" | string;
659
+ theme?: "alternate" | "default" | "moon" | "purple" | "solarized" | "bluePlanet" | "saturn" | "kepler" | "mars" | "deepSpace" | "none";
468
660
  layout?: "modern" | "classic" | string;
469
661
  hideModels?: boolean;
470
662
  hideDownloadButton?: boolean;
@@ -476,6 +668,9 @@ export interface FindOptions {
476
668
  limit?: number;
477
669
  page?: number;
478
670
  sort?: string;
671
+ after?: string;
672
+ before?: string;
673
+ cursorColumn?: string;
479
674
  }
480
675
  export interface PaginatedResult<T> {
481
676
  docs: T[];
@@ -489,6 +684,8 @@ export interface PaginatedResult<T> {
489
684
  hasNextPage: boolean;
490
685
  prevPage: number | null;
491
686
  nextPage: number | null;
687
+ nextCursor?: string | null;
688
+ prevCursor?: string | null;
492
689
  }
493
690
  export interface DatabaseAdapter {
494
691
  name: string;
@@ -497,8 +694,8 @@ export interface DatabaseAdapter {
497
694
  /**
498
695
  * Internal ORM instance (e.g. Drizzle instance)
499
696
  */
500
- readonly db?: unknown;
501
- readonly raw?: unknown;
697
+ readonly db?: any;
698
+ readonly raw?: any;
502
699
  unsafe(sql: string, params?: unknown[]): Promise<unknown>;
503
700
  count(collection: string, query?: Record<string, unknown>): Promise<number>;
504
701
  create<T extends object>(collection: string, data: Partial<T>): Promise<T>;
@@ -531,7 +728,7 @@ export interface SerializableCollection {
531
728
  slug: string;
532
729
  apiPath?: string;
533
730
  label?: string;
534
- icon?: IconName;
731
+ icon?: LucideIcons;
535
732
  versions?: {
536
733
  drafts?: boolean;
537
734
  maxRevisions?: number;
@@ -550,10 +747,14 @@ export interface SerializableCollection {
550
747
  Field?: string;
551
748
  Cell?: string;
552
749
  };
750
+ condition?: (data: any) => boolean;
751
+ requiredCondition?: (data: any) => boolean;
553
752
  };
554
753
  required?: boolean;
555
754
  unique?: boolean;
556
755
  defaultValue?: unknown;
756
+ condition?: (data: any) => boolean;
757
+ requiredCondition?: (data: any) => boolean;
557
758
  options?: {
558
759
  defaultMode?: "simple" | "notion";
559
760
  [key: string]: unknown;
@@ -619,7 +820,7 @@ export interface SerializableConfig {
619
820
  globals?: {
620
821
  slug: string;
621
822
  label?: string;
622
- icon?: IconName;
823
+ icon?: LucideIcons;
623
824
  fields: {
624
825
  name?: string;
625
826
  type: FieldType;
@@ -672,7 +873,7 @@ export interface SerializableConfig {
672
873
  /**
673
874
  * Icon to be used in the admin UI.
674
875
  */
675
- icon?: IconName;
876
+ icon?: LucideIcons;
676
877
  /**
677
878
  * Assets to be loaded in the admin UI.
678
879
  */
@@ -680,20 +881,30 @@ export interface SerializableConfig {
680
881
  styles?: string[];
681
882
  scripts?: string[];
682
883
  };
683
- /**
684
- * Admin UI configuration.
685
- */
686
884
  adminUI?: {
687
- /**
688
- * The name of the custom element to register.
689
- */
690
- component?: string;
691
- /**
692
- * The inlined transpiled source code - Used in Workers/Production
693
- */
694
- source?: string;
885
+ type: "iframe" | "ssr";
886
+ path: string;
695
887
  };
696
888
  settings?: Record<string, any>;
697
889
  configSchema?: SerializableCollection["fields"];
698
890
  }[];
891
+ api?: {
892
+ rest?: {
893
+ enabled?: boolean;
894
+ };
895
+ graphql?: {
896
+ enabled?: boolean;
897
+ path?: string;
898
+ graphiql?: boolean;
899
+ };
900
+ openAPI?: {
901
+ enabled?: boolean;
902
+ path?: string;
903
+ theme?: "none" | "default" | "alternate" | "moon" | "purple" | "solarized" | "bluePlanet" | "deepSpace" | "saturn" | "kepler" | "elysiajs" | "fastify" | "mars" | "laserwave" | string;
904
+ layout?: "modern" | "classic" | string;
905
+ hideModels?: boolean;
906
+ hideDownloadButton?: boolean;
907
+ customCss?: string;
908
+ };
909
+ };
699
910
  }
@@ -0,0 +1,14 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ export interface RequestContextData {
3
+ userId?: string | null;
4
+ previousData?: any;
5
+ }
6
+ export declare const requestContext: AsyncLocalStorage<RequestContextData>;
7
+ /**
8
+ * Gets the current user ID from the request context.
9
+ */
10
+ export declare function getUserIdFromContext(): string | null;
11
+ /**
12
+ * Gets the stashed previous data from the request context.
13
+ */
14
+ export declare function getPreviousDataFromContext(): any;
@@ -8,6 +8,8 @@ export declare class OpacaLogger {
8
8
  debug(message: string, ...args: any[]): void;
9
9
  warn(message: string, ...args: any[]): void;
10
10
  error(message: string, ...args: any[]): void;
11
+ log(message: string, ...args: any[]): void;
12
+ bold(msg: string): string;
11
13
  format(color: "green" | "red" | "yellow" | "gray", msg: string): string;
12
14
  }
13
15
  export declare const logger: OpacaLogger;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Sanitizes a string to be a valid GraphQL name.
3
+ * GraphQL names must match /[_a-zA-Z][_a-zA-Z0-9]* /
4
+ */
5
+ export declare function sanitizeGraphQLName(name: string): string;
6
+ /**
7
+ * Generates a random name for a migration.
8
+ * Uses a combination of an adjective and a noun.
9
+ */
10
+ export declare function getRandomMigrationName(): string;