opacacms 0.2.1 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -22
- package/dist/admin/auth-client.d.ts +39 -39
- package/dist/admin/index.d.ts +2 -2
- package/dist/admin/index.js +15 -10520
- package/dist/admin/plugin-client.d.ts +65 -0
- package/dist/admin/react.d.ts +2 -2
- package/dist/admin/react.js +34 -4
- package/dist/admin/stores/ui.d.ts +19 -4
- package/dist/admin/ui/components/PluginSettingsForm.d.ts +2 -2
- package/dist/admin/ui/components/custom-alert.d.ts +7 -0
- package/dist/admin/ui/components/{DetailSheet.d.ts → detail-sheet.d.ts} +1 -2
- package/dist/admin/ui/components/fields/FieldLabel.d.ts +1 -1
- package/dist/admin/ui/components/fields/RelationshipField.d.ts +1 -1
- package/dist/admin/ui/components/media/AssetManagerModal.d.ts +2 -2
- package/dist/admin/ui/components/plugin-iframe.d.ts +7 -0
- package/dist/admin/ui/components/ui/accordion.d.ts +17 -7
- package/dist/admin/ui/components/ui/alert-dialog.d.ts +16 -12
- package/dist/admin/ui/components/ui/button.d.ts +11 -7
- package/dist/admin/ui/components/ui/relationship.d.ts +1 -1
- package/dist/admin/ui/components/ui/sheet.d.ts +14 -27
- package/dist/admin/ui/components/ui/tooltip.d.ts +7 -0
- package/dist/admin/ui/components/versions-sheet.d.ts +4 -5
- package/dist/admin/ui/views/collection-list-view.d.ts +1 -1
- package/dist/admin/ui/views/dashboard-view.d.ts +1 -1
- package/dist/admin/ui/views/media-registry-view.d.ts +3 -3
- package/dist/admin/ui/views/settings-view.d.ts +2 -2
- package/dist/admin/vue.js +27 -4
- package/dist/admin/webcomponent.js +66 -16
- package/dist/admin.css +1 -1
- package/dist/auth/index.d.ts +43 -43
- package/dist/{chunk-7y1nbmw6.js → chunk-1bd7fz7n.js} +32 -2
- package/dist/chunk-1qm0m8r8.js +413 -0
- package/dist/chunk-2k3ysje3.js +31 -0
- package/dist/{chunk-jdfw4v3r.js → chunk-3j9zjfmn.js} +95 -30
- package/dist/{chunk-byq8g0rd.js → chunk-48ywpd0a.js} +16 -22
- package/dist/{chunk-tfnaf41w.js → chunk-5422w4eq.js} +41 -25
- package/dist/chunk-56n342hs.js +95 -0
- package/dist/chunk-5b8r0v8c.js +47 -0
- package/dist/chunk-63yg00vx.js +263 -0
- package/dist/{chunk-8sqjbsgt.js → chunk-6bywt602.js} +26 -1
- package/dist/{chunk-v9z61v3g.js → chunk-6qs0g65f.js} +43 -3
- package/dist/chunk-7rr5p01g.js +581 -0
- package/dist/{chunk-2es275xs.js → chunk-941zxavt.js} +867 -322
- package/dist/{chunk-51z3x7kq.js → chunk-a3qae86h.js} +1 -1
- package/dist/{chunk-3rdhbedb.js → chunk-adq2b75c.js} +2 -2
- package/dist/chunk-d0tb1xjw.js +93 -0
- package/dist/chunk-d7cgd6vn.js +318 -0
- package/dist/{chunk-6d1vdfwa.js → chunk-e0g6gn7n.js} +54 -75
- package/dist/chunk-ec4jhybj.js +1137 -0
- package/dist/chunk-fatyf6f7.js +221 -0
- package/dist/{chunk-526a3gqx.js → chunk-fnsf1dfm.js} +1 -1
- package/dist/chunk-g9bxb6h0.js +205 -0
- package/dist/chunk-gyaf5kgf.js +10 -0
- package/dist/{chunk-9kxpbcb1.js → chunk-h6dhexzr.js} +16 -7
- package/dist/{chunk-dykn5hr6.js → chunk-j8js1y0h.js} +31 -74
- package/dist/{chunk-t0zg026p.js → chunk-jq1drsen.js} +12 -1
- package/dist/{chunk-b3kr8w41.js → chunk-m24yqkeq.js} +38 -26
- package/dist/chunk-m5ems3hh.js +410 -0
- package/dist/{chunk-8scgdznr.js → chunk-m83ybzf8.js} +15 -18
- package/dist/chunk-majsbncm.js +98 -0
- package/dist/chunk-mp2gt9yh.js +237 -0
- package/dist/chunk-n1twhqmf.js +54 -0
- package/dist/{chunk-bygjkgrx.js → chunk-naqcqj8n.js} +57 -80
- package/dist/chunk-q5sb5dcr.js +15 -0
- package/dist/{chunk-06ks4ggh.js → chunk-qhdsjek6.js} +49 -89
- package/dist/{chunk-n133qpsm.js → chunk-qsh2nqz3.js} +50 -81
- package/dist/chunk-r0ms5tk1.js +76 -0
- package/dist/chunk-rwqwsanx.js +75 -0
- package/dist/chunk-sqsfk9p4.js +700 -0
- package/dist/{chunk-5gvbp2qa.js → chunk-x7bnzswh.js} +25 -18
- package/dist/cli/commands/dev.d.ts +8 -0
- package/dist/cli/commands/doctor.d.ts +8 -0
- package/dist/cli/commands/generate.d.ts +26 -0
- package/dist/cli/commands/init.d.ts +13 -1
- package/dist/cli/commands/migrate.d.ts +33 -0
- package/dist/cli/commands/plugin.d.ts +13 -0
- package/dist/cli/commands/seed.d.ts +21 -0
- package/dist/cli/{commands/migrate-commands.d.ts → core/migrations/migrate-logic.d.ts} +2 -2
- package/dist/cli/core/migrations/schema-diff-engine.d.ts +12 -0
- package/dist/cli/core/migrations/schema-diff.d.ts +11 -0
- package/dist/cli/{seeding.d.ts → core/seeding/auto-seed.d.ts} +7 -4
- package/dist/cli/core/seeding/seed-logic.d.ts +2 -0
- package/dist/cli/index.d.ts +4 -0
- package/dist/cli/index.js +6 -170
- package/dist/client/RichText.d.ts +5 -0
- package/dist/client/rich-text-utils.d.ts +5 -0
- package/dist/client.js +3 -2
- package/dist/config.d.ts +3 -3
- package/dist/db/better-sqlite.d.ts +2 -3
- package/dist/db/better-sqlite.js +6 -5
- package/dist/db/bun-sqlite.d.ts +2 -3
- package/dist/db/bun-sqlite.js +6 -5
- package/dist/db/d1.d.ts +13 -7
- package/dist/db/d1.js +6 -5
- package/dist/db/index.d.ts +2 -2
- package/dist/db/index.js +10 -12
- package/dist/db/kysely/factory.d.ts +29 -0
- package/dist/db/kysely/plugins/audit-logging.d.ts +48 -0
- package/dist/db/kysely/plugins/auto-timestamps.d.ts +38 -0
- package/dist/db/kysely/plugins/cursor-pagination.d.ts +42 -0
- package/dist/db/kysely/plugins/deadlock-handler.d.ts +47 -0
- package/dist/db/kysely/plugins/draft-swapper.d.ts +33 -0
- package/dist/db/kysely/plugins/field-masking.d.ts +45 -0
- package/dist/db/kysely/plugins/fts-normalizer.d.ts +38 -0
- package/dist/db/kysely/plugins/i18n-fallback.d.ts +48 -0
- package/dist/db/kysely/plugins/id-generation.d.ts +42 -0
- package/dist/db/kysely/plugins/index.d.ts +16 -0
- package/dist/db/kysely/plugins/json-flattener.d.ts +38 -0
- package/dist/db/kysely/plugins/relationship-preloading.d.ts +39 -0
- package/dist/db/kysely/plugins/slug-generation.d.ts +37 -0
- package/dist/db/kysely/plugins/soft-delete.d.ts +42 -0
- package/dist/db/kysely/plugins/tree-resolver.d.ts +39 -0
- package/dist/db/kysely/plugins/virtual-field-resolver.d.ts +54 -0
- package/dist/db/kysely/plugins/zod-coercion.d.ts +34 -0
- package/dist/db/kysely/snapshot/snapshot-manager.d.ts +18 -0
- package/dist/db/postgres.d.ts +2 -2
- package/dist/db/postgres.js +6 -5
- package/dist/db/sqlite.d.ts +2 -3
- package/dist/db/sqlite.js +6 -5
- package/dist/index.d.ts +3 -0
- package/dist/index.js +161 -7
- package/dist/runtimes/bun.js +9 -6
- package/dist/runtimes/cloudflare-workers.d.ts +3 -1
- package/dist/runtimes/cloudflare-workers.js +36 -7
- package/dist/runtimes/next.js +8 -5
- package/dist/runtimes/node.js +9 -6
- package/dist/schema/collection.d.ts +116 -70
- package/dist/schema/compiler.d.ts +6 -0
- package/dist/schema/global.d.ts +38 -71
- package/dist/schema/index.d.ts +5 -4
- package/dist/schema/index.js +35 -550
- package/dist/schema/zod.d.ts +564 -0
- package/dist/server/admin-router.d.ts +1 -1
- package/dist/server/collection-router.d.ts +1 -1
- package/dist/server/graphql.d.ts +6 -0
- package/dist/server/handlers.d.ts +25 -7
- package/dist/server/middlewares/auth.d.ts +1 -1
- package/dist/server/plugins-loader.d.ts +1 -1
- package/dist/server/router.d.ts +2 -2
- package/dist/server/routers/admin.d.ts +1 -1
- package/dist/server/routers/auth.d.ts +1 -1
- package/dist/server/routers/collections.d.ts +4 -1
- package/dist/server/routers/plugins.d.ts +2 -2
- package/dist/server/setup-middlewares.d.ts +1 -1
- package/dist/server/system-router.d.ts +1 -1
- package/dist/server.js +11 -6
- package/dist/storage/adapters/cloudflare-r2.d.ts +11 -2
- package/dist/storage/index.js +5 -5
- package/dist/types.d.ts +253 -42
- package/dist/utils/context.d.ts +14 -0
- package/dist/utils/logger.d.ts +2 -0
- package/dist/utils/string.d.ts +10 -0
- package/dist/utils/webhooks-engine.d.ts +24 -0
- package/dist/validation.d.ts +67 -1
- package/dist/validator.d.ts +1 -0
- package/package.json +50 -11
- package/src/cli/index.ts +117 -0
- package/dist/chunk-6qq3ne6b.js +0 -288
- package/dist/chunk-6v1fw7q7.js +0 -126
- package/dist/chunk-7a9kn0np.js +0 -116
- package/dist/chunk-bexcv7xe.js +0 -36
- package/dist/chunk-d3ffeqp9.js +0 -87
- package/dist/chunk-fj19qccp.js +0 -78
- package/dist/chunk-g1jb60xd.js +0 -17
- package/dist/chunk-j53pz21t.js +0 -20
- package/dist/chunk-mkn49zmy.js +0 -102
- package/dist/chunk-r39em4yj.js +0 -29
- package/dist/chunk-rsf0tpy1.js +0 -8
- package/dist/chunk-srsac177.js +0 -85
- package/dist/chunk-twpvxfce.js +0 -64
- package/dist/chunk-ywm4t2gm.js +0 -19
- package/dist/cli/commands/plugin-sync.d.ts +0 -1
- package/dist/cli/commands/seed-command.d.ts +0 -2
- package/dist/plugins/ui-bridge.d.ts +0 -12
- package/dist/schema/fields/base.d.ts +0 -84
- package/dist/schema/fields/index.d.ts +0 -147
- package/dist/schema/infer.d.ts +0 -55
- /package/dist/admin/ui/components/{ColumnVisibilityToggle.d.ts → column-visibility-toggle.d.ts} +0 -0
- /package/dist/admin/ui/components/{DataDetailView.d.ts → data-detail-view.d.ts} +0 -0
- /package/dist/cli/{d1-mock.d.ts → core/mocks/d1-mock.d.ts} +0 -0
- /package/dist/cli/{r2-mock.d.ts → core/mocks/r2-mock.d.ts} +0 -0
- /package/dist/cli/{commands → core/plugins}/plugin-build.d.ts +0 -0
- /package/dist/cli/{commands → core/plugins}/plugin-init.d.ts +0 -0
- /package/dist/cli/{commands → core/types}/generate-types.d.ts +0 -0
- /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-
|
|
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,15 +17,15 @@ import {
|
|
|
14
17
|
} from "./chunk-qxt9vge8.js";
|
|
15
18
|
import {
|
|
16
19
|
logger
|
|
17
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-jq1drsen.js";
|
|
18
21
|
import {
|
|
19
22
|
__require
|
|
20
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-6bywt602.js";
|
|
21
24
|
|
|
22
25
|
// src/db/d1.ts
|
|
23
26
|
import fs from "node:fs/promises";
|
|
24
27
|
import path from "node:path";
|
|
25
|
-
import { CompiledQuery, FileMigrationProvider,
|
|
28
|
+
import { CompiledQuery, FileMigrationProvider, Migrator } from "kysely";
|
|
26
29
|
class D1Adapter extends BaseDatabaseAdapter {
|
|
27
30
|
name = "d1";
|
|
28
31
|
_rawDb;
|
|
@@ -52,8 +55,14 @@ class D1Adapter extends BaseDatabaseAdapter {
|
|
|
52
55
|
if (this._db)
|
|
53
56
|
return;
|
|
54
57
|
const { D1Dialect } = await import("kysely-d1");
|
|
55
|
-
|
|
56
|
-
|
|
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
|
+
}
|
|
57
66
|
});
|
|
58
67
|
}
|
|
59
68
|
async disconnect() {
|
|
@@ -65,44 +74,6 @@ class D1Adapter extends BaseDatabaseAdapter {
|
|
|
65
74
|
const result = await this.db.executeQuery(compiled);
|
|
66
75
|
return result.rows;
|
|
67
76
|
}
|
|
68
|
-
async coerceData(collection, data) {
|
|
69
|
-
const colDef = this._collections.find((c) => c.slug === collection);
|
|
70
|
-
if (!colDef)
|
|
71
|
-
return data;
|
|
72
|
-
const result = { ...data };
|
|
73
|
-
const allFields = flattenFields(colDef.fields);
|
|
74
|
-
for (const field of allFields) {
|
|
75
|
-
const colName = toSnakeCase(field.name);
|
|
76
|
-
if (!(colName in result))
|
|
77
|
-
continue;
|
|
78
|
-
const value = result[colName];
|
|
79
|
-
if (value === undefined || value === null)
|
|
80
|
-
continue;
|
|
81
|
-
switch (field.type) {
|
|
82
|
-
case "boolean":
|
|
83
|
-
result[colName] = value ? 1 : 0;
|
|
84
|
-
break;
|
|
85
|
-
case "number":
|
|
86
|
-
result[colName] = Number(value);
|
|
87
|
-
break;
|
|
88
|
-
case "date":
|
|
89
|
-
if (value instanceof Date) {
|
|
90
|
-
result[colName] = value.toISOString();
|
|
91
|
-
} else if (typeof value === "string") {
|
|
92
|
-
result[colName] = new Date(value).toISOString();
|
|
93
|
-
}
|
|
94
|
-
break;
|
|
95
|
-
case "richtext":
|
|
96
|
-
case "json":
|
|
97
|
-
case "file":
|
|
98
|
-
if (typeof value === "object") {
|
|
99
|
-
result[colName] = JSON.stringify(value);
|
|
100
|
-
}
|
|
101
|
-
break;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
return result;
|
|
105
|
-
}
|
|
106
77
|
async count(collection, query) {
|
|
107
78
|
const tableName = toSnakeCase(collection);
|
|
108
79
|
let qb = this.db.selectFrom(tableName).select((eb) => eb.fn.count("id").as("count"));
|
|
@@ -138,18 +109,14 @@ class D1Adapter extends BaseDatabaseAdapter {
|
|
|
138
109
|
validCols.add("id");
|
|
139
110
|
validCols.add(toSnakeCase("createdAt"));
|
|
140
111
|
validCols.add(toSnakeCase("updatedAt"));
|
|
141
|
-
const now = new Date().toISOString();
|
|
142
|
-
flatData[toSnakeCase("createdAt")] = now;
|
|
143
|
-
flatData[toSnakeCase("updatedAt")] = now;
|
|
144
112
|
const filteredData = {};
|
|
145
113
|
for (const col of Object.keys(flatData)) {
|
|
146
114
|
if (validCols.has(col)) {
|
|
147
115
|
filteredData[col] = flatData[col];
|
|
148
116
|
}
|
|
149
117
|
}
|
|
150
|
-
const coercedData = await this.coerceData(collection, filteredData);
|
|
151
118
|
try {
|
|
152
|
-
await this.db.insertInto(tableName).values(
|
|
119
|
+
await this.db.insertInto(tableName).values(filteredData).execute();
|
|
153
120
|
} catch (e) {
|
|
154
121
|
logger.error(`[D1] Create failed in ${collection}: ${e.message}`);
|
|
155
122
|
throw e;
|
|
@@ -181,13 +148,13 @@ class D1Adapter extends BaseDatabaseAdapter {
|
|
|
181
148
|
}
|
|
182
149
|
}
|
|
183
150
|
delete blockFlatData.blockType;
|
|
184
|
-
const
|
|
151
|
+
const blockData = {
|
|
185
152
|
...blockFlatData,
|
|
186
153
|
_parent_id: flatData.id,
|
|
187
154
|
_order: i,
|
|
188
155
|
block_type: block.blockType
|
|
189
|
-
}
|
|
190
|
-
await this.db.insertInto(blockTableName).values(
|
|
156
|
+
};
|
|
157
|
+
await this.db.insertInto(blockTableName).values(blockData).execute();
|
|
191
158
|
}
|
|
192
159
|
}
|
|
193
160
|
return this.findOne(collection, { id: flatData.id }, this.db);
|
|
@@ -258,9 +225,17 @@ class D1Adapter extends BaseDatabaseAdapter {
|
|
|
258
225
|
const page = options?.page || 1;
|
|
259
226
|
const limit = options?.limit || 10;
|
|
260
227
|
const offset = (page - 1) * limit;
|
|
228
|
+
const cursorColumn = options?.cursorColumn || "id";
|
|
261
229
|
const total = await this.count(collection, query);
|
|
262
230
|
const tableName = toSnakeCase(collection);
|
|
263
|
-
let qb = this.db.selectFrom(tableName).selectAll().limit(limit)
|
|
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
|
+
}
|
|
264
239
|
if (query && Object.keys(query).length > 0) {
|
|
265
240
|
qb = qb.where((eb) => buildKyselyWhere(eb, query) || eb.val(true));
|
|
266
241
|
}
|
|
@@ -270,11 +245,13 @@ class D1Adapter extends BaseDatabaseAdapter {
|
|
|
270
245
|
qb = qb.orderBy(col, dir === "desc" ? "desc" : "asc");
|
|
271
246
|
}
|
|
272
247
|
} else {
|
|
273
|
-
qb = qb.orderBy(
|
|
248
|
+
qb = qb.orderBy(cursorColumn, "desc");
|
|
274
249
|
}
|
|
275
250
|
const rows = await qb.execute();
|
|
276
251
|
if (rows.length === 0) {
|
|
277
252
|
const totalPages2 = Math.ceil(total / limit);
|
|
253
|
+
const afterAnchor = options?.after;
|
|
254
|
+
const beforeAnchor = options?.before;
|
|
278
255
|
return {
|
|
279
256
|
docs: [],
|
|
280
257
|
totalDocs: total,
|
|
@@ -282,10 +259,12 @@ class D1Adapter extends BaseDatabaseAdapter {
|
|
|
282
259
|
totalPages: totalPages2,
|
|
283
260
|
page,
|
|
284
261
|
pagingCounter: offset + 1,
|
|
285
|
-
hasNextPage:
|
|
286
|
-
hasPrevPage: page > 1,
|
|
287
|
-
prevPage:
|
|
288
|
-
nextPage:
|
|
262
|
+
hasNextPage: false,
|
|
263
|
+
hasPrevPage: !!afterAnchor || page > 1,
|
|
264
|
+
prevPage: null,
|
|
265
|
+
nextPage: null,
|
|
266
|
+
nextCursor: null,
|
|
267
|
+
prevCursor: afterAnchor ? afterAnchor : null
|
|
289
268
|
};
|
|
290
269
|
}
|
|
291
270
|
const rowIds = rows.map((r) => r.id);
|
|
@@ -363,9 +342,11 @@ class D1Adapter extends BaseDatabaseAdapter {
|
|
|
363
342
|
page,
|
|
364
343
|
pagingCounter: offset + 1,
|
|
365
344
|
hasNextPage: page * limit < total,
|
|
366
|
-
hasPrevPage: page > 1,
|
|
345
|
+
hasPrevPage: page > 1 || !!options?.after || !!options?.before,
|
|
367
346
|
prevPage: page > 1 ? page - 1 : null,
|
|
368
|
-
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
|
|
369
350
|
};
|
|
370
351
|
}
|
|
371
352
|
async update(collection, query, data) {
|
|
@@ -377,6 +358,9 @@ class D1Adapter extends BaseDatabaseAdapter {
|
|
|
377
358
|
const current = await this.findOne(collection, normalizedQuery, this.db);
|
|
378
359
|
if (!current)
|
|
379
360
|
throw new Error("Document not found");
|
|
361
|
+
const store = requestContext.getStore();
|
|
362
|
+
if (store)
|
|
363
|
+
store.previousData = current;
|
|
380
364
|
const colDef = this._collections.find((c) => c.slug === collection);
|
|
381
365
|
const jsonFields = colDef?.fields.filter((f) => f.name && (["richtext", "json", "file"].includes(f.type) || f.localized)).map((f) => f.name) || [];
|
|
382
366
|
const flatData = flattenPayload(data, "", jsonFields);
|
|
@@ -394,30 +378,18 @@ class D1Adapter extends BaseDatabaseAdapter {
|
|
|
394
378
|
delete flatData[key];
|
|
395
379
|
}
|
|
396
380
|
}
|
|
397
|
-
const ts = colDef?.timestamps !== false;
|
|
398
|
-
if (ts) {
|
|
399
|
-
const config = typeof colDef?.timestamps === "object" ? colDef.timestamps : {};
|
|
400
|
-
const updatedField = toSnakeCase(config.updatedAt || "updatedAt");
|
|
401
|
-
flatData[updatedField] = new Date().toISOString();
|
|
402
|
-
}
|
|
403
381
|
if (Object.keys(flatData).length > 0) {
|
|
404
382
|
const dbFields = flattenFields(colDef?.fields || []);
|
|
405
383
|
const validCols = new Set(dbFields.map((f) => toSnakeCase(f.name)));
|
|
406
384
|
validCols.add("id");
|
|
407
|
-
if (ts) {
|
|
408
|
-
const config = typeof colDef?.timestamps === "object" ? colDef.timestamps : {};
|
|
409
|
-
validCols.add(toSnakeCase(config.createdAt || "createdAt"));
|
|
410
|
-
validCols.add(toSnakeCase(config.updatedAt || "updatedAt"));
|
|
411
|
-
}
|
|
412
385
|
const filteredData = {};
|
|
413
386
|
for (const col of Object.keys(flatData)) {
|
|
414
387
|
if (validCols.has(col)) {
|
|
415
388
|
filteredData[col] = flatData[col];
|
|
416
389
|
}
|
|
417
390
|
}
|
|
418
|
-
const coercedData = await this.coerceData(collection, filteredData);
|
|
419
391
|
try {
|
|
420
|
-
await this.db.updateTable(tableName).set(
|
|
392
|
+
await this.db.updateTable(tableName).set(filteredData).where("id", "=", current.id).execute();
|
|
421
393
|
} catch (e) {
|
|
422
394
|
logger.error(`[D1] Update failed in ${collection}: ${e.message}`);
|
|
423
395
|
throw e;
|
|
@@ -459,13 +431,13 @@ class D1Adapter extends BaseDatabaseAdapter {
|
|
|
459
431
|
}
|
|
460
432
|
}
|
|
461
433
|
delete blockFlatData.blockType;
|
|
462
|
-
const
|
|
434
|
+
const blockData = {
|
|
463
435
|
...blockFlatData,
|
|
464
436
|
_parent_id: current.id,
|
|
465
437
|
_order: i,
|
|
466
438
|
block_type: block.blockType
|
|
467
|
-
}
|
|
468
|
-
await this.db.insertInto(blockTableName).values(
|
|
439
|
+
};
|
|
440
|
+
await this.db.insertInto(blockTableName).values(blockData).execute();
|
|
469
441
|
}
|
|
470
442
|
}
|
|
471
443
|
return this.findOne(collection, { id: current.id }, this.db);
|
|
@@ -484,31 +456,19 @@ class D1Adapter extends BaseDatabaseAdapter {
|
|
|
484
456
|
delete flatData[key];
|
|
485
457
|
}
|
|
486
458
|
}
|
|
487
|
-
const ts = colDef?.timestamps !== false;
|
|
488
|
-
if (ts) {
|
|
489
|
-
const config = typeof colDef?.timestamps === "object" ? colDef.timestamps : {};
|
|
490
|
-
const updatedField = toSnakeCase(config.updatedAt || "updatedAt");
|
|
491
|
-
flatData[updatedField] = new Date().toISOString();
|
|
492
|
-
}
|
|
493
459
|
if (Object.keys(flatData).length > 0) {
|
|
494
460
|
const dbFields = flattenFields(colDef?.fields || []);
|
|
495
461
|
const validCols = new Set(dbFields.map((f) => toSnakeCase(f.name)));
|
|
496
462
|
validCols.add("id");
|
|
497
|
-
if (ts) {
|
|
498
|
-
const config = typeof colDef?.timestamps === "object" ? colDef.timestamps : {};
|
|
499
|
-
validCols.add(toSnakeCase(config.createdAt || "createdAt"));
|
|
500
|
-
validCols.add(toSnakeCase(config.updatedAt || "updatedAt"));
|
|
501
|
-
}
|
|
502
463
|
const filteredData = {};
|
|
503
464
|
for (const col of Object.keys(flatData)) {
|
|
504
465
|
if (validCols.has(col)) {
|
|
505
466
|
filteredData[col] = flatData[col];
|
|
506
467
|
}
|
|
507
468
|
}
|
|
508
|
-
const coercedData = await this.coerceData(collection, filteredData);
|
|
509
469
|
logger.debug(`[D1] Bulk updating in ${collection}...`);
|
|
510
470
|
try {
|
|
511
|
-
const result = await qb.set(
|
|
471
|
+
const result = await qb.set(filteredData).executeTakeFirst();
|
|
512
472
|
return Number(result.numUpdatedRows || 0);
|
|
513
473
|
} catch (e) {
|
|
514
474
|
logger.error(`[D1] Bulk update failed in ${collection}: ${e.message}`);
|
|
@@ -3,10 +3,13 @@ import {
|
|
|
3
3
|
flattenPayload,
|
|
4
4
|
pushSchema,
|
|
5
5
|
unflattenRow
|
|
6
|
-
} from "./chunk-
|
|
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,15 +17,15 @@ import {
|
|
|
14
17
|
} from "./chunk-qxt9vge8.js";
|
|
15
18
|
import {
|
|
16
19
|
logger
|
|
17
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-jq1drsen.js";
|
|
18
21
|
import {
|
|
19
22
|
__require
|
|
20
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-6bywt602.js";
|
|
21
24
|
|
|
22
25
|
// src/db/bun-sqlite.ts
|
|
23
26
|
import fs from "node:fs/promises";
|
|
24
27
|
import path from "node:path";
|
|
25
|
-
import { FileMigrationProvider,
|
|
28
|
+
import { FileMigrationProvider, Migrator, sql } from "kysely";
|
|
26
29
|
class BunSQLiteAdapter extends BaseDatabaseAdapter {
|
|
27
30
|
path;
|
|
28
31
|
name = "bun-sqlite";
|
|
@@ -54,10 +57,16 @@ class BunSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
54
57
|
const { Database } = await import("bun:sqlite");
|
|
55
58
|
const { BunSqliteDialect } = await import("kysely-bun-sqlite");
|
|
56
59
|
this._rawDb = new Database(this.path);
|
|
57
|
-
|
|
60
|
+
const { createOpacaKysely } = await import("./chunk-sqsfk9p4.js");
|
|
61
|
+
this._db = createOpacaKysely({
|
|
58
62
|
dialect: new BunSqliteDialect({
|
|
59
63
|
database: this._rawDb
|
|
60
|
-
})
|
|
64
|
+
}),
|
|
65
|
+
config: {
|
|
66
|
+
collections: this._collections,
|
|
67
|
+
globals: this._globals,
|
|
68
|
+
db: { name: "bun-sqlite" }
|
|
69
|
+
}
|
|
61
70
|
});
|
|
62
71
|
}
|
|
63
72
|
async disconnect() {
|
|
@@ -69,47 +78,6 @@ class BunSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
69
78
|
const result = await compiled.execute(this.db);
|
|
70
79
|
return result.rows;
|
|
71
80
|
}
|
|
72
|
-
async coerceData(collection, data) {
|
|
73
|
-
const colDef = this._collections.find((c) => c.slug === collection);
|
|
74
|
-
if (!colDef)
|
|
75
|
-
return data;
|
|
76
|
-
const result = { ...data };
|
|
77
|
-
const allFields = flattenFields(colDef.fields);
|
|
78
|
-
for (const field of allFields) {
|
|
79
|
-
const colName = toSnakeCase(field.name);
|
|
80
|
-
if (!(colName in result))
|
|
81
|
-
continue;
|
|
82
|
-
const value = result[colName];
|
|
83
|
-
if (value === undefined || value === null)
|
|
84
|
-
continue;
|
|
85
|
-
switch (field.type) {
|
|
86
|
-
case "boolean":
|
|
87
|
-
result[colName] = value ? 1 : 0;
|
|
88
|
-
break;
|
|
89
|
-
case "number":
|
|
90
|
-
result[colName] = Number(value);
|
|
91
|
-
break;
|
|
92
|
-
case "date":
|
|
93
|
-
if (value instanceof Date) {
|
|
94
|
-
result[colName] = value.toISOString();
|
|
95
|
-
} else if (typeof value === "string") {
|
|
96
|
-
const d = new Date(value);
|
|
97
|
-
if (!isNaN(d.getTime())) {
|
|
98
|
-
result[colName] = d.toISOString();
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
break;
|
|
102
|
-
case "richtext":
|
|
103
|
-
case "json":
|
|
104
|
-
case "file":
|
|
105
|
-
if (typeof value === "object") {
|
|
106
|
-
result[colName] = JSON.stringify(value);
|
|
107
|
-
}
|
|
108
|
-
break;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
return result;
|
|
112
|
-
}
|
|
113
81
|
async count(collection, query) {
|
|
114
82
|
const tableName = toSnakeCase(collection);
|
|
115
83
|
let qb = this.db.selectFrom(tableName).select((eb) => eb.fn.count("id").as("count"));
|
|
@@ -122,13 +90,7 @@ class BunSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
122
90
|
async create(collection, data) {
|
|
123
91
|
const tableName = toSnakeCase(collection);
|
|
124
92
|
const colDef = this._collections.find((c) => c.slug === collection);
|
|
125
|
-
const
|
|
126
|
-
const flatData = flattenPayload(data, "", jsonFields);
|
|
127
|
-
for (const field of jsonFields) {
|
|
128
|
-
if (flatData[field] && typeof flatData[field] === "object") {
|
|
129
|
-
flatData[field] = JSON.stringify(flatData[field]);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
93
|
+
const flatData = flattenPayload(data);
|
|
132
94
|
const relationalFields = getRelationalFields(colDef?.fields || []);
|
|
133
95
|
const hasManyData = {};
|
|
134
96
|
const blocksData = {};
|
|
@@ -143,24 +105,18 @@ class BunSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
143
105
|
delete flatData[key];
|
|
144
106
|
}
|
|
145
107
|
}
|
|
146
|
-
if (!flatData.id)
|
|
147
|
-
flatData.id = crypto.randomUUID();
|
|
148
108
|
const dbFields = flattenFields(colDef?.fields || []);
|
|
149
109
|
const validCols = new Set(dbFields.map((f) => toSnakeCase(f.name)));
|
|
150
110
|
validCols.add("id");
|
|
151
111
|
validCols.add(toSnakeCase("createdAt"));
|
|
152
112
|
validCols.add(toSnakeCase("updatedAt"));
|
|
153
|
-
const now = new Date().toISOString();
|
|
154
|
-
flatData[toSnakeCase("createdAt")] = now;
|
|
155
|
-
flatData[toSnakeCase("updatedAt")] = now;
|
|
156
113
|
const filteredData = {};
|
|
157
114
|
for (const col of Object.keys(flatData)) {
|
|
158
115
|
if (validCols.has(col)) {
|
|
159
116
|
filteredData[col] = flatData[col];
|
|
160
117
|
}
|
|
161
118
|
}
|
|
162
|
-
|
|
163
|
-
await this.db.insertInto(tableName).values(coercedData).execute();
|
|
119
|
+
await this.db.insertInto(tableName).values(filteredData).execute();
|
|
164
120
|
for (const [key, values] of Object.entries(hasManyData)) {
|
|
165
121
|
const joinTableName = `${tableName}_${toSnakeCase(key)}_relations`.toLowerCase();
|
|
166
122
|
if (values.length > 0) {
|
|
@@ -188,13 +144,13 @@ class BunSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
188
144
|
}
|
|
189
145
|
}
|
|
190
146
|
delete blockFlatData.blockType;
|
|
191
|
-
const
|
|
147
|
+
const blockData = {
|
|
192
148
|
...blockFlatData,
|
|
193
149
|
_parent_id: flatData.id,
|
|
194
150
|
_order: i,
|
|
195
151
|
block_type: block.blockType
|
|
196
|
-
}
|
|
197
|
-
await this.db.insertInto(blockTableName).values(
|
|
152
|
+
};
|
|
153
|
+
await this.db.insertInto(blockTableName).values(blockData).execute();
|
|
198
154
|
}
|
|
199
155
|
}
|
|
200
156
|
return this.findOne(collection, { id: flatData.id }, this.db);
|
|
@@ -265,9 +221,17 @@ class BunSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
265
221
|
const page = options?.page || 1;
|
|
266
222
|
const limit = options?.limit || 10;
|
|
267
223
|
const offset = (page - 1) * limit;
|
|
224
|
+
const cursorColumn = options?.cursorColumn || "id";
|
|
268
225
|
const total = await this.count(collection, query);
|
|
269
226
|
const tableName = toSnakeCase(collection);
|
|
270
|
-
let qb = this.db.selectFrom(tableName).selectAll().limit(limit)
|
|
227
|
+
let qb = this.db.selectFrom(tableName).selectAll().limit(limit);
|
|
228
|
+
if (options?.after) {
|
|
229
|
+
qb = qb.where(cursorColumn, ">", options.after);
|
|
230
|
+
} else if (options?.before) {
|
|
231
|
+
qb = qb.where(cursorColumn, "<", options.before);
|
|
232
|
+
} else {
|
|
233
|
+
qb = qb.offset(offset);
|
|
234
|
+
}
|
|
271
235
|
if (query && Object.keys(query).length > 0) {
|
|
272
236
|
qb = qb.where((eb) => buildKyselyWhere(eb, query) || eb.val(true));
|
|
273
237
|
}
|
|
@@ -277,11 +241,13 @@ class BunSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
277
241
|
qb = qb.orderBy(col, dir === "desc" ? "desc" : "asc");
|
|
278
242
|
}
|
|
279
243
|
} else {
|
|
280
|
-
qb = qb.orderBy(
|
|
244
|
+
qb = qb.orderBy(cursorColumn, "desc");
|
|
281
245
|
}
|
|
282
246
|
const rows = await qb.execute();
|
|
283
247
|
if (rows.length === 0) {
|
|
284
248
|
const totalPages2 = Math.ceil(total / limit);
|
|
249
|
+
const afterAnchor = options?.after;
|
|
250
|
+
const beforeAnchor = options?.before;
|
|
285
251
|
return {
|
|
286
252
|
docs: [],
|
|
287
253
|
totalDocs: total,
|
|
@@ -289,10 +255,12 @@ class BunSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
289
255
|
totalPages: totalPages2,
|
|
290
256
|
page,
|
|
291
257
|
pagingCounter: offset + 1,
|
|
292
|
-
hasNextPage:
|
|
293
|
-
hasPrevPage: page > 1,
|
|
294
|
-
prevPage:
|
|
295
|
-
nextPage:
|
|
258
|
+
hasNextPage: false,
|
|
259
|
+
hasPrevPage: !!afterAnchor || page > 1,
|
|
260
|
+
prevPage: null,
|
|
261
|
+
nextPage: null,
|
|
262
|
+
nextCursor: null,
|
|
263
|
+
prevCursor: afterAnchor ? afterAnchor : null
|
|
296
264
|
};
|
|
297
265
|
}
|
|
298
266
|
const rowIds = rows.map((r) => r.id);
|
|
@@ -370,9 +338,11 @@ class BunSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
370
338
|
page,
|
|
371
339
|
pagingCounter: offset + 1,
|
|
372
340
|
hasNextPage: page * limit < total,
|
|
373
|
-
hasPrevPage: page > 1,
|
|
341
|
+
hasPrevPage: page > 1 || !!options?.after || !!options?.before,
|
|
374
342
|
prevPage: page > 1 ? page - 1 : null,
|
|
375
|
-
nextPage: page < totalPages ? page + 1 : null
|
|
343
|
+
nextPage: page < totalPages ? page + 1 : null,
|
|
344
|
+
nextCursor: docs.length > 0 ? docs[docs.length - 1][cursorColumn] : null,
|
|
345
|
+
prevCursor: docs.length > 0 && (page > 1 || !!options?.after || !!options?.before) ? docs[0][cursorColumn] : null
|
|
376
346
|
};
|
|
377
347
|
}
|
|
378
348
|
async update(collection, query, data) {
|
|
@@ -384,6 +354,9 @@ class BunSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
384
354
|
const current = await this.findOne(collection, normalizedQuery, tx);
|
|
385
355
|
if (!current)
|
|
386
356
|
throw new Error("Document not found");
|
|
357
|
+
const store = requestContext.getStore();
|
|
358
|
+
if (store)
|
|
359
|
+
store.previousData = current;
|
|
387
360
|
const colDef = this._collections.find((c) => c.slug === collection);
|
|
388
361
|
const jsonFields = colDef?.fields.filter((f) => ["richtext", "json", "file"].includes(f.type)).map((f) => f.name) || [];
|
|
389
362
|
const flatData = flattenPayload(data, "", jsonFields);
|
|
@@ -406,10 +379,8 @@ class BunSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
406
379
|
delete flatData[key];
|
|
407
380
|
}
|
|
408
381
|
}
|
|
409
|
-
flatData.updated_at = new Date().toISOString();
|
|
410
382
|
if (Object.keys(flatData).length > 0) {
|
|
411
|
-
|
|
412
|
-
await tx.updateTable(toSnakeCase(collection)).set(coercedData).where("id", "=", current.id).execute();
|
|
383
|
+
await tx.updateTable(toSnakeCase(collection)).set(flatData).where("id", "=", current.id).execute();
|
|
413
384
|
}
|
|
414
385
|
for (const [key, values] of Object.entries(hasManyData)) {
|
|
415
386
|
const joinTableName = `${toSnakeCase(collection)}_${toSnakeCase(key)}_relations`.toLowerCase();
|
|
@@ -447,13 +418,13 @@ class BunSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
447
418
|
}
|
|
448
419
|
}
|
|
449
420
|
delete blockFlatData.blockType;
|
|
450
|
-
const
|
|
421
|
+
const blockData = {
|
|
451
422
|
...blockFlatData,
|
|
452
423
|
_parent_id: current.id,
|
|
453
424
|
_order: i,
|
|
454
425
|
block_type: block.blockType
|
|
455
|
-
}
|
|
456
|
-
await this.db.insertInto(blockTableName).values(
|
|
426
|
+
};
|
|
427
|
+
await this.db.insertInto(blockTableName).values(blockData).execute();
|
|
457
428
|
}
|
|
458
429
|
}
|
|
459
430
|
return this.findOne(collection, { id: current.id }, tx);
|
|
@@ -478,10 +449,8 @@ class BunSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
478
449
|
delete flatData[key];
|
|
479
450
|
}
|
|
480
451
|
}
|
|
481
|
-
flatData.updated_at = new Date().toISOString();
|
|
482
452
|
if (Object.keys(flatData).length > 0) {
|
|
483
|
-
const
|
|
484
|
-
const result = await qb.set(coercedData).executeTakeFirst();
|
|
453
|
+
const result = await qb.set(flatData).executeTakeFirst();
|
|
485
454
|
return Number(result.numUpdatedRows || 0);
|
|
486
455
|
}
|
|
487
456
|
return 0;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import {
|
|
2
|
+
require_picocolors
|
|
3
|
+
} from "./chunk-rwqwsanx.js";
|
|
4
|
+
import {
|
|
5
|
+
Gt,
|
|
6
|
+
R,
|
|
7
|
+
Vt,
|
|
8
|
+
Wt
|
|
9
|
+
} from "./chunk-ec4jhybj.js";
|
|
10
|
+
import {
|
|
11
|
+
defineCommand
|
|
12
|
+
} from "./chunk-1qm0m8r8.js";
|
|
13
|
+
import {
|
|
14
|
+
__toESM
|
|
15
|
+
} from "./chunk-6bywt602.js";
|
|
16
|
+
|
|
17
|
+
// src/cli/commands/dev.ts
|
|
18
|
+
import { spawn } from "node:child_process";
|
|
19
|
+
import fs from "node:fs";
|
|
20
|
+
import { resolve } from "node:path";
|
|
21
|
+
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
22
|
+
var dev_default = defineCommand({
|
|
23
|
+
meta: {
|
|
24
|
+
name: "dev",
|
|
25
|
+
description: "Start the OpacaCMS development server"
|
|
26
|
+
},
|
|
27
|
+
args: {
|
|
28
|
+
entry: {
|
|
29
|
+
type: "string",
|
|
30
|
+
description: "Path to your entry point (default: index.ts)",
|
|
31
|
+
default: "index.ts"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
async run({ args }) {
|
|
35
|
+
console.log();
|
|
36
|
+
Wt(import_picocolors.default.bgBlue(import_picocolors.default.white(" OpacaCMS Dev Server ")));
|
|
37
|
+
const entryPath = resolve(process.cwd(), args.entry);
|
|
38
|
+
if (!fs.existsSync(entryPath)) {
|
|
39
|
+
R.error(import_picocolors.default.red(`Entry file not found at ${entryPath}`));
|
|
40
|
+
R.info("Try specifying the entry file: opacacms dev --entry src/index.ts");
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
Vt(`Watching for changes...`, "Status");
|
|
44
|
+
const isD1 = fs.readFileSync(entryPath, "utf-8").includes("createCloudflareWorkersHandler");
|
|
45
|
+
let cmd = "bun";
|
|
46
|
+
let cmdArgs = ["run", "--watch", args.entry];
|
|
47
|
+
if (isD1) {
|
|
48
|
+
cmd = "bun";
|
|
49
|
+
cmdArgs = ["x", "wrangler", "dev", args.entry];
|
|
50
|
+
}
|
|
51
|
+
const child = spawn(cmd, cmdArgs, {
|
|
52
|
+
stdio: "inherit",
|
|
53
|
+
cwd: process.cwd(),
|
|
54
|
+
env: process.env
|
|
55
|
+
});
|
|
56
|
+
child.on("error", (err) => {
|
|
57
|
+
R.error(import_picocolors.default.red(`Failed to start server: ${err.message}`));
|
|
58
|
+
});
|
|
59
|
+
child.on("exit", (code) => {
|
|
60
|
+
if (code !== 0) {
|
|
61
|
+
R.warn(`Server exited with code ${code}`);
|
|
62
|
+
}
|
|
63
|
+
Gt("Goodbye!");
|
|
64
|
+
process.exit(code || 0);
|
|
65
|
+
});
|
|
66
|
+
process.on("SIGINT", () => {
|
|
67
|
+
child.kill("SIGINT");
|
|
68
|
+
});
|
|
69
|
+
process.on("SIGTERM", () => {
|
|
70
|
+
child.kill("SIGTERM");
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
export {
|
|
75
|
+
dev_default as default
|
|
76
|
+
};
|