opacacms 0.2.1 → 0.3.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 (185) 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 +66 -16
  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-jdfw4v3r.js → chunk-3j9zjfmn.js} +95 -30
  35. package/dist/{chunk-byq8g0rd.js → chunk-48ywpd0a.js} +16 -22
  36. package/dist/{chunk-tfnaf41w.js → chunk-5422w4eq.js} +41 -25
  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-2es275xs.js → chunk-941zxavt.js} +867 -322
  44. package/dist/{chunk-51z3x7kq.js → chunk-a3qae86h.js} +1 -1
  45. package/dist/{chunk-3rdhbedb.js → chunk-adq2b75c.js} +2 -2
  46. package/dist/chunk-d0tb1xjw.js +93 -0
  47. package/dist/chunk-d7cgd6vn.js +318 -0
  48. package/dist/{chunk-6d1vdfwa.js → chunk-e0g6gn7n.js} +54 -75
  49. package/dist/chunk-ec4jhybj.js +1137 -0
  50. package/dist/chunk-fatyf6f7.js +221 -0
  51. package/dist/{chunk-526a3gqx.js → chunk-fnsf1dfm.js} +1 -1
  52. package/dist/chunk-g9bxb6h0.js +205 -0
  53. package/dist/chunk-gyaf5kgf.js +10 -0
  54. package/dist/{chunk-9kxpbcb1.js → chunk-h6dhexzr.js} +16 -7
  55. package/dist/{chunk-dykn5hr6.js → chunk-j8js1y0h.js} +31 -74
  56. package/dist/{chunk-t0zg026p.js → chunk-jq1drsen.js} +12 -1
  57. package/dist/{chunk-b3kr8w41.js → chunk-m24yqkeq.js} +38 -26
  58. package/dist/chunk-m5ems3hh.js +410 -0
  59. package/dist/{chunk-8scgdznr.js → chunk-m83ybzf8.js} +15 -18
  60. package/dist/chunk-majsbncm.js +98 -0
  61. package/dist/chunk-mp2gt9yh.js +237 -0
  62. package/dist/chunk-n1twhqmf.js +54 -0
  63. package/dist/{chunk-bygjkgrx.js → chunk-naqcqj8n.js} +57 -80
  64. package/dist/chunk-q5sb5dcr.js +15 -0
  65. package/dist/{chunk-06ks4ggh.js → chunk-qhdsjek6.js} +49 -89
  66. package/dist/{chunk-n133qpsm.js → chunk-qsh2nqz3.js} +50 -81
  67. package/dist/chunk-r0ms5tk1.js +76 -0
  68. package/dist/chunk-rwqwsanx.js +75 -0
  69. package/dist/chunk-sqsfk9p4.js +700 -0
  70. package/dist/{chunk-5gvbp2qa.js → chunk-x7bnzswh.js} +25 -18
  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/better-sqlite.d.ts +2 -3
  90. package/dist/db/better-sqlite.js +6 -5
  91. package/dist/db/bun-sqlite.d.ts +2 -3
  92. package/dist/db/bun-sqlite.js +6 -5
  93. package/dist/db/d1.d.ts +13 -7
  94. package/dist/db/d1.js +6 -5
  95. package/dist/db/index.d.ts +2 -2
  96. package/dist/db/index.js +10 -12
  97. package/dist/db/kysely/factory.d.ts +29 -0
  98. package/dist/db/kysely/plugins/audit-logging.d.ts +48 -0
  99. package/dist/db/kysely/plugins/auto-timestamps.d.ts +38 -0
  100. package/dist/db/kysely/plugins/cursor-pagination.d.ts +42 -0
  101. package/dist/db/kysely/plugins/deadlock-handler.d.ts +47 -0
  102. package/dist/db/kysely/plugins/draft-swapper.d.ts +33 -0
  103. package/dist/db/kysely/plugins/field-masking.d.ts +45 -0
  104. package/dist/db/kysely/plugins/fts-normalizer.d.ts +38 -0
  105. package/dist/db/kysely/plugins/i18n-fallback.d.ts +48 -0
  106. package/dist/db/kysely/plugins/id-generation.d.ts +42 -0
  107. package/dist/db/kysely/plugins/index.d.ts +16 -0
  108. package/dist/db/kysely/plugins/json-flattener.d.ts +38 -0
  109. package/dist/db/kysely/plugins/relationship-preloading.d.ts +39 -0
  110. package/dist/db/kysely/plugins/slug-generation.d.ts +37 -0
  111. package/dist/db/kysely/plugins/soft-delete.d.ts +42 -0
  112. package/dist/db/kysely/plugins/tree-resolver.d.ts +39 -0
  113. package/dist/db/kysely/plugins/virtual-field-resolver.d.ts +54 -0
  114. package/dist/db/kysely/plugins/zod-coercion.d.ts +34 -0
  115. package/dist/db/kysely/snapshot/snapshot-manager.d.ts +18 -0
  116. package/dist/db/postgres.d.ts +2 -2
  117. package/dist/db/postgres.js +6 -5
  118. package/dist/db/sqlite.d.ts +2 -3
  119. package/dist/db/sqlite.js +6 -5
  120. package/dist/index.d.ts +3 -0
  121. package/dist/index.js +161 -7
  122. package/dist/runtimes/bun.js +9 -6
  123. package/dist/runtimes/cloudflare-workers.d.ts +3 -1
  124. package/dist/runtimes/cloudflare-workers.js +36 -7
  125. package/dist/runtimes/next.js +8 -5
  126. package/dist/runtimes/node.js +9 -6
  127. package/dist/schema/collection.d.ts +116 -70
  128. package/dist/schema/compiler.d.ts +6 -0
  129. package/dist/schema/global.d.ts +38 -71
  130. package/dist/schema/index.d.ts +5 -4
  131. package/dist/schema/index.js +35 -550
  132. package/dist/schema/zod.d.ts +564 -0
  133. package/dist/server/admin-router.d.ts +1 -1
  134. package/dist/server/collection-router.d.ts +1 -1
  135. package/dist/server/graphql.d.ts +6 -0
  136. package/dist/server/handlers.d.ts +25 -7
  137. package/dist/server/middlewares/auth.d.ts +1 -1
  138. package/dist/server/plugins-loader.d.ts +1 -1
  139. package/dist/server/router.d.ts +2 -2
  140. package/dist/server/routers/admin.d.ts +1 -1
  141. package/dist/server/routers/auth.d.ts +1 -1
  142. package/dist/server/routers/collections.d.ts +4 -1
  143. package/dist/server/routers/plugins.d.ts +2 -2
  144. package/dist/server/setup-middlewares.d.ts +1 -1
  145. package/dist/server/system-router.d.ts +1 -1
  146. package/dist/server.js +11 -6
  147. package/dist/storage/adapters/cloudflare-r2.d.ts +11 -2
  148. package/dist/storage/index.js +5 -5
  149. package/dist/types.d.ts +253 -42
  150. package/dist/utils/context.d.ts +14 -0
  151. package/dist/utils/logger.d.ts +2 -0
  152. package/dist/utils/string.d.ts +10 -0
  153. package/dist/utils/webhooks-engine.d.ts +24 -0
  154. package/dist/validation.d.ts +67 -1
  155. package/dist/validator.d.ts +1 -0
  156. package/package.json +50 -11
  157. package/src/cli/index.ts +117 -0
  158. package/dist/chunk-6qq3ne6b.js +0 -288
  159. package/dist/chunk-6v1fw7q7.js +0 -126
  160. package/dist/chunk-7a9kn0np.js +0 -116
  161. package/dist/chunk-bexcv7xe.js +0 -36
  162. package/dist/chunk-d3ffeqp9.js +0 -87
  163. package/dist/chunk-fj19qccp.js +0 -78
  164. package/dist/chunk-g1jb60xd.js +0 -17
  165. package/dist/chunk-j53pz21t.js +0 -20
  166. package/dist/chunk-mkn49zmy.js +0 -102
  167. package/dist/chunk-r39em4yj.js +0 -29
  168. package/dist/chunk-rsf0tpy1.js +0 -8
  169. package/dist/chunk-srsac177.js +0 -85
  170. package/dist/chunk-twpvxfce.js +0 -64
  171. package/dist/chunk-ywm4t2gm.js +0 -19
  172. package/dist/cli/commands/plugin-sync.d.ts +0 -1
  173. package/dist/cli/commands/seed-command.d.ts +0 -2
  174. package/dist/plugins/ui-bridge.d.ts +0 -12
  175. package/dist/schema/fields/base.d.ts +0 -84
  176. package/dist/schema/fields/index.d.ts +0 -147
  177. package/dist/schema/infer.d.ts +0 -55
  178. /package/dist/admin/ui/components/{ColumnVisibilityToggle.d.ts → column-visibility-toggle.d.ts} +0 -0
  179. /package/dist/admin/ui/components/{DataDetailView.d.ts → data-detail-view.d.ts} +0 -0
  180. /package/dist/cli/{d1-mock.d.ts → core/mocks/d1-mock.d.ts} +0 -0
  181. /package/dist/cli/{r2-mock.d.ts → core/mocks/r2-mock.d.ts} +0 -0
  182. /package/dist/cli/{commands → core/plugins}/plugin-build.d.ts +0 -0
  183. /package/dist/cli/{commands → core/plugins}/plugin-init.d.ts +0 -0
  184. /package/dist/cli/{commands → core/types}/generate-types.d.ts +0 -0
  185. /package/dist/{schema/fields/validation.test.d.ts → cli/seeding.test.d.ts} +0 -0
package/dist/db/index.js CHANGED
@@ -1,34 +1,32 @@
1
1
  import {
2
2
  D1Adapter,
3
3
  createD1Adapter
4
- } from "../chunk-06ks4ggh.js";
4
+ } from "../chunk-qhdsjek6.js";
5
5
  import {
6
6
  PostgresAdapter,
7
7
  createPostgresAdapter
8
- } from "../chunk-tfnaf41w.js";
8
+ } from "../chunk-5422w4eq.js";
9
9
  import {
10
10
  SQLiteAdapter,
11
11
  createSQLiteAdapter
12
- } from "../chunk-6d1vdfwa.js";
12
+ } from "../chunk-e0g6gn7n.js";
13
13
  import {
14
14
  BunSQLiteAdapter,
15
15
  createBunSQLiteAdapter
16
- } from "../chunk-n133qpsm.js";
16
+ } from "../chunk-qsh2nqz3.js";
17
17
  import {
18
18
  BetterSQLiteAdapter,
19
19
  createBetterSQLiteAdapter
20
- } from "../chunk-bygjkgrx.js";
21
- import"../chunk-dykn5hr6.js";
20
+ } from "../chunk-naqcqj8n.js";
21
+ import"../chunk-j8js1y0h.js";
22
22
  import {
23
23
  BaseDatabaseAdapter
24
24
  } from "../chunk-s8mqwnm1.js";
25
+ import"../chunk-q5sb5dcr.js";
25
26
  import"../chunk-qxt9vge8.js";
26
- import"../chunk-v9z61v3g.js";
27
- import"../chunk-t0zg026p.js";
28
- import"../chunk-8sqjbsgt.js";
29
-
30
- // src/db/index.ts
31
- import { sql } from "kysely";
27
+ import"../chunk-jq1drsen.js";
28
+ import"../chunk-6qs0g65f.js";
29
+ import"../chunk-6bywt602.js";
32
30
  export {
33
31
  sql,
34
32
  createSQLiteAdapter,
@@ -0,0 +1,29 @@
1
+ import { type Dialect, Kysely } from "kysely";
2
+ import type { OpacaConfig } from "../../types";
3
+ /**
4
+ * Options for creating an OpacaCMS Kysely instance.
5
+ */
6
+ export interface CreateOpacaKyselyOptions {
7
+ dialect: Dialect;
8
+ config: OpacaConfig;
9
+ /**
10
+ * If true, administrative/system features (like masking) might be adjusted.
11
+ * Defaults to false.
12
+ */
13
+ isAdmin?: boolean;
14
+ /**
15
+ * Function to get the current user ID for audit logging.
16
+ */
17
+ getUserId?: () => string | null;
18
+ }
19
+ /**
20
+ * Factory for creating a Kysely instance pre-configured with all OpacaCMS plugins.
21
+ *
22
+ * This is the central entry point for database initialization in OpacaCMS.
23
+ * It ensures that all specialized plugins (JSON, Masking, Audit, etc.) are
24
+ * correctly configured and applied in the right order.
25
+ *
26
+ * @param options - Configuration including dialect and CMS schema.
27
+ * @returns A "super-charged" Kysely instance.
28
+ */
29
+ export declare function createOpacaKysely(options: CreateOpacaKyselyOptions): Kysely<any>;
@@ -0,0 +1,48 @@
1
+ import type { KyselyPlugin, PluginTransformQueryArgs, PluginTransformResultArgs, QueryResult, RootOperationNode } from "kysely";
2
+ /**
3
+ * Configuration for the AuditLoggingPlugin.
4
+ */
5
+ export interface AuditLoggingPluginConfig {
6
+ /**
7
+ * Name of the audit log table. Defaults to '_audit_logs'.
8
+ */
9
+ auditTable?: string;
10
+ /**
11
+ * Function to get the current user ID for logging.
12
+ */
13
+ getUserId?: () => string | null;
14
+ }
15
+ /**
16
+ * Kysely plugin that automatically records all database changes for auditing.
17
+ *
18
+ * Security and transparency are critical in a CMS. This plugin ensures that every
19
+ * insertion, update, or deletion is logged with the corresponding data changes.
20
+ *
21
+ * This plugin:
22
+ * 1. Intercepts `INSERT`, `UPDATE`, and `DELETE` queries.
23
+ * 2. Records the operation, collection/table, entity ID, and the data payload.
24
+ * 3. Saves the audit trail to the defined system audit log table.
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * const db = new Kysely<Database>({
29
+ * dialect,
30
+ * plugins: [new AuditLoggingPlugin({ getUserId: () => authContext.userId })]
31
+ * });
32
+ * ```
33
+ */
34
+ export declare class AuditLoggingPlugin implements KyselyPlugin {
35
+ private auditTable;
36
+ private getUserId?;
37
+ private db;
38
+ private queryNodes;
39
+ constructor(config?: AuditLoggingPluginConfig);
40
+ /**
41
+ * Called by the factory to provide the database instance for logging.
42
+ */
43
+ setDb(db: any): void;
44
+ transformQuery(args: PluginTransformQueryArgs): RootOperationNode;
45
+ transformResult(args: PluginTransformResultArgs): Promise<QueryResult<any>>;
46
+ private getTableName;
47
+ private logOperation;
48
+ }
@@ -0,0 +1,38 @@
1
+ import type { KyselyPlugin, PluginTransformQueryArgs, PluginTransformResultArgs, QueryResult, RootOperationNode } from "kysely";
2
+ /**
3
+ * Configuration for the AutoTimestampsPlugin.
4
+ */
5
+ export interface AutoTimestampsPluginConfig {
6
+ /** The name of the creation timestamp column. Defaults to 'created_at'. */
7
+ createdAtColumn?: string;
8
+ /** The name of the update timestamp column. Defaults to 'updated_at'. */
9
+ updatedAtColumn?: string;
10
+ }
11
+ /**
12
+ * Kysely plugin that automatically manages creation and modification timestamps.
13
+ *
14
+ * In a database-driven application, tracking when a record was created or last
15
+ * modified is a standard requirement.
16
+ *
17
+ * This plugin:
18
+ * 1. Intercepts `INSERT` queries and injects values for both `createdAt` and `updatedAt`.
19
+ * 2. Intercepts `UPDATE` queries and automatically refreshes the `updatedAt` value.
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * const db = new Kysely<Database>({
24
+ * dialect,
25
+ * plugins: [new AutoTimestampsPlugin({ createdAtColumn: 'created_at', updatedAtColumn: 'updated_at' })]
26
+ * });
27
+ *
28
+ * // No need to manually pass timestamps anymore
29
+ * await db.insertInto('posts').values({ title: 'Hello' }).execute();
30
+ * ```
31
+ */
32
+ export declare class AutoTimestampsPlugin implements KyselyPlugin {
33
+ private createdAtColumn;
34
+ private updatedAtColumn;
35
+ constructor(config?: AutoTimestampsPluginConfig);
36
+ transformQuery(args: PluginTransformQueryArgs): RootOperationNode;
37
+ transformResult(args: PluginTransformResultArgs): Promise<QueryResult<any>>;
38
+ }
@@ -0,0 +1,42 @@
1
+ import { type KyselyPlugin, type PluginTransformQueryArgs, type PluginTransformResultArgs, type QueryResult, type RootOperationNode } from "kysely";
2
+ /**
3
+ * Configuration for the CursorPaginationPlugin.
4
+ */
5
+ export interface CursorPaginationPluginConfig {
6
+ /**
7
+ * The cursor value for pagination (typically the 'id' or 'createdAt' encoded).
8
+ */
9
+ after?: string | number;
10
+ /**
11
+ * The column to use for the cursor. Defaults to 'id'.
12
+ */
13
+ cursorColumn?: string;
14
+ }
15
+ /**
16
+ * Kysely plugin that simplifies cursor-based pagination.
17
+ *
18
+ * Traditional OFFSET/LIMIT pagination gets slow on large datasets.
19
+ * Cursor-based pagination provides a stable performance by using a unique index (like 'id').
20
+ *
21
+ * This plugin:
22
+ * 1. Automatically injects `WHERE column > ?` into the query if an `after` cursor is provided.
23
+ * 2. Ensures the order matches the cursor direction.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * const db = new Kysely<Database>({
28
+ * dialect,
29
+ * plugins: [new CursorPaginationPlugin({ after: lastId })]
30
+ * });
31
+ *
32
+ * // Query remains simple, but gets the next page optimized
33
+ * await db.selectFrom('posts').selectAll().limit(10).execute();
34
+ * ```
35
+ */
36
+ export declare class CursorPaginationPlugin implements KyselyPlugin {
37
+ private after;
38
+ private cursorColumn;
39
+ constructor(config: CursorPaginationPluginConfig);
40
+ transformQuery(args: PluginTransformQueryArgs): RootOperationNode;
41
+ transformResult(args: PluginTransformResultArgs): Promise<QueryResult<any>>;
42
+ }
@@ -0,0 +1,47 @@
1
+ import type { KyselyPlugin, PluginTransformQueryArgs, PluginTransformResultArgs, QueryResult, RootOperationNode } from "kysely";
2
+ /**
3
+ * Configuration for the DeadlockRetryPlugin.
4
+ */
5
+ export interface DeadlockRetryPluginConfig {
6
+ /**
7
+ * Maximum number of retry attempts. Defaults to 3.
8
+ */
9
+ maxRetries?: number;
10
+ /**
11
+ * Initial delay in milliseconds for exponential backoff. Defaults to 50.
12
+ */
13
+ initialDelay?: number;
14
+ }
15
+ /**
16
+ * Kysely plugin that automatically handles database deadlocks and retries.
17
+ *
18
+ * Databases like SQLite (especially in highly concurrent environments like
19
+ * Cloudflare Workers with D1) can throw 'BUSY' or 'LOCKED' errors.
20
+ *
21
+ * This plugin implements an Exponential Backoff retry strategy to ensure
22
+ * that temporary lock issues don't crash your CMS operations.
23
+ *
24
+ * @note Because Kysely plugins are designed to transform queries and results,
25
+ * catching execution errors is best handled at the Dialect or Adapter layer.
26
+ * This plugin serves as a standard implementation of the retry logic.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * const db = new Kysely<Database>({
31
+ * dialect,
32
+ * plugins: [new DeadlockRetryPlugin({ maxRetries: 5 })]
33
+ * });
34
+ * ```
35
+ */
36
+ export declare class DeadlockRetryPlugin implements KyselyPlugin {
37
+ private maxRetries;
38
+ private initialDelay;
39
+ constructor(config: DeadlockRetryPluginConfig);
40
+ transformQuery(args: PluginTransformQueryArgs): RootOperationNode;
41
+ transformResult(args: PluginTransformResultArgs): Promise<QueryResult<any>>;
42
+ /**
43
+ * Helper method to execute a function with retry logic.
44
+ * Can be used by adapters to wrap their execution calls.
45
+ */
46
+ retry<T>(fn: () => Promise<T>): Promise<T>;
47
+ }
@@ -0,0 +1,33 @@
1
+ import { type KyselyPlugin, type PluginTransformQueryArgs, type PluginTransformResultArgs, type QueryResult, type RootOperationNode } from "kysely";
2
+ import type { Collection, Global } from "../../../types";
3
+ /**
4
+ * Configuration for the DraftSwapperPlugin.
5
+ */
6
+ export interface DraftSwapperPluginConfig {
7
+ /**
8
+ * If true, queries will be redirected to the centralized versions table.
9
+ */
10
+ draftMode?: boolean;
11
+ /**
12
+ * Optional list of table names that should be swapped.
13
+ */
14
+ tables?: string[];
15
+ /**
16
+ * Full collection registry to help with query rewriting.
17
+ */
18
+ collections?: Collection[];
19
+ globals?: Global[];
20
+ }
21
+ /**
22
+ * Kysely plugin that redirects queries to the centralized `_doc_versions` table when in draft mode.
23
+ *
24
+ * Instead of having per-collection shadow tables, OpacaCMS uses a single `_doc_versions` table
25
+ * storing data as JSON blobs. This plugin intercepts queries and redirects them.
26
+ */
27
+ export declare class DraftSwapperPlugin implements KyselyPlugin {
28
+ private draftMode;
29
+ private tables;
30
+ constructor(config: DraftSwapperPluginConfig);
31
+ transformQuery(args: PluginTransformQueryArgs): RootOperationNode;
32
+ transformResult(args: PluginTransformResultArgs): Promise<QueryResult<any>>;
33
+ }
@@ -0,0 +1,45 @@
1
+ import type { KyselyPlugin, PluginTransformQueryArgs, PluginTransformResultArgs, QueryResult, RootOperationNode } from "kysely";
2
+ import type { Collection, Global } from "../../../types";
3
+ /**
4
+ * Configuration for the FieldMaskingPlugin.
5
+ */
6
+ export interface FieldMaskingPluginConfig {
7
+ /** The list of CMS collections. */
8
+ collections: Collection[];
9
+ /** The list of CMS globals. */
10
+ globals?: Global[];
11
+ /**
12
+ * If true, masking is disabled.
13
+ * Useful in Admin context or when performing internal system operations
14
+ * where sensitive data should be visible.
15
+ */
16
+ disabled?: boolean;
17
+ }
18
+ /**
19
+ * Kysely plugin for automated data redaction.
20
+ *
21
+ * Prevents sensitive data (like password hashes, secret tokens, or fields marked
22
+ * as hidden in the CMS) from leaking into public API responses.
23
+ *
24
+ * This plugin:
25
+ * 1. Reads the Zod-based CMS schema to identify sensitive fields.
26
+ * 2. Intercepts query results and masks or removes those fields.
27
+ * 3. Supports a "disabled" flag for administrative or trusted contexts.
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * const db = new Kysely<Database>({
32
+ * dialect: dialect,
33
+ * plugins: [new FieldMaskingPlugin({ collections, globals, disabled: isInternalContext })]
34
+ * });
35
+ * ```
36
+ */
37
+ export declare class FieldMaskingPlugin implements KyselyPlugin {
38
+ private maskedFields;
39
+ private disabled;
40
+ constructor(config: FieldMaskingPluginConfig);
41
+ private parseConfig;
42
+ transformQuery(args: PluginTransformQueryArgs): RootOperationNode;
43
+ transformResult(args: PluginTransformResultArgs): Promise<QueryResult<any>>;
44
+ private maskRow;
45
+ }
@@ -0,0 +1,38 @@
1
+ import type { KyselyPlugin, PluginTransformQueryArgs, PluginTransformResultArgs, QueryResult, RootOperationNode } from "kysely";
2
+ /**
3
+ * Configuration for the FtsNormalizerPlugin.
4
+ */
5
+ export interface FtsNormalizerPluginConfig {
6
+ /** The database dialect (e.g. 'sqlite', 'postgres'). */
7
+ dialect: "sqlite" | "postgres" | "mysql" | "better-sqlite3" | "d1" | string;
8
+ }
9
+ /**
10
+ * Kysely plugin that provides a dialect-agnostic interface for Full-Text Search (FTS).
11
+ *
12
+ * Writing performant FTS queries is different for every database (e.g., `MATCH` in SQLite
13
+ * vs `to_tsvector` in Postgres).
14
+ *
15
+ * This plugin:
16
+ * 1. Intercepts specific search predicates like `.where('search', '=', 'term')`.
17
+ * 2. Automatically translates them to the native optimized FTS syntax of the current dialect.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * const db = new Kysely<Database>({
22
+ * dialect: sqliteDialect,
23
+ * plugins: [new FtsNormalizerPlugin({ dialect: 'sqlite' })]
24
+ * });
25
+ *
26
+ * // Generic search query
27
+ * await db.selectFrom('posts').where('search', '=', 'Hello').execute();
28
+ *
29
+ * // Translates to (SQLite):
30
+ * // SELECT * FROM posts WHERE posts MATCH 'Hello';
31
+ * ```
32
+ */
33
+ export declare class FtsNormalizerPlugin implements KyselyPlugin {
34
+ private dialect;
35
+ constructor(config: FtsNormalizerPluginConfig);
36
+ transformQuery(args: PluginTransformQueryArgs): RootOperationNode;
37
+ transformResult(args: PluginTransformResultArgs): Promise<QueryResult<any>>;
38
+ }
@@ -0,0 +1,48 @@
1
+ import type { KyselyPlugin, PluginTransformQueryArgs, PluginTransformResultArgs, QueryResult, RootOperationNode } from "kysely";
2
+ import type { Collection, Global } from "../../../types";
3
+ /**
4
+ * Configuration for the AutoTranslationFallbackPlugin.
5
+ */
6
+ export interface AutoTranslationFallbackPluginConfig {
7
+ /** The list of CMS collections. */
8
+ collections: Collection[];
9
+ /** The list of CMS globals. */
10
+ globals?: Global[];
11
+ /** The default locale to fallback to (e.g. 'en'). */
12
+ defaultLocale: string;
13
+ /** The currently requested locale (e.g. 'pt'). */
14
+ currentLocale: string;
15
+ }
16
+ /**
17
+ * Kysely plugin that automatically fallbacks to the default language for empty localized fields.
18
+ *
19
+ * In a multilingual CMS, if a field is requested in a specific language (e.g. 'pt')
20
+ * but that field is empty/null in the database, the plugin automatically copies
21
+ * the value from the default language (e.g. 'en') to ensure the frontend doesn't break.
22
+ *
23
+ * This plugin:
24
+ * 1. Identifies localized fields from the CMS schema.
25
+ * 2. Intercepts query results.
26
+ * 3. For each row, if the current locale field is empty, it populates it with the default locale's value.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * const db = new Kysely<Database>({
31
+ * dialect,
32
+ * plugins: [new AutoTranslationFallbackPlugin({
33
+ * collections,
34
+ * defaultLocale: 'en',
35
+ * currentLocale: 'pt'
36
+ * })]
37
+ * });
38
+ * ```
39
+ */
40
+ export declare class AutoTranslationFallbackPlugin implements KyselyPlugin {
41
+ private localizedFields;
42
+ private config;
43
+ constructor(config: AutoTranslationFallbackPluginConfig);
44
+ private parseConfig;
45
+ transformQuery(args: PluginTransformQueryArgs): RootOperationNode;
46
+ transformResult(args: PluginTransformResultArgs): Promise<QueryResult<any>>;
47
+ private fallbackRow;
48
+ }
@@ -0,0 +1,42 @@
1
+ import type { KyselyPlugin, PluginTransformQueryArgs, PluginTransformResultArgs, QueryResult, RootOperationNode } from "kysely";
2
+ /**
3
+ * Configuration for the IdGenerationPlugin.
4
+ */
5
+ export interface IdGenerationPluginConfig {
6
+ /**
7
+ * The generation function to use. Defaults to crypto.randomUUID().
8
+ */
9
+ generateId?: () => string;
10
+ /**
11
+ * The primary key column name. Defaults to 'id'.
12
+ */
13
+ idColumn?: string;
14
+ }
15
+ /**
16
+ * Kysely plugin that automatically generates unique identifiers for new records.
17
+ *
18
+ * Manually injecting IDs (like UUIDs or CUIDs) for every insert can be
19
+ * repetitive. This plugin automates the process at the database layer.
20
+ *
21
+ * This plugin:
22
+ * 1. Intercepts `INSERT` queries.
23
+ * 2. If the `id` column is missing from the values, it generates and injects one.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * const db = new Kysely<Database>({
28
+ * dialect,
29
+ * plugins: [new IdGenerationPlugin({ idColumn: 'id' })]
30
+ * });
31
+ *
32
+ * // 'id' will be automatically generated and injected
33
+ * await db.insertInto('posts').values({ title: 'New Post' }).execute();
34
+ * ```
35
+ */
36
+ export declare class IdGenerationPlugin implements KyselyPlugin {
37
+ private generateId;
38
+ private idColumn;
39
+ constructor(config?: IdGenerationPluginConfig);
40
+ transformQuery(args: PluginTransformQueryArgs): RootOperationNode;
41
+ transformResult(args: PluginTransformResultArgs): Promise<QueryResult<any>>;
42
+ }
@@ -0,0 +1,16 @@
1
+ export * from "./audit-logging";
2
+ export * from "./auto-timestamps";
3
+ export * from "./cursor-pagination";
4
+ export * from "./deadlock-handler";
5
+ export * from "./draft-swapper";
6
+ export * from "./field-masking";
7
+ export * from "./fts-normalizer";
8
+ export * from "./i18n-fallback";
9
+ export * from "./id-generation";
10
+ export * from "./json-flattener";
11
+ export * from "./relationship-preloading";
12
+ export * from "./slug-generation";
13
+ export * from "./soft-delete";
14
+ export * from "./tree-resolver";
15
+ export * from "./virtual-field-resolver";
16
+ export * from "./zod-coercion";
@@ -0,0 +1,38 @@
1
+ import type { KyselyPlugin, PluginTransformQueryArgs, PluginTransformResultArgs, QueryResult, RootOperationNode } from "kysely";
2
+ import type { Collection, Global } from "../../../types";
3
+ /**
4
+ * Configuration for the JsonFlattenerPlugin.
5
+ */
6
+ export interface JsonFlattenerPluginConfig {
7
+ /** The list of CMS collections. */
8
+ collections: Collection[];
9
+ /** The list of CMS globals. */
10
+ globals?: Global[];
11
+ }
12
+ /**
13
+ * Kysely plugin that automatically handles JSON serialization and deserialization
14
+ * for SQLite and Cloudflare D1 databases.
15
+ *
16
+ * In a headless CMS, many fields like 'blocks', 'richtext', or 'localized' are stored
17
+ * as JSON strings in the database but should be treated as objects in the application.
18
+ *
19
+ * This plugin:
20
+ * 1. Inspects the CMS schema to identify JSON-compatible fields.
21
+ * 2. Automatically `JSON.parse`es results from the database.
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * const db = new Kysely<Database>({
26
+ * dialect: new SqliteDialect({ database }),
27
+ * plugins: [new JsonFlattenerPlugin({ collections, globals })]
28
+ * });
29
+ * ```
30
+ */
31
+ export declare class JsonFlattenerPlugin implements KyselyPlugin {
32
+ private jsonFields;
33
+ constructor(config: JsonFlattenerPluginConfig);
34
+ private parseConfig;
35
+ transformQuery(args: PluginTransformQueryArgs): RootOperationNode;
36
+ transformResult(args: PluginTransformResultArgs): Promise<QueryResult<any>>;
37
+ private mapRow;
38
+ }
@@ -0,0 +1,39 @@
1
+ import type { KyselyPlugin, PluginTransformQueryArgs, PluginTransformResultArgs, QueryResult, RootOperationNode } from "kysely";
2
+ /**
3
+ * Configuration for the RelationshipPreloadingPlugin.
4
+ */
5
+ export interface RelationshipPreloadingPluginConfig {
6
+ /**
7
+ * The maximum depth of the relationship expansion. Defaults to 2.
8
+ */
9
+ maxDepth?: number;
10
+ }
11
+ /**
12
+ * Kysely plugin that automatically pre-loads and nests related entities (Virtual Joins).
13
+ *
14
+ * Manually performing multiple joins or manual relationship resolution from foreign keys
15
+ * can be complex. This plugin handles the process transparently by fetching and
16
+ * nesting related documents.
17
+ *
18
+ * This plugin:
19
+ * 1. Identifies relationship fields in the returning result.
20
+ * 2. If expansion is requested, it batch-fetches related documents using a DataLoader pattern.
21
+ * 3. Replaces foreign key strings (UUIDs) with the expanded nested objects.
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * const db = new Kysely<Database>({
26
+ * dialect,
27
+ * plugins: [new RelationshipPreloadingPlugin({ maxDepth: 5 })]
28
+ * });
29
+ *
30
+ * // Query result will have { author: { id: '...', name: 'João' } }
31
+ * // instead of { author_id: '...' }
32
+ * ```
33
+ */
34
+ export declare class RelationshipPreloadingPlugin implements KyselyPlugin {
35
+ private maxDepth;
36
+ constructor(config?: RelationshipPreloadingPluginConfig);
37
+ transformQuery(args: PluginTransformQueryArgs): RootOperationNode;
38
+ transformResult(args: PluginTransformResultArgs): Promise<QueryResult<any>>;
39
+ }
@@ -0,0 +1,37 @@
1
+ import type { KyselyPlugin, PluginTransformQueryArgs, PluginTransformResultArgs, QueryResult, RootOperationNode } from "kysely";
2
+ /**
3
+ * Configuration for the SlugGenerationPlugin.
4
+ */
5
+ export interface SlugGenerationPluginConfig {
6
+ /** The source column to generate the slug from. Defaults to 'title'. */
7
+ sourceColumn?: string;
8
+ /** The target slug column. Defaults to 'slug'. */
9
+ slugColumn?: string;
10
+ }
11
+ /**
12
+ * Kysely plugin that automatically generates URL-friendly slugs from content.
13
+ *
14
+ * Manually creating slugs can be error-prone and tedious. This plugin
15
+ * ensures that every record has a clean slug derived from its title or name.
16
+ *
17
+ * This plugin:
18
+ * 1. Intercepts `INSERT` and `UPDATE` queries.
19
+ * 2. If the `slug` field is empty or missing, it generates one from the `sourceColumn`.
20
+ * 3. Applies standard slugification (lowercase, hyphens, alphanumeric only).
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * const db = new Kysely<Database>({
25
+ * dialect,
26
+ * plugins: [new SlugGenerationPlugin({ sourceColumn: 'name' })]
27
+ * });
28
+ * ```
29
+ */
30
+ export declare class SlugGenerationPlugin implements KyselyPlugin {
31
+ private sourceColumn;
32
+ private slugColumn;
33
+ constructor(config?: SlugGenerationPluginConfig);
34
+ transformQuery(args: PluginTransformQueryArgs): RootOperationNode;
35
+ transformResult(args: PluginTransformResultArgs): Promise<QueryResult<any>>;
36
+ private slugify;
37
+ }
@@ -0,0 +1,42 @@
1
+ import type { KyselyPlugin, PluginTransformQueryArgs, PluginTransformResultArgs, QueryResult, RootOperationNode } from "kysely";
2
+ /**
3
+ * Configuration for the SoftDeletePlugin.
4
+ */
5
+ export interface SoftDeletePluginConfig {
6
+ /** The name of the soft delete column. Defaults to 'deleted_at'. */
7
+ deletedAtColumn?: string;
8
+ /** List of tables that should support soft delete. If empty, applies to all. */
9
+ tables?: string[];
10
+ }
11
+ /**
12
+ * Kysely plugin that implements soft deletion logic.
13
+ *
14
+ * Instead of physically removing records from the database, this plugin
15
+ * marks them as deleted using a timestamp. This allows for data recovery
16
+ * and audit trails.
17
+ *
18
+ * This plugin:
19
+ * 1. Intercepts `DELETE` queries and rewrites them as `UPDATE` queries setting `deletedAt`.
20
+ * 2. Intercepts `SELECT` queries and automatically adds a `WHERE deletedAt IS NULL` filter.
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * const db = new Kysely<Database>({
25
+ * dialect,
26
+ * plugins: [new SoftDeletePlugin({ deletedAtColumn: 'deleted_at' })]
27
+ * });
28
+ *
29
+ * // This will now perform an UPDATE instead of a DELETE
30
+ * await db.deleteFrom('posts').where('id', '=', 1).execute();
31
+ *
32
+ * // This will automatically exclude soft-deleted records
33
+ * await db.selectFrom('posts').selectAll().execute();
34
+ * ```
35
+ */
36
+ export declare class SoftDeletePlugin implements KyselyPlugin {
37
+ private deletedAtColumn;
38
+ private tables;
39
+ constructor(config?: SoftDeletePluginConfig);
40
+ transformQuery(args: PluginTransformQueryArgs): RootOperationNode;
41
+ transformResult(args: PluginTransformResultArgs): Promise<QueryResult<any>>;
42
+ }