cajonzero 0.1.2 → 0.2.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/LICENSE +21 -21
- package/README.md +49 -27
- package/dist/bin/cj0.js +14877 -89
- package/dist/catalog-BRO-mQoP.d.ts +67 -0
- package/dist/{config-BOzAyP7m.d.ts → config-glwUbUbx.d.ts} +1 -1
- package/dist/core.d.ts +19 -8
- package/dist/core.js +15300 -415
- package/dist/index.d.ts +7 -5
- package/dist/index.js +32123 -9901
- package/dist/maps.d.ts +182 -0
- package/dist/maps.js +14062 -0
- package/dist/{providers-BX7e4pNW.d.ts → providers-Bu0-iMVs.d.ts} +129 -56
- package/dist/quickjs.wasm +0 -0
- package/dist/scaffold.d.ts +73 -6
- package/dist/scaffold.js +334 -51
- package/dist/serve.d.ts +2 -1
- package/dist/serve.js +33010 -10788
- package/dist/ui/assets/index-Bf4Kjuyg.js +4404 -0
- package/dist/ui/assets/index-ZzhH55rc.css +2 -0
- package/dist/ui/assets/{main-BeABKxzY.js → main-DB66UjcY.js} +16 -16
- package/dist/ui/assets/{voxel.worker-CvX1GY4o.js → voxel.worker-BFiKMi1W.js} +1 -1
- package/dist/ui/index.html +2 -2
- package/package.json +103 -95
- package/dist/ui/assets/index-Bhv7LV8L.css +0 -2
- package/dist/ui/assets/index-CaAHje8X.js +0 -4404
package/dist/scaffold.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { readFileSync, existsSync, statSync, mkdirSync, writeFileSync, readdirSync } from 'fs';
|
|
2
|
-
import
|
|
1
|
+
import { readFileSync, existsSync, statSync, mkdirSync, writeFileSync, renameSync, rmSync, cpSync, readdirSync } from 'fs';
|
|
2
|
+
import path3 from 'path';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
|
-
import { randomBytes } from 'crypto';
|
|
4
|
+
import { randomBytes, createHash } from 'crypto';
|
|
5
|
+
import { createRequire } from 'module';
|
|
5
6
|
|
|
6
7
|
// src/scaffold/templates.ts
|
|
7
8
|
var SCAFFOLD_ENTRY_PATH = "src/index.ts";
|
|
@@ -71,7 +72,7 @@ var SCAFFOLD_CONFIG_CONTENT = `${JSON.stringify(
|
|
|
71
72
|
`;
|
|
72
73
|
var SCAFFOLD_MAPS_CONTENT = `${JSON.stringify({ version: 1, maps: [] }, null, 2)}
|
|
73
74
|
`;
|
|
74
|
-
var
|
|
75
|
+
var SCAFFOLD_PUBLIC_KEEP_PATH = "public/.gitkeep";
|
|
75
76
|
function packageJson(options) {
|
|
76
77
|
const manifest = {
|
|
77
78
|
name: options.packageName,
|
|
@@ -79,12 +80,12 @@ function packageJson(options) {
|
|
|
79
80
|
private: true,
|
|
80
81
|
type: "module",
|
|
81
82
|
scripts: {
|
|
82
|
-
dev:
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
83
|
+
dev: "wrangler dev",
|
|
84
|
+
// `cj0 deploy` syncs the packaged UI, uploads the private map-script
|
|
85
|
+
// packs, then runs `wrangler deploy` — one command, no build chain.
|
|
86
|
+
deploy: "cj0 deploy",
|
|
87
|
+
sync: "cj0 sync",
|
|
88
|
+
maps: "cj0 list"
|
|
88
89
|
},
|
|
89
90
|
dependencies: {
|
|
90
91
|
cajonzero: options.cajonzeroRange,
|
|
@@ -109,10 +110,17 @@ function wranglerConfig(options) {
|
|
|
109
110
|
` "compatibility_date": ${JSON.stringify(options.compatibilityDate)},`,
|
|
110
111
|
" // Deliberately NO `nodejs_compat`: cajonzero's worker path is Node-free.",
|
|
111
112
|
' "compatibility_flags": [],',
|
|
112
|
-
" //
|
|
113
|
-
" //
|
|
113
|
+
" // QuickJS is a build-time-compiled WASM module; workerd forbids runtime",
|
|
114
|
+
" // WebAssembly codegen. Keep this rule when editing the config.",
|
|
115
|
+
' "rules": [',
|
|
116
|
+
' { "type": "CompiledWasm", "globs": ["**/*.wasm"], "fallthrough": true }',
|
|
117
|
+
" ],",
|
|
118
|
+
" // Static UI + imported maps (play lobby + owner admin console).",
|
|
119
|
+
" // `cj0 sync` writes the packaged UI here; `cj0 add` writes public/maps/.",
|
|
114
120
|
' "assets": {',
|
|
115
|
-
' "directory": "
|
|
121
|
+
' "directory": "public",',
|
|
122
|
+
" // Binding so the room can read imported maps + seed packs at runtime.",
|
|
123
|
+
' "binding": "ASSETS",',
|
|
116
124
|
" // History routing: deep links (/play/x, /admin/bans) boot index.html.",
|
|
117
125
|
' "not_found_handling": "single-page-application",',
|
|
118
126
|
' "run_worker_first": ["/api/*", "/runtime/*"]',
|
|
@@ -163,17 +171,18 @@ function readme(options) {
|
|
|
163
171
|
"",
|
|
164
172
|
"```bash",
|
|
165
173
|
"npm install",
|
|
166
|
-
"npx cj0 setup # \u4EA4\u4E92\u5F0F\u914D\u7F6E
|
|
174
|
+
"npx cj0 setup # \u4EA4\u4E92\u5F0F\u914D\u7F6E ENV + KV namespace",
|
|
167
175
|
"npm run dev # http://localhost:8787",
|
|
168
176
|
"```",
|
|
169
177
|
"",
|
|
170
178
|
"## \u73AF\u5883\u53D8\u91CF",
|
|
171
179
|
"",
|
|
172
180
|
"`cj0 setup` \u628A\u975E\u5BC6\u94A5\u5199\u5165 `wrangler.jsonc` \u7684 `vars`\uFF0C\u628A\u5BC6\u94A5\u5199\u5165 `.dev.vars`\uFF08\u672C\u5730\uFF09\u3002",
|
|
173
|
-
"\
|
|
181
|
+
"KV namespace \u4E5F\u7531 `cj0 setup` \u914D\u7F6E\uFF1A\u56DE\u8F66\u4F1A\u81EA\u52A8\u8C03\u7528 wrangler \u521B\u5EFA\u5E76\u5199\u56DE id\uFF08\u9700\u5148\u767B\u5F55\uFF09\uFF0C",
|
|
182
|
+
"\u4E5F\u53EF\u4EE5\u7C98\u8D34\u5DF2\u6709 id\u3002\u79BB\u7EBF\u65F6\u624B\u52A8\u8FD0\u884C\uFF1A",
|
|
174
183
|
"",
|
|
175
184
|
"```bash",
|
|
176
|
-
"npx wrangler kv namespace create
|
|
185
|
+
"npx wrangler kv namespace create <name> --update-config --binding CAJONZERO_KV",
|
|
177
186
|
"npx wrangler secret put CAJONZERO_SESSION_SECRET",
|
|
178
187
|
"npx wrangler secret put BOX_PLAY_ADMIN_TOKEN",
|
|
179
188
|
"```",
|
|
@@ -197,24 +206,25 @@ function readme(options) {
|
|
|
197
206
|
"",
|
|
198
207
|
"## \u5730\u56FE",
|
|
199
208
|
"",
|
|
200
|
-
"\u5730\u56FE\
|
|
201
|
-
"\u518D\u5728 `cajonzero/maps.json` \u767B\u8BB0\uFF1A",
|
|
209
|
+
"\u5730\u56FE\u5728\u672C\u5730\u5BFC\u5165\uFF0C\u968F worker \u4E00\u6B21\u90E8\u7F72\uFF08\u9759\u6001\u8D44\u6E90 `public/`\uFF09\uFF1A",
|
|
202
210
|
"",
|
|
203
|
-
"```
|
|
204
|
-
"
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
"
|
|
208
|
-
' "slug": "omega",',
|
|
209
|
-
' "root": "https://cdn.example.com/cajonzero/omega/",',
|
|
210
|
-
' "worldId": "project-omega",',
|
|
211
|
-
' "name": "Omega City Reloaded"',
|
|
212
|
-
" }",
|
|
213
|
-
" ]",
|
|
214
|
-
"}",
|
|
211
|
+
"```bash",
|
|
212
|
+
"npx cj0 add ./race.boxplay # \u89E3\u5305\u5230 public/maps/race/ \u5E76\u751F\u6210 seed",
|
|
213
|
+
"npx cj0 update race ./race-v2.boxplay # \u8986\u76D6\u5DF2\u6709 slug",
|
|
214
|
+
"npx cj0 list # \u67E5\u770B catalog + \u672C\u5730\u5BFC\u5165\u72B6\u6001",
|
|
215
|
+
"npx cj0 remove race # \u5220\u9664\u5730\u56FE\u3001\u79C1\u6709\u811A\u672C\u4E0E catalog \u6761\u76EE",
|
|
215
216
|
"```",
|
|
216
217
|
"",
|
|
217
|
-
"`
|
|
218
|
+
"`add/update` \u4F1A\uFF1A",
|
|
219
|
+
"",
|
|
220
|
+
"1. \u628A\u516C\u5F00\u5730\u56FE\u8D44\u6E90\u89E3\u5305\u5230 `public/maps/<slug>/`\uFF1B",
|
|
221
|
+
"2. \u5728\u672C\u5730\u89E3\u6790\u4E16\u754C\u56FE\u5E76\u5199\u5165 `public/maps/<slug>/seed.json.gz`\uFF1B",
|
|
222
|
+
"3. \u628A**\u670D\u52A1\u7AEF\u811A\u672C**\u5199\u5230 `cajonzero/private/<slug>.json.gz`\uFF0C\u4E0D\u8FDB\u5165 `public/`\uFF1B",
|
|
223
|
+
'4. \u5728 `cajonzero/maps.json` \u5199\u5165 `"root": "/maps/<slug>/"`\uFF0C\u5E76\u628A\u670D\u52A1\u7AEF\u811A\u672C\u6587\u4EF6\u8BB0\u5F55\u4E3A',
|
|
224
|
+
' `"scriptsFile": "cajonzero/private/<slug>.json.gz"`\uFF08\u8BE5\u76EE\u5F55\u4F1A\u63D0\u4EA4\uFF0CCF \u6784\u5EFA\u65F6 `cj0 deploy` \u53EF\u4E0A\u4F20\uFF09\u3002',
|
|
225
|
+
"",
|
|
226
|
+
"\u9700\u8981\u72EC\u7ACB CDN \u65F6\uFF0C\u624B\u52A8\u628A\u8BE5\u6761\u76EE\u7684 `root` \u6539\u6210 `https://cdn.example.com/.../` \u5373\u53EF\uFF1B",
|
|
227
|
+
"`cj0 update` \u9ED8\u8BA4\u4FDD\u7559\u4F60\u6539\u8FC7\u7684 `root`\uFF08`--reset-root` \u53EF\u6062\u590D\uFF09\u3002",
|
|
218
228
|
"",
|
|
219
229
|
"## \u90E8\u7F72",
|
|
220
230
|
"",
|
|
@@ -222,6 +232,9 @@ function readme(options) {
|
|
|
222
232
|
"npm run deploy",
|
|
223
233
|
"```",
|
|
224
234
|
"",
|
|
235
|
+
"`cj0 deploy` \u4F1A\u540C\u6B65\u6253\u5305\u7684 UI \u5230 `public/`\u3001\u4E0A\u4F20\u79C1\u6709\u811A\u672C\uFF0C\u7136\u540E\u6267\u884C",
|
|
236
|
+
"`wrangler deploy`\u3002\u9996\u6B21\u90E8\u7F72\u524D\u5148\u8FD0\u884C `npx cj0 setup`\u3002",
|
|
237
|
+
"",
|
|
225
238
|
"\u5927\u5385\u5728 `/`\uFF0C\u7BA1\u7406\u540E\u53F0\u5728 `/admin`\u3002",
|
|
226
239
|
""
|
|
227
240
|
].join("\n");
|
|
@@ -236,6 +249,7 @@ function buildScaffoldFiles(options) {
|
|
|
236
249
|
content: SCAFFOLD_CONFIG_CONTENT.replace("<project-name>", options.packageName)
|
|
237
250
|
},
|
|
238
251
|
{ path: "cajonzero/maps.json", content: SCAFFOLD_MAPS_CONTENT },
|
|
252
|
+
{ path: SCAFFOLD_PUBLIC_KEEP_PATH, content: "" },
|
|
239
253
|
{ path: ".gitignore", content: gitignore() },
|
|
240
254
|
{ path: "README.md", content: readme(options) }
|
|
241
255
|
];
|
|
@@ -264,7 +278,7 @@ function readCajonzeroPackage(manifestPath) {
|
|
|
264
278
|
return { version, wranglerRange, unstorageRange };
|
|
265
279
|
}
|
|
266
280
|
function toPackageName(folder) {
|
|
267
|
-
const base =
|
|
281
|
+
const base = path3.basename(folder);
|
|
268
282
|
const slug = base.toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^[-._]+/, "").replace(/[-._]+$/, "");
|
|
269
283
|
return slug.length > 0 ? slug : "cajonzero-app";
|
|
270
284
|
}
|
|
@@ -279,7 +293,7 @@ function createProject(folder, options = {}) {
|
|
|
279
293
|
throw new ScaffoldError("INVALID_TARGET", "create requires a target folder");
|
|
280
294
|
}
|
|
281
295
|
const cwd = options.cwd ?? process.cwd();
|
|
282
|
-
const target =
|
|
296
|
+
const target = path3.resolve(cwd, name);
|
|
283
297
|
if (existsSync(target) && !statSync(target).isDirectory()) {
|
|
284
298
|
throw new ScaffoldError("INVALID_TARGET", `target exists and is not a directory: ${target}`);
|
|
285
299
|
}
|
|
@@ -302,8 +316,8 @@ function createProject(folder, options = {}) {
|
|
|
302
316
|
});
|
|
303
317
|
mkdirSync(target, { recursive: true });
|
|
304
318
|
for (const file of files) {
|
|
305
|
-
const fullPath =
|
|
306
|
-
mkdirSync(
|
|
319
|
+
const fullPath = path3.join(target, file.path);
|
|
320
|
+
mkdirSync(path3.dirname(fullPath), { recursive: true });
|
|
307
321
|
writeFileSync(fullPath, file.content, "utf8");
|
|
308
322
|
}
|
|
309
323
|
return { target, files: files.map((file) => file.path) };
|
|
@@ -388,6 +402,13 @@ var SETUP_FIELDS = [
|
|
|
388
402
|
required: true,
|
|
389
403
|
hint: "\u7559\u7A7A\u81EA\u52A8\u751F\u6210\uFF1B\u672C\u5730\u5199\u5165 .dev.vars"
|
|
390
404
|
},
|
|
405
|
+
{
|
|
406
|
+
name: "CAJONZERO_KV_ID",
|
|
407
|
+
label: "KV namespace id",
|
|
408
|
+
kind: "kv",
|
|
409
|
+
required: true,
|
|
410
|
+
hint: "\u56DE\u8F66\u81EA\u52A8\u521B\u5EFA\uFF08\u9700 wrangler \u767B\u5F55\uFF09\u6216\u7C98\u8D34\u5DF2\u6709 id"
|
|
411
|
+
},
|
|
391
412
|
{
|
|
392
413
|
name: "CAJONZERO_ENV",
|
|
393
414
|
label: "\u90E8\u7F72\u540D\u79F0",
|
|
@@ -435,10 +456,11 @@ function serializeDevVars(values) {
|
|
|
435
456
|
return `${lines.join("\n")}
|
|
436
457
|
`;
|
|
437
458
|
}
|
|
438
|
-
function
|
|
439
|
-
const
|
|
459
|
+
function findKeyBlock(raw, key, openChar) {
|
|
460
|
+
const closeChar = openChar === "{" ? "}" : "]";
|
|
461
|
+
const match = new RegExp(`"${key}"\\s*:\\s*\\${openChar}`).exec(raw);
|
|
440
462
|
if (match === null) return null;
|
|
441
|
-
const open = raw.indexOf(
|
|
463
|
+
const open = raw.indexOf(openChar, match.index);
|
|
442
464
|
let depth = 0;
|
|
443
465
|
let inString = false;
|
|
444
466
|
let escaped = false;
|
|
@@ -451,8 +473,8 @@ function findVarsBlock(raw) {
|
|
|
451
473
|
continue;
|
|
452
474
|
}
|
|
453
475
|
if (ch === '"') inString = true;
|
|
454
|
-
else if (ch ===
|
|
455
|
-
else if (ch ===
|
|
476
|
+
else if (ch === openChar) depth += 1;
|
|
477
|
+
else if (ch === closeChar) {
|
|
456
478
|
depth -= 1;
|
|
457
479
|
if (depth === 0) {
|
|
458
480
|
const lineStart = raw.lastIndexOf("\n", match.index) + 1;
|
|
@@ -463,7 +485,10 @@ function findVarsBlock(raw) {
|
|
|
463
485
|
}
|
|
464
486
|
return null;
|
|
465
487
|
}
|
|
466
|
-
function
|
|
488
|
+
function findVarsBlock(raw) {
|
|
489
|
+
return findKeyBlock(raw, "vars", "{");
|
|
490
|
+
}
|
|
491
|
+
function stripJsoncComments(text) {
|
|
467
492
|
let out = "";
|
|
468
493
|
let inString = false;
|
|
469
494
|
let escaped = false;
|
|
@@ -494,13 +519,95 @@ function parseJsoncObject(text) {
|
|
|
494
519
|
}
|
|
495
520
|
out += ch;
|
|
496
521
|
}
|
|
497
|
-
|
|
522
|
+
return out;
|
|
523
|
+
}
|
|
524
|
+
function parseJsonc(text) {
|
|
498
525
|
try {
|
|
499
|
-
const
|
|
500
|
-
return
|
|
526
|
+
const clean = text.replace(/^\uFEFF/, "");
|
|
527
|
+
return JSON.parse(stripJsoncComments(clean).replace(/,(\s*[}\]])/g, "$1"));
|
|
501
528
|
} catch {
|
|
502
|
-
return
|
|
529
|
+
return void 0;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
function parseJsoncObject(text) {
|
|
533
|
+
const parsed = parseJsonc(text);
|
|
534
|
+
return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : {};
|
|
535
|
+
}
|
|
536
|
+
function parseJsoncArray(text) {
|
|
537
|
+
const parsed = parseJsonc(text);
|
|
538
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
539
|
+
}
|
|
540
|
+
function escapeRegExp(text) {
|
|
541
|
+
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
542
|
+
}
|
|
543
|
+
function findBindingObject(raw, block, binding) {
|
|
544
|
+
const bindingPattern = new RegExp(`"binding"\\s*:\\s*"${escapeRegExp(binding)}"`);
|
|
545
|
+
const stack = [];
|
|
546
|
+
let inString = false;
|
|
547
|
+
let escaped = false;
|
|
548
|
+
for (let i = block.open; i <= block.close; i += 1) {
|
|
549
|
+
const ch = raw[i];
|
|
550
|
+
if (inString) {
|
|
551
|
+
if (escaped) escaped = false;
|
|
552
|
+
else if (ch === "\\") escaped = true;
|
|
553
|
+
else if (ch === '"') inString = false;
|
|
554
|
+
continue;
|
|
555
|
+
}
|
|
556
|
+
if (ch === '"') inString = true;
|
|
557
|
+
else if (ch === "{") stack.push(i);
|
|
558
|
+
else if (ch === "}") {
|
|
559
|
+
const start = stack.pop();
|
|
560
|
+
if (start !== void 0 && bindingPattern.test(raw.slice(start, i + 1))) {
|
|
561
|
+
const lineStart = raw.lastIndexOf("\n", start) + 1;
|
|
562
|
+
const indent = /^\s*/.exec(raw.slice(lineStart, start))?.[0] ?? " ";
|
|
563
|
+
return { start, end: i + 1, indent };
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
return null;
|
|
568
|
+
}
|
|
569
|
+
function readWranglerKvNamespaceId(raw, binding = "CAJONZERO_KV") {
|
|
570
|
+
const block = findKeyBlock(raw, "kv_namespaces", "[");
|
|
571
|
+
if (block === null) return void 0;
|
|
572
|
+
const entries = parseJsoncArray(raw.slice(block.open, block.close + 1));
|
|
573
|
+
for (const entry of entries) {
|
|
574
|
+
if (typeof entry !== "object" || entry === null) continue;
|
|
575
|
+
const record = entry;
|
|
576
|
+
if (record["binding"] !== binding) continue;
|
|
577
|
+
const id = record["id"];
|
|
578
|
+
return typeof id === "string" && id.length > 0 ? id : void 0;
|
|
503
579
|
}
|
|
580
|
+
return void 0;
|
|
581
|
+
}
|
|
582
|
+
function setWranglerKvNamespaceId(raw, binding, id) {
|
|
583
|
+
const block = findKeyBlock(raw, "kv_namespaces", "[");
|
|
584
|
+
if (block !== null) {
|
|
585
|
+
const entry = findBindingObject(raw, block, binding);
|
|
586
|
+
if (entry !== null) {
|
|
587
|
+
const entryText = raw.slice(entry.start, entry.end);
|
|
588
|
+
const nextEntry = /"id"\s*:/.test(entryText) ? entryText.replace(/("id"\s*:\s*)"(?:[^"\\]|\\.)*"/, `$1${JSON.stringify(id)}`) : entryText.replace(
|
|
589
|
+
/("binding"\s*:\s*"(?:[^"\\]|\\.)*")/,
|
|
590
|
+
`$1,
|
|
591
|
+
${entry.indent}"id": ${JSON.stringify(id)}`
|
|
592
|
+
);
|
|
593
|
+
return raw.slice(0, entry.start) + nextEntry + raw.slice(entry.end);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
const existing = block === null ? [] : parseJsoncArray(raw.slice(block.open, block.close + 1));
|
|
597
|
+
const filtered = existing.filter(
|
|
598
|
+
(entry) => !(typeof entry === "object" && entry !== null && entry["binding"] === binding)
|
|
599
|
+
);
|
|
600
|
+
const indent = block?.indent ?? " ";
|
|
601
|
+
const arrayText = JSON.stringify([...filtered, { binding, id }], null, 2).split("\n").map((line, index) => index === 0 ? line : `${indent}${line}`).join("\n");
|
|
602
|
+
if (block !== null) {
|
|
603
|
+
return raw.slice(0, block.open) + arrayText + raw.slice(block.close + 1);
|
|
604
|
+
}
|
|
605
|
+
const close = raw.lastIndexOf("}");
|
|
606
|
+
if (close < 0) throw new Error("wrangler config is not a JSON object");
|
|
607
|
+
const body = raw.slice(0, close).trimEnd();
|
|
608
|
+
const separator = body.endsWith("{") || body.endsWith(",") ? "\n" : ",\n";
|
|
609
|
+
return `${body}${separator}${indent}"kv_namespaces": ${arrayText}
|
|
610
|
+
${raw.slice(close)}`;
|
|
504
611
|
}
|
|
505
612
|
function setWranglerVars(raw, vars) {
|
|
506
613
|
const managed = new Set(SETUP_FIELDS.filter((f) => f.kind === "var").map((f) => f.name));
|
|
@@ -543,26 +650,33 @@ function readSetupValues(cwd, configPath, devVarsPath) {
|
|
|
543
650
|
if (typeof value === "string") out[key] = value;
|
|
544
651
|
}
|
|
545
652
|
}
|
|
653
|
+
const kvId = readWranglerKvNamespaceId(raw);
|
|
654
|
+
if (kvId !== void 0 && kvId !== SCAFFOLD_KV_PLACEHOLDER_ID) {
|
|
655
|
+
out["CAJONZERO_KV_ID"] = kvId;
|
|
656
|
+
}
|
|
546
657
|
}
|
|
547
658
|
return out;
|
|
548
659
|
}
|
|
549
660
|
function applySetup(options) {
|
|
550
661
|
const cwd = options.cwd ?? process.cwd();
|
|
551
|
-
const configPath =
|
|
552
|
-
const devVarsPath =
|
|
662
|
+
const configPath = path3.resolve(cwd, options.configPath ?? "wrangler.jsonc");
|
|
663
|
+
const devVarsPath = path3.join(path3.dirname(configPath), ".dev.vars");
|
|
553
664
|
if (!existsSync(configPath)) {
|
|
554
|
-
throw new Error(`\u627E\u4E0D\u5230 ${
|
|
665
|
+
throw new Error(`\u627E\u4E0D\u5230 ${path3.basename(configPath)}\uFF0C\u8BF7\u5728 cj0 create \u751F\u6210\u7684\u9879\u76EE\u76EE\u5F55\u4E2D\u8FD0\u884C`);
|
|
555
666
|
}
|
|
556
667
|
const vars = {};
|
|
557
668
|
const secrets = {};
|
|
669
|
+
let kvId;
|
|
558
670
|
for (const field of SETUP_FIELDS) {
|
|
559
671
|
const value = options.values[field.name]?.trim();
|
|
560
672
|
if (value === void 0 || value.length === 0) continue;
|
|
561
673
|
if (field.kind === "secret") secrets[field.name] = value;
|
|
674
|
+
else if (field.kind === "kv") kvId = value;
|
|
562
675
|
else vars[field.name] = value;
|
|
563
676
|
}
|
|
564
677
|
const raw = readFileSync(configPath, "utf8");
|
|
565
|
-
|
|
678
|
+
let next = setWranglerVars(raw, vars);
|
|
679
|
+
if (kvId !== void 0) next = setWranglerKvNamespaceId(next, "CAJONZERO_KV", kvId);
|
|
566
680
|
if (next !== raw) writeFileSync(configPath, next, "utf8");
|
|
567
681
|
const existingDev = existsSync(devVarsPath) ? parseDevVars(readFileSync(devVarsPath, "utf8")) : {};
|
|
568
682
|
const managedSecrets = new Set(
|
|
@@ -574,9 +688,178 @@ function applySetup(options) {
|
|
|
574
688
|
}
|
|
575
689
|
Object.assign(mergedDev, secrets);
|
|
576
690
|
writeFileSync(devVarsPath, serializeDevVars(mergedDev), "utf8");
|
|
577
|
-
return { configPath, devVarsPath, vars, secrets };
|
|
691
|
+
return { configPath, devVarsPath, vars, secrets, ...kvId !== void 0 ? { kvId } : {} };
|
|
692
|
+
}
|
|
693
|
+
var ASSETS_STAMP_FILE = ".cajonzero-assets.json";
|
|
694
|
+
var ASSETS_MAPS_DIR = "maps";
|
|
695
|
+
var ASSETS_KEEP_FILE = ".gitkeep";
|
|
696
|
+
var DEFAULT_CONFIG = "wrangler.jsonc";
|
|
697
|
+
function resolvePackageRoot() {
|
|
698
|
+
try {
|
|
699
|
+
return path3.dirname(createRequire(import.meta.url).resolve("cajonzero/package.json"));
|
|
700
|
+
} catch {
|
|
701
|
+
return path3.dirname(fileURLToPath(new URL("../../package.json", import.meta.url)));
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
function readPackageVersion(root) {
|
|
705
|
+
try {
|
|
706
|
+
const parsed = JSON.parse(readFileSync(path3.join(root, "package.json"), "utf8"));
|
|
707
|
+
return typeof parsed.version === "string" ? parsed.version : void 0;
|
|
708
|
+
} catch {
|
|
709
|
+
return void 0;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
function readWranglerAssetsDirectory(configPath) {
|
|
713
|
+
if (!existsSync(configPath)) {
|
|
714
|
+
throw new Error(`\u627E\u4E0D\u5230 ${path3.basename(configPath)}\uFF0C\u8BF7\u5728 cj0 create \u751F\u6210\u7684\u9879\u76EE\u76EE\u5F55\u4E2D\u8FD0\u884C`);
|
|
715
|
+
}
|
|
716
|
+
const ext = path3.extname(configPath).toLowerCase();
|
|
717
|
+
if (ext !== ".json" && ext !== ".jsonc") {
|
|
718
|
+
throw new Error(
|
|
719
|
+
`\u4E0D\u652F\u6301\u8BFB\u53D6 ${path3.basename(configPath)}\uFF08\u53EA\u652F\u6301 JSON/JSONC wrangler \u914D\u7F6E\uFF1B\u7528 --assets \u6307\u5B9A\u76EE\u5F55\uFF09`
|
|
720
|
+
);
|
|
721
|
+
}
|
|
722
|
+
const parsed = parseJsoncObject(readFileSync(configPath, "utf8"));
|
|
723
|
+
const assets = parsed["assets"];
|
|
724
|
+
if (typeof assets === "object" && assets !== null && !Array.isArray(assets)) {
|
|
725
|
+
const directory = assets["directory"];
|
|
726
|
+
if (typeof directory === "string" && directory.length > 0) return directory;
|
|
727
|
+
}
|
|
728
|
+
return void 0;
|
|
729
|
+
}
|
|
730
|
+
function fingerprintTree(dir) {
|
|
731
|
+
const entries = [];
|
|
732
|
+
const walk = (relative) => {
|
|
733
|
+
const absolute = relative.length === 0 ? dir : path3.join(dir, relative);
|
|
734
|
+
for (const entry of readdirSync(absolute, { withFileTypes: true })) {
|
|
735
|
+
if (entry.name === ASSETS_STAMP_FILE) continue;
|
|
736
|
+
const child = relative.length === 0 ? entry.name : `${relative}/${entry.name}`;
|
|
737
|
+
if (entry.isDirectory()) walk(child);
|
|
738
|
+
else if (entry.isFile()) entries.push(child);
|
|
739
|
+
}
|
|
740
|
+
};
|
|
741
|
+
walk("");
|
|
742
|
+
entries.sort();
|
|
743
|
+
const hash = createHash("sha256");
|
|
744
|
+
let bytes = 0;
|
|
745
|
+
for (const relative of entries) {
|
|
746
|
+
const content = readFileSync(path3.join(dir, relative));
|
|
747
|
+
bytes += content.length;
|
|
748
|
+
hash.update(relative);
|
|
749
|
+
hash.update("\0");
|
|
750
|
+
hash.update(content);
|
|
751
|
+
hash.update("\0");
|
|
752
|
+
}
|
|
753
|
+
return { files: entries.length, bytes, hash: hash.digest("hex") };
|
|
754
|
+
}
|
|
755
|
+
function readStamp(targetDir) {
|
|
756
|
+
try {
|
|
757
|
+
const parsed = JSON.parse(
|
|
758
|
+
readFileSync(path3.join(targetDir, ASSETS_STAMP_FILE), "utf8")
|
|
759
|
+
);
|
|
760
|
+
if (parsed.version !== 1 || typeof parsed.fingerprint !== "string") return void 0;
|
|
761
|
+
return { version: 1, fingerprint: parsed.fingerprint, packageVersion: parsed.packageVersion };
|
|
762
|
+
} catch {
|
|
763
|
+
return void 0;
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
function assertSafeTarget(targetDir, sourceDir, configDir) {
|
|
767
|
+
const contains = (parent, child) => child === parent || child.startsWith(`${parent}${path3.sep}`);
|
|
768
|
+
if (targetDir === path3.parse(targetDir).root) {
|
|
769
|
+
throw new Error(`\u62D2\u7EDD\u628A\u6587\u4EF6\u7CFB\u7EDF\u6839\u76EE\u5F55\u4F5C\u4E3A assets \u76EE\u5F55\uFF1A${targetDir}`);
|
|
770
|
+
}
|
|
771
|
+
if (contains(targetDir, configDir) || contains(targetDir, sourceDir) || contains(sourceDir, targetDir)) {
|
|
772
|
+
throw new Error(`assets \u76EE\u5F55\u4E0D\u80FD\u5305\u542B\u9879\u76EE\u914D\u7F6E/cajonzero \u8D44\u6E90\u76EE\u5F55\uFF1A${targetDir}`);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
async function syncPublicAssets(options = {}) {
|
|
776
|
+
const cwd = options.cwd ?? process.cwd();
|
|
777
|
+
const configPath = path3.resolve(cwd, options.configPath ?? DEFAULT_CONFIG);
|
|
778
|
+
const configDir = path3.dirname(configPath);
|
|
779
|
+
const packageRoot = resolvePackageRoot();
|
|
780
|
+
const sourceDir = path3.resolve(options.sourceDir ?? path3.join(packageRoot, "dist", "ui"));
|
|
781
|
+
if (!existsSync(sourceDir)) {
|
|
782
|
+
throw new Error(
|
|
783
|
+
`cajonzero \u7684 UI \u8D44\u6E90\u7F3A\u5931\uFF1A${sourceDir}\uFF08\u8BF7\u91CD\u65B0\u5B89\u88C5 cajonzero\uFF0C\u6216\u5728\u6E90\u7801\u4ED3\u5E93\u5148 npm run build\uFF09`
|
|
784
|
+
);
|
|
785
|
+
}
|
|
786
|
+
const configured = options.assetsDir ?? readWranglerAssetsDirectory(configPath);
|
|
787
|
+
if (configured === void 0) {
|
|
788
|
+
throw new Error(
|
|
789
|
+
`${path3.basename(configPath)} \u672A\u914D\u7F6E assets.directory\uFF1B\u7528 --assets <dir> \u6307\u5B9A\u8F93\u51FA\u76EE\u5F55`
|
|
790
|
+
);
|
|
791
|
+
}
|
|
792
|
+
const targetDir = path3.resolve(configDir, configured);
|
|
793
|
+
assertSafeTarget(targetDir, sourceDir, configDir);
|
|
794
|
+
const source = fingerprintTree(sourceDir);
|
|
795
|
+
const stamp = readStamp(targetDir);
|
|
796
|
+
if (!options.force && stamp?.fingerprint === source.hash && existsSync(targetDir)) {
|
|
797
|
+
return {
|
|
798
|
+
sourceDir,
|
|
799
|
+
targetDir,
|
|
800
|
+
fingerprint: source.hash,
|
|
801
|
+
copied: false,
|
|
802
|
+
files: source.files,
|
|
803
|
+
bytes: source.bytes
|
|
804
|
+
};
|
|
805
|
+
}
|
|
806
|
+
const mapsDir = path3.join(targetDir, ASSETS_MAPS_DIR);
|
|
807
|
+
const mapsBackup = path3.join(configDir, `.cajonzero-maps-backup-${process.pid}`);
|
|
808
|
+
const keepFile = path3.join(targetDir, ASSETS_KEEP_FILE);
|
|
809
|
+
const keepBackup = path3.join(configDir, `.cajonzero-keep-backup-${process.pid}`);
|
|
810
|
+
if (!existsSync(mapsDir) && existsSync(mapsBackup)) {
|
|
811
|
+
mkdirSync(path3.dirname(mapsDir), { recursive: true });
|
|
812
|
+
renameSync(mapsBackup, mapsDir);
|
|
813
|
+
}
|
|
814
|
+
let hasMaps = false;
|
|
815
|
+
if (existsSync(mapsDir)) {
|
|
816
|
+
rmSync(mapsBackup, { recursive: true, force: true });
|
|
817
|
+
renameSync(mapsDir, mapsBackup);
|
|
818
|
+
hasMaps = true;
|
|
819
|
+
}
|
|
820
|
+
let hasKeep = false;
|
|
821
|
+
if (existsSync(keepFile)) {
|
|
822
|
+
rmSync(keepBackup, { force: true });
|
|
823
|
+
renameSync(keepFile, keepBackup);
|
|
824
|
+
hasKeep = true;
|
|
825
|
+
}
|
|
826
|
+
try {
|
|
827
|
+
rmSync(targetDir, { recursive: true, force: true });
|
|
828
|
+
mkdirSync(targetDir, { recursive: true });
|
|
829
|
+
cpSync(sourceDir, targetDir, {
|
|
830
|
+
recursive: true,
|
|
831
|
+
force: true,
|
|
832
|
+
filter: (from) => path3.basename(from) !== ASSETS_STAMP_FILE
|
|
833
|
+
});
|
|
834
|
+
} finally {
|
|
835
|
+
if (hasMaps && existsSync(mapsBackup)) {
|
|
836
|
+
mkdirSync(targetDir, { recursive: true });
|
|
837
|
+
rmSync(mapsDir, { recursive: true, force: true });
|
|
838
|
+
renameSync(mapsBackup, mapsDir);
|
|
839
|
+
}
|
|
840
|
+
if (hasKeep && existsSync(keepBackup)) {
|
|
841
|
+
mkdirSync(targetDir, { recursive: true });
|
|
842
|
+
rmSync(keepFile, { force: true });
|
|
843
|
+
renameSync(keepBackup, keepFile);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
const next = {
|
|
847
|
+
version: 1,
|
|
848
|
+
fingerprint: source.hash,
|
|
849
|
+
packageVersion: readPackageVersion(packageRoot)
|
|
850
|
+
};
|
|
851
|
+
writeFileSync(path3.join(targetDir, ASSETS_STAMP_FILE), `${JSON.stringify(next, null, 2)}
|
|
852
|
+
`, "utf8");
|
|
853
|
+
return {
|
|
854
|
+
sourceDir,
|
|
855
|
+
targetDir,
|
|
856
|
+
fingerprint: source.hash,
|
|
857
|
+
copied: true,
|
|
858
|
+
files: source.files,
|
|
859
|
+
bytes: source.bytes
|
|
860
|
+
};
|
|
578
861
|
}
|
|
579
862
|
|
|
580
|
-
export { SCAFFOLD_COMPATIBILITY_DATE, SCAFFOLD_CONFIG_CONTENT, SCAFFOLD_ENTRY_CONTENT, SCAFFOLD_ENTRY_PATH, SCAFFOLD_KV_PLACEHOLDER_ID, SCAFFOLD_MAPS_CONTENT, SETUP_FIELDS, ScaffoldError, applySetup, buildScaffoldFiles, createProject, generateAdminToken, generateSecret, parseDevVars, readCajonzeroPackage, readSetupValues, serializeDevVars, setWranglerVars, suggestedValue, toPackageName };
|
|
863
|
+
export { ASSETS_KEEP_FILE, ASSETS_MAPS_DIR, ASSETS_STAMP_FILE, SCAFFOLD_COMPATIBILITY_DATE, SCAFFOLD_CONFIG_CONTENT, SCAFFOLD_ENTRY_CONTENT, SCAFFOLD_ENTRY_PATH, SCAFFOLD_KV_PLACEHOLDER_ID, SCAFFOLD_MAPS_CONTENT, SETUP_FIELDS, ScaffoldError, applySetup, buildScaffoldFiles, createProject, generateAdminToken, generateSecret, parseDevVars, parseJsoncObject, readCajonzeroPackage, readSetupValues, readWranglerAssetsDirectory, readWranglerKvNamespaceId, serializeDevVars, setWranglerKvNamespaceId, setWranglerVars, suggestedValue, syncPublicAssets, toPackageName };
|
|
581
864
|
//# sourceMappingURL=scaffold.js.map
|
|
582
865
|
//# sourceMappingURL=scaffold.js.map
|
package/dist/serve.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { ExecutionContext } from 'hono';
|
|
2
|
-
import { R as Room, D as DurableObjectNamespace, b as Env } from './providers-
|
|
2
|
+
import { R as Room, D as DurableObjectNamespace, b as Env } from './providers-Bu0-iMVs.js';
|
|
3
3
|
import { StorageSource, EnvProvider, SettingDefaults } from './core.js';
|
|
4
4
|
import 'unstorage';
|
|
5
|
+
import './catalog-BRO-mQoP.js';
|
|
5
6
|
import 'gl-matrix';
|
|
6
7
|
import 'zod';
|
|
7
8
|
|