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,10 +3,13 @@ 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
  flattenFields,
12
15
  getRelationalFields,
@@ -14,17 +17,19 @@ import {
14
17
  } from "./chunk-qxt9vge8.js";
15
18
  import {
16
19
  logger
17
- } from "./chunk-t0zg026p.js";
20
+ } from "./chunk-jq1drsen.js";
21
+ import {
22
+ __require
23
+ } from "./chunk-6bywt602.js";
18
24
 
19
25
  // src/db/d1.ts
20
26
  import fs from "node:fs/promises";
21
27
  import path from "node:path";
22
- import { CompiledQuery, FileMigrationProvider, Kysely, Migrator } from "kysely";
23
- import { D1Dialect } from "kysely-d1";
28
+ import { CompiledQuery, FileMigrationProvider, Migrator } from "kysely";
24
29
  class D1Adapter extends BaseDatabaseAdapter {
25
30
  name = "d1";
26
31
  _rawDb;
27
- _db;
32
+ _db = null;
28
33
  _collections = [];
29
34
  _globals = [];
30
35
  push;
@@ -34,69 +39,44 @@ class D1Adapter extends BaseDatabaseAdapter {
34
39
  return this._rawDb;
35
40
  }
36
41
  get db() {
42
+ if (!this._db)
43
+ throw new Error("Database not connected. Call connect() first.");
37
44
  return this._db;
38
45
  }
39
46
  constructor(db, options) {
40
47
  super();
41
48
  this._rawDb = db;
42
- this._db = new Kysely({
43
- dialect: new D1Dialect({ database: db })
44
- });
45
49
  const isDev = typeof process !== "undefined" && true;
46
50
  this.push = options?.push ?? isDev;
47
51
  this.pushDestructive = options?.pushDestructive ?? false;
48
52
  this.migrationDir = options?.migrationDir ?? "./migrations";
49
53
  }
50
- async connect() {}
54
+ async connect() {
55
+ if (this._db)
56
+ return;
57
+ const { D1Dialect } = await import("kysely-d1");
58
+ const { createOpacaKysely } = await import("./chunk-sqsfk9p4.js");
59
+ this._db = createOpacaKysely({
60
+ dialect: new D1Dialect({ database: this._rawDb }),
61
+ config: {
62
+ collections: this._collections,
63
+ globals: this._globals,
64
+ db: { name: "d1" }
65
+ }
66
+ });
67
+ }
51
68
  async disconnect() {
52
- await this._db.destroy();
69
+ if (this._db)
70
+ await this.db.destroy();
53
71
  }
54
72
  async unsafe(query, params) {
55
73
  const compiled = CompiledQuery.raw(query, params || []);
56
- const result = await this._db.executeQuery(compiled);
74
+ const result = await this.db.executeQuery(compiled);
57
75
  return result.rows;
58
76
  }
59
- async coerceData(collection, data) {
60
- const colDef = this._collections.find((c) => c.slug === collection);
61
- if (!colDef)
62
- return data;
63
- const result = { ...data };
64
- const allFields = flattenFields(colDef.fields);
65
- for (const field of allFields) {
66
- const colName = toSnakeCase(field.name);
67
- if (!(colName in result))
68
- continue;
69
- const value = result[colName];
70
- if (value === undefined || value === null)
71
- continue;
72
- switch (field.type) {
73
- case "boolean":
74
- result[colName] = value ? 1 : 0;
75
- break;
76
- case "number":
77
- result[colName] = Number(value);
78
- break;
79
- case "date":
80
- if (value instanceof Date) {
81
- result[colName] = value.toISOString();
82
- } else if (typeof value === "string") {
83
- result[colName] = new Date(value).toISOString();
84
- }
85
- break;
86
- case "richtext":
87
- case "json":
88
- case "file":
89
- if (typeof value === "object") {
90
- result[colName] = JSON.stringify(value);
91
- }
92
- break;
93
- }
94
- }
95
- return result;
96
- }
97
77
  async count(collection, query) {
98
78
  const tableName = toSnakeCase(collection);
99
- let qb = this._db.selectFrom(tableName).select((eb) => eb.fn.count("id").as("count"));
79
+ let qb = this.db.selectFrom(tableName).select((eb) => eb.fn.count("id").as("count"));
100
80
  if (query && Object.keys(query).length > 0) {
101
81
  qb = qb.where((eb) => buildKyselyWhere(eb, query) || eb.val(true));
102
82
  }
@@ -129,18 +109,14 @@ class D1Adapter extends BaseDatabaseAdapter {
129
109
  validCols.add("id");
130
110
  validCols.add(toSnakeCase("createdAt"));
131
111
  validCols.add(toSnakeCase("updatedAt"));
132
- const now = new Date().toISOString();
133
- flatData[toSnakeCase("createdAt")] = now;
134
- flatData[toSnakeCase("updatedAt")] = now;
135
112
  const filteredData = {};
136
113
  for (const col of Object.keys(flatData)) {
137
114
  if (validCols.has(col)) {
138
115
  filteredData[col] = flatData[col];
139
116
  }
140
117
  }
141
- const coercedData = await this.coerceData(collection, filteredData);
142
118
  try {
143
- await this._db.insertInto(tableName).values(coercedData).execute();
119
+ await this.db.insertInto(tableName).values(filteredData).execute();
144
120
  } catch (e) {
145
121
  logger.error(`[D1] Create failed in ${collection}: ${e.message}`);
146
122
  throw e;
@@ -152,7 +128,7 @@ class D1Adapter extends BaseDatabaseAdapter {
152
128
  const tId = typeof val === "object" ? val.id : val;
153
129
  return { id: crypto.randomUUID(), source_id: flatData.id, target_id: tId, order: idx };
154
130
  });
155
- await this._db.insertInto(joinTableName).values(joinData).execute();
131
+ await this.db.insertInto(joinTableName).values(joinData).execute();
156
132
  }
157
133
  }
158
134
  for (const [key, blocks] of Object.entries(blocksData)) {
@@ -172,20 +148,20 @@ class D1Adapter extends BaseDatabaseAdapter {
172
148
  }
173
149
  }
174
150
  delete blockFlatData.blockType;
175
- const coercedBlockData = await this.coerceData(blockTableName, {
151
+ const blockData = {
176
152
  ...blockFlatData,
177
153
  _parent_id: flatData.id,
178
154
  _order: i,
179
155
  block_type: block.blockType
180
- });
181
- await this._db.insertInto(blockTableName).values(coercedBlockData).execute();
156
+ };
157
+ await this.db.insertInto(blockTableName).values(blockData).execute();
182
158
  }
183
159
  }
184
- return this.findOne(collection, { id: flatData.id }, this._db);
160
+ return this.findOne(collection, { id: flatData.id }, this.db);
185
161
  }
186
162
  async findOne(collection, query, tx) {
187
163
  const tableName = toSnakeCase(collection);
188
- const executor = tx || this._db;
164
+ const executor = tx || this.db;
189
165
  let qb = executor.selectFrom(tableName).selectAll();
190
166
  if (query && Object.keys(query).length > 0) {
191
167
  qb = qb.where((eb) => buildKyselyWhere(eb, query) || eb.val(true));
@@ -249,9 +225,17 @@ class D1Adapter extends BaseDatabaseAdapter {
249
225
  const page = options?.page || 1;
250
226
  const limit = options?.limit || 10;
251
227
  const offset = (page - 1) * limit;
228
+ const cursorColumn = options?.cursorColumn || "id";
252
229
  const total = await this.count(collection, query);
253
230
  const tableName = toSnakeCase(collection);
254
- let qb = this._db.selectFrom(tableName).selectAll().limit(limit).offset(offset);
231
+ let qb = this.db.selectFrom(tableName).selectAll().limit(limit);
232
+ if (options?.after) {
233
+ qb = qb.where(cursorColumn, ">", options.after);
234
+ } else if (options?.before) {
235
+ qb = qb.where(cursorColumn, "<", options.before);
236
+ } else {
237
+ qb = qb.offset(offset);
238
+ }
255
239
  if (query && Object.keys(query).length > 0) {
256
240
  qb = qb.where((eb) => buildKyselyWhere(eb, query) || eb.val(true));
257
241
  }
@@ -261,11 +245,13 @@ class D1Adapter extends BaseDatabaseAdapter {
261
245
  qb = qb.orderBy(col, dir === "desc" ? "desc" : "asc");
262
246
  }
263
247
  } else {
264
- qb = qb.orderBy("created_at", "desc");
248
+ qb = qb.orderBy(cursorColumn, "desc");
265
249
  }
266
250
  const rows = await qb.execute();
267
251
  if (rows.length === 0) {
268
252
  const totalPages2 = Math.ceil(total / limit);
253
+ const afterAnchor = options?.after;
254
+ const beforeAnchor = options?.before;
269
255
  return {
270
256
  docs: [],
271
257
  totalDocs: total,
@@ -273,10 +259,12 @@ class D1Adapter extends BaseDatabaseAdapter {
273
259
  totalPages: totalPages2,
274
260
  page,
275
261
  pagingCounter: offset + 1,
276
- hasNextPage: page * limit < total,
277
- hasPrevPage: page > 1,
278
- prevPage: page > 1 ? page - 1 : null,
279
- nextPage: page < totalPages2 ? page + 1 : null
262
+ hasNextPage: false,
263
+ hasPrevPage: !!afterAnchor || page > 1,
264
+ prevPage: null,
265
+ nextPage: null,
266
+ nextCursor: null,
267
+ prevCursor: afterAnchor ? afterAnchor : null
280
268
  };
281
269
  }
282
270
  const rowIds = rows.map((r) => r.id);
@@ -291,7 +279,7 @@ class D1Adapter extends BaseDatabaseAdapter {
291
279
  if (field.type === "relationship" && "hasMany" in field && field.hasMany) {
292
280
  const joinTableName = `${toSnakeCase(collection)}_${snakeName}_relations`.toLowerCase();
293
281
  try {
294
- const allRelations = await this._db.selectFrom(joinTableName).selectAll().where("source_id", "in", rowIds).orderBy("order", "asc").execute();
282
+ const allRelations = await this.db.selectFrom(joinTableName).selectAll().where("source_id", "in", rowIds).orderBy("order", "asc").execute();
295
283
  const relationsBySource = allRelations.reduce((acc, r) => {
296
284
  if (!acc[r.source_id])
297
285
  acc[r.source_id] = [];
@@ -315,7 +303,7 @@ class D1Adapter extends BaseDatabaseAdapter {
315
303
  for (const b of field.blocks) {
316
304
  const blockTableName = `${collection}_${snakeName}_${toSnakeCase(b.slug)}`.toLowerCase();
317
305
  try {
318
- const allBlocks = await this._db.selectFrom(blockTableName).selectAll().where("_parent_id", "in", rowIds).execute();
306
+ const allBlocks = await this.db.selectFrom(blockTableName).selectAll().where("_parent_id", "in", rowIds).execute();
319
307
  for (const blk of allBlocks) {
320
308
  const uf = unflattenRow(blk);
321
309
  uf.blockType = blk.block_type;
@@ -354,9 +342,11 @@ class D1Adapter extends BaseDatabaseAdapter {
354
342
  page,
355
343
  pagingCounter: offset + 1,
356
344
  hasNextPage: page * limit < total,
357
- hasPrevPage: page > 1,
345
+ hasPrevPage: page > 1 || !!options?.after || !!options?.before,
358
346
  prevPage: page > 1 ? page - 1 : null,
359
- nextPage: page < totalPages ? page + 1 : null
347
+ nextPage: page < totalPages ? page + 1 : null,
348
+ nextCursor: docs.length > 0 ? docs[docs.length - 1][cursorColumn] : null,
349
+ prevCursor: docs.length > 0 && (page > 1 || !!options?.after || !!options?.before) ? docs[0][cursorColumn] : null
360
350
  };
361
351
  }
362
352
  async update(collection, query, data) {
@@ -365,9 +355,12 @@ class D1Adapter extends BaseDatabaseAdapter {
365
355
  if (typeof query !== "object" || query === null) {
366
356
  normalizedQuery = { id: query };
367
357
  }
368
- const current = await this.findOne(collection, normalizedQuery, this._db);
358
+ const current = await this.findOne(collection, normalizedQuery, this.db);
369
359
  if (!current)
370
360
  throw new Error("Document not found");
361
+ const store = requestContext.getStore();
362
+ if (store)
363
+ store.previousData = current;
371
364
  const colDef = this._collections.find((c) => c.slug === collection);
372
365
  const jsonFields = colDef?.fields.filter((f) => f.name && (["richtext", "json", "file"].includes(f.type) || f.localized)).map((f) => f.name) || [];
373
366
  const flatData = flattenPayload(data, "", jsonFields);
@@ -385,30 +378,18 @@ class D1Adapter extends BaseDatabaseAdapter {
385
378
  delete flatData[key];
386
379
  }
387
380
  }
388
- const ts = colDef?.timestamps !== false;
389
- if (ts) {
390
- const config = typeof colDef?.timestamps === "object" ? colDef.timestamps : {};
391
- const updatedField = toSnakeCase(config.updatedAt || "updatedAt");
392
- flatData[updatedField] = new Date().toISOString();
393
- }
394
381
  if (Object.keys(flatData).length > 0) {
395
382
  const dbFields = flattenFields(colDef?.fields || []);
396
383
  const validCols = new Set(dbFields.map((f) => toSnakeCase(f.name)));
397
384
  validCols.add("id");
398
- if (ts) {
399
- const config = typeof colDef?.timestamps === "object" ? colDef.timestamps : {};
400
- validCols.add(toSnakeCase(config.createdAt || "createdAt"));
401
- validCols.add(toSnakeCase(config.updatedAt || "updatedAt"));
402
- }
403
385
  const filteredData = {};
404
386
  for (const col of Object.keys(flatData)) {
405
387
  if (validCols.has(col)) {
406
388
  filteredData[col] = flatData[col];
407
389
  }
408
390
  }
409
- const coercedData = await this.coerceData(collection, filteredData);
410
391
  try {
411
- await this._db.updateTable(tableName).set(coercedData).where("id", "=", current.id).execute();
392
+ await this.db.updateTable(tableName).set(filteredData).where("id", "=", current.id).execute();
412
393
  } catch (e) {
413
394
  logger.error(`[D1] Update failed in ${collection}: ${e.message}`);
414
395
  throw e;
@@ -416,13 +397,13 @@ class D1Adapter extends BaseDatabaseAdapter {
416
397
  }
417
398
  for (const [key, values] of Object.entries(hasManyData)) {
418
399
  const joinTableName = `${tableName}_${toSnakeCase(key)}_relations`.toLowerCase();
419
- await this._db.deleteFrom(joinTableName).where("source_id", "=", current.id).execute();
400
+ await this.db.deleteFrom(joinTableName).where("source_id", "=", current.id).execute();
420
401
  if (values.length > 0) {
421
402
  const joinData = values.map((val, idx) => {
422
403
  const tId = typeof val === "object" ? val.id : val;
423
404
  return { id: crypto.randomUUID(), source_id: current.id, target_id: tId, order: idx };
424
405
  });
425
- await this._db.insertInto(joinTableName).values(joinData).execute();
406
+ await this.db.insertInto(joinTableName).values(joinData).execute();
426
407
  }
427
408
  }
428
409
  for (const [key, blocks] of Object.entries(blocksData)) {
@@ -431,7 +412,7 @@ class D1Adapter extends BaseDatabaseAdapter {
431
412
  for (const b of blockDef.blocks) {
432
413
  const blockTableName = `${tableName}_${toSnakeCase(key)}_${toSnakeCase(b.slug)}`.toLowerCase();
433
414
  try {
434
- await this._db.deleteFrom(blockTableName).where("_parent_id", "=", current.id).execute();
415
+ await this.db.deleteFrom(blockTableName).where("_parent_id", "=", current.id).execute();
435
416
  } catch (e) {}
436
417
  }
437
418
  }
@@ -450,20 +431,20 @@ class D1Adapter extends BaseDatabaseAdapter {
450
431
  }
451
432
  }
452
433
  delete blockFlatData.blockType;
453
- const coercedBlockData = await this.coerceData(blockTableName, {
434
+ const blockData = {
454
435
  ...blockFlatData,
455
436
  _parent_id: current.id,
456
437
  _order: i,
457
438
  block_type: block.blockType
458
- });
459
- await this._db.insertInto(blockTableName).values(coercedBlockData).execute();
439
+ };
440
+ await this.db.insertInto(blockTableName).values(blockData).execute();
460
441
  }
461
442
  }
462
- return this.findOne(collection, { id: current.id }, this._db);
443
+ return this.findOne(collection, { id: current.id }, this.db);
463
444
  }
464
445
  async updateMany(collection, query, data) {
465
446
  const tableName = toSnakeCase(collection);
466
- let qb = this._db.updateTable(tableName);
447
+ let qb = this.db.updateTable(tableName);
467
448
  if (query && Object.keys(query).length > 0) {
468
449
  qb = qb.where((eb) => buildKyselyWhere(eb, query) || eb.val(true));
469
450
  }
@@ -475,31 +456,19 @@ class D1Adapter extends BaseDatabaseAdapter {
475
456
  delete flatData[key];
476
457
  }
477
458
  }
478
- const ts = colDef?.timestamps !== false;
479
- if (ts) {
480
- const config = typeof colDef?.timestamps === "object" ? colDef.timestamps : {};
481
- const updatedField = toSnakeCase(config.updatedAt || "updatedAt");
482
- flatData[updatedField] = new Date().toISOString();
483
- }
484
459
  if (Object.keys(flatData).length > 0) {
485
460
  const dbFields = flattenFields(colDef?.fields || []);
486
461
  const validCols = new Set(dbFields.map((f) => toSnakeCase(f.name)));
487
462
  validCols.add("id");
488
- if (ts) {
489
- const config = typeof colDef?.timestamps === "object" ? colDef.timestamps : {};
490
- validCols.add(toSnakeCase(config.createdAt || "createdAt"));
491
- validCols.add(toSnakeCase(config.updatedAt || "updatedAt"));
492
- }
493
463
  const filteredData = {};
494
464
  for (const col of Object.keys(flatData)) {
495
465
  if (validCols.has(col)) {
496
466
  filteredData[col] = flatData[col];
497
467
  }
498
468
  }
499
- const coercedData = await this.coerceData(collection, filteredData);
500
469
  logger.debug(`[D1] Bulk updating in ${collection}...`);
501
470
  try {
502
- const result = await qb.set(coercedData).executeTakeFirst();
471
+ const result = await qb.set(filteredData).executeTakeFirst();
503
472
  return Number(result.numUpdatedRows || 0);
504
473
  } catch (e) {
505
474
  logger.error(`[D1] Bulk update failed in ${collection}: ${e.message}`);
@@ -527,31 +496,31 @@ class D1Adapter extends BaseDatabaseAdapter {
527
496
  if (field.type === "relationship" && "hasMany" in field && field.hasMany) {
528
497
  const joinTableName = `${tableName}_${snakeName}_relations`.toLowerCase();
529
498
  try {
530
- await this._db.deleteFrom(joinTableName).where("source_id", "=", current.id).execute();
499
+ await this.db.deleteFrom(joinTableName).where("source_id", "=", current.id).execute();
531
500
  } catch (e) {}
532
501
  } else if (field.type === "blocks" && "blocks" in field && field.blocks) {
533
502
  for (const b of field.blocks) {
534
503
  const blockTableName = `${tableName}_${snakeName}_${toSnakeCase(b.slug)}`.toLowerCase();
535
504
  try {
536
- await this._db.deleteFrom(blockTableName).where("_parent_id", "=", current.id).execute();
505
+ await this.db.deleteFrom(blockTableName).where("_parent_id", "=", current.id).execute();
537
506
  } catch (e) {}
538
507
  }
539
508
  }
540
509
  }
541
510
  }
542
- await this._db.deleteFrom(tableName).where("id", "=", current.id).execute();
511
+ await this.db.deleteFrom(tableName).where("id", "=", current.id).execute();
543
512
  return true;
544
513
  }
545
514
  async deleteMany(collection, query) {
546
515
  const tableName = toSnakeCase(collection);
547
- let selectQb = this._db.selectFrom(tableName).select("id");
516
+ let selectQb = this.db.selectFrom(tableName).select("id");
548
517
  if (query && Object.keys(query).length > 0) {
549
518
  selectQb = selectQb.where((eb) => buildKyselyWhere(eb, query) || eb.val(true));
550
519
  }
551
- const docs = await selectQb.execute();
552
- if (docs.length === 0)
520
+ const rowsToDelete = await selectQb.execute();
521
+ const idsToDelete = rowsToDelete.map((row) => row.id);
522
+ if (idsToDelete.length === 0)
553
523
  return 0;
554
- const ids = docs.map((d) => d.id);
555
524
  const colDef = this._collections.find((c) => c.slug === collection);
556
525
  if (colDef) {
557
526
  const relationalFields = getRelationalFields(colDef.fields);
@@ -562,24 +531,24 @@ class D1Adapter extends BaseDatabaseAdapter {
562
531
  if (field.type === "relationship" && "hasMany" in field && field.hasMany) {
563
532
  const joinTableName = `${tableName}_${snakeName}_relations`.toLowerCase();
564
533
  try {
565
- await this._db.deleteFrom(joinTableName).where("source_id", "in", ids).execute();
534
+ await this.db.deleteFrom(joinTableName).where("source_id", "in", idsToDelete).execute();
566
535
  } catch (e) {}
567
536
  } else if (field.type === "blocks" && "blocks" in field && field.blocks) {
568
537
  for (const b of field.blocks) {
569
538
  const blockTableName = `${tableName}_${snakeName}_${toSnakeCase(b.slug)}`.toLowerCase();
570
539
  try {
571
- await this._db.deleteFrom(blockTableName).where("_parent_id", "in", ids).execute();
540
+ await this.db.deleteFrom(blockTableName).where("_parent_id", "in", idsToDelete).execute();
572
541
  } catch (e) {}
573
542
  }
574
543
  }
575
544
  }
576
545
  }
577
- const result = await this._db.deleteFrom(tableName).where("id", "in", ids).executeTakeFirst();
546
+ const result = await this.db.deleteFrom(tableName).where("id", "in", idsToDelete).executeTakeFirst();
578
547
  return Number(result.numDeletedRows || 0);
579
548
  }
580
549
  async findGlobal(slug) {
581
550
  const tableName = toSnakeCase(slug);
582
- const row = await this._db.selectFrom(tableName).selectAll().limit(1).executeTakeFirst();
551
+ const row = await this.db.selectFrom(tableName).selectAll().limit(1).executeTakeFirst();
583
552
  return row ? unflattenRow(row) : null;
584
553
  }
585
554
  async updateGlobal(slug, data) {
@@ -593,15 +562,15 @@ class D1Adapter extends BaseDatabaseAdapter {
593
562
  if (!flatData.id)
594
563
  flatData.id = "global";
595
564
  flatData[toSnakeCase("createdAt")] = now;
596
- await this._db.insertInto(tableName).values(flatData).execute();
565
+ await this.db.insertInto(tableName).values(flatData).execute();
597
566
  } else {
598
- await this._db.updateTable(tableName).set(flatData).where("id", "=", existing.id).execute();
567
+ await this.db.updateTable(tableName).set(flatData).where("id", "=", existing.id).execute();
599
568
  }
600
569
  return this.findGlobal(slug);
601
570
  }
602
571
  async runMigrations() {
603
572
  const migrator = new Migrator({
604
- db: this._db,
573
+ db: this.db,
605
574
  provider: new FileMigrationProvider({
606
575
  fs,
607
576
  path,
@@ -624,7 +593,7 @@ class D1Adapter extends BaseDatabaseAdapter {
624
593
  this._collections = collections;
625
594
  this._globals = globals;
626
595
  if (this.push) {
627
- await pushSchema(this._db, "d1", collections, globals, {
596
+ await pushSchema(this.db, "d1", collections, globals, {
628
597
  pushDestructive: this.pushDestructive
629
598
  });
630
599
  }