opacacms 0.3.16 → 0.3.17

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 (121) hide show
  1. package/dist/admin/{stores → features/collections}/admin-queries.d.ts +1 -1
  2. package/dist/admin/{ui/views → features/collections}/collection-list-view.d.ts +1 -1
  3. package/dist/admin/{ui/views → features/collections}/document-edit-view.d.ts +2 -1
  4. package/dist/admin/{ui/views → features/collections}/global-edit-view.d.ts +1 -1
  5. package/dist/admin/{ui/components → features/collections}/versions-sheet.d.ts +3 -3
  6. package/dist/admin/{ui/views → features/dashboard}/dashboard-view.d.ts +1 -1
  7. package/dist/admin/{ui/components/media/AssetManagerModal.d.ts → features/media/components/asset-manager-modal.d.ts} +1 -2
  8. package/dist/admin/features/media/media-registry-view.d.ts +7 -0
  9. package/dist/admin/{ui/components/PluginSettingsForm.d.ts → features/settings/plugin-settings-form.d.ts} +3 -3
  10. package/dist/admin/{ui/views → features/settings}/settings-view.d.ts +2 -2
  11. package/dist/admin/{stores → features/ui-shell}/config.d.ts +1 -1
  12. package/dist/admin/{stores → features/ui-shell}/ui.d.ts +1 -1
  13. package/dist/admin/index.d.ts +8 -8
  14. package/dist/admin/index.js +4 -4
  15. package/dist/admin/ui/{components/ui → core}/blocks.d.ts +1 -1
  16. package/dist/admin/ui/core/breadcrumbs.d.ts +21 -0
  17. package/dist/admin/ui/{components/ui → core}/button.d.ts +4 -4
  18. package/dist/admin/ui/{components/ui → core}/collapsible.d.ts +2 -2
  19. package/dist/admin/ui/core/context-menu.d.ts +29 -0
  20. package/dist/admin/ui/core/dialog.d.ts +20 -0
  21. package/dist/admin/ui/{components/ui → core}/group.d.ts +2 -2
  22. package/dist/admin/ui/core/index.d.ts +17 -0
  23. package/dist/admin/ui/{components/ui → core}/input.d.ts +2 -2
  24. package/dist/admin/ui/{components/ui → core}/join.d.ts +1 -1
  25. package/dist/admin/ui/core/label.d.ts +4 -0
  26. package/dist/admin/ui/core/popover.d.ts +10 -0
  27. package/dist/admin/ui/{components/ui → core}/radio-group.d.ts +2 -2
  28. package/dist/admin/ui/{components/ui → core}/relationship.d.ts +1 -1
  29. package/dist/admin/ui/{components/ui → core}/scroll-area.d.ts +1 -1
  30. package/dist/admin/ui/core/select.d.ts +15 -0
  31. package/dist/admin/ui/{components/ui → core}/sheet.d.ts +6 -6
  32. package/dist/admin/ui/core/sidebar.d.ts +69 -0
  33. package/dist/admin/ui/core/skeleton.d.ts +2 -0
  34. package/dist/admin/ui/core/switch.d.ts +6 -0
  35. package/dist/admin/ui/core/table.d.ts +10 -0
  36. package/dist/admin/ui/core/tabs.d.ts +11 -0
  37. package/dist/admin/ui/hooks/use-mobile.d.ts +1 -0
  38. package/dist/admin/ui/{admin-client.d.ts → layout/admin-client.d.ts} +1 -1
  39. package/dist/admin/ui/{admin-layout.d.ts → layout/admin-layout.d.ts} +2 -2
  40. package/dist/admin/ui/{components → shared}/column-visibility-toggle.d.ts +1 -1
  41. package/dist/admin/ui/{components → shared}/detail-sheet.d.ts +2 -2
  42. package/dist/admin/ui/{components/fields/ArrayField.d.ts → shared/fields/array-field.d.ts} +1 -1
  43. package/dist/admin/ui/shared/fields/blocks-field.d.ts +25 -0
  44. package/dist/admin/ui/{components/fields/BooleanField.d.ts → shared/fields/boolean-field.d.ts} +1 -1
  45. package/dist/admin/ui/{components/fields/CollapsibleField.d.ts → shared/fields/collapsible-field.d.ts} +1 -1
  46. package/dist/admin/ui/{components/fields/FileField.d.ts → shared/fields/file-field.d.ts} +13 -3
  47. package/dist/admin/ui/{components/fields/GroupField.d.ts → shared/fields/group-field.d.ts} +1 -1
  48. package/dist/admin/ui/shared/fields/index.d.ts +28 -0
  49. package/dist/admin/ui/{components/fields/JoinField.d.ts → shared/fields/join-field.d.ts} +1 -1
  50. package/dist/admin/ui/{components/fields/RelationshipField.d.ts → shared/fields/relationship-field.d.ts} +1 -1
  51. package/dist/admin/ui/{components → shared}/fields/richtext-editor/index.d.ts +2 -2
  52. package/dist/admin/ui/{components/fields/richtext-editor/nodes/ImageNode.d.ts → shared/fields/richtext-editor/nodes/image-node.d.ts} +3 -3
  53. package/dist/admin/ui/{components/fields/TabsField.d.ts → shared/fields/tabs-field.d.ts} +1 -1
  54. package/dist/admin/ui/{components/fields/VirtualField.d.ts → shared/fields/virtual-field.d.ts} +1 -1
  55. package/dist/admin/ui/{components → shared}/toast.d.ts +1 -1
  56. package/dist/admin/webcomponent.js +34 -34
  57. package/dist/admin.css +1 -1
  58. package/dist/{chunk-5y0mkt7x.js → chunk-2abqb0h6.js} +2 -2
  59. package/dist/{chunk-m83ybzf8.js → chunk-hrxq1x98.js} +1 -1
  60. package/dist/{chunk-nch158fe.js → chunk-y3ehzvp4.js} +1 -1
  61. package/dist/{chunk-vmz9ncf1.js → chunk-yw9w63kr.js} +3 -3
  62. package/dist/cli/commands/init.d.ts +1 -0
  63. package/dist/cli/index.js +28 -3
  64. package/dist/db/better-sqlite.js +583 -9
  65. package/dist/db/bun-sqlite.js +590 -9
  66. package/dist/db/d1.js +605 -9
  67. package/dist/db/index.d.ts +0 -5
  68. package/dist/db/index.js +0 -35
  69. package/dist/db/postgres.js +613 -9
  70. package/dist/db/sqlite.js +598 -9
  71. package/dist/runtimes/bun.js +1 -1
  72. package/dist/runtimes/cloudflare-workers.js +1 -1
  73. package/dist/runtimes/next.js +1 -1
  74. package/dist/runtimes/node.js +1 -1
  75. package/dist/server.js +4 -4
  76. package/package.json +25 -7
  77. package/dist/admin/ui/components/Table.d.ts +0 -10
  78. package/dist/admin/ui/components/fields/BlocksField.d.ts +0 -17
  79. package/dist/admin/ui/components/fields/index.d.ts +0 -28
  80. package/dist/admin/ui/components/ui/breadcrumbs.d.ts +0 -7
  81. package/dist/admin/ui/components/ui/dialog.d.ts +0 -27
  82. package/dist/admin/ui/components/ui/index.d.ts +0 -17
  83. package/dist/admin/ui/components/ui/label.d.ts +0 -3
  84. package/dist/admin/ui/components/ui/select.d.ts +0 -37
  85. package/dist/admin/ui/components/ui/tabs.d.ts +0 -17
  86. package/dist/admin/ui/views/media-registry-view.d.ts +0 -7
  87. package/dist/chunk-5b9eqr34.js +0 -608
  88. package/dist/chunk-dz5bh1bd.js +0 -586
  89. package/dist/chunk-nz6xhtja.js +0 -601
  90. package/dist/chunk-qsefknd3.js +0 -593
  91. package/dist/chunk-tsmhn78f.js +0 -616
  92. /package/dist/admin/{stores → features/auth}/auth.d.ts +0 -0
  93. /package/dist/admin/{ui/views → features/auth}/login-view.d.ts +0 -0
  94. /package/dist/admin/{ui/components → features/collections}/data-detail-view.d.ts +0 -0
  95. /package/dist/admin/{ui/views → features/init}/init-view.d.ts +0 -0
  96. /package/dist/admin/{stores → features/media}/media.d.ts +0 -0
  97. /package/dist/admin/{stores → features/ui-shell}/column-visibility.d.ts +0 -0
  98. /package/dist/admin/{stores → features/ui-shell}/query.d.ts +0 -0
  99. /package/dist/admin/ui/{components/ui → core}/accordion.d.ts +0 -0
  100. /package/dist/admin/ui/{components/ui → core}/alert-dialog.d.ts +0 -0
  101. /package/dist/admin/ui/{components/ui → core}/separator.d.ts +0 -0
  102. /package/dist/admin/ui/{components/ui → core}/tooltip.d.ts +0 -0
  103. /package/dist/admin/ui/{components/ui → core}/utils.d.ts +0 -0
  104. /package/dist/admin/ui/{components → shared}/custom-alert.d.ts +0 -0
  105. /package/dist/admin/ui/{components/fields/DateField.d.ts → shared/fields/date-field.d.ts} +0 -0
  106. /package/dist/admin/ui/{components/fields/FieldLabel.d.ts → shared/fields/field-label.d.ts} +0 -0
  107. /package/dist/admin/ui/{components/fields/NumberField.d.ts → shared/fields/number-field.d.ts} +0 -0
  108. /package/dist/admin/ui/{components/fields/RadioField.d.ts → shared/fields/radio-field.d.ts} +0 -0
  109. /package/dist/admin/ui/{components/fields/richtext-editor/nodes/ImageComponent.d.ts → shared/fields/richtext-editor/nodes/image-component.d.ts} +0 -0
  110. /package/dist/admin/ui/{components/fields/richtext-editor/plugins/ComponentPickerPlugin.d.ts → shared/fields/richtext-editor/plugins/component-picker-plugin.d.ts} +0 -0
  111. /package/dist/admin/ui/{components/fields/richtext-editor/plugins/EditableSyncPlugin.d.ts → shared/fields/richtext-editor/plugins/editable-sync-plugin.d.ts} +0 -0
  112. /package/dist/admin/ui/{components/fields/richtext-editor/plugins/NotionToolbarPlugin.d.ts → shared/fields/richtext-editor/plugins/notion-toolbar-plugin.d.ts} +0 -0
  113. /package/dist/admin/ui/{components/fields/richtext-editor/plugins/SimpleToolbarPlugin.d.ts → shared/fields/richtext-editor/plugins/simple-toolbar-plugin.d.ts} +0 -0
  114. /package/dist/admin/ui/{components/fields/richtext-editor/plugins/ValueSyncPlugin.d.ts → shared/fields/richtext-editor/plugins/value-sync-plugin.d.ts} +0 -0
  115. /package/dist/admin/ui/{components/fields/RowField.d.ts → shared/fields/row-field.d.ts} +0 -0
  116. /package/dist/admin/ui/{components/fields/SelectField.d.ts → shared/fields/select-field.d.ts} +0 -0
  117. /package/dist/admin/ui/{components/fields/TextAreaField.d.ts → shared/fields/text-area-field.d.ts} +0 -0
  118. /package/dist/admin/ui/{components/fields/TextField.d.ts → shared/fields/text-field.d.ts} +0 -0
  119. /package/dist/admin/ui/{components → shared}/fields/utils.d.ts +0 -0
  120. /package/dist/admin/ui/{components → shared}/link.d.ts +0 -0
  121. /package/dist/admin/ui/{components → shared}/plugin-iframe.d.ts +0 -0
package/dist/db/d1.js CHANGED
@@ -1,14 +1,610 @@
1
1
  import {
2
- D1Adapter,
3
- createD1Adapter
4
- } from "../chunk-5b9eqr34.js";
5
- import"../chunk-re459gm9.js";
6
- import"../chunk-s8mqwnm1.js";
7
- import"../chunk-q5sb5dcr.js";
8
- import"../chunk-5xpf5jxd.js";
9
- import"../chunk-jq1drsen.js";
2
+ buildKyselyWhere,
3
+ flattenPayload,
4
+ pushSchema,
5
+ unflattenRow
6
+ } from "../chunk-re459gm9.js";
7
+ import {
8
+ requestContext
9
+ } from "../chunk-q5sb5dcr.js";
10
+ import {
11
+ flattenFields,
12
+ getRelationalFields,
13
+ toSnakeCase
14
+ } from "../chunk-5xpf5jxd.js";
15
+ import {
16
+ logger
17
+ } from "../chunk-jq1drsen.js";
10
18
  import"../chunk-h8v093av.js";
11
- import"../chunk-8sqjbsgt.js";
19
+ import {
20
+ BaseDatabaseAdapter
21
+ } from "../chunk-s8mqwnm1.js";
22
+ import {
23
+ __require
24
+ } from "../chunk-8sqjbsgt.js";
25
+
26
+ // src/db/d1.ts
27
+ import fs from "node:fs/promises";
28
+ import path from "node:path";
29
+ import { pathToFileURL } from "node:url";
30
+ import { CompiledQuery, FileMigrationProvider, Migrator } from "kysely";
31
+ class D1Adapter extends BaseDatabaseAdapter {
32
+ name = "d1";
33
+ _rawDb;
34
+ _db = null;
35
+ _collections = [];
36
+ _globals = [];
37
+ push;
38
+ migrationDir;
39
+ pushDestructive;
40
+ get raw() {
41
+ return this._rawDb;
42
+ }
43
+ get db() {
44
+ if (!this._db)
45
+ throw new Error("Database not connected. Call connect() first.");
46
+ return this._db;
47
+ }
48
+ constructor(db, options) {
49
+ super();
50
+ this._rawDb = db;
51
+ const isDev = typeof process !== "undefined" && true;
52
+ this.push = options?.push ?? isDev;
53
+ this.pushDestructive = options?.pushDestructive ?? false;
54
+ this.migrationDir = options?.migrationDir ?? "./migrations";
55
+ }
56
+ async connect() {
57
+ if (this._db)
58
+ return;
59
+ const { D1Dialect } = await import("kysely-d1");
60
+ const { createOpacaKysely } = await import("../chunk-gzbz5jwy.js");
61
+ this._db = createOpacaKysely({
62
+ dialect: new D1Dialect({ database: this._rawDb }),
63
+ config: {
64
+ collections: this._collections,
65
+ globals: this._globals,
66
+ db: { name: "d1" }
67
+ }
68
+ });
69
+ }
70
+ async disconnect() {
71
+ if (this._db)
72
+ await this.db.destroy();
73
+ }
74
+ async unsafe(query, params) {
75
+ const compiled = CompiledQuery.raw(query, params || []);
76
+ const result = await this.db.executeQuery(compiled);
77
+ return result.rows;
78
+ }
79
+ async count(collection, query) {
80
+ const tableName = toSnakeCase(collection);
81
+ let qb = this.db.selectFrom(tableName).select((eb) => eb.fn.count("id").as("count"));
82
+ if (query && Object.keys(query).length > 0) {
83
+ qb = qb.where((eb) => buildKyselyWhere(eb, query) || eb.val(true));
84
+ }
85
+ const result = await qb.executeTakeFirst();
86
+ return Number(result?.count || 0);
87
+ }
88
+ async create(collection, data) {
89
+ const tableName = toSnakeCase(collection);
90
+ const colDef = this._collections.find((c) => c.slug === collection);
91
+ const jsonFields = colDef?.fields.filter((f) => f.name && (["richtext", "json", "file"].includes(f.type) || f.localized)).map((f) => f.name) || [];
92
+ const flatData = flattenPayload(data, "", jsonFields);
93
+ const relationalFields = getRelationalFields(colDef?.fields || []);
94
+ const hasManyData = {};
95
+ const blocksData = {};
96
+ for (const field of relationalFields) {
97
+ const key = field.name;
98
+ if (Array.isArray(flatData[key])) {
99
+ if (field.type === "relationship" && "hasMany" in field && field.hasMany) {
100
+ hasManyData[key] = flatData[key];
101
+ } else if (field.type === "blocks") {
102
+ blocksData[key] = flatData[key];
103
+ }
104
+ delete flatData[key];
105
+ }
106
+ }
107
+ if (!flatData.id)
108
+ flatData.id = crypto.randomUUID();
109
+ const dbFields = flattenFields(colDef?.fields || []);
110
+ const validCols = new Set(dbFields.map((f) => toSnakeCase(f.name)));
111
+ validCols.add("id");
112
+ validCols.add(toSnakeCase("createdAt"));
113
+ validCols.add(toSnakeCase("updatedAt"));
114
+ const filteredData = {};
115
+ for (const col of Object.keys(flatData)) {
116
+ if (validCols.has(col)) {
117
+ filteredData[col] = flatData[col];
118
+ }
119
+ }
120
+ try {
121
+ await this.db.insertInto(tableName).values(filteredData).execute();
122
+ } catch (e) {
123
+ logger.error(`[D1] Create failed in ${collection}: ${e.message}`);
124
+ throw e;
125
+ }
126
+ for (const [key, values] of Object.entries(hasManyData)) {
127
+ const joinTableName = `${tableName}_${toSnakeCase(key)}_relations`.toLowerCase();
128
+ if (values.length > 0) {
129
+ const joinData = values.map((val, idx) => {
130
+ const tId = typeof val === "object" ? val.id : val;
131
+ return { id: crypto.randomUUID(), source_id: flatData.id, target_id: tId, order: idx };
132
+ });
133
+ await this.db.insertInto(joinTableName).values(joinData).execute();
134
+ }
135
+ }
136
+ for (const [key, blocks] of Object.entries(blocksData)) {
137
+ for (let i = 0;i < blocks.length; i++) {
138
+ const block = blocks[i];
139
+ if (!block.blockType)
140
+ continue;
141
+ const blockTableName = `${tableName}_${toSnakeCase(key)}_${toSnakeCase(block.blockType)}`.toLowerCase();
142
+ const bId = block.id || crypto.randomUUID();
143
+ const blockDef = relationalFields.find((f) => f.name === key && f.type === "blocks");
144
+ const blockConfig = blockDef?.blocks?.find((b) => b.slug === block.blockType);
145
+ const blockJsonFields = blockConfig?.fields.filter((f) => ["richtext", "json", "file"].includes(f.type)).map((f) => toSnakeCase(f.name)) || [];
146
+ const blockFlatData = flattenPayload({ ...block, id: bId }, "", blockJsonFields);
147
+ for (const f of blockJsonFields) {
148
+ if (blockFlatData[f] && typeof blockFlatData[f] === "object") {
149
+ blockFlatData[f] = JSON.stringify(blockFlatData[f]);
150
+ }
151
+ }
152
+ delete blockFlatData.blockType;
153
+ const blockData = {
154
+ ...blockFlatData,
155
+ _parent_id: flatData.id,
156
+ _order: i,
157
+ block_type: block.blockType
158
+ };
159
+ await this.db.insertInto(blockTableName).values(blockData).execute();
160
+ }
161
+ }
162
+ return this.findOne(collection, { id: flatData.id }, this.db);
163
+ }
164
+ async findOne(collection, query, tx) {
165
+ const tableName = toSnakeCase(collection);
166
+ const executor = tx || this.db;
167
+ let qb = executor.selectFrom(tableName).selectAll();
168
+ if (query && Object.keys(query).length > 0) {
169
+ qb = qb.where((eb) => buildKyselyWhere(eb, query) || eb.val(true));
170
+ }
171
+ const row = await qb.executeTakeFirst();
172
+ if (!row)
173
+ return null;
174
+ const unflattened = unflattenRow(row);
175
+ const colDef = this._collections.find((c) => c.slug === collection);
176
+ if (colDef) {
177
+ const relationalFields = getRelationalFields(colDef.fields);
178
+ for (const field of relationalFields) {
179
+ if (!field.name)
180
+ continue;
181
+ const snakeName = toSnakeCase(field.name);
182
+ if (field.type === "relationship" && "hasMany" in field && field.hasMany) {
183
+ const joinTableName = `${tableName}_${snakeName}_relations`.toLowerCase();
184
+ try {
185
+ const relations = await executor.selectFrom(joinTableName).selectAll().where("source_id", "=", row.id).orderBy("order", "asc").execute();
186
+ const parts = field.name.split("__");
187
+ let current = unflattened;
188
+ for (let i = 0;i < parts.length - 1; i++) {
189
+ if (!current[parts[i]])
190
+ current[parts[i]] = {};
191
+ current = current[parts[i]];
192
+ }
193
+ current[parts[parts.length - 1]] = relations.map((r) => r.target_id);
194
+ } catch (e) {}
195
+ } else if (field.type === "blocks" && "blocks" in field && field.blocks) {
196
+ const blockData = [];
197
+ for (const b of field.blocks) {
198
+ const blockTableName = `${tableName}_${snakeName}_${toSnakeCase(b.slug)}`.toLowerCase();
199
+ try {
200
+ const blocks = await executor.selectFrom(blockTableName).selectAll().where("_parent_id", "=", row.id).execute();
201
+ for (const blk of blocks) {
202
+ const uf = unflattenRow(blk);
203
+ uf.blockType = blk.block_type;
204
+ blockData.push(uf);
205
+ }
206
+ } catch (e) {}
207
+ }
208
+ blockData.sort((a, b) => a._order - b._order);
209
+ blockData.forEach((b) => {
210
+ delete b._order;
211
+ delete b._parent_id;
212
+ });
213
+ const parts = field.name.split("__");
214
+ let current = unflattened;
215
+ for (let i = 0;i < parts.length - 1; i++) {
216
+ if (!current[parts[i]])
217
+ current[parts[i]] = {};
218
+ current = current[parts[i]];
219
+ }
220
+ current[parts[parts.length - 1]] = blockData;
221
+ }
222
+ }
223
+ }
224
+ return unflattened;
225
+ }
226
+ async find(collection, query, options) {
227
+ const page = options?.page || 1;
228
+ const limit = options?.limit || 10;
229
+ const offset = (page - 1) * limit;
230
+ const cursorColumn = options?.cursorColumn || "id";
231
+ const total = await this.count(collection, query);
232
+ const tableName = toSnakeCase(collection);
233
+ let qb = this.db.selectFrom(tableName).selectAll().limit(limit);
234
+ if (options?.after) {
235
+ qb = qb.where(cursorColumn, ">", options.after);
236
+ } else if (options?.before) {
237
+ qb = qb.where(cursorColumn, "<", options.before);
238
+ } else {
239
+ qb = qb.offset(offset);
240
+ }
241
+ if (query && Object.keys(query).length > 0) {
242
+ qb = qb.where((eb) => buildKyselyWhere(eb, query) || eb.val(true));
243
+ }
244
+ if (options?.sort) {
245
+ const [col, dir] = (options.sort ?? "").split(":");
246
+ if (col) {
247
+ qb = qb.orderBy(col, dir === "desc" ? "desc" : "asc");
248
+ }
249
+ } else {
250
+ qb = qb.orderBy(cursorColumn, "desc");
251
+ }
252
+ const rows = await qb.execute();
253
+ if (rows.length === 0) {
254
+ const totalPages2 = Math.ceil(total / limit);
255
+ const afterAnchor = options?.after;
256
+ const beforeAnchor = options?.before;
257
+ return {
258
+ docs: [],
259
+ totalDocs: total,
260
+ limit,
261
+ totalPages: totalPages2,
262
+ page,
263
+ pagingCounter: offset + 1,
264
+ hasNextPage: false,
265
+ hasPrevPage: !!afterAnchor || page > 1,
266
+ prevPage: null,
267
+ nextPage: null,
268
+ nextCursor: null,
269
+ prevCursor: afterAnchor ? afterAnchor : null
270
+ };
271
+ }
272
+ const rowIds = rows.map((r) => r.id);
273
+ const docs = rows.map((r) => unflattenRow(r));
274
+ const colDef = this._collections.find((c) => c.slug === collection);
275
+ if (colDef) {
276
+ const relationalFields = getRelationalFields(colDef.fields);
277
+ for (const field of relationalFields) {
278
+ if (!field.name)
279
+ continue;
280
+ const snakeName = toSnakeCase(field.name);
281
+ if (field.type === "relationship" && "hasMany" in field && field.hasMany) {
282
+ const joinTableName = `${toSnakeCase(collection)}_${snakeName}_relations`.toLowerCase();
283
+ try {
284
+ const allRelations = await this.db.selectFrom(joinTableName).selectAll().where("source_id", "in", rowIds).orderBy("order", "asc").execute();
285
+ const relationsBySource = allRelations.reduce((acc, r) => {
286
+ if (!acc[r.source_id])
287
+ acc[r.source_id] = [];
288
+ acc[r.source_id].push(r.target_id);
289
+ return acc;
290
+ }, {});
291
+ const parts = field.name.split("__");
292
+ for (let docIdx = 0;docIdx < docs.length; docIdx++) {
293
+ const rowId = rowIds[docIdx];
294
+ let current = docs[docIdx];
295
+ for (let i = 0;i < parts.length - 1; i++) {
296
+ if (!current[parts[i]])
297
+ current[parts[i]] = {};
298
+ current = current[parts[i]];
299
+ }
300
+ current[parts[parts.length - 1]] = relationsBySource[rowId] || [];
301
+ }
302
+ } catch (e) {}
303
+ } else if (field.type === "blocks" && field.blocks) {
304
+ const blocksBySource = {};
305
+ for (const b of field.blocks) {
306
+ const blockTableName = `${collection}_${snakeName}_${toSnakeCase(b.slug)}`.toLowerCase();
307
+ try {
308
+ const allBlocks = await this.db.selectFrom(blockTableName).selectAll().where("_parent_id", "in", rowIds).execute();
309
+ for (const blk of allBlocks) {
310
+ const uf = unflattenRow(blk);
311
+ uf.blockType = blk.block_type;
312
+ if (!blocksBySource[blk._parent_id])
313
+ blocksBySource[blk._parent_id] = [];
314
+ blocksBySource[blk._parent_id].push(uf);
315
+ }
316
+ } catch (e) {}
317
+ }
318
+ const parts = field.name.split("__");
319
+ for (let docIdx = 0;docIdx < docs.length; docIdx++) {
320
+ const rowId = rowIds[docIdx];
321
+ const blockData = blocksBySource[rowId] || [];
322
+ blockData.sort((a, b) => a._order - b._order);
323
+ blockData.forEach((b) => {
324
+ delete b._order;
325
+ delete b._parentId;
326
+ });
327
+ let current = docs[docIdx];
328
+ for (let i = 0;i < parts.length - 1; i++) {
329
+ if (!current[parts[i]])
330
+ current[parts[i]] = {};
331
+ current = current[parts[i]];
332
+ }
333
+ current[parts[parts.length - 1]] = blockData;
334
+ }
335
+ }
336
+ }
337
+ }
338
+ const totalPages = Math.ceil(total / limit);
339
+ const hasNextPage = page * limit < total;
340
+ return {
341
+ docs: docs.filter(Boolean),
342
+ totalDocs: total,
343
+ limit,
344
+ totalPages,
345
+ page,
346
+ pagingCounter: offset + 1,
347
+ hasNextPage,
348
+ hasPrevPage: page > 1 || !!options?.after || !!options?.before,
349
+ prevPage: page > 1 ? page - 1 : null,
350
+ nextPage: page < totalPages ? page + 1 : null,
351
+ nextCursor: docs.length > 0 && hasNextPage ? docs[docs.length - 1][cursorColumn] : null,
352
+ prevCursor: docs.length > 0 && (page > 1 || !!options?.after || !!options?.before) ? docs[0][cursorColumn] : null
353
+ };
354
+ }
355
+ async update(collection, query, data) {
356
+ const tableName = toSnakeCase(collection);
357
+ let normalizedQuery = query;
358
+ if (typeof query !== "object" || query === null) {
359
+ normalizedQuery = { id: query };
360
+ }
361
+ const current = await this.findOne(collection, normalizedQuery, this.db);
362
+ if (!current)
363
+ throw new Error("Document not found");
364
+ const store = requestContext.getStore();
365
+ if (store)
366
+ store.previousData = current;
367
+ const colDef = this._collections.find((c) => c.slug === collection);
368
+ const jsonFields = colDef?.fields.filter((f) => f.name && (["richtext", "json", "file"].includes(f.type) || f.localized)).map((f) => f.name) || [];
369
+ const flatData = flattenPayload(data, "", jsonFields);
370
+ const relationalFields = getRelationalFields(colDef?.fields || []);
371
+ const hasManyData = {};
372
+ const blocksData = {};
373
+ for (const field of relationalFields) {
374
+ const key = field.name;
375
+ if (Array.isArray(flatData[key])) {
376
+ if (field.type === "relationship" && "hasMany" in field && field.hasMany) {
377
+ hasManyData[key] = flatData[key];
378
+ } else if (field.type === "blocks") {
379
+ blocksData[key] = flatData[key];
380
+ }
381
+ delete flatData[key];
382
+ }
383
+ }
384
+ if (Object.keys(flatData).length > 0) {
385
+ const dbFields = flattenFields(colDef?.fields || []);
386
+ const validCols = new Set(dbFields.map((f) => toSnakeCase(f.name)));
387
+ validCols.add("id");
388
+ const filteredData = {};
389
+ for (const col of Object.keys(flatData)) {
390
+ if (validCols.has(col)) {
391
+ filteredData[col] = flatData[col];
392
+ }
393
+ }
394
+ try {
395
+ await this.db.updateTable(tableName).set(filteredData).where("id", "=", current.id).execute();
396
+ } catch (e) {
397
+ logger.error(`[D1] Update failed in ${collection}: ${e.message}`);
398
+ throw e;
399
+ }
400
+ }
401
+ for (const [key, values] of Object.entries(hasManyData)) {
402
+ const joinTableName = `${tableName}_${toSnakeCase(key)}_relations`.toLowerCase();
403
+ await this.db.deleteFrom(joinTableName).where("source_id", "=", current.id).execute();
404
+ if (values.length > 0) {
405
+ const joinData = values.map((val, idx) => {
406
+ const tId = typeof val === "object" ? val.id : val;
407
+ return { id: crypto.randomUUID(), source_id: current.id, target_id: tId, order: idx };
408
+ });
409
+ await this.db.insertInto(joinTableName).values(joinData).execute();
410
+ }
411
+ }
412
+ for (const [key, blocks] of Object.entries(blocksData)) {
413
+ const blockDef = relationalFields.find((f) => f.name === key && f.type === "blocks");
414
+ if (blockDef && "blocks" in blockDef && blockDef.blocks) {
415
+ await Promise.all(blockDef.blocks.map(async (b) => {
416
+ const blockTableName = `${tableName}_${toSnakeCase(key)}_${toSnakeCase(b.slug)}`.toLowerCase();
417
+ try {
418
+ await this.db.deleteFrom(blockTableName).where("_parent_id", "=", current.id).execute();
419
+ } catch (e) {}
420
+ }));
421
+ }
422
+ for (let i = 0;i < blocks.length; i++) {
423
+ const block = blocks[i];
424
+ if (!block.blockType)
425
+ continue;
426
+ const blockTableName = `${tableName}_${toSnakeCase(key)}_${toSnakeCase(block.blockType)}`.toLowerCase();
427
+ const bId = block.id || crypto.randomUUID();
428
+ const blockConfig = blockDef?.blocks?.find((b) => b.slug === block.blockType);
429
+ const blockJsonFields = blockConfig?.fields.filter((f) => ["richtext", "json", "file"].includes(f.type)).map((f) => toSnakeCase(f.name)) || [];
430
+ const blockFlatData = flattenPayload({ ...block, id: bId }, "", blockJsonFields);
431
+ for (const f of blockJsonFields) {
432
+ if (blockFlatData[f] && typeof blockFlatData[f] === "object") {
433
+ blockFlatData[f] = JSON.stringify(blockFlatData[f]);
434
+ }
435
+ }
436
+ delete blockFlatData.blockType;
437
+ const blockData = {
438
+ ...blockFlatData,
439
+ _parent_id: current.id,
440
+ _order: i,
441
+ block_type: block.blockType
442
+ };
443
+ await this.db.insertInto(blockTableName).values(blockData).execute();
444
+ }
445
+ }
446
+ return this.findOne(collection, { id: current.id }, this.db);
447
+ }
448
+ async updateMany(collection, query, data) {
449
+ const tableName = toSnakeCase(collection);
450
+ let qb = this.db.updateTable(tableName);
451
+ if (query && Object.keys(query).length > 0) {
452
+ qb = qb.where((eb) => buildKyselyWhere(eb, query) || eb.val(true));
453
+ }
454
+ const colDef = this._collections.find((c) => c.slug === collection);
455
+ const jsonFields = colDef?.fields.filter((f) => f.name && (["richtext", "json", "file"].includes(f.type) || f.localized)).map((f) => f.name) || [];
456
+ const flatData = flattenPayload(data, "", jsonFields);
457
+ for (const key in flatData) {
458
+ if (Array.isArray(flatData[key])) {
459
+ delete flatData[key];
460
+ }
461
+ }
462
+ if (Object.keys(flatData).length > 0) {
463
+ const dbFields = flattenFields(colDef?.fields || []);
464
+ const validCols = new Set(dbFields.map((f) => toSnakeCase(f.name)));
465
+ validCols.add("id");
466
+ const filteredData = {};
467
+ for (const col of Object.keys(flatData)) {
468
+ if (validCols.has(col)) {
469
+ filteredData[col] = flatData[col];
470
+ }
471
+ }
472
+ logger.debug(`[D1] Bulk updating in ${collection}...`);
473
+ try {
474
+ const result = await qb.set(filteredData).executeTakeFirst();
475
+ return Number(result.numUpdatedRows || 0);
476
+ } catch (e) {
477
+ logger.error(`[D1] Bulk update failed in ${collection}: ${e.message}`);
478
+ throw e;
479
+ }
480
+ }
481
+ return 0;
482
+ }
483
+ async delete(collection, query) {
484
+ const tableName = toSnakeCase(collection);
485
+ let normalizedQuery = query;
486
+ if (typeof query !== "object" || query === null) {
487
+ normalizedQuery = { id: query };
488
+ }
489
+ const current = await this.findOne(collection, normalizedQuery);
490
+ if (!current)
491
+ return false;
492
+ const colDef = this._collections.find((c) => c.slug === collection);
493
+ if (colDef) {
494
+ const relationalFields = getRelationalFields(colDef.fields);
495
+ for (const field of relationalFields) {
496
+ if (!field.name)
497
+ continue;
498
+ const snakeName = toSnakeCase(field.name);
499
+ if (field.type === "relationship" && "hasMany" in field && field.hasMany) {
500
+ const joinTableName = `${tableName}_${snakeName}_relations`.toLowerCase();
501
+ try {
502
+ await this.db.deleteFrom(joinTableName).where("source_id", "=", current.id).execute();
503
+ } catch (e) {}
504
+ } else if (field.type === "blocks" && "blocks" in field && field.blocks) {
505
+ await Promise.all(field.blocks.map(async (b) => {
506
+ const blockTableName = `${tableName}_${snakeName}_${toSnakeCase(b.slug)}`.toLowerCase();
507
+ try {
508
+ await this.db.deleteFrom(blockTableName).where("_parent_id", "=", current.id).execute();
509
+ } catch (e) {}
510
+ }));
511
+ }
512
+ }
513
+ }
514
+ await this.db.deleteFrom(tableName).where("id", "=", current.id).execute();
515
+ return true;
516
+ }
517
+ async deleteMany(collection, query) {
518
+ const tableName = toSnakeCase(collection);
519
+ let selectQb = this.db.selectFrom(tableName).select("id");
520
+ if (query && Object.keys(query).length > 0) {
521
+ selectQb = selectQb.where((eb) => buildKyselyWhere(eb, query) || eb.val(true));
522
+ }
523
+ const rowsToDelete = await selectQb.execute();
524
+ const idsToDelete = rowsToDelete.map((row) => row.id);
525
+ if (idsToDelete.length === 0)
526
+ return 0;
527
+ const colDef = this._collections.find((c) => c.slug === collection);
528
+ if (colDef) {
529
+ const relationalFields = getRelationalFields(colDef.fields);
530
+ for (const field of relationalFields) {
531
+ if (!field.name)
532
+ continue;
533
+ const snakeName = toSnakeCase(field.name);
534
+ if (field.type === "relationship" && "hasMany" in field && field.hasMany) {
535
+ const joinTableName = `${tableName}_${snakeName}_relations`.toLowerCase();
536
+ try {
537
+ await this.db.deleteFrom(joinTableName).where("source_id", "in", idsToDelete).execute();
538
+ } catch (e) {}
539
+ } else if (field.type === "blocks" && "blocks" in field && field.blocks) {
540
+ await Promise.all(field.blocks.map(async (b) => {
541
+ const blockTableName = `${tableName}_${snakeName}_${toSnakeCase(b.slug)}`.toLowerCase();
542
+ try {
543
+ await this.db.deleteFrom(blockTableName).where("_parent_id", "in", idsToDelete).execute();
544
+ } catch (e) {}
545
+ }));
546
+ }
547
+ }
548
+ }
549
+ const result = await this.db.deleteFrom(tableName).where("id", "in", idsToDelete).executeTakeFirst();
550
+ return Number(result.numDeletedRows || 0);
551
+ }
552
+ async findGlobal(slug) {
553
+ const tableName = toSnakeCase(slug);
554
+ const row = await this.db.selectFrom(tableName).selectAll().limit(1).executeTakeFirst();
555
+ return row ? unflattenRow(row) : null;
556
+ }
557
+ async updateGlobal(slug, data) {
558
+ const tableName = toSnakeCase(slug);
559
+ const existing = await this.findGlobal(slug);
560
+ const flatData = flattenPayload(data);
561
+ const globalDef = this._globals.find((g) => g.slug === slug);
562
+ const now = new Date().toISOString();
563
+ flatData[toSnakeCase("updatedAt")] = now;
564
+ if (!existing) {
565
+ if (!flatData.id)
566
+ flatData.id = "global";
567
+ flatData[toSnakeCase("createdAt")] = now;
568
+ await this.db.insertInto(tableName).values(flatData).execute();
569
+ } else {
570
+ await this.db.updateTable(tableName).set(flatData).where("id", "=", existing.id).execute();
571
+ }
572
+ return this.findGlobal(slug);
573
+ }
574
+ async runMigrations() {
575
+ const migrator = new Migrator({
576
+ db: this.db,
577
+ provider: new FileMigrationProvider({
578
+ fs,
579
+ path,
580
+ migrationFolder: pathToFileURL(path.resolve(process.cwd(), this.migrationDir)).href
581
+ })
582
+ });
583
+ const { error, results } = await migrator.migrateToLatest();
584
+ results?.forEach((it) => {
585
+ if (it.status === "Success") {
586
+ logger.success(`\uD83D\uDE80 Migration "${it.migrationName}" was executed successfully`);
587
+ } else if (it.status === "Error") {
588
+ logger.error(`❌ Migration "${it.migrationName}" failed`);
589
+ }
590
+ });
591
+ if (error) {
592
+ throw error;
593
+ }
594
+ }
595
+ async migrate(collections, globals = []) {
596
+ this._collections = collections;
597
+ this._globals = globals;
598
+ if (this.push) {
599
+ await pushSchema(this.db, "d1", collections, globals, {
600
+ pushDestructive: this.pushDestructive
601
+ });
602
+ }
603
+ }
604
+ }
605
+ function createD1Adapter(db, options) {
606
+ return new D1Adapter(db, options);
607
+ }
12
608
  export {
13
609
  createD1Adapter,
14
610
  D1Adapter
@@ -2,8 +2,3 @@ import type { Kysely } from "kysely";
2
2
  export { sql } from "kysely";
3
3
  export type OpacaMigrationDb = Kysely<any>;
4
4
  export * from "./adapter";
5
- export * from "./better-sqlite";
6
- export * from "./bun-sqlite";
7
- export * from "./d1";
8
- export * from "./postgres";
9
- export * from "./sqlite";
package/dist/db/index.js CHANGED
@@ -1,43 +1,8 @@
1
- import {
2
- D1Adapter,
3
- createD1Adapter
4
- } from "../chunk-5b9eqr34.js";
5
- import {
6
- PostgresAdapter,
7
- createPostgresAdapter
8
- } from "../chunk-tsmhn78f.js";
9
- import {
10
- SQLiteAdapter,
11
- createSQLiteAdapter
12
- } from "../chunk-nz6xhtja.js";
13
- import {
14
- BunSQLiteAdapter,
15
- createBunSQLiteAdapter
16
- } from "../chunk-qsefknd3.js";
17
- import {
18
- BetterSQLiteAdapter,
19
- createBetterSQLiteAdapter
20
- } from "../chunk-dz5bh1bd.js";
21
- import"../chunk-re459gm9.js";
22
1
  import {
23
2
  BaseDatabaseAdapter
24
3
  } from "../chunk-s8mqwnm1.js";
25
- import"../chunk-q5sb5dcr.js";
26
- import"../chunk-5xpf5jxd.js";
27
- import"../chunk-jq1drsen.js";
28
- import"../chunk-h8v093av.js";
29
4
  import"../chunk-8sqjbsgt.js";
30
5
  export {
31
6
  sql,
32
- createSQLiteAdapter,
33
- createPostgresAdapter,
34
- createD1Adapter,
35
- createBunSQLiteAdapter,
36
- createBetterSQLiteAdapter,
37
- SQLiteAdapter,
38
- PostgresAdapter,
39
- D1Adapter,
40
- BunSQLiteAdapter,
41
- BetterSQLiteAdapter,
42
7
  BaseDatabaseAdapter
43
8
  };