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
@@ -3,20 +3,23 @@ import {
3
3
  flattenPayload,
4
4
  pushSchema,
5
5
  unflattenRow
6
- } from "./chunk-dykn5hr6.js";
6
+ } from "./chunk-j8js1y0h.js";
7
7
  import {
8
8
  BaseDatabaseAdapter
9
9
  } from "./chunk-s8mqwnm1.js";
10
+ import {
11
+ requestContext
12
+ } from "./chunk-q5sb5dcr.js";
10
13
  import {
11
14
  getRelationalFields,
12
15
  toSnakeCase
13
16
  } from "./chunk-qxt9vge8.js";
14
17
  import {
15
18
  logger
16
- } from "./chunk-t0zg026p.js";
19
+ } from "./chunk-jq1drsen.js";
17
20
  import {
18
21
  __require
19
- } from "./chunk-8sqjbsgt.js";
22
+ } from "./chunk-6bywt602.js";
20
23
 
21
24
  // src/db/postgres.ts
22
25
  import fs from "node:fs/promises";
@@ -24,11 +27,9 @@ import path from "node:path";
24
27
  import {
25
28
  CompiledQuery,
26
29
  FileMigrationProvider,
27
- Kysely,
28
30
  Migrator,
29
31
  PostgresDialect
30
32
  } from "kysely";
31
- import postgres from "postgres";
32
33
  class PostgresAdapter extends BaseDatabaseAdapter {
33
34
  name = "postgres";
34
35
  _rawDb = null;
@@ -43,6 +44,8 @@ class PostgresAdapter extends BaseDatabaseAdapter {
43
44
  return this._rawDb;
44
45
  }
45
46
  get db() {
47
+ if (!this._db)
48
+ throw new Error("Database not connected. Call connect() first.");
46
49
  return this._db;
47
50
  }
48
51
  constructor(config, options) {
@@ -55,6 +58,7 @@ class PostgresAdapter extends BaseDatabaseAdapter {
55
58
  async connect() {
56
59
  if (this._rawDb)
57
60
  return;
61
+ const { default: postgres } = await import("postgres");
58
62
  if (typeof this.config === "string") {
59
63
  this._rawDb = postgres(this.config);
60
64
  } else {
@@ -67,7 +71,8 @@ class PostgresAdapter extends BaseDatabaseAdapter {
67
71
  ssl: this.config.ssl
68
72
  });
69
73
  }
70
- this._db = new Kysely({
74
+ const { createOpacaKysely } = await import("./chunk-sqsfk9p4.js");
75
+ this._db = createOpacaKysely({
71
76
  dialect: new PostgresDialect({
72
77
  pool: {
73
78
  connect: async () => {
@@ -80,29 +85,32 @@ class PostgresAdapter extends BaseDatabaseAdapter {
80
85
  end: async () => {},
81
86
  on: () => {}
82
87
  }
83
- })
88
+ }),
89
+ config: {
90
+ collections: this._collections,
91
+ globals: this._globals,
92
+ db: { name: "postgres" }
93
+ }
84
94
  });
85
95
  }
86
96
  async disconnect() {
87
97
  if (this._db)
88
- await this._db.destroy();
98
+ await this.db.destroy();
89
99
  if (this._rawDb)
90
100
  await this._rawDb.end();
91
101
  this._db = null;
92
102
  this._rawDb = null;
93
103
  }
94
104
  async unsafe(query, params) {
95
- if (!this._db)
105
+ if (!this.db)
96
106
  throw new Error("DB not connected");
97
107
  const compiled = CompiledQuery.raw(query, params || []);
98
- const result = await this._db.executeQuery(compiled);
108
+ const result = await this.db.executeQuery(compiled);
99
109
  return result.rows;
100
110
  }
101
111
  async count(collection, query) {
102
- if (!this._db)
103
- throw new Error("DB not connected");
104
112
  const tableName = toSnakeCase(collection);
105
- let qb = this._db.selectFrom(tableName).select((eb) => eb.fn.count("id").as("count"));
113
+ let qb = this.db.selectFrom(tableName).select((eb) => eb.fn.count("id").as("count"));
106
114
  if (query && Object.keys(query).length > 0) {
107
115
  qb = qb.where((eb) => buildKyselyWhere(eb, query) || eb.val(true));
108
116
  }
@@ -110,10 +118,10 @@ class PostgresAdapter extends BaseDatabaseAdapter {
110
118
  return Number(result?.count || 0);
111
119
  }
112
120
  async create(collection, data) {
113
- if (!this._db)
121
+ if (!this.db)
114
122
  throw new Error("DB not connected");
115
123
  const tableName = toSnakeCase(collection);
116
- return this._db.transaction().execute(async (tx) => {
124
+ return this.db.transaction().execute(async (tx) => {
117
125
  const colDef = this._collections.find((c) => c.slug === collection);
118
126
  const jsonFields = colDef?.fields.filter((f) => f.name && (["richtext", "json", "file"].includes(f.type) || f.localized)).map((f) => f.name) || [];
119
127
  const flatData = flattenPayload(data, "", jsonFields);
@@ -130,15 +138,6 @@ class PostgresAdapter extends BaseDatabaseAdapter {
130
138
  delete flatData[key];
131
139
  }
132
140
  }
133
- if (!flatData.id)
134
- flatData.id = crypto.randomUUID();
135
- const now = new Date().toISOString();
136
- const createdKey = toSnakeCase("createdAt");
137
- const updatedKey = toSnakeCase("updatedAt");
138
- if (!flatData[createdKey])
139
- flatData[createdKey] = now;
140
- if (!flatData[updatedKey])
141
- flatData[updatedKey] = now;
142
141
  await tx.insertInto(tableName).values(flatData).execute();
143
142
  for (const [key, values] of Object.entries(hasManyData)) {
144
143
  const joinTableName = `${tableName}_${toSnakeCase(key)}_relations`.toLowerCase();
@@ -172,7 +171,7 @@ class PostgresAdapter extends BaseDatabaseAdapter {
172
171
  }
173
172
  async findOne(collection, query, tx) {
174
173
  const tableName = toSnakeCase(collection);
175
- const executor = tx || this._db;
174
+ const executor = tx || this.db;
176
175
  if (!executor)
177
176
  throw new Error("DB not connected");
178
177
  let qb = executor.selectFrom(tableName).selectAll();
@@ -185,7 +184,7 @@ class PostgresAdapter extends BaseDatabaseAdapter {
185
184
  const unflattened = unflattenRow(row);
186
185
  const colDef = this._collections.find((c) => c.slug === collection);
187
186
  if (colDef) {
188
- const { getRelationalFields: getRelationalFields2, toSnakeCase: toSnakeCase2 } = await import("./chunk-526a3gqx.js");
187
+ const { getRelationalFields: getRelationalFields2, toSnakeCase: toSnakeCase2 } = await import("./chunk-fnsf1dfm.js");
189
188
  const relationalFields = getRelationalFields2(colDef.fields);
190
189
  for (const field of relationalFields) {
191
190
  if (!field.name)
@@ -236,14 +235,22 @@ class PostgresAdapter extends BaseDatabaseAdapter {
236
235
  return unflattened;
237
236
  }
238
237
  async find(collection, query, options) {
239
- if (!this._db)
238
+ if (!this.db)
240
239
  throw new Error("DB not connected");
241
240
  const page = options?.page || 1;
242
241
  const limit = options?.limit || 10;
243
242
  const offset = (page - 1) * limit;
243
+ const cursorColumn = options?.cursorColumn || "id";
244
244
  const total = await this.count(collection, query);
245
245
  const tableName = toSnakeCase(collection);
246
- let qb = this._db.selectFrom(tableName).selectAll().limit(limit).offset(offset);
246
+ let qb = this.db.selectFrom(tableName).selectAll().limit(limit);
247
+ if (options?.after) {
248
+ qb = qb.where(cursorColumn, ">", options.after);
249
+ } else if (options?.before) {
250
+ qb = qb.where(cursorColumn, "<", options.before);
251
+ } else {
252
+ qb = qb.offset(offset);
253
+ }
247
254
  if (query && Object.keys(query).length > 0) {
248
255
  qb = qb.where((eb) => buildKyselyWhere(eb, query) || eb.val(true));
249
256
  }
@@ -253,11 +260,13 @@ class PostgresAdapter extends BaseDatabaseAdapter {
253
260
  qb = qb.orderBy(col, dir === "desc" ? "desc" : "asc");
254
261
  }
255
262
  } else {
256
- qb = qb.orderBy("created_at", "desc");
263
+ qb = qb.orderBy(cursorColumn, "desc");
257
264
  }
258
265
  const rows = await qb.execute();
259
266
  if (rows.length === 0) {
260
267
  const totalPages2 = Math.ceil(total / limit);
268
+ const afterAnchor = options?.after;
269
+ const beforeAnchor = options?.before;
261
270
  return {
262
271
  docs: [],
263
272
  totalDocs: total,
@@ -265,10 +274,12 @@ class PostgresAdapter extends BaseDatabaseAdapter {
265
274
  totalPages: totalPages2,
266
275
  page,
267
276
  pagingCounter: offset + 1,
268
- hasNextPage: page * limit < total,
269
- hasPrevPage: page > 1,
270
- prevPage: page > 1 ? page - 1 : null,
271
- nextPage: page < totalPages2 ? page + 1 : null
277
+ hasNextPage: false,
278
+ hasPrevPage: !!afterAnchor || page > 1,
279
+ prevPage: null,
280
+ nextPage: null,
281
+ nextCursor: null,
282
+ prevCursor: afterAnchor ? afterAnchor : null
272
283
  };
273
284
  }
274
285
  const rowIds = rows.map((r) => r.id);
@@ -283,7 +294,7 @@ class PostgresAdapter extends BaseDatabaseAdapter {
283
294
  if (field.type === "relationship" && "hasMany" in field && field.hasMany) {
284
295
  const joinTableName = `${toSnakeCase(collection)}_${snakeName}_relations`.toLowerCase();
285
296
  try {
286
- const allRelations = await this._db.selectFrom(joinTableName).selectAll().where("source_id", "in", rowIds).orderBy("order", "asc").execute();
297
+ const allRelations = await this.db.selectFrom(joinTableName).selectAll().where("source_id", "in", rowIds).orderBy("order", "asc").execute();
287
298
  const relationsBySource = allRelations.reduce((acc, r) => {
288
299
  if (!acc[r.source_id])
289
300
  acc[r.source_id] = [];
@@ -307,7 +318,7 @@ class PostgresAdapter extends BaseDatabaseAdapter {
307
318
  for (const b of field.blocks) {
308
319
  const blockTableName = `${collection}_${snakeName}_${toSnakeCase(b.slug)}`.toLowerCase();
309
320
  try {
310
- const allBlocks = await this._db.selectFrom(blockTableName).selectAll().where("_parent_id", "in", rowIds).execute();
321
+ const allBlocks = await this.db.selectFrom(blockTableName).selectAll().where("_parent_id", "in", rowIds).execute();
311
322
  for (const blk of allBlocks) {
312
323
  const uf = unflattenRow(blk);
313
324
  uf.blockType = blk.block_type;
@@ -346,15 +357,17 @@ class PostgresAdapter extends BaseDatabaseAdapter {
346
357
  page,
347
358
  pagingCounter: offset + 1,
348
359
  hasNextPage: page * limit < total,
349
- hasPrevPage: page > 1,
360
+ hasPrevPage: page > 1 || !!options?.after || !!options?.before,
350
361
  prevPage: page > 1 ? page - 1 : null,
351
- nextPage: page < totalPages ? page + 1 : null
362
+ nextPage: page < totalPages ? page + 1 : null,
363
+ nextCursor: docs.length > 0 ? docs[docs.length - 1][cursorColumn] : null,
364
+ prevCursor: docs.length > 0 && (page > 1 || !!options?.after || !!options?.before) ? docs[0][cursorColumn] : null
352
365
  };
353
366
  }
354
367
  async update(collection, query, data) {
355
- if (!this._db)
368
+ if (!this.db)
356
369
  throw new Error("DB not connected");
357
- return this._db.transaction().execute(async (tx) => {
370
+ return this.db.transaction().execute(async (tx) => {
358
371
  let normalizedQuery = query;
359
372
  if (typeof query !== "object" || query === null) {
360
373
  normalizedQuery = { id: query };
@@ -362,6 +375,9 @@ class PostgresAdapter extends BaseDatabaseAdapter {
362
375
  const current = await this.findOne(collection, normalizedQuery, tx);
363
376
  if (!current)
364
377
  throw new Error("Document not found");
378
+ const store = requestContext.getStore();
379
+ if (store)
380
+ store.previousData = current;
365
381
  const colDef = this._collections.find((c) => c.slug === collection);
366
382
  const jsonFields = colDef?.fields.filter((f) => f.name && (["richtext", "json", "file"].includes(f.type) || f.localized)).map((f) => f.name) || [];
367
383
  const flatData = flattenPayload(data, "", jsonFields);
@@ -424,10 +440,10 @@ class PostgresAdapter extends BaseDatabaseAdapter {
424
440
  });
425
441
  }
426
442
  async updateMany(collection, query, data) {
427
- if (!this._db)
443
+ if (!this.db)
428
444
  throw new Error("DB not connected");
429
445
  const tableName = toSnakeCase(collection);
430
- return this._db.transaction().execute(async (tx) => {
446
+ return this.db.transaction().execute(async (tx) => {
431
447
  let qb = tx.updateTable(tableName);
432
448
  if (query && Object.keys(query).length > 0) {
433
449
  qb = qb.where((eb) => buildKyselyWhere(eb, query) || eb.val(true));
@@ -447,7 +463,7 @@ class PostgresAdapter extends BaseDatabaseAdapter {
447
463
  });
448
464
  }
449
465
  async delete(collection, query) {
450
- if (!this._db)
466
+ if (!this.db)
451
467
  throw new Error("DB not connected");
452
468
  let normalizedQuery = query;
453
469
  if (typeof query !== "object" || query === null) {
@@ -457,7 +473,7 @@ class PostgresAdapter extends BaseDatabaseAdapter {
457
473
  if (!current)
458
474
  return false;
459
475
  const tableName = toSnakeCase(collection);
460
- await this._db.transaction().execute(async (tx) => {
476
+ await this.db.transaction().execute(async (tx) => {
461
477
  const colDef = this._collections.find((c) => c.slug === collection);
462
478
  if (colDef) {
463
479
  for (const field of colDef.fields) {
@@ -482,10 +498,10 @@ class PostgresAdapter extends BaseDatabaseAdapter {
482
498
  return true;
483
499
  }
484
500
  async deleteMany(collection, query) {
485
- if (!this._db)
501
+ if (!this.db)
486
502
  throw new Error("DB not connected");
487
503
  const tableName = toSnakeCase(collection);
488
- return this._db.transaction().execute(async (tx) => {
504
+ return this.db.transaction().execute(async (tx) => {
489
505
  let selectQb = tx.selectFrom(tableName).select("id");
490
506
  if (query && Object.keys(query).length > 0) {
491
507
  selectQb = selectQb.where((eb) => buildKyselyWhere(eb, query) || eb.val(true));
@@ -518,14 +534,14 @@ class PostgresAdapter extends BaseDatabaseAdapter {
518
534
  });
519
535
  }
520
536
  async findGlobal(slug) {
521
- if (!this._db)
537
+ if (!this.db)
522
538
  throw new Error("DB not connected");
523
539
  const tableName = toSnakeCase(slug);
524
- const row = await this._db.selectFrom(tableName).selectAll().limit(1).executeTakeFirst();
540
+ const row = await this.db.selectFrom(tableName).selectAll().limit(1).executeTakeFirst();
525
541
  return row ? unflattenRow(row) : null;
526
542
  }
527
543
  async updateGlobal(slug, data) {
528
- if (!this._db)
544
+ if (!this.db)
529
545
  throw new Error("DB not connected");
530
546
  const tableName = toSnakeCase(slug);
531
547
  const existing = await this.findGlobal(slug);
@@ -538,17 +554,17 @@ class PostgresAdapter extends BaseDatabaseAdapter {
538
554
  if (!flatData.id)
539
555
  flatData.id = "global";
540
556
  flatData[toSnakeCase("createdAt")] = now;
541
- await this._db.insertInto(tableName).values(flatData).execute();
557
+ await this.db.insertInto(tableName).values(flatData).execute();
542
558
  } else {
543
- await this._db.updateTable(tableName).set(flatData).where("id", "=", existing.id).execute();
559
+ await this.db.updateTable(tableName).set(flatData).where("id", "=", existing.id).execute();
544
560
  }
545
561
  return this.findGlobal(slug);
546
562
  }
547
563
  async runMigrations() {
548
- if (!this._db)
564
+ if (!this.db)
549
565
  throw new Error("DB not connected");
550
566
  const migrator = new Migrator({
551
- db: this._db,
567
+ db: this.db,
552
568
  provider: new FileMigrationProvider({
553
569
  fs,
554
570
  path,
@@ -568,11 +584,11 @@ class PostgresAdapter extends BaseDatabaseAdapter {
568
584
  }
569
585
  }
570
586
  async migrate(collections, globals = []) {
571
- const { getSystemCollections } = await import("./chunk-3rdhbedb.js");
587
+ const { getSystemCollections } = await import("./chunk-adq2b75c.js");
572
588
  this._collections = [...getSystemCollections(), ...collections];
573
589
  this._globals = globals;
574
590
  if (this.push && this._db) {
575
- await pushSchema(this._db, "postgres", collections, globals, {
591
+ await pushSchema(this.db, "postgres", collections, globals, {
576
592
  pushDestructive: this.pushDestructive
577
593
  });
578
594
  }
@@ -0,0 +1,95 @@
1
+ import {
2
+ require_picocolors
3
+ } from "./chunk-rwqwsanx.js";
4
+ import {
5
+ Gt,
6
+ R,
7
+ Vt,
8
+ Wt,
9
+ be
10
+ } from "./chunk-ec4jhybj.js";
11
+ import {
12
+ loadConfig,
13
+ resolveConfigPath
14
+ } from "./chunk-majsbncm.js";
15
+ import {
16
+ defineCommand
17
+ } from "./chunk-1qm0m8r8.js";
18
+ import {
19
+ __toESM
20
+ } from "./chunk-6bywt602.js";
21
+
22
+ // src/cli/commands/doctor.ts
23
+ import fs from "node:fs";
24
+ var import_picocolors = __toESM(require_picocolors(), 1);
25
+ var doctor_default = defineCommand({
26
+ meta: {
27
+ name: "doctor",
28
+ description: "Diagnose your OpacaCMS project configuration and database connection"
29
+ },
30
+ args: {
31
+ config: {
32
+ type: "string",
33
+ alias: "c",
34
+ description: "Path to the OpacaCMS configuration file"
35
+ }
36
+ },
37
+ async run({ args }) {
38
+ console.log();
39
+ Wt(import_picocolors.default.bgMagenta(import_picocolors.default.white(" OpacaCMS Doctor ")));
40
+ const s = be();
41
+ s.start("Locating configuration file...");
42
+ let configPath;
43
+ try {
44
+ configPath = resolveConfigPath(args.config);
45
+ s.stop(`Config found at ${import_picocolors.default.green(configPath)}`);
46
+ } catch (err) {
47
+ s.stop(import_picocolors.default.red("Config file not found."));
48
+ R.error("Could not find opacacms.config.ts or similar.");
49
+ Gt(import_picocolors.default.red("Diagnosis failed."));
50
+ process.exit(1);
51
+ }
52
+ s.start("Loading configuration...");
53
+ let opaca;
54
+ try {
55
+ opaca = await loadConfig(configPath);
56
+ s.stop(`Configuration loaded successfully. App Name: ${import_picocolors.default.cyan(opaca.appName || "Unknown")}`);
57
+ } catch (err) {
58
+ s.stop(import_picocolors.default.red("Failed to load configuration."));
59
+ R.error(err.message);
60
+ Gt(import_picocolors.default.red("Diagnosis failed."));
61
+ process.exit(1);
62
+ }
63
+ s.start("Verifying database connection...");
64
+ try {
65
+ if (!opaca.db)
66
+ throw new Error("No database configured in config.db");
67
+ const tables = await opaca.db.kysely.introspection.getTables();
68
+ s.stop(`Database connected successfully. Found ${import_picocolors.default.green(tables.length)} tables.`);
69
+ } catch (err) {
70
+ s.stop(import_picocolors.default.red("Database connection failed."));
71
+ R.error(err.message);
72
+ }
73
+ s.start("Checking dependencies...");
74
+ try {
75
+ const pkgPath = `${process.cwd()}/package.json`;
76
+ if (fs.existsSync(pkgPath)) {
77
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
78
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
79
+ if (!deps.opacacms) {
80
+ R.warn(import_picocolors.default.yellow("opacacms is missing from package.json"));
81
+ }
82
+ s.stop(`Dependencies checked.`);
83
+ } else {
84
+ s.stop(import_picocolors.default.yellow("package.json not found."));
85
+ }
86
+ } catch (err) {
87
+ s.stop(import_picocolors.default.red("Error checking dependencies."));
88
+ }
89
+ Vt(`Everything seems to be in order! Run \`opacacms dev\` to start.`, "Diagnosis Complete");
90
+ Gt("Doctor out.");
91
+ }
92
+ });
93
+ export {
94
+ doctor_default as default
95
+ };
@@ -0,0 +1,47 @@
1
+ // src/utils/string.ts
2
+ function sanitizeGraphQLName(name) {
3
+ return name.replace(/[^_a-zA-Z0-9]/g, "_");
4
+ }
5
+ function getRandomMigrationName() {
6
+ const adjectives = [
7
+ "vibrant",
8
+ "snarky",
9
+ "brave",
10
+ "swift",
11
+ "silent",
12
+ "funky",
13
+ "mystic",
14
+ "loyal",
15
+ "nimble",
16
+ "eager",
17
+ "wild",
18
+ "chill",
19
+ "golden",
20
+ "magic",
21
+ "smart",
22
+ "fierce"
23
+ ];
24
+ const nouns = [
25
+ "vulture",
26
+ "badger",
27
+ "falcon",
28
+ "otter",
29
+ "lynx",
30
+ "panda",
31
+ "fox",
32
+ "lemur",
33
+ "cobra",
34
+ "whale",
35
+ "eagle",
36
+ "tiger",
37
+ "koala",
38
+ "bison",
39
+ "raven",
40
+ "shark"
41
+ ];
42
+ const adj = adjectives[Math.floor(Math.random() * adjectives.length)];
43
+ const noun = nouns[Math.floor(Math.random() * nouns.length)];
44
+ return `${adj}_${noun}`;
45
+ }
46
+
47
+ export { sanitizeGraphQLName, getRandomMigrationName };