opacacms 0.1.21 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/README.md +792 -50
  2. package/dist/admin/auth-client.d.ts +39 -39
  3. package/dist/admin/index.js +2360 -1392
  4. package/dist/admin/react.d.ts +1 -1
  5. package/dist/admin/react.js +8 -0
  6. package/dist/admin/router.d.ts +1 -0
  7. package/dist/admin/stores/ui.d.ts +10 -0
  8. package/dist/admin/ui/admin-layout.d.ts +4 -4
  9. package/dist/admin/ui/components/DataDetailView.d.ts +1 -1
  10. package/dist/admin/ui/components/DetailSheet.d.ts +19 -0
  11. package/dist/admin/ui/components/PluginSettingsForm.d.ts +11 -0
  12. package/dist/admin/ui/components/fields/BooleanField.d.ts +2 -1
  13. package/dist/admin/ui/components/fields/DateField.d.ts +1 -1
  14. package/dist/admin/ui/components/fields/FieldLabel.d.ts +11 -0
  15. package/dist/admin/ui/components/fields/FileField.d.ts +1 -1
  16. package/dist/admin/ui/components/fields/NumberField.d.ts +1 -1
  17. package/dist/admin/ui/components/fields/RadioField.d.ts +1 -1
  18. package/dist/admin/ui/components/fields/RelationshipField.d.ts +3 -1
  19. package/dist/admin/ui/components/fields/SelectField.d.ts +1 -1
  20. package/dist/admin/ui/components/fields/TextAreaField.d.ts +1 -1
  21. package/dist/admin/ui/components/fields/TextField.d.ts +1 -1
  22. package/dist/admin/ui/components/fields/VirtualField.d.ts +1 -0
  23. package/dist/admin/ui/components/fields/index.d.ts +16 -16
  24. package/dist/admin/ui/components/fields/richtext-editor/index.d.ts +1 -1
  25. package/dist/admin/ui/components/media/AssetManagerModal.d.ts +1 -1
  26. package/dist/admin/ui/components/toast.d.ts +1 -1
  27. package/dist/admin/ui/components/ui/accordion.d.ts +1 -1
  28. package/dist/admin/ui/components/ui/button.d.ts +1 -1
  29. package/dist/admin/ui/components/ui/collapsible.d.ts +1 -1
  30. package/dist/admin/ui/components/ui/dialog.d.ts +1 -1
  31. package/dist/admin/ui/components/ui/group.d.ts +1 -1
  32. package/dist/admin/ui/components/ui/index.d.ts +17 -17
  33. package/dist/admin/ui/components/ui/input.d.ts +1 -1
  34. package/dist/admin/ui/components/ui/label.d.ts +1 -1
  35. package/dist/admin/ui/components/ui/radio-group.d.ts +1 -1
  36. package/dist/admin/ui/components/ui/relationship.d.ts +4 -4
  37. package/dist/admin/ui/components/ui/select.d.ts +1 -1
  38. package/dist/admin/ui/components/ui/sheet.d.ts +1 -1
  39. package/dist/admin/ui/components/ui/tabs.d.ts +1 -1
  40. package/dist/admin/ui/components/versions-sheet.d.ts +11 -0
  41. package/dist/admin/ui/views/media-registry-view.d.ts +1 -1
  42. package/dist/admin/ui/views/settings-view.d.ts +2 -2
  43. package/dist/admin/vue.js +8 -0
  44. package/dist/admin/webcomponent.js +20 -2
  45. package/dist/admin.css +1 -1
  46. package/dist/auth/index.d.ts +101 -41
  47. package/dist/{chunk-fqastxq9.js → chunk-06ks4ggh.js} +133 -44
  48. package/dist/{chunk-xrfhhz85.js → chunk-2es275xs.js} +480 -85
  49. package/dist/{chunk-v521d72w.js → chunk-3rdhbedb.js} +1 -1
  50. package/dist/chunk-51z3x7kq.js +20 -0
  51. package/dist/{chunk-7fyepksb.js → chunk-526a3gqx.js} +1 -1
  52. package/dist/{chunk-0sdceeys.js → chunk-6d1vdfwa.js} +121 -31
  53. package/dist/{chunk-wmvjvn7b.js → chunk-6qq3ne6b.js} +39 -1
  54. package/dist/{chunk-0am1m47g.js → chunk-6v1fw7q7.js} +5 -5
  55. package/dist/{chunk-t9v845m2.js → chunk-7y1nbmw6.js} +34 -3
  56. package/dist/chunk-8scgdznr.js +44 -0
  57. package/dist/{chunk-mycmsjd9.js → chunk-b3kr8w41.js} +57 -6
  58. package/dist/chunk-bexcv7xe.js +36 -0
  59. package/dist/{chunk-ekxkvqjm.js → chunk-bygjkgrx.js} +124 -34
  60. package/dist/{chunk-16vgcf3k.js → chunk-byq8g0rd.js} +1 -1
  61. package/dist/{chunk-cpw2y3pn.js → chunk-dykn5hr6.js} +7 -7
  62. package/dist/chunk-fj19qccp.js +78 -0
  63. package/dist/{chunk-n1xraw7j.js → chunk-g1jb60xd.js} +1 -1
  64. package/dist/{chunk-xa7rjsn2.js → chunk-j53pz21t.js} +2 -2
  65. package/dist/{chunk-nb7ctdg8.js → chunk-jdfw4v3r.js} +1 -1
  66. package/dist/chunk-mkn49zmy.js +102 -0
  67. package/dist/{chunk-59sg3pw9.js → chunk-n133qpsm.js} +128 -34
  68. package/dist/{chunk-2kyhqvhc.js → chunk-qxt9vge8.js} +1 -1
  69. package/dist/chunk-r39em4yj.js +29 -0
  70. package/dist/chunk-rqyjjqgy.js +91 -0
  71. package/dist/chunk-rsf0tpy1.js +8 -0
  72. package/dist/chunk-t0zg026p.js +71 -0
  73. package/dist/{chunk-61kwqve4.js → chunk-tfnaf41w.js} +118 -37
  74. package/dist/chunk-twpvxfce.js +64 -0
  75. package/dist/{chunk-ybbbqj63.js → chunk-v9z61v3g.js} +15 -0
  76. package/dist/{chunk-jwjk85ze.js → chunk-ywm4t2gm.js} +6 -2
  77. package/dist/cli/commands/plugin-build.d.ts +1 -0
  78. package/dist/cli/commands/plugin-init.d.ts +1 -0
  79. package/dist/cli/commands/plugin-sync.d.ts +1 -0
  80. package/dist/cli/index.js +24 -6
  81. package/dist/config-utils.d.ts +1 -1
  82. package/dist/config.d.ts +21 -4
  83. package/dist/db/adapter.d.ts +2 -2
  84. package/dist/db/better-sqlite.d.ts +2 -1
  85. package/dist/db/better-sqlite.js +5 -5
  86. package/dist/db/bun-sqlite.d.ts +2 -1
  87. package/dist/db/bun-sqlite.js +5 -5
  88. package/dist/db/d1.d.ts +1 -1
  89. package/dist/db/d1.js +5 -5
  90. package/dist/db/index.js +9 -9
  91. package/dist/db/postgres.d.ts +3 -3
  92. package/dist/db/postgres.js +5 -5
  93. package/dist/db/sqlite.d.ts +2 -1
  94. package/dist/db/sqlite.js +5 -5
  95. package/dist/index.js +4 -3
  96. package/dist/plugins/index.d.ts +1 -0
  97. package/dist/plugins/ui-bridge.d.ts +12 -0
  98. package/dist/plugins/utils.d.ts +5 -0
  99. package/dist/runtimes/bun.js +13 -7
  100. package/dist/runtimes/cloudflare-workers.js +5 -5
  101. package/dist/runtimes/next.js +5 -5
  102. package/dist/runtimes/node.js +13 -7
  103. package/dist/schema/collection.d.ts +9 -26
  104. package/dist/schema/fields/base.d.ts +3 -2
  105. package/dist/schema/fields/index.d.ts +12 -0
  106. package/dist/schema/fields/validation.test.d.ts +1 -0
  107. package/dist/schema/global.d.ts +10 -7
  108. package/dist/schema/index.js +22 -6
  109. package/dist/server/admin-router.d.ts +2 -2
  110. package/dist/server/admin.d.ts +2 -1
  111. package/dist/server/collection-router.d.ts +1 -1
  112. package/dist/server/handlers.d.ts +10 -0
  113. package/dist/server/middlewares/admin.d.ts +2 -2
  114. package/dist/server/middlewares/auth.d.ts +1 -1
  115. package/dist/server/middlewares/context.d.ts +2 -0
  116. package/dist/server/middlewares/rate-limit.d.ts +1 -1
  117. package/dist/server/openapi.d.ts +2 -0
  118. package/dist/server/plugins-loader.d.ts +6 -0
  119. package/dist/server/router.d.ts +3 -3
  120. package/dist/server/routers/admin.d.ts +2 -2
  121. package/dist/server/routers/auth.d.ts +1 -1
  122. package/dist/server/routers/collections.d.ts +1 -1
  123. package/dist/server/routers/plugins.d.ts +18 -0
  124. package/dist/server/setup-middlewares.d.ts +2 -2
  125. package/dist/server/system-router.d.ts +1 -1
  126. package/dist/server.js +11 -7
  127. package/dist/storage/adapters/local.d.ts +1 -1
  128. package/dist/storage/adapters/s3.d.ts +1 -1
  129. package/dist/storage/index.js +34 -25
  130. package/dist/types.d.ts +224 -17
  131. package/dist/utils/logger.d.ts +13 -35
  132. package/dist/validation.d.ts +40 -0
  133. package/dist/validator.d.ts +1 -1
  134. package/package.json +41 -27
  135. package/dist/admin/ui/components/DataDetailSheet.d.ts +0 -13
  136. package/dist/admin/ui/components/ui/relationship-detail-sheet.d.ts +0 -9
  137. package/dist/chunk-62ev8gnc.js +0 -41
  138. package/dist/chunk-j4d50hrx.js +0 -20
@@ -1,7 +1,7 @@
1
1
  import { Hono } from "hono";
2
2
  import type { Auth } from "../../auth";
3
3
  import type { OpacaConfig } from "../../types";
4
- import type { ApiContextVariables } from "../router";
4
+ import type { ApiContextVariables } from "../../server/router";
5
5
  export declare function createAuthRouter(config: OpacaConfig, state: {
6
6
  auth: Auth | undefined;
7
7
  }): Hono<{
@@ -1,7 +1,7 @@
1
1
  import { Hono } from "hono";
2
2
  import type { Auth } from "../../auth";
3
3
  import type { OpacaConfig } from "../../types";
4
- import type { ApiContextVariables } from "../router";
4
+ import type { ApiContextVariables } from "../../server/router";
5
5
  export declare function mountCollectionRoutes(router: Hono<{
6
6
  Variables: ApiContextVariables;
7
7
  }>, config: OpacaConfig, state: {
@@ -0,0 +1,18 @@
1
+ import type { Hono } from "hono";
2
+ import type { OpacaConfig } from "../../types";
3
+ import type { ApiContextVariables } from "../setup-middlewares";
4
+ /**
5
+ * Mounts all plugin-specific routes and middlewares.
6
+ *
7
+ * @param config - The OpacaCMS configuration.
8
+ * @param settings - The loaded plugin settings.
9
+ * @param logger - The system logger.
10
+ * @param router - The Hono router instance.
11
+ */
12
+ export declare function mountPluginRoutes(config: OpacaConfig, settings: Record<string, any>, logger: typeof import("../../utils/logger").logger, router: Hono<{
13
+ Variables: ApiContextVariables;
14
+ }>): void;
15
+ /**
16
+ * Fires the onInitComplete hook for all plugins.
17
+ */
18
+ export declare function firePluginInitComplete(config: OpacaConfig, settings: Record<string, any>, logger: typeof import("../../utils/logger").logger): void;
@@ -1,8 +1,8 @@
1
1
  import type { Hono } from "hono";
2
2
  import type { Auth } from "../auth";
3
3
  import type { OpacaConfig } from "../types";
4
- import { type AuthContextVariables } from "./middlewares/auth";
5
- import { type OpacaContextVariables } from "./middlewares/context";
4
+ import { type AuthContextVariables } from "../server/middlewares/auth";
5
+ import { type OpacaContextVariables } from "../server/middlewares/context";
6
6
  export type ApiContextVariables = OpacaContextVariables & AuthContextVariables;
7
7
  export declare function setupMiddlewares(router: Hono<{
8
8
  Variables: ApiContextVariables;
@@ -1,6 +1,6 @@
1
1
  import { Hono } from "hono";
2
2
  import type { OpacaConfig } from "../types";
3
- import type { ApiContextVariables } from "./router";
3
+ import type { ApiContextVariables } from "../server/router";
4
4
  export declare function createSystemRouter(config: OpacaConfig): Hono<{
5
5
  Variables: ApiContextVariables;
6
6
  }, import("hono/types").BlankSchema, "/">;
package/dist/server.js CHANGED
@@ -3,20 +3,24 @@ import {
3
3
  createAdminHandlers,
4
4
  createGlobalHandlers,
5
5
  createHandlers,
6
- hydrateDoc
7
- } from "./chunk-xrfhhz85.js";
6
+ hydrateDoc,
7
+ parsePopulate,
8
+ populateDoc
9
+ } from "./chunk-2es275xs.js";
8
10
  import {
9
11
  defineConfig
10
- } from "./chunk-t9v845m2.js";
11
- import"./chunk-mycmsjd9.js";
12
+ } from "./chunk-7y1nbmw6.js";
13
+ import"./chunk-b3kr8w41.js";
12
14
  import {
13
15
  BaseDatabaseAdapter
14
16
  } from "./chunk-s8mqwnm1.js";
15
- import"./chunk-62ev8gnc.js";
16
- import"./chunk-2kyhqvhc.js";
17
- import"./chunk-ybbbqj63.js";
17
+ import"./chunk-qxt9vge8.js";
18
+ import"./chunk-v9z61v3g.js";
19
+ import"./chunk-t0zg026p.js";
18
20
  import"./chunk-8sqjbsgt.js";
19
21
  export {
22
+ populateDoc,
23
+ parsePopulate,
20
24
  hydrateDoc,
21
25
  defineConfig,
22
26
  createHandlers,
@@ -1,4 +1,4 @@
1
- import type { StorageAdapter, StorageAdapterConfig } from "../types";
1
+ import type { StorageAdapter, StorageAdapterConfig } from "../../storage/types";
2
2
  export interface LocalAdapterConfig extends StorageAdapterConfig {
3
3
  uploadDir: string;
4
4
  publicUrl: string;
@@ -1,4 +1,4 @@
1
- import type { StorageAdapter, StorageAdapterConfig } from "../types";
1
+ import type { StorageAdapter, StorageAdapterConfig } from "../../storage/types";
2
2
  export interface S3AdapterConfig extends StorageAdapterConfig {
3
3
  region: string;
4
4
  bucket: string;
@@ -219,21 +219,25 @@ function createLocalAdapter(config) {
219
219
  };
220
220
  }
221
221
  // src/storage/adapters/s3.ts
222
- import {
223
- DeleteObjectCommand,
224
- GetObjectCommand,
225
- HeadObjectCommand,
226
- PutObjectCommand,
227
- S3Client
228
- } from "@aws-sdk/client-s3";
229
- import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
230
222
  function createS3Adapter(config) {
231
- const s3Client = new S3Client({
232
- region: config.region,
233
- endpoint: config.endpoint,
234
- credentials: config.credentials,
235
- forcePathStyle: config.forcePathStyle
236
- });
223
+ let _s3Client = null;
224
+ let _sdk = null;
225
+ const getSdk = async () => {
226
+ if (_sdk)
227
+ return _sdk;
228
+ const [clientS3, presigner] = await Promise.all([
229
+ import("@aws-sdk/client-s3"),
230
+ import("@aws-sdk/s3-request-presigner")
231
+ ]);
232
+ _sdk = { ...clientS3, ...presigner };
233
+ _s3Client = new _sdk.S3Client({
234
+ region: config.region,
235
+ endpoint: config.endpoint,
236
+ credentials: config.credentials,
237
+ forcePathStyle: config.forcePathStyle
238
+ });
239
+ return _sdk;
240
+ };
237
241
  const getFullKey = (filename) => {
238
242
  if (config.prefix) {
239
243
  const p = config.prefix.replace(/\/$/, "");
@@ -252,6 +256,7 @@ function createS3Adapter(config) {
252
256
  name: "s3",
253
257
  async upload(file, options) {
254
258
  try {
259
+ const sdk = await getSdk();
255
260
  if (options?.allowedmime_types && !options.allowedmime_types.includes(file.mime_type)) {
256
261
  throw new Invalidmime_typeError("s3", options.allowedmime_types, file.mime_type);
257
262
  }
@@ -267,7 +272,7 @@ function createS3Adapter(config) {
267
272
  }
268
273
  const key = getFullKey(finalFilename);
269
274
  const body = file.buffer || file.stream;
270
- const command = new PutObjectCommand({
275
+ const command = new sdk.PutObjectCommand({
271
276
  Bucket: config.bucket,
272
277
  Key: key,
273
278
  Body: body,
@@ -275,7 +280,7 @@ function createS3Adapter(config) {
275
280
  ContentLength: file.filesize,
276
281
  ACL: config.acl || "private"
277
282
  });
278
- await s3Client.send(command);
283
+ await _s3Client.send(command);
279
284
  return {
280
285
  filename: finalFilename,
281
286
  mime_type: file.mime_type,
@@ -290,22 +295,24 @@ function createS3Adapter(config) {
290
295
  },
291
296
  async delete(filename) {
292
297
  try {
293
- const command = new DeleteObjectCommand({
298
+ const sdk = await getSdk();
299
+ const command = new sdk.DeleteObjectCommand({
294
300
  Bucket: config.bucket,
295
301
  Key: getFullKey(filename)
296
302
  });
297
- await s3Client.send(command);
303
+ await _s3Client.send(command);
298
304
  } catch (error) {
299
305
  throw new StorageError("s3", "delete", `Failed to delete ${filename} from S3 bucket ${config.bucket}`, error);
300
306
  }
301
307
  },
302
308
  async exists(filename) {
303
309
  try {
304
- const command = new HeadObjectCommand({
310
+ const sdk = await getSdk();
311
+ const command = new sdk.HeadObjectCommand({
305
312
  Bucket: config.bucket,
306
313
  Key: getFullKey(filename)
307
314
  });
308
- await s3Client.send(command);
315
+ await _s3Client.send(command);
309
316
  return true;
310
317
  } catch (error) {
311
318
  if (error.name === "NotFound" || error.$metadata?.httpStatusCode === 404)
@@ -315,24 +322,26 @@ function createS3Adapter(config) {
315
322
  },
316
323
  async generatePresignedUrl(filename, operation, expiresInSeconds = 3600) {
317
324
  try {
325
+ const sdk = await getSdk();
318
326
  let command;
319
327
  if (operation === "write") {
320
- command = new PutObjectCommand({ Bucket: config.bucket, Key: getFullKey(filename) });
328
+ command = new sdk.PutObjectCommand({ Bucket: config.bucket, Key: getFullKey(filename) });
321
329
  } else {
322
- command = new GetObjectCommand({ Bucket: config.bucket, Key: getFullKey(filename) });
330
+ command = new sdk.GetObjectCommand({ Bucket: config.bucket, Key: getFullKey(filename) });
323
331
  }
324
- return await getSignedUrl(s3Client, command, { expiresIn: expiresInSeconds });
332
+ return await sdk.getSignedUrl(_s3Client, command, { expiresIn: expiresInSeconds });
325
333
  } catch (error) {
326
334
  throw new StorageError("s3", "presign", `Failed to generate presigned URL for ${filename}`, error);
327
335
  }
328
336
  },
329
337
  async download(filename) {
330
338
  try {
331
- const command = new GetObjectCommand({
339
+ const sdk = await getSdk();
340
+ const command = new sdk.GetObjectCommand({
332
341
  Bucket: config.bucket,
333
342
  Key: getFullKey(filename)
334
343
  });
335
- const response = await s3Client.send(command);
344
+ const response = await _s3Client.send(command);
336
345
  if (!response.Body) {
337
346
  throw new StorageError("s3", "download", `File not found: ${filename}`);
338
347
  }
package/dist/types.d.ts CHANGED
@@ -1,8 +1,16 @@
1
- import type { Session, User } from "better-auth";
1
+ import type { z } from "zod";
2
+ import type { Session as BetterAuthSession, User as BetterAuthUser, Prettify } from "better-auth";
2
3
  import type { Context } from "hono";
3
4
  import type { icons } from "lucide-react";
4
- import type { AdminConfig, CollectionHooks, FieldType, AccessConfig as ValidationAccessConfig, Collection as ValidationCollection, Global as ValidationGlobal, OpacaConfig as ValidationOpacaConfig } from "./validation";
5
+ import type { AdminConfig, CollectionHooks, FieldType, AccessConfig as ValidationAccessConfig } from "./validation";
5
6
  export type { FieldType };
7
+ export type Session = BetterAuthSession;
8
+ export type User = Prettify<BetterAuthUser & {
9
+ role?: string;
10
+ banned?: boolean;
11
+ banReason?: string | null;
12
+ bannedUntil?: Date | null;
13
+ }>;
6
14
  export type IconName = keyof typeof icons;
7
15
  export interface BaseField {
8
16
  name: string;
@@ -12,7 +20,7 @@ export interface BaseField {
12
20
  unique?: boolean;
13
21
  localized?: boolean;
14
22
  defaultValue?: unknown;
15
- validate?: (value: unknown) => boolean | string;
23
+ validate?: ((value: unknown) => boolean | string) | z.ZodTypeAny;
16
24
  access?: FieldAccessConfig;
17
25
  admin?: {
18
26
  description?: string;
@@ -26,6 +34,7 @@ export interface BaseField {
26
34
  Field?: string;
27
35
  Cell?: string;
28
36
  };
37
+ customProps?: Record<string, unknown>;
29
38
  };
30
39
  references?: {
31
40
  table: string;
@@ -167,7 +176,10 @@ export interface VirtualField extends BaseField {
167
176
  }) => any | Promise<any>;
168
177
  returnType?: "string" | "number" | "boolean" | "json";
169
178
  }
170
- export type Field = TextField | SlugField | TextAreaField | NumberField | RichTextField | RelationshipField | SelectField | VirtualField | RadioField | DateField | BooleanField | JSONField | FileField | BlocksField | GroupField | RowField | CollapsibleField | TabsField | JoinField | ArrayField;
179
+ export interface UIField extends BaseField {
180
+ type: "ui";
181
+ }
182
+ export type Field = TextField | SlugField | TextAreaField | NumberField | RichTextField | RelationshipField | SelectField | VirtualField | RadioField | DateField | BooleanField | JSONField | FileField | BlocksField | GroupField | RowField | CollapsibleField | TabsField | JoinField | ArrayField | UIField;
171
183
  export interface ApiKey {
172
184
  id: string;
173
185
  name: string | null;
@@ -197,18 +209,20 @@ export interface AccessConfig extends Omit<ValidationAccessConfig, "read" | "cre
197
209
  delete?: boolean | ((args: AccessArgs) => boolean | Promise<boolean>);
198
210
  }
199
211
  export type { CollectionHooks };
200
- export interface Collection extends Omit<ValidationCollection, "fields" | "hooks" | "access" | "admin" | "apiPath" | "versions" | "webhooks" | "timestamps"> {
201
- fields: Field[];
212
+ export interface Collection {
213
+ slug: string;
214
+ label?: string;
215
+ icon?: IconName;
202
216
  apiPath?: string;
217
+ fields: Field[];
203
218
  hooks?: CollectionHooks;
204
219
  access?: AccessConfig;
205
- icon?: IconName;
206
220
  versions?: {
207
221
  drafts?: boolean;
208
222
  maxRevisions?: number;
209
223
  autosave?: boolean;
210
224
  };
211
- timestamps: boolean | {
225
+ timestamps?: boolean | {
212
226
  createdAt?: string;
213
227
  updatedAt?: string;
214
228
  };
@@ -217,11 +231,23 @@ export interface Collection extends Omit<ValidationCollection, "fields" | "hooks
217
231
  url: string;
218
232
  headers?: Record<string, string>;
219
233
  }[];
234
+ auth?: boolean;
220
235
  admin?: {
221
- defaultColumns?: string[];
236
+ /**
237
+ * If true, the collection's title will be used as a breadcrumb.
238
+ */
222
239
  useAsTitle?: string;
240
+ /**
241
+ * If true, the collection will be hidden from the Admin UI sidebar but still accessible via direct URL.
242
+ */
223
243
  hidden?: boolean;
244
+ /**
245
+ * If true, the collection will be completely disabled from the Admin UI (hidden from sidebar and blocked via direct URL).
246
+ */
224
247
  disableAdmin?: boolean;
248
+ /**
249
+ * Predefined filtered views for the collection list.
250
+ */
225
251
  views?: {
226
252
  name: string;
227
253
  filter: Record<string, any>;
@@ -235,21 +261,121 @@ export interface Collection extends Omit<ValidationCollection, "fields" | "hooks
235
261
  }) => Promise<unknown>;
236
262
  }[];
237
263
  } | boolean;
264
+ hidden?: boolean;
238
265
  }
239
- export interface Global extends Omit<ValidationGlobal, "fields" | "access" | "timestamps"> {
266
+ export interface Global {
267
+ slug: string;
240
268
  fields: Field[];
241
269
  access?: AccessConfig;
242
270
  label?: string;
243
271
  icon?: IconName;
244
- timestamps: boolean | {
272
+ timestamps?: boolean | {
245
273
  createdAt?: string;
246
274
  updatedAt?: string;
247
275
  };
248
276
  }
249
- export interface OpacaConfig<Resource extends string = string> extends Omit<ValidationOpacaConfig, "collections" | "globals" | "admin" | "api" | "access" | "trustedOrigins" | "auth" | "i18n"> {
277
+ export interface OpacaPluginContext {
278
+ config: OpacaConfig;
279
+ logger: typeof import("./utils/logger").logger;
280
+ settings?: Record<string, any>;
281
+ }
282
+ export interface OpacaPlugin {
283
+ /**
284
+ * Unique name/slug for the plugin (e.g. 'stripe')
285
+ */
286
+ name: string;
287
+ /**
288
+ * User-friendly label for the plugin
289
+ */
290
+ label?: string;
291
+ /**
292
+ * Short description of what the plugin does
293
+ */
294
+ description?: string;
295
+ /**
296
+ * Plugin version (e.g. '1.0.0')
297
+ */
298
+ version?: string;
299
+ /**
300
+ * Plugin author
301
+ */
302
+ author?: string;
303
+ /**
304
+ * Link to plugin documentation or homepage
305
+ */
306
+ homepage?: string;
307
+ /**
308
+ * Lucide icon name for the plugin
309
+ */
310
+ icon?: IconName;
311
+ /**
312
+ * Callback fired during OpacaCMS initialization.
313
+ * Use this to extend the schema (collections, globals).
314
+ */
315
+ onInit?: (context: OpacaPluginContext) => OpacaConfig | void;
316
+ /**
317
+ * Callback fired when the Hono router is initialized.
318
+ * Use this to add custom API routes.
319
+ */
320
+ onRouterInit?: (app: import("hono").Hono<any, any, any>, context: OpacaPluginContext) => void;
321
+ /**
322
+ * Callback fired after all plugins have been initialized.
323
+ */
324
+ onInitComplete?: (context: OpacaPluginContext) => void | Promise<void>;
325
+ /**
326
+ * Hook called on every CMS API request.
327
+ * Return false to block the request.
328
+ */
329
+ onRequest?: (c: import("hono").Context) => void | false | Promise<void | false>;
330
+ /**
331
+ * Hook for static site generation (SSG) output.
332
+ */
333
+ onExport?: (args: {
334
+ pages: any[];
335
+ outputDir: string;
336
+ }) => void | Promise<void | {
337
+ path: string;
338
+ content: string;
339
+ }[]>;
340
+ /**
341
+ * Callback fired when the CMS is shutting down.
342
+ */
343
+ onDestroy?: () => void | Promise<void>;
344
+ /**
345
+ * Defines UI assets (scripts, styles) to be loaded by the Admin UI.
346
+ */
347
+ adminAssets?: () => {
348
+ styles?: string[];
349
+ scripts?: string[];
350
+ };
351
+ /**
352
+ * Defines a configuration schema for the plugin.
353
+ * This will be used to generate a settings form in the Admin UI.
354
+ */
355
+ configSchema?: Field[];
356
+ /**
357
+ * Defines the administrative UI for the plugin.
358
+ * This can point to local files during development or contain inlined source for production.
359
+ */
360
+ 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;
367
+ };
368
+ /** Runtime settings for the plugin */
369
+ settings?: Record<string, any>;
370
+ }
371
+ export interface OpacaConfig<Resource extends string = string> {
372
+ appName?: string;
373
+ serverURL?: string;
374
+ secret?: string;
375
+ db: DatabaseAdapter;
376
+ logger?: OpacaLoggerConfig;
250
377
  collections: Collection[];
251
378
  globals?: Global[];
252
- db: DatabaseAdapter;
253
379
  admin?: AdminConfig;
254
380
  api?: ApiConfig;
255
381
  access?: OpacaAccessConfig<Resource>;
@@ -259,6 +385,14 @@ export interface OpacaConfig<Resource extends string = string> extends Omit<Vali
259
385
  locales: string[];
260
386
  defaultLocale: string;
261
387
  };
388
+ storages?: Record<string, any>;
389
+ runMigrationsOnStartup?: boolean;
390
+ plugins?: OpacaPlugin[];
391
+ }
392
+ export interface OpacaLoggerConfig {
393
+ disabled?: boolean;
394
+ disableColors?: boolean;
395
+ level?: "debug" | "info" | "warn" | "error";
262
396
  }
263
397
  export interface OpacaAuthConfig {
264
398
  /**
@@ -327,6 +461,15 @@ export interface ApiConfig {
327
461
  provider?: (c: Context) => any;
328
462
  keyGenerator?: (c: Context) => string | Promise<string>;
329
463
  };
464
+ openAPI?: {
465
+ enabled?: boolean;
466
+ path?: string;
467
+ theme?: "alternate" | "default" | "moon" | "purple" | "solarized" | "bluePlanet" | "saturn" | "kepler" | "mars" | "deepSpace" | "none" | string;
468
+ layout?: "modern" | "classic" | string;
469
+ hideModels?: boolean;
470
+ hideDownloadButton?: boolean;
471
+ customCss?: string;
472
+ };
330
473
  }
331
474
  export type { AdminConfig };
332
475
  export interface FindOptions {
@@ -354,8 +497,8 @@ export interface DatabaseAdapter {
354
497
  /**
355
498
  * Internal ORM instance (e.g. Drizzle instance)
356
499
  */
357
- readonly db?: unknown;
358
- readonly raw?: unknown;
500
+ readonly db?: any;
501
+ readonly raw?: any;
359
502
  unsafe(sql: string, params?: unknown[]): Promise<unknown>;
360
503
  count(collection: string, query?: Record<string, unknown>): Promise<number>;
361
504
  create<T extends object>(collection: string, data: Partial<T>): Promise<T>;
@@ -431,16 +574,28 @@ export interface SerializableCollection {
431
574
  fields: SerializableCollection["fields"];
432
575
  }[];
433
576
  }[];
434
- timestamps: boolean | {
577
+ timestamps?: boolean | {
435
578
  createdAt?: string;
436
579
  updatedAt?: string;
437
580
  };
438
581
  auth?: boolean;
439
582
  admin?: {
440
583
  defaultColumns?: string[];
584
+ /**
585
+ * If true, the collection's title will be used as a breadcrumb.
586
+ */
441
587
  useAsTitle?: string;
588
+ /**
589
+ * If true, the collection will be hidden from the Admin UI sidebar but still accessible via direct URL.
590
+ */
442
591
  hidden?: boolean;
592
+ /**
593
+ * If true, the collection will be completely disabled from the Admin UI (hidden from sidebar and blocked via direct URL).
594
+ */
443
595
  disableAdmin?: boolean;
596
+ /**
597
+ * Predefined filtered views for the collection list.
598
+ */
444
599
  views?: {
445
600
  name: string;
446
601
  filter: Record<string, any>;
@@ -488,5 +643,57 @@ export interface SerializableConfig {
488
643
  }[];
489
644
  }[];
490
645
  needsInit?: boolean;
491
- storages?: Record<string, unknown>;
646
+ storages: Record<string, unknown>;
647
+ plugins?: {
648
+ /**
649
+ * Name of the plugin.
650
+ */
651
+ name: string;
652
+ /**
653
+ * Label to be used in the admin UI.
654
+ */
655
+ label?: string;
656
+ /**
657
+ * Description of the plugin.
658
+ */
659
+ description?: string;
660
+ /**
661
+ * Version of the plugin.
662
+ */
663
+ version?: string;
664
+ /**
665
+ * Author of the plugin.
666
+ */
667
+ author?: string;
668
+ /**
669
+ * Homepage of the plugin.
670
+ */
671
+ homepage?: string;
672
+ /**
673
+ * Icon to be used in the admin UI.
674
+ */
675
+ icon?: IconName;
676
+ /**
677
+ * Assets to be loaded in the admin UI.
678
+ */
679
+ adminAssets?: {
680
+ styles?: string[];
681
+ scripts?: string[];
682
+ };
683
+ /**
684
+ * Admin UI configuration.
685
+ */
686
+ 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;
695
+ };
696
+ settings?: Record<string, any>;
697
+ configSchema?: SerializableCollection["fields"];
698
+ }[];
492
699
  }
@@ -1,35 +1,13 @@
1
- /**
2
- * Core Logger Utility for OpacaCMS.
3
- * Standardizes console output across the package with ANSI colors and standard prefixes.
4
- */
5
- export declare const logger: {
6
- /**
7
- * General information logging.
8
- * Useful for successful operations, initialization steps, etc.
9
- */
10
- info: (message: string, ...args: any[]) => void;
11
- /**
12
- * Action logging. Usually highlighted in green.
13
- * e.g., "Created table users", "Connected to DB"
14
- */
15
- success: (message: string, ...args: any[]) => void;
16
- /**
17
- * Dim/Debug logging.
18
- * e.g., "Starting schema push...", "Syncing database..."
19
- */
20
- debug: (message: string, ...args: any[]) => void;
21
- /**
22
- * Warning logging.
23
- * For non-fatal errors or deprecated warnings.
24
- */
25
- warn: (message: string, ...args: any[]) => void;
26
- /**
27
- * Error logging.
28
- * For fatal errors, exceptions, and validation failures.
29
- */
30
- error: (message: string, ...args: any[]) => void;
31
- /**
32
- * Raw formatting function if manual concatenation is needed.
33
- */
34
- format: (color: "green" | "red" | "yellow" | "gray", msg: string) => string;
35
- };
1
+ import type { OpacaLoggerConfig } from "../types";
2
+ export declare class OpacaLogger {
3
+ private config;
4
+ constructor(config?: OpacaLoggerConfig);
5
+ private shouldLog;
6
+ info(message: string, ...args: any[]): void;
7
+ success(message: string, ...args: any[]): void;
8
+ debug(message: string, ...args: any[]): void;
9
+ warn(message: string, ...args: any[]): void;
10
+ error(message: string, ...args: any[]): void;
11
+ format(color: "green" | "red" | "yellow" | "gray", msg: string): string;
12
+ }
13
+ export declare const logger: OpacaLogger;