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