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,221 @@
|
|
|
1
|
+
import {
|
|
2
|
+
require_picocolors
|
|
3
|
+
} from "./chunk-rwqwsanx.js";
|
|
4
|
+
import {
|
|
5
|
+
Ct,
|
|
6
|
+
Gt,
|
|
7
|
+
Jt,
|
|
8
|
+
Nt,
|
|
9
|
+
Rt,
|
|
10
|
+
Vt,
|
|
11
|
+
Wt,
|
|
12
|
+
Zt,
|
|
13
|
+
be
|
|
14
|
+
} from "./chunk-ec4jhybj.js";
|
|
15
|
+
import {
|
|
16
|
+
defineCommand
|
|
17
|
+
} from "./chunk-1qm0m8r8.js";
|
|
18
|
+
import {
|
|
19
|
+
__toESM
|
|
20
|
+
} from "./chunk-6bywt602.js";
|
|
21
|
+
|
|
22
|
+
// src/cli/commands/init.ts
|
|
23
|
+
import fs from "node:fs";
|
|
24
|
+
import { resolve } from "node:path";
|
|
25
|
+
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
26
|
+
var init_default = defineCommand({
|
|
27
|
+
meta: {
|
|
28
|
+
name: "init",
|
|
29
|
+
description: "Initialize a new OpacaCMS project"
|
|
30
|
+
},
|
|
31
|
+
args: {
|
|
32
|
+
target: {
|
|
33
|
+
type: "positional",
|
|
34
|
+
description: "Target directory name",
|
|
35
|
+
required: false
|
|
36
|
+
},
|
|
37
|
+
example: {
|
|
38
|
+
type: "string",
|
|
39
|
+
alias: "e",
|
|
40
|
+
description: "Use an example template"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
async run({ args }) {
|
|
44
|
+
console.log();
|
|
45
|
+
Wt(import_picocolors.default.bgBlue(import_picocolors.default.white(" Welcome to OpacaCMS! ")));
|
|
46
|
+
let target = args.target;
|
|
47
|
+
if (!target) {
|
|
48
|
+
const response = await Zt({
|
|
49
|
+
message: "Where should we create your project?",
|
|
50
|
+
placeholder: "my-opaca-app",
|
|
51
|
+
defaultValue: "my-opaca-app"
|
|
52
|
+
});
|
|
53
|
+
if (Ct(response)) {
|
|
54
|
+
Nt("Operation cancelled.");
|
|
55
|
+
process.exit(0);
|
|
56
|
+
}
|
|
57
|
+
target = response;
|
|
58
|
+
}
|
|
59
|
+
if (args.example) {
|
|
60
|
+
const s2 = be();
|
|
61
|
+
s2.start(`Using example template: ${args.example}`);
|
|
62
|
+
let currentDir = resolve(import.meta.dirname);
|
|
63
|
+
let exampleDir = "";
|
|
64
|
+
const localExample = resolve(process.cwd(), "examples", args.example);
|
|
65
|
+
if (fs.existsSync(localExample)) {
|
|
66
|
+
exampleDir = localExample;
|
|
67
|
+
} else {
|
|
68
|
+
while (currentDir !== resolve(currentDir, "..")) {
|
|
69
|
+
const potential = resolve(currentDir, "examples", args.example);
|
|
70
|
+
if (fs.existsSync(potential)) {
|
|
71
|
+
exampleDir = potential;
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
currentDir = resolve(currentDir, "..");
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (!exampleDir) {
|
|
78
|
+
s2.stop(`Example ${args.example} not found.`);
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
fs.cpSync(exampleDir, resolve(process.cwd(), target), { recursive: true });
|
|
82
|
+
s2.stop(`Copied example ${args.example} to ${target}!`);
|
|
83
|
+
Gt(`Run ${import_picocolors.default.cyan(`cd ${target} && bun install`)} to get started.`);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const dbType = await Jt({
|
|
87
|
+
message: "Which database would you like to use?",
|
|
88
|
+
options: [
|
|
89
|
+
{ value: "sqlite", label: "SQLite (Local/Bun)" },
|
|
90
|
+
{ value: "d1", label: "Cloudflare D1" },
|
|
91
|
+
{ value: "postgres", label: "PostgreSQL" }
|
|
92
|
+
],
|
|
93
|
+
initialValue: "sqlite"
|
|
94
|
+
});
|
|
95
|
+
if (Ct(dbType)) {
|
|
96
|
+
Nt("Operation cancelled.");
|
|
97
|
+
process.exit(0);
|
|
98
|
+
}
|
|
99
|
+
const useAuth = await Rt({
|
|
100
|
+
message: "Enable Authentication (Better Auth)?",
|
|
101
|
+
initialValue: true
|
|
102
|
+
});
|
|
103
|
+
if (Ct(useAuth)) {
|
|
104
|
+
Nt("Operation cancelled.");
|
|
105
|
+
process.exit(0);
|
|
106
|
+
}
|
|
107
|
+
const s = be();
|
|
108
|
+
s.start(`Generating boilerplate in ./${target}...`);
|
|
109
|
+
fs.mkdirSync(resolve(process.cwd(), target), { recursive: true });
|
|
110
|
+
let dbImport = "";
|
|
111
|
+
let dbInit = "";
|
|
112
|
+
if (dbType === "sqlite") {
|
|
113
|
+
dbImport = `import { createSQLiteAdapter } from 'opacacms/db/sqlite';`;
|
|
114
|
+
dbInit = `createSQLiteAdapter('local.db')`;
|
|
115
|
+
} else if (dbType === "d1") {
|
|
116
|
+
dbImport = `import { createD1Adapter } from 'opacacms/db/d1';`;
|
|
117
|
+
dbInit = `createD1Adapter(env.DB)`;
|
|
118
|
+
} else if (dbType === "postgres") {
|
|
119
|
+
dbImport = `import { createPostgresAdapter } from 'opacacms/db/postgres';`;
|
|
120
|
+
dbInit = `createPostgresAdapter(process.env.DATABASE_URL!)`;
|
|
121
|
+
}
|
|
122
|
+
let authConfig = "";
|
|
123
|
+
if (useAuth) {
|
|
124
|
+
authConfig = `
|
|
125
|
+
auth: {
|
|
126
|
+
strategies: { emailPassword: true },
|
|
127
|
+
features: {
|
|
128
|
+
apiKeys: { enabled: true }
|
|
129
|
+
}
|
|
130
|
+
},`;
|
|
131
|
+
}
|
|
132
|
+
let configCode = `import { defineConfig } from 'opacacms/config';
|
|
133
|
+
import { z, defineCollection } from 'opacacms/schema';
|
|
134
|
+
${dbImport}
|
|
135
|
+
|
|
136
|
+
const posts = defineCollection({
|
|
137
|
+
slug: 'posts',
|
|
138
|
+
schema: z.object({
|
|
139
|
+
id: z.text().default(() => crypto.randomUUID()),
|
|
140
|
+
title: z.text().required(),
|
|
141
|
+
content: z.richText(),
|
|
142
|
+
})
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
export default defineConfig({
|
|
146
|
+
appName: "My OpacaCMS App",
|
|
147
|
+
serverURL: "http://localhost:3000",
|
|
148
|
+
secret: "my-super-secret-key-change-me",
|
|
149
|
+
db: ${dbInit},
|
|
150
|
+
runMigrationsOnStartup: true,${authConfig}
|
|
151
|
+
collections: [posts]
|
|
152
|
+
});
|
|
153
|
+
`;
|
|
154
|
+
if (dbType === "d1") {
|
|
155
|
+
configCode = `import { defineConfig } from 'opacacms/config';
|
|
156
|
+
import { z, defineCollection } from 'opacacms/schema';
|
|
157
|
+
${dbImport}
|
|
158
|
+
|
|
159
|
+
const posts = defineCollection({
|
|
160
|
+
slug: 'posts',
|
|
161
|
+
schema: z.object({
|
|
162
|
+
id: z.text().default(() => crypto.randomUUID()),
|
|
163
|
+
title: z.text().required(),
|
|
164
|
+
content: z.richText(),
|
|
165
|
+
})
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
const getConfig = (env: any, request: Request) => defineConfig({
|
|
169
|
+
appName: "My Edge App",
|
|
170
|
+
serverURL: new URL(request.url).origin,
|
|
171
|
+
secret: env.OPACA_SECRET,
|
|
172
|
+
db: ${dbInit},
|
|
173
|
+
runMigrationsOnStartup: true,${authConfig}
|
|
174
|
+
collections: [posts]
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
export default getConfig;
|
|
178
|
+
`;
|
|
179
|
+
}
|
|
180
|
+
fs.writeFileSync(resolve(process.cwd(), target, "opacacms.config.ts"), configCode);
|
|
181
|
+
let serverCode = "";
|
|
182
|
+
if (dbType === "d1") {
|
|
183
|
+
serverCode = `import { createCloudflareWorkersHandler } from 'opacacms/runtimes/cloudflare-workers';
|
|
184
|
+
import config from './opacacms.config';
|
|
185
|
+
|
|
186
|
+
const app = createCloudflareWorkersHandler(config);
|
|
187
|
+
|
|
188
|
+
export default app;
|
|
189
|
+
`;
|
|
190
|
+
} else {
|
|
191
|
+
serverCode = `import { createBunHandler } from 'opacacms/runtimes/bun';
|
|
192
|
+
import config from './opacacms.config';
|
|
193
|
+
|
|
194
|
+
const { app, init } = createBunHandler(config, { port: 3000 });
|
|
195
|
+
|
|
196
|
+
await init(); // Connects DB, runs migrations, starts server
|
|
197
|
+
console.log('\uD83D\uDE80 Listening on http://localhost:3000');
|
|
198
|
+
`;
|
|
199
|
+
}
|
|
200
|
+
fs.writeFileSync(resolve(process.cwd(), target, "index.ts"), serverCode);
|
|
201
|
+
const pkgJson = {
|
|
202
|
+
name: target,
|
|
203
|
+
type: "module",
|
|
204
|
+
scripts: {
|
|
205
|
+
dev: dbType === "d1" ? "wrangler dev" : "bun run --watch index.ts"
|
|
206
|
+
},
|
|
207
|
+
dependencies: {
|
|
208
|
+
opacacms: "latest"
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
fs.writeFileSync(resolve(process.cwd(), target, "package.json"), JSON.stringify(pkgJson, null, 2));
|
|
212
|
+
s.stop(`Project created successfully in ${import_picocolors.default.green(`./${target}`)}!`);
|
|
213
|
+
Vt(`cd ${target}
|
|
214
|
+
bun install
|
|
215
|
+
bun run dev`, "Next Steps");
|
|
216
|
+
Gt(`Build something awesome! \uD83C\uDF88`);
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
export {
|
|
220
|
+
init_default as default
|
|
221
|
+
};
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import {
|
|
2
|
+
sanitizeGraphQLName
|
|
3
|
+
} from "./chunk-5b8r0v8c.js";
|
|
4
|
+
|
|
5
|
+
// src/client.ts
|
|
6
|
+
var capitalize = (s) => s.charAt(0).toUpperCase() + s.slice(1);
|
|
7
|
+
|
|
8
|
+
class OpacaError extends Error {
|
|
9
|
+
status;
|
|
10
|
+
data;
|
|
11
|
+
constructor(message, status, data = {}) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.name = "OpacaError";
|
|
14
|
+
this.status = status;
|
|
15
|
+
this.data = data;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function createClient(configOrOptions) {
|
|
19
|
+
const options = configOrOptions.serverURL ? { baseURL: configOrOptions.serverURL } : configOrOptions;
|
|
20
|
+
const baseURL = options.baseURL.replace(/\/$/, "");
|
|
21
|
+
let engineConfig = null;
|
|
22
|
+
let metadataCache = null;
|
|
23
|
+
const getHeaders = () => {
|
|
24
|
+
const headers = {
|
|
25
|
+
"Content-Type": "application/json"
|
|
26
|
+
};
|
|
27
|
+
if (options.token) {
|
|
28
|
+
headers.Authorization = `Bearer ${options.token}`;
|
|
29
|
+
}
|
|
30
|
+
return headers;
|
|
31
|
+
};
|
|
32
|
+
const fetcher = async (path, init) => {
|
|
33
|
+
const res = await fetch(`${baseURL}${path}`, {
|
|
34
|
+
...init,
|
|
35
|
+
credentials: "include",
|
|
36
|
+
headers: {
|
|
37
|
+
...getHeaders(),
|
|
38
|
+
...init?.headers
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
if (!res.ok) {
|
|
42
|
+
const errorData = await res.json().catch(() => ({}));
|
|
43
|
+
throw new OpacaError(errorData.message || `API Error: ${res.status}`, res.status, errorData);
|
|
44
|
+
}
|
|
45
|
+
return res.json();
|
|
46
|
+
};
|
|
47
|
+
const initConfig = async () => {
|
|
48
|
+
if (engineConfig && metadataCache)
|
|
49
|
+
return;
|
|
50
|
+
try {
|
|
51
|
+
const [setupRes, metadataRes] = await Promise.all([
|
|
52
|
+
fetcher("/api/__admin/setup"),
|
|
53
|
+
fetcher("/api/__admin/collections")
|
|
54
|
+
]);
|
|
55
|
+
engineConfig = setupRes.api || { rest: true, graphql: { enabled: false, path: "/graphql" } };
|
|
56
|
+
metadataCache = metadataRes;
|
|
57
|
+
} catch (e) {
|
|
58
|
+
engineConfig = { rest: true, graphql: { enabled: false, path: "/graphql" } };
|
|
59
|
+
metadataCache = { collections: [], globals: [] };
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
const buildSelectionSet = (fields) => {
|
|
63
|
+
if (!fields || fields.length === 0)
|
|
64
|
+
return "id";
|
|
65
|
+
const keys = ["id", "createdAt", "updatedAt"];
|
|
66
|
+
for (const f of fields) {
|
|
67
|
+
if (f.name)
|
|
68
|
+
keys.push(f.name);
|
|
69
|
+
}
|
|
70
|
+
return keys.join(" ");
|
|
71
|
+
};
|
|
72
|
+
const getSelectionSetForCollection = (slug) => {
|
|
73
|
+
const col = metadataCache?.collections?.find((c) => c.slug === slug);
|
|
74
|
+
return buildSelectionSet(col?.fields || []);
|
|
75
|
+
};
|
|
76
|
+
const getSelectionSetForGlobal = (slug) => {
|
|
77
|
+
const glbl = metadataCache?.globals?.find((g) => g.slug === slug);
|
|
78
|
+
return buildSelectionSet(glbl?.fields || []);
|
|
79
|
+
};
|
|
80
|
+
const client = {
|
|
81
|
+
getMetadata: () => fetcher("/api/__admin/metadata"),
|
|
82
|
+
getCollections: () => fetcher("/api/__admin/collections"),
|
|
83
|
+
getSetupStatus: () => fetcher("/api/__admin/setup"),
|
|
84
|
+
graphql: async (query, variables) => {
|
|
85
|
+
await initConfig();
|
|
86
|
+
if (!engineConfig?.graphql?.enabled) {
|
|
87
|
+
throw new OpacaError("GraphQL is not enabled on this server.", 400);
|
|
88
|
+
}
|
|
89
|
+
return fetcher(engineConfig.graphql.path, {
|
|
90
|
+
method: "POST",
|
|
91
|
+
body: JSON.stringify({ query, variables })
|
|
92
|
+
});
|
|
93
|
+
},
|
|
94
|
+
collections: new Proxy({}, {
|
|
95
|
+
get(_, collectionSlug) {
|
|
96
|
+
return {
|
|
97
|
+
find: async (query) => {
|
|
98
|
+
await initConfig();
|
|
99
|
+
if (engineConfig?.graphql?.enabled && !engineConfig?.rest) {
|
|
100
|
+
const selection = getSelectionSetForCollection(String(collectionSlug));
|
|
101
|
+
const limit = query?.limit ? `limit: ${query.limit}` : "";
|
|
102
|
+
const page = query?.page ? `page: ${query.page}` : "";
|
|
103
|
+
const argsStr = [limit, page].filter(Boolean).join(", ");
|
|
104
|
+
const args = argsStr ? `(${argsStr})` : "";
|
|
105
|
+
const capitalizedSlug = capitalize(sanitizeGraphQLName(String(collectionSlug)));
|
|
106
|
+
const gql = `query { find${capitalizedSlug}${args} { docs { ${selection} }, totalDocs, limit, totalPages, page, pagingCounter, hasPrevPage, hasNextPage, prevPage, nextPage, nextCursor, prevCursor } }`;
|
|
107
|
+
const res = await client.graphql(gql);
|
|
108
|
+
return res.data[`find${capitalizedSlug}`];
|
|
109
|
+
}
|
|
110
|
+
const searchParams = new URLSearchParams;
|
|
111
|
+
if (query) {
|
|
112
|
+
Object.entries(query).forEach(([key, value]) => {
|
|
113
|
+
searchParams.append(key, typeof value === "object" ? JSON.stringify(value) : String(value));
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
const queryString = searchParams.toString();
|
|
117
|
+
return fetcher(`/api/${String(collectionSlug)}${queryString ? `?${queryString}` : ""}`);
|
|
118
|
+
},
|
|
119
|
+
findOne: async (id) => {
|
|
120
|
+
await initConfig();
|
|
121
|
+
if (engineConfig?.graphql?.enabled && !engineConfig?.rest) {
|
|
122
|
+
const selection = getSelectionSetForCollection(String(collectionSlug));
|
|
123
|
+
const capitalizedSlug = capitalize(sanitizeGraphQLName(String(collectionSlug)));
|
|
124
|
+
const res = await client.graphql(`query getDoc($id: String!) { get${capitalizedSlug}(id: $id) { ${selection} } }`, { id });
|
|
125
|
+
return res.data[`get${capitalizedSlug}`];
|
|
126
|
+
}
|
|
127
|
+
return fetcher(`/api/${String(collectionSlug)}/${id}`);
|
|
128
|
+
},
|
|
129
|
+
list: async () => {
|
|
130
|
+
return client.collections[collectionSlug].find();
|
|
131
|
+
},
|
|
132
|
+
create: async (data) => {
|
|
133
|
+
await initConfig();
|
|
134
|
+
if (engineConfig?.graphql?.enabled && !engineConfig?.rest) {
|
|
135
|
+
const selection = getSelectionSetForCollection(String(collectionSlug));
|
|
136
|
+
const capitalizedSlug = capitalize(sanitizeGraphQLName(String(collectionSlug)));
|
|
137
|
+
const res = await client.graphql(`mutation createDoc($data: JSON!) { create${capitalizedSlug}(data: $data) { ${selection} } }`, { data });
|
|
138
|
+
return res.data[`create${capitalizedSlug}`];
|
|
139
|
+
}
|
|
140
|
+
return fetcher(`/api/${String(collectionSlug)}`, {
|
|
141
|
+
method: "POST",
|
|
142
|
+
body: JSON.stringify(data)
|
|
143
|
+
});
|
|
144
|
+
},
|
|
145
|
+
update: async (id, data) => {
|
|
146
|
+
await initConfig();
|
|
147
|
+
if (engineConfig?.graphql?.enabled && !engineConfig?.rest) {
|
|
148
|
+
const selection = getSelectionSetForCollection(String(collectionSlug));
|
|
149
|
+
const capitalizedSlug = capitalize(sanitizeGraphQLName(String(collectionSlug)));
|
|
150
|
+
const res = await client.graphql(`mutation updateDoc($id: String!, $data: JSON!) { update${capitalizedSlug}(id: $id, data: $data) { ${selection} } }`, { id, data });
|
|
151
|
+
return res.data[`update${capitalizedSlug}`];
|
|
152
|
+
}
|
|
153
|
+
return fetcher(`/api/${String(collectionSlug)}/${id}`, {
|
|
154
|
+
method: "PATCH",
|
|
155
|
+
body: JSON.stringify(data)
|
|
156
|
+
});
|
|
157
|
+
},
|
|
158
|
+
delete: async (id) => {
|
|
159
|
+
await initConfig();
|
|
160
|
+
if (engineConfig?.graphql?.enabled && !engineConfig?.rest) {
|
|
161
|
+
const capitalizedSlug = capitalize(sanitizeGraphQLName(String(collectionSlug)));
|
|
162
|
+
const res = await client.graphql(`mutation deleteDoc($id: String!) { delete${capitalizedSlug}(id: $id) }`, { id });
|
|
163
|
+
return res.data[`delete${capitalizedSlug}`];
|
|
164
|
+
}
|
|
165
|
+
return fetcher(`/api/${String(collectionSlug)}/${id}`, {
|
|
166
|
+
method: "DELETE"
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
}),
|
|
172
|
+
globals: new Proxy({}, {
|
|
173
|
+
get(_, globalSlug) {
|
|
174
|
+
return {
|
|
175
|
+
get: async () => {
|
|
176
|
+
await initConfig();
|
|
177
|
+
if (engineConfig?.graphql?.enabled && !engineConfig?.rest) {
|
|
178
|
+
const selection = getSelectionSetForGlobal(String(globalSlug));
|
|
179
|
+
const capitalizedSlug = capitalize(sanitizeGraphQLName(String(globalSlug)));
|
|
180
|
+
const res = await client.graphql(`query getGlobal { get${capitalizedSlug} { ${selection} } }`);
|
|
181
|
+
return res.data[`get${capitalizedSlug}`];
|
|
182
|
+
}
|
|
183
|
+
return fetcher(`/api/globals/${String(globalSlug)}`);
|
|
184
|
+
},
|
|
185
|
+
update: async (data) => {
|
|
186
|
+
await initConfig();
|
|
187
|
+
if (engineConfig?.graphql?.enabled && !engineConfig?.rest) {
|
|
188
|
+
const selection = getSelectionSetForGlobal(String(globalSlug));
|
|
189
|
+
const capitalizedSlug = capitalize(sanitizeGraphQLName(String(globalSlug)));
|
|
190
|
+
const res = await client.graphql(`mutation updateGlobal($data: JSON!) { update${capitalizedSlug}(data: $data) { ${selection} } }`, { data });
|
|
191
|
+
return res.data[`update${capitalizedSlug}`];
|
|
192
|
+
}
|
|
193
|
+
return fetcher(`/api/globals/${String(globalSlug)}`, {
|
|
194
|
+
method: "PATCH",
|
|
195
|
+
body: JSON.stringify(data)
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
})
|
|
201
|
+
};
|
|
202
|
+
return client;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export { OpacaError, createClient };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import"./chunk-
|
|
1
|
+
import"./chunk-6bywt602.js";
|
|
2
2
|
|
|
3
|
-
// src/cli/d1-mock.ts
|
|
3
|
+
// src/cli/core/mocks/d1-mock.ts
|
|
4
4
|
import { Database } from "bun:sqlite";
|
|
5
5
|
import fs from "node:fs";
|
|
6
6
|
import path from "node:path";
|
|
@@ -20,14 +20,23 @@ function createD1Mock(dbPath = ".opaca/local-d1.db") {
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
let finalPath = dbPath;
|
|
24
|
+
if (!finalPath) {
|
|
25
|
+
finalPath = ":memory:";
|
|
26
|
+
console.log("[OpacaCMS] Using in-memory D1 mock (no -c/--config provided)");
|
|
27
|
+
}
|
|
28
|
+
const absolutePath = finalPath === ":memory:" ? finalPath : path.isAbsolute(finalPath) ? finalPath : path.resolve(process.cwd(), finalPath);
|
|
25
29
|
try {
|
|
26
|
-
if (
|
|
27
|
-
|
|
30
|
+
if (absolutePath !== ":memory:") {
|
|
31
|
+
const dir = path.dirname(absolutePath);
|
|
32
|
+
if (!fs.existsSync(dir)) {
|
|
33
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
34
|
+
}
|
|
28
35
|
}
|
|
29
36
|
const sqlite = new Database(absolutePath);
|
|
30
|
-
|
|
37
|
+
if (absolutePath !== ":memory:") {
|
|
38
|
+
console.log(`[OpacaCMS] Using local CLI database: ${absolutePath}`);
|
|
39
|
+
}
|
|
31
40
|
return wrapSqlite(sqlite);
|
|
32
41
|
} catch (err) {
|
|
33
42
|
console.warn(`[OpacaCMS] Warning: Could not open database at ${absolutePath}. Using memory database.`);
|