deepspace 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +45 -0
- package/dist/cli.js +483 -141
- package/dist/cli.js.map +1 -1
- package/dist/index.js +53 -5
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +29 -1
- package/dist/server.js +27 -2
- package/dist/server.js.map +1 -1
- package/dist/worker.d.ts +29 -1
- package/dist/worker.js +27 -2
- package/dist/worker.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli/cli.ts
|
|
4
|
-
import { defineCommand as
|
|
4
|
+
import { defineCommand as defineCommand14, runMain, runCommand } from "citty";
|
|
5
5
|
import { sync as spawnSync8 } from "cross-spawn";
|
|
6
|
-
import { readFileSync as readFileSync28, existsSync as
|
|
6
|
+
import { readFileSync as readFileSync28, existsSync as existsSync26 } from "fs";
|
|
7
7
|
import { dirname as dirname10, join as join24 } from "path";
|
|
8
8
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
9
9
|
|
|
@@ -709,7 +709,7 @@ async function provisionProfile(jwt) {
|
|
|
709
709
|
}
|
|
710
710
|
}
|
|
711
711
|
function sleep(ms) {
|
|
712
|
-
return new Promise((
|
|
712
|
+
return new Promise((resolve19) => setTimeout(resolve19, ms));
|
|
713
713
|
}
|
|
714
714
|
function base64url(bytes) {
|
|
715
715
|
return bytes.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
@@ -929,6 +929,7 @@ import { dirname as dirname2, join as join5, resolve as resolve3 } from "path";
|
|
|
929
929
|
// src/cli/lib/git/process.ts
|
|
930
930
|
import { sync as spawnSync } from "cross-spawn";
|
|
931
931
|
var MAX_GIT_BUFFER = 512 * 1024 * 1024;
|
|
932
|
+
var GIT_TIMEOUT_MS = 3e5;
|
|
932
933
|
var GitError = class extends Error {
|
|
933
934
|
constructor(message, code) {
|
|
934
935
|
super(message);
|
|
@@ -937,10 +938,16 @@ var GitError = class extends Error {
|
|
|
937
938
|
}
|
|
938
939
|
};
|
|
939
940
|
function runGit(cwd, args, opts = {}) {
|
|
941
|
+
const timeout = opts.timeoutMs ?? GIT_TIMEOUT_MS;
|
|
940
942
|
const result = spawnSync("git", args, {
|
|
941
943
|
cwd,
|
|
942
944
|
input: opts.input,
|
|
943
945
|
maxBuffer: MAX_GIT_BUFFER,
|
|
946
|
+
timeout,
|
|
947
|
+
// SIGKILL, not the default SIGTERM: a child that ignores or traps TERM
|
|
948
|
+
// would otherwise keep running for its full duration and the "timeout"
|
|
949
|
+
// would bound nothing.
|
|
950
|
+
killSignal: "SIGKILL",
|
|
944
951
|
stdio: ["pipe", "pipe", "pipe"],
|
|
945
952
|
env: {
|
|
946
953
|
...process.env,
|
|
@@ -949,6 +956,12 @@ function runGit(cwd, args, opts = {}) {
|
|
|
949
956
|
...opts.env ?? {}
|
|
950
957
|
}
|
|
951
958
|
});
|
|
959
|
+
if (result.error?.code === "ETIMEDOUT") {
|
|
960
|
+
throw new GitError(
|
|
961
|
+
`git ${args[0]} did not finish within ${Math.round(timeout / 1e3)}s and was stopped. If this was a push, the history is probably too large to transfer \u2014 see \`deepspace push\` for the size limits; otherwise retry, and report it with \`deepspace feedback\` if it persists.`,
|
|
962
|
+
"git_timeout"
|
|
963
|
+
);
|
|
964
|
+
}
|
|
952
965
|
if (result.error) {
|
|
953
966
|
const code = result.error.code;
|
|
954
967
|
if (code === "ENOENT") {
|
|
@@ -2534,10 +2547,10 @@ function formatSchemaLintFindings(findings) {
|
|
|
2534
2547
|
import { createServer } from "net";
|
|
2535
2548
|
var DEFAULT_PORT = 5173;
|
|
2536
2549
|
function checkPortAvailable(port, host = "0.0.0.0") {
|
|
2537
|
-
return new Promise((
|
|
2550
|
+
return new Promise((resolve19) => {
|
|
2538
2551
|
const srv = createServer();
|
|
2539
|
-
srv.once("error", () =>
|
|
2540
|
-
srv.once("listening", () => srv.close(() =>
|
|
2552
|
+
srv.once("error", () => resolve19(false));
|
|
2553
|
+
srv.once("listening", () => srv.close(() => resolve19(true)));
|
|
2541
2554
|
srv.listen(port, host);
|
|
2542
2555
|
});
|
|
2543
2556
|
}
|
|
@@ -3679,8 +3692,8 @@ var clear = defineDeepspaceCommand({
|
|
|
3679
3692
|
failures.push({ email: a.email, error: err.message });
|
|
3680
3693
|
}
|
|
3681
3694
|
}
|
|
3682
|
-
const deleted = targets.filter((
|
|
3683
|
-
removeTestAccounts(deleted.map((
|
|
3695
|
+
const deleted = targets.filter((target2) => !failures.some((failure) => failure.email === target2.email));
|
|
3696
|
+
removeTestAccounts(deleted.map((target2) => target2.id), deleted.map((target2) => target2.email));
|
|
3684
3697
|
if (failures.length > 0) {
|
|
3685
3698
|
throw new Refusal(
|
|
3686
3699
|
`Deleted ${ok2}/${targets.length} test account(s).
|
|
@@ -4657,6 +4670,37 @@ function repoApi(deployUrl, token, appId) {
|
|
|
4657
4670
|
};
|
|
4658
4671
|
}
|
|
4659
4672
|
|
|
4673
|
+
// src/shared/app-files.ts
|
|
4674
|
+
var MAX_APP_FILE_BYTES = 25 * 1024 * 1024;
|
|
4675
|
+
function formatBytes(bytes) {
|
|
4676
|
+
if (bytes >= 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MiB`;
|
|
4677
|
+
if (bytes >= 1024) return `${Math.round(bytes / 1024)} KiB`;
|
|
4678
|
+
return `${bytes} B`;
|
|
4679
|
+
}
|
|
4680
|
+
function encodeKeyPath(key) {
|
|
4681
|
+
return key.split("/").map(encodeURIComponent).join("/");
|
|
4682
|
+
}
|
|
4683
|
+
function oversizeMessage(bytes) {
|
|
4684
|
+
return `That file is ${formatBytes(bytes)}; the limit is ${formatBytes(MAX_APP_FILE_BYTES)} per file.`;
|
|
4685
|
+
}
|
|
4686
|
+
function describeFilesFailure(status3, body) {
|
|
4687
|
+
const trimmed = body.trim();
|
|
4688
|
+
if (trimmed.startsWith("{")) {
|
|
4689
|
+
try {
|
|
4690
|
+
const parsed = JSON.parse(trimmed);
|
|
4691
|
+
if (parsed.error) return parsed.error;
|
|
4692
|
+
} catch {
|
|
4693
|
+
}
|
|
4694
|
+
}
|
|
4695
|
+
if (status3 === 413) {
|
|
4696
|
+
return `The file is too large to upload. The limit is ${formatBytes(MAX_APP_FILE_BYTES)} per file; larger uploads are rejected by the network before the app receives them.`;
|
|
4697
|
+
}
|
|
4698
|
+
if (status3 === 401 || status3 === 403) return "Not authorized to write these files.";
|
|
4699
|
+
if (status3 === 415) return "That file type is not accepted.";
|
|
4700
|
+
if (status3 >= 500) return `The files service failed (HTTP ${status3}). Retry shortly.`;
|
|
4701
|
+
return `Upload failed (HTTP ${status3}).`;
|
|
4702
|
+
}
|
|
4703
|
+
|
|
4660
4704
|
// src/cli/lib/vc-remote.ts
|
|
4661
4705
|
import { existsSync as existsSync17 } from "fs";
|
|
4662
4706
|
import { tmpdir } from "os";
|
|
@@ -4821,7 +4865,7 @@ function isThinPackRejection(result) {
|
|
|
4821
4865
|
function isRecoverablePushFailure(status3) {
|
|
4822
4866
|
return status3 === "non_fast_forward" || status3 === "ref_conflict";
|
|
4823
4867
|
}
|
|
4824
|
-
function classifyPushTransportFailure(error) {
|
|
4868
|
+
function classifyPushTransportFailure(error, cwd) {
|
|
4825
4869
|
const message = error instanceof Error ? error.message : String(error);
|
|
4826
4870
|
if (/(?:HTTP |error: )409\b/i.test(message)) {
|
|
4827
4871
|
return {
|
|
@@ -4841,6 +4885,9 @@ function classifyPushTransportFailure(error) {
|
|
|
4841
4885
|
error: "The cloud repo rate-limited this push. Wait a few seconds, then retry."
|
|
4842
4886
|
};
|
|
4843
4887
|
}
|
|
4888
|
+
if (/(?:HTTP |error: )413\b/i.test(message)) {
|
|
4889
|
+
return { code: "push_too_large", error: pushTooLargeMessage(cwd) };
|
|
4890
|
+
}
|
|
4844
4891
|
return null;
|
|
4845
4892
|
}
|
|
4846
4893
|
function pushToSpace(cwd, token, refspec, opts = {}) {
|
|
@@ -4865,18 +4912,28 @@ function pushToSpace(cwd, token, refspec, opts = {}) {
|
|
|
4865
4912
|
}
|
|
4866
4913
|
var OVERSIZED_PUSH_RE = /too large|exceeds|\bLFS\b/i;
|
|
4867
4914
|
var SERVER_OBJECT_CAP_BYTES = 20 * 1024 * 1024;
|
|
4868
|
-
var
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
return
|
|
4873
|
-
}
|
|
4874
|
-
function
|
|
4875
|
-
|
|
4876
|
-
if (objects.length === 0) return OVERSIZED_PUSH_FIX;
|
|
4915
|
+
var SERVER_PACK_CAP_BYTES = 32 * 1024 * 1024;
|
|
4916
|
+
var OVERSIZED_PUSH_FIX = `Find the offending object with \`git rev-list --objects --all | git cat-file --batch-check='%(objecttype) %(objectsize) %(rest)' | sort -k2 -n | tail\`.`;
|
|
4917
|
+
function removeFromHistoryAdvice(path) {
|
|
4918
|
+
const file = path ? shQuote(path) : "<file>";
|
|
4919
|
+
return `Media belongs in the app's files rather than Git history \u2014 \`deepspace app files put ${file}\` stores it in the app's own allocation and serves it over HTTP. Then get it out of the push: add it to .gitignore, and drop it from the commits that carry it \u2014 if those commits are still local, \`git reset --soft <last pushed commit>\` and re-commit without the file. \`git rm --cached\` plus a new commit is NOT sufficient on its own: the blob stays reachable from the earlier commit and the push is rejected the same way. If it already reached pushed history, rewrite it out (\`git filter-repo --path ${file} --invert-paths\`).`;
|
|
4920
|
+
}
|
|
4921
|
+
function fixForObjects(objects) {
|
|
4922
|
+
if (objects.length === 0) return `${OVERSIZED_PUSH_FIX} ${removeFromHistoryAdvice(null)}`;
|
|
4877
4923
|
const one = objects.length === 1;
|
|
4878
4924
|
const named = objects.map((object) => `${object.path} (${formatBytes(object.bytes)})`).join(", ");
|
|
4879
|
-
return `The oversized ${one ? "file is" : "files are"} ${named}.
|
|
4925
|
+
return `The oversized ${one ? "file is" : "files are"} ${named}. ${removeFromHistoryAdvice(one ? objects[0].path : null)}`;
|
|
4926
|
+
}
|
|
4927
|
+
function oversizedPushFix(cwd, cap = SERVER_OBJECT_CAP_BYTES) {
|
|
4928
|
+
return fixForObjects(cwd ? findOversizedObjects(cwd, cap) : []);
|
|
4929
|
+
}
|
|
4930
|
+
function pushTooLargeMessage(cwd) {
|
|
4931
|
+
const ceilings = `The cloud repo refused this push as too large (HTTP 413). The ceilings are ${formatBytes(SERVER_OBJECT_CAP_BYTES)} per file and ${formatBytes(SERVER_PACK_CAP_BYTES)} of compressed history per push. Large media never compresses, so every clone would pay for it forever.`;
|
|
4932
|
+
const objects = cwd ? findOversizedObjects(cwd, SERVER_OBJECT_CAP_BYTES) : [];
|
|
4933
|
+
if (objects.length === 0) {
|
|
4934
|
+
return `${ceilings} No single file is over the per-file cap, so this is the volume of history \u2014 push it in smaller batches (\`git push space <earlier-commit>:refs/heads/<branch>\` first, then the rest). ${OVERSIZED_PUSH_FIX}`;
|
|
4935
|
+
}
|
|
4936
|
+
return `${ceilings} ${fixForObjects(objects)}`;
|
|
4880
4937
|
}
|
|
4881
4938
|
function pushFailureMessage(label, push, cwd) {
|
|
4882
4939
|
const reason = push.reason ?? push.summary ?? "";
|
|
@@ -4966,7 +5023,7 @@ function remotePublicRefs(cwd, remote) {
|
|
|
4966
5023
|
function remoteBranchOid(cwd, remote, branch) {
|
|
4967
5024
|
return remotePublicRefs(cwd, remote).find((ref) => ref.name === `refs/heads/${branch}`)?.oid ?? null;
|
|
4968
5025
|
}
|
|
4969
|
-
function localTransferRefs(cwd, prefix,
|
|
5026
|
+
function localTransferRefs(cwd, prefix, target2) {
|
|
4970
5027
|
const output = runGit(cwd, [
|
|
4971
5028
|
"for-each-ref",
|
|
4972
5029
|
"--format=%(refname) %(objectname)",
|
|
@@ -4974,7 +5031,7 @@ function localTransferRefs(cwd, prefix, target) {
|
|
|
4974
5031
|
]).stdout.toString("utf-8");
|
|
4975
5032
|
return output.split("\n").map((line) => line.trim()).filter(Boolean).map((line) => {
|
|
4976
5033
|
const [name, oid] = line.split(/\s+/, 2);
|
|
4977
|
-
return { name: `${
|
|
5034
|
+
return { name: `${target2}/${name.slice(`${prefix}/`.length)}`, oid };
|
|
4978
5035
|
}).filter((ref) => /^[0-9a-f]{40}$/.test(ref.oid));
|
|
4979
5036
|
}
|
|
4980
5037
|
|
|
@@ -5087,7 +5144,7 @@ async function syncDeployRepository(options) {
|
|
|
5087
5144
|
}
|
|
5088
5145
|
} else if (pushResult.status === "rejected") {
|
|
5089
5146
|
output.die(
|
|
5090
|
-
|
|
5147
|
+
`${pushFailureMessage("Cloud repo push", pushResult, appDir)} Publish the commit before deploying.`,
|
|
5091
5148
|
"vc_push_rejected"
|
|
5092
5149
|
);
|
|
5093
5150
|
} else {
|
|
@@ -5131,7 +5188,7 @@ async function syncDeployRepository(options) {
|
|
|
5131
5188
|
sourceRevision = claimed.revision;
|
|
5132
5189
|
}
|
|
5133
5190
|
} catch (error) {
|
|
5134
|
-
const failure = deployRepositoryFailure(error);
|
|
5191
|
+
const failure = deployRepositoryFailure(error, appDir);
|
|
5135
5192
|
output.die(failure.error, failure.code);
|
|
5136
5193
|
}
|
|
5137
5194
|
return { commitOid, recoverable, deployKey, source, sourceRevision, baseReleaseId };
|
|
@@ -5158,8 +5215,8 @@ function classifyRemoteState(appDir, token, branch, localTip, remote) {
|
|
|
5158
5215
|
function errorMessage3(error) {
|
|
5159
5216
|
return error instanceof Error ? error.message : String(error);
|
|
5160
5217
|
}
|
|
5161
|
-
function deployRepositoryFailure(error) {
|
|
5162
|
-
const transportFailure = classifyPushTransportFailure(error);
|
|
5218
|
+
function deployRepositoryFailure(error, cwd) {
|
|
5219
|
+
const transportFailure = classifyPushTransportFailure(error, cwd);
|
|
5163
5220
|
if (transportFailure) return transportFailure;
|
|
5164
5221
|
const code = errorCode(error);
|
|
5165
5222
|
const message = errorMessage3(error);
|
|
@@ -5169,15 +5226,18 @@ function deployRepositoryFailure(error) {
|
|
|
5169
5226
|
error: `Version-control sync failed: ${message}`
|
|
5170
5227
|
};
|
|
5171
5228
|
}
|
|
5229
|
+
var PUSH_RETRY_BUDGET_MS = 12e4;
|
|
5172
5230
|
async function pushWithTransientRetry(push) {
|
|
5173
5231
|
const backoffMs = [500, 1500, 3500];
|
|
5232
|
+
const deadline = Date.now() + PUSH_RETRY_BUDGET_MS;
|
|
5174
5233
|
for (let attempt = 0; ; attempt++) {
|
|
5175
5234
|
try {
|
|
5176
5235
|
return push();
|
|
5177
5236
|
} catch (error) {
|
|
5178
5237
|
const message = errorMessage3(error);
|
|
5179
|
-
|
|
5180
|
-
|
|
5238
|
+
const transient = /(?:HTTP |error: )(?:429|503)\b/i.test(message);
|
|
5239
|
+
if (transient && attempt < backoffMs.length && Date.now() + backoffMs[attempt] < deadline) {
|
|
5240
|
+
await new Promise((resolve19) => setTimeout(resolve19, backoffMs[attempt]));
|
|
5181
5241
|
continue;
|
|
5182
5242
|
}
|
|
5183
5243
|
throw error;
|
|
@@ -5521,7 +5581,7 @@ async function postWithRetry(url, makeInit, {
|
|
|
5521
5581
|
lastError = error;
|
|
5522
5582
|
}
|
|
5523
5583
|
if (attempt < attempts) {
|
|
5524
|
-
await new Promise((
|
|
5584
|
+
await new Promise((resolve19) => setTimeout(resolve19, Math.min(8e3, 500 * 2 ** (attempt - 1))));
|
|
5525
5585
|
}
|
|
5526
5586
|
}
|
|
5527
5587
|
if (lastResponse) return lastResponse;
|
|
@@ -5903,7 +5963,7 @@ async function waitForAssetsReady(url, timeoutMs) {
|
|
|
5903
5963
|
if (!body.includes("Assets have not yet deployed") && !body.includes("No app configured")) {
|
|
5904
5964
|
streak++;
|
|
5905
5965
|
if (streak >= 3) return true;
|
|
5906
|
-
await new Promise((
|
|
5966
|
+
await new Promise((resolve19) => setTimeout(resolve19, 1500));
|
|
5907
5967
|
continue;
|
|
5908
5968
|
}
|
|
5909
5969
|
streak = 0;
|
|
@@ -5911,7 +5971,7 @@ async function waitForAssetsReady(url, timeoutMs) {
|
|
|
5911
5971
|
streak = 0;
|
|
5912
5972
|
}
|
|
5913
5973
|
const waitMs = Math.min(8e3, 1e3 * 2 ** (attempt - 1));
|
|
5914
|
-
await new Promise((
|
|
5974
|
+
await new Promise((resolve19) => setTimeout(resolve19, waitMs));
|
|
5915
5975
|
}
|
|
5916
5976
|
return false;
|
|
5917
5977
|
}
|
|
@@ -7621,11 +7681,11 @@ function fmtDate(iso) {
|
|
|
7621
7681
|
}
|
|
7622
7682
|
async function confirm4(message) {
|
|
7623
7683
|
process.stdout.write(`${message} [y/N] `);
|
|
7624
|
-
return new Promise((
|
|
7684
|
+
return new Promise((resolve19) => {
|
|
7625
7685
|
process.stdin.setEncoding("utf-8");
|
|
7626
7686
|
process.stdin.once("data", (data) => {
|
|
7627
7687
|
const answer = data.toString().trim().toLowerCase();
|
|
7628
|
-
|
|
7688
|
+
resolve19(answer === "y" || answer === "yes");
|
|
7629
7689
|
});
|
|
7630
7690
|
});
|
|
7631
7691
|
}
|
|
@@ -7913,8 +7973,289 @@ var domain_default = defineCommand5({
|
|
|
7913
7973
|
subCommands: { search, buy, list: list2, status, attach, detach, renew }
|
|
7914
7974
|
});
|
|
7915
7975
|
|
|
7916
|
-
// src/cli/commands/
|
|
7976
|
+
// src/cli/commands/app-files.ts
|
|
7917
7977
|
import { defineCommand as defineCommand6 } from "citty";
|
|
7978
|
+
import { basename as basename4, resolve as resolve15 } from "path";
|
|
7979
|
+
import { existsSync as existsSync21, statSync as statSync2 } from "fs";
|
|
7980
|
+
|
|
7981
|
+
// src/cli/lib/app-files-api.ts
|
|
7982
|
+
import { createWriteStream, openAsBlob, statSync } from "fs";
|
|
7983
|
+
import { basename as basename3, extname } from "path";
|
|
7984
|
+
import { Readable } from "stream";
|
|
7985
|
+
import { pipeline } from "stream/promises";
|
|
7986
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
7987
|
+
var CONTENT_TYPES = {
|
|
7988
|
+
".avif": "image/avif",
|
|
7989
|
+
".css": "text/css",
|
|
7990
|
+
".csv": "text/csv",
|
|
7991
|
+
".gif": "image/gif",
|
|
7992
|
+
".ico": "image/x-icon",
|
|
7993
|
+
".jpeg": "image/jpeg",
|
|
7994
|
+
".jpg": "image/jpeg",
|
|
7995
|
+
".json": "application/json",
|
|
7996
|
+
".md": "text/markdown",
|
|
7997
|
+
".mp3": "audio/mpeg",
|
|
7998
|
+
".mp4": "video/mp4",
|
|
7999
|
+
".otf": "font/otf",
|
|
8000
|
+
".pdf": "application/pdf",
|
|
8001
|
+
".png": "image/png",
|
|
8002
|
+
".txt": "text/plain",
|
|
8003
|
+
".wasm": "application/wasm",
|
|
8004
|
+
".wav": "audio/wav",
|
|
8005
|
+
".webm": "video/webm",
|
|
8006
|
+
".webp": "image/webp",
|
|
8007
|
+
".woff": "font/woff",
|
|
8008
|
+
".woff2": "font/woff2",
|
|
8009
|
+
".zip": "application/zip"
|
|
8010
|
+
};
|
|
8011
|
+
function contentTypeFor(path) {
|
|
8012
|
+
return CONTENT_TYPES[extname(path).toLowerCase()] ?? "application/octet-stream";
|
|
8013
|
+
}
|
|
8014
|
+
function filesPath(appId, rest = "") {
|
|
8015
|
+
return `/api/app-files/${appId}${rest}`;
|
|
8016
|
+
}
|
|
8017
|
+
async function request(baseUrl, token, path, init = {}) {
|
|
8018
|
+
let res;
|
|
8019
|
+
try {
|
|
8020
|
+
res = await fetch(`${baseUrl}${path}`, {
|
|
8021
|
+
...init,
|
|
8022
|
+
headers: { Authorization: `Bearer ${token}`, ...init.headers ?? {} }
|
|
8023
|
+
});
|
|
8024
|
+
} catch (err) {
|
|
8025
|
+
throw new ApiError(
|
|
8026
|
+
`Could not reach the DeepSpace platform at ${baseUrl}: ${err instanceof Error ? err.message : String(err)}. Check your connection (and DEEPSPACE_PLATFORM_URL), then retry.`,
|
|
8027
|
+
0,
|
|
8028
|
+
"network_error",
|
|
8029
|
+
path
|
|
8030
|
+
);
|
|
8031
|
+
}
|
|
8032
|
+
if (res.ok) return res;
|
|
8033
|
+
const text2 = await res.text();
|
|
8034
|
+
let code;
|
|
8035
|
+
try {
|
|
8036
|
+
code = JSON.parse(text2.trim()).code;
|
|
8037
|
+
} catch {
|
|
8038
|
+
}
|
|
8039
|
+
throw new ApiError(
|
|
8040
|
+
describeFilesFailure(res.status, text2),
|
|
8041
|
+
res.status,
|
|
8042
|
+
code ?? (res.status === 413 ? "file_too_large" : res.status >= 500 ? "server_error" : "http_error"),
|
|
8043
|
+
path
|
|
8044
|
+
);
|
|
8045
|
+
}
|
|
8046
|
+
async function readJson(res, path) {
|
|
8047
|
+
const text2 = await res.text();
|
|
8048
|
+
try {
|
|
8049
|
+
return JSON.parse(text2);
|
|
8050
|
+
} catch {
|
|
8051
|
+
throw new ApiError(
|
|
8052
|
+
`The DeepSpace platform returned a malformed (non-JSON) response.`,
|
|
8053
|
+
res.status,
|
|
8054
|
+
"invalid_response",
|
|
8055
|
+
path
|
|
8056
|
+
);
|
|
8057
|
+
}
|
|
8058
|
+
}
|
|
8059
|
+
async function multipartBody(localPath, fileName, contentType) {
|
|
8060
|
+
const boundary = `----deepspace${randomUUID2().replace(/-/g, "")}`;
|
|
8061
|
+
const safeName = fileName.replace(/["\\\r\n]/g, "_");
|
|
8062
|
+
const head = `--${boundary}\r
|
|
8063
|
+
Content-Disposition: form-data; name="file"; filename="${safeName}"\r
|
|
8064
|
+
Content-Type: ${contentType}\r
|
|
8065
|
+
\r
|
|
8066
|
+
`;
|
|
8067
|
+
const file = await openAsBlob(localPath, { type: contentType });
|
|
8068
|
+
return {
|
|
8069
|
+
blob: new Blob([head, file, `\r
|
|
8070
|
+
--${boundary}--\r
|
|
8071
|
+
`]),
|
|
8072
|
+
contentType: `multipart/form-data; boundary=${boundary}`
|
|
8073
|
+
};
|
|
8074
|
+
}
|
|
8075
|
+
async function uploadAppFile(baseUrl, token, appId, localPath, key) {
|
|
8076
|
+
const path = filesPath(appId, `/upload?key=${encodeKeyPath(key)}`);
|
|
8077
|
+
const size = statSync(localPath).size;
|
|
8078
|
+
if (size > MAX_APP_FILE_BYTES) {
|
|
8079
|
+
throw new ApiError(oversizeMessage(size), 0, "file_too_large", path);
|
|
8080
|
+
}
|
|
8081
|
+
const { blob, contentType } = await multipartBody(
|
|
8082
|
+
localPath,
|
|
8083
|
+
basename3(localPath),
|
|
8084
|
+
contentTypeFor(localPath)
|
|
8085
|
+
);
|
|
8086
|
+
const res = await request(baseUrl, token, path, {
|
|
8087
|
+
method: "POST",
|
|
8088
|
+
headers: { "Content-Type": contentType },
|
|
8089
|
+
body: blob
|
|
8090
|
+
});
|
|
8091
|
+
const body = await readJson(res, path);
|
|
8092
|
+
return { key: body.key, name: body.name, size };
|
|
8093
|
+
}
|
|
8094
|
+
async function listAppFiles(baseUrl, token, appId, query) {
|
|
8095
|
+
const path = filesPath(appId, `?${query}`);
|
|
8096
|
+
return readJson(await request(baseUrl, token, path), path);
|
|
8097
|
+
}
|
|
8098
|
+
async function deleteAppFile(baseUrl, token, appId, key) {
|
|
8099
|
+
await request(baseUrl, token, filesPath(appId, `/${encodeKeyPath(key)}`), { method: "DELETE" });
|
|
8100
|
+
}
|
|
8101
|
+
async function downloadAppFile(baseUrl, token, appId, key, destination) {
|
|
8102
|
+
const path = filesPath(appId, `/${encodeKeyPath(key)}`);
|
|
8103
|
+
const res = await request(baseUrl, token, path);
|
|
8104
|
+
if (!res.body) {
|
|
8105
|
+
throw new ApiError("The server returned an empty response", 502, "invalid_response", path);
|
|
8106
|
+
}
|
|
8107
|
+
let bytes = 0;
|
|
8108
|
+
await pipeline(
|
|
8109
|
+
Readable.fromWeb(res.body),
|
|
8110
|
+
async function* (chunks) {
|
|
8111
|
+
for await (const chunk of chunks) {
|
|
8112
|
+
bytes += chunk.length;
|
|
8113
|
+
yield chunk;
|
|
8114
|
+
}
|
|
8115
|
+
},
|
|
8116
|
+
createWriteStream(destination)
|
|
8117
|
+
);
|
|
8118
|
+
return { bytes, contentType: res.headers.get("content-type") ?? "application/octet-stream" };
|
|
8119
|
+
}
|
|
8120
|
+
|
|
8121
|
+
// src/cli/commands/app-files.ts
|
|
8122
|
+
var DEPLOY_URL8 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
|
|
8123
|
+
var PLATFORM_URL = process.env.DEEPSPACE_PLATFORM_URL ?? PLATFORM_URLS.platform;
|
|
8124
|
+
async function target(app2) {
|
|
8125
|
+
const token = await ensureToken();
|
|
8126
|
+
const appId = await resolveAppTarget(DEPLOY_URL8, token, app2);
|
|
8127
|
+
return { token, appId };
|
|
8128
|
+
}
|
|
8129
|
+
var MAX_LIST_LIMIT = 1e3;
|
|
8130
|
+
function parseLimit(raw) {
|
|
8131
|
+
const limit = Number(raw ?? 100);
|
|
8132
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > MAX_LIST_LIMIT) {
|
|
8133
|
+
throw new Refusal(`--limit must be a whole number from 1 to ${MAX_LIST_LIMIT}.`, "invalid_limit");
|
|
8134
|
+
}
|
|
8135
|
+
return limit;
|
|
8136
|
+
}
|
|
8137
|
+
function requireKey(raw) {
|
|
8138
|
+
const key = raw.trim().replace(/^\/+/, "");
|
|
8139
|
+
if (!key) throw new Refusal("A key is required (for example `logo.png`).", "invalid_key");
|
|
8140
|
+
if (key.split("/").some((segment) => segment === ".." || segment === ".")) {
|
|
8141
|
+
throw new Refusal(
|
|
8142
|
+
`"${raw}" contains a path traversal segment. Keys are relative to the app, e.g. \`img/hero.jpg\`.`,
|
|
8143
|
+
"invalid_key"
|
|
8144
|
+
);
|
|
8145
|
+
}
|
|
8146
|
+
return key;
|
|
8147
|
+
}
|
|
8148
|
+
function appPrefixOf(key) {
|
|
8149
|
+
const segments = key.split("/");
|
|
8150
|
+
return segments.length > 2 ? `${segments[0]}/${segments[1]}/` : "";
|
|
8151
|
+
}
|
|
8152
|
+
function relativeKey(key, prefix) {
|
|
8153
|
+
return prefix && key.startsWith(prefix) ? key.slice(prefix.length) : key;
|
|
8154
|
+
}
|
|
8155
|
+
function servedPath(key) {
|
|
8156
|
+
return `/api/files/${encodeKeyPath(key)}?scope=app`;
|
|
8157
|
+
}
|
|
8158
|
+
var put = defineDeepspaceCommand({
|
|
8159
|
+
meta: { name: "put", description: "Upload a file to the app\u2019s files" },
|
|
8160
|
+
args: {
|
|
8161
|
+
file: { type: "positional", description: "Local file to upload", required: true },
|
|
8162
|
+
key: { type: "string", description: "Key to store it under (default: the file name)" },
|
|
8163
|
+
app: { type: "string", description: "App id or live name (defaults to ./wrangler.toml)" }
|
|
8164
|
+
},
|
|
8165
|
+
async run({ args }) {
|
|
8166
|
+
const localPath = resolve15(String(args.file));
|
|
8167
|
+
if (!existsSync21(localPath) || !statSync2(localPath).isFile()) {
|
|
8168
|
+
throw new Refusal(`No such file: ${args.file}`, "file_not_found");
|
|
8169
|
+
}
|
|
8170
|
+
const key = requireKey(args.key ?? basename4(localPath));
|
|
8171
|
+
const { token, appId } = await target(args.app);
|
|
8172
|
+
const result = await uploadAppFile(PLATFORM_URL, token, appId, localPath, key);
|
|
8173
|
+
if (!args.json) {
|
|
8174
|
+
console.log(`\u2713 ${key} (${formatBytes(result.size)})`);
|
|
8175
|
+
console.log(` Served from your app at ${servedPath(result.key)}`);
|
|
8176
|
+
}
|
|
8177
|
+
return { data: { appId, key, storedKey: result.key, size: result.size, path: servedPath(result.key) } };
|
|
8178
|
+
}
|
|
8179
|
+
});
|
|
8180
|
+
var list3 = defineDeepspaceCommand({
|
|
8181
|
+
meta: { name: "list", description: "List the app\u2019s files" },
|
|
8182
|
+
args: {
|
|
8183
|
+
prefix: { type: "string", description: "Only keys starting with this prefix" },
|
|
8184
|
+
limit: {
|
|
8185
|
+
type: "string",
|
|
8186
|
+
description: `Max entries, 1-${MAX_LIST_LIMIT} (default 100)`,
|
|
8187
|
+
default: "100"
|
|
8188
|
+
},
|
|
8189
|
+
app: { type: "string", description: "App id or live name (defaults to ./wrangler.toml)" }
|
|
8190
|
+
},
|
|
8191
|
+
async run({ args }) {
|
|
8192
|
+
const limit = parseLimit(args.limit);
|
|
8193
|
+
const { token, appId } = await target(args.app);
|
|
8194
|
+
const query = new URLSearchParams({ limit: String(limit) });
|
|
8195
|
+
if (args.prefix) query.set("prefix", String(args.prefix));
|
|
8196
|
+
const result = await listAppFiles(PLATFORM_URL, token, appId, query);
|
|
8197
|
+
const prefix = result.files.length ? appPrefixOf(result.files[0].key) : "";
|
|
8198
|
+
const files = result.files.map((file) => ({
|
|
8199
|
+
key: relativeKey(file.key, prefix),
|
|
8200
|
+
size: file.size,
|
|
8201
|
+
uploaded: file.uploaded,
|
|
8202
|
+
path: servedPath(file.key)
|
|
8203
|
+
}));
|
|
8204
|
+
if (!args.json) {
|
|
8205
|
+
if (files.length === 0) {
|
|
8206
|
+
console.log("No files. Upload one with `deepspace app files put <file>`.");
|
|
8207
|
+
} else {
|
|
8208
|
+
const keyWidth = Math.max(3, ...files.map((file) => file.key.length));
|
|
8209
|
+
console.log(`${"KEY".padEnd(keyWidth)} ${"SIZE".padStart(9)} UPLOADED`);
|
|
8210
|
+
for (const file of files) {
|
|
8211
|
+
console.log(
|
|
8212
|
+
`${file.key.padEnd(keyWidth)} ${formatBytes(file.size).padStart(9)} ${file.uploaded.slice(0, 10)}`
|
|
8213
|
+
);
|
|
8214
|
+
}
|
|
8215
|
+
const more = limit < MAX_LIST_LIMIT ? "raise --limit or narrow with --prefix" : "narrow with --prefix";
|
|
8216
|
+
if (result.truncated) console.log(`(truncated at ${limit} \u2014 ${more})`);
|
|
8217
|
+
}
|
|
8218
|
+
}
|
|
8219
|
+
return { data: { appId, files, truncated: result.truncated } };
|
|
8220
|
+
}
|
|
8221
|
+
});
|
|
8222
|
+
var get = defineDeepspaceCommand({
|
|
8223
|
+
meta: { name: "get", description: "Download one file" },
|
|
8224
|
+
args: {
|
|
8225
|
+
key: { type: "positional", description: "Key to download", required: true },
|
|
8226
|
+
out: { type: "string", description: "Write here (default: the key\u2019s file name)" },
|
|
8227
|
+
app: { type: "string", description: "App id or live name (defaults to ./wrangler.toml)" }
|
|
8228
|
+
},
|
|
8229
|
+
async run({ args }) {
|
|
8230
|
+
const key = requireKey(String(args.key));
|
|
8231
|
+
const destination = resolve15(String(args.out ?? basename4(key)));
|
|
8232
|
+
const { token, appId } = await target(args.app);
|
|
8233
|
+
const result = await downloadAppFile(PLATFORM_URL, token, appId, key, destination);
|
|
8234
|
+
if (!args.json) console.log(`\u2713 ${key} \u2192 ${destination} (${formatBytes(result.bytes)})`);
|
|
8235
|
+
return { data: { appId, key, out: destination, size: result.bytes, contentType: result.contentType } };
|
|
8236
|
+
}
|
|
8237
|
+
});
|
|
8238
|
+
var rm = defineDeepspaceCommand({
|
|
8239
|
+
meta: { name: "rm", description: "Delete one file" },
|
|
8240
|
+
args: {
|
|
8241
|
+
key: { type: "positional", description: "Key to delete", required: true },
|
|
8242
|
+
app: { type: "string", description: "App id or live name (defaults to ./wrangler.toml)" }
|
|
8243
|
+
},
|
|
8244
|
+
async run({ args }) {
|
|
8245
|
+
const key = requireKey(String(args.key));
|
|
8246
|
+
const { token, appId } = await target(args.app);
|
|
8247
|
+
await deleteAppFile(PLATFORM_URL, token, appId, key);
|
|
8248
|
+
if (!args.json) console.log(`\u2713 deleted ${key}`);
|
|
8249
|
+
return { data: { appId, key, deleted: true } };
|
|
8250
|
+
}
|
|
8251
|
+
});
|
|
8252
|
+
var app_files_default = defineCommand6({
|
|
8253
|
+
meta: { name: "files", description: "Upload and manage the app\u2019s files (images, media)" },
|
|
8254
|
+
subCommands: { put, list: list3, get, rm }
|
|
8255
|
+
});
|
|
8256
|
+
|
|
8257
|
+
// src/cli/commands/collaborators.ts
|
|
8258
|
+
import { defineCommand as defineCommand7 } from "citty";
|
|
7918
8259
|
|
|
7919
8260
|
// src/server/auth/testAccounts.ts
|
|
7920
8261
|
var TEST_ACCOUNT_EMAIL_SUFFIX = "@deepspace.test";
|
|
@@ -7924,18 +8265,18 @@ function isTestAccountEmail(email) {
|
|
|
7924
8265
|
|
|
7925
8266
|
// src/cli/commands/collaborators.ts
|
|
7926
8267
|
var API_URL5 = process.env.DEEPSPACE_API_URL ?? PLATFORM_URLS.api;
|
|
7927
|
-
var
|
|
8268
|
+
var DEPLOY_URL9 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
|
|
7928
8269
|
function api2(token, path, init) {
|
|
7929
8270
|
return apiFetch(API_URL5, token, path, init);
|
|
7930
8271
|
}
|
|
7931
|
-
var
|
|
8272
|
+
var list4 = defineDeepspaceCommand({
|
|
7932
8273
|
meta: { name: "list", description: "List collaborators on your app" },
|
|
7933
8274
|
args: {
|
|
7934
8275
|
app: { type: "string", alias: "a", description: "App id or name (defaults to ./wrangler.toml)" }
|
|
7935
8276
|
},
|
|
7936
8277
|
async run({ args }) {
|
|
7937
8278
|
const token = await ensureToken();
|
|
7938
|
-
const app2 = await resolveAppTarget(
|
|
8279
|
+
const app2 = await resolveAppTarget(DEPLOY_URL9, token, args.app);
|
|
7939
8280
|
const { collaborators, pending = [] } = await api2(token, `/api/app-collaborators/${encodeURIComponent(app2)}`);
|
|
7940
8281
|
if (!collaborators.length && !pending.length) {
|
|
7941
8282
|
if (!args.json) {
|
|
@@ -7973,7 +8314,7 @@ var add = defineDeepspaceCommand({
|
|
|
7973
8314
|
async run({ args }) {
|
|
7974
8315
|
const email = String(args.email);
|
|
7975
8316
|
const token = await ensureToken();
|
|
7976
|
-
const app2 = await resolveAppTarget(
|
|
8317
|
+
const app2 = await resolveAppTarget(DEPLOY_URL9, token, args.app);
|
|
7977
8318
|
if (isTestAccountEmail(email)) {
|
|
7978
8319
|
throw new Refusal(
|
|
7979
8320
|
"Test accounts (@deepspace.test) cannot be added as collaborators. Use a real DeepSpace account.",
|
|
@@ -8015,13 +8356,13 @@ var remove = defineDeepspaceCommand({
|
|
|
8015
8356
|
async run({ args }) {
|
|
8016
8357
|
const email = String(args.email);
|
|
8017
8358
|
const token = await ensureToken();
|
|
8018
|
-
const app2 = await resolveAppTarget(
|
|
8359
|
+
const app2 = await resolveAppTarget(DEPLOY_URL9, token, args.app);
|
|
8019
8360
|
const { collaborators } = await api2(
|
|
8020
8361
|
token,
|
|
8021
8362
|
`/api/app-collaborators/${encodeURIComponent(app2)}`
|
|
8022
8363
|
);
|
|
8023
|
-
const
|
|
8024
|
-
const found = collaborators.find((c) => c.emailDisplay.toLowerCase() ===
|
|
8364
|
+
const target2 = email.trim().toLowerCase();
|
|
8365
|
+
const found = collaborators.find((c) => c.emailDisplay.toLowerCase() === target2);
|
|
8025
8366
|
if (!found) {
|
|
8026
8367
|
throw new Refusal(`${email} is not a collaborator on ${app2}`, "not_a_collaborator", {
|
|
8027
8368
|
action: cliAction("deepspace", "app", "collaborators", "list", "--app", app2)
|
|
@@ -8045,13 +8386,13 @@ var cancel3 = defineDeepspaceCommand({
|
|
|
8045
8386
|
async run({ args }) {
|
|
8046
8387
|
const email = String(args.email);
|
|
8047
8388
|
const token = await ensureToken();
|
|
8048
|
-
const app2 = await resolveAppTarget(
|
|
8389
|
+
const app2 = await resolveAppTarget(DEPLOY_URL9, token, args.app);
|
|
8049
8390
|
const { pending = [] } = await api2(
|
|
8050
8391
|
token,
|
|
8051
8392
|
`/api/app-collaborators/${encodeURIComponent(app2)}`
|
|
8052
8393
|
);
|
|
8053
|
-
const
|
|
8054
|
-
const found = pending.find((p34) => p34.email.toLowerCase() ===
|
|
8394
|
+
const target2 = email.trim().toLowerCase();
|
|
8395
|
+
const found = pending.find((p34) => p34.email.toLowerCase() === target2);
|
|
8055
8396
|
if (!found) {
|
|
8056
8397
|
throw new Refusal(`${email} has no pending invite on ${app2}`, "no_pending_invite", {
|
|
8057
8398
|
action: cliAction("deepspace", "app", "collaborators", "list", "--app", app2)
|
|
@@ -8066,16 +8407,16 @@ var cancel3 = defineDeepspaceCommand({
|
|
|
8066
8407
|
return { data: { cancelled: found } };
|
|
8067
8408
|
}
|
|
8068
8409
|
});
|
|
8069
|
-
var collaborators_default =
|
|
8410
|
+
var collaborators_default = defineCommand7({
|
|
8070
8411
|
meta: { name: "collaborators", description: "Manage who can deploy your app" },
|
|
8071
|
-
subCommands: { list:
|
|
8412
|
+
subCommands: { list: list4, add, remove, cancel: cancel3 }
|
|
8072
8413
|
});
|
|
8073
8414
|
|
|
8074
8415
|
// src/cli/commands/transfer.ts
|
|
8075
|
-
import { defineCommand as
|
|
8416
|
+
import { defineCommand as defineCommand8 } from "citty";
|
|
8076
8417
|
import * as p14 from "@clack/prompts";
|
|
8077
8418
|
var API_URL6 = process.env.DEEPSPACE_API_URL ?? PLATFORM_URLS.api;
|
|
8078
|
-
var
|
|
8419
|
+
var DEPLOY_URL10 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
|
|
8079
8420
|
var offer = defineDeepspaceCommand({
|
|
8080
8421
|
meta: { name: "offer", description: "Offer this app to another DeepSpace user" },
|
|
8081
8422
|
args: {
|
|
@@ -8089,7 +8430,7 @@ var offer = defineDeepspaceCommand({
|
|
|
8089
8430
|
async run({ args }) {
|
|
8090
8431
|
const email = String(args.email);
|
|
8091
8432
|
const token = await ensureToken();
|
|
8092
|
-
const app2 = await resolveAppTarget(
|
|
8433
|
+
const app2 = await resolveAppTarget(DEPLOY_URL10, token, args.app);
|
|
8093
8434
|
const pending = await apiFetch(
|
|
8094
8435
|
API_URL6,
|
|
8095
8436
|
token,
|
|
@@ -8141,7 +8482,7 @@ var status2 = defineDeepspaceCommand({
|
|
|
8141
8482
|
},
|
|
8142
8483
|
async run({ args }) {
|
|
8143
8484
|
const token = await ensureToken();
|
|
8144
|
-
const app2 = await resolveAppTarget(
|
|
8485
|
+
const app2 = await resolveAppTarget(DEPLOY_URL10, token, args.app);
|
|
8145
8486
|
const { transfer } = await apiFetch(API_URL6, token, `/api/app-transfers/${encodeURIComponent(app2)}`);
|
|
8146
8487
|
if (!transfer) {
|
|
8147
8488
|
if (!args.json) console.log(`No pending transfer for ${app2}.`);
|
|
@@ -8168,7 +8509,7 @@ var accept = defineDeepspaceCommand({
|
|
|
8168
8509
|
const msg = err instanceof Error ? err.message : String(err);
|
|
8169
8510
|
throw new Refusal(msg, msg.startsWith("No app id") ? "not_in_app_repo" : "invalid_app");
|
|
8170
8511
|
}
|
|
8171
|
-
await apiFetch(
|
|
8512
|
+
await apiFetch(DEPLOY_URL10, token, `/api/apps/${encodeURIComponent(app2)}/transfer/accept`, {
|
|
8172
8513
|
method: "POST"
|
|
8173
8514
|
});
|
|
8174
8515
|
if (!args.json) {
|
|
@@ -8186,37 +8527,37 @@ var cancel4 = defineDeepspaceCommand({
|
|
|
8186
8527
|
},
|
|
8187
8528
|
async run({ args }) {
|
|
8188
8529
|
const token = await ensureToken();
|
|
8189
|
-
const app2 = await resolveAppTarget(
|
|
8530
|
+
const app2 = await resolveAppTarget(DEPLOY_URL10, token, args.app);
|
|
8190
8531
|
await apiFetch(API_URL6, token, `/api/app-transfers/${encodeURIComponent(app2)}`, { method: "DELETE" });
|
|
8191
8532
|
if (!args.json) console.log(`\u2713 Transfer offer for ${app2} cancelled.`);
|
|
8192
8533
|
return { data: { app: app2, cancelled: true } };
|
|
8193
8534
|
}
|
|
8194
8535
|
});
|
|
8195
|
-
var transfer_default =
|
|
8536
|
+
var transfer_default = defineCommand8({
|
|
8196
8537
|
meta: { name: "transfer", description: "Transfer app ownership to another user" },
|
|
8197
8538
|
subCommands: { offer, status: status2, accept, cancel: cancel4 }
|
|
8198
8539
|
});
|
|
8199
8540
|
|
|
8200
8541
|
// src/cli/commands/integrations.ts
|
|
8201
|
-
import { defineCommand as
|
|
8542
|
+
import { defineCommand as defineCommand9 } from "citty";
|
|
8202
8543
|
|
|
8203
8544
|
// src/cli/commands/_invoke-impl.ts
|
|
8204
8545
|
import { readFileSync as readFileSync22 } from "fs";
|
|
8205
8546
|
import * as p15 from "@clack/prompts";
|
|
8206
8547
|
var API_URL7 = process.env.DEEPSPACE_API_URL ?? PLATFORM_URLS.api;
|
|
8207
8548
|
var DEFAULT_TIMEOUT_MS = 12e4;
|
|
8208
|
-
function parseTarget(
|
|
8209
|
-
if (!
|
|
8549
|
+
function parseTarget(target2) {
|
|
8550
|
+
if (!target2 || typeof target2 !== "string") {
|
|
8210
8551
|
throw new Refusal(
|
|
8211
8552
|
"Missing target. Expected '<integration>/<endpoint>' (e.g. 'openai/chat-completion').",
|
|
8212
8553
|
"missing_target",
|
|
8213
8554
|
{ action: cliAction("deepspace", "integrations", "list") }
|
|
8214
8555
|
);
|
|
8215
8556
|
}
|
|
8216
|
-
const parts =
|
|
8557
|
+
const parts = target2.split("/");
|
|
8217
8558
|
if (parts.length !== 2 || !parts[0] || !parts[1]) {
|
|
8218
8559
|
throw new Refusal(
|
|
8219
|
-
`Bad target '${
|
|
8560
|
+
`Bad target '${target2}'. Expected '<integration>/<endpoint>' (e.g. 'openai/chat-completion').`,
|
|
8220
8561
|
"bad_target",
|
|
8221
8562
|
{ action: cliAction("deepspace", "integrations", "list") }
|
|
8222
8563
|
);
|
|
@@ -8436,7 +8777,7 @@ async function runInvoke(args) {
|
|
|
8436
8777
|
}
|
|
8437
8778
|
|
|
8438
8779
|
// src/cli/commands/integrations.ts
|
|
8439
|
-
var
|
|
8780
|
+
var list5 = defineDeepspaceCommand({
|
|
8440
8781
|
meta: {
|
|
8441
8782
|
name: "list",
|
|
8442
8783
|
description: "List all available integrations"
|
|
@@ -8507,13 +8848,13 @@ var invoke = defineDeepspaceCommand({
|
|
|
8507
8848
|
});
|
|
8508
8849
|
}
|
|
8509
8850
|
});
|
|
8510
|
-
var integrations_default =
|
|
8851
|
+
var integrations_default = defineCommand9({
|
|
8511
8852
|
meta: {
|
|
8512
8853
|
name: "integrations",
|
|
8513
8854
|
description: "List, inspect, and invoke platform integrations"
|
|
8514
8855
|
},
|
|
8515
8856
|
subCommands: {
|
|
8516
|
-
list:
|
|
8857
|
+
list: list5,
|
|
8517
8858
|
info,
|
|
8518
8859
|
invoke
|
|
8519
8860
|
}
|
|
@@ -8521,7 +8862,7 @@ var integrations_default = defineCommand8({
|
|
|
8521
8862
|
|
|
8522
8863
|
// src/cli/commands/feedback.ts
|
|
8523
8864
|
import * as p16 from "@clack/prompts";
|
|
8524
|
-
import { existsSync as
|
|
8865
|
+
import { existsSync as existsSync22, readFileSync as readFileSync23 } from "fs";
|
|
8525
8866
|
import { dirname as dirname8, join as join20 } from "path";
|
|
8526
8867
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
8527
8868
|
import { release } from "os";
|
|
@@ -8549,7 +8890,7 @@ function readCliVersion() {
|
|
|
8549
8890
|
join20(here, "..", "..", "..", "package.json")
|
|
8550
8891
|
];
|
|
8551
8892
|
for (const path of candidates) {
|
|
8552
|
-
if (!
|
|
8893
|
+
if (!existsSync22(path)) continue;
|
|
8553
8894
|
const pkg2 = JSON.parse(readFileSync23(path, "utf-8"));
|
|
8554
8895
|
if (pkg2.name === "deepspace" && pkg2.version) return pkg2.version;
|
|
8555
8896
|
}
|
|
@@ -8745,7 +9086,7 @@ Context: deepspace ${payload.cliVersion} \xB7 ${payload.nodeVersion} \xB7 ${payl
|
|
|
8745
9086
|
});
|
|
8746
9087
|
|
|
8747
9088
|
// src/cli/commands/secrets.ts
|
|
8748
|
-
import { defineCommand as
|
|
9089
|
+
import { defineCommand as defineCommand10 } from "citty";
|
|
8749
9090
|
import { readFileSync as readFileSync24 } from "fs";
|
|
8750
9091
|
|
|
8751
9092
|
// src/cli/lib/citty-args.ts
|
|
@@ -8779,7 +9120,7 @@ function parseCursorArg(raw) {
|
|
|
8779
9120
|
}
|
|
8780
9121
|
|
|
8781
9122
|
// src/cli/commands/secrets.ts
|
|
8782
|
-
var
|
|
9123
|
+
var DEPLOY_URL11 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
|
|
8783
9124
|
var COMMON_ARGS = {
|
|
8784
9125
|
app: {
|
|
8785
9126
|
type: "string",
|
|
@@ -8849,7 +9190,7 @@ function warnIfDebugRoutesEnabled(secrets) {
|
|
|
8849
9190
|
}
|
|
8850
9191
|
var APPLY_HINT = "Run `deepspace deploy` to apply \u2014 secrets take effect at deploy time.";
|
|
8851
9192
|
var LOCAL_DEV_HINT = "Running `deepspace dev start`? Restart it to load the change locally.";
|
|
8852
|
-
var
|
|
9193
|
+
var list6 = defineCommand10({
|
|
8853
9194
|
meta: { name: "list", description: "List masked secrets in a config" },
|
|
8854
9195
|
args: {
|
|
8855
9196
|
...COMMON_ARGS,
|
|
@@ -8862,7 +9203,7 @@ var list5 = defineCommand9({
|
|
|
8862
9203
|
async run({ args }) {
|
|
8863
9204
|
try {
|
|
8864
9205
|
const t = await resolveTarget(args);
|
|
8865
|
-
const { secrets } = await listSecrets(
|
|
9206
|
+
const { secrets } = await listSecrets(DEPLOY_URL11, t.token, t.appId, t.configName);
|
|
8866
9207
|
if (args.json) {
|
|
8867
9208
|
console.log(JSON.stringify({ ok: true, appId: t.appId, config: t.configName, secrets }));
|
|
8868
9209
|
return;
|
|
@@ -8879,7 +9220,7 @@ var list5 = defineCommand9({
|
|
|
8879
9220
|
}
|
|
8880
9221
|
}
|
|
8881
9222
|
});
|
|
8882
|
-
var set =
|
|
9223
|
+
var set = defineCommand10({
|
|
8883
9224
|
meta: { name: "set", description: "Set secrets from KEY=value pairs" },
|
|
8884
9225
|
args: {
|
|
8885
9226
|
...COMMON_ARGS,
|
|
@@ -8907,9 +9248,9 @@ var set = defineCommand9({
|
|
|
8907
9248
|
}
|
|
8908
9249
|
if (Object.keys(secrets).length === 1) {
|
|
8909
9250
|
const [[k, v]] = Object.entries(secrets);
|
|
8910
|
-
await setSecret(
|
|
9251
|
+
await setSecret(DEPLOY_URL11, t.token, t.appId, t.configName, k, v);
|
|
8911
9252
|
} else {
|
|
8912
|
-
await uploadSecrets(
|
|
9253
|
+
await uploadSecrets(DEPLOY_URL11, t.token, t.appId, t.configName, secrets, false);
|
|
8913
9254
|
}
|
|
8914
9255
|
const n = Object.keys(secrets).length;
|
|
8915
9256
|
ok(
|
|
@@ -8928,7 +9269,7 @@ var set = defineCommand9({
|
|
|
8928
9269
|
}
|
|
8929
9270
|
}
|
|
8930
9271
|
});
|
|
8931
|
-
var
|
|
9272
|
+
var get2 = defineCommand10({
|
|
8932
9273
|
meta: { name: "get", description: "Get a secret; pass --plain to print the value" },
|
|
8933
9274
|
args: {
|
|
8934
9275
|
...COMMON_ARGS,
|
|
@@ -8940,11 +9281,11 @@ var get = defineCommand9({
|
|
|
8940
9281
|
const t = await resolveTarget(args);
|
|
8941
9282
|
const key = validateSecretName(args.key);
|
|
8942
9283
|
if (args.plain) {
|
|
8943
|
-
const { value } = await getSecretPlain(
|
|
9284
|
+
const { value } = await getSecretPlain(DEPLOY_URL11, t.token, t.appId, t.configName, key);
|
|
8944
9285
|
process.stdout.write(process.stdout.isTTY ? value + "\n" : value);
|
|
8945
9286
|
return;
|
|
8946
9287
|
}
|
|
8947
|
-
const { secrets } = await listSecrets(
|
|
9288
|
+
const { secrets } = await listSecrets(DEPLOY_URL11, t.token, t.appId, t.configName);
|
|
8948
9289
|
const item = secrets.find((s) => s.key === key);
|
|
8949
9290
|
if (!item)
|
|
8950
9291
|
fail(new InputError(`Secret "${key}" not found in ${t.configName}`, "secret_not_found"));
|
|
@@ -8964,7 +9305,7 @@ var get = defineCommand9({
|
|
|
8964
9305
|
}
|
|
8965
9306
|
}
|
|
8966
9307
|
});
|
|
8967
|
-
var del2 =
|
|
9308
|
+
var del2 = defineCommand10({
|
|
8968
9309
|
meta: { name: "delete", description: "Delete one or more secrets" },
|
|
8969
9310
|
args: {
|
|
8970
9311
|
...COMMON_ARGS,
|
|
@@ -8979,7 +9320,7 @@ var del2 = defineCommand9({
|
|
|
8979
9320
|
for (const key of keys) {
|
|
8980
9321
|
const name = validateSecretName(key);
|
|
8981
9322
|
try {
|
|
8982
|
-
await deleteSecret(
|
|
9323
|
+
await deleteSecret(DEPLOY_URL11, t.token, t.appId, t.configName, name);
|
|
8983
9324
|
deleted++;
|
|
8984
9325
|
} catch (err) {
|
|
8985
9326
|
if (err?.status === 404) absent++;
|
|
@@ -8998,7 +9339,7 @@ var del2 = defineCommand9({
|
|
|
8998
9339
|
}
|
|
8999
9340
|
}
|
|
9000
9341
|
});
|
|
9001
|
-
var upload =
|
|
9342
|
+
var upload = defineCommand10({
|
|
9002
9343
|
meta: { name: "upload", description: "Upload secrets from a dotenv or JSON file" },
|
|
9003
9344
|
args: {
|
|
9004
9345
|
...COMMON_ARGS,
|
|
@@ -9020,7 +9361,7 @@ var upload = defineCommand9({
|
|
|
9020
9361
|
const secrets = parseSecretsUpload(content);
|
|
9021
9362
|
if (Object.keys(secrets).length === 0)
|
|
9022
9363
|
fail(new InputError("No secrets found in the input.", "empty_input"));
|
|
9023
|
-
await uploadSecrets(
|
|
9364
|
+
await uploadSecrets(DEPLOY_URL11, t.token, t.appId, t.configName, secrets, args.replace);
|
|
9024
9365
|
const uploaded = Object.keys(secrets);
|
|
9025
9366
|
ok(
|
|
9026
9367
|
args.json === true,
|
|
@@ -9035,7 +9376,7 @@ var upload = defineCommand9({
|
|
|
9035
9376
|
}
|
|
9036
9377
|
}
|
|
9037
9378
|
});
|
|
9038
|
-
var download =
|
|
9379
|
+
var download = defineCommand10({
|
|
9039
9380
|
meta: { name: "download", description: "Download a config\u2019s secrets (dotenv/json/shell)" },
|
|
9040
9381
|
args: {
|
|
9041
9382
|
...COMMON_ARGS,
|
|
@@ -9057,14 +9398,14 @@ var download = defineCommand9({
|
|
|
9057
9398
|
)
|
|
9058
9399
|
);
|
|
9059
9400
|
}
|
|
9060
|
-
const { secrets } = await fetchSecretsValues(
|
|
9401
|
+
const { secrets } = await fetchSecretsValues(DEPLOY_URL11, t.token, t.appId, t.configName);
|
|
9061
9402
|
process.stdout.write(formatSecretsDownload(secrets, format));
|
|
9062
9403
|
} catch (err) {
|
|
9063
9404
|
fail(err);
|
|
9064
9405
|
}
|
|
9065
9406
|
}
|
|
9066
9407
|
});
|
|
9067
|
-
var pull =
|
|
9408
|
+
var pull = defineCommand10({
|
|
9068
9409
|
meta: { name: "pull", description: "Refresh the .dev.vars cache from the app store" },
|
|
9069
9410
|
args: { ...COMMON_ARGS },
|
|
9070
9411
|
async run({ args }) {
|
|
@@ -9080,7 +9421,7 @@ var pull = defineCommand9({
|
|
|
9080
9421
|
);
|
|
9081
9422
|
const t = await resolveTarget(args);
|
|
9082
9423
|
const ownerId = decodeJwtPayload(t.token).sub;
|
|
9083
|
-
const pulled = await pullAppSecretsCache(
|
|
9424
|
+
const pulled = await pullAppSecretsCache(DEPLOY_URL11, t.token, t.appId, t.configName);
|
|
9084
9425
|
if (!pulled) {
|
|
9085
9426
|
ok(
|
|
9086
9427
|
args.json === true,
|
|
@@ -9107,13 +9448,13 @@ var pull = defineCommand9({
|
|
|
9107
9448
|
}
|
|
9108
9449
|
}
|
|
9109
9450
|
});
|
|
9110
|
-
var configsList =
|
|
9451
|
+
var configsList = defineCommand10({
|
|
9111
9452
|
meta: { name: "list", description: "List the app\u2019s configs" },
|
|
9112
9453
|
args: { ...COMMON_ARGS },
|
|
9113
9454
|
async run({ args }) {
|
|
9114
9455
|
try {
|
|
9115
9456
|
const t = await resolveTarget(args);
|
|
9116
|
-
const { configs: configs2 } = await listConfigs(
|
|
9457
|
+
const { configs: configs2 } = await listConfigs(DEPLOY_URL11, t.token, t.appId);
|
|
9117
9458
|
ok(args.json === true, { appId: t.appId, configs: configs2 }, () => {
|
|
9118
9459
|
if (configs2.length === 0) {
|
|
9119
9460
|
console.log("No configs yet \u2014 the first `secrets set` creates one.");
|
|
@@ -9128,7 +9469,7 @@ var configsList = defineCommand9({
|
|
|
9128
9469
|
}
|
|
9129
9470
|
}
|
|
9130
9471
|
});
|
|
9131
|
-
var configsCreate =
|
|
9472
|
+
var configsCreate = defineCommand10({
|
|
9132
9473
|
meta: { name: "create", description: "Create a config (optionally copying another)" },
|
|
9133
9474
|
args: {
|
|
9134
9475
|
...COMMON_ARGS,
|
|
@@ -9140,7 +9481,7 @@ var configsCreate = defineCommand9({
|
|
|
9140
9481
|
const t = await resolveTarget(args);
|
|
9141
9482
|
const name = validateConfigName(args.name);
|
|
9142
9483
|
const copyFrom = args["copy-from"] || void 0;
|
|
9143
|
-
const { configs: configs2 } = await listConfigs(
|
|
9484
|
+
const { configs: configs2 } = await listConfigs(DEPLOY_URL11, t.token, t.appId);
|
|
9144
9485
|
if (configs2.some((c) => c.name === name)) {
|
|
9145
9486
|
if (copyFrom) {
|
|
9146
9487
|
fail(
|
|
@@ -9157,7 +9498,7 @@ var configsCreate = defineCommand9({
|
|
|
9157
9498
|
);
|
|
9158
9499
|
return;
|
|
9159
9500
|
}
|
|
9160
|
-
await createConfig(
|
|
9501
|
+
await createConfig(DEPLOY_URL11, t.token, t.appId, name, copyFrom);
|
|
9161
9502
|
ok(
|
|
9162
9503
|
args.json === true,
|
|
9163
9504
|
{ appId: t.appId, config: name, created: true, ...copyFrom ? { copyFrom } : {} },
|
|
@@ -9168,7 +9509,7 @@ var configsCreate = defineCommand9({
|
|
|
9168
9509
|
}
|
|
9169
9510
|
}
|
|
9170
9511
|
});
|
|
9171
|
-
var configsDelete =
|
|
9512
|
+
var configsDelete = defineCommand10({
|
|
9172
9513
|
meta: { name: "delete", description: "Delete a config and all of its secrets" },
|
|
9173
9514
|
args: {
|
|
9174
9515
|
...COMMON_ARGS,
|
|
@@ -9178,7 +9519,7 @@ var configsDelete = defineCommand9({
|
|
|
9178
9519
|
try {
|
|
9179
9520
|
const t = await resolveTarget(args);
|
|
9180
9521
|
const name = validateConfigName(args.name);
|
|
9181
|
-
await deleteConfig(
|
|
9522
|
+
await deleteConfig(DEPLOY_URL11, t.token, t.appId, name);
|
|
9182
9523
|
ok(
|
|
9183
9524
|
args.json === true,
|
|
9184
9525
|
{ appId: t.appId, config: name, deleted: true },
|
|
@@ -9189,16 +9530,16 @@ var configsDelete = defineCommand9({
|
|
|
9189
9530
|
}
|
|
9190
9531
|
}
|
|
9191
9532
|
});
|
|
9192
|
-
var configs =
|
|
9533
|
+
var configs = defineCommand10({
|
|
9193
9534
|
meta: { name: "configs", description: "Manage the app\u2019s secrets configs" },
|
|
9194
9535
|
subCommands: { list: configsList, create: configsCreate, delete: configsDelete }
|
|
9195
9536
|
});
|
|
9196
|
-
var secrets_default =
|
|
9537
|
+
var secrets_default = defineCommand10({
|
|
9197
9538
|
meta: { name: "secrets", description: "Manage the app\u2019s secrets store" },
|
|
9198
9539
|
subCommands: {
|
|
9199
|
-
list:
|
|
9540
|
+
list: list6,
|
|
9200
9541
|
set,
|
|
9201
|
-
get,
|
|
9542
|
+
get: get2,
|
|
9202
9543
|
delete: del2,
|
|
9203
9544
|
upload,
|
|
9204
9545
|
download,
|
|
@@ -9270,9 +9611,9 @@ var init_default = defineDeepspaceCommand({
|
|
|
9270
9611
|
});
|
|
9271
9612
|
|
|
9272
9613
|
// src/cli/commands/status.ts
|
|
9273
|
-
import { defineCommand as
|
|
9614
|
+
import { defineCommand as defineCommand11 } from "citty";
|
|
9274
9615
|
import * as p17 from "@clack/prompts";
|
|
9275
|
-
import { existsSync as
|
|
9616
|
+
import { existsSync as existsSync23, readFileSync as readFileSync25 } from "fs";
|
|
9276
9617
|
function timeAgo(iso) {
|
|
9277
9618
|
const ms = Date.now() - Date.parse(iso);
|
|
9278
9619
|
if (!Number.isFinite(ms) || ms < 0) return iso;
|
|
@@ -9305,7 +9646,7 @@ function resolveStatusApp(appDir, wranglerEnv) {
|
|
|
9305
9646
|
if (!resolved.ok) throw new InputError(resolved.reason, "invalid_env");
|
|
9306
9647
|
return { appName: resolved.name, appId: readAppId(appDir, wranglerEnv) };
|
|
9307
9648
|
}
|
|
9308
|
-
var status_default =
|
|
9649
|
+
var status_default = defineCommand11({
|
|
9309
9650
|
meta: {
|
|
9310
9651
|
name: "status",
|
|
9311
9652
|
description: "One screenful of current state: session, app, workspace, and live release"
|
|
@@ -9357,7 +9698,7 @@ var status_default = defineCommand10({
|
|
|
9357
9698
|
json.services = urls;
|
|
9358
9699
|
if (urlOverrides.length > 0) json.urlOverrides = urlOverrides;
|
|
9359
9700
|
}
|
|
9360
|
-
facts.loggedIn =
|
|
9701
|
+
facts.loggedIn = existsSync23(SESSION_PATH);
|
|
9361
9702
|
let userId = null;
|
|
9362
9703
|
if (!facts.loggedIn) {
|
|
9363
9704
|
lines.push(["Session", "not logged in"]);
|
|
@@ -9596,8 +9937,8 @@ var push_default = defineDeepspaceCommand({
|
|
|
9596
9937
|
const branchArg = args.branch === void 0 ? void 0 : String(args.branch);
|
|
9597
9938
|
const appArg = typeof args.app === "string" ? args.app : void 0;
|
|
9598
9939
|
const force = args.force === true;
|
|
9940
|
+
const appDir = findAppDir();
|
|
9599
9941
|
try {
|
|
9600
|
-
const appDir = findAppDir();
|
|
9601
9942
|
if (!appDir)
|
|
9602
9943
|
throw new Refusal(
|
|
9603
9944
|
"No wrangler.toml found \u2014 run from inside an app directory.",
|
|
@@ -9726,7 +10067,7 @@ var push_default = defineDeepspaceCommand({
|
|
|
9726
10067
|
}
|
|
9727
10068
|
const recoverable = isRecoverablePushFailure(result.status);
|
|
9728
10069
|
const rejectReason = result.reason ?? result.summary;
|
|
9729
|
-
const errorMsg = ok2 ? null : result.status === "ref_conflict" ? `The cloud repo's ${branch} moved while you worked (${rejectReason}). Run \`deepspace pull --app ${shQuote(appId)} --branch ${shQuote(branch)}\` to integrate, then push again.` : result.status === "rejected" ? `The cloud repo rejected ${branch}
|
|
10070
|
+
const errorMsg = ok2 ? null : result.status === "ref_conflict" ? `The cloud repo's ${branch} moved while you worked (${rejectReason}). Run \`deepspace pull --app ${shQuote(appId)} --branch ${shQuote(branch)}\` to integrate, then push again.` : result.status === "rejected" ? pushFailureMessage(`The cloud repo rejected ${branch}`, result, appDir ?? void 0) : `The cloud repo's ${branch} has commit(s) your local ${branch} doesn't. Run \`deepspace pull --app ${shQuote(appId)} --branch ${shQuote(branch)}\` and merge (or rebase), then push. Avoid --force here \u2014 it's guarded and will refuse rather than silently drop a peer's commits.`;
|
|
9730
10071
|
if (!args.json && ok2) p18.log.info(`App: ${appId}`);
|
|
9731
10072
|
const action = recoverable ? pullRecoveryAction(pullRecoveryCwd, appId, branch) : void 0;
|
|
9732
10073
|
if (!ok2) {
|
|
@@ -9739,7 +10080,7 @@ var push_default = defineDeepspaceCommand({
|
|
|
9739
10080
|
return { data: { status: result.status, appId, branch, oid: tipOid } };
|
|
9740
10081
|
} catch (err) {
|
|
9741
10082
|
if (err instanceof Refusal) throw err;
|
|
9742
|
-
const transportFailure = classifyPushTransportFailure(err);
|
|
10083
|
+
const transportFailure = classifyPushTransportFailure(err, appDir ?? void 0);
|
|
9743
10084
|
if (transportFailure) {
|
|
9744
10085
|
throw new Refusal(transportFailure.error, transportFailure.code);
|
|
9745
10086
|
}
|
|
@@ -10031,14 +10372,14 @@ var pull_default = defineDeepspaceCommand({
|
|
|
10031
10372
|
|
|
10032
10373
|
// src/cli/commands/clone.ts
|
|
10033
10374
|
import * as p20 from "@clack/prompts";
|
|
10034
|
-
import { existsSync as
|
|
10035
|
-
import { resolve as
|
|
10375
|
+
import { existsSync as existsSync24, readdirSync as readdirSync6, rmSync as rmSync5 } from "fs";
|
|
10376
|
+
import { resolve as resolve16, basename as basename5, join as join21 } from "path";
|
|
10036
10377
|
function cleanFailedCloneDir(dir) {
|
|
10037
10378
|
let entries;
|
|
10038
10379
|
try {
|
|
10039
10380
|
entries = readdirSync6(dir);
|
|
10040
10381
|
} catch {
|
|
10041
|
-
return
|
|
10382
|
+
return existsSync24(dir) ? ["<unreadable>"] : [];
|
|
10042
10383
|
}
|
|
10043
10384
|
if (entries.length === 1 && entries[0] === ".git") {
|
|
10044
10385
|
try {
|
|
@@ -10051,7 +10392,7 @@ function cleanFailedCloneDir(dir) {
|
|
|
10051
10392
|
return entries;
|
|
10052
10393
|
}
|
|
10053
10394
|
function validateCloneTarget(dir) {
|
|
10054
|
-
if (!
|
|
10395
|
+
if (!existsSync24(dir)) return false;
|
|
10055
10396
|
let entries;
|
|
10056
10397
|
try {
|
|
10057
10398
|
entries = readdirSync6(dir);
|
|
@@ -10086,7 +10427,7 @@ var clone_default = defineDeepspaceCommand({
|
|
|
10086
10427
|
async run({ args }) {
|
|
10087
10428
|
assertAppTargetResolvable(String(args.app));
|
|
10088
10429
|
const selector = String(args.app).trim();
|
|
10089
|
-
const dir =
|
|
10430
|
+
const dir = resolve16(String(args.dir ?? selector));
|
|
10090
10431
|
const dirPreexisted = validateCloneTarget(dir);
|
|
10091
10432
|
const spinner2 = args.json ? null : createSpinner();
|
|
10092
10433
|
spinner2?.start(`Resolving ${selector}\u2026`);
|
|
@@ -10129,7 +10470,7 @@ var clone_default = defineDeepspaceCommand({
|
|
|
10129
10470
|
const head = resolveCommit(dir, "HEAD");
|
|
10130
10471
|
const branch = currentBranch(dir);
|
|
10131
10472
|
spinner2?.stop(
|
|
10132
|
-
`Cloned ${selector} (${branches.length} ${branches.length === 1 ? "branch" : "branches"}) into ${
|
|
10473
|
+
`Cloned ${selector} (${branches.length} ${branches.length === 1 ? "branch" : "branches"}) into ${basename5(dir)}/ at ${head?.slice(0, 10) ?? "(unborn)"}.`
|
|
10133
10474
|
);
|
|
10134
10475
|
if (!args.json && !branch) {
|
|
10135
10476
|
p20.log.warn("HEAD is detached \u2014 check `git branch -a`.");
|
|
@@ -10152,7 +10493,7 @@ var clone_default = defineDeepspaceCommand({
|
|
|
10152
10493
|
|
|
10153
10494
|
// src/cli/commands/releases.ts
|
|
10154
10495
|
import * as p21 from "@clack/prompts";
|
|
10155
|
-
var
|
|
10496
|
+
var DEPLOY_URL12 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
|
|
10156
10497
|
var releases_default = defineDeepspaceCommand({
|
|
10157
10498
|
meta: {
|
|
10158
10499
|
name: "releases",
|
|
@@ -10187,8 +10528,8 @@ var releases_default = defineDeepspaceCommand({
|
|
|
10187
10528
|
const spinner2 = args.json ? null : createSpinner();
|
|
10188
10529
|
spinner2?.start("Loading release history\u2026");
|
|
10189
10530
|
const token = await ensureToken();
|
|
10190
|
-
const appId = await resolveAppTarget(
|
|
10191
|
-
const { releases } = await repoApi(
|
|
10531
|
+
const appId = await resolveAppTarget(DEPLOY_URL12, token, appArg, { wranglerEnv: envArg });
|
|
10532
|
+
const { releases } = await repoApi(DEPLOY_URL12, token, appId).listReleases(limit);
|
|
10192
10533
|
spinner2?.stop(`Loaded ${releases.length} ${releases.length === 1 ? "release" : "releases"}.`);
|
|
10193
10534
|
if (!args.json) {
|
|
10194
10535
|
if (releases.length === 0) {
|
|
@@ -10220,7 +10561,7 @@ Retry in a moment, or re-run with --allow-do-deletion to accept the risk.`,
|
|
|
10220
10561
|
"do_guard_unavailable"
|
|
10221
10562
|
);
|
|
10222
10563
|
}
|
|
10223
|
-
var
|
|
10564
|
+
var DEPLOY_URL13 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
|
|
10224
10565
|
function pickPreviousRelease(releases) {
|
|
10225
10566
|
if (releases.length === 0) {
|
|
10226
10567
|
return { error: "No releases recorded yet \u2014 nothing to roll back to.", code: "no_releases" };
|
|
@@ -10282,8 +10623,8 @@ var rollback_default = defineDeepspaceCommand({
|
|
|
10282
10623
|
const spinner2 = args.json ? null : createSpinner();
|
|
10283
10624
|
spinner2?.start("Preparing rollback\u2026");
|
|
10284
10625
|
const token = await ensureToken();
|
|
10285
|
-
const appId = await resolveAppTarget(
|
|
10286
|
-
const api4 = repoApi(
|
|
10626
|
+
const appId = await resolveAppTarget(DEPLOY_URL13, token, appArg, { wranglerEnv: envArg });
|
|
10627
|
+
const api4 = repoApi(DEPLOY_URL13, token, appId);
|
|
10287
10628
|
let releaseId = args.release ? String(args.release).trim() : "";
|
|
10288
10629
|
if (!releaseId) {
|
|
10289
10630
|
const { releases } = await api4.listReleases(2);
|
|
@@ -10294,7 +10635,7 @@ var rollback_default = defineDeepspaceCommand({
|
|
|
10294
10635
|
spinner2?.message(`Rolling back to ${releaseId}\u2026`);
|
|
10295
10636
|
let result;
|
|
10296
10637
|
try {
|
|
10297
|
-
result = await apiFetch(
|
|
10638
|
+
result = await apiFetch(DEPLOY_URL13, token, `/api/deploy/${appId}/rollback`, {
|
|
10298
10639
|
method: "POST",
|
|
10299
10640
|
body: JSON.stringify({
|
|
10300
10641
|
releaseId,
|
|
@@ -10355,11 +10696,11 @@ Re-run with --allow-do-deletion to accept the data loss.`,
|
|
|
10355
10696
|
});
|
|
10356
10697
|
|
|
10357
10698
|
// src/cli/commands/workspace.ts
|
|
10358
|
-
import { defineCommand as
|
|
10699
|
+
import { defineCommand as defineCommand12 } from "citty";
|
|
10359
10700
|
|
|
10360
10701
|
// src/cli/commands/workspace/new.ts
|
|
10361
10702
|
import * as p25 from "@clack/prompts";
|
|
10362
|
-
import { isAbsolute as isAbsolute6, resolve as
|
|
10703
|
+
import { isAbsolute as isAbsolute6, resolve as resolve17 } from "path";
|
|
10363
10704
|
|
|
10364
10705
|
// src/cli/commands/workspace/analysis.ts
|
|
10365
10706
|
import * as p23 from "@clack/prompts";
|
|
@@ -10484,7 +10825,7 @@ function printOverlaps(overlaps, json) {
|
|
|
10484
10825
|
|
|
10485
10826
|
// src/cli/commands/workspace/local.ts
|
|
10486
10827
|
import * as p24 from "@clack/prompts";
|
|
10487
|
-
import { mkdirSync as mkdirSync7, readFileSync as readFileSync26, realpathSync as realpathSync5, renameSync as renameSync2, statSync, writeFileSync as writeFileSync9 } from "fs";
|
|
10828
|
+
import { mkdirSync as mkdirSync7, readFileSync as readFileSync26, realpathSync as realpathSync5, renameSync as renameSync2, statSync as statSync3, writeFileSync as writeFileSync9 } from "fs";
|
|
10488
10829
|
import { dirname as dirname9, isAbsolute as isAbsolute5, join as join22, relative as relative2, sep as sep2 } from "path";
|
|
10489
10830
|
var WORKSPACE_MARKER = "deepspace-workspace.json";
|
|
10490
10831
|
function excludeWorktreeDir(appDir, dir) {
|
|
@@ -10573,7 +10914,7 @@ function materializeWorkspaceWorktree(appDir, worktreeRoot, branch, startPoint,
|
|
|
10573
10914
|
function inOwnLinkedWorktree(appDir, id) {
|
|
10574
10915
|
if (workspaceIdFromBranch(currentBranch(appDir)) !== id) return false;
|
|
10575
10916
|
try {
|
|
10576
|
-
return
|
|
10917
|
+
return statSync3(join22(repoToplevel(appDir), ".git")).isFile();
|
|
10577
10918
|
} catch {
|
|
10578
10919
|
return false;
|
|
10579
10920
|
}
|
|
@@ -10919,7 +11260,7 @@ var newWorkspaceCommand = defineDeepspaceCommand({
|
|
|
10919
11260
|
idempotencyKey: mintIdempotencyKey()
|
|
10920
11261
|
});
|
|
10921
11262
|
const dirInput = typeof args.dir === "string" ? args.dir.trim() : "";
|
|
10922
|
-
const worktreeRoot = dirInput ? isAbsolute6(dirInput) ? dirInput :
|
|
11263
|
+
const worktreeRoot = dirInput ? isAbsolute6(dirInput) ? dirInput : resolve17(appDir, dirInput) : defaultWorkspaceRoot(appDir, id);
|
|
10923
11264
|
const dir = appDirInWorktree(appDir, worktreeRoot);
|
|
10924
11265
|
try {
|
|
10925
11266
|
materializeWorkspaceWorktree(appDir, worktreeRoot, branch, baseOid, id);
|
|
@@ -10957,8 +11298,8 @@ var newWorkspaceCommand = defineDeepspaceCommand({
|
|
|
10957
11298
|
|
|
10958
11299
|
// src/cli/commands/workspace/attach.ts
|
|
10959
11300
|
import * as p26 from "@clack/prompts";
|
|
10960
|
-
import { existsSync as
|
|
10961
|
-
import { isAbsolute as isAbsolute7, resolve as
|
|
11301
|
+
import { existsSync as existsSync25, readdirSync as readdirSync7, rmSync as rmSync6 } from "fs";
|
|
11302
|
+
import { isAbsolute as isAbsolute7, resolve as resolve18 } from "path";
|
|
10962
11303
|
function finishedWorkspaceMessage(id, view) {
|
|
10963
11304
|
const workspace = view.workspace;
|
|
10964
11305
|
if (workspace.status === "landed") {
|
|
@@ -10967,7 +11308,7 @@ function finishedWorkspaceMessage(id, view) {
|
|
|
10967
11308
|
return `Workspace ${id} is ${workspace.status} \u2014 its ref is retained briefly (fetch ${workspace.ref} to inspect), but attach only works on active workspaces.`;
|
|
10968
11309
|
}
|
|
10969
11310
|
function cleanFailedFreshAttachDir(dir) {
|
|
10970
|
-
if (!
|
|
11311
|
+
if (!existsSync25(dir)) return [];
|
|
10971
11312
|
let entries;
|
|
10972
11313
|
try {
|
|
10973
11314
|
entries = readdirSync7(dir);
|
|
@@ -11043,7 +11384,7 @@ var attachWorkspaceCommand = defineDeepspaceCommand({
|
|
|
11043
11384
|
);
|
|
11044
11385
|
}
|
|
11045
11386
|
const requestedDir = typeof args.dir === "string" ? args.dir.trim() : "";
|
|
11046
|
-
const worktreeRoot = requestedDir ? isAbsolute7(requestedDir) ? requestedDir :
|
|
11387
|
+
const worktreeRoot = requestedDir ? isAbsolute7(requestedDir) ? requestedDir : resolve18(appDir, requestedDir) : defaultWorkspaceRoot(appDir, id);
|
|
11047
11388
|
const dir2 = appDirInWorktree(appDir, worktreeRoot);
|
|
11048
11389
|
if (resolveCommit(appDir, `refs/heads/${branch}`)) {
|
|
11049
11390
|
throw new Refusal(
|
|
@@ -11082,11 +11423,11 @@ var attachWorkspaceCommand = defineDeepspaceCommand({
|
|
|
11082
11423
|
extra: { status: view.workspace.status }
|
|
11083
11424
|
});
|
|
11084
11425
|
}
|
|
11085
|
-
const dir =
|
|
11426
|
+
const dir = resolve18(
|
|
11086
11427
|
process.cwd(),
|
|
11087
11428
|
(typeof args.dir === "string" ? args.dir.trim() : "") || `ws-${id.slice(3).toLowerCase()}`
|
|
11088
11429
|
);
|
|
11089
|
-
if (
|
|
11430
|
+
if (existsSync25(dir)) {
|
|
11090
11431
|
spinner2?.stop("Target exists.");
|
|
11091
11432
|
throw new Refusal(`${dir} already exists \u2014 pass a different directory.`, "dir_exists");
|
|
11092
11433
|
}
|
|
@@ -11830,7 +12171,7 @@ var dropWorkspaceCommand = defineDeepspaceCommand({
|
|
|
11830
12171
|
});
|
|
11831
12172
|
|
|
11832
12173
|
// src/cli/commands/workspace.ts
|
|
11833
|
-
var workspace_default =
|
|
12174
|
+
var workspace_default = defineCommand12({
|
|
11834
12175
|
meta: {
|
|
11835
12176
|
name: "workspace",
|
|
11836
12177
|
description: "Durable parallel-agent workspaces (new/attach/sync/list/status/land/drop)"
|
|
@@ -12001,7 +12342,7 @@ var activity_default = defineDeepspaceCommand({
|
|
|
12001
12342
|
});
|
|
12002
12343
|
|
|
12003
12344
|
// src/cli/commands/git-credential.ts
|
|
12004
|
-
import { defineCommand as
|
|
12345
|
+
import { defineCommand as defineCommand13 } from "citty";
|
|
12005
12346
|
function parseFields(input) {
|
|
12006
12347
|
const fields = /* @__PURE__ */ new Map();
|
|
12007
12348
|
for (const line of input.split("\n")) {
|
|
@@ -12050,7 +12391,7 @@ async function readStdin() {
|
|
|
12050
12391
|
for await (const chunk of process.stdin) data += chunk;
|
|
12051
12392
|
return data;
|
|
12052
12393
|
}
|
|
12053
|
-
var git_credential_default =
|
|
12394
|
+
var git_credential_default = defineCommand13({
|
|
12054
12395
|
meta: {
|
|
12055
12396
|
name: "git-credential",
|
|
12056
12397
|
description: "Git credential helper (installed automatically; not for direct use)"
|
|
@@ -12168,8 +12509,8 @@ function reportSource(appId, state, json) {
|
|
|
12168
12509
|
async function moveToGitHub(input) {
|
|
12169
12510
|
const { appDir, appId, token, deployUrl, state, remoteArg } = input;
|
|
12170
12511
|
const selected = requireGitHubRemote(appDir, remoteArg);
|
|
12171
|
-
const
|
|
12172
|
-
if (sameSource(state.source,
|
|
12512
|
+
const target2 = { provider: "github", repository: selected.repository };
|
|
12513
|
+
if (sameSource(state.source, target2)) return { source: target2, revision: state.revision };
|
|
12173
12514
|
if (state.source?.provider === "deepspace") {
|
|
12174
12515
|
requireLocalHead(appDir);
|
|
12175
12516
|
const api4 = repoApi(deployUrl, token, appId);
|
|
@@ -12225,7 +12566,7 @@ async function moveToGitHub(input) {
|
|
|
12225
12566
|
);
|
|
12226
12567
|
}
|
|
12227
12568
|
return setAppSource(deployUrl, token, appId, {
|
|
12228
|
-
source:
|
|
12569
|
+
source: target2,
|
|
12229
12570
|
expectedRevision: state.revision,
|
|
12230
12571
|
refs: wanted,
|
|
12231
12572
|
...releaseExpectation(latest)
|
|
@@ -12233,17 +12574,17 @@ async function moveToGitHub(input) {
|
|
|
12233
12574
|
}
|
|
12234
12575
|
requirePublishedHead(appDir, selected, appId);
|
|
12235
12576
|
return setAppSource(deployUrl, token, appId, {
|
|
12236
|
-
source:
|
|
12577
|
+
source: target2,
|
|
12237
12578
|
expectedRevision: state.revision
|
|
12238
12579
|
});
|
|
12239
12580
|
}
|
|
12240
12581
|
async function moveToDeepSpace(input) {
|
|
12241
12582
|
const { appDir, appId, token, deployUrl, state, remoteArg } = input;
|
|
12242
|
-
const
|
|
12243
|
-
if (sameSource(state.source,
|
|
12583
|
+
const target2 = { provider: "deepspace" };
|
|
12584
|
+
if (sameSource(state.source, target2)) return { source: target2, revision: state.revision };
|
|
12244
12585
|
if (state.source?.provider !== "github") {
|
|
12245
12586
|
return setAppSource(deployUrl, token, appId, {
|
|
12246
|
-
source:
|
|
12587
|
+
source: target2,
|
|
12247
12588
|
expectedRevision: state.revision
|
|
12248
12589
|
});
|
|
12249
12590
|
}
|
|
@@ -12277,7 +12618,7 @@ async function moveToDeepSpace(input) {
|
|
|
12277
12618
|
);
|
|
12278
12619
|
}
|
|
12279
12620
|
return setAppSource(deployUrl, token, appId, {
|
|
12280
|
-
source:
|
|
12621
|
+
source: target2,
|
|
12281
12622
|
expectedRevision: state.revision,
|
|
12282
12623
|
branch,
|
|
12283
12624
|
commitOid: oid,
|
|
@@ -12905,10 +13246,10 @@ function reportMigration(migration, json) {
|
|
|
12905
13246
|
// src/cli/cli.ts
|
|
12906
13247
|
var __dirname = dirname10(fileURLToPath3(import.meta.url));
|
|
12907
13248
|
var pkg = JSON.parse(readFileSync28(join24(__dirname, "..", "package.json"), "utf-8"));
|
|
12908
|
-
if (process.platform === "linux" && !process.env.SSL_CERT_FILE &&
|
|
13249
|
+
if (process.platform === "linux" && !process.env.SSL_CERT_FILE && existsSync26("/etc/ssl/certs/ca-certificates.crt")) {
|
|
12909
13250
|
process.env.SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt";
|
|
12910
13251
|
}
|
|
12911
|
-
var create2 =
|
|
13252
|
+
var create2 = defineCommand14({
|
|
12912
13253
|
meta: {
|
|
12913
13254
|
name: "create",
|
|
12914
13255
|
description: "Create a new DeepSpace app (runs create-deepspace; all flags are forwarded)"
|
|
@@ -12947,19 +13288,20 @@ var create2 = defineCommand13({
|
|
|
12947
13288
|
}
|
|
12948
13289
|
});
|
|
12949
13290
|
var rename = (cmd, name) => ({ ...cmd, meta: { ...cmd.meta ?? {}, name } });
|
|
12950
|
-
var auth =
|
|
13291
|
+
var auth = defineCommand14({
|
|
12951
13292
|
meta: { name: "auth", description: "Session: login, logout, whoami" },
|
|
12952
13293
|
subCommands: { login: login_default, logout: logout_default, whoami: whoami_default }
|
|
12953
13294
|
});
|
|
12954
|
-
var app =
|
|
13295
|
+
var app = defineCommand14({
|
|
12955
13296
|
meta: {
|
|
12956
13297
|
name: "app",
|
|
12957
|
-
description: "The app itself: create, init, list, source, migrate, undeploy, transfer, collaborators, domain, usage"
|
|
13298
|
+
description: "The app itself: create, init, list, files, source, migrate, undeploy, transfer, collaborators, domain, usage"
|
|
12958
13299
|
},
|
|
12959
13300
|
subCommands: {
|
|
12960
13301
|
create: create2,
|
|
12961
13302
|
init: init_default,
|
|
12962
13303
|
list: rename(apps_default, "list"),
|
|
13304
|
+
files: app_files_default,
|
|
12963
13305
|
undeploy: undeploy_default,
|
|
12964
13306
|
transfer: transfer_default,
|
|
12965
13307
|
collaborators: collaborators_default,
|
|
@@ -12969,11 +13311,11 @@ var app = defineCommand13({
|
|
|
12969
13311
|
migrate: migrate_default
|
|
12970
13312
|
}
|
|
12971
13313
|
});
|
|
12972
|
-
var devGroup =
|
|
13314
|
+
var devGroup = defineCommand14({
|
|
12973
13315
|
meta: { name: "dev", description: "Local development" },
|
|
12974
13316
|
subCommands: { start: rename(dev_default, "start"), kill: kill_default }
|
|
12975
13317
|
});
|
|
12976
|
-
var testGroup =
|
|
13318
|
+
var testGroup = defineCommand14({
|
|
12977
13319
|
meta: { name: "test", description: "App tests and test tooling" },
|
|
12978
13320
|
subCommands: {
|
|
12979
13321
|
run: rename(test_default, "run"),
|
|
@@ -12981,7 +13323,7 @@ var testGroup = defineCommand13({
|
|
|
12981
13323
|
accounts: rename(test_accounts_default, "accounts")
|
|
12982
13324
|
}
|
|
12983
13325
|
});
|
|
12984
|
-
var main =
|
|
13326
|
+
var main = defineCommand14({
|
|
12985
13327
|
meta: {
|
|
12986
13328
|
name: "deepspace",
|
|
12987
13329
|
version: pkg.version,
|