deepspace 0.4.4 → 0.4.5
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/dist/cli.js +229 -1306
- package/dist/cli.js.map +1 -1
- package/dist/server.d.ts +2 -86
- package/dist/server.js +9 -495
- package/dist/server.js.map +1 -1
- package/dist/testing.d.ts +115 -0
- package/dist/worker.d.ts +2 -86
- package/dist/worker.js +9 -495
- package/dist/worker.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli/cli.ts
|
|
4
|
-
import { defineCommand as
|
|
4
|
+
import { defineCommand as defineCommand18, runMain } from "citty";
|
|
5
5
|
import { execSync as execSync5 } from "child_process";
|
|
6
|
-
import { readFileSync as
|
|
7
|
-
import { dirname as dirname4, join as
|
|
6
|
+
import { readFileSync as readFileSync12, existsSync as existsSync13 } from "fs";
|
|
7
|
+
import { dirname as dirname4, join as join14 } from "path";
|
|
8
8
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
9
9
|
|
|
10
10
|
// src/cli/commands/login.ts
|
|
@@ -122,6 +122,9 @@ function resolveAppNameForEnv(config, envName) {
|
|
|
122
122
|
}
|
|
123
123
|
return resolveAppName(envBlock.name);
|
|
124
124
|
}
|
|
125
|
+
function devVarsPathFor(appDir, envName) {
|
|
126
|
+
return envName ? join(appDir, `.dev.vars.${envName}`) : join(appDir, ".dev.vars");
|
|
127
|
+
}
|
|
125
128
|
var WranglerConfigError = class extends Error {
|
|
126
129
|
constructor(path, cause) {
|
|
127
130
|
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
@@ -232,22 +235,8 @@ var SDK_MANAGED_KEYS = /* @__PURE__ */ new Set([
|
|
|
232
235
|
"OWNER_USER_ID",
|
|
233
236
|
"APP_OWNER_JWT",
|
|
234
237
|
"APP_IDENTITY_TOKEN",
|
|
235
|
-
"APP_SECRETS_KEY",
|
|
236
|
-
"APP_SECRETS_LOCAL_FALLBACK",
|
|
237
238
|
"ALLOW_DEBUG_ROUTES"
|
|
238
239
|
]);
|
|
239
|
-
var MANAGED_ENV_HEADER = "# Managed by `deepspace secrets` and regenerated by `deepspace dev`/`deepspace test`.";
|
|
240
|
-
var MANAGED_ENV_SYNCED_HEADER = "# DeepSpace synced secrets - mirrored with the deployed app secrets store.";
|
|
241
|
-
var MANAGED_ENV_DEV_ONLY_HEADER = "# DeepSpace dev-only secrets - used by `deepspace dev`; never synced unless pushed.";
|
|
242
|
-
function localEnvPath(appDir) {
|
|
243
|
-
return join2(appDir, ".env");
|
|
244
|
-
}
|
|
245
|
-
function legacyDevVarsPath(appDir, wranglerEnv) {
|
|
246
|
-
return join2(appDir, wranglerEnv ? `.dev.vars.${wranglerEnv}` : ".dev.vars");
|
|
247
|
-
}
|
|
248
|
-
function hasLegacyDevVars(appDir, wranglerEnv) {
|
|
249
|
-
return existsSync2(legacyDevVarsPath(appDir, wranglerEnv));
|
|
250
|
-
}
|
|
251
240
|
var DEV_VARS_DIVIDER = "# --- not managed by the SDK; preserved across dev/test runs ---";
|
|
252
241
|
function extractCustomDevVars(content) {
|
|
253
242
|
const lines = content.split("\n");
|
|
@@ -354,189 +343,6 @@ function parseDevVars(content) {
|
|
|
354
343
|
}
|
|
355
344
|
return result;
|
|
356
345
|
}
|
|
357
|
-
function parseDevVarsStrict(content, file = ".env") {
|
|
358
|
-
const result = {};
|
|
359
|
-
const lines = content.split("\n");
|
|
360
|
-
let i = 0;
|
|
361
|
-
while (i < lines.length) {
|
|
362
|
-
const line = lines[i];
|
|
363
|
-
const trimmed = line.trim();
|
|
364
|
-
if (!trimmed || trimmed.startsWith("#")) {
|
|
365
|
-
i++;
|
|
366
|
-
continue;
|
|
367
|
-
}
|
|
368
|
-
const eq = line.indexOf("=");
|
|
369
|
-
if (eq < 0) {
|
|
370
|
-
throw new Error(`${file}: invalid dotenv syntax on line ${i + 1}. Expected KEY=value.`);
|
|
371
|
-
}
|
|
372
|
-
const keyMatch = line.slice(0, eq).match(/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*$/);
|
|
373
|
-
if (!keyMatch) {
|
|
374
|
-
throw new Error(`${file}: invalid variable name on line ${i + 1}.`);
|
|
375
|
-
}
|
|
376
|
-
const key = keyMatch[1];
|
|
377
|
-
let value = line.slice(eq + 1);
|
|
378
|
-
let closed = !value.startsWith('"') || hasUnescapedQuote(value.slice(1));
|
|
379
|
-
if (!closed) {
|
|
380
|
-
i++;
|
|
381
|
-
while (i < lines.length) {
|
|
382
|
-
value += "\n" + lines[i];
|
|
383
|
-
if (hasUnescapedQuote(lines[i])) {
|
|
384
|
-
closed = true;
|
|
385
|
-
i++;
|
|
386
|
-
break;
|
|
387
|
-
}
|
|
388
|
-
i++;
|
|
389
|
-
}
|
|
390
|
-
} else {
|
|
391
|
-
i++;
|
|
392
|
-
}
|
|
393
|
-
if (value.startsWith('"') && !closed) {
|
|
394
|
-
throw new Error(`${file}: unterminated quoted value for key "${key}".`);
|
|
395
|
-
}
|
|
396
|
-
if (value.startsWith('"') && value.endsWith('"') && value.length >= 2) {
|
|
397
|
-
value = value.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, "\\");
|
|
398
|
-
}
|
|
399
|
-
result[key] = value;
|
|
400
|
-
}
|
|
401
|
-
return result;
|
|
402
|
-
}
|
|
403
|
-
function quoteEnvValue(value) {
|
|
404
|
-
return /^[A-Za-z0-9_./:@-]*$/.test(value) && !value.includes("\n") ? value : `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
405
|
-
}
|
|
406
|
-
function stripSdkManaged(vars) {
|
|
407
|
-
const out = {};
|
|
408
|
-
for (const [name, value] of Object.entries(vars)) {
|
|
409
|
-
if (!SDK_MANAGED_KEYS.has(name)) out[name] = value;
|
|
410
|
-
}
|
|
411
|
-
return out;
|
|
412
|
-
}
|
|
413
|
-
function sortRecord(input) {
|
|
414
|
-
const out = {};
|
|
415
|
-
for (const key of Object.keys(input).sort()) out[key] = input[key];
|
|
416
|
-
return out;
|
|
417
|
-
}
|
|
418
|
-
function readManagedEnvSections(appDir) {
|
|
419
|
-
const path = localEnvPath(appDir);
|
|
420
|
-
if (!existsSync2(path)) return { sdk: {}, synced: {}, devOnly: {} };
|
|
421
|
-
return parseManagedEnvSections(readFileSync2(path, "utf-8"));
|
|
422
|
-
}
|
|
423
|
-
function parseManagedEnvSections(content) {
|
|
424
|
-
const sections = { sdk: {}, synced: {}, devOnly: {} };
|
|
425
|
-
const legacyAppLines = [];
|
|
426
|
-
let target = "sdk";
|
|
427
|
-
const lines = content.split("\n");
|
|
428
|
-
for (let i = 0; i < lines.length; i++) {
|
|
429
|
-
const line = lines[i];
|
|
430
|
-
if (line.trim() === MANAGED_ENV_SYNCED_HEADER.trim()) {
|
|
431
|
-
target = "synced";
|
|
432
|
-
continue;
|
|
433
|
-
}
|
|
434
|
-
if (line.trim() === MANAGED_ENV_DEV_ONLY_HEADER.trim()) {
|
|
435
|
-
target = "devOnly";
|
|
436
|
-
continue;
|
|
437
|
-
}
|
|
438
|
-
if (line.trim().startsWith("#")) continue;
|
|
439
|
-
const name = assignmentName(line);
|
|
440
|
-
if (!name) {
|
|
441
|
-
if (line.trim()) legacyAppLines.push(line);
|
|
442
|
-
continue;
|
|
443
|
-
}
|
|
444
|
-
const block = [line];
|
|
445
|
-
const eq = line.indexOf("=");
|
|
446
|
-
const valStart = eq >= 0 ? line.slice(eq + 1) : "";
|
|
447
|
-
if (valStart.startsWith('"') && !hasUnescapedQuote(valStart.slice(1))) {
|
|
448
|
-
i++;
|
|
449
|
-
while (i < lines.length) {
|
|
450
|
-
block.push(lines[i]);
|
|
451
|
-
const closed = hasUnescapedQuote(lines[i]);
|
|
452
|
-
if (closed) break;
|
|
453
|
-
i++;
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
if (target === "sdk" && !SDK_MANAGED_KEYS.has(name)) {
|
|
457
|
-
legacyAppLines.push(...block);
|
|
458
|
-
continue;
|
|
459
|
-
}
|
|
460
|
-
const parsed = parseDevVarsStrict(block.join("\n"), ".env");
|
|
461
|
-
Object.assign(sections[target], parsed);
|
|
462
|
-
}
|
|
463
|
-
if (legacyAppLines.length) {
|
|
464
|
-
Object.assign(sections.synced, stripSdkManaged(parseDevVarsStrict(legacyAppLines.join("\n"), ".env")));
|
|
465
|
-
}
|
|
466
|
-
return sections;
|
|
467
|
-
}
|
|
468
|
-
function assignmentName(line) {
|
|
469
|
-
const eq = line.indexOf("=");
|
|
470
|
-
if (eq < 0) return null;
|
|
471
|
-
const match = line.slice(0, eq).match(/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*$/);
|
|
472
|
-
return match?.[1] ?? null;
|
|
473
|
-
}
|
|
474
|
-
function readManagedAppEnv(appDir) {
|
|
475
|
-
const sections = readManagedEnvSections(appDir);
|
|
476
|
-
return { ...sections.synced, ...sections.devOnly };
|
|
477
|
-
}
|
|
478
|
-
function readManagedSyncedEnv(appDir) {
|
|
479
|
-
return { ...readManagedEnvSections(appDir).synced };
|
|
480
|
-
}
|
|
481
|
-
function readManagedDevOnlyEnv(appDir) {
|
|
482
|
-
return { ...readManagedEnvSections(appDir).devOnly };
|
|
483
|
-
}
|
|
484
|
-
function writeManagedEnvSections(appDir, sections) {
|
|
485
|
-
ensureLocalEnvIgnored(appDir);
|
|
486
|
-
const lines = [
|
|
487
|
-
MANAGED_ENV_HEADER,
|
|
488
|
-
"# Do not commit this file. Edit secrets with `deepspace secrets`, not by hand."
|
|
489
|
-
];
|
|
490
|
-
for (const [name, value] of Object.entries(sortRecord(sections.sdk))) {
|
|
491
|
-
lines.push(`${name}=${quoteEnvValue(value)}`);
|
|
492
|
-
}
|
|
493
|
-
lines.push("", MANAGED_ENV_SYNCED_HEADER);
|
|
494
|
-
for (const [name, value] of Object.entries(sortRecord(sections.synced))) {
|
|
495
|
-
lines.push(`${name}=${quoteEnvValue(value)}`);
|
|
496
|
-
}
|
|
497
|
-
lines.push("", MANAGED_ENV_DEV_ONLY_HEADER);
|
|
498
|
-
for (const [name, value] of Object.entries(sortRecord(sections.devOnly))) {
|
|
499
|
-
lines.push(`${name}=${quoteEnvValue(value)}`);
|
|
500
|
-
}
|
|
501
|
-
writeFileSync(localEnvPath(appDir), lines.join("\n") + "\n", { mode: 384 });
|
|
502
|
-
}
|
|
503
|
-
function ensureLocalEnvIgnored(appDir) {
|
|
504
|
-
const path = join2(appDir, ".gitignore");
|
|
505
|
-
const existing = existsSync2(path) ? readFileSync2(path, "utf-8") : "";
|
|
506
|
-
const lines = new Set(existing.split("\n").map((line) => line.trim()));
|
|
507
|
-
const additions = [".env", ".dev.vars"].filter((entry) => !lines.has(entry));
|
|
508
|
-
if (!additions.length) return;
|
|
509
|
-
const prefix = existing && !existing.endsWith("\n") ? existing + "\n" : existing;
|
|
510
|
-
writeFileSync(path, `${prefix}${additions.join("\n")}
|
|
511
|
-
`);
|
|
512
|
-
}
|
|
513
|
-
function patchManagedSyncedEnv(appDir, set2 = {}, removeNames = []) {
|
|
514
|
-
const sections = readManagedEnvSections(appDir);
|
|
515
|
-
for (const [name, value] of Object.entries(set2)) sections.synced[name] = value;
|
|
516
|
-
for (const name of removeNames) delete sections.synced[name];
|
|
517
|
-
writeManagedEnvSections(appDir, sections);
|
|
518
|
-
}
|
|
519
|
-
function patchManagedDevOnlyEnv(appDir, set2 = {}, removeNames = []) {
|
|
520
|
-
const sections = readManagedEnvSections(appDir);
|
|
521
|
-
for (const [name, value] of Object.entries(set2)) sections.devOnly[name] = value;
|
|
522
|
-
for (const name of removeNames) delete sections.devOnly[name];
|
|
523
|
-
writeManagedEnvSections(appDir, sections);
|
|
524
|
-
}
|
|
525
|
-
function replaceManagedSyncedEnv(appDir, syncedVars) {
|
|
526
|
-
const sections = readManagedEnvSections(appDir);
|
|
527
|
-
sections.synced = stripSdkManaged(syncedVars);
|
|
528
|
-
writeManagedEnvSections(appDir, sections);
|
|
529
|
-
}
|
|
530
|
-
function moveManagedDevOnlyToSynced(appDir, names) {
|
|
531
|
-
const sections = readManagedEnvSections(appDir);
|
|
532
|
-
for (const name of names) {
|
|
533
|
-
if (name in sections.devOnly) {
|
|
534
|
-
sections.synced[name] = sections.devOnly[name];
|
|
535
|
-
delete sections.devOnly[name];
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
writeManagedEnvSections(appDir, sections);
|
|
539
|
-
}
|
|
540
346
|
async function writeDevVars(appDir, env, ownerId, callerJwt, wranglerEnv) {
|
|
541
347
|
const urls = ENVS[env];
|
|
542
348
|
const publicKey = await fetchPublicKey(urls.auth);
|
|
@@ -552,18 +358,11 @@ async function writeDevVars(appDir, env, ownerId, callerJwt, wranglerEnv) {
|
|
|
552
358
|
`OWNER_USER_ID=${ownerId}`,
|
|
553
359
|
`APP_OWNER_JWT=${appOwnerJwt}`,
|
|
554
360
|
...appIdentityToken ? [`APP_IDENTITY_TOKEN=${appIdentityToken}`] : [],
|
|
555
|
-
`APP_SECRETS_LOCAL_FALLBACK=true`,
|
|
556
361
|
// Open /api/debug/* (proxied to RecordRoom) for dev + tests only.
|
|
557
362
|
// Production secrets never set this, so deployed apps 404 the route.
|
|
558
363
|
`ALLOW_DEBUG_ROUTES=true`
|
|
559
364
|
].join("\n");
|
|
560
|
-
const
|
|
561
|
-
if (!hasLegacyDevVars(appDir, wranglerEnv)) {
|
|
562
|
-
const sections = readManagedEnvSections(appDir);
|
|
563
|
-
writeManagedEnvSections(appDir, { ...sections, sdk: sdkEnv });
|
|
564
|
-
return;
|
|
565
|
-
}
|
|
566
|
-
const devVarsPath = legacyDevVarsPath(appDir, wranglerEnv);
|
|
365
|
+
const devVarsPath = join2(appDir, wranglerEnv ? `.dev.vars.${wranglerEnv}` : ".dev.vars");
|
|
567
366
|
const existing = existsSync2(devVarsPath) ? readFileSync2(devVarsPath, "utf-8") : "";
|
|
568
367
|
const custom = extractCustomDevVars(existing);
|
|
569
368
|
const body = custom ? `${sdkVars}
|
|
@@ -772,7 +571,7 @@ var logout_default = defineCommand2({
|
|
|
772
571
|
});
|
|
773
572
|
|
|
774
573
|
// src/cli/commands/dev.ts
|
|
775
|
-
import { defineCommand as
|
|
574
|
+
import { defineCommand as defineCommand3 } from "citty";
|
|
776
575
|
import { resolve as resolve3, basename } from "path";
|
|
777
576
|
import spawn from "cross-spawn";
|
|
778
577
|
|
|
@@ -782,8 +581,8 @@ import { join as join5 } from "path";
|
|
|
782
581
|
import { homedir as homedir3 } from "os";
|
|
783
582
|
|
|
784
583
|
// src/cli/jwt.ts
|
|
785
|
-
function decodeJwtPayload(
|
|
786
|
-
const payloadSegment =
|
|
584
|
+
function decodeJwtPayload(token) {
|
|
585
|
+
const payloadSegment = token.split(".")[1];
|
|
787
586
|
if (!payloadSegment) {
|
|
788
587
|
throw new Error("JWT payload is missing");
|
|
789
588
|
}
|
|
@@ -806,13 +605,13 @@ async function ensureToken() {
|
|
|
806
605
|
throw new Error("Not logged in. Run `deepspace login` first.");
|
|
807
606
|
}
|
|
808
607
|
const sessionToken = readFileSync4(SESSION_PATH2, "utf-8").trim();
|
|
809
|
-
const
|
|
810
|
-
if (!
|
|
608
|
+
const token = await exchangeSession(AUTH_URL3, sessionToken);
|
|
609
|
+
if (!token) {
|
|
811
610
|
throw new Error("Session expired. Run `deepspace login` to re-authenticate.");
|
|
812
611
|
}
|
|
813
612
|
mkdirSync2(DIR2, { recursive: true, mode: 448 });
|
|
814
|
-
writeFileSync3(TOKEN_PATH2,
|
|
815
|
-
return
|
|
613
|
+
writeFileSync3(TOKEN_PATH2, token, { mode: 384 });
|
|
614
|
+
return token;
|
|
816
615
|
}
|
|
817
616
|
function isTokenValid(jwt) {
|
|
818
617
|
try {
|
|
@@ -947,525 +746,9 @@ function preflightWindowsWorkerd(appDir) {
|
|
|
947
746
|
}
|
|
948
747
|
}
|
|
949
748
|
|
|
950
|
-
// src/cli/commands/secrets.ts
|
|
951
|
-
import { existsSync as existsSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
|
|
952
|
-
import { join as join8 } from "path";
|
|
953
|
-
import { defineCommand as defineCommand3 } from "citty";
|
|
954
|
-
var SECRET_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
955
|
-
var ERROR_SNIPPET_CHARS = 500;
|
|
956
|
-
var COLLABORATOR_ROUTES_404 = "Platform API does not expose app-collaborator routes; deploy/update api-worker before using collaborator commands.";
|
|
957
|
-
var COLLABORATOR_SCHEMA_NOT_MIGRATED = "Platform API is missing app-collaborator database tables. Run api-worker /_migrate with x-migration-secret, then retry collaborator commands.";
|
|
958
|
-
function parseAssignment(value) {
|
|
959
|
-
const eq = value.indexOf("=");
|
|
960
|
-
if (eq <= 0) throw new Error("Use KEY=value.");
|
|
961
|
-
const name = value.slice(0, eq);
|
|
962
|
-
if (!SECRET_NAME_RE.test(name)) throw new Error(`Invalid secret name "${name}".`);
|
|
963
|
-
if (SDK_MANAGED_KEYS.has(name)) throw new Error(`${name} is managed by DeepSpace and cannot be set as an app secret.`);
|
|
964
|
-
return [name, value.slice(eq + 1)];
|
|
965
|
-
}
|
|
966
|
-
function devTargetPath() {
|
|
967
|
-
return join8(process.cwd(), ".dev.vars");
|
|
968
|
-
}
|
|
969
|
-
function readDevTarget() {
|
|
970
|
-
if (!hasLegacyDevVars(process.cwd())) {
|
|
971
|
-
return readManagedAppEnv(process.cwd());
|
|
972
|
-
}
|
|
973
|
-
const path = devTargetPath();
|
|
974
|
-
if (!existsSync8(path)) return {};
|
|
975
|
-
return stripSdkManaged(parseDevVars(splitDevTarget(readFileSync7(path, "utf-8")).custom));
|
|
976
|
-
}
|
|
977
|
-
function readSyncedTarget() {
|
|
978
|
-
if (hasLegacyDevVars(process.cwd())) return readDevTarget();
|
|
979
|
-
return readManagedSyncedEnv(process.cwd());
|
|
980
|
-
}
|
|
981
|
-
function readDevOnlyTarget() {
|
|
982
|
-
if (hasLegacyDevVars(process.cwd())) return readDevTarget();
|
|
983
|
-
return readManagedDevOnlyEnv(process.cwd());
|
|
984
|
-
}
|
|
985
|
-
function writeLocalPatch(set2 = {}, removeNames = []) {
|
|
986
|
-
for (const name of [...Object.keys(set2), ...removeNames]) {
|
|
987
|
-
if (SDK_MANAGED_KEYS.has(name)) {
|
|
988
|
-
throw new Error(`${name} is managed by DeepSpace and cannot be set as an app secret.`);
|
|
989
|
-
}
|
|
990
|
-
}
|
|
991
|
-
if (hasLegacyDevVars(process.cwd())) writeDevTargetPatch(set2, removeNames);
|
|
992
|
-
else {
|
|
993
|
-
patchManagedDevOnlyEnv(process.cwd(), set2, removeNames);
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
function quote(value) {
|
|
997
|
-
return quoteEnvValue(value);
|
|
998
|
-
}
|
|
999
|
-
function splitLocal(raw) {
|
|
1000
|
-
const idx = raw.indexOf(DEV_VARS_DIVIDER);
|
|
1001
|
-
if (idx < 0) return { top: "", custom: raw };
|
|
1002
|
-
const after = raw.slice(idx + DEV_VARS_DIVIDER.length);
|
|
1003
|
-
return {
|
|
1004
|
-
top: raw.slice(0, idx).trimEnd(),
|
|
1005
|
-
custom: after.startsWith("\n") ? after.slice(1) : after
|
|
1006
|
-
};
|
|
1007
|
-
}
|
|
1008
|
-
function splitDevTarget(raw) {
|
|
1009
|
-
const idx = raw.indexOf(DEV_VARS_DIVIDER);
|
|
1010
|
-
if (idx >= 0) return splitLocal(raw);
|
|
1011
|
-
const lines = raw.split("\n");
|
|
1012
|
-
const top = [];
|
|
1013
|
-
const custom = [];
|
|
1014
|
-
let target = top;
|
|
1015
|
-
let i = 0;
|
|
1016
|
-
while (i < lines.length) {
|
|
1017
|
-
const line = lines[i];
|
|
1018
|
-
const name = assignmentName2(line);
|
|
1019
|
-
const eq = line.indexOf("=");
|
|
1020
|
-
const valStart = eq >= 0 ? line.slice(eq + 1) : "";
|
|
1021
|
-
const block = [line];
|
|
1022
|
-
i++;
|
|
1023
|
-
if (name && valStart.startsWith('"') && !hasUnescapedQuote2(valStart.slice(1))) {
|
|
1024
|
-
while (i < lines.length) {
|
|
1025
|
-
block.push(lines[i]);
|
|
1026
|
-
const closed = hasUnescapedQuote2(lines[i]);
|
|
1027
|
-
i++;
|
|
1028
|
-
if (closed) break;
|
|
1029
|
-
}
|
|
1030
|
-
}
|
|
1031
|
-
if (name && !SDK_MANAGED_KEYS.has(name)) target = custom;
|
|
1032
|
-
target.push(...block);
|
|
1033
|
-
}
|
|
1034
|
-
while (top.length && top[top.length - 1] === "") top.pop();
|
|
1035
|
-
while (custom.length && custom[custom.length - 1] === "") custom.pop();
|
|
1036
|
-
return { top: top.join("\n"), custom: custom.join("\n") };
|
|
1037
|
-
}
|
|
1038
|
-
function assignmentName2(line) {
|
|
1039
|
-
const eq = line.indexOf("=");
|
|
1040
|
-
if (eq < 0) return null;
|
|
1041
|
-
const match = line.slice(0, eq).match(/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*$/);
|
|
1042
|
-
return match?.[1] ?? null;
|
|
1043
|
-
}
|
|
1044
|
-
function hasUnescapedQuote2(s) {
|
|
1045
|
-
let escaped = false;
|
|
1046
|
-
for (const ch of s) {
|
|
1047
|
-
if (escaped) {
|
|
1048
|
-
escaped = false;
|
|
1049
|
-
continue;
|
|
1050
|
-
}
|
|
1051
|
-
if (ch === "\\") {
|
|
1052
|
-
escaped = true;
|
|
1053
|
-
continue;
|
|
1054
|
-
}
|
|
1055
|
-
if (ch === '"') return true;
|
|
1056
|
-
}
|
|
1057
|
-
return false;
|
|
1058
|
-
}
|
|
1059
|
-
function rewriteCustomSection(custom, set2, remove2) {
|
|
1060
|
-
const lines = custom.split("\n");
|
|
1061
|
-
const out = [];
|
|
1062
|
-
const pending = new Set(Object.keys(set2));
|
|
1063
|
-
let i = 0;
|
|
1064
|
-
while (i < lines.length) {
|
|
1065
|
-
const line = lines[i];
|
|
1066
|
-
const name = assignmentName2(line);
|
|
1067
|
-
const eq = line.indexOf("=");
|
|
1068
|
-
const valStart = eq >= 0 ? line.slice(eq + 1) : "";
|
|
1069
|
-
const block = [line];
|
|
1070
|
-
i++;
|
|
1071
|
-
if (name && valStart.startsWith('"') && !hasUnescapedQuote2(valStart.slice(1))) {
|
|
1072
|
-
while (i < lines.length) {
|
|
1073
|
-
block.push(lines[i]);
|
|
1074
|
-
const closed = hasUnescapedQuote2(lines[i]);
|
|
1075
|
-
i++;
|
|
1076
|
-
if (closed) break;
|
|
1077
|
-
}
|
|
1078
|
-
}
|
|
1079
|
-
if (name && (remove2.has(name) || pending.has(name))) {
|
|
1080
|
-
if (pending.has(name)) {
|
|
1081
|
-
out.push(`${name}=${quote(set2[name])}`);
|
|
1082
|
-
pending.delete(name);
|
|
1083
|
-
}
|
|
1084
|
-
continue;
|
|
1085
|
-
}
|
|
1086
|
-
out.push(...block);
|
|
1087
|
-
}
|
|
1088
|
-
while (out.length && out[out.length - 1] === "") out.pop();
|
|
1089
|
-
for (const name of Array.from(pending).sort()) {
|
|
1090
|
-
out.push(`${name}=${quote(set2[name])}`);
|
|
1091
|
-
}
|
|
1092
|
-
return out.join("\n");
|
|
1093
|
-
}
|
|
1094
|
-
function writeDevTargetPatch(set2 = {}, removeNames = []) {
|
|
1095
|
-
const path = devTargetPath();
|
|
1096
|
-
const existing = existsSync8(path) ? readFileSync7(path, "utf-8") : "";
|
|
1097
|
-
const { top, custom: existingCustom } = splitDevTarget(existing);
|
|
1098
|
-
const custom = rewriteCustomSection(existingCustom, set2, new Set(removeNames));
|
|
1099
|
-
const body = top ? `${top}
|
|
1100
|
-
|
|
1101
|
-
${DEV_VARS_DIVIDER}
|
|
1102
|
-
${custom}${custom ? "\n" : ""}` : `${DEV_VARS_DIVIDER}
|
|
1103
|
-
${custom}${custom ? "\n" : ""}`;
|
|
1104
|
-
writeFileSync5(path, body);
|
|
1105
|
-
}
|
|
1106
|
-
async function remoteDeployState(appName, token2) {
|
|
1107
|
-
const res = await fetch(`${process.env.DEEPSPACE_DEPLOY_URL ?? "https://deploy-worker.deep.space"}/api/deploy/${encodeURIComponent(appName)}`, {
|
|
1108
|
-
headers: { Authorization: `Bearer ${token2}` }
|
|
1109
|
-
});
|
|
1110
|
-
const text2 = await res.text().catch(() => "");
|
|
1111
|
-
let body = {};
|
|
1112
|
-
if (text2) {
|
|
1113
|
-
try {
|
|
1114
|
-
body = JSON.parse(text2);
|
|
1115
|
-
} catch (err) {
|
|
1116
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
1117
|
-
throw new Error(`Could not determine deploy status for ${appName}: invalid JSON response (${message}).`);
|
|
1118
|
-
}
|
|
1119
|
-
}
|
|
1120
|
-
if (!res.ok) {
|
|
1121
|
-
const detail = body.error ?? (text2 || "unknown error");
|
|
1122
|
-
throw new Error(`Could not determine deploy status for ${appName} (${res.status}): ${detail}`);
|
|
1123
|
-
}
|
|
1124
|
-
if (body.deployed === true) return "deployed";
|
|
1125
|
-
if (body.deployed === false) return "not-deployed";
|
|
1126
|
-
throw new Error(`Could not determine deploy status for ${appName}: response missing "deployed".`);
|
|
1127
|
-
}
|
|
1128
|
-
async function remoteAvailable(appName, token2) {
|
|
1129
|
-
return await remoteDeployState(appName, token2) === "deployed";
|
|
1130
|
-
}
|
|
1131
|
-
async function mintScopedSecretsToken(appName, token2) {
|
|
1132
|
-
const body = await collaboratorFetch(appName, token2, "/secrets-token", { method: "POST" });
|
|
1133
|
-
if (!body.token) throw new Error("Platform API did not return an app-secret access token.");
|
|
1134
|
-
return body.token;
|
|
1135
|
-
}
|
|
1136
|
-
async function remoteFetch(appName, token2, path = "", init = {}) {
|
|
1137
|
-
const scopedToken = await mintScopedSecretsToken(appName, token2);
|
|
1138
|
-
const res = await fetch(`https://${appName}.app.space/_deepspace/secrets${path}`, {
|
|
1139
|
-
...init,
|
|
1140
|
-
headers: {
|
|
1141
|
-
"Content-Type": "application/json",
|
|
1142
|
-
Authorization: `Bearer ${scopedToken}`,
|
|
1143
|
-
...init.headers ?? {}
|
|
1144
|
-
}
|
|
1145
|
-
});
|
|
1146
|
-
const contentType = res.headers.get("content-type") ?? "unknown";
|
|
1147
|
-
const text2 = await res.text().catch(() => "");
|
|
1148
|
-
let body = null;
|
|
1149
|
-
let parseError = null;
|
|
1150
|
-
if (text2 && contentType.toLowerCase().includes("json")) {
|
|
1151
|
-
try {
|
|
1152
|
-
body = JSON.parse(text2);
|
|
1153
|
-
} catch (err) {
|
|
1154
|
-
parseError = err instanceof Error ? err.message : String(err);
|
|
1155
|
-
}
|
|
1156
|
-
}
|
|
1157
|
-
if (!res.ok) {
|
|
1158
|
-
if (body?.error) throw new Error(body.error);
|
|
1159
|
-
const snippet = text2 ? ` Body: ${text2.slice(0, ERROR_SNIPPET_CHARS)}` : " Body: <empty>";
|
|
1160
|
-
const parseDetail2 = parseError ? ` JSON parse failed: ${parseError}.` : "";
|
|
1161
|
-
throw new Error(`Remote secrets request failed (${res.status}; content-type: ${contentType}).${parseDetail2}${snippet}`);
|
|
1162
|
-
}
|
|
1163
|
-
if (body) return body;
|
|
1164
|
-
if (!text2) return {};
|
|
1165
|
-
const parseDetail = parseError ? ` JSON parse failed: ${parseError}.` : "";
|
|
1166
|
-
throw new Error(`Remote secrets response was not JSON (${res.status}; content-type: ${contentType}).${parseDetail} Body: ${text2.slice(0, ERROR_SNIPPET_CHARS)}`);
|
|
1167
|
-
}
|
|
1168
|
-
function apiUrl() {
|
|
1169
|
-
return process.env.DEEPSPACE_API_URL ?? ENVS.prod.api;
|
|
1170
|
-
}
|
|
1171
|
-
async function collaboratorFetch(appName, token2, path, init = {}) {
|
|
1172
|
-
const url = `${apiUrl()}/api/app-collaborators/${encodeURIComponent(appName)}${path}`;
|
|
1173
|
-
const res = await fetch(url, {
|
|
1174
|
-
...init,
|
|
1175
|
-
headers: {
|
|
1176
|
-
"Content-Type": "application/json",
|
|
1177
|
-
Authorization: `Bearer ${token2}`,
|
|
1178
|
-
...init.headers ?? {}
|
|
1179
|
-
}
|
|
1180
|
-
});
|
|
1181
|
-
const text2 = await res.text().catch(() => "");
|
|
1182
|
-
let body = {};
|
|
1183
|
-
if (text2) {
|
|
1184
|
-
try {
|
|
1185
|
-
body = JSON.parse(text2);
|
|
1186
|
-
} catch {
|
|
1187
|
-
if (res.status === 404) throw new Error(COLLABORATOR_ROUTES_404);
|
|
1188
|
-
if (!res.ok) throw new Error(`Collaborator request failed (${res.status}): ${text2.slice(0, ERROR_SNIPPET_CHARS)}`);
|
|
1189
|
-
throw new Error(`Collaborator response was not JSON (${res.status}): ${text2.slice(0, ERROR_SNIPPET_CHARS)}`);
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1192
|
-
if (!res.ok) {
|
|
1193
|
-
if (res.status === 404 && (!body.error || body.error === "Not found" || body.error === "not_found")) {
|
|
1194
|
-
throw new Error(COLLABORATOR_ROUTES_404);
|
|
1195
|
-
}
|
|
1196
|
-
if (body.error === "platform_schema_not_migrated") {
|
|
1197
|
-
const diagnostic = body;
|
|
1198
|
-
const action = typeof diagnostic.action === "string" ? ` ${diagnostic.action}` : "";
|
|
1199
|
-
throw new Error(`${COLLABORATOR_SCHEMA_NOT_MIGRATED}${action}`);
|
|
1200
|
-
}
|
|
1201
|
-
throw new Error(body.error ?? `Collaborator request failed (${res.status})`);
|
|
1202
|
-
}
|
|
1203
|
-
return body;
|
|
1204
|
-
}
|
|
1205
|
-
async function requireRemoteSecretsAvailable(appName, token2) {
|
|
1206
|
-
const state = await remoteDeployState(appName, token2);
|
|
1207
|
-
if (state === "deployed") return;
|
|
1208
|
-
throw new Error(
|
|
1209
|
-
"Remote secrets are available after the first deploy. Deploy this app first, then run `deepspace secrets push`; `deepspace secrets set --dev` writes dev-only secrets for `deepspace dev` without touching remote."
|
|
1210
|
-
);
|
|
1211
|
-
}
|
|
1212
|
-
function diffMaps(local, remote) {
|
|
1213
|
-
const localOnly = [];
|
|
1214
|
-
const remoteOnly = [];
|
|
1215
|
-
const changed = [];
|
|
1216
|
-
const matching = [];
|
|
1217
|
-
for (const [name, value] of Object.entries(local)) {
|
|
1218
|
-
if (!(name in remote)) localOnly.push(name);
|
|
1219
|
-
else if (remote[name] !== value) changed.push(name);
|
|
1220
|
-
else matching.push(name);
|
|
1221
|
-
}
|
|
1222
|
-
for (const name of Object.keys(remote)) {
|
|
1223
|
-
if (!(name in local)) remoteOnly.push(name);
|
|
1224
|
-
}
|
|
1225
|
-
return { localOnly, remoteOnly, changed, matching };
|
|
1226
|
-
}
|
|
1227
|
-
function diffNames(local, remote) {
|
|
1228
|
-
const localSet = new Set(local);
|
|
1229
|
-
const remoteSet = new Set(remote);
|
|
1230
|
-
return {
|
|
1231
|
-
localOnly: local.filter((name) => !remoteSet.has(name)).sort(),
|
|
1232
|
-
remoteOnly: remote.filter((name) => !localSet.has(name)).sort()
|
|
1233
|
-
};
|
|
1234
|
-
}
|
|
1235
|
-
function statusLine(d, remote) {
|
|
1236
|
-
if (!remote) return "Secrets: remote unavailable until first deploy; dev-only .env section updated.";
|
|
1237
|
-
if (!d || !d.localOnly.length && !d.remoteOnly.length && !d.changed.length) {
|
|
1238
|
-
return "Secrets: synced .env section matches remote.";
|
|
1239
|
-
}
|
|
1240
|
-
return `Secrets: ${d.localOnly.length} local-only, ${d.remoteOnly.length} remote-only, ${d.changed.length} changed. Run \`deepspace secrets diff\`.`;
|
|
1241
|
-
}
|
|
1242
|
-
function nameStatusLine(d) {
|
|
1243
|
-
if (!d.localOnly.length && !d.remoteOnly.length) {
|
|
1244
|
-
return "Secrets: synced .env section has the same names as remote.";
|
|
1245
|
-
}
|
|
1246
|
-
return `Secrets: ${d.localOnly.length} local-only, ${d.remoteOnly.length} remote-only. Run \`deepspace secrets diff\` to compare values.`;
|
|
1247
|
-
}
|
|
1248
|
-
async function compare(appName, token2) {
|
|
1249
|
-
if (!await remoteAvailable(appName, token2)) return null;
|
|
1250
|
-
const local = readSyncedTarget();
|
|
1251
|
-
const remote = await remoteFetch(appName, token2, "/pull");
|
|
1252
|
-
return diffMaps(local, remote.secrets ?? {});
|
|
1253
|
-
}
|
|
1254
|
-
var set = defineCommand3({
|
|
1255
|
-
meta: { name: "set", description: "Set an app secret" },
|
|
1256
|
-
args: {
|
|
1257
|
-
assignment: { type: "positional", required: true, description: "KEY=value" },
|
|
1258
|
-
dev: {
|
|
1259
|
-
type: "boolean",
|
|
1260
|
-
default: false,
|
|
1261
|
-
description: "Write only to the dev-only .env section used by `deepspace dev`; never sync to the deployed app"
|
|
1262
|
-
}
|
|
1263
|
-
},
|
|
1264
|
-
async run({ args }) {
|
|
1265
|
-
const [name, value] = parseAssignment(String(args.assignment));
|
|
1266
|
-
const token2 = await ensureToken();
|
|
1267
|
-
const appName = requireAppName(void 0);
|
|
1268
|
-
if (args.dev) {
|
|
1269
|
-
writeLocalPatch({ [name]: value });
|
|
1270
|
-
console.log("Secrets: updated dev-only .env section for `deepspace dev`; remote was not changed.");
|
|
1271
|
-
return;
|
|
1272
|
-
}
|
|
1273
|
-
const state = await remoteDeployState(appName, token2);
|
|
1274
|
-
if (state === "not-deployed") {
|
|
1275
|
-
writeLocalPatch({ [name]: value });
|
|
1276
|
-
console.log("Secrets: app is not deployed; wrote to dev-only .env section. Run `deepspace secrets push` after deploy.");
|
|
1277
|
-
return;
|
|
1278
|
-
}
|
|
1279
|
-
await remoteFetch(appName, token2, "", { method: "PATCH", body: JSON.stringify({ set: { [name]: value } }) });
|
|
1280
|
-
if (hasLegacyDevVars(process.cwd())) writeDevTargetPatch({ [name]: value });
|
|
1281
|
-
else patchManagedSyncedEnv(process.cwd(), { [name]: value });
|
|
1282
|
-
console.log("Secrets: updated remote and synced .env section.");
|
|
1283
|
-
}
|
|
1284
|
-
});
|
|
1285
|
-
var unset = defineCommand3({
|
|
1286
|
-
meta: { name: "unset", description: "Remove an app secret" },
|
|
1287
|
-
args: {
|
|
1288
|
-
name: { type: "positional", required: true, description: "Secret name" },
|
|
1289
|
-
dev: {
|
|
1290
|
-
type: "boolean",
|
|
1291
|
-
default: false,
|
|
1292
|
-
description: "Remove only from the dev-only .env section used by `deepspace dev`; never sync to the deployed app"
|
|
1293
|
-
}
|
|
1294
|
-
},
|
|
1295
|
-
async run({ args }) {
|
|
1296
|
-
const name = String(args.name);
|
|
1297
|
-
if (!SECRET_NAME_RE.test(name)) throw new Error(`Invalid secret name "${name}".`);
|
|
1298
|
-
const token2 = await ensureToken();
|
|
1299
|
-
const appName = requireAppName(void 0);
|
|
1300
|
-
if (args.dev) {
|
|
1301
|
-
writeLocalPatch({}, [name]);
|
|
1302
|
-
console.log("Secrets: removed from dev-only .env section; remote was not changed.");
|
|
1303
|
-
return;
|
|
1304
|
-
}
|
|
1305
|
-
const state = await remoteDeployState(appName, token2);
|
|
1306
|
-
if (state === "not-deployed") {
|
|
1307
|
-
writeLocalPatch({}, [name]);
|
|
1308
|
-
console.log("Secrets: app is not deployed; removed from dev-only .env section if present.");
|
|
1309
|
-
return;
|
|
1310
|
-
}
|
|
1311
|
-
await remoteFetch(appName, token2, "", { method: "PATCH", body: JSON.stringify({ delete: [name] }) });
|
|
1312
|
-
if (hasLegacyDevVars(process.cwd())) writeDevTargetPatch({}, [name]);
|
|
1313
|
-
else patchManagedSyncedEnv(process.cwd(), {}, [name]);
|
|
1314
|
-
console.log("Secrets: removed from remote and synced .env section.");
|
|
1315
|
-
}
|
|
1316
|
-
});
|
|
1317
|
-
var list = defineCommand3({
|
|
1318
|
-
meta: { name: "list", description: "List app secret names and metadata" },
|
|
1319
|
-
async run() {
|
|
1320
|
-
const token2 = await ensureToken();
|
|
1321
|
-
const appName = requireAppName(void 0);
|
|
1322
|
-
await requireRemoteSecretsAvailable(appName, token2);
|
|
1323
|
-
const body = await remoteFetch(appName, token2);
|
|
1324
|
-
for (const item of body.secrets ?? []) console.log(`${item.name} version=${item.version} updated=${item.updatedAt}`);
|
|
1325
|
-
const d = diffNames(Object.keys(readSyncedTarget()), (body.secrets ?? []).map((item) => item.name));
|
|
1326
|
-
console.log(nameStatusLine(d));
|
|
1327
|
-
}
|
|
1328
|
-
});
|
|
1329
|
-
var pull = defineCommand3({
|
|
1330
|
-
meta: { name: "pull", description: "Pull remote app secrets into the synced .env section" },
|
|
1331
|
-
async run() {
|
|
1332
|
-
const token2 = await ensureToken();
|
|
1333
|
-
const appName = requireAppName(void 0);
|
|
1334
|
-
await requireRemoteSecretsAvailable(appName, token2);
|
|
1335
|
-
const body = await remoteFetch(appName, token2, "/pull");
|
|
1336
|
-
const remoteSecrets = body.secrets ?? {};
|
|
1337
|
-
if (hasLegacyDevVars(process.cwd())) {
|
|
1338
|
-
writeDevTargetPatch(remoteSecrets);
|
|
1339
|
-
} else {
|
|
1340
|
-
replaceManagedSyncedEnv(process.cwd(), remoteSecrets);
|
|
1341
|
-
}
|
|
1342
|
-
const count = Object.keys(remoteSecrets).length;
|
|
1343
|
-
console.log(`Secrets: pulled ${count} remote secret${count === 1 ? "" : "s"} into synced .env section.`);
|
|
1344
|
-
}
|
|
1345
|
-
});
|
|
1346
|
-
var push = defineCommand3({
|
|
1347
|
-
meta: { name: "push", description: "Push dev-only .env secrets to remote and move them to synced" },
|
|
1348
|
-
async run() {
|
|
1349
|
-
const token2 = await ensureToken();
|
|
1350
|
-
const appName = requireAppName(void 0);
|
|
1351
|
-
const local = readDevOnlyTarget();
|
|
1352
|
-
await requireRemoteSecretsAvailable(appName, token2);
|
|
1353
|
-
const names = Object.keys(local);
|
|
1354
|
-
if (!names.length) {
|
|
1355
|
-
console.log("Secrets: no dev-only .env secrets to push.");
|
|
1356
|
-
return;
|
|
1357
|
-
}
|
|
1358
|
-
await remoteFetch(appName, token2, "", { method: "PATCH", body: JSON.stringify({ set: local }) });
|
|
1359
|
-
if (hasLegacyDevVars(process.cwd())) {
|
|
1360
|
-
console.log(`Secrets: pushed ${names.length} dev-only secret${names.length === 1 ? "" : "s"} to remote.`);
|
|
1361
|
-
} else {
|
|
1362
|
-
moveManagedDevOnlyToSynced(process.cwd(), names);
|
|
1363
|
-
console.log(`Secrets: pushed ${names.length} dev-only secret${names.length === 1 ? "" : "s"} to remote and moved ${names.length === 1 ? "it" : "them"} to synced .env section.`);
|
|
1364
|
-
}
|
|
1365
|
-
}
|
|
1366
|
-
});
|
|
1367
|
-
var diff = defineCommand3({
|
|
1368
|
-
meta: { name: "diff", description: "Compare synced .env section with remote app secrets" },
|
|
1369
|
-
async run() {
|
|
1370
|
-
const token2 = await ensureToken();
|
|
1371
|
-
const appName = requireAppName(void 0);
|
|
1372
|
-
await requireRemoteSecretsAvailable(appName, token2);
|
|
1373
|
-
const d = await compare(appName, token2);
|
|
1374
|
-
for (const name of d?.localOnly ?? []) console.log(`local-only ${name}`);
|
|
1375
|
-
for (const name of d?.remoteOnly ?? []) console.log(`remote-only ${name}`);
|
|
1376
|
-
for (const name of d?.changed ?? []) console.log(`changed ${name}`);
|
|
1377
|
-
console.log(statusLine(d, true));
|
|
1378
|
-
}
|
|
1379
|
-
});
|
|
1380
|
-
var collaboratorsList = defineCommand3({
|
|
1381
|
-
meta: { name: "list", description: "List app secret collaborators" },
|
|
1382
|
-
async run() {
|
|
1383
|
-
const token2 = await ensureToken();
|
|
1384
|
-
const appName = requireAppName(void 0);
|
|
1385
|
-
const body = await collaboratorFetch(appName, token2, "/collaborators");
|
|
1386
|
-
for (const item of body.collaborators ?? []) {
|
|
1387
|
-
console.log(`${item.emailDisplay} ${item.userId} created=${new Date(item.createdAt).toISOString()}`);
|
|
1388
|
-
}
|
|
1389
|
-
if (!body.collaborators?.length) console.log("No secrets collaborators.");
|
|
1390
|
-
}
|
|
1391
|
-
});
|
|
1392
|
-
var collaboratorsAdd = defineCommand3({
|
|
1393
|
-
meta: { name: "add", description: "Add an existing DeepSpace user as a secrets collaborator" },
|
|
1394
|
-
args: {
|
|
1395
|
-
email: { type: "positional", required: true, description: "Collaborator email" }
|
|
1396
|
-
},
|
|
1397
|
-
async run({ args }) {
|
|
1398
|
-
const token2 = await ensureToken();
|
|
1399
|
-
const appName = requireAppName(void 0);
|
|
1400
|
-
const body = await collaboratorFetch(appName, token2, "/collaborators", {
|
|
1401
|
-
method: "POST",
|
|
1402
|
-
body: JSON.stringify({ email: String(args.email) })
|
|
1403
|
-
});
|
|
1404
|
-
console.log(`Added ${body.collaborator.emailDisplay} (${body.collaborator.userId}) as a secrets collaborator.`);
|
|
1405
|
-
}
|
|
1406
|
-
});
|
|
1407
|
-
var collaboratorsRemove = defineCommand3({
|
|
1408
|
-
meta: { name: "remove", description: "Remove a secrets collaborator" },
|
|
1409
|
-
args: {
|
|
1410
|
-
target: { type: "positional", required: true, description: "Collaborator email or user id" }
|
|
1411
|
-
},
|
|
1412
|
-
async run({ args }) {
|
|
1413
|
-
const token2 = await ensureToken();
|
|
1414
|
-
const appName = requireAppName(void 0);
|
|
1415
|
-
const target = String(args.target);
|
|
1416
|
-
let userId = target;
|
|
1417
|
-
if (target.includes("@")) {
|
|
1418
|
-
const body = await collaboratorFetch(appName, token2, "/collaborators");
|
|
1419
|
-
const normalized = target.trim().toLowerCase();
|
|
1420
|
-
const match = body.collaborators.find((item) => item.emailNormalized === normalized);
|
|
1421
|
-
if (!match) throw new Error(`No collaborator found for ${target}.`);
|
|
1422
|
-
userId = match.userId;
|
|
1423
|
-
}
|
|
1424
|
-
await collaboratorFetch(appName, token2, `/collaborators/${encodeURIComponent(userId)}`, { method: "DELETE" });
|
|
1425
|
-
console.log(`Removed secrets collaborator ${target}.`);
|
|
1426
|
-
}
|
|
1427
|
-
});
|
|
1428
|
-
var invitesList = defineCommand3({
|
|
1429
|
-
meta: { name: "list", description: "List app secret collaborator invites" },
|
|
1430
|
-
async run() {
|
|
1431
|
-
const token2 = await ensureToken();
|
|
1432
|
-
const appName = requireAppName(void 0);
|
|
1433
|
-
const body = await collaboratorFetch(appName, token2, "/invites");
|
|
1434
|
-
for (const invite of body.invites ?? []) {
|
|
1435
|
-
const status2 = invite.revokedAt ? "revoked" : invite.acceptedAt ? "accepted" : new Date(invite.expiresAt).getTime() <= Date.now() ? "expired" : "pending";
|
|
1436
|
-
console.log(`${invite.id} ${invite.emailDisplay} status=${status2} expires=${new Date(invite.expiresAt).toISOString()}`);
|
|
1437
|
-
}
|
|
1438
|
-
if (!body.invites?.length) console.log("No secrets collaborator invites.");
|
|
1439
|
-
}
|
|
1440
|
-
});
|
|
1441
|
-
var invitesRevoke = defineCommand3({
|
|
1442
|
-
meta: { name: "revoke", description: "Revoke a pending app secret collaborator invite" },
|
|
1443
|
-
args: {
|
|
1444
|
-
inviteId: { type: "positional", required: true, description: "Invite id" }
|
|
1445
|
-
},
|
|
1446
|
-
async run({ args }) {
|
|
1447
|
-
const token2 = await ensureToken();
|
|
1448
|
-
const appName = requireAppName(void 0);
|
|
1449
|
-
await collaboratorFetch(appName, token2, `/invites/${encodeURIComponent(String(args.inviteId))}`, { method: "DELETE" });
|
|
1450
|
-
console.log(`Revoked secrets collaborator invite ${String(args.inviteId)}.`);
|
|
1451
|
-
}
|
|
1452
|
-
});
|
|
1453
|
-
var invites = defineCommand3({
|
|
1454
|
-
meta: { name: "invites", description: "Manage app secret collaborator invites" },
|
|
1455
|
-
subCommands: { list: invitesList, revoke: invitesRevoke }
|
|
1456
|
-
});
|
|
1457
|
-
var collaborators = defineCommand3({
|
|
1458
|
-
meta: { name: "collaborators", description: "Manage app secret collaborators" },
|
|
1459
|
-
subCommands: { list: collaboratorsList, add: collaboratorsAdd, remove: collaboratorsRemove, invites }
|
|
1460
|
-
});
|
|
1461
|
-
var secrets_default = defineCommand3({
|
|
1462
|
-
meta: { name: "secrets", description: "Manage app-owned DeepSpace secrets" },
|
|
1463
|
-
subCommands: { set, unset, list, pull, push, diff, collaborators }
|
|
1464
|
-
});
|
|
1465
|
-
|
|
1466
749
|
// src/cli/commands/dev.ts
|
|
1467
750
|
var DEFAULT_PORT = 5173;
|
|
1468
|
-
var dev_default =
|
|
751
|
+
var dev_default = defineCommand3({
|
|
1469
752
|
meta: {
|
|
1470
753
|
name: "dev",
|
|
1471
754
|
description: "Start local development server"
|
|
@@ -1483,18 +766,13 @@ var dev_default = defineCommand4({
|
|
|
1483
766
|
},
|
|
1484
767
|
env: {
|
|
1485
768
|
type: "string",
|
|
1486
|
-
description: "wrangler.toml [env.<name>] block to run (e.g. --env staging).
|
|
769
|
+
description: "wrangler.toml [env.<name>] block to run (e.g. --env staging). Reads .dev.vars.<name> and applies the env's overrides at build time.",
|
|
1487
770
|
required: false
|
|
1488
771
|
},
|
|
1489
772
|
port: {
|
|
1490
773
|
type: "string",
|
|
1491
774
|
description: `Port to bind (default ${DEFAULT_PORT}, or $DEEPSPACE_PORT)`,
|
|
1492
775
|
required: false
|
|
1493
|
-
},
|
|
1494
|
-
"no-pull-env": {
|
|
1495
|
-
type: "boolean",
|
|
1496
|
-
description: "Skip pulling remote app secrets into the synced .env section on startup",
|
|
1497
|
-
default: false
|
|
1498
776
|
}
|
|
1499
777
|
},
|
|
1500
778
|
async run({ args }) {
|
|
@@ -1516,40 +794,25 @@ var dev_default = defineCommand4({
|
|
|
1516
794
|
}
|
|
1517
795
|
writeLaunchConfigIfMissing(appDir, detectAppName(appDir) ?? basename(appDir), port);
|
|
1518
796
|
ensureInstallReady(appDir);
|
|
1519
|
-
let
|
|
797
|
+
let token;
|
|
1520
798
|
try {
|
|
1521
|
-
|
|
799
|
+
token = await ensureToken();
|
|
1522
800
|
} catch (err) {
|
|
1523
801
|
console.error(err.message);
|
|
1524
802
|
process.exit(1);
|
|
1525
803
|
}
|
|
1526
804
|
let payload;
|
|
1527
805
|
try {
|
|
1528
|
-
payload = decodeJwtPayload(
|
|
806
|
+
payload = decodeJwtPayload(token);
|
|
1529
807
|
} catch {
|
|
1530
808
|
console.error("Malformed session token. Run `npx deepspace login`.");
|
|
1531
809
|
process.exit(1);
|
|
1532
810
|
}
|
|
1533
|
-
console.log(`Logged in as ${payload.name ?? payload.email}`);
|
|
1534
|
-
console.log(`Platform: ${env}`);
|
|
1535
|
-
if (wranglerEnv) console.log(`Wrangler env: ${wranglerEnv}`);
|
|
1536
|
-
console.log(`Port: ${port}`);
|
|
1537
|
-
await writeDevVars(appDir, env, payload.sub,
|
|
1538
|
-
if (env === "dev" && !args["no-pull-env"] && !hasLegacyDevVars(appDir, wranglerEnv)) {
|
|
1539
|
-
const appName = resolveCurrentAppName(appDir, wranglerEnv);
|
|
1540
|
-
if (appName) {
|
|
1541
|
-
try {
|
|
1542
|
-
if (await remoteAvailable(appName, token2)) {
|
|
1543
|
-
const body = await remoteFetch(appName, token2, "/pull");
|
|
1544
|
-
replaceManagedSyncedEnv(appDir, body.secrets ?? {});
|
|
1545
|
-
console.log("Secrets: pulled remote app secrets into synced .env section.");
|
|
1546
|
-
}
|
|
1547
|
-
} catch (err) {
|
|
1548
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
1549
|
-
console.warn(`Secrets: remote app secrets pull skipped (${message}).`);
|
|
1550
|
-
}
|
|
1551
|
-
}
|
|
1552
|
-
}
|
|
811
|
+
console.log(`Logged in as ${payload.name ?? payload.email}`);
|
|
812
|
+
console.log(`Platform: ${env}`);
|
|
813
|
+
if (wranglerEnv) console.log(`Wrangler env: ${wranglerEnv}`);
|
|
814
|
+
console.log(`Port: ${port}`);
|
|
815
|
+
await writeDevVars(appDir, env, payload.sub, token, wranglerEnv);
|
|
1553
816
|
preflightWindowsWorkerd(appDir);
|
|
1554
817
|
console.log("Starting dev server...\n");
|
|
1555
818
|
const vite = spawn(
|
|
@@ -1559,10 +822,9 @@ var dev_default = defineCommand4({
|
|
|
1559
822
|
cwd: appDir,
|
|
1560
823
|
stdio: "inherit",
|
|
1561
824
|
// CLOUDFLARE_ENV is what the Cloudflare Vite plugin keys off — it
|
|
1562
|
-
// applies `[env.<name>]` overrides
|
|
1563
|
-
//
|
|
1564
|
-
//
|
|
1565
|
-
// exactly as before.
|
|
825
|
+
// applies `[env.<name>]` overrides and loads `.dev.vars.<name>`
|
|
826
|
+
// instead of `.dev.vars`. Set only when --env was passed so the
|
|
827
|
+
// default invocation behaves exactly as before.
|
|
1566
828
|
env: {
|
|
1567
829
|
...process.env,
|
|
1568
830
|
DEEPSPACE_PORT: String(port),
|
|
@@ -1585,23 +847,15 @@ function resolvePort(arg) {
|
|
|
1585
847
|
}
|
|
1586
848
|
return n;
|
|
1587
849
|
}
|
|
1588
|
-
function resolveCurrentAppName(appDir, wranglerEnv) {
|
|
1589
|
-
try {
|
|
1590
|
-
const resolved = resolveAppNameForEnv(readWranglerConfig(appDir), wranglerEnv);
|
|
1591
|
-
return resolved.ok ? resolved.name : null;
|
|
1592
|
-
} catch {
|
|
1593
|
-
return null;
|
|
1594
|
-
}
|
|
1595
|
-
}
|
|
1596
850
|
|
|
1597
851
|
// src/cli/commands/kill.ts
|
|
1598
|
-
import { defineCommand as
|
|
852
|
+
import { defineCommand as defineCommand4 } from "citty";
|
|
1599
853
|
import { spawnSync } from "child_process";
|
|
1600
854
|
import { setTimeout as wait } from "timers/promises";
|
|
1601
855
|
var DEFAULT_PORT2 = 5173;
|
|
1602
856
|
var SIGTERM_GRACE_MS = 1500;
|
|
1603
857
|
var IS_WIN = process.platform === "win32";
|
|
1604
|
-
var kill_default =
|
|
858
|
+
var kill_default = defineCommand4({
|
|
1605
859
|
meta: {
|
|
1606
860
|
name: "kill",
|
|
1607
861
|
description: "Kill the local dev server and any orphaned workerd processes"
|
|
@@ -1756,7 +1010,7 @@ function isAlive(pid) {
|
|
|
1756
1010
|
}
|
|
1757
1011
|
|
|
1758
1012
|
// src/cli/commands/test.ts
|
|
1759
|
-
import { defineCommand as
|
|
1013
|
+
import { defineCommand as defineCommand5 } from "citty";
|
|
1760
1014
|
import { resolve as resolve4 } from "path";
|
|
1761
1015
|
import { sync as spawnSync3 } from "cross-spawn";
|
|
1762
1016
|
|
|
@@ -1786,7 +1040,7 @@ function ensurePlaywright(appDir) {
|
|
|
1786
1040
|
|
|
1787
1041
|
// src/cli/commands/test.ts
|
|
1788
1042
|
var DEFAULT_PORT3 = 5173;
|
|
1789
|
-
var test_default =
|
|
1043
|
+
var test_default = defineCommand5({
|
|
1790
1044
|
meta: {
|
|
1791
1045
|
name: "test",
|
|
1792
1046
|
description: "Run tests for your DeepSpace app"
|
|
@@ -1820,17 +1074,17 @@ var test_default = defineCommand6({
|
|
|
1820
1074
|
process.exit(1);
|
|
1821
1075
|
}
|
|
1822
1076
|
ensureInstallReady(appDir);
|
|
1823
|
-
let
|
|
1077
|
+
let token;
|
|
1824
1078
|
let ownerId;
|
|
1825
1079
|
try {
|
|
1826
|
-
|
|
1827
|
-
const payload = decodeJwtPayload(
|
|
1080
|
+
token = await ensureToken();
|
|
1081
|
+
const payload = decodeJwtPayload(token);
|
|
1828
1082
|
ownerId = payload.sub;
|
|
1829
1083
|
} catch (err) {
|
|
1830
1084
|
console.error("`deepspace test` requires you to be logged in. Run `deepspace login` first.");
|
|
1831
1085
|
process.exit(1);
|
|
1832
1086
|
}
|
|
1833
|
-
await writeDevVars(appDir, "dev", ownerId,
|
|
1087
|
+
await writeDevVars(appDir, "dev", ownerId, token);
|
|
1834
1088
|
if (suite !== "unit") {
|
|
1835
1089
|
preflightWindowsWorkerd(appDir);
|
|
1836
1090
|
ensurePlaywright(appDir);
|
|
@@ -1901,10 +1155,10 @@ function resolvePort3(arg) {
|
|
|
1901
1155
|
}
|
|
1902
1156
|
|
|
1903
1157
|
// src/cli/commands/screenshot.ts
|
|
1904
|
-
import { defineCommand as
|
|
1158
|
+
import { defineCommand as defineCommand6 } from "citty";
|
|
1905
1159
|
import { sync as spawnSync4 } from "cross-spawn";
|
|
1906
1160
|
import { resolve as resolve5 } from "path";
|
|
1907
|
-
var screenshot_default =
|
|
1161
|
+
var screenshot_default = defineCommand6({
|
|
1908
1162
|
meta: {
|
|
1909
1163
|
name: "screenshot",
|
|
1910
1164
|
description: "Take a Playwright screenshot, installing Chromium on demand"
|
|
@@ -1948,30 +1202,30 @@ var screenshot_default = defineCommand7({
|
|
|
1948
1202
|
});
|
|
1949
1203
|
|
|
1950
1204
|
// src/cli/commands/test-accounts.ts
|
|
1951
|
-
import { defineCommand as
|
|
1205
|
+
import { defineCommand as defineCommand7 } from "citty";
|
|
1952
1206
|
import * as p3 from "@clack/prompts";
|
|
1953
|
-
import { readFileSync as
|
|
1954
|
-
import { join as
|
|
1207
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync8, mkdirSync as mkdirSync4 } from "fs";
|
|
1208
|
+
import { join as join8 } from "path";
|
|
1955
1209
|
import { homedir as homedir4 } from "os";
|
|
1956
1210
|
var SESSION_COOKIE2 = "__Secure-better-auth.session_token";
|
|
1957
1211
|
var AUTH_URL4 = process.env.DEEPSPACE_AUTH_URL ?? ENVS.prod.auth;
|
|
1958
|
-
var DIR3 =
|
|
1959
|
-
var ACCOUNTS_PATH =
|
|
1212
|
+
var DIR3 = join8(homedir4(), ".deepspace");
|
|
1213
|
+
var ACCOUNTS_PATH = join8(DIR3, "test-accounts.json");
|
|
1960
1214
|
function loadAccounts() {
|
|
1961
|
-
if (!
|
|
1215
|
+
if (!existsSync8(ACCOUNTS_PATH)) return [];
|
|
1962
1216
|
try {
|
|
1963
|
-
return JSON.parse(
|
|
1217
|
+
return JSON.parse(readFileSync7(ACCOUNTS_PATH, "utf-8"));
|
|
1964
1218
|
} catch {
|
|
1965
1219
|
return [];
|
|
1966
1220
|
}
|
|
1967
1221
|
}
|
|
1968
1222
|
function saveAccounts(accounts) {
|
|
1969
1223
|
mkdirSync4(DIR3, { recursive: true });
|
|
1970
|
-
|
|
1224
|
+
writeFileSync5(ACCOUNTS_PATH, JSON.stringify(accounts, null, 2), { mode: 384 });
|
|
1971
1225
|
}
|
|
1972
1226
|
function sessionCookie() {
|
|
1973
|
-
const
|
|
1974
|
-
return `${SESSION_COOKIE2}=${encodeURIComponent(
|
|
1227
|
+
const token = readFileSync7(SESSION_PATH2, "utf-8").trim();
|
|
1228
|
+
return `${SESSION_COOKIE2}=${encodeURIComponent(token)}`;
|
|
1975
1229
|
}
|
|
1976
1230
|
async function fetchRemoteAccounts() {
|
|
1977
1231
|
const res = await fetch(`${AUTH_URL4}/api/auth/test-accounts`, {
|
|
@@ -1993,7 +1247,7 @@ async function deleteRemote(id) {
|
|
|
1993
1247
|
throw new Error(data.error ?? `DELETE returned ${res.status}`);
|
|
1994
1248
|
}
|
|
1995
1249
|
}
|
|
1996
|
-
var create =
|
|
1250
|
+
var create = defineCommand7({
|
|
1997
1251
|
meta: {
|
|
1998
1252
|
name: "create",
|
|
1999
1253
|
description: "Create a test account"
|
|
@@ -2063,7 +1317,7 @@ var create = defineCommand8({
|
|
|
2063
1317
|
Saved to ${ACCOUNTS_PATH}`);
|
|
2064
1318
|
}
|
|
2065
1319
|
});
|
|
2066
|
-
var
|
|
1320
|
+
var list = defineCommand7({
|
|
2067
1321
|
meta: {
|
|
2068
1322
|
name: "list",
|
|
2069
1323
|
description: "List your test accounts"
|
|
@@ -2098,7 +1352,7 @@ var list2 = defineCommand8({
|
|
|
2098
1352
|
}
|
|
2099
1353
|
}
|
|
2100
1354
|
});
|
|
2101
|
-
var del =
|
|
1355
|
+
var del = defineCommand7({
|
|
2102
1356
|
meta: {
|
|
2103
1357
|
name: "delete",
|
|
2104
1358
|
description: "Delete a test account by --email or --id"
|
|
@@ -2155,7 +1409,7 @@ var del = defineCommand8({
|
|
|
2155
1409
|
console.log(`Test account deleted${targetEmail ? `: ${targetEmail}` : `: ${targetId}`}`);
|
|
2156
1410
|
}
|
|
2157
1411
|
});
|
|
2158
|
-
var clear =
|
|
1412
|
+
var clear = defineCommand7({
|
|
2159
1413
|
meta: {
|
|
2160
1414
|
name: "clear",
|
|
2161
1415
|
description: "Delete all your test accounts (or those matching --label)"
|
|
@@ -2221,25 +1475,25 @@ Failed:`);
|
|
|
2221
1475
|
}
|
|
2222
1476
|
}
|
|
2223
1477
|
});
|
|
2224
|
-
var test_accounts_default =
|
|
1478
|
+
var test_accounts_default = defineCommand7({
|
|
2225
1479
|
meta: {
|
|
2226
1480
|
name: "test-accounts",
|
|
2227
1481
|
description: "Manage test accounts for development"
|
|
2228
1482
|
},
|
|
2229
1483
|
subCommands: {
|
|
2230
1484
|
create,
|
|
2231
|
-
list
|
|
1485
|
+
list,
|
|
2232
1486
|
delete: del,
|
|
2233
1487
|
clear
|
|
2234
1488
|
}
|
|
2235
1489
|
});
|
|
2236
1490
|
|
|
2237
1491
|
// src/cli/commands/deploy.ts
|
|
2238
|
-
import { defineCommand as
|
|
1492
|
+
import { defineCommand as defineCommand8 } from "citty";
|
|
2239
1493
|
import { execSync as execSync2 } from "child_process";
|
|
2240
1494
|
import { randomUUID } from "crypto";
|
|
2241
|
-
import { readFileSync as
|
|
2242
|
-
import { join as
|
|
1495
|
+
import { readFileSync as readFileSync8, readdirSync as readdirSync2, existsSync as existsSync9 } from "fs";
|
|
1496
|
+
import { join as join9, resolve as resolve6, dirname as dirname2 } from "path";
|
|
2243
1497
|
import { pathToFileURL } from "url";
|
|
2244
1498
|
import * as p4 from "@clack/prompts";
|
|
2245
1499
|
|
|
@@ -2268,7 +1522,6 @@ var RESERVED_BINDING_NAMES = /* @__PURE__ */ new Set([
|
|
|
2268
1522
|
"AUTH_WORKER_URL",
|
|
2269
1523
|
"APP_IDENTITY_TOKEN",
|
|
2270
1524
|
"APP_OWNER_JWT",
|
|
2271
|
-
"APP_SECRETS_KEY",
|
|
2272
1525
|
"USAGE_EVENTS"
|
|
2273
1526
|
]);
|
|
2274
1527
|
function validateBindingManifest(manifest) {
|
|
@@ -2449,7 +1702,6 @@ function asObjectArray(v) {
|
|
|
2449
1702
|
// src/cli/commands/deploy.ts
|
|
2450
1703
|
var DEPLOY_URL = process.env.DEEPSPACE_DEPLOY_URL ?? ENVS.prod.deploy;
|
|
2451
1704
|
var API_URL = process.env.DEEPSPACE_API_URL ?? ENVS.prod.api;
|
|
2452
|
-
var SECRET_NAME_RE2 = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
2453
1705
|
var CLOUDFLARE_DEPLOY_ERROR_HINT = "Deployment reached the DeepSpace deploy worker, but Cloudflare's deployment control-plane API failed. This is often caused by a Cloudflare Dashboard/API incident or Workers for Platforms entitlement outage. Already deployed apps should keep serving; wait for Cloudflare to recover and retry.";
|
|
2454
1706
|
var RESERVED_RUN_WORKER_FIRST = /* @__PURE__ */ new Set([
|
|
2455
1707
|
"/api/*",
|
|
@@ -2492,14 +1744,6 @@ function formatDeployWorkerError(status2, error) {
|
|
|
2492
1744
|
|
|
2493
1745
|
Underlying error: ${detail}`;
|
|
2494
1746
|
}
|
|
2495
|
-
function legacyDevVarsAppSecretsRoomWarning(userSecrets, doManifest) {
|
|
2496
|
-
if (!Object.keys(userSecrets).length) return null;
|
|
2497
|
-
const hasAppSecretsRoom = (doManifest ?? []).some(
|
|
2498
|
-
(binding) => binding.binding === "SECRETS_ROOMS" || binding.className === "AppSecretsRoom"
|
|
2499
|
-
);
|
|
2500
|
-
if (!hasAppSecretsRoom) return null;
|
|
2501
|
-
return "Legacy .dev.vars secrets are still being deployed as direct Worker bindings even though AppSecretsRoom is configured. Move these values with `deepspace secrets set` to manage them through the app secrets store.";
|
|
2502
|
-
}
|
|
2503
1747
|
var MAX_GROUP_BYTES = 40 * 1024 * 1024;
|
|
2504
1748
|
var GROUP_BYTES = (() => {
|
|
2505
1749
|
const raw = Number(process.env.DEEPSPACE_DEPLOY_GROUP_BYTES);
|
|
@@ -2544,16 +1788,16 @@ async function postWithRetry(url, makeInit, { attempts = 4, retryServerErrors =
|
|
|
2544
1788
|
if (lastRes) return lastRes;
|
|
2545
1789
|
throw lastErr instanceof Error ? lastErr : new Error(String(lastErr));
|
|
2546
1790
|
}
|
|
2547
|
-
async function abortStagedUpload(appName, uploadId, totalGroups,
|
|
1791
|
+
async function abortStagedUpload(appName, uploadId, totalGroups, token) {
|
|
2548
1792
|
try {
|
|
2549
1793
|
await fetch(
|
|
2550
1794
|
`${DEPLOY_URL}/api/deploy/${appName}/assets?uploadId=${uploadId}&totalGroups=${totalGroups}`,
|
|
2551
|
-
{ method: "DELETE", headers: { Authorization: `Bearer ${
|
|
1795
|
+
{ method: "DELETE", headers: { Authorization: `Bearer ${token}` } }
|
|
2552
1796
|
);
|
|
2553
1797
|
} catch {
|
|
2554
1798
|
}
|
|
2555
1799
|
}
|
|
2556
|
-
var deploy_default =
|
|
1800
|
+
var deploy_default = defineCommand8({
|
|
2557
1801
|
meta: {
|
|
2558
1802
|
name: "deploy",
|
|
2559
1803
|
description: "Build and deploy your DeepSpace app"
|
|
@@ -2595,9 +1839,9 @@ var deploy_default = defineCommand9({
|
|
|
2595
1839
|
}
|
|
2596
1840
|
const appName = nameRes.name;
|
|
2597
1841
|
p4.log.info(envName ? `App: ${appName} (env: ${envName})` : `App: ${appName}`);
|
|
2598
|
-
let
|
|
1842
|
+
let token;
|
|
2599
1843
|
try {
|
|
2600
|
-
|
|
1844
|
+
token = await ensureToken();
|
|
2601
1845
|
} catch (err) {
|
|
2602
1846
|
p4.cancel(err.message);
|
|
2603
1847
|
process.exit(1);
|
|
@@ -2617,18 +1861,18 @@ var deploy_default = defineCommand9({
|
|
|
2617
1861
|
process.exit(1);
|
|
2618
1862
|
}
|
|
2619
1863
|
s.stop("Built");
|
|
2620
|
-
const deployConfigPath =
|
|
2621
|
-
if (!
|
|
1864
|
+
const deployConfigPath = join9(appDir, ".wrangler", "deploy", "config.json");
|
|
1865
|
+
if (!existsSync9(deployConfigPath)) {
|
|
2622
1866
|
p4.cancel("Build output config not found at .wrangler/deploy/config.json");
|
|
2623
1867
|
process.exit(1);
|
|
2624
1868
|
}
|
|
2625
|
-
const deployConfig = JSON.parse(
|
|
1869
|
+
const deployConfig = JSON.parse(readFileSync8(deployConfigPath, "utf-8"));
|
|
2626
1870
|
const outputWranglerPath = resolve6(dirname2(deployConfigPath), deployConfig.configPath);
|
|
2627
|
-
if (!
|
|
1871
|
+
if (!existsSync9(outputWranglerPath)) {
|
|
2628
1872
|
p4.cancel(`Output wrangler.json not found at ${outputWranglerPath}`);
|
|
2629
1873
|
process.exit(1);
|
|
2630
1874
|
}
|
|
2631
|
-
const outputConfig = JSON.parse(
|
|
1875
|
+
const outputConfig = JSON.parse(readFileSync8(outputWranglerPath, "utf-8"));
|
|
2632
1876
|
if (outputConfig.name && outputConfig.name !== appName) {
|
|
2633
1877
|
const envHint = envName ? ` (--env ${envName})` : "";
|
|
2634
1878
|
p4.cancel(
|
|
@@ -2637,20 +1881,20 @@ var deploy_default = defineCommand9({
|
|
|
2637
1881
|
process.exit(1);
|
|
2638
1882
|
}
|
|
2639
1883
|
const workerDir = dirname2(outputWranglerPath);
|
|
2640
|
-
const workerBundlePath =
|
|
1884
|
+
const workerBundlePath = join9(workerDir, outputConfig.main);
|
|
2641
1885
|
const clientDir = outputConfig.assets?.directory ? resolve6(workerDir, outputConfig.assets.directory) : null;
|
|
2642
|
-
if (!
|
|
1886
|
+
if (!existsSync9(workerBundlePath)) {
|
|
2643
1887
|
p4.cancel(`Worker bundle not found at ${workerBundlePath}`);
|
|
2644
1888
|
process.exit(1);
|
|
2645
1889
|
}
|
|
2646
|
-
if (!clientDir || !
|
|
1890
|
+
if (!clientDir || !existsSync9(clientDir)) {
|
|
2647
1891
|
p4.cancel(`Client assets not found at ${clientDir}`);
|
|
2648
1892
|
process.exit(1);
|
|
2649
1893
|
}
|
|
2650
1894
|
s.start("Collecting assets...");
|
|
2651
1895
|
const assets = collectAssets(clientDir);
|
|
2652
1896
|
s.stop(`Collected ${assets.length} assets`);
|
|
2653
|
-
const workerJs =
|
|
1897
|
+
const workerJs = readFileSync8(workerBundlePath, "utf-8");
|
|
2654
1898
|
const doBindings = outputConfig.durable_objects?.bindings;
|
|
2655
1899
|
const sqliteClasses = new Set(
|
|
2656
1900
|
outputConfig.migrations?.flatMap((m) => m.new_sqlite_classes ?? []) ?? []
|
|
@@ -2677,20 +1921,40 @@ var deploy_default = defineCommand9({
|
|
|
2677
1921
|
`Custom bindings: ${customBindings.map((b) => `${b.name} (${b.type})`).join(", ")}`
|
|
2678
1922
|
);
|
|
2679
1923
|
}
|
|
1924
|
+
const devVarsPath = devVarsPathFor(appDir, envName);
|
|
2680
1925
|
let userSecrets = {};
|
|
2681
|
-
if (
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
1926
|
+
if (existsSync9(devVarsPath)) {
|
|
1927
|
+
const customSection = extractCustomDevVars(readFileSync8(devVarsPath, "utf-8"));
|
|
1928
|
+
if (customSection) {
|
|
1929
|
+
try {
|
|
1930
|
+
userSecrets = parseDevVars(customSection);
|
|
1931
|
+
} catch (err) {
|
|
1932
|
+
p4.cancel(`.dev.vars: ${err.message}`);
|
|
1933
|
+
process.exit(1);
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1936
|
+
}
|
|
1937
|
+
const userSecretNames = Object.keys(userSecrets);
|
|
1938
|
+
const declaredBindingNames = /* @__PURE__ */ new Set([
|
|
1939
|
+
...customBindings.map((b) => b.name),
|
|
1940
|
+
...(doManifest ?? []).map((d) => d.binding)
|
|
1941
|
+
]);
|
|
1942
|
+
for (const name of userSecretNames) {
|
|
1943
|
+
if (RESERVED_BINDING_NAMES.has(name)) {
|
|
1944
|
+
p4.cancel(
|
|
1945
|
+
`.dev.vars: "${name}" is a reserved binding name and cannot be used as an app secret.`
|
|
1946
|
+
);
|
|
1947
|
+
process.exit(1);
|
|
1948
|
+
}
|
|
1949
|
+
if (declaredBindingNames.has(name)) {
|
|
1950
|
+
p4.cancel(
|
|
1951
|
+
`.dev.vars: "${name}" collides with a binding declared in wrangler.toml \u2014 rename one or the other.`
|
|
1952
|
+
);
|
|
2687
1953
|
process.exit(1);
|
|
2688
1954
|
}
|
|
2689
1955
|
}
|
|
2690
|
-
if (
|
|
2691
|
-
p4.log.info(`
|
|
2692
|
-
const warning = legacyDevVarsAppSecretsRoomWarning(userSecrets, doManifest);
|
|
2693
|
-
if (warning) p4.log.warn(warning);
|
|
1956
|
+
if (userSecretNames.length) {
|
|
1957
|
+
p4.log.info(`App secrets (from .dev.vars): ${userSecretNames.join(", ")}`);
|
|
2694
1958
|
}
|
|
2695
1959
|
s.start(`Deploying to ${appName}.app.space...`);
|
|
2696
1960
|
const extraRoutes = extractRunWorkerFirst(wranglerConfig);
|
|
@@ -2715,7 +1979,7 @@ var deploy_default = defineCommand9({
|
|
|
2715
1979
|
() => ({
|
|
2716
1980
|
method: "POST",
|
|
2717
1981
|
headers: {
|
|
2718
|
-
Authorization: `Bearer ${
|
|
1982
|
+
Authorization: `Bearer ${token}`,
|
|
2719
1983
|
"Content-Type": "application/json"
|
|
2720
1984
|
},
|
|
2721
1985
|
body: groupJson
|
|
@@ -2723,7 +1987,7 @@ var deploy_default = defineCommand9({
|
|
|
2723
1987
|
);
|
|
2724
1988
|
if (!groupRes.ok) {
|
|
2725
1989
|
const errBody = await groupRes.json().catch(() => ({}));
|
|
2726
|
-
await abortStagedUpload(appName, uploadId, totalGroups,
|
|
1990
|
+
await abortStagedUpload(appName, uploadId, totalGroups, token);
|
|
2727
1991
|
s.stop("Deploy failed");
|
|
2728
1992
|
p4.cancel(
|
|
2729
1993
|
`Asset upload failed on group ${i + 1}/${totalGroups}: ${errBody.error ?? `HTTP ${groupRes.status}`}`
|
|
@@ -2732,7 +1996,7 @@ var deploy_default = defineCommand9({
|
|
|
2732
1996
|
}
|
|
2733
1997
|
}
|
|
2734
1998
|
} catch (err) {
|
|
2735
|
-
await abortStagedUpload(appName, uploadId, totalGroups,
|
|
1999
|
+
await abortStagedUpload(appName, uploadId, totalGroups, token);
|
|
2736
2000
|
s.stop("Deploy failed");
|
|
2737
2001
|
p4.cancel(`Asset upload failed (network): ${err?.message ?? err}`);
|
|
2738
2002
|
process.exit(1);
|
|
@@ -2754,12 +2018,12 @@ var deploy_default = defineCommand9({
|
|
|
2754
2018
|
if (customBindings.length) {
|
|
2755
2019
|
form.append("bindingManifest", JSON.stringify(customBindings));
|
|
2756
2020
|
}
|
|
2021
|
+
if (userSecretNames.length) {
|
|
2022
|
+
form.append("userSecrets", JSON.stringify(userSecrets));
|
|
2023
|
+
}
|
|
2757
2024
|
if (extraRoutes.length) {
|
|
2758
2025
|
form.append("extraRunWorkerFirst", JSON.stringify(extraRoutes));
|
|
2759
2026
|
}
|
|
2760
|
-
if (Object.keys(userSecrets).length) {
|
|
2761
|
-
form.append("userSecrets", JSON.stringify(userSecrets));
|
|
2762
|
-
}
|
|
2763
2027
|
return form;
|
|
2764
2028
|
};
|
|
2765
2029
|
let res;
|
|
@@ -2768,7 +2032,7 @@ var deploy_default = defineCommand9({
|
|
|
2768
2032
|
`${DEPLOY_URL}/api/deploy/${appName}`,
|
|
2769
2033
|
() => ({
|
|
2770
2034
|
method: "POST",
|
|
2771
|
-
headers: { Authorization: `Bearer ${
|
|
2035
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
2772
2036
|
body: makeForm()
|
|
2773
2037
|
}),
|
|
2774
2038
|
// Commit runs a real deploy — don't retry its 5xx (could double-deploy);
|
|
@@ -2777,14 +2041,14 @@ var deploy_default = defineCommand9({
|
|
|
2777
2041
|
{ retryServerErrors: false }
|
|
2778
2042
|
);
|
|
2779
2043
|
} catch (err) {
|
|
2780
|
-
if (uploadId) await abortStagedUpload(appName, uploadId, totalGroups,
|
|
2044
|
+
if (uploadId) await abortStagedUpload(appName, uploadId, totalGroups, token);
|
|
2781
2045
|
s.stop("Deploy failed");
|
|
2782
2046
|
p4.cancel(`Deploy request failed: ${err?.message ?? err}`);
|
|
2783
2047
|
process.exit(1);
|
|
2784
2048
|
}
|
|
2785
2049
|
const body = await res.json().catch(() => ({}));
|
|
2786
2050
|
if (!res.ok || !body.success) {
|
|
2787
|
-
if (uploadId) await abortStagedUpload(appName, uploadId, totalGroups,
|
|
2051
|
+
if (uploadId) await abortStagedUpload(appName, uploadId, totalGroups, token);
|
|
2788
2052
|
s.stop("Deploy failed");
|
|
2789
2053
|
p4.cancel(formatDeployWorkerError(res.status, body.error));
|
|
2790
2054
|
process.exit(1);
|
|
@@ -2796,52 +2060,29 @@ var deploy_default = defineCommand9({
|
|
|
2796
2060
|
s.stop("Deployed (edge propagation still in progress after 90s)");
|
|
2797
2061
|
p4.log.warn("First requests may briefly hit the assets transitional page; retry in a minute.");
|
|
2798
2062
|
p4.log.success(`Live at: ${body.url}`);
|
|
2799
|
-
|
|
2800
|
-
await
|
|
2801
|
-
await syncOneTimeProducts(appDir, appName, token2);
|
|
2063
|
+
await syncSubscriptionPlans(appDir, appName, token);
|
|
2064
|
+
await syncOneTimeProducts(appDir, appName, token);
|
|
2802
2065
|
p4.outro("Done");
|
|
2803
2066
|
return;
|
|
2804
2067
|
}
|
|
2805
2068
|
}
|
|
2806
2069
|
s.stop("Deployed!");
|
|
2807
2070
|
p4.log.success(`Live at: ${body.url}`);
|
|
2808
|
-
|
|
2809
|
-
await
|
|
2810
|
-
await syncOneTimeProducts(appDir, appName, token2);
|
|
2071
|
+
await syncSubscriptionPlans(appDir, appName, token);
|
|
2072
|
+
await syncOneTimeProducts(appDir, appName, token);
|
|
2811
2073
|
p4.outro("Done");
|
|
2812
2074
|
}
|
|
2813
2075
|
});
|
|
2814
|
-
function
|
|
2815
|
-
const
|
|
2816
|
-
if (!
|
|
2817
|
-
const vars = parseDevVars(extractCustomDevVars(readFileSync9(path, "utf-8")));
|
|
2818
|
-
const reserved = /* @__PURE__ */ new Set([
|
|
2819
|
-
...SDK_MANAGED_KEYS,
|
|
2820
|
-
...customBindings.map((b) => b.name),
|
|
2821
|
-
...(doManifest ?? []).flatMap((b) => [b.binding, b.className])
|
|
2822
|
-
]);
|
|
2823
|
-
const out = {};
|
|
2824
|
-
for (const [name, value] of Object.entries(vars)) {
|
|
2825
|
-
if (!SECRET_NAME_RE2.test(name)) {
|
|
2826
|
-
throw new Error(`.dev.vars: invalid secret name "${name}".`);
|
|
2827
|
-
}
|
|
2828
|
-
if (reserved.has(name)) {
|
|
2829
|
-
throw new Error(`.dev.vars: "${name}" is reserved and cannot be deployed as a user secret.`);
|
|
2830
|
-
}
|
|
2831
|
-
out[name] = value;
|
|
2832
|
-
}
|
|
2833
|
-
return out;
|
|
2834
|
-
}
|
|
2835
|
-
async function syncSubscriptionPlans(appDir, appName, token2) {
|
|
2836
|
-
const subsPath = join10(appDir, "src", "subscriptions.ts");
|
|
2837
|
-
if (!existsSync10(subsPath)) return;
|
|
2076
|
+
async function syncSubscriptionPlans(appDir, appName, token) {
|
|
2077
|
+
const subsPath = join9(appDir, "src", "subscriptions.ts");
|
|
2078
|
+
if (!existsSync9(subsPath)) return;
|
|
2838
2079
|
const s = createSpinner();
|
|
2839
2080
|
s.start("Syncing subscription plans...");
|
|
2840
2081
|
let plans;
|
|
2841
2082
|
try {
|
|
2842
2083
|
const esbuild = await import("esbuild");
|
|
2843
|
-
const outDir =
|
|
2844
|
-
const outFile =
|
|
2084
|
+
const outDir = join9(appDir, ".wrangler", "deploy");
|
|
2085
|
+
const outFile = join9(outDir, "subscriptions.bundle.mjs");
|
|
2845
2086
|
await esbuild.build({
|
|
2846
2087
|
entryPoints: [subsPath],
|
|
2847
2088
|
bundle: true,
|
|
@@ -2871,7 +2112,7 @@ async function syncSubscriptionPlans(appDir, appName, token2) {
|
|
|
2871
2112
|
res = await fetch(`${API_URL}/api/subscriptions/sync`, {
|
|
2872
2113
|
method: "POST",
|
|
2873
2114
|
headers: {
|
|
2874
|
-
Authorization: `Bearer ${
|
|
2115
|
+
Authorization: `Bearer ${token}`,
|
|
2875
2116
|
"Content-Type": "application/json"
|
|
2876
2117
|
},
|
|
2877
2118
|
body: JSON.stringify({ appName, plans })
|
|
@@ -2891,7 +2132,7 @@ async function syncSubscriptionPlans(appDir, appName, token2) {
|
|
|
2891
2132
|
}
|
|
2892
2133
|
const changes = (body.planChanges ?? []).filter((c) => c.affectedSubscribers > 0);
|
|
2893
2134
|
if (changes.length > 0) {
|
|
2894
|
-
await promptAndCancelChangedPlans(appName,
|
|
2135
|
+
await promptAndCancelChangedPlans(appName, token, changes);
|
|
2895
2136
|
}
|
|
2896
2137
|
return;
|
|
2897
2138
|
}
|
|
@@ -2912,7 +2153,7 @@ function summaryLine(c) {
|
|
|
2912
2153
|
const diffs = (c.intervals ?? []).map((i) => `${i.interval}: ${formatCents(i.oldCents)} \u2192 ${formatCents(i.newCents)}`).join("; ");
|
|
2913
2154
|
return ` \u2022 ${c.slug} \u2014 repriced (${diffs}; ${suffix} grandfathered on old price)`;
|
|
2914
2155
|
}
|
|
2915
|
-
async function promptAndCancelChangedPlans(appName,
|
|
2156
|
+
async function promptAndCancelChangedPlans(appName, token, changes) {
|
|
2916
2157
|
const summary = changes.map(summaryLine).join("\n");
|
|
2917
2158
|
p4.log.warn(
|
|
2918
2159
|
`Plan change${changes.length === 1 ? "" : "s"} from this deploy left subscribers stranded:
|
|
@@ -2943,7 +2184,7 @@ current billing period? (Skip to leave them grandfathered.)`
|
|
|
2943
2184
|
const res = await fetch(`${API_URL}/api/subscriptions/admin-cancel`, {
|
|
2944
2185
|
method: "POST",
|
|
2945
2186
|
headers: {
|
|
2946
|
-
Authorization: `Bearer ${
|
|
2187
|
+
Authorization: `Bearer ${token}`,
|
|
2947
2188
|
"Content-Type": "application/json"
|
|
2948
2189
|
},
|
|
2949
2190
|
body: JSON.stringify({
|
|
@@ -2981,16 +2222,16 @@ current billing period? (Skip to leave them grandfathered.)`
|
|
|
2981
2222
|
}
|
|
2982
2223
|
}
|
|
2983
2224
|
}
|
|
2984
|
-
async function syncOneTimeProducts(appDir, appName,
|
|
2985
|
-
const productsPath =
|
|
2986
|
-
if (!
|
|
2225
|
+
async function syncOneTimeProducts(appDir, appName, token) {
|
|
2226
|
+
const productsPath = join9(appDir, "src", "products.ts");
|
|
2227
|
+
if (!existsSync9(productsPath)) return;
|
|
2987
2228
|
const s = createSpinner();
|
|
2988
2229
|
s.start("Syncing one-time products...");
|
|
2989
2230
|
let products;
|
|
2990
2231
|
try {
|
|
2991
2232
|
const esbuild = await import("esbuild");
|
|
2992
|
-
const outDir =
|
|
2993
|
-
const outFile =
|
|
2233
|
+
const outDir = join9(appDir, ".wrangler", "deploy");
|
|
2234
|
+
const outFile = join9(outDir, "products.bundle.mjs");
|
|
2994
2235
|
await esbuild.build({
|
|
2995
2236
|
entryPoints: [productsPath],
|
|
2996
2237
|
bundle: true,
|
|
@@ -3020,7 +2261,7 @@ async function syncOneTimeProducts(appDir, appName, token2) {
|
|
|
3020
2261
|
res = await fetch(`${API_URL}/api/charges/products/sync`, {
|
|
3021
2262
|
method: "POST",
|
|
3022
2263
|
headers: {
|
|
3023
|
-
Authorization: `Bearer ${
|
|
2264
|
+
Authorization: `Bearer ${token}`,
|
|
3024
2265
|
"Content-Type": "application/json"
|
|
3025
2266
|
},
|
|
3026
2267
|
body: JSON.stringify({ appName, products })
|
|
@@ -3064,14 +2305,14 @@ function collectAssets(dir) {
|
|
|
3064
2305
|
function walk(d, prefix) {
|
|
3065
2306
|
for (const entry of readdirSync2(d, { withFileTypes: true })) {
|
|
3066
2307
|
if (entry.name === ".assetsignore") continue;
|
|
3067
|
-
const full =
|
|
2308
|
+
const full = join9(d, entry.name);
|
|
3068
2309
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
3069
2310
|
if (entry.isDirectory()) {
|
|
3070
2311
|
walk(full, rel);
|
|
3071
2312
|
} else {
|
|
3072
2313
|
assets.push({
|
|
3073
2314
|
path: "/" + rel,
|
|
3074
|
-
contentBase64:
|
|
2315
|
+
contentBase64: readFileSync8(full).toString("base64")
|
|
3075
2316
|
});
|
|
3076
2317
|
}
|
|
3077
2318
|
}
|
|
@@ -3081,10 +2322,10 @@ function collectAssets(dir) {
|
|
|
3081
2322
|
}
|
|
3082
2323
|
|
|
3083
2324
|
// src/cli/commands/undeploy.ts
|
|
3084
|
-
import { defineCommand as
|
|
2325
|
+
import { defineCommand as defineCommand9 } from "citty";
|
|
3085
2326
|
import * as p5 from "@clack/prompts";
|
|
3086
2327
|
var DEPLOY_URL2 = process.env.DEEPSPACE_DEPLOY_URL ?? ENVS.prod.deploy;
|
|
3087
|
-
var undeploy_default =
|
|
2328
|
+
var undeploy_default = defineCommand9({
|
|
3088
2329
|
meta: {
|
|
3089
2330
|
name: "undeploy",
|
|
3090
2331
|
description: "Remove a deployed DeepSpace app"
|
|
@@ -3119,9 +2360,9 @@ var undeploy_default = defineCommand10({
|
|
|
3119
2360
|
p5.cancel("Provide an app name or run from a DeepSpace app directory.");
|
|
3120
2361
|
process.exit(1);
|
|
3121
2362
|
}
|
|
3122
|
-
let
|
|
2363
|
+
let token;
|
|
3123
2364
|
try {
|
|
3124
|
-
|
|
2365
|
+
token = await ensureToken();
|
|
3125
2366
|
} catch (err) {
|
|
3126
2367
|
p5.cancel(err.message);
|
|
3127
2368
|
process.exit(1);
|
|
@@ -3131,7 +2372,7 @@ var undeploy_default = defineCommand10({
|
|
|
3131
2372
|
s.start("Removing...");
|
|
3132
2373
|
const res = await fetch(`${DEPLOY_URL2}/api/deploy/${appName}`, {
|
|
3133
2374
|
method: "DELETE",
|
|
3134
|
-
headers: { Authorization: `Bearer ${
|
|
2375
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
3135
2376
|
});
|
|
3136
2377
|
const body = await res.json().catch(() => ({}));
|
|
3137
2378
|
if (!res.ok || !body.success) {
|
|
@@ -3145,8 +2386,8 @@ var undeploy_default = defineCommand10({
|
|
|
3145
2386
|
});
|
|
3146
2387
|
|
|
3147
2388
|
// src/cli/commands/whoami.ts
|
|
3148
|
-
import { defineCommand as
|
|
3149
|
-
var whoami_default =
|
|
2389
|
+
import { defineCommand as defineCommand10 } from "citty";
|
|
2390
|
+
var whoami_default = defineCommand10({
|
|
3150
2391
|
meta: {
|
|
3151
2392
|
name: "whoami",
|
|
3152
2393
|
description: "Show the currently logged-in user"
|
|
@@ -3201,18 +2442,18 @@ var whoami_default = defineCommand11({
|
|
|
3201
2442
|
});
|
|
3202
2443
|
|
|
3203
2444
|
// src/cli/commands/add.ts
|
|
3204
|
-
import { defineCommand as
|
|
3205
|
-
import { existsSync as
|
|
3206
|
-
import { resolve as resolve7, join as
|
|
2445
|
+
import { defineCommand as defineCommand11 } from "citty";
|
|
2446
|
+
import { existsSync as existsSync10 } from "fs";
|
|
2447
|
+
import { resolve as resolve7, join as join10 } from "path";
|
|
3207
2448
|
import { execSync as execSync3 } from "child_process";
|
|
3208
2449
|
function findScript(from) {
|
|
3209
|
-
const inNodeModules =
|
|
3210
|
-
if (
|
|
3211
|
-
const inDotDeepspace =
|
|
3212
|
-
if (
|
|
2450
|
+
const inNodeModules = join10(from, "node_modules", "deepspace", "scripts", "add-feature.cjs");
|
|
2451
|
+
if (existsSync10(inNodeModules)) return inNodeModules;
|
|
2452
|
+
const inDotDeepspace = join10(from, ".deepspace", "scripts", "add-feature.cjs");
|
|
2453
|
+
if (existsSync10(inDotDeepspace)) return inDotDeepspace;
|
|
3213
2454
|
return null;
|
|
3214
2455
|
}
|
|
3215
|
-
var add_default =
|
|
2456
|
+
var add_default = defineCommand11({
|
|
3216
2457
|
meta: {
|
|
3217
2458
|
name: "add",
|
|
3218
2459
|
description: "Add a feature to your DeepSpace app"
|
|
@@ -3247,8 +2488,8 @@ var add_default = defineCommand12({
|
|
|
3247
2488
|
if (!script) {
|
|
3248
2489
|
console.error("Could not find the deepspace feature installer.");
|
|
3249
2490
|
console.error("Looked in:");
|
|
3250
|
-
console.error(` ${
|
|
3251
|
-
console.error(` ${
|
|
2491
|
+
console.error(` ${join10(appDir, "node_modules", "deepspace", "scripts", "add-feature.cjs")}`);
|
|
2492
|
+
console.error(` ${join10(appDir, ".deepspace", "scripts", "add-feature.cjs")}`);
|
|
3252
2493
|
console.error("Are you in a DeepSpace app directory? Try `npm install` first.");
|
|
3253
2494
|
process.exit(1);
|
|
3254
2495
|
}
|
|
@@ -3270,10 +2511,10 @@ var add_default = defineCommand12({
|
|
|
3270
2511
|
});
|
|
3271
2512
|
|
|
3272
2513
|
// src/cli/commands/skills.ts
|
|
3273
|
-
import { defineCommand as
|
|
2514
|
+
import { defineCommand as defineCommand12 } from "citty";
|
|
3274
2515
|
import spawn2 from "cross-spawn";
|
|
3275
2516
|
import { mkdirSync as mkdirSync5 } from "fs";
|
|
3276
|
-
import { join as
|
|
2517
|
+
import { join as join11 } from "path";
|
|
3277
2518
|
import { homedir as homedir5 } from "os";
|
|
3278
2519
|
var SKILL_REPO = "deepdotspace/deepspace-skill";
|
|
3279
2520
|
function runSkillsAdd(extraArgs) {
|
|
@@ -3292,9 +2533,9 @@ function runSkillsAdd(extraArgs) {
|
|
|
3292
2533
|
});
|
|
3293
2534
|
}
|
|
3294
2535
|
function precreateClaudeDir(baseDir) {
|
|
3295
|
-
mkdirSync5(
|
|
2536
|
+
mkdirSync5(join11(baseDir, ".claude"), { recursive: true });
|
|
3296
2537
|
}
|
|
3297
|
-
var add =
|
|
2538
|
+
var add = defineCommand12({
|
|
3298
2539
|
meta: {
|
|
3299
2540
|
name: "add",
|
|
3300
2541
|
description: "Install the DeepSpace skill for your coding agent"
|
|
@@ -3336,7 +2577,7 @@ var add = defineCommand13({
|
|
|
3336
2577
|
if (code !== 0) process.exit(code);
|
|
3337
2578
|
}
|
|
3338
2579
|
});
|
|
3339
|
-
var skills_default =
|
|
2580
|
+
var skills_default = defineCommand12({
|
|
3340
2581
|
meta: {
|
|
3341
2582
|
name: "skills",
|
|
3342
2583
|
description: "Manage the DeepSpace agent skill (Claude Code, Codex, OpenCode, Cursor, ...)"
|
|
@@ -3347,14 +2588,14 @@ var skills_default = defineCommand13({
|
|
|
3347
2588
|
});
|
|
3348
2589
|
|
|
3349
2590
|
// src/cli/commands/domain.ts
|
|
3350
|
-
import { defineCommand as
|
|
2591
|
+
import { defineCommand as defineCommand13 } from "citty";
|
|
3351
2592
|
import { execSync as execSync4 } from "child_process";
|
|
3352
2593
|
var API_URL2 = process.env.DEEPSPACE_API_URL ?? ENVS.prod.api;
|
|
3353
|
-
async function api(
|
|
2594
|
+
async function api(token, path, init) {
|
|
3354
2595
|
const res = await fetch(`${API_URL2}${path}`, {
|
|
3355
2596
|
...init,
|
|
3356
2597
|
headers: {
|
|
3357
|
-
Authorization: `Bearer ${
|
|
2598
|
+
Authorization: `Bearer ${token}`,
|
|
3358
2599
|
"Content-Type": "application/json",
|
|
3359
2600
|
...init?.headers ?? {}
|
|
3360
2601
|
}
|
|
@@ -3403,7 +2644,7 @@ async function confirm3(message) {
|
|
|
3403
2644
|
});
|
|
3404
2645
|
});
|
|
3405
2646
|
}
|
|
3406
|
-
var search =
|
|
2647
|
+
var search = defineCommand13({
|
|
3407
2648
|
meta: { name: "search", description: "Search for available domains" },
|
|
3408
2649
|
args: {
|
|
3409
2650
|
query: { type: "positional", description: "Domain or keyword", required: true },
|
|
@@ -3411,10 +2652,10 @@ var search = defineCommand14({
|
|
|
3411
2652
|
json: { type: "boolean", description: "Emit JSON instead of a table" }
|
|
3412
2653
|
},
|
|
3413
2654
|
async run({ args }) {
|
|
3414
|
-
const
|
|
2655
|
+
const token = await ensureToken();
|
|
3415
2656
|
const limit = parseInt(args.limit ?? "10", 10) || 10;
|
|
3416
2657
|
const result = await api(
|
|
3417
|
-
|
|
2658
|
+
token,
|
|
3418
2659
|
`/api/domains/search?q=${encodeURIComponent(args.query)}&limit=${limit}`
|
|
3419
2660
|
);
|
|
3420
2661
|
if (args.json) {
|
|
@@ -3433,7 +2674,7 @@ var search = defineCommand14({
|
|
|
3433
2674
|
}
|
|
3434
2675
|
}
|
|
3435
2676
|
});
|
|
3436
|
-
var buy =
|
|
2677
|
+
var buy = defineCommand13({
|
|
3437
2678
|
meta: { name: "buy", description: "Buy a domain and attach it to an app" },
|
|
3438
2679
|
args: {
|
|
3439
2680
|
domain: { type: "positional", description: "Domain to buy", required: true },
|
|
@@ -3444,9 +2685,9 @@ var buy = defineCommand14({
|
|
|
3444
2685
|
json: { type: "boolean", description: "Emit JSON to stdout", default: false }
|
|
3445
2686
|
},
|
|
3446
2687
|
async run({ args }) {
|
|
3447
|
-
const
|
|
2688
|
+
const token = await ensureToken();
|
|
3448
2689
|
const appName = requireAppName(args.app);
|
|
3449
|
-
const priceCheck = await api(
|
|
2690
|
+
const priceCheck = await api(token, "/api/domains/check", {
|
|
3450
2691
|
method: "POST",
|
|
3451
2692
|
body: JSON.stringify({ domains: [args.domain] })
|
|
3452
2693
|
});
|
|
@@ -3467,7 +2708,7 @@ var buy = defineCommand14({
|
|
|
3467
2708
|
}
|
|
3468
2709
|
}
|
|
3469
2710
|
const checkout = await api(
|
|
3470
|
-
|
|
2711
|
+
token,
|
|
3471
2712
|
"/api/domains/checkout",
|
|
3472
2713
|
{
|
|
3473
2714
|
method: "POST",
|
|
@@ -3494,7 +2735,7 @@ var buy = defineCommand14({
|
|
|
3494
2735
|
await new Promise((r) => setTimeout(r, 5e3));
|
|
3495
2736
|
try {
|
|
3496
2737
|
const detail = await api(
|
|
3497
|
-
|
|
2738
|
+
token,
|
|
3498
2739
|
`/api/domains/${checkout.purchaseId}`
|
|
3499
2740
|
);
|
|
3500
2741
|
if (detail.domain.status !== lastStatus) {
|
|
@@ -3522,14 +2763,14 @@ var buy = defineCommand14({
|
|
|
3522
2763
|
process.exit(1);
|
|
3523
2764
|
}
|
|
3524
2765
|
});
|
|
3525
|
-
var
|
|
2766
|
+
var list2 = defineCommand13({
|
|
3526
2767
|
meta: { name: "list", description: "List your domains" },
|
|
3527
2768
|
args: {
|
|
3528
2769
|
json: { type: "boolean", description: "Emit JSON" }
|
|
3529
2770
|
},
|
|
3530
2771
|
async run({ args }) {
|
|
3531
|
-
const
|
|
3532
|
-
const result = await api(
|
|
2772
|
+
const token = await ensureToken();
|
|
2773
|
+
const result = await api(token, "/api/domains");
|
|
3533
2774
|
if (args.json) {
|
|
3534
2775
|
process.stdout.write(JSON.stringify(scrubInternal(result), null, 2) + "\n");
|
|
3535
2776
|
return;
|
|
@@ -3546,15 +2787,15 @@ var list3 = defineCommand14({
|
|
|
3546
2787
|
}
|
|
3547
2788
|
}
|
|
3548
2789
|
});
|
|
3549
|
-
var status =
|
|
2790
|
+
var status = defineCommand13({
|
|
3550
2791
|
meta: { name: "status", description: "Show details for one domain" },
|
|
3551
2792
|
args: {
|
|
3552
2793
|
domain: { type: "positional", description: "Domain", required: true },
|
|
3553
2794
|
json: { type: "boolean" }
|
|
3554
2795
|
},
|
|
3555
2796
|
async run({ args }) {
|
|
3556
|
-
const
|
|
3557
|
-
const all = await api(
|
|
2797
|
+
const token = await ensureToken();
|
|
2798
|
+
const all = await api(token, "/api/domains");
|
|
3558
2799
|
const found = all.domains.find((d) => d.domain === args.domain);
|
|
3559
2800
|
if (!found) {
|
|
3560
2801
|
console.error(`No domain ${args.domain} in your account`);
|
|
@@ -3574,7 +2815,7 @@ var status = defineCommand14({
|
|
|
3574
2815
|
console.log(`Charged: ${fmtCents(found.chargedCents)}/yr`);
|
|
3575
2816
|
}
|
|
3576
2817
|
});
|
|
3577
|
-
var attach =
|
|
2818
|
+
var attach = defineCommand13({
|
|
3578
2819
|
meta: { name: "attach", description: "Re-point a domain at a different app" },
|
|
3579
2820
|
args: {
|
|
3580
2821
|
domain: { type: "positional", description: "Domain to re-point", required: true },
|
|
@@ -3582,16 +2823,16 @@ var attach = defineCommand14({
|
|
|
3582
2823
|
json: { type: "boolean" }
|
|
3583
2824
|
},
|
|
3584
2825
|
async run({ args }) {
|
|
3585
|
-
const
|
|
2826
|
+
const token = await ensureToken();
|
|
3586
2827
|
const targetApp = requireAppName(args.app);
|
|
3587
|
-
const all = await api(
|
|
2828
|
+
const all = await api(token, "/api/domains");
|
|
3588
2829
|
const found = all.domains.find((d) => d.domain === args.domain);
|
|
3589
2830
|
if (!found) {
|
|
3590
2831
|
console.error(`No domain ${args.domain} in your account`);
|
|
3591
2832
|
process.exit(1);
|
|
3592
2833
|
}
|
|
3593
2834
|
const result = await api(
|
|
3594
|
-
|
|
2835
|
+
token,
|
|
3595
2836
|
`/api/domains/${found.id}/reattach`,
|
|
3596
2837
|
{
|
|
3597
2838
|
method: "POST",
|
|
@@ -3605,7 +2846,7 @@ var attach = defineCommand14({
|
|
|
3605
2846
|
console.log(`\u2713 ${args.domain} now points at ${targetApp}`);
|
|
3606
2847
|
}
|
|
3607
2848
|
});
|
|
3608
|
-
var detach =
|
|
2849
|
+
var detach = defineCommand13({
|
|
3609
2850
|
meta: {
|
|
3610
2851
|
name: "detach",
|
|
3611
2852
|
description: "Stop routing the domain (keeps the registration; auto-renew unchanged)"
|
|
@@ -3615,8 +2856,8 @@ var detach = defineCommand14({
|
|
|
3615
2856
|
yes: { type: "boolean", description: "Skip the confirmation prompt" }
|
|
3616
2857
|
},
|
|
3617
2858
|
async run({ args }) {
|
|
3618
|
-
const
|
|
3619
|
-
const all = await api(
|
|
2859
|
+
const token = await ensureToken();
|
|
2860
|
+
const all = await api(token, "/api/domains");
|
|
3620
2861
|
const found = all.domains.find((d) => d.domain === args.domain);
|
|
3621
2862
|
if (!found) {
|
|
3622
2863
|
console.error(`No domain ${args.domain} in your account`);
|
|
@@ -3631,11 +2872,11 @@ var detach = defineCommand14({
|
|
|
3631
2872
|
return;
|
|
3632
2873
|
}
|
|
3633
2874
|
}
|
|
3634
|
-
await api(
|
|
2875
|
+
await api(token, `/api/domains/${found.id}`, { method: "DELETE" });
|
|
3635
2876
|
console.log(`\u2713 ${args.domain} detached. Use \`deepspace domain attach\` to re-route, or \`renew --auto off\` to stop auto-renewal.`);
|
|
3636
2877
|
}
|
|
3637
2878
|
});
|
|
3638
|
-
var renew =
|
|
2879
|
+
var renew = defineCommand13({
|
|
3639
2880
|
meta: { name: "renew", description: "Toggle auto-renewal at the registrar" },
|
|
3640
2881
|
args: {
|
|
3641
2882
|
domain: { type: "positional", description: "Domain", required: true },
|
|
@@ -3646,15 +2887,15 @@ var renew = defineCommand14({
|
|
|
3646
2887
|
console.error('--auto must be "on" or "off"');
|
|
3647
2888
|
process.exit(1);
|
|
3648
2889
|
}
|
|
3649
|
-
const
|
|
3650
|
-
const all = await api(
|
|
2890
|
+
const token = await ensureToken();
|
|
2891
|
+
const all = await api(token, "/api/domains");
|
|
3651
2892
|
const found = all.domains.find((d) => d.domain === args.domain);
|
|
3652
2893
|
if (!found) {
|
|
3653
2894
|
console.error(`No domain ${args.domain} in your account`);
|
|
3654
2895
|
process.exit(1);
|
|
3655
2896
|
}
|
|
3656
2897
|
const enabled = args.auto === "on";
|
|
3657
|
-
await api(
|
|
2898
|
+
await api(token, `/api/domains/${found.id}/auto-renew`, {
|
|
3658
2899
|
method: "POST",
|
|
3659
2900
|
body: JSON.stringify({ autoRenew: enabled })
|
|
3660
2901
|
});
|
|
@@ -3669,16 +2910,16 @@ function openBrowser2(url) {
|
|
|
3669
2910
|
} catch {
|
|
3670
2911
|
}
|
|
3671
2912
|
}
|
|
3672
|
-
var domain_default =
|
|
2913
|
+
var domain_default = defineCommand13({
|
|
3673
2914
|
meta: { name: "domain", description: "Buy and manage custom domains" },
|
|
3674
|
-
subCommands: { search, buy, list:
|
|
2915
|
+
subCommands: { search, buy, list: list2, status, attach, detach, renew }
|
|
3675
2916
|
});
|
|
3676
2917
|
|
|
3677
2918
|
// src/cli/commands/integrations.ts
|
|
3678
|
-
import { defineCommand as
|
|
2919
|
+
import { defineCommand as defineCommand14 } from "citty";
|
|
3679
2920
|
|
|
3680
2921
|
// src/cli/commands/_invoke-impl.ts
|
|
3681
|
-
import { readFileSync as
|
|
2922
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
3682
2923
|
var API_URL3 = process.env.DEEPSPACE_API_URL ?? ENVS.prod.api;
|
|
3683
2924
|
var DEFAULT_TIMEOUT_MS = 12e4;
|
|
3684
2925
|
function parseTarget(target) {
|
|
@@ -3699,7 +2940,7 @@ function resolveBody(opts) {
|
|
|
3699
2940
|
if (opts.body != null) {
|
|
3700
2941
|
raw = opts.body;
|
|
3701
2942
|
} else if (opts.bodyFile != null) {
|
|
3702
|
-
raw = opts.bodyFile === "-" ?
|
|
2943
|
+
raw = opts.bodyFile === "-" ? readFileSync9(0, "utf-8") : readFileSync9(opts.bodyFile, "utf-8");
|
|
3703
2944
|
} else {
|
|
3704
2945
|
return "{}";
|
|
3705
2946
|
}
|
|
@@ -3850,7 +3091,7 @@ async function runInvoke(args) {
|
|
|
3850
3091
|
}
|
|
3851
3092
|
|
|
3852
3093
|
// src/cli/commands/integrations.ts
|
|
3853
|
-
var
|
|
3094
|
+
var list3 = defineCommand14({
|
|
3854
3095
|
meta: {
|
|
3855
3096
|
name: "list",
|
|
3856
3097
|
description: "List all available integrations"
|
|
@@ -3871,7 +3112,7 @@ var list4 = defineCommand15({
|
|
|
3871
3112
|
}
|
|
3872
3113
|
}
|
|
3873
3114
|
});
|
|
3874
|
-
var info =
|
|
3115
|
+
var info = defineCommand14({
|
|
3875
3116
|
meta: {
|
|
3876
3117
|
name: "info",
|
|
3877
3118
|
description: "Print schema + example body for an integration endpoint"
|
|
@@ -3897,7 +3138,7 @@ var info = defineCommand15({
|
|
|
3897
3138
|
}
|
|
3898
3139
|
}
|
|
3899
3140
|
});
|
|
3900
|
-
var invoke =
|
|
3141
|
+
var invoke = defineCommand14({
|
|
3901
3142
|
meta: {
|
|
3902
3143
|
name: "invoke",
|
|
3903
3144
|
description: "Invoke a platform integration as the logged-in user"
|
|
@@ -3950,21 +3191,21 @@ var invoke = defineCommand15({
|
|
|
3950
3191
|
}
|
|
3951
3192
|
}
|
|
3952
3193
|
});
|
|
3953
|
-
var integrations_default =
|
|
3194
|
+
var integrations_default = defineCommand14({
|
|
3954
3195
|
meta: {
|
|
3955
3196
|
name: "integrations",
|
|
3956
3197
|
description: "List, inspect, and invoke platform integrations"
|
|
3957
3198
|
},
|
|
3958
3199
|
subCommands: {
|
|
3959
|
-
list:
|
|
3200
|
+
list: list3,
|
|
3960
3201
|
info,
|
|
3961
3202
|
invoke
|
|
3962
3203
|
}
|
|
3963
3204
|
});
|
|
3964
3205
|
|
|
3965
3206
|
// src/cli/commands/invoke.ts
|
|
3966
|
-
import { defineCommand as
|
|
3967
|
-
var invoke_default =
|
|
3207
|
+
import { defineCommand as defineCommand15 } from "citty";
|
|
3208
|
+
var invoke_default = defineCommand15({
|
|
3968
3209
|
meta: {
|
|
3969
3210
|
name: "invoke",
|
|
3970
3211
|
description: "Invoke a platform integration as the logged-in user"
|
|
@@ -4036,257 +3277,14 @@ var invoke_default = defineCommand16({
|
|
|
4036
3277
|
}
|
|
4037
3278
|
});
|
|
4038
3279
|
|
|
4039
|
-
// src/cli/commands/managed-repos.ts
|
|
4040
|
-
import { defineCommand as defineCommand17 } from "citty";
|
|
4041
|
-
var API_URL4 = process.env.DEEPSPACE_API_URL ?? ENVS.prod.api;
|
|
4042
|
-
var SIMPLE_APP_ID = /^[a-z0-9][a-z0-9_.:-]{0,119}$/i;
|
|
4043
|
-
var SIMPLE_APP_NAME = /^[a-z0-9][a-z0-9_-]{0,119}$/i;
|
|
4044
|
-
async function api2(token2, path, init) {
|
|
4045
|
-
const res = await fetch(`${API_URL4}${path}`, {
|
|
4046
|
-
...init,
|
|
4047
|
-
headers: {
|
|
4048
|
-
Authorization: `Bearer ${token2}`,
|
|
4049
|
-
"Content-Type": "application/json",
|
|
4050
|
-
...init?.headers ?? {}
|
|
4051
|
-
}
|
|
4052
|
-
});
|
|
4053
|
-
const text2 = await res.text();
|
|
4054
|
-
if (!res.ok) {
|
|
4055
|
-
let msg = text2;
|
|
4056
|
-
try {
|
|
4057
|
-
msg = JSON.parse(text2).error ?? text2;
|
|
4058
|
-
} catch {
|
|
4059
|
-
}
|
|
4060
|
-
throw new Error(`API ${path} (${res.status}): ${msg}`);
|
|
4061
|
-
}
|
|
4062
|
-
return JSON.parse(text2);
|
|
4063
|
-
}
|
|
4064
|
-
function defaultAppId(appName) {
|
|
4065
|
-
return `cli-${slugId(appName)}`;
|
|
4066
|
-
}
|
|
4067
|
-
function slugId(raw) {
|
|
4068
|
-
return raw.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "") || "app";
|
|
4069
|
-
}
|
|
4070
|
-
function assertSimple(value, pattern, label) {
|
|
4071
|
-
if (!pattern.test(value)) {
|
|
4072
|
-
throw new Error(`${label} must start with a letter or number and contain only simple identifier characters.`);
|
|
4073
|
-
}
|
|
4074
|
-
}
|
|
4075
|
-
function printQuota(quota) {
|
|
4076
|
-
console.log(`Repo quota: ${quota.activeCount} / ${quota.limit} active (${quota.remaining} remaining)`);
|
|
4077
|
-
}
|
|
4078
|
-
function printRepo(repo) {
|
|
4079
|
-
console.log(`${repo.fullName}`);
|
|
4080
|
-
console.log(` ID: ${repo.id}`);
|
|
4081
|
-
console.log(` App: ${repo.appName}`);
|
|
4082
|
-
console.log(` App ID: ${repo.appId}`);
|
|
4083
|
-
console.log(` URL: ${repo.htmlUrl}`);
|
|
4084
|
-
console.log(` Clone: ${repo.cloneUrl}`);
|
|
4085
|
-
}
|
|
4086
|
-
async function confirm4(message) {
|
|
4087
|
-
if (!process.stdin.isTTY) {
|
|
4088
|
-
throw new Error(`${message} \u2014 pass --yes to confirm non-interactively`);
|
|
4089
|
-
}
|
|
4090
|
-
process.stdout.write(`${message} [y/N] `);
|
|
4091
|
-
return new Promise((resolve9) => {
|
|
4092
|
-
process.stdin.setEncoding("utf-8");
|
|
4093
|
-
process.stdin.once("data", (data) => {
|
|
4094
|
-
const answer = data.toString().trim().toLowerCase();
|
|
4095
|
-
resolve9(answer === "y" || answer === "yes");
|
|
4096
|
-
});
|
|
4097
|
-
});
|
|
4098
|
-
}
|
|
4099
|
-
var list5 = defineCommand17({
|
|
4100
|
-
meta: {
|
|
4101
|
-
name: "list",
|
|
4102
|
-
description: "List your DeepSpace-managed repos and quota"
|
|
4103
|
-
},
|
|
4104
|
-
args: {
|
|
4105
|
-
json: {
|
|
4106
|
-
type: "boolean",
|
|
4107
|
-
description: "Emit JSON instead of human output",
|
|
4108
|
-
default: false
|
|
4109
|
-
}
|
|
4110
|
-
},
|
|
4111
|
-
async run({ args }) {
|
|
4112
|
-
const token2 = await ensureToken();
|
|
4113
|
-
const result = await api2(token2, "/api/github/repos");
|
|
4114
|
-
if (args.json) {
|
|
4115
|
-
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
4116
|
-
return;
|
|
4117
|
-
}
|
|
4118
|
-
printQuota(result.quota);
|
|
4119
|
-
if (result.repos.length === 0) {
|
|
4120
|
-
console.log("No DeepSpace-managed repos. Create one with `deepspace managed-repos create <app-name>`.");
|
|
4121
|
-
return;
|
|
4122
|
-
}
|
|
4123
|
-
console.log("");
|
|
4124
|
-
for (const repo of result.repos) {
|
|
4125
|
-
printRepo(repo);
|
|
4126
|
-
}
|
|
4127
|
-
}
|
|
4128
|
-
});
|
|
4129
|
-
var create2 = defineCommand17({
|
|
4130
|
-
meta: {
|
|
4131
|
-
name: "create",
|
|
4132
|
-
description: "Create a private DeepSpace-managed GitHub repo"
|
|
4133
|
-
},
|
|
4134
|
-
args: {
|
|
4135
|
-
appName: {
|
|
4136
|
-
type: "positional",
|
|
4137
|
-
description: "Working app name for this repo",
|
|
4138
|
-
required: true
|
|
4139
|
-
},
|
|
4140
|
-
appId: {
|
|
4141
|
-
type: "string",
|
|
4142
|
-
description: "Stable DeepSpace repo app id (defaults to cli-<app-name>)",
|
|
4143
|
-
required: false
|
|
4144
|
-
},
|
|
4145
|
-
nameHint: {
|
|
4146
|
-
type: "string",
|
|
4147
|
-
description: "Repo-name hint (defaults to app name)",
|
|
4148
|
-
required: false
|
|
4149
|
-
},
|
|
4150
|
-
json: {
|
|
4151
|
-
type: "boolean",
|
|
4152
|
-
description: "Emit JSON instead of human output",
|
|
4153
|
-
default: false
|
|
4154
|
-
}
|
|
4155
|
-
},
|
|
4156
|
-
async run({ args }) {
|
|
4157
|
-
const appName = String(args.appName);
|
|
4158
|
-
const appId = args.appId ? String(args.appId) : defaultAppId(appName);
|
|
4159
|
-
const nameHint = args.nameHint ? String(args.nameHint) : void 0;
|
|
4160
|
-
try {
|
|
4161
|
-
assertSimple(appName, SIMPLE_APP_NAME, "appName");
|
|
4162
|
-
assertSimple(appId, SIMPLE_APP_ID, "appId");
|
|
4163
|
-
if (nameHint) assertSimple(nameHint, SIMPLE_APP_NAME, "nameHint");
|
|
4164
|
-
} catch (err) {
|
|
4165
|
-
console.error(err.message);
|
|
4166
|
-
process.exit(1);
|
|
4167
|
-
}
|
|
4168
|
-
const token2 = await ensureToken();
|
|
4169
|
-
const result = await api2(token2, "/api/github/repos", {
|
|
4170
|
-
method: "POST",
|
|
4171
|
-
body: JSON.stringify({ appName, appId, ...nameHint ? { nameHint } : {} })
|
|
4172
|
-
});
|
|
4173
|
-
if (args.json) {
|
|
4174
|
-
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
4175
|
-
return;
|
|
4176
|
-
}
|
|
4177
|
-
console.log(result.alreadyExists ? "Existing DeepSpace-managed repo:" : "Created DeepSpace-managed repo:");
|
|
4178
|
-
printRepo(result.repo);
|
|
4179
|
-
}
|
|
4180
|
-
});
|
|
4181
|
-
var token = defineCommand17({
|
|
4182
|
-
meta: {
|
|
4183
|
-
name: "token",
|
|
4184
|
-
description: "Mint a short-lived GitHub token for a DeepSpace-managed repo"
|
|
4185
|
-
},
|
|
4186
|
-
args: {
|
|
4187
|
-
repoId: {
|
|
4188
|
-
type: "positional",
|
|
4189
|
-
description: "Repo id from `deepspace managed-repos list`",
|
|
4190
|
-
required: true
|
|
4191
|
-
},
|
|
4192
|
-
json: {
|
|
4193
|
-
type: "boolean",
|
|
4194
|
-
description: "Emit JSON instead of human output",
|
|
4195
|
-
default: false
|
|
4196
|
-
}
|
|
4197
|
-
},
|
|
4198
|
-
async run({ args }) {
|
|
4199
|
-
const jwt = await ensureToken();
|
|
4200
|
-
const result = await api2(
|
|
4201
|
-
jwt,
|
|
4202
|
-
`/api/github/repos/${encodeURIComponent(String(args.repoId))}/agent-token`,
|
|
4203
|
-
{ method: "POST" }
|
|
4204
|
-
);
|
|
4205
|
-
if (args.json) {
|
|
4206
|
-
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
4207
|
-
return;
|
|
4208
|
-
}
|
|
4209
|
-
console.log(`Repo: ${result.repo.fullName}`);
|
|
4210
|
-
console.log(`Expires: ${result.token.expiresAt}`);
|
|
4211
|
-
console.log(`Token: ${result.token.token}`);
|
|
4212
|
-
console.log("");
|
|
4213
|
-
console.log(`Clone: git clone https://x-access-token:${encodeURIComponent(result.token.token)}@github.com/${result.repo.fullName}.git`);
|
|
4214
|
-
}
|
|
4215
|
-
});
|
|
4216
|
-
var remove = defineCommand17({
|
|
4217
|
-
meta: {
|
|
4218
|
-
name: "delete",
|
|
4219
|
-
description: "Delete a DeepSpace-managed GitHub repo"
|
|
4220
|
-
},
|
|
4221
|
-
args: {
|
|
4222
|
-
repoId: {
|
|
4223
|
-
type: "positional",
|
|
4224
|
-
description: "Repo id from `deepspace managed-repos list`",
|
|
4225
|
-
required: true
|
|
4226
|
-
},
|
|
4227
|
-
yes: {
|
|
4228
|
-
type: "boolean",
|
|
4229
|
-
description: "Skip the confirmation prompt",
|
|
4230
|
-
default: false
|
|
4231
|
-
},
|
|
4232
|
-
json: {
|
|
4233
|
-
type: "boolean",
|
|
4234
|
-
description: "Emit JSON instead of human output",
|
|
4235
|
-
default: false
|
|
4236
|
-
}
|
|
4237
|
-
},
|
|
4238
|
-
async run({ args }) {
|
|
4239
|
-
if (!args.yes) {
|
|
4240
|
-
try {
|
|
4241
|
-
const ok = await confirm4(
|
|
4242
|
-
"Delete this DeepSpace-managed GitHub repo? This removes the GitHub repository and counts against your daily delete quota."
|
|
4243
|
-
);
|
|
4244
|
-
if (!ok) {
|
|
4245
|
-
console.log("Cancelled.");
|
|
4246
|
-
return;
|
|
4247
|
-
}
|
|
4248
|
-
} catch (err) {
|
|
4249
|
-
console.error(err.message);
|
|
4250
|
-
process.exit(1);
|
|
4251
|
-
}
|
|
4252
|
-
}
|
|
4253
|
-
const jwt = await ensureToken();
|
|
4254
|
-
const result = await api2(
|
|
4255
|
-
jwt,
|
|
4256
|
-
`/api/github/repos/${encodeURIComponent(String(args.repoId))}`,
|
|
4257
|
-
{ method: "DELETE" }
|
|
4258
|
-
);
|
|
4259
|
-
if (args.json) {
|
|
4260
|
-
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
4261
|
-
return;
|
|
4262
|
-
}
|
|
4263
|
-
console.log(`Deleted ${result.repo.fullName}`);
|
|
4264
|
-
console.log(
|
|
4265
|
-
`Delete quota: ${result.deletionQuota.deletedCount} / ${result.deletionQuota.limit} used today (${result.deletionQuota.remaining} remaining)`
|
|
4266
|
-
);
|
|
4267
|
-
}
|
|
4268
|
-
});
|
|
4269
|
-
var managed_repos_default = defineCommand17({
|
|
4270
|
-
meta: {
|
|
4271
|
-
name: "managed-repos",
|
|
4272
|
-
description: "Create and manage DeepSpace-owned GitHub repos"
|
|
4273
|
-
},
|
|
4274
|
-
subCommands: {
|
|
4275
|
-
list: list5,
|
|
4276
|
-
create: create2,
|
|
4277
|
-
token,
|
|
4278
|
-
delete: remove
|
|
4279
|
-
}
|
|
4280
|
-
});
|
|
4281
|
-
|
|
4282
3280
|
// src/cli/commands/library.ts
|
|
4283
|
-
import { defineCommand as
|
|
4284
|
-
import { existsSync as
|
|
4285
|
-
import { join as
|
|
3281
|
+
import { defineCommand as defineCommand16 } from "citty";
|
|
3282
|
+
import { existsSync as existsSync11, readFileSync as readFileSync10 } from "fs";
|
|
3283
|
+
import { join as join12, resolve as resolve8 } from "path";
|
|
4286
3284
|
import { parse as parseToml3 } from "smol-toml";
|
|
4287
3285
|
import * as p6 from "@clack/prompts";
|
|
4288
3286
|
var DEFAULT_LIBRARY_APP = "deepdotspace-site";
|
|
4289
|
-
var publish =
|
|
3287
|
+
var publish = defineCommand16({
|
|
4290
3288
|
meta: {
|
|
4291
3289
|
name: "publish",
|
|
4292
3290
|
description: "Publish the current app to the DeepSpace library"
|
|
@@ -4360,11 +3358,11 @@ var publish = defineCommand18({
|
|
|
4360
3358
|
let appName = typeof args.app === "string" && args.app.trim() ? args.app.trim() : void 0;
|
|
4361
3359
|
if (!appName) {
|
|
4362
3360
|
const appDir = resolve8(typeof args.dir === "string" && args.dir ? args.dir : ".");
|
|
4363
|
-
const wranglerPath =
|
|
4364
|
-
if (!
|
|
3361
|
+
const wranglerPath = join12(appDir, "wrangler.toml");
|
|
3362
|
+
if (!existsSync11(wranglerPath)) {
|
|
4365
3363
|
return die("No --app provided and no wrangler.toml found. Either pass --app <name> or run from your app's directory.");
|
|
4366
3364
|
}
|
|
4367
|
-
const cfg = parseToml3(
|
|
3365
|
+
const cfg = parseToml3(readFileSync10(wranglerPath, "utf-8"));
|
|
4368
3366
|
const nameRes = resolveAppName(cfg.name);
|
|
4369
3367
|
if (!nameRes.ok) return die(`wrangler.toml: ${nameRes.reason}`);
|
|
4370
3368
|
appName = nameRes.name;
|
|
@@ -4377,9 +3375,9 @@ var publish = defineCommand18({
|
|
|
4377
3375
|
const tags = typeof args.tags === "string" && args.tags ? args.tags.split(",").map((t) => t.trim()).filter(Boolean) : void 0;
|
|
4378
3376
|
const libraryApp = typeof args["library-app"] === "string" && args["library-app"] ? args["library-app"] : DEFAULT_LIBRARY_APP;
|
|
4379
3377
|
const libraryHost = process.env.DEEPSPACE_LIBRARY_HOST ?? `https://${libraryApp}.app.space`;
|
|
4380
|
-
let
|
|
3378
|
+
let token;
|
|
4381
3379
|
try {
|
|
4382
|
-
|
|
3380
|
+
token = await ensureToken();
|
|
4383
3381
|
} catch (err) {
|
|
4384
3382
|
return die(err instanceof Error ? err.message : String(err));
|
|
4385
3383
|
}
|
|
@@ -4399,7 +3397,7 @@ var publish = defineCommand18({
|
|
|
4399
3397
|
method: "POST",
|
|
4400
3398
|
headers: {
|
|
4401
3399
|
"Content-Type": "application/json",
|
|
4402
|
-
Authorization: `Bearer ${
|
|
3400
|
+
Authorization: `Bearer ${token}`
|
|
4403
3401
|
},
|
|
4404
3402
|
body: JSON.stringify(payload)
|
|
4405
3403
|
});
|
|
@@ -4425,7 +3423,7 @@ var publish = defineCommand18({
|
|
|
4425
3423
|
p6.outro("Done");
|
|
4426
3424
|
}
|
|
4427
3425
|
});
|
|
4428
|
-
var unpublish =
|
|
3426
|
+
var unpublish = defineCommand16({
|
|
4429
3427
|
meta: {
|
|
4430
3428
|
name: "unpublish",
|
|
4431
3429
|
description: "Remove a library entry (owner or admin only)"
|
|
@@ -4455,9 +3453,9 @@ var unpublish = defineCommand18({
|
|
|
4455
3453
|
process.exit(1);
|
|
4456
3454
|
};
|
|
4457
3455
|
if (!json) p6.intro("Unpublishing library entry");
|
|
4458
|
-
let
|
|
3456
|
+
let token;
|
|
4459
3457
|
try {
|
|
4460
|
-
|
|
3458
|
+
token = await ensureToken();
|
|
4461
3459
|
} catch (err) {
|
|
4462
3460
|
return die(err instanceof Error ? err.message : String(err));
|
|
4463
3461
|
}
|
|
@@ -4465,7 +3463,7 @@ var unpublish = defineCommand18({
|
|
|
4465
3463
|
const libraryHost = process.env.DEEPSPACE_LIBRARY_HOST ?? `https://${libraryApp}.app.space`;
|
|
4466
3464
|
const res = await fetch(`${libraryHost}/api/actions/library.unpublish`, {
|
|
4467
3465
|
method: "POST",
|
|
4468
|
-
headers: { "Content-Type": "application/json", Authorization: `Bearer ${
|
|
3466
|
+
headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
|
|
4469
3467
|
body: JSON.stringify({ templateHandle: String(args.handle) })
|
|
4470
3468
|
});
|
|
4471
3469
|
const body = await res.text();
|
|
@@ -4484,7 +3482,7 @@ var unpublish = defineCommand18({
|
|
|
4484
3482
|
p6.outro("Done");
|
|
4485
3483
|
}
|
|
4486
3484
|
});
|
|
4487
|
-
var library_default =
|
|
3485
|
+
var library_default = defineCommand16({
|
|
4488
3486
|
meta: {
|
|
4489
3487
|
name: "library",
|
|
4490
3488
|
description: "Manage your DeepSpace library entries"
|
|
@@ -4495,86 +3493,14 @@ var library_default = defineCommand18({
|
|
|
4495
3493
|
}
|
|
4496
3494
|
});
|
|
4497
3495
|
|
|
4498
|
-
// src/cli/commands/admin.ts
|
|
4499
|
-
import { defineCommand as defineCommand19 } from "citty";
|
|
4500
|
-
import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync7 } from "fs";
|
|
4501
|
-
import { homedir as homedir6 } from "os";
|
|
4502
|
-
import { join as join14 } from "path";
|
|
4503
|
-
var AUTH_URL5 = process.env.DEEPSPACE_AUTH_URL ?? ENVS.prod.auth;
|
|
4504
|
-
var impersonate = defineCommand19({
|
|
4505
|
-
meta: {
|
|
4506
|
-
name: "impersonate",
|
|
4507
|
-
description: "Store a short-lived CLI token for another user"
|
|
4508
|
-
},
|
|
4509
|
-
args: {
|
|
4510
|
-
email: {
|
|
4511
|
-
type: "string",
|
|
4512
|
-
description: "Target user email",
|
|
4513
|
-
required: false
|
|
4514
|
-
},
|
|
4515
|
-
userId: {
|
|
4516
|
-
type: "string",
|
|
4517
|
-
description: "Target user id",
|
|
4518
|
-
required: false
|
|
4519
|
-
},
|
|
4520
|
-
secret: {
|
|
4521
|
-
type: "string",
|
|
4522
|
-
description: "Admin secret; defaults to DEEPSPACE_ADMIN_SECRET",
|
|
4523
|
-
required: false
|
|
4524
|
-
}
|
|
4525
|
-
},
|
|
4526
|
-
async run({ args }) {
|
|
4527
|
-
const secret = args.secret ?? process.env.DEEPSPACE_ADMIN_SECRET;
|
|
4528
|
-
if (!secret) {
|
|
4529
|
-
console.error("Missing admin secret. Set DEEPSPACE_ADMIN_SECRET or pass --secret.");
|
|
4530
|
-
process.exit(1);
|
|
4531
|
-
}
|
|
4532
|
-
if (!args.email && !args.userId) {
|
|
4533
|
-
console.error("Pass --email or --userId.");
|
|
4534
|
-
process.exit(1);
|
|
4535
|
-
}
|
|
4536
|
-
const res = await fetch(`${AUTH_URL5}/api/auth/admin/impersonate`, {
|
|
4537
|
-
method: "POST",
|
|
4538
|
-
headers: {
|
|
4539
|
-
"Content-Type": "application/json",
|
|
4540
|
-
Authorization: `Bearer ${secret}`
|
|
4541
|
-
},
|
|
4542
|
-
body: JSON.stringify({
|
|
4543
|
-
email: args.email,
|
|
4544
|
-
userId: args.userId
|
|
4545
|
-
})
|
|
4546
|
-
});
|
|
4547
|
-
const data = await res.json().catch(() => ({}));
|
|
4548
|
-
if (!res.ok || !data.token || !data.user) {
|
|
4549
|
-
console.error(`Failed: ${data.error ?? `HTTP ${res.status}`}`);
|
|
4550
|
-
process.exit(1);
|
|
4551
|
-
}
|
|
4552
|
-
const dir = join14(homedir6(), ".deepspace");
|
|
4553
|
-
mkdirSync6(dir, { recursive: true });
|
|
4554
|
-
writeFileSync7(TOKEN_PATH2, data.token, { mode: 384 });
|
|
4555
|
-
console.log(`Impersonating ${data.user.name ?? data.user.email ?? data.user.id}`);
|
|
4556
|
-
console.log(`Email: ${data.user.email ?? "(none)"}`);
|
|
4557
|
-
console.log(`UserID: ${data.user.id}`);
|
|
4558
|
-
}
|
|
4559
|
-
});
|
|
4560
|
-
var admin_default = defineCommand19({
|
|
4561
|
-
meta: {
|
|
4562
|
-
name: "admin",
|
|
4563
|
-
description: "Maintainer-only admin commands"
|
|
4564
|
-
},
|
|
4565
|
-
subCommands: {
|
|
4566
|
-
impersonate
|
|
4567
|
-
}
|
|
4568
|
-
});
|
|
4569
|
-
|
|
4570
3496
|
// src/cli/commands/feedback.ts
|
|
4571
|
-
import { defineCommand as
|
|
3497
|
+
import { defineCommand as defineCommand17 } from "citty";
|
|
4572
3498
|
import * as p7 from "@clack/prompts";
|
|
4573
|
-
import { existsSync as
|
|
4574
|
-
import { dirname as dirname3, join as
|
|
3499
|
+
import { existsSync as existsSync12, readFileSync as readFileSync11 } from "fs";
|
|
3500
|
+
import { dirname as dirname3, join as join13 } from "path";
|
|
4575
3501
|
import { fileURLToPath } from "url";
|
|
4576
3502
|
import { release } from "os";
|
|
4577
|
-
var
|
|
3503
|
+
var API_URL4 = process.env.DEEPSPACE_API_URL ?? ENVS.prod.api;
|
|
4578
3504
|
var TYPES = ["bug", "feature", "other"];
|
|
4579
3505
|
var TYPE_LABELS = {
|
|
4580
3506
|
bug: "Bug report",
|
|
@@ -4584,11 +3510,11 @@ var TYPE_LABELS = {
|
|
|
4584
3510
|
var MAX_TITLE_LEN = 200;
|
|
4585
3511
|
var MAX_BODY_LEN = 1e4;
|
|
4586
3512
|
var MAX_CONTEXT_LEN = 200;
|
|
4587
|
-
async function
|
|
4588
|
-
const res = await fetch(`${
|
|
3513
|
+
async function api2(token, path, init) {
|
|
3514
|
+
const res = await fetch(`${API_URL4}${path}`, {
|
|
4589
3515
|
...init,
|
|
4590
3516
|
headers: {
|
|
4591
|
-
Authorization: `Bearer ${
|
|
3517
|
+
Authorization: `Bearer ${token}`,
|
|
4592
3518
|
"Content-Type": "application/json",
|
|
4593
3519
|
...init?.headers ?? {}
|
|
4594
3520
|
}
|
|
@@ -4613,12 +3539,12 @@ function readCliVersion() {
|
|
|
4613
3539
|
try {
|
|
4614
3540
|
const here = dirname3(fileURLToPath(import.meta.url));
|
|
4615
3541
|
const candidates = [
|
|
4616
|
-
|
|
4617
|
-
|
|
3542
|
+
join13(here, "..", "package.json"),
|
|
3543
|
+
join13(here, "..", "..", "..", "package.json")
|
|
4618
3544
|
];
|
|
4619
3545
|
for (const path of candidates) {
|
|
4620
|
-
if (!
|
|
4621
|
-
const pkg2 = JSON.parse(
|
|
3546
|
+
if (!existsSync12(path)) continue;
|
|
3547
|
+
const pkg2 = JSON.parse(readFileSync11(path, "utf-8"));
|
|
4622
3548
|
if (pkg2.name === "deepspace" && pkg2.version) return pkg2.version;
|
|
4623
3549
|
}
|
|
4624
3550
|
} catch {
|
|
@@ -4669,7 +3595,7 @@ function buildFeedbackPayload(input) {
|
|
|
4669
3595
|
...input.context
|
|
4670
3596
|
};
|
|
4671
3597
|
}
|
|
4672
|
-
var feedback_default =
|
|
3598
|
+
var feedback_default = defineCommand17({
|
|
4673
3599
|
meta: {
|
|
4674
3600
|
name: "feedback",
|
|
4675
3601
|
description: "Submit a bug report, feature request, or feedback to DeepSpace"
|
|
@@ -4802,15 +3728,15 @@ Context: deepspace ${payload.cliVersion} \xB7 ${payload.nodeVersion} \xB7 ${payl
|
|
|
4802
3728
|
process.exit(0);
|
|
4803
3729
|
}
|
|
4804
3730
|
}
|
|
4805
|
-
let
|
|
3731
|
+
let token;
|
|
4806
3732
|
try {
|
|
4807
|
-
|
|
3733
|
+
token = await ensureToken();
|
|
4808
3734
|
} catch (err) {
|
|
4809
3735
|
return fail(err.message ?? "Not signed in. Run `deepspace login`.");
|
|
4810
3736
|
}
|
|
4811
3737
|
let result;
|
|
4812
3738
|
try {
|
|
4813
|
-
result = await
|
|
3739
|
+
result = await api2(token, "/api/feedback", {
|
|
4814
3740
|
method: "POST",
|
|
4815
3741
|
body: JSON.stringify(payload)
|
|
4816
3742
|
});
|
|
@@ -4832,11 +3758,11 @@ Context: deepspace ${payload.cliVersion} \xB7 ${payload.nodeVersion} \xB7 ${payl
|
|
|
4832
3758
|
|
|
4833
3759
|
// src/cli/cli.ts
|
|
4834
3760
|
var __dirname = dirname4(fileURLToPath2(import.meta.url));
|
|
4835
|
-
var pkg = JSON.parse(
|
|
4836
|
-
if (process.platform === "linux" && !process.env.SSL_CERT_FILE &&
|
|
3761
|
+
var pkg = JSON.parse(readFileSync12(join14(__dirname, "..", "package.json"), "utf-8"));
|
|
3762
|
+
if (process.platform === "linux" && !process.env.SSL_CERT_FILE && existsSync13("/etc/ssl/certs/ca-certificates.crt")) {
|
|
4837
3763
|
process.env.SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt";
|
|
4838
3764
|
}
|
|
4839
|
-
var
|
|
3765
|
+
var create2 = defineCommand18({
|
|
4840
3766
|
meta: {
|
|
4841
3767
|
name: "create",
|
|
4842
3768
|
description: "Create a new DeepSpace app"
|
|
@@ -4855,14 +3781,14 @@ var create3 = defineCommand21({
|
|
|
4855
3781
|
execSync5(`npm create deepspace@latest${name}`, { stdio: "inherit" });
|
|
4856
3782
|
}
|
|
4857
3783
|
});
|
|
4858
|
-
var main =
|
|
3784
|
+
var main = defineCommand18({
|
|
4859
3785
|
meta: {
|
|
4860
3786
|
name: "deepspace",
|
|
4861
3787
|
version: pkg.version,
|
|
4862
3788
|
description: "DeepSpace SDK CLI"
|
|
4863
3789
|
},
|
|
4864
3790
|
subCommands: {
|
|
4865
|
-
create:
|
|
3791
|
+
create: create2,
|
|
4866
3792
|
login: login_default,
|
|
4867
3793
|
logout: logout_default,
|
|
4868
3794
|
whoami: whoami_default,
|
|
@@ -4874,15 +3800,12 @@ var main = defineCommand21({
|
|
|
4874
3800
|
add: add_default,
|
|
4875
3801
|
skills: skills_default,
|
|
4876
3802
|
integrations: integrations_default,
|
|
4877
|
-
"managed-repos": managed_repos_default,
|
|
4878
3803
|
invoke: invoke_default,
|
|
4879
3804
|
deploy: deploy_default,
|
|
4880
3805
|
undeploy: undeploy_default,
|
|
4881
3806
|
domain: domain_default,
|
|
4882
3807
|
library: library_default,
|
|
4883
|
-
|
|
4884
|
-
feedback: feedback_default,
|
|
4885
|
-
secrets: secrets_default
|
|
3808
|
+
feedback: feedback_default
|
|
4886
3809
|
}
|
|
4887
3810
|
// No `run()` here — citty cascades parent run() AFTER subcommand finishes,
|
|
4888
3811
|
// which corrupts agent-friendly output (`--json`) and prints noise on every
|