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.
- 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 +20 -2
- 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-3j9zjfmn.js +376 -0
- package/dist/{chunk-byq8g0rd.js → chunk-48ywpd0a.js} +16 -22
- package/dist/{chunk-esrg9qj0.js → chunk-5422w4eq.js} +70 -54
- 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-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-0bq155dy.js → chunk-e0g6gn7n.js} +89 -100
- 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-gmee4mdc.js → chunk-naqcqj8n.js} +92 -106
- package/dist/chunk-q5sb5dcr.js +15 -0
- package/dist/{chunk-d1asgtke.js → chunk-qhdsjek6.js} +90 -121
- package/dist/{chunk-0gtxnxmd.js → chunk-qsh2nqz3.js} +85 -105
- 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/{chunk-kc4jfnv7.js → chunk-z3ffn2b7.js} +851 -324
- 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/adapter.d.ts +2 -2
- package/dist/db/better-sqlite.d.ts +3 -3
- package/dist/db/better-sqlite.js +6 -5
- package/dist/db/bun-sqlite.d.ts +3 -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 +4 -4
- package/dist/db/postgres.js +6 -5
- package/dist/db/sqlite.d.ts +3 -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 +39 -30
- package/dist/types.d.ts +255 -44
- 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 +36 -33
- 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-j53pz21t.js +0 -20
- package/dist/chunk-mkn49zmy.js +0 -102
- package/dist/chunk-qb6ztvw9.js +0 -17
- package/dist/chunk-r39em4yj.js +0 -29
- package/dist/chunk-rsf0tpy1.js +0 -8
- package/dist/chunk-srsac177.js +0 -85
- package/dist/chunk-swtcpvhf.js +0 -2442
- 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,23 +17,25 @@ 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/better-sqlite.ts
|
|
23
26
|
import fs from "node:fs/promises";
|
|
24
27
|
import path from "node:path";
|
|
25
|
-
import {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
import {
|
|
29
|
+
CompiledQuery,
|
|
30
|
+
FileMigrationProvider,
|
|
31
|
+
Migrator,
|
|
32
|
+
SqliteDialect
|
|
33
|
+
} from "kysely";
|
|
30
34
|
class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
35
|
+
path;
|
|
31
36
|
name = "better-sqlite3";
|
|
32
37
|
_rawDb;
|
|
33
|
-
_db;
|
|
38
|
+
_db = null;
|
|
34
39
|
_collections = [];
|
|
35
40
|
_globals = [];
|
|
36
41
|
push;
|
|
@@ -40,71 +45,50 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
40
45
|
return this._rawDb;
|
|
41
46
|
}
|
|
42
47
|
get db() {
|
|
48
|
+
if (!this._db)
|
|
49
|
+
throw new Error("Database not connected. Call connect() first.");
|
|
43
50
|
return this._db;
|
|
44
51
|
}
|
|
45
52
|
constructor(path2, options) {
|
|
46
53
|
super();
|
|
47
|
-
this.
|
|
48
|
-
this._db = new Kysely({
|
|
49
|
-
dialect: new SqliteDialect({
|
|
50
|
-
database: this._rawDb
|
|
51
|
-
})
|
|
52
|
-
});
|
|
54
|
+
this.path = path2;
|
|
53
55
|
this.push = options?.push ?? true;
|
|
54
56
|
this.pushDestructive = options?.pushDestructive ?? false;
|
|
55
57
|
this.migrationDir = options?.migrationDir ?? "./migrations";
|
|
56
58
|
}
|
|
57
|
-
async connect() {
|
|
59
|
+
async connect() {
|
|
60
|
+
if (this._db)
|
|
61
|
+
return;
|
|
62
|
+
const { createRequire } = await import("node:module");
|
|
63
|
+
const require2 = createRequire(import.meta.url);
|
|
64
|
+
const Database = require2("better-sqlite3");
|
|
65
|
+
this._rawDb = new Database(this.path);
|
|
66
|
+
const { createOpacaKysely } = await import("./chunk-sqsfk9p4.js");
|
|
67
|
+
this._db = createOpacaKysely({
|
|
68
|
+
dialect: new SqliteDialect({
|
|
69
|
+
database: this._rawDb
|
|
70
|
+
}),
|
|
71
|
+
config: {
|
|
72
|
+
collections: this._collections,
|
|
73
|
+
globals: this._globals,
|
|
74
|
+
db: { name: "better-sqlite3" }
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
58
78
|
async disconnect() {
|
|
59
|
-
|
|
79
|
+
if (this._db)
|
|
80
|
+
await this.db.destroy();
|
|
60
81
|
}
|
|
61
82
|
async unsafe(query, params) {
|
|
83
|
+
if (!this._db)
|
|
84
|
+
await this.connect();
|
|
62
85
|
const compiled = CompiledQuery.raw(query, params || []);
|
|
63
|
-
const result = await this.
|
|
86
|
+
const result = await this.db.executeQuery(compiled);
|
|
64
87
|
return result.rows;
|
|
65
88
|
}
|
|
66
|
-
async coerceData(collection, data) {
|
|
67
|
-
const colDef = this._collections.find((c) => c.slug === collection);
|
|
68
|
-
if (!colDef)
|
|
69
|
-
return data;
|
|
70
|
-
const result = { ...data };
|
|
71
|
-
const { flattenFields: flattenFields2 } = await import("./chunk-526a3gqx.js");
|
|
72
|
-
const allFields = flattenFields2(colDef.fields);
|
|
73
|
-
for (const field of allFields) {
|
|
74
|
-
const colName = toSnakeCase(field.name);
|
|
75
|
-
if (!(colName in result))
|
|
76
|
-
continue;
|
|
77
|
-
const value = result[colName];
|
|
78
|
-
if (value === undefined || value === null)
|
|
79
|
-
continue;
|
|
80
|
-
switch (field.type) {
|
|
81
|
-
case "boolean":
|
|
82
|
-
result[colName] = value ? 1 : 0;
|
|
83
|
-
break;
|
|
84
|
-
case "number":
|
|
85
|
-
result[colName] = Number(value);
|
|
86
|
-
break;
|
|
87
|
-
case "date":
|
|
88
|
-
if (value instanceof Date) {
|
|
89
|
-
result[colName] = value.toISOString();
|
|
90
|
-
} else if (typeof value === "string") {
|
|
91
|
-
result[colName] = new Date(value).toISOString();
|
|
92
|
-
}
|
|
93
|
-
break;
|
|
94
|
-
case "richtext":
|
|
95
|
-
case "json":
|
|
96
|
-
case "file":
|
|
97
|
-
if (typeof value === "object") {
|
|
98
|
-
result[colName] = JSON.stringify(value);
|
|
99
|
-
}
|
|
100
|
-
break;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
return result;
|
|
104
|
-
}
|
|
105
89
|
async count(collection, query) {
|
|
106
90
|
const tableName = toSnakeCase(collection);
|
|
107
|
-
let qb = this.
|
|
91
|
+
let qb = this.db.selectFrom(tableName).select((eb) => eb.fn.count("id").as("count"));
|
|
108
92
|
if (query && Object.keys(query).length > 0) {
|
|
109
93
|
qb = qb.where((eb) => buildKyselyWhere(eb, query) || eb.val(true));
|
|
110
94
|
}
|
|
@@ -113,15 +97,10 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
113
97
|
}
|
|
114
98
|
async create(collection, data) {
|
|
115
99
|
const tableName = toSnakeCase(collection);
|
|
116
|
-
return this.
|
|
100
|
+
return this.db.transaction().execute(async (tx) => {
|
|
117
101
|
const colDef = this._collections.find((c) => c.slug === collection);
|
|
118
|
-
const
|
|
119
|
-
const
|
|
120
|
-
for (const field of jsonFields) {
|
|
121
|
-
if (flatData[field] && typeof flatData[field] === "object") {
|
|
122
|
-
flatData[field] = JSON.stringify(flatData[field]);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
102
|
+
const flatData = flattenPayload(data);
|
|
103
|
+
const relationalFields = getRelationalFields(colDef?.fields || []);
|
|
125
104
|
const hasManyData = {};
|
|
126
105
|
const blocksData = {};
|
|
127
106
|
for (const key in flatData) {
|
|
@@ -135,24 +114,18 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
135
114
|
delete flatData[key];
|
|
136
115
|
}
|
|
137
116
|
}
|
|
138
|
-
if (!flatData.id)
|
|
139
|
-
flatData.id = crypto.randomUUID();
|
|
140
117
|
const dbFields = flattenFields(colDef?.fields || []);
|
|
141
118
|
const validCols = new Set(dbFields.map((f) => toSnakeCase(f.name)));
|
|
142
119
|
validCols.add("id");
|
|
143
120
|
validCols.add(toSnakeCase("createdAt"));
|
|
144
121
|
validCols.add(toSnakeCase("updatedAt"));
|
|
145
|
-
const now = new Date().toISOString();
|
|
146
|
-
flatData[toSnakeCase("createdAt")] = now;
|
|
147
|
-
flatData[toSnakeCase("updatedAt")] = now;
|
|
148
122
|
const filteredData = {};
|
|
149
123
|
for (const col of Object.keys(flatData)) {
|
|
150
124
|
if (validCols.has(col)) {
|
|
151
125
|
filteredData[col] = flatData[col];
|
|
152
126
|
}
|
|
153
127
|
}
|
|
154
|
-
|
|
155
|
-
await tx.insertInto(tableName).values(coercedData).execute();
|
|
128
|
+
await tx.insertInto(tableName).values(filteredData).execute();
|
|
156
129
|
for (const [key, values] of Object.entries(hasManyData)) {
|
|
157
130
|
const joinTableName = `${tableName}_${toSnakeCase(key)}_relations`.toLowerCase();
|
|
158
131
|
if (values.length > 0) {
|
|
@@ -180,13 +153,13 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
180
153
|
}
|
|
181
154
|
}
|
|
182
155
|
delete blockFlatData.blockType;
|
|
183
|
-
const
|
|
156
|
+
const blockData = {
|
|
184
157
|
...blockFlatData,
|
|
185
158
|
_parent_id: flatData.id,
|
|
186
159
|
_order: i,
|
|
187
160
|
block_type: block.blockType
|
|
188
|
-
}
|
|
189
|
-
await tx.insertInto(blockTableName).values(
|
|
161
|
+
};
|
|
162
|
+
await tx.insertInto(blockTableName).values(blockData).execute();
|
|
190
163
|
}
|
|
191
164
|
}
|
|
192
165
|
return this.findOne(collection, { id: flatData.id }, tx);
|
|
@@ -194,7 +167,7 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
194
167
|
}
|
|
195
168
|
async findOne(collection, query, tx) {
|
|
196
169
|
const tableName = toSnakeCase(collection);
|
|
197
|
-
const executor = tx || this.
|
|
170
|
+
const executor = tx || this.db;
|
|
198
171
|
let qb = executor.selectFrom(tableName).selectAll();
|
|
199
172
|
if (query && Object.keys(query).length > 0) {
|
|
200
173
|
qb = qb.where((eb) => buildKyselyWhere(eb, query) || eb.val(true));
|
|
@@ -205,7 +178,7 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
205
178
|
const unflattened = unflattenRow(row);
|
|
206
179
|
const colDef = this._collections.find((c) => c.slug === collection);
|
|
207
180
|
if (colDef) {
|
|
208
|
-
const { getRelationalFields: getRelationalFields2, toSnakeCase: toSnakeCase2 } = await import("./chunk-
|
|
181
|
+
const { getRelationalFields: getRelationalFields2, toSnakeCase: toSnakeCase2 } = await import("./chunk-fnsf1dfm.js");
|
|
209
182
|
const relationalFields = getRelationalFields2(colDef.fields);
|
|
210
183
|
for (const field of relationalFields) {
|
|
211
184
|
if (!field.name)
|
|
@@ -245,9 +218,17 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
245
218
|
const page = options?.page || 1;
|
|
246
219
|
const limit = options?.limit || 10;
|
|
247
220
|
const offset = (page - 1) * limit;
|
|
221
|
+
const cursorColumn = options?.cursorColumn || "id";
|
|
248
222
|
const total = await this.count(collection, query);
|
|
249
223
|
const tableName = toSnakeCase(collection);
|
|
250
|
-
let qb = this.
|
|
224
|
+
let qb = this.db.selectFrom(tableName).selectAll().limit(limit);
|
|
225
|
+
if (options?.after) {
|
|
226
|
+
qb = qb.where(cursorColumn, ">", options.after);
|
|
227
|
+
} else if (options?.before) {
|
|
228
|
+
qb = qb.where(cursorColumn, "<", options.before);
|
|
229
|
+
} else {
|
|
230
|
+
qb = qb.offset(offset);
|
|
231
|
+
}
|
|
251
232
|
if (query && Object.keys(query).length > 0) {
|
|
252
233
|
qb = qb.where((eb) => buildKyselyWhere(eb, query) || eb.val(true));
|
|
253
234
|
}
|
|
@@ -256,11 +237,13 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
256
237
|
const col = isDesc ? options.sort.substring(1) : options.sort;
|
|
257
238
|
qb = qb.orderBy(col, isDesc ? "desc" : "asc");
|
|
258
239
|
} else {
|
|
259
|
-
qb = qb.orderBy(
|
|
240
|
+
qb = qb.orderBy(cursorColumn, "desc");
|
|
260
241
|
}
|
|
261
242
|
const rows = await qb.execute();
|
|
262
243
|
if (rows.length === 0) {
|
|
263
244
|
const totalPages2 = Math.ceil(total / limit);
|
|
245
|
+
const afterAnchor = options?.after;
|
|
246
|
+
const beforeAnchor = options?.before;
|
|
264
247
|
return {
|
|
265
248
|
docs: [],
|
|
266
249
|
totalDocs: total,
|
|
@@ -268,10 +251,12 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
268
251
|
totalPages: totalPages2,
|
|
269
252
|
page,
|
|
270
253
|
pagingCounter: offset + 1,
|
|
271
|
-
hasNextPage:
|
|
272
|
-
hasPrevPage: page > 1,
|
|
273
|
-
prevPage:
|
|
274
|
-
nextPage:
|
|
254
|
+
hasNextPage: false,
|
|
255
|
+
hasPrevPage: !!afterAnchor || page > 1,
|
|
256
|
+
prevPage: null,
|
|
257
|
+
nextPage: null,
|
|
258
|
+
nextCursor: null,
|
|
259
|
+
prevCursor: afterAnchor ? afterAnchor : null
|
|
275
260
|
};
|
|
276
261
|
}
|
|
277
262
|
const rowIds = rows.map((r) => r.id);
|
|
@@ -286,7 +271,7 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
286
271
|
if (field.type === "relationship" && "hasMany" in field && field.hasMany) {
|
|
287
272
|
const joinTableName = `${toSnakeCase(collection)}_${snakeName}_relations`.toLowerCase();
|
|
288
273
|
try {
|
|
289
|
-
const allRelations = await this.
|
|
274
|
+
const allRelations = await this.db.selectFrom(joinTableName).selectAll().where("source_id", "in", rowIds).orderBy("order", "asc").execute();
|
|
290
275
|
const relationsBySource = allRelations.reduce((acc, r) => {
|
|
291
276
|
if (!acc[r.source_id])
|
|
292
277
|
acc[r.source_id] = [];
|
|
@@ -310,7 +295,7 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
310
295
|
for (const b of field.blocks) {
|
|
311
296
|
const blockTableName = `${collection}_${snakeName}_${toSnakeCase(b.slug)}`.toLowerCase();
|
|
312
297
|
try {
|
|
313
|
-
const allBlocks = await this.
|
|
298
|
+
const allBlocks = await this.db.selectFrom(blockTableName).selectAll().where("_parent_id", "in", rowIds).execute();
|
|
314
299
|
for (const blk of allBlocks) {
|
|
315
300
|
const uf = unflattenRow(blk);
|
|
316
301
|
uf.blockType = blk.block_type;
|
|
@@ -349,14 +334,16 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
349
334
|
page,
|
|
350
335
|
pagingCounter: offset + 1,
|
|
351
336
|
hasNextPage: page * limit < total,
|
|
352
|
-
hasPrevPage: page > 1,
|
|
337
|
+
hasPrevPage: page > 1 || !!options?.after || !!options?.before,
|
|
353
338
|
prevPage: page > 1 ? page - 1 : null,
|
|
354
|
-
nextPage: page < totalPages ? page + 1 : null
|
|
339
|
+
nextPage: page < totalPages ? page + 1 : null,
|
|
340
|
+
nextCursor: docs.length > 0 ? docs[docs.length - 1][cursorColumn] : null,
|
|
341
|
+
prevCursor: docs.length > 0 && (page > 1 || !!options?.after || !!options?.before) ? docs[0][cursorColumn] : null
|
|
355
342
|
};
|
|
356
343
|
}
|
|
357
344
|
async update(collection, query, data) {
|
|
358
345
|
const tableName = toSnakeCase(collection);
|
|
359
|
-
return this.
|
|
346
|
+
return this.db.transaction().execute(async (tx) => {
|
|
360
347
|
let normalizedQuery = query;
|
|
361
348
|
if (typeof query !== "object" || query === null) {
|
|
362
349
|
normalizedQuery = { id: query };
|
|
@@ -364,6 +351,9 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
364
351
|
const current = await this.findOne(collection, normalizedQuery, tx);
|
|
365
352
|
if (!current)
|
|
366
353
|
throw new Error("Document not found");
|
|
354
|
+
const store = requestContext.getStore();
|
|
355
|
+
if (store)
|
|
356
|
+
store.previousData = current;
|
|
367
357
|
const colDef = this._collections.find((c) => c.slug === collection);
|
|
368
358
|
const jsonFields = colDef?.fields.filter((f) => ["richtext", "json", "file"].includes(f.type)).map((f) => f.name) || [];
|
|
369
359
|
const flatData = flattenPayload(data, "", jsonFields);
|
|
@@ -385,10 +375,8 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
385
375
|
delete flatData[key];
|
|
386
376
|
}
|
|
387
377
|
}
|
|
388
|
-
flatData.updated_at = new Date().toISOString();
|
|
389
378
|
if (Object.keys(flatData).length > 0) {
|
|
390
|
-
|
|
391
|
-
await tx.updateTable(tableName).set(coercedData).where("id", "=", current.id).execute();
|
|
379
|
+
await tx.updateTable(tableName).set(flatData).where("id", "=", current.id).execute();
|
|
392
380
|
}
|
|
393
381
|
for (const [key, values] of Object.entries(hasManyData)) {
|
|
394
382
|
const joinTableName = `${tableName}_${toSnakeCase(key)}_relations`.toLowerCase();
|
|
@@ -426,13 +414,13 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
426
414
|
}
|
|
427
415
|
}
|
|
428
416
|
delete blockFlatData.blockType;
|
|
429
|
-
const
|
|
417
|
+
const blockData = {
|
|
430
418
|
...blockFlatData,
|
|
431
419
|
_parent_id: current.id,
|
|
432
420
|
_order: i,
|
|
433
421
|
block_type: block.blockType
|
|
434
|
-
}
|
|
435
|
-
await tx.insertInto(blockTableName).values(
|
|
422
|
+
};
|
|
423
|
+
await tx.insertInto(blockTableName).values(blockData).execute();
|
|
436
424
|
}
|
|
437
425
|
}
|
|
438
426
|
return this.findOne(collection, { id: current.id }, tx);
|
|
@@ -447,7 +435,7 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
447
435
|
const current = await this.findOne(collection, normalizedQuery);
|
|
448
436
|
if (!current)
|
|
449
437
|
return false;
|
|
450
|
-
await this.
|
|
438
|
+
await this.db.transaction().execute(async (tx) => {
|
|
451
439
|
const colDef = this._collections.find((c) => c.slug === collection);
|
|
452
440
|
if (colDef) {
|
|
453
441
|
for (const field of colDef.fields) {
|
|
@@ -473,7 +461,7 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
473
461
|
}
|
|
474
462
|
async updateMany(collection, query, data) {
|
|
475
463
|
const tableName = toSnakeCase(collection);
|
|
476
|
-
return this.
|
|
464
|
+
return this.db.transaction().execute(async (tx) => {
|
|
477
465
|
let qb = tx.updateTable(tableName);
|
|
478
466
|
if (query && Object.keys(query).length > 0) {
|
|
479
467
|
qb = qb.where((eb) => buildKyselyWhere(eb, query) || eb.val(true));
|
|
@@ -491,10 +479,8 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
491
479
|
delete flatData[key];
|
|
492
480
|
}
|
|
493
481
|
}
|
|
494
|
-
flatData.updated_at = new Date().toISOString();
|
|
495
482
|
if (Object.keys(flatData).length > 0) {
|
|
496
|
-
const
|
|
497
|
-
const result = await qb.set(coercedData).executeTakeFirst();
|
|
483
|
+
const result = await qb.set(flatData).executeTakeFirst();
|
|
498
484
|
return Number(result.numUpdatedRows || 0);
|
|
499
485
|
}
|
|
500
486
|
return 0;
|
|
@@ -502,7 +488,7 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
502
488
|
}
|
|
503
489
|
async deleteMany(collection, query) {
|
|
504
490
|
const tableName = toSnakeCase(collection);
|
|
505
|
-
return this.
|
|
491
|
+
return this.db.transaction().execute(async (tx) => {
|
|
506
492
|
let selectQb = tx.selectFrom(tableName).select("id");
|
|
507
493
|
if (query && Object.keys(query).length > 0) {
|
|
508
494
|
selectQb = selectQb.where((eb) => buildKyselyWhere(eb, query) || eb.val(true));
|
|
@@ -536,7 +522,7 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
536
522
|
}
|
|
537
523
|
async findGlobal(slug) {
|
|
538
524
|
const tableName = toSnakeCase(slug);
|
|
539
|
-
const row = await this.
|
|
525
|
+
const row = await this.db.selectFrom(tableName).selectAll().limit(1).executeTakeFirst();
|
|
540
526
|
return row ? unflattenRow(row) : null;
|
|
541
527
|
}
|
|
542
528
|
async updateGlobal(slug, data) {
|
|
@@ -550,15 +536,15 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
550
536
|
if (!flatData.id)
|
|
551
537
|
flatData.id = "global";
|
|
552
538
|
flatData[toSnakeCase("createdAt")] = now;
|
|
553
|
-
await this.
|
|
539
|
+
await this.db.insertInto(tableName).values(flatData).execute();
|
|
554
540
|
} else {
|
|
555
|
-
await this.
|
|
541
|
+
await this.db.updateTable(tableName).set(flatData).where("id", "=", existing.id).execute();
|
|
556
542
|
}
|
|
557
543
|
return this.findGlobal(slug);
|
|
558
544
|
}
|
|
559
545
|
async runMigrations() {
|
|
560
546
|
const migrator = new Migrator({
|
|
561
|
-
db: this.
|
|
547
|
+
db: this.db,
|
|
562
548
|
provider: new FileMigrationProvider({
|
|
563
549
|
fs,
|
|
564
550
|
path,
|
|
@@ -581,7 +567,7 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
581
567
|
this._collections = collections;
|
|
582
568
|
this._globals = globals;
|
|
583
569
|
if (this.push) {
|
|
584
|
-
await pushSchema(this.
|
|
570
|
+
await pushSchema(this.db, "sqlite", collections, globals, {
|
|
585
571
|
pushDestructive: this.pushDestructive
|
|
586
572
|
});
|
|
587
573
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// src/utils/context.ts
|
|
2
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3
|
+
var GLOBAL_CONTEXT_KEY = Symbol.for("opacacms.requestContext");
|
|
4
|
+
if (!globalThis[GLOBAL_CONTEXT_KEY]) {
|
|
5
|
+
globalThis[GLOBAL_CONTEXT_KEY] = new AsyncLocalStorage;
|
|
6
|
+
}
|
|
7
|
+
var requestContext = globalThis[GLOBAL_CONTEXT_KEY];
|
|
8
|
+
function getUserIdFromContext() {
|
|
9
|
+
return requestContext.getStore()?.userId || null;
|
|
10
|
+
}
|
|
11
|
+
function getPreviousDataFromContext() {
|
|
12
|
+
return requestContext.getStore()?.previousData || null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export { requestContext, getUserIdFromContext, getPreviousDataFromContext };
|