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
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import {
|
|
2
|
+
require_picocolors
|
|
3
|
+
} from "./chunk-rwqwsanx.js";
|
|
4
|
+
import {
|
|
5
|
+
Ct,
|
|
6
|
+
Nt,
|
|
7
|
+
R,
|
|
8
|
+
Vt,
|
|
9
|
+
Zt
|
|
10
|
+
} from "./chunk-ec4jhybj.js";
|
|
11
|
+
import {
|
|
12
|
+
defineCommand
|
|
13
|
+
} from "./chunk-1qm0m8r8.js";
|
|
14
|
+
import {
|
|
15
|
+
__toESM
|
|
16
|
+
} from "./chunk-6bywt602.js";
|
|
17
|
+
|
|
18
|
+
// src/cli/commands/generate.ts
|
|
19
|
+
import fs2 from "node:fs";
|
|
20
|
+
import { resolve as resolve2 } from "node:path";
|
|
21
|
+
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
22
|
+
|
|
23
|
+
// src/cli/core/types/generate-types.ts
|
|
24
|
+
import fs from "node:fs";
|
|
25
|
+
import { resolve } from "node:path";
|
|
26
|
+
async function generateTypesCommand(url, token, out) {
|
|
27
|
+
console.log(`[OpacaCMS] Fetching metadata from ${url}/api/__admin/metadata...`);
|
|
28
|
+
let data;
|
|
29
|
+
try {
|
|
30
|
+
const res = await fetch(`${url.replace(/\/$/, "")}/api/__admin/metadata`, {
|
|
31
|
+
headers: {
|
|
32
|
+
Authorization: `Bearer ${token}`
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
if (!res.ok) {
|
|
36
|
+
if (res.status === 401 || res.status === 403) {
|
|
37
|
+
throw new Error("Authentication failed. Ensure your API Key is correct and has the necessary permissions.");
|
|
38
|
+
}
|
|
39
|
+
const errorText = await res.text().catch(() => "Unknown error");
|
|
40
|
+
throw new Error(`Server responded with ${res.status}: ${errorText}`);
|
|
41
|
+
}
|
|
42
|
+
data = await res.json();
|
|
43
|
+
} catch (err) {
|
|
44
|
+
console.error(`[OpacaCMS] Failed to fetch metadata: ${err.message}`);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
console.log(`[OpacaCMS] Successfully fetched metadata for ${data.collections.length} collections and ${data.globals?.length || 0} globals.`);
|
|
48
|
+
let dtsContent = `// Automatically generated by OpacaCMS CLI
|
|
49
|
+
// Do not edit this file manually
|
|
50
|
+
|
|
51
|
+
export interface OpacaAsset {
|
|
52
|
+
assetId: string;
|
|
53
|
+
url: string;
|
|
54
|
+
filename: string;
|
|
55
|
+
mime_type: string;
|
|
56
|
+
filesize: number;
|
|
57
|
+
meta?: Record<string, any>;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface OpacaCollections {
|
|
61
|
+
collections: {
|
|
62
|
+
`;
|
|
63
|
+
for (const collection of data.collections) {
|
|
64
|
+
dtsContent += ` "${collection.slug}": {
|
|
65
|
+
`;
|
|
66
|
+
dtsContent += ` id: string | number;
|
|
67
|
+
`;
|
|
68
|
+
for (const field of collection.fields) {
|
|
69
|
+
const typeStr = mapFieldToTsType(field.type);
|
|
70
|
+
const isOptional = field.required ? "" : "?";
|
|
71
|
+
dtsContent += ` ${field.name}${isOptional}: ${typeStr};
|
|
72
|
+
`;
|
|
73
|
+
}
|
|
74
|
+
if (collection.timestamps) {
|
|
75
|
+
dtsContent += ` createdAt: string;
|
|
76
|
+
`;
|
|
77
|
+
dtsContent += ` updatedAt: string;
|
|
78
|
+
`;
|
|
79
|
+
}
|
|
80
|
+
dtsContent += ` };
|
|
81
|
+
`;
|
|
82
|
+
}
|
|
83
|
+
dtsContent += ` };
|
|
84
|
+
`;
|
|
85
|
+
if (data.globals && data.globals.length > 0) {
|
|
86
|
+
dtsContent += ` globals: {
|
|
87
|
+
`;
|
|
88
|
+
for (const globalConf of data.globals) {
|
|
89
|
+
dtsContent += ` "${globalConf.slug}": {
|
|
90
|
+
`;
|
|
91
|
+
for (const field of globalConf.fields) {
|
|
92
|
+
const typeStr = mapFieldToTsType(field.type);
|
|
93
|
+
const isOptional = field.required ? "" : "?";
|
|
94
|
+
dtsContent += ` ${field.name}${isOptional}: ${typeStr};
|
|
95
|
+
`;
|
|
96
|
+
}
|
|
97
|
+
dtsContent += ` };
|
|
98
|
+
`;
|
|
99
|
+
}
|
|
100
|
+
dtsContent += ` };
|
|
101
|
+
`;
|
|
102
|
+
} else {
|
|
103
|
+
dtsContent += ` globals: Record<string, any>;
|
|
104
|
+
`;
|
|
105
|
+
}
|
|
106
|
+
dtsContent += `}
|
|
107
|
+
`;
|
|
108
|
+
const outputPath = resolve(process.cwd(), out || "opaca.d.ts");
|
|
109
|
+
fs.writeFileSync(outputPath, dtsContent);
|
|
110
|
+
console.log(`[OpacaCMS] Types successfully generated at ${outputPath}`);
|
|
111
|
+
}
|
|
112
|
+
function mapFieldToTsType(type) {
|
|
113
|
+
switch (type) {
|
|
114
|
+
case "text":
|
|
115
|
+
case "textarea":
|
|
116
|
+
case "richtext":
|
|
117
|
+
case "select":
|
|
118
|
+
case "date":
|
|
119
|
+
return "string";
|
|
120
|
+
case "number":
|
|
121
|
+
return "number";
|
|
122
|
+
case "boolean":
|
|
123
|
+
return "boolean";
|
|
124
|
+
case "json":
|
|
125
|
+
return "any | any[]";
|
|
126
|
+
case "file":
|
|
127
|
+
return "OpacaAsset";
|
|
128
|
+
case "relationship":
|
|
129
|
+
return "string | number | any";
|
|
130
|
+
default:
|
|
131
|
+
return "any";
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// src/cli/commands/generate.ts
|
|
136
|
+
var generate_default = defineCommand({
|
|
137
|
+
meta: {
|
|
138
|
+
name: "generate",
|
|
139
|
+
description: "Generate boilerplates (collections/globals) or TypeScript definitions"
|
|
140
|
+
},
|
|
141
|
+
args: {
|
|
142
|
+
type: {
|
|
143
|
+
type: "positional",
|
|
144
|
+
description: "What to generate: 'types', 'collection', or 'global'",
|
|
145
|
+
required: true
|
|
146
|
+
},
|
|
147
|
+
name: {
|
|
148
|
+
type: "positional",
|
|
149
|
+
description: "The name of the collection or global to generate (if applicable)",
|
|
150
|
+
required: false
|
|
151
|
+
},
|
|
152
|
+
url: {
|
|
153
|
+
type: "string",
|
|
154
|
+
description: "The URL of the OpacaCMS instance (for 'types')"
|
|
155
|
+
},
|
|
156
|
+
token: {
|
|
157
|
+
type: "string",
|
|
158
|
+
description: "The API Key to use for fetching metadata (for 'types')"
|
|
159
|
+
},
|
|
160
|
+
out: {
|
|
161
|
+
type: "string",
|
|
162
|
+
alias: "o",
|
|
163
|
+
description: "The output file path (for 'types')"
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
async run({ args }) {
|
|
167
|
+
if (args.type === "types") {
|
|
168
|
+
if (!args.url || !args.token) {
|
|
169
|
+
R.error(import_picocolors.default.red("URL and Token are required to generate types from a remote instance."));
|
|
170
|
+
R.info("Usage: opacacms generate types --url <url> --token <token> [--out <file>]");
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
await generateTypesCommand(args.url, args.token, args.out || "opaca.d.ts");
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (args.type === "collection" || args.type === "global") {
|
|
177
|
+
let name = args.name;
|
|
178
|
+
if (!name) {
|
|
179
|
+
const response = await Zt({
|
|
180
|
+
message: `What should we name your ${args.type}? (e.g. ${args.type === "collection" ? "posts" : "site-settings"})`
|
|
181
|
+
});
|
|
182
|
+
if (Ct(response)) {
|
|
183
|
+
Nt("Operation cancelled.");
|
|
184
|
+
process.exit(0);
|
|
185
|
+
}
|
|
186
|
+
name = response;
|
|
187
|
+
}
|
|
188
|
+
const isCollection = args.type === "collection";
|
|
189
|
+
const folderName = isCollection ? "collections" : "globals";
|
|
190
|
+
const fileName = `${name}.ts`;
|
|
191
|
+
const filePath = resolve2(process.cwd(), folderName, fileName);
|
|
192
|
+
if (fs2.existsSync(filePath)) {
|
|
193
|
+
R.error(import_picocolors.default.red(`File already exists at ${folderName}/${fileName}`));
|
|
194
|
+
process.exit(1);
|
|
195
|
+
}
|
|
196
|
+
fs2.mkdirSync(resolve2(process.cwd(), folderName), { recursive: true });
|
|
197
|
+
const template = isCollection ? `import { z, defineCollection } from 'opacacms/schema';
|
|
198
|
+
|
|
199
|
+
export const ${name} = defineCollection({
|
|
200
|
+
slug: '${name}',
|
|
201
|
+
label: '${name.charAt(0).toUpperCase() + name.slice(1)}',
|
|
202
|
+
admin: {
|
|
203
|
+
useAsTitle: 'title',
|
|
204
|
+
icon: 'FileText'
|
|
205
|
+
},
|
|
206
|
+
schema: z.object({
|
|
207
|
+
id: z.text().default(() => crypto.randomUUID()),
|
|
208
|
+
title: z.text({ label: 'Title' }).required(),
|
|
209
|
+
content: z.richText({ label: 'Content' }),
|
|
210
|
+
})
|
|
211
|
+
});
|
|
212
|
+
` : `import { z, defineGlobal } from 'opacacms/schema';
|
|
213
|
+
|
|
214
|
+
export const ${name} = defineGlobal({
|
|
215
|
+
slug: '${name}',
|
|
216
|
+
label: '${name.charAt(0).toUpperCase() + name.slice(1)}',
|
|
217
|
+
admin: {
|
|
218
|
+
icon: 'Settings'
|
|
219
|
+
},
|
|
220
|
+
schema: z.object({
|
|
221
|
+
siteName: z.text({ label: 'Site Name' }).required(),
|
|
222
|
+
description: z.textarea({ label: 'Description' }),
|
|
223
|
+
})
|
|
224
|
+
});
|
|
225
|
+
`;
|
|
226
|
+
fs2.writeFileSync(filePath, template);
|
|
227
|
+
R.success(import_picocolors.default.green(`Successfully generated ${args.type} at ./${folderName}/${fileName}`));
|
|
228
|
+
Vt(`Don't forget to import it into your opacacms.config.ts and add it to the '${folderName}' array!`, "Reminder");
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
R.error(import_picocolors.default.red(`Unknown generation type: ${args.type}. Use 'types', 'collection', or 'global'.`));
|
|
232
|
+
process.exit(1);
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
export {
|
|
236
|
+
generate_default as default
|
|
237
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import {
|
|
2
|
+
init_compiler,
|
|
3
|
+
init_zod,
|
|
4
|
+
zodToOpacaFields
|
|
5
|
+
} from "./chunk-m5ems3hh.js";
|
|
6
|
+
|
|
7
|
+
// src/schema/collection.ts
|
|
8
|
+
init_compiler();
|
|
9
|
+
function defineCollection(config) {
|
|
10
|
+
const compiledSchema = config.schema.meta({
|
|
11
|
+
opaca: {
|
|
12
|
+
collectionConfig: {
|
|
13
|
+
slug: config.slug,
|
|
14
|
+
label: config.label,
|
|
15
|
+
useAsTitle: config.admin?.useAsTitle
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
return {
|
|
20
|
+
...config,
|
|
21
|
+
schema: compiledSchema,
|
|
22
|
+
fields: zodToOpacaFields(compiledSchema),
|
|
23
|
+
seed: config.seed,
|
|
24
|
+
__type: null
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// src/schema/index.ts
|
|
29
|
+
init_compiler();
|
|
30
|
+
|
|
31
|
+
// src/schema/global.ts
|
|
32
|
+
init_compiler();
|
|
33
|
+
function defineGlobal(config) {
|
|
34
|
+
const compiledSchema = config.schema.meta({
|
|
35
|
+
opaca: {
|
|
36
|
+
globalConfig: {
|
|
37
|
+
slug: config.slug,
|
|
38
|
+
label: config.label
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
return {
|
|
43
|
+
...config,
|
|
44
|
+
schema: compiledSchema,
|
|
45
|
+
fields: zodToOpacaFields(compiledSchema),
|
|
46
|
+
seed: config.seed,
|
|
47
|
+
__type: null
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// src/schema/index.ts
|
|
52
|
+
init_zod();
|
|
53
|
+
|
|
54
|
+
export { defineCollection, defineGlobal };
|
|
@@ -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,20 @@ 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 {
|
|
28
|
+
import {
|
|
29
|
+
CompiledQuery,
|
|
30
|
+
FileMigrationProvider,
|
|
31
|
+
Migrator,
|
|
32
|
+
SqliteDialect
|
|
33
|
+
} from "kysely";
|
|
26
34
|
class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
27
35
|
path;
|
|
28
36
|
name = "better-sqlite3";
|
|
@@ -55,10 +63,16 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
55
63
|
const require2 = createRequire(import.meta.url);
|
|
56
64
|
const Database = require2("better-sqlite3");
|
|
57
65
|
this._rawDb = new Database(this.path);
|
|
58
|
-
|
|
66
|
+
const { createOpacaKysely } = await import("./chunk-sqsfk9p4.js");
|
|
67
|
+
this._db = createOpacaKysely({
|
|
59
68
|
dialect: new SqliteDialect({
|
|
60
69
|
database: this._rawDb
|
|
61
|
-
})
|
|
70
|
+
}),
|
|
71
|
+
config: {
|
|
72
|
+
collections: this._collections,
|
|
73
|
+
globals: this._globals,
|
|
74
|
+
db: { name: "better-sqlite3" }
|
|
75
|
+
}
|
|
62
76
|
});
|
|
63
77
|
}
|
|
64
78
|
async disconnect() {
|
|
@@ -72,45 +86,6 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
72
86
|
const result = await this.db.executeQuery(compiled);
|
|
73
87
|
return result.rows;
|
|
74
88
|
}
|
|
75
|
-
async coerceData(collection, data) {
|
|
76
|
-
const colDef = this._collections.find((c) => c.slug === collection);
|
|
77
|
-
if (!colDef)
|
|
78
|
-
return data;
|
|
79
|
-
const result = { ...data };
|
|
80
|
-
const { flattenFields: flattenFields2 } = await import("./chunk-526a3gqx.js");
|
|
81
|
-
const allFields = flattenFields2(colDef.fields);
|
|
82
|
-
for (const field of allFields) {
|
|
83
|
-
const colName = toSnakeCase(field.name);
|
|
84
|
-
if (!(colName in result))
|
|
85
|
-
continue;
|
|
86
|
-
const value = result[colName];
|
|
87
|
-
if (value === undefined || value === null)
|
|
88
|
-
continue;
|
|
89
|
-
switch (field.type) {
|
|
90
|
-
case "boolean":
|
|
91
|
-
result[colName] = value ? 1 : 0;
|
|
92
|
-
break;
|
|
93
|
-
case "number":
|
|
94
|
-
result[colName] = Number(value);
|
|
95
|
-
break;
|
|
96
|
-
case "date":
|
|
97
|
-
if (value instanceof Date) {
|
|
98
|
-
result[colName] = value.toISOString();
|
|
99
|
-
} else if (typeof value === "string") {
|
|
100
|
-
result[colName] = new Date(value).toISOString();
|
|
101
|
-
}
|
|
102
|
-
break;
|
|
103
|
-
case "richtext":
|
|
104
|
-
case "json":
|
|
105
|
-
case "file":
|
|
106
|
-
if (typeof value === "object") {
|
|
107
|
-
result[colName] = JSON.stringify(value);
|
|
108
|
-
}
|
|
109
|
-
break;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
return result;
|
|
113
|
-
}
|
|
114
89
|
async count(collection, query) {
|
|
115
90
|
const tableName = toSnakeCase(collection);
|
|
116
91
|
let qb = this.db.selectFrom(tableName).select((eb) => eb.fn.count("id").as("count"));
|
|
@@ -124,13 +99,8 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
124
99
|
const tableName = toSnakeCase(collection);
|
|
125
100
|
return this.db.transaction().execute(async (tx) => {
|
|
126
101
|
const colDef = this._collections.find((c) => c.slug === collection);
|
|
127
|
-
const
|
|
128
|
-
const
|
|
129
|
-
for (const field of jsonFields) {
|
|
130
|
-
if (flatData[field] && typeof flatData[field] === "object") {
|
|
131
|
-
flatData[field] = JSON.stringify(flatData[field]);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
102
|
+
const flatData = flattenPayload(data);
|
|
103
|
+
const relationalFields = getRelationalFields(colDef?.fields || []);
|
|
134
104
|
const hasManyData = {};
|
|
135
105
|
const blocksData = {};
|
|
136
106
|
for (const key in flatData) {
|
|
@@ -144,24 +114,18 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
144
114
|
delete flatData[key];
|
|
145
115
|
}
|
|
146
116
|
}
|
|
147
|
-
if (!flatData.id)
|
|
148
|
-
flatData.id = crypto.randomUUID();
|
|
149
117
|
const dbFields = flattenFields(colDef?.fields || []);
|
|
150
118
|
const validCols = new Set(dbFields.map((f) => toSnakeCase(f.name)));
|
|
151
119
|
validCols.add("id");
|
|
152
120
|
validCols.add(toSnakeCase("createdAt"));
|
|
153
121
|
validCols.add(toSnakeCase("updatedAt"));
|
|
154
|
-
const now = new Date().toISOString();
|
|
155
|
-
flatData[toSnakeCase("createdAt")] = now;
|
|
156
|
-
flatData[toSnakeCase("updatedAt")] = now;
|
|
157
122
|
const filteredData = {};
|
|
158
123
|
for (const col of Object.keys(flatData)) {
|
|
159
124
|
if (validCols.has(col)) {
|
|
160
125
|
filteredData[col] = flatData[col];
|
|
161
126
|
}
|
|
162
127
|
}
|
|
163
|
-
|
|
164
|
-
await tx.insertInto(tableName).values(coercedData).execute();
|
|
128
|
+
await tx.insertInto(tableName).values(filteredData).execute();
|
|
165
129
|
for (const [key, values] of Object.entries(hasManyData)) {
|
|
166
130
|
const joinTableName = `${tableName}_${toSnakeCase(key)}_relations`.toLowerCase();
|
|
167
131
|
if (values.length > 0) {
|
|
@@ -189,13 +153,13 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
189
153
|
}
|
|
190
154
|
}
|
|
191
155
|
delete blockFlatData.blockType;
|
|
192
|
-
const
|
|
156
|
+
const blockData = {
|
|
193
157
|
...blockFlatData,
|
|
194
158
|
_parent_id: flatData.id,
|
|
195
159
|
_order: i,
|
|
196
160
|
block_type: block.blockType
|
|
197
|
-
}
|
|
198
|
-
await tx.insertInto(blockTableName).values(
|
|
161
|
+
};
|
|
162
|
+
await tx.insertInto(blockTableName).values(blockData).execute();
|
|
199
163
|
}
|
|
200
164
|
}
|
|
201
165
|
return this.findOne(collection, { id: flatData.id }, tx);
|
|
@@ -214,7 +178,7 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
214
178
|
const unflattened = unflattenRow(row);
|
|
215
179
|
const colDef = this._collections.find((c) => c.slug === collection);
|
|
216
180
|
if (colDef) {
|
|
217
|
-
const { getRelationalFields: getRelationalFields2, toSnakeCase: toSnakeCase2 } = await import("./chunk-
|
|
181
|
+
const { getRelationalFields: getRelationalFields2, toSnakeCase: toSnakeCase2 } = await import("./chunk-fnsf1dfm.js");
|
|
218
182
|
const relationalFields = getRelationalFields2(colDef.fields);
|
|
219
183
|
for (const field of relationalFields) {
|
|
220
184
|
if (!field.name)
|
|
@@ -254,9 +218,17 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
254
218
|
const page = options?.page || 1;
|
|
255
219
|
const limit = options?.limit || 10;
|
|
256
220
|
const offset = (page - 1) * limit;
|
|
221
|
+
const cursorColumn = options?.cursorColumn || "id";
|
|
257
222
|
const total = await this.count(collection, query);
|
|
258
223
|
const tableName = toSnakeCase(collection);
|
|
259
|
-
let qb = this.db.selectFrom(tableName).selectAll().limit(limit)
|
|
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
|
+
}
|
|
260
232
|
if (query && Object.keys(query).length > 0) {
|
|
261
233
|
qb = qb.where((eb) => buildKyselyWhere(eb, query) || eb.val(true));
|
|
262
234
|
}
|
|
@@ -265,11 +237,13 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
265
237
|
const col = isDesc ? options.sort.substring(1) : options.sort;
|
|
266
238
|
qb = qb.orderBy(col, isDesc ? "desc" : "asc");
|
|
267
239
|
} else {
|
|
268
|
-
qb = qb.orderBy(
|
|
240
|
+
qb = qb.orderBy(cursorColumn, "desc");
|
|
269
241
|
}
|
|
270
242
|
const rows = await qb.execute();
|
|
271
243
|
if (rows.length === 0) {
|
|
272
244
|
const totalPages2 = Math.ceil(total / limit);
|
|
245
|
+
const afterAnchor = options?.after;
|
|
246
|
+
const beforeAnchor = options?.before;
|
|
273
247
|
return {
|
|
274
248
|
docs: [],
|
|
275
249
|
totalDocs: total,
|
|
@@ -277,10 +251,12 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
277
251
|
totalPages: totalPages2,
|
|
278
252
|
page,
|
|
279
253
|
pagingCounter: offset + 1,
|
|
280
|
-
hasNextPage:
|
|
281
|
-
hasPrevPage: page > 1,
|
|
282
|
-
prevPage:
|
|
283
|
-
nextPage:
|
|
254
|
+
hasNextPage: false,
|
|
255
|
+
hasPrevPage: !!afterAnchor || page > 1,
|
|
256
|
+
prevPage: null,
|
|
257
|
+
nextPage: null,
|
|
258
|
+
nextCursor: null,
|
|
259
|
+
prevCursor: afterAnchor ? afterAnchor : null
|
|
284
260
|
};
|
|
285
261
|
}
|
|
286
262
|
const rowIds = rows.map((r) => r.id);
|
|
@@ -358,9 +334,11 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
358
334
|
page,
|
|
359
335
|
pagingCounter: offset + 1,
|
|
360
336
|
hasNextPage: page * limit < total,
|
|
361
|
-
hasPrevPage: page > 1,
|
|
337
|
+
hasPrevPage: page > 1 || !!options?.after || !!options?.before,
|
|
362
338
|
prevPage: page > 1 ? page - 1 : null,
|
|
363
|
-
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
|
|
364
342
|
};
|
|
365
343
|
}
|
|
366
344
|
async update(collection, query, data) {
|
|
@@ -373,6 +351,9 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
373
351
|
const current = await this.findOne(collection, normalizedQuery, tx);
|
|
374
352
|
if (!current)
|
|
375
353
|
throw new Error("Document not found");
|
|
354
|
+
const store = requestContext.getStore();
|
|
355
|
+
if (store)
|
|
356
|
+
store.previousData = current;
|
|
376
357
|
const colDef = this._collections.find((c) => c.slug === collection);
|
|
377
358
|
const jsonFields = colDef?.fields.filter((f) => ["richtext", "json", "file"].includes(f.type)).map((f) => f.name) || [];
|
|
378
359
|
const flatData = flattenPayload(data, "", jsonFields);
|
|
@@ -394,10 +375,8 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
394
375
|
delete flatData[key];
|
|
395
376
|
}
|
|
396
377
|
}
|
|
397
|
-
flatData.updated_at = new Date().toISOString();
|
|
398
378
|
if (Object.keys(flatData).length > 0) {
|
|
399
|
-
|
|
400
|
-
await tx.updateTable(tableName).set(coercedData).where("id", "=", current.id).execute();
|
|
379
|
+
await tx.updateTable(tableName).set(flatData).where("id", "=", current.id).execute();
|
|
401
380
|
}
|
|
402
381
|
for (const [key, values] of Object.entries(hasManyData)) {
|
|
403
382
|
const joinTableName = `${tableName}_${toSnakeCase(key)}_relations`.toLowerCase();
|
|
@@ -435,13 +414,13 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
435
414
|
}
|
|
436
415
|
}
|
|
437
416
|
delete blockFlatData.blockType;
|
|
438
|
-
const
|
|
417
|
+
const blockData = {
|
|
439
418
|
...blockFlatData,
|
|
440
419
|
_parent_id: current.id,
|
|
441
420
|
_order: i,
|
|
442
421
|
block_type: block.blockType
|
|
443
|
-
}
|
|
444
|
-
await tx.insertInto(blockTableName).values(
|
|
422
|
+
};
|
|
423
|
+
await tx.insertInto(blockTableName).values(blockData).execute();
|
|
445
424
|
}
|
|
446
425
|
}
|
|
447
426
|
return this.findOne(collection, { id: current.id }, tx);
|
|
@@ -500,10 +479,8 @@ class BetterSQLiteAdapter extends BaseDatabaseAdapter {
|
|
|
500
479
|
delete flatData[key];
|
|
501
480
|
}
|
|
502
481
|
}
|
|
503
|
-
flatData.updated_at = new Date().toISOString();
|
|
504
482
|
if (Object.keys(flatData).length > 0) {
|
|
505
|
-
const
|
|
506
|
-
const result = await qb.set(coercedData).executeTakeFirst();
|
|
483
|
+
const result = await qb.set(flatData).executeTakeFirst();
|
|
507
484
|
return Number(result.numUpdatedRows || 0);
|
|
508
485
|
}
|
|
509
486
|
return 0;
|
|
@@ -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 };
|