deepspace 0.12.0 → 0.14.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 +162 -0
- package/dist/{chunk-ZJ43EK3N.js → chunk-233GQU2H.js} +492 -365
- package/dist/chunk-233GQU2H.js.map +1 -0
- package/dist/cli.js +536 -172
- package/dist/cli.js.map +1 -1
- package/dist/documentation-client-core.d.ts +2 -2
- package/dist/documentation-client-core.js +1 -1
- package/dist/documentation-default-renderer.cjs +34 -34
- package/dist/documentation-react.d.ts +1 -1
- package/dist/documentation-react.js +1 -1
- package/dist/documentation-runtime.js +10 -10
- package/dist/documentation-server-core.d.ts +2 -2
- package/dist/documentation-server-core.js +1 -1
- package/dist/documentation.js +2 -2
- package/dist/documentation.js.map +1 -1
- package/dist/index.d.ts +28 -3
- package/dist/index.js +93 -8
- package/dist/index.js.map +1 -1
- package/dist/{public-BGRX_Cjd.d.ts → public-BtArwbVM.d.ts} +8 -0
- package/dist/server.d.ts +143 -27
- package/dist/server.js +427 -91
- package/dist/server.js.map +1 -1
- package/dist/worker.d.ts +140 -24
- package/dist/worker.js +432 -91
- package/dist/worker.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-ZJ43EK3N.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli/cli.ts
|
|
4
|
-
import { defineCommand as defineCommand14, runMain, runCommand } from "citty";
|
|
4
|
+
import { defineCommand as defineCommand14, runMain, runCommand, renderUsage } from "citty";
|
|
5
5
|
import { sync as spawnSync8 } from "cross-spawn";
|
|
6
6
|
import { readFileSync as readFileSync28, existsSync as existsSync26 } from "fs";
|
|
7
7
|
import { dirname as dirname10, join as join24 } from "path";
|
|
@@ -44,6 +44,13 @@ import * as p2 from "@clack/prompts";
|
|
|
44
44
|
import { isAbsolute } from "path";
|
|
45
45
|
|
|
46
46
|
// src/cli/lib/cli-format.ts
|
|
47
|
+
var ANSI_RE = /\[[0-9;]*m/g;
|
|
48
|
+
function stripAnsi(s) {
|
|
49
|
+
return s.replace(ANSI_RE, "");
|
|
50
|
+
}
|
|
51
|
+
function forTerminal(s) {
|
|
52
|
+
return process.stdout.isTTY ? s : stripAnsi(s);
|
|
53
|
+
}
|
|
47
54
|
function shQuote(s) {
|
|
48
55
|
return `'${s.replace(/'/g, "'\\''")}'`;
|
|
49
56
|
}
|
|
@@ -176,7 +183,10 @@ var API_ERROR_HINTS = {
|
|
|
176
183
|
test_account_cannot_be_collaborator: "Test accounts cannot be added as collaborators. Use a real DeepSpace account.",
|
|
177
184
|
user_not_found: "No DeepSpace user with that email. They need to log in to DeepSpace at least once (`deepspace auth login`, or sign in to any app) before they can be referenced by email.",
|
|
178
185
|
insufficient_credits: "Out of credits. Inviting a new collaborator by email sends them a transactional email billed to your account \u2014 top up your credits and try again.",
|
|
179
|
-
|
|
186
|
+
// "Try again" alone sends callers into a loop when the address itself is the
|
|
187
|
+
// problem — the send is what failed, and an undeliverable address fails the
|
|
188
|
+
// same way every time.
|
|
189
|
+
invite_email_failed: "The invite itself was not created and the charge was voided \u2014 nothing to undo. Retrying helps only if the send was transient; check the address is real and deliverable first. An email is needed ONLY for someone with no DeepSpace account yet: an existing user is added instantly, so having them sign in once and re-running this skips email entirely. If a retry now reports `already_invited` with no email sent, cancel the stuck invite (`deepspace app collaborators cancel <email>`) and invite again."
|
|
180
190
|
};
|
|
181
191
|
function formatCliError(err) {
|
|
182
192
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -222,6 +232,18 @@ function wrapCommandErrors(cmd) {
|
|
|
222
232
|
}
|
|
223
233
|
|
|
224
234
|
// src/cli/lib/command-suggestions.ts
|
|
235
|
+
function splitTokenPath(token, table) {
|
|
236
|
+
const parts = token.trim().split(/\s+/);
|
|
237
|
+
if (parts.length < 2) return null;
|
|
238
|
+
let node = table;
|
|
239
|
+
for (const part of parts) {
|
|
240
|
+
const next = node?.[part];
|
|
241
|
+
if (!next) return null;
|
|
242
|
+
node = next.subCommands;
|
|
243
|
+
}
|
|
244
|
+
return parts;
|
|
245
|
+
}
|
|
246
|
+
var DESTRUCTIVE_VERBS = /* @__PURE__ */ new Set(["rm", "delete", "remove", "drop", "clear", "undeploy", "kill"]);
|
|
225
247
|
function editDistance(a, b) {
|
|
226
248
|
const left = a.toLowerCase();
|
|
227
249
|
const right = b.toLowerCase();
|
|
@@ -263,12 +285,15 @@ function findUnknownCommand(argv, rootCommands) {
|
|
|
263
285
|
if (!table || token.startsWith("-")) return null;
|
|
264
286
|
const command = table[token];
|
|
265
287
|
if (!command) {
|
|
266
|
-
const
|
|
288
|
+
const split = splitTokenPath(token, table);
|
|
289
|
+
const relativeSuggestion = split ?? closestCommandPath(token, table);
|
|
267
290
|
if (!relativeSuggestion) return null;
|
|
268
291
|
return {
|
|
269
292
|
attemptedPath: ["deepspace", ...accepted, token],
|
|
270
293
|
helpPath: ["deepspace", ...accepted],
|
|
271
|
-
suggestion: ["deepspace", ...accepted, ...relativeSuggestion]
|
|
294
|
+
suggestion: ["deepspace", ...accepted, ...relativeSuggestion],
|
|
295
|
+
executable: !DESTRUCTIVE_VERBS.has(relativeSuggestion.at(-1) ?? ""),
|
|
296
|
+
...split ? { quotedToken: true } : {}
|
|
272
297
|
};
|
|
273
298
|
}
|
|
274
299
|
accepted.push(token);
|
|
@@ -2544,16 +2569,31 @@ function formatSchemaLintFindings(findings) {
|
|
|
2544
2569
|
}
|
|
2545
2570
|
|
|
2546
2571
|
// src/cli/lib/port.ts
|
|
2547
|
-
import { createServer } from "net";
|
|
2572
|
+
import { createServer, Socket } from "net";
|
|
2548
2573
|
var DEFAULT_PORT = 5173;
|
|
2549
|
-
function
|
|
2574
|
+
function isPortListening(port, host, timeoutMs = 500) {
|
|
2575
|
+
const target2 = host === "0.0.0.0" || host === "::" ? "127.0.0.1" : host;
|
|
2550
2576
|
return new Promise((resolve19) => {
|
|
2551
|
-
const
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2577
|
+
const socket = new Socket();
|
|
2578
|
+
const done = (listening) => {
|
|
2579
|
+
socket.destroy();
|
|
2580
|
+
resolve19(listening);
|
|
2581
|
+
};
|
|
2582
|
+
socket.setTimeout(timeoutMs);
|
|
2583
|
+
socket.once("connect", () => done(true));
|
|
2584
|
+
socket.once("timeout", () => done(false));
|
|
2585
|
+
socket.once("error", () => done(false));
|
|
2586
|
+
socket.connect(port, target2);
|
|
2555
2587
|
});
|
|
2556
2588
|
}
|
|
2589
|
+
async function waitForPortListening(port, host, timeoutMs) {
|
|
2590
|
+
const deadline = Date.now() + timeoutMs;
|
|
2591
|
+
while (Date.now() < deadline) {
|
|
2592
|
+
if (await isPortListening(port, host)) return true;
|
|
2593
|
+
await new Promise((resolve19) => setTimeout(resolve19, 250));
|
|
2594
|
+
}
|
|
2595
|
+
return false;
|
|
2596
|
+
}
|
|
2557
2597
|
function resolvePort(arg) {
|
|
2558
2598
|
const raw = arg ?? process.env.DEEPSPACE_PORT;
|
|
2559
2599
|
if (!raw) return DEFAULT_PORT;
|
|
@@ -2565,6 +2605,8 @@ function resolvePort(arg) {
|
|
|
2565
2605
|
}
|
|
2566
2606
|
|
|
2567
2607
|
// src/cli/commands/dev.ts
|
|
2608
|
+
var DEFAULT_DEV_HOST = "0.0.0.0";
|
|
2609
|
+
var READINESS_TIMEOUT_MS = 12e4;
|
|
2568
2610
|
var DEPLOY_URL = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
|
|
2569
2611
|
function noAppDirMessage(start, children) {
|
|
2570
2612
|
const lines = [`No wrangler.toml found at or above ${start}.`];
|
|
@@ -2600,6 +2642,11 @@ var dev_default = defineDeepspaceCommand({
|
|
|
2600
2642
|
type: "string",
|
|
2601
2643
|
description: `Port to bind (default ${DEFAULT_PORT}, or $DEEPSPACE_PORT)`,
|
|
2602
2644
|
required: false
|
|
2645
|
+
},
|
|
2646
|
+
host: {
|
|
2647
|
+
type: "string",
|
|
2648
|
+
description: `Interface to bind (default ${DEFAULT_DEV_HOST} \u2014 reachable from outside a container)`,
|
|
2649
|
+
required: false
|
|
2603
2650
|
}
|
|
2604
2651
|
},
|
|
2605
2652
|
async run({ args }) {
|
|
@@ -2608,6 +2655,7 @@ var dev_default = defineDeepspaceCommand({
|
|
|
2608
2655
|
};
|
|
2609
2656
|
preflightNodeVersion("dev start");
|
|
2610
2657
|
const wranglerEnv = typeof args.env === "string" && args.env.trim() ? args.env.trim() : void 0;
|
|
2658
|
+
const host = typeof args.host === "string" && args.host.trim() ? args.host.trim() : DEFAULT_DEV_HOST;
|
|
2611
2659
|
const start = resolve7(args.dir ?? ".");
|
|
2612
2660
|
const appDir = findAppDir(start);
|
|
2613
2661
|
if (!appDir) {
|
|
@@ -2671,6 +2719,7 @@ var dev_default = defineDeepspaceCommand({
|
|
|
2671
2719
|
say(`Logged in as ${payload.name ?? payload.email}`);
|
|
2672
2720
|
if (wranglerEnv) say(`Wrangler env: ${wranglerEnv}`);
|
|
2673
2721
|
say(`Port: ${port}`);
|
|
2722
|
+
if (host !== DEFAULT_DEV_HOST) say(`Host: ${host}`);
|
|
2674
2723
|
let generatedSecretsCache;
|
|
2675
2724
|
const appIdForSecrets = readAppId(appDir, wranglerEnv);
|
|
2676
2725
|
if (appIdForSecrets) {
|
|
@@ -2698,7 +2747,7 @@ var dev_default = defineDeepspaceCommand({
|
|
|
2698
2747
|
{ sharedDevVarsCache }
|
|
2699
2748
|
);
|
|
2700
2749
|
preflightWindowsWorkerd(appDir);
|
|
2701
|
-
if (
|
|
2750
|
+
if (await isPortListening(port, host)) {
|
|
2702
2751
|
const killArgv = port === DEFAULT_PORT ? ["deepspace", "dev", "kill"] : ["deepspace", "dev", "kill", "--port", String(port)];
|
|
2703
2752
|
const killCmd = killArgv.join(" ");
|
|
2704
2753
|
wranglerConfig.cleanup();
|
|
@@ -2709,12 +2758,34 @@ Free it with \`${killCmd}\`, or start on another port: \`deepspace dev start --p
|
|
|
2709
2758
|
{ extra: { port } }
|
|
2710
2759
|
);
|
|
2711
2760
|
}
|
|
2761
|
+
const url = `http://${host === DEFAULT_DEV_HOST ? "localhost" : host}:${port}`;
|
|
2712
2762
|
say("Starting dev server...\n");
|
|
2713
|
-
const vite = spawn(
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2763
|
+
const vite = spawn(
|
|
2764
|
+
"npx",
|
|
2765
|
+
["vite", "--port", String(port), "--strictPort", "--host", host],
|
|
2766
|
+
{
|
|
2767
|
+
cwd: appDir,
|
|
2768
|
+
stdio: "inherit",
|
|
2769
|
+
env: wranglerViteEnv(process.env, wranglerConfig, { DEEPSPACE_PORT: String(port) })
|
|
2770
|
+
}
|
|
2771
|
+
);
|
|
2772
|
+
if (args.json) {
|
|
2773
|
+
void waitForPortListening(port, host, READINESS_TIMEOUT_MS).then((ready) => {
|
|
2774
|
+
console.log(
|
|
2775
|
+
JSON.stringify(
|
|
2776
|
+
ready ? { ok: true, ready: true, url, port, host, appDir } : {
|
|
2777
|
+
ok: false,
|
|
2778
|
+
code: "dev_server_not_ready",
|
|
2779
|
+
error: `The dev server did not answer on ${url} within ${READINESS_TIMEOUT_MS / 1e3}s.`,
|
|
2780
|
+
url,
|
|
2781
|
+
port,
|
|
2782
|
+
host,
|
|
2783
|
+
appDir
|
|
2784
|
+
}
|
|
2785
|
+
)
|
|
2786
|
+
);
|
|
2787
|
+
});
|
|
2788
|
+
}
|
|
2718
2789
|
let stopping = false;
|
|
2719
2790
|
const stop = () => {
|
|
2720
2791
|
stopping = true;
|
|
@@ -2736,7 +2807,7 @@ Free it with \`${killCmd}\`, or start on another port: \`deepspace dev start --p
|
|
|
2736
2807
|
extra: { port, appDir, exitCode: code }
|
|
2737
2808
|
});
|
|
2738
2809
|
}
|
|
2739
|
-
return { data: { port, appDir, wranglerEnv: wranglerEnv ?? null } };
|
|
2810
|
+
return { data: { port, host, url, appDir, wranglerEnv: wranglerEnv ?? null } };
|
|
2740
2811
|
}
|
|
2741
2812
|
});
|
|
2742
2813
|
|
|
@@ -3725,6 +3796,133 @@ import * as p12 from "@clack/prompts";
|
|
|
3725
3796
|
import { defineCommand as defineCommand3 } from "citty";
|
|
3726
3797
|
import { resolve as resolve12 } from "path";
|
|
3727
3798
|
|
|
3799
|
+
// src/cli/lib/edge-propagation.ts
|
|
3800
|
+
var NOT_SERVING = ["Assets have not yet deployed", "No app configured"];
|
|
3801
|
+
var RELEASE_STAMP_PATH = "/.well-known/deepspace/release.json";
|
|
3802
|
+
async function waitForLiveRelease(url, releaseStamp, timeoutMs) {
|
|
3803
|
+
return releaseStamp ? waitForReleaseStamp(url, releaseStamp, timeoutMs) : waitForEdgePropagation(url, timeoutMs);
|
|
3804
|
+
}
|
|
3805
|
+
async function waitForReleaseStamp(url, releaseStamp, timeoutMs) {
|
|
3806
|
+
const deadline = Date.now() + timeoutMs;
|
|
3807
|
+
let attempt = 0;
|
|
3808
|
+
let streak = 0;
|
|
3809
|
+
while (Date.now() < deadline) {
|
|
3810
|
+
attempt++;
|
|
3811
|
+
try {
|
|
3812
|
+
const probe = new URL(RELEASE_STAMP_PATH, url);
|
|
3813
|
+
probe.searchParams.set("probe", `${Date.now()}-${attempt}`);
|
|
3814
|
+
const response = await fetch(probe, { redirect: "manual" });
|
|
3815
|
+
const body = await response.json().catch(() => null);
|
|
3816
|
+
if (response.ok && body?.release === releaseStamp) {
|
|
3817
|
+
streak++;
|
|
3818
|
+
if (streak >= 3) return true;
|
|
3819
|
+
await new Promise((resolve19) => setTimeout(resolve19, 1500));
|
|
3820
|
+
continue;
|
|
3821
|
+
}
|
|
3822
|
+
streak = 0;
|
|
3823
|
+
} catch {
|
|
3824
|
+
streak = 0;
|
|
3825
|
+
}
|
|
3826
|
+
const waitMs = Math.min(8e3, 1e3 * 2 ** (attempt - 1));
|
|
3827
|
+
await new Promise((resolve19) => setTimeout(resolve19, waitMs));
|
|
3828
|
+
}
|
|
3829
|
+
return false;
|
|
3830
|
+
}
|
|
3831
|
+
async function waitForEdgePropagation(url, timeoutMs) {
|
|
3832
|
+
const deadline = Date.now() + timeoutMs;
|
|
3833
|
+
let attempt = 0;
|
|
3834
|
+
let streak = 0;
|
|
3835
|
+
while (Date.now() < deadline) {
|
|
3836
|
+
attempt++;
|
|
3837
|
+
try {
|
|
3838
|
+
const response = await fetch(url, { redirect: "manual" });
|
|
3839
|
+
const body = await response.text();
|
|
3840
|
+
if (!NOT_SERVING.some((marker) => body.includes(marker))) {
|
|
3841
|
+
streak++;
|
|
3842
|
+
if (streak >= 3) return true;
|
|
3843
|
+
await new Promise((resolve19) => setTimeout(resolve19, 1500));
|
|
3844
|
+
continue;
|
|
3845
|
+
}
|
|
3846
|
+
streak = 0;
|
|
3847
|
+
} catch {
|
|
3848
|
+
streak = 0;
|
|
3849
|
+
}
|
|
3850
|
+
const waitMs = Math.min(8e3, 1e3 * 2 ** (attempt - 1));
|
|
3851
|
+
await new Promise((resolve19) => setTimeout(resolve19, waitMs));
|
|
3852
|
+
}
|
|
3853
|
+
return false;
|
|
3854
|
+
}
|
|
3855
|
+
|
|
3856
|
+
// src/shared/app-files.ts
|
|
3857
|
+
var MAX_APP_FILE_BYTES = 1024 * 1024 * 1024;
|
|
3858
|
+
var MAX_UPLOAD_REQUEST_BYTES = 25 * 1024 * 1024;
|
|
3859
|
+
var UPLOAD_PART_BYTES = 20 * 1024 * 1024;
|
|
3860
|
+
var MAX_UPLOAD_PARTS = Math.ceil(MAX_APP_FILE_BYTES / UPLOAD_PART_BYTES);
|
|
3861
|
+
var MAX_BASE64_UPLOAD_BYTES = Math.floor(MAX_UPLOAD_REQUEST_BYTES * 3 / 4);
|
|
3862
|
+
function planUploadParts(totalBytes, partSize) {
|
|
3863
|
+
const parts = [];
|
|
3864
|
+
for (let start = 0; start < totalBytes; start += partSize) {
|
|
3865
|
+
parts.push({
|
|
3866
|
+
partNumber: parts.length + 1,
|
|
3867
|
+
start,
|
|
3868
|
+
end: Math.min(start + partSize, totalBytes)
|
|
3869
|
+
});
|
|
3870
|
+
}
|
|
3871
|
+
return parts;
|
|
3872
|
+
}
|
|
3873
|
+
var APP_STORAGE_LIMIT_BYTES = {
|
|
3874
|
+
test: 0,
|
|
3875
|
+
free: 128 * 1024 * 1024,
|
|
3876
|
+
starter: 512 * 1024 * 1024,
|
|
3877
|
+
premium: 2 * 1024 * 1024 * 1024,
|
|
3878
|
+
admin: 10 * 1024 * 1024 * 1024
|
|
3879
|
+
};
|
|
3880
|
+
var MAX_DEPLOY_ASSET_FILE_BYTES = 25 * 1024 * 1024;
|
|
3881
|
+
var DANGEROUS_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
3882
|
+
"text/html",
|
|
3883
|
+
"application/xhtml+xml",
|
|
3884
|
+
"image/svg+xml",
|
|
3885
|
+
"application/xml",
|
|
3886
|
+
"text/xml",
|
|
3887
|
+
"application/javascript",
|
|
3888
|
+
"text/javascript",
|
|
3889
|
+
"application/ecmascript",
|
|
3890
|
+
"text/ecmascript"
|
|
3891
|
+
]);
|
|
3892
|
+
function activeContentMessage(mimeType) {
|
|
3893
|
+
return `${mimeType} is not accepted: the files API serves your app's own origin, so stored HTML/SVG/JavaScript would execute there with your users' sessions. Ship it as a build asset under \`public/\` instead, where it is served as part of your app rather than as user-uploaded content.`;
|
|
3894
|
+
}
|
|
3895
|
+
function formatBytes(bytes) {
|
|
3896
|
+
if (bytes >= 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GiB`;
|
|
3897
|
+
if (bytes >= 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MiB`;
|
|
3898
|
+
if (bytes >= 1024) return `${Math.round(bytes / 1024)} KiB`;
|
|
3899
|
+
return `${bytes} B`;
|
|
3900
|
+
}
|
|
3901
|
+
function encodeKeyPath(key) {
|
|
3902
|
+
return key.split("/").map(encodeURIComponent).join("/");
|
|
3903
|
+
}
|
|
3904
|
+
function oversizeMessage(bytes, limit = MAX_APP_FILE_BYTES) {
|
|
3905
|
+
return `That file is ${formatBytes(bytes)}; the limit is ${formatBytes(limit)} per file.`;
|
|
3906
|
+
}
|
|
3907
|
+
function describeFilesFailure(status3, body) {
|
|
3908
|
+
const trimmed = body.trim();
|
|
3909
|
+
if (trimmed.startsWith("{")) {
|
|
3910
|
+
try {
|
|
3911
|
+
const parsed = JSON.parse(trimmed);
|
|
3912
|
+
if (parsed.error) return parsed.error;
|
|
3913
|
+
} catch {
|
|
3914
|
+
}
|
|
3915
|
+
}
|
|
3916
|
+
if (status3 === 413) {
|
|
3917
|
+
return `The upload is too large. Files are limited to ${formatBytes(MAX_APP_FILE_BYTES)}, and one request may carry ${formatBytes(MAX_UPLOAD_REQUEST_BYTES)} \u2014 a larger request is rejected by the network before the app receives it.`;
|
|
3918
|
+
}
|
|
3919
|
+
if (status3 === 411) return "The upload did not declare its length.";
|
|
3920
|
+
if (status3 === 401 || status3 === 403) return "Not authorized to write these files.";
|
|
3921
|
+
if (status3 === 415) return "That file type is not accepted.";
|
|
3922
|
+
if (status3 >= 500) return `The files service failed (HTTP ${status3}). Retry shortly.`;
|
|
3923
|
+
return `Upload failed (HTTP ${status3}).`;
|
|
3924
|
+
}
|
|
3925
|
+
|
|
3728
3926
|
// src/cli/commands/deploy/build.ts
|
|
3729
3927
|
import * as p6 from "@clack/prompts";
|
|
3730
3928
|
import { execSync as execSync2 } from "child_process";
|
|
@@ -4044,7 +4242,14 @@ var RESERVED_RUN_WORKER_FIRST = /* @__PURE__ */ new Set([
|
|
|
4044
4242
|
"/_documentation",
|
|
4045
4243
|
"/_documentation/*",
|
|
4046
4244
|
"/_documentation-root",
|
|
4047
|
-
"/_documentation-root/*"
|
|
4245
|
+
"/_documentation-root/*",
|
|
4246
|
+
// Agent-protocol paths: the worker must see them so they cannot fall through
|
|
4247
|
+
// to the SPA shell (templates/base/src/server/http-routes.ts reserves them).
|
|
4248
|
+
"/llms.txt",
|
|
4249
|
+
"/llms-full.txt",
|
|
4250
|
+
"/.well-known/mcp",
|
|
4251
|
+
"/.well-known/mcp.json",
|
|
4252
|
+
"/.well-known/mcp/*"
|
|
4048
4253
|
]);
|
|
4049
4254
|
async function buildDeployBundle(options) {
|
|
4050
4255
|
const { appDir, appName, envName, sharedDevVarsCache, output, spinner: spinner2 } = options;
|
|
@@ -4178,6 +4383,12 @@ function resolveDeployRunWorkerFirst(config) {
|
|
|
4178
4383
|
const routes = extractRunWorkerFirst(config);
|
|
4179
4384
|
return routes;
|
|
4180
4385
|
}
|
|
4386
|
+
function oversizedAssetRefusal(assets) {
|
|
4387
|
+
const tooBig = assets.find((asset) => asset.size > MAX_DEPLOY_ASSET_FILE_BYTES);
|
|
4388
|
+
if (!tooBig) return null;
|
|
4389
|
+
return `${tooBig.path} is ${formatBytes(tooBig.size)}; the per-file limit for deploy assets is ${formatBytes(MAX_DEPLOY_ASSET_FILE_BYTES)}. ${LARGE_MEDIA_HOME}`;
|
|
4390
|
+
}
|
|
4391
|
+
var LARGE_MEDIA_HOME = "Large media belongs in your app files (`deepspace app files put`), not in the deploy bundle \u2014 move it out of `public/` and reference it at runtime.";
|
|
4181
4392
|
function collectAssets(dir) {
|
|
4182
4393
|
const assets = [];
|
|
4183
4394
|
const walk = (currentDir, prefix) => {
|
|
@@ -4670,37 +4881,6 @@ function repoApi(deployUrl, token, appId) {
|
|
|
4670
4881
|
};
|
|
4671
4882
|
}
|
|
4672
4883
|
|
|
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
|
-
|
|
4704
4884
|
// src/cli/lib/vc-remote.ts
|
|
4705
4885
|
import { existsSync as existsSync17 } from "fs";
|
|
4706
4886
|
import { tmpdir } from "os";
|
|
@@ -4913,10 +5093,11 @@ function pushToSpace(cwd, token, refspec, opts = {}) {
|
|
|
4913
5093
|
var OVERSIZED_PUSH_RE = /too large|exceeds|\bLFS\b/i;
|
|
4914
5094
|
var SERVER_OBJECT_CAP_BYTES = 20 * 1024 * 1024;
|
|
4915
5095
|
var SERVER_PACK_CAP_BYTES = 32 * 1024 * 1024;
|
|
5096
|
+
var PUSH_CEILINGS = `${formatBytes(SERVER_OBJECT_CAP_BYTES)} per file, ${formatBytes(SERVER_PACK_CAP_BYTES)} per push`;
|
|
4916
5097
|
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
5098
|
function removeFromHistoryAdvice(path) {
|
|
4918
5099
|
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:
|
|
5100
|
+
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 both the push and the bundle, in this order: (1) move it OUT of \`public/\` \u2014 .gitignore keeps it out of Git but not out of the deploy bundle, which uploads every file under \`public/\`; (2) if the commits that carry it are still local, \`git reset --soft <last pushed commit>\`, then \`git restore --staged ${file}\` \u2014 reset --soft moves HEAD only and leaves the file staged, so skipping this step re-commits the same blob; (3) commit what remains, then push \u2014 if git says "nothing to commit", that commit held only the file, so skip straight to the push and "Everything up-to-date" means you are done. If it already reached pushed history, rewrite it out instead (\`git filter-repo --path ${file} --invert-paths\`).`;
|
|
4920
5101
|
}
|
|
4921
5102
|
function fixForObjects(objects) {
|
|
4922
5103
|
if (objects.length === 0) return `${OVERSIZED_PUSH_FIX} ${removeFromHistoryAdvice(null)}`;
|
|
@@ -5402,7 +5583,7 @@ async function deployBuiltBundle(options) {
|
|
|
5402
5583
|
);
|
|
5403
5584
|
}
|
|
5404
5585
|
if (body.onBehalfOfOwner) {
|
|
5405
|
-
p10.log.warn(
|
|
5586
|
+
p10.log.warn("This release is attributed to the app's owner, not to your account.");
|
|
5406
5587
|
}
|
|
5407
5588
|
if (body.staleBaseGuard === "skipped") {
|
|
5408
5589
|
p10.log.warn(
|
|
@@ -5483,10 +5664,11 @@ async function uploadDeployAssets(options) {
|
|
|
5483
5664
|
p10.log.info(`Assets: ${byHash.size} file(s), all already uploaded`);
|
|
5484
5665
|
return;
|
|
5485
5666
|
}
|
|
5486
|
-
const missingBytes = missing.reduce((
|
|
5667
|
+
const missingBytes = missing.reduce((total2, asset) => total2 + asset.size, 0);
|
|
5487
5668
|
p10.log.info(
|
|
5488
5669
|
`Assets: ${byHash.size} file(s), uploading ${missing.length} (${Math.ceil(missingBytes / 1024)} KiB); the rest are already stored`
|
|
5489
5670
|
);
|
|
5671
|
+
const total = missing.length;
|
|
5490
5672
|
let uploaded = 0;
|
|
5491
5673
|
const next = () => missing.pop();
|
|
5492
5674
|
const worker = async () => {
|
|
@@ -5515,7 +5697,7 @@ async function uploadDeployAssets(options) {
|
|
|
5515
5697
|
);
|
|
5516
5698
|
}
|
|
5517
5699
|
uploaded++;
|
|
5518
|
-
spinner2.message(`Uploading assets \u2014 ${uploaded}/${
|
|
5700
|
+
spinner2.message(`Uploading assets \u2014 ${uploaded}/${total}...`);
|
|
5519
5701
|
}
|
|
5520
5702
|
};
|
|
5521
5703
|
try {
|
|
@@ -5746,7 +5928,11 @@ var DEPLOY_URL3 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
|
|
|
5746
5928
|
var deploy_default = defineCommand3({
|
|
5747
5929
|
meta: {
|
|
5748
5930
|
name: "deploy",
|
|
5749
|
-
|
|
5931
|
+
// The per-file ceiling belongs in --help: it was previously discoverable
|
|
5932
|
+
// only by hitting it, after the build and the push had already run. The
|
|
5933
|
+
// per-deploy total is deliberately absent — it is env-configurable, so any
|
|
5934
|
+
// number stated here would be wrong for some environment.
|
|
5935
|
+
description: `Build and deploy your DeepSpace app (assets: ${formatBytes(MAX_DEPLOY_ASSET_FILE_BYTES)} per file)`
|
|
5750
5936
|
},
|
|
5751
5937
|
args: {
|
|
5752
5938
|
dir: {
|
|
@@ -5842,6 +6028,20 @@ var deploy_default = defineCommand3({
|
|
|
5842
6028
|
output
|
|
5843
6029
|
});
|
|
5844
6030
|
const sourceState = await getAppSource(DEPLOY_URL3, token, appId);
|
|
6031
|
+
const spinner2 = createSpinner();
|
|
6032
|
+
const bundle = await buildDeployBundle({
|
|
6033
|
+
appDir,
|
|
6034
|
+
appName,
|
|
6035
|
+
envName,
|
|
6036
|
+
sharedDevVarsCache: secretsCache.linked !== null,
|
|
6037
|
+
output,
|
|
6038
|
+
spinner: spinner2
|
|
6039
|
+
});
|
|
6040
|
+
const oversized = oversizedAssetRefusal(bundle.assets);
|
|
6041
|
+
if (oversized) {
|
|
6042
|
+
spinner2.stop("Deploy failed");
|
|
6043
|
+
output.die(oversized, "assets_too_large");
|
|
6044
|
+
}
|
|
5845
6045
|
const repository = await syncDeployRepository({
|
|
5846
6046
|
deployUrl: DEPLOY_URL3,
|
|
5847
6047
|
appDir,
|
|
@@ -5852,15 +6052,6 @@ var deploy_default = defineCommand3({
|
|
|
5852
6052
|
output,
|
|
5853
6053
|
sourceState
|
|
5854
6054
|
});
|
|
5855
|
-
const spinner2 = createSpinner();
|
|
5856
|
-
const bundle = await buildDeployBundle({
|
|
5857
|
-
appDir,
|
|
5858
|
-
appName,
|
|
5859
|
-
envName,
|
|
5860
|
-
sharedDevVarsCache: secretsCache.linked !== null,
|
|
5861
|
-
output,
|
|
5862
|
-
spinner: spinner2
|
|
5863
|
-
});
|
|
5864
6055
|
const secrets = prepareDeploySecrets({
|
|
5865
6056
|
appDir,
|
|
5866
6057
|
envName,
|
|
@@ -5886,7 +6077,7 @@ var deploy_default = defineCommand3({
|
|
|
5886
6077
|
});
|
|
5887
6078
|
if (body.url) {
|
|
5888
6079
|
spinner2.message("Waiting for edge propagation...");
|
|
5889
|
-
const ready = await
|
|
6080
|
+
const ready = await waitForLiveRelease(body.url, body.releaseStamp, 9e4);
|
|
5890
6081
|
if (!ready) {
|
|
5891
6082
|
spinner2.stop("Deployed (edge propagation still in progress after 90s)");
|
|
5892
6083
|
p12.log.warn(
|
|
@@ -5951,30 +6142,6 @@ function blankSelectorRefusal(args) {
|
|
|
5951
6142
|
function staleBaseGuardFields(body) {
|
|
5952
6143
|
return body.staleBaseGuard === "skipped" ? { staleBaseGuard: "skipped" } : {};
|
|
5953
6144
|
}
|
|
5954
|
-
async function waitForAssetsReady(url, timeoutMs) {
|
|
5955
|
-
const deadline = Date.now() + timeoutMs;
|
|
5956
|
-
let attempt = 0;
|
|
5957
|
-
let streak = 0;
|
|
5958
|
-
while (Date.now() < deadline) {
|
|
5959
|
-
attempt++;
|
|
5960
|
-
try {
|
|
5961
|
-
const response = await fetch(url, { redirect: "manual" });
|
|
5962
|
-
const body = await response.text();
|
|
5963
|
-
if (!body.includes("Assets have not yet deployed") && !body.includes("No app configured")) {
|
|
5964
|
-
streak++;
|
|
5965
|
-
if (streak >= 3) return true;
|
|
5966
|
-
await new Promise((resolve19) => setTimeout(resolve19, 1500));
|
|
5967
|
-
continue;
|
|
5968
|
-
}
|
|
5969
|
-
streak = 0;
|
|
5970
|
-
} catch {
|
|
5971
|
-
streak = 0;
|
|
5972
|
-
}
|
|
5973
|
-
const waitMs = Math.min(8e3, 1e3 * 2 ** (attempt - 1));
|
|
5974
|
-
await new Promise((resolve19) => setTimeout(resolve19, waitMs));
|
|
5975
|
-
}
|
|
5976
|
-
return false;
|
|
5977
|
-
}
|
|
5978
6145
|
function errorMessage6(error) {
|
|
5979
6146
|
return error instanceof Error ? error.message : String(error);
|
|
5980
6147
|
}
|
|
@@ -6014,6 +6181,19 @@ function requireAppIdArg(explicit) {
|
|
|
6014
6181
|
}
|
|
6015
6182
|
return id;
|
|
6016
6183
|
}
|
|
6184
|
+
function liveAppUrl(app2) {
|
|
6185
|
+
return app2.status === "active" && app2.deployedAt !== null ? app2.url : null;
|
|
6186
|
+
}
|
|
6187
|
+
async function listApps(deployUrl, token) {
|
|
6188
|
+
const { apps } = await apiFetch(deployUrl, token, "/api/apps");
|
|
6189
|
+
if (!Array.isArray(apps)) {
|
|
6190
|
+
throw new InputError(
|
|
6191
|
+
`The deploy service at ${deployUrl} returned an unexpected response shape for the app list \u2014 check DEEPSPACE_DEPLOY_URL (is this the service the app lives on?).`,
|
|
6192
|
+
"invalid_response"
|
|
6193
|
+
);
|
|
6194
|
+
}
|
|
6195
|
+
return apps;
|
|
6196
|
+
}
|
|
6017
6197
|
function matchAppSelector(apps, selector) {
|
|
6018
6198
|
const byId = apps.find((app2) => app2.appId === selector);
|
|
6019
6199
|
if (byId) return byId.appId;
|
|
@@ -6023,14 +6203,7 @@ function matchAppSelector(apps, selector) {
|
|
|
6023
6203
|
}
|
|
6024
6204
|
async function resolveAppSelector(deployUrl, token, selector) {
|
|
6025
6205
|
if (STRICT_APP_ID_RE.test(selector)) return selector;
|
|
6026
|
-
const
|
|
6027
|
-
if (!Array.isArray(apps)) {
|
|
6028
|
-
throw new InputError(
|
|
6029
|
-
`The deploy service at ${deployUrl} returned an unexpected response shape for the app list \u2014 check DEEPSPACE_DEPLOY_URL (is this the service the app lives on?).`,
|
|
6030
|
-
"invalid_response"
|
|
6031
|
-
);
|
|
6032
|
-
}
|
|
6033
|
-
const id = matchAppSelector(apps, selector);
|
|
6206
|
+
const id = matchAppSelector(await listApps(deployUrl, token), selector);
|
|
6034
6207
|
if (id) return id;
|
|
6035
6208
|
const shared = await resolveAppIdByName(deployUrl, token, selector);
|
|
6036
6209
|
if (shared) return shared;
|
|
@@ -6113,7 +6286,7 @@ function assertAppTargetResolvable(appArg, options = {}) {
|
|
|
6113
6286
|
async function warnIfPhantomApp(deployUrl, token, appId, explicit) {
|
|
6114
6287
|
if (!explicit || !STRICT_APP_ID_RE.test(explicit.trim())) return;
|
|
6115
6288
|
try {
|
|
6116
|
-
const
|
|
6289
|
+
const apps = await listApps(deployUrl, token);
|
|
6117
6290
|
if (!apps.some((app2) => app2.appId === appId)) {
|
|
6118
6291
|
process.stderr.write(
|
|
6119
6292
|
`warning: ${appId} is not among your apps. If it exists and you have access (collaborator/admin), the server will use it; if it doesn't exist, this will register it as a NEW app under your account \u2014 check the id if that's not what you meant (a subdomain name also works with -a).
|
|
@@ -6227,7 +6400,6 @@ var whoami_default = defineDeepspaceCommand({
|
|
|
6227
6400
|
if (!args.json) {
|
|
6228
6401
|
console.log(`Name: ${payload.name ?? "(none)"}`);
|
|
6229
6402
|
console.log(`Email: ${payload.email ?? "(none)"}`);
|
|
6230
|
-
console.log(`UserID: ${payload.sub ?? "(none)"}`);
|
|
6231
6403
|
console.log(`Type: ${accountType}`);
|
|
6232
6404
|
if (payload.iss) console.log(`Issuer: ${payload.iss}`);
|
|
6233
6405
|
console.log(`Dashboard: ${DASHBOARD_URL}`);
|
|
@@ -6259,7 +6431,7 @@ var apps_default = defineDeepspaceCommand({
|
|
|
6259
6431
|
},
|
|
6260
6432
|
async run({ args }) {
|
|
6261
6433
|
const token = await ensureToken();
|
|
6262
|
-
const
|
|
6434
|
+
const apps = await listApps(DEPLOY_URL5, token);
|
|
6263
6435
|
if (!args.json) {
|
|
6264
6436
|
if (!apps.length) {
|
|
6265
6437
|
console.log("No apps yet. Create one with `npx create-deepspace <name>` and `deepspace deploy`.");
|
|
@@ -6267,16 +6439,18 @@ var apps_default = defineDeepspaceCommand({
|
|
|
6267
6439
|
const rows = [...apps].sort(
|
|
6268
6440
|
(left, right) => Number(right.status !== "undeployed") - Number(left.status !== "undeployed")
|
|
6269
6441
|
);
|
|
6442
|
+
const roleOf = (a) => a.role ?? "owner";
|
|
6443
|
+
const roleWidth = Math.max(4, ...rows.map((a) => roleOf(a).length));
|
|
6270
6444
|
const nameWidth = Math.max(4, ...rows.map((a) => (a.name ?? "\u2014").length));
|
|
6271
6445
|
const statusWidth = Math.max(6, ...rows.map((a) => a.status.length));
|
|
6272
6446
|
const idWidth = Math.max(6, ...rows.map((a) => a.appId.length));
|
|
6273
6447
|
console.log(
|
|
6274
|
-
`${"NAME".padEnd(nameWidth)} ${"STATUS".padEnd(statusWidth)} ${"APP ID".padEnd(idWidth)} URL`
|
|
6448
|
+
`${"NAME".padEnd(nameWidth)} ${"STATUS".padEnd(statusWidth)} ${"ROLE".padEnd(roleWidth)} ${"APP ID".padEnd(idWidth)} URL`
|
|
6275
6449
|
);
|
|
6276
6450
|
for (const a of rows) {
|
|
6277
|
-
const url = a
|
|
6451
|
+
const url = liveAppUrl(a) ?? "(not deployed)";
|
|
6278
6452
|
console.log(
|
|
6279
|
-
`${(a.name ?? "\u2014").padEnd(nameWidth)} ${a.status.padEnd(statusWidth)} ${a.appId.padEnd(idWidth)} ${url}`
|
|
6453
|
+
`${(a.name ?? "\u2014").padEnd(nameWidth)} ${a.status.padEnd(statusWidth)} ${roleOf(a).padEnd(roleWidth)} ${a.appId.padEnd(idWidth)} ${url}`
|
|
6280
6454
|
);
|
|
6281
6455
|
}
|
|
6282
6456
|
}
|
|
@@ -7989,11 +8163,16 @@ var CONTENT_TYPES = {
|
|
|
7989
8163
|
".css": "text/css",
|
|
7990
8164
|
".csv": "text/csv",
|
|
7991
8165
|
".gif": "image/gif",
|
|
8166
|
+
".htm": "text/html",
|
|
8167
|
+
".html": "text/html",
|
|
7992
8168
|
".ico": "image/x-icon",
|
|
7993
8169
|
".jpeg": "image/jpeg",
|
|
7994
8170
|
".jpg": "image/jpeg",
|
|
8171
|
+
".js": "text/javascript",
|
|
7995
8172
|
".json": "application/json",
|
|
7996
8173
|
".md": "text/markdown",
|
|
8174
|
+
".mjs": "text/javascript",
|
|
8175
|
+
".svg": "image/svg+xml",
|
|
7997
8176
|
".mp3": "audio/mpeg",
|
|
7998
8177
|
".mp4": "video/mp4",
|
|
7999
8178
|
".otf": "font/otf",
|
|
@@ -8039,7 +8218,10 @@ async function request(baseUrl, token, path, init = {}) {
|
|
|
8039
8218
|
throw new ApiError(
|
|
8040
8219
|
describeFilesFailure(res.status, text2),
|
|
8041
8220
|
res.status,
|
|
8042
|
-
|
|
8221
|
+
// Same slug the worker emits for the same condition — the edge cutting an
|
|
8222
|
+
// oversized request short is not a different failure from the worker
|
|
8223
|
+
// refusing it, and two codes made it look like one.
|
|
8224
|
+
code ?? (res.status === 413 ? "too_large" : res.status >= 500 ? "server_error" : "http_error"),
|
|
8043
8225
|
path
|
|
8044
8226
|
);
|
|
8045
8227
|
}
|
|
@@ -8072,31 +8254,96 @@ Content-Type: ${contentType}\r
|
|
|
8072
8254
|
contentType: `multipart/form-data; boundary=${boundary}`
|
|
8073
8255
|
};
|
|
8074
8256
|
}
|
|
8075
|
-
async function uploadAppFile(baseUrl, token, appId, localPath, key) {
|
|
8257
|
+
async function uploadAppFile(baseUrl, token, appId, localPath, key, onProgress) {
|
|
8076
8258
|
const path = filesPath(appId, `/upload?key=${encodeKeyPath(key)}`);
|
|
8077
8259
|
const size = statSync(localPath).size;
|
|
8078
8260
|
if (size > MAX_APP_FILE_BYTES) {
|
|
8079
|
-
throw new ApiError(oversizeMessage(size), 0, "
|
|
8261
|
+
throw new ApiError(oversizeMessage(size), 0, "too_large", path);
|
|
8080
8262
|
}
|
|
8081
|
-
const
|
|
8082
|
-
|
|
8083
|
-
|
|
8084
|
-
|
|
8085
|
-
)
|
|
8263
|
+
const declaredType = contentTypeFor(localPath);
|
|
8264
|
+
if (DANGEROUS_MIME_TYPES.has(declaredType)) {
|
|
8265
|
+
throw new ApiError(activeContentMessage(declaredType), 0, "active_content", path);
|
|
8266
|
+
}
|
|
8267
|
+
if (size > UPLOAD_PART_BYTES) {
|
|
8268
|
+
return uploadInParts(baseUrl, token, appId, localPath, key, size, onProgress);
|
|
8269
|
+
}
|
|
8270
|
+
const { blob, contentType } = await multipartBody(localPath, basename3(localPath), declaredType);
|
|
8086
8271
|
const res = await request(baseUrl, token, path, {
|
|
8087
8272
|
method: "POST",
|
|
8088
8273
|
headers: { "Content-Type": contentType },
|
|
8089
8274
|
body: blob
|
|
8090
8275
|
});
|
|
8091
8276
|
const body = await readJson(res, path);
|
|
8092
|
-
|
|
8277
|
+
onProgress?.(size, size, 1, 1);
|
|
8278
|
+
return { key: body.key, name: body.name, size, parts: 1 };
|
|
8279
|
+
}
|
|
8280
|
+
function isRetryable(err) {
|
|
8281
|
+
if (!(err instanceof ApiError)) return false;
|
|
8282
|
+
return err.status === 0 || err.status === 429 || err.status >= 500;
|
|
8283
|
+
}
|
|
8284
|
+
async function uploadInParts(baseUrl, token, appId, localPath, key, size, onProgress) {
|
|
8285
|
+
const contentType = contentTypeFor(localPath);
|
|
8286
|
+
const initPath = filesPath(appId, `/multipart?key=${encodeKeyPath(key)}`);
|
|
8287
|
+
const session = await readJson(
|
|
8288
|
+
await request(baseUrl, token, initPath, {
|
|
8289
|
+
method: "POST",
|
|
8290
|
+
headers: { "Content-Type": "application/json" },
|
|
8291
|
+
body: JSON.stringify({ name: basename3(localPath), mimeType: contentType, size })
|
|
8292
|
+
}),
|
|
8293
|
+
initPath
|
|
8294
|
+
);
|
|
8295
|
+
const query = `uploadKey=${encodeKeyPath(session.uploadKey)}&uploadId=${encodeURIComponent(session.uploadId)}`;
|
|
8296
|
+
if (!Number.isSafeInteger(session.partSize) || session.partSize < 1) {
|
|
8297
|
+
throw new ApiError(
|
|
8298
|
+
`The platform advertised an unusable part size (${session.partSize}).`,
|
|
8299
|
+
0,
|
|
8300
|
+
"invalid_response",
|
|
8301
|
+
initPath
|
|
8302
|
+
);
|
|
8303
|
+
}
|
|
8304
|
+
const plan = planUploadParts(size, session.partSize);
|
|
8305
|
+
const file = await openAsBlob(localPath, { type: contentType });
|
|
8306
|
+
const uploaded = [];
|
|
8307
|
+
try {
|
|
8308
|
+
for (const part of plan) {
|
|
8309
|
+
const partPath = filesPath(appId, `/multipart/part?${query}&partNumber=${part.partNumber}`);
|
|
8310
|
+
const send = () => request(baseUrl, token, partPath, {
|
|
8311
|
+
method: "PUT",
|
|
8312
|
+
body: file.slice(part.start, part.end, contentType)
|
|
8313
|
+
});
|
|
8314
|
+
const res = await send().catch(async (err) => {
|
|
8315
|
+
if (!isRetryable(err)) throw err;
|
|
8316
|
+
return send();
|
|
8317
|
+
});
|
|
8318
|
+
uploaded.push(await readJson(res, partPath));
|
|
8319
|
+
onProgress?.(part.end, size, part.partNumber, plan.length);
|
|
8320
|
+
}
|
|
8321
|
+
const completePath = filesPath(appId, `/multipart/complete?${query}`);
|
|
8322
|
+
const body = await readJson(
|
|
8323
|
+
await request(baseUrl, token, completePath, {
|
|
8324
|
+
method: "POST",
|
|
8325
|
+
headers: { "Content-Type": "application/json" },
|
|
8326
|
+
body: JSON.stringify({ parts: uploaded })
|
|
8327
|
+
}),
|
|
8328
|
+
completePath
|
|
8329
|
+
);
|
|
8330
|
+
return { key: body.key, name: body.name, size, parts: plan.length };
|
|
8331
|
+
} catch (err) {
|
|
8332
|
+
await request(baseUrl, token, filesPath(appId, `/multipart?${query}`), {
|
|
8333
|
+
method: "DELETE"
|
|
8334
|
+
}).catch(() => void 0);
|
|
8335
|
+
throw err;
|
|
8336
|
+
}
|
|
8093
8337
|
}
|
|
8094
8338
|
async function listAppFiles(baseUrl, token, appId, query) {
|
|
8095
8339
|
const path = filesPath(appId, `?${query}`);
|
|
8096
8340
|
return readJson(await request(baseUrl, token, path), path);
|
|
8097
8341
|
}
|
|
8098
8342
|
async function deleteAppFile(baseUrl, token, appId, key) {
|
|
8099
|
-
|
|
8343
|
+
const path = filesPath(appId, `/${encodeKeyPath(key)}`);
|
|
8344
|
+
const res = await request(baseUrl, token, path, { method: "DELETE" });
|
|
8345
|
+
const body = await readJson(res, path);
|
|
8346
|
+
return { existed: body.existed !== false };
|
|
8100
8347
|
}
|
|
8101
8348
|
async function downloadAppFile(baseUrl, token, appId, key, destination) {
|
|
8102
8349
|
const path = filesPath(appId, `/${encodeKeyPath(key)}`);
|
|
@@ -8156,7 +8403,10 @@ function servedPath(key) {
|
|
|
8156
8403
|
return `/api/files/${encodeKeyPath(key)}?scope=app`;
|
|
8157
8404
|
}
|
|
8158
8405
|
var put = defineDeepspaceCommand({
|
|
8159
|
-
meta: {
|
|
8406
|
+
meta: {
|
|
8407
|
+
name: "put",
|
|
8408
|
+
description: `Upload a file to the app\u2019s files (${formatBytes(MAX_APP_FILE_BYTES)} per file)`
|
|
8409
|
+
},
|
|
8160
8410
|
args: {
|
|
8161
8411
|
file: { type: "positional", description: "Local file to upload", required: true },
|
|
8162
8412
|
key: { type: "string", description: "Key to store it under (default: the file name)" },
|
|
@@ -8169,12 +8419,42 @@ var put = defineDeepspaceCommand({
|
|
|
8169
8419
|
}
|
|
8170
8420
|
const key = requireKey(args.key ?? basename4(localPath));
|
|
8171
8421
|
const { token, appId } = await target(args.app);
|
|
8172
|
-
const
|
|
8422
|
+
const spinner2 = args.json ? null : createSpinner();
|
|
8423
|
+
let started = false;
|
|
8424
|
+
const result = await uploadAppFile(
|
|
8425
|
+
PLATFORM_URL,
|
|
8426
|
+
token,
|
|
8427
|
+
appId,
|
|
8428
|
+
localPath,
|
|
8429
|
+
key,
|
|
8430
|
+
(sent, total, part, parts) => {
|
|
8431
|
+
if (parts === 1 || !spinner2) return;
|
|
8432
|
+
if (!started) {
|
|
8433
|
+
spinner2.start(`Uploading ${key} in ${parts} parts`);
|
|
8434
|
+
started = true;
|
|
8435
|
+
}
|
|
8436
|
+
spinner2.message(
|
|
8437
|
+
`${key} \u2014 part ${part}/${parts} (${formatBytes(sent)} of ${formatBytes(total)})`
|
|
8438
|
+
);
|
|
8439
|
+
}
|
|
8440
|
+
).finally(() => {
|
|
8441
|
+
if (started) spinner2?.stop();
|
|
8442
|
+
});
|
|
8173
8443
|
if (!args.json) {
|
|
8174
|
-
|
|
8444
|
+
const how = result.parts > 1 ? ` in ${result.parts} parts` : "";
|
|
8445
|
+
console.log(`\u2713 ${key} (${formatBytes(result.size)})${how}`);
|
|
8175
8446
|
console.log(` Served from your app at ${servedPath(result.key)}`);
|
|
8176
8447
|
}
|
|
8177
|
-
return {
|
|
8448
|
+
return {
|
|
8449
|
+
data: {
|
|
8450
|
+
appId,
|
|
8451
|
+
key,
|
|
8452
|
+
storedKey: result.key,
|
|
8453
|
+
size: result.size,
|
|
8454
|
+
parts: result.parts,
|
|
8455
|
+
path: servedPath(result.key)
|
|
8456
|
+
}
|
|
8457
|
+
};
|
|
8178
8458
|
}
|
|
8179
8459
|
});
|
|
8180
8460
|
var list3 = defineDeepspaceCommand({
|
|
@@ -8215,8 +8495,14 @@ var list3 = defineDeepspaceCommand({
|
|
|
8215
8495
|
const more = limit < MAX_LIST_LIMIT ? "raise --limit or narrow with --prefix" : "narrow with --prefix";
|
|
8216
8496
|
if (result.truncated) console.log(`(truncated at ${limit} \u2014 ${more})`);
|
|
8217
8497
|
}
|
|
8498
|
+
if (result.storage) {
|
|
8499
|
+
const { usedBytes, limitBytes } = result.storage;
|
|
8500
|
+
console.log(
|
|
8501
|
+
limitBytes === void 0 ? `Storage: ${formatBytes(usedBytes)} used (limit unavailable right now)` : `Storage: ${formatBytes(usedBytes)} of ${formatBytes(limitBytes)} used`
|
|
8502
|
+
);
|
|
8503
|
+
}
|
|
8218
8504
|
}
|
|
8219
|
-
return { data: { appId, files, truncated: result.truncated } };
|
|
8505
|
+
return { data: { appId, files, truncated: result.truncated, storage: result.storage ?? null } };
|
|
8220
8506
|
}
|
|
8221
8507
|
});
|
|
8222
8508
|
var get = defineDeepspaceCommand({
|
|
@@ -8244,7 +8530,13 @@ var rm = defineDeepspaceCommand({
|
|
|
8244
8530
|
async run({ args }) {
|
|
8245
8531
|
const key = requireKey(String(args.key));
|
|
8246
8532
|
const { token, appId } = await target(args.app);
|
|
8247
|
-
await deleteAppFile(PLATFORM_URL, token, appId, key);
|
|
8533
|
+
const { existed } = await deleteAppFile(PLATFORM_URL, token, appId, key);
|
|
8534
|
+
if (!existed) {
|
|
8535
|
+
throw new Refusal(
|
|
8536
|
+
`No file at ${key} \u2014 nothing was deleted. Check the key with \`deepspace app files list\`.`,
|
|
8537
|
+
"file_not_found"
|
|
8538
|
+
);
|
|
8539
|
+
}
|
|
8248
8540
|
if (!args.json) console.log(`\u2713 deleted ${key}`);
|
|
8249
8541
|
return { data: { appId, key, deleted: true } };
|
|
8250
8542
|
}
|
|
@@ -8338,7 +8630,7 @@ var add = defineDeepspaceCommand({
|
|
|
8338
8630
|
}
|
|
8339
8631
|
if (!args.json) {
|
|
8340
8632
|
console.log(
|
|
8341
|
-
`\u2713 Invite sent to ${res.email} (expires ${expires}). They
|
|
8633
|
+
`\u2713 Invite sent to ${res.email} (expires ${expires}). They accept it from the emailed link, or by signing in and running \`deepspace app collaborators accept ${app2}\`.`
|
|
8342
8634
|
);
|
|
8343
8635
|
}
|
|
8344
8636
|
return { data: { ...res } };
|
|
@@ -8407,9 +8699,56 @@ var cancel3 = defineDeepspaceCommand({
|
|
|
8407
8699
|
return { data: { cancelled: found } };
|
|
8408
8700
|
}
|
|
8409
8701
|
});
|
|
8702
|
+
var invites = defineDeepspaceCommand({
|
|
8703
|
+
meta: { name: "invites", description: "List invites waiting for you" },
|
|
8704
|
+
async run({ args }) {
|
|
8705
|
+
const token = await ensureToken();
|
|
8706
|
+
const { invites: invites2 } = await api2(
|
|
8707
|
+
token,
|
|
8708
|
+
"/api/app-collaborators/invites/mine"
|
|
8709
|
+
);
|
|
8710
|
+
if (!args.json) {
|
|
8711
|
+
if (!invites2.length) {
|
|
8712
|
+
console.log("No pending invites for your email.");
|
|
8713
|
+
} else {
|
|
8714
|
+
for (const invite of invites2) {
|
|
8715
|
+
console.log(
|
|
8716
|
+
`${invite.appId} invited by ${invite.invitedByName} (expires ${new Date(invite.expiresAt).toLocaleDateString()})`
|
|
8717
|
+
);
|
|
8718
|
+
}
|
|
8719
|
+
console.log("Accept one with `deepspace app collaborators accept <app-id>`.");
|
|
8720
|
+
}
|
|
8721
|
+
}
|
|
8722
|
+
return { data: { invites: invites2 } };
|
|
8723
|
+
}
|
|
8724
|
+
});
|
|
8725
|
+
var accept = defineDeepspaceCommand({
|
|
8726
|
+
meta: { name: "accept", description: "Accept an invite to collaborate on an app" },
|
|
8727
|
+
args: {
|
|
8728
|
+
app: { type: "positional", description: "App id (see `collaborators invites`)", required: true }
|
|
8729
|
+
},
|
|
8730
|
+
async run({ args }) {
|
|
8731
|
+
const appId = String(args.app);
|
|
8732
|
+
const token = await ensureToken();
|
|
8733
|
+
const res = await api2(
|
|
8734
|
+
token,
|
|
8735
|
+
`/api/app-collaborators/invites/${encodeURIComponent(appId)}/accept`,
|
|
8736
|
+
{ method: "POST" }
|
|
8737
|
+
);
|
|
8738
|
+
if (!args.json) {
|
|
8739
|
+
console.log(
|
|
8740
|
+
res.alreadyMember ? `\u2022 You already have access to ${res.appId}.` : `\u2713 You can now deploy ${res.appId}.`
|
|
8741
|
+
);
|
|
8742
|
+
}
|
|
8743
|
+
return {
|
|
8744
|
+
data: { ...res },
|
|
8745
|
+
action: cliAction("deepspace", "pull", "--app", res.appId)
|
|
8746
|
+
};
|
|
8747
|
+
}
|
|
8748
|
+
});
|
|
8410
8749
|
var collaborators_default = defineCommand7({
|
|
8411
8750
|
meta: { name: "collaborators", description: "Manage who can deploy your app" },
|
|
8412
|
-
subCommands: { list: list4, add, remove, cancel: cancel3 }
|
|
8751
|
+
subCommands: { list: list4, add, remove, cancel: cancel3, invites, accept }
|
|
8413
8752
|
});
|
|
8414
8753
|
|
|
8415
8754
|
// src/cli/commands/transfer.ts
|
|
@@ -8494,7 +8833,7 @@ var status2 = defineDeepspaceCommand({
|
|
|
8494
8833
|
return { data: { app: app2, transfer } };
|
|
8495
8834
|
}
|
|
8496
8835
|
});
|
|
8497
|
-
var
|
|
8836
|
+
var accept2 = defineDeepspaceCommand({
|
|
8498
8837
|
meta: { name: "accept", description: "Accept a transfer offered to you" },
|
|
8499
8838
|
args: {
|
|
8500
8839
|
app: { type: "string", alias: "a", description: "App id of the offered app", required: true }
|
|
@@ -8535,7 +8874,7 @@ var cancel4 = defineDeepspaceCommand({
|
|
|
8535
8874
|
});
|
|
8536
8875
|
var transfer_default = defineCommand8({
|
|
8537
8876
|
meta: { name: "transfer", description: "Transfer app ownership to another user" },
|
|
8538
|
-
subCommands: { offer, status: status2, accept, cancel: cancel4 }
|
|
8877
|
+
subCommands: { offer, status: status2, accept: accept2, cancel: cancel4 }
|
|
8539
8878
|
});
|
|
8540
8879
|
|
|
8541
8880
|
// src/cli/commands/integrations.ts
|
|
@@ -9795,24 +10134,36 @@ var status_default = defineCommand11({
|
|
|
9795
10134
|
const failure = statusRemoteFailure(error);
|
|
9796
10135
|
lines.push([label, failure.human]);
|
|
9797
10136
|
json[key] = failure.json;
|
|
9798
|
-
},
|
|
10137
|
+
}, reportLive2 = function(rel, entry) {
|
|
10138
|
+
if (rel === null) {
|
|
10139
|
+
lines.push(["Live", "never deployed"]);
|
|
10140
|
+
json.live = null;
|
|
10141
|
+
return;
|
|
10142
|
+
}
|
|
9799
10143
|
const byYou = userId !== null && rel.actor === userId;
|
|
9800
|
-
|
|
9801
|
-
|
|
9802
|
-
`release #${rel.seq} (${rel.kind} of ${rel.commitOid?.slice(0, 10) ?? "unknown source"}, ${timeAgo(rel.createdAt)}${byYou ? ", by you" : ""})` + (rel.url ? ` \xB7 ${rel.url}` : "")
|
|
9803
|
-
]);
|
|
9804
|
-
json.live = {
|
|
10144
|
+
const release2 = `release #${rel.seq} (${rel.kind} of ${rel.commitOid?.slice(0, 10) ?? "unknown source"}, ${timeAgo(rel.createdAt)}${byYou ? ", by you" : ""})`;
|
|
10145
|
+
const details = {
|
|
9805
10146
|
seq: rel.seq,
|
|
9806
10147
|
kind: rel.kind,
|
|
9807
10148
|
commitOid: rel.commitOid,
|
|
9808
10149
|
createdAt: rel.createdAt,
|
|
9809
|
-
url: rel.url,
|
|
9810
10150
|
byYou,
|
|
9811
10151
|
source: rel.source,
|
|
9812
10152
|
sourceRevision: rel.sourceRevision
|
|
9813
10153
|
};
|
|
10154
|
+
if (!entry) {
|
|
10155
|
+
lines.push(["Live", `${release2} \xB7 serving state not visible from your account`]);
|
|
10156
|
+
json.live = { ...details, serving: null, url: null };
|
|
10157
|
+
return;
|
|
10158
|
+
}
|
|
10159
|
+
const url = liveAppUrl(entry);
|
|
10160
|
+
lines.push([
|
|
10161
|
+
"Live",
|
|
10162
|
+
url ? `${release2} \xB7 ${url}` : `not serving \u2014 ${entry.status}, last ${release2}`
|
|
10163
|
+
]);
|
|
10164
|
+
json.live = { ...details, serving: url !== null, url };
|
|
9814
10165
|
};
|
|
9815
|
-
var reportWorkspace = reportWorkspace2, reportRemoteFailure = reportRemoteFailure2,
|
|
10166
|
+
var reportWorkspace = reportWorkspace2, reportRemoteFailure = reportRemoteFailure2, reportLive = reportLive2;
|
|
9816
10167
|
const api4 = repoApi(deployBaseUrl(), token, appId);
|
|
9817
10168
|
const sourceResult = await observeRemote(getAppSource(deployBaseUrl(), token, appId));
|
|
9818
10169
|
const source = sourceResult.ok ? sourceResult.value.source : null;
|
|
@@ -9832,10 +10183,11 @@ var status_default = defineCommand11({
|
|
|
9832
10183
|
lines.push(["Source", "unclaimed \xB7 next normal deploy defaults to DeepSpace"]);
|
|
9833
10184
|
json.source = null;
|
|
9834
10185
|
}
|
|
9835
|
-
const [refsResult, wsResult, releaseResult] = await Promise.all([
|
|
10186
|
+
const [refsResult, wsResult, releaseResult, appsResult] = await Promise.all([
|
|
9836
10187
|
githubSource ? Promise.resolve({ ok: true, value: null }) : observeRemote(api4.getRefs()),
|
|
9837
10188
|
facts.workspaceId && !githubSource ? observeRemote(api4.getWorkspace(facts.workspaceId).then((r) => r.view)) : Promise.resolve({ ok: true, value: null }),
|
|
9838
|
-
observeRemote(api4.latestRelease().then((r) => r.release))
|
|
10189
|
+
observeRemote(api4.latestRelease().then((r) => r.release)),
|
|
10190
|
+
observeRemote(listApps(deployBaseUrl(), token))
|
|
9839
10191
|
]);
|
|
9840
10192
|
if (facts.workspaceId) {
|
|
9841
10193
|
if (githubSource) {
|
|
@@ -9864,12 +10216,8 @@ var status_default = defineCommand11({
|
|
|
9864
10216
|
}
|
|
9865
10217
|
}
|
|
9866
10218
|
if (!releaseResult.ok) reportRemoteFailure2("Live", "live", releaseResult.error);
|
|
9867
|
-
else if (
|
|
9868
|
-
|
|
9869
|
-
json.live = null;
|
|
9870
|
-
} else {
|
|
9871
|
-
reportRelease2(releaseResult.value);
|
|
9872
|
-
}
|
|
10219
|
+
else if (!appsResult.ok) reportRemoteFailure2("Live", "live", appsResult.error);
|
|
10220
|
+
else reportLive2(releaseResult.value, appsResult.value.find((a) => a.appId === appId));
|
|
9873
10221
|
}
|
|
9874
10222
|
spinner2?.stop("Cloud state checked.");
|
|
9875
10223
|
}
|
|
@@ -9912,7 +10260,7 @@ function workspaceBranchPushRefusal(branch) {
|
|
|
9912
10260
|
var push_default = defineDeepspaceCommand({
|
|
9913
10261
|
meta: {
|
|
9914
10262
|
name: "push",
|
|
9915
|
-
description:
|
|
10263
|
+
description: `Push local git commits to the app's cloud repo (${PUSH_CEILINGS})`
|
|
9916
10264
|
},
|
|
9917
10265
|
args: {
|
|
9918
10266
|
branch: {
|
|
@@ -10493,6 +10841,27 @@ var clone_default = defineDeepspaceCommand({
|
|
|
10493
10841
|
|
|
10494
10842
|
// src/cli/commands/releases.ts
|
|
10495
10843
|
import * as p21 from "@clack/prompts";
|
|
10844
|
+
|
|
10845
|
+
// src/cli/lib/actor-labels.ts
|
|
10846
|
+
var API_URL9 = process.env.DEEPSPACE_API_URL ?? PLATFORM_URLS.api;
|
|
10847
|
+
async function actorLabels(token, appId) {
|
|
10848
|
+
const labels = /* @__PURE__ */ new Map();
|
|
10849
|
+
try {
|
|
10850
|
+
const { sub, email } = decodeJwtPayload(token);
|
|
10851
|
+
if (sub && email) labels.set(sub, `${email} (you)`);
|
|
10852
|
+
} catch {
|
|
10853
|
+
}
|
|
10854
|
+
try {
|
|
10855
|
+
const { collaborators } = await apiFetch(API_URL9, token, `/api/app-collaborators/${encodeURIComponent(appId)}`);
|
|
10856
|
+
for (const c of collaborators) {
|
|
10857
|
+
if (!labels.has(c.userId)) labels.set(c.userId, c.emailDisplay);
|
|
10858
|
+
}
|
|
10859
|
+
} catch {
|
|
10860
|
+
}
|
|
10861
|
+
return labels;
|
|
10862
|
+
}
|
|
10863
|
+
|
|
10864
|
+
// src/cli/commands/releases.ts
|
|
10496
10865
|
var DEPLOY_URL12 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
|
|
10497
10866
|
var releases_default = defineDeepspaceCommand({
|
|
10498
10867
|
meta: {
|
|
@@ -10535,11 +10904,12 @@ var releases_default = defineDeepspaceCommand({
|
|
|
10535
10904
|
if (releases.length === 0) {
|
|
10536
10905
|
p21.log.info("No releases yet \u2014 the history starts with the next `deepspace deploy`.");
|
|
10537
10906
|
} else {
|
|
10907
|
+
const actors = await actorLabels(token, appId);
|
|
10538
10908
|
for (const r of releases) {
|
|
10539
10909
|
const source = r.commitOid ? `commit ${r.commitOid.slice(0, 10)}` : "(no source recorded)";
|
|
10540
10910
|
const rollback = r.rollbackAvailable ? "rollback available" : "rollback unavailable";
|
|
10541
10911
|
console.log(
|
|
10542
|
-
`#${r.seq} ${r.id} ${r.kind.padEnd(8)} ${r.createdAt} ${r.actor} ${source} ${rollback}`
|
|
10912
|
+
`#${r.seq} ${r.id} ${r.kind.padEnd(8)} ${r.createdAt} ${actors.get(r.actor) ?? r.actor} ${source} ${rollback}`
|
|
10543
10913
|
);
|
|
10544
10914
|
}
|
|
10545
10915
|
p21.log.info(
|
|
@@ -10662,10 +11032,20 @@ Re-run with --allow-do-deletion to accept the data loss.`,
|
|
|
10662
11032
|
"invalid_response"
|
|
10663
11033
|
);
|
|
10664
11034
|
}
|
|
10665
|
-
|
|
11035
|
+
let edgePropagating = false;
|
|
11036
|
+
if (result.url) {
|
|
11037
|
+
spinner2?.message("Waiting for edge propagation...");
|
|
11038
|
+
edgePropagating = !await waitForLiveRelease(result.url, result.releaseStamp, 9e4);
|
|
11039
|
+
}
|
|
11040
|
+
spinner2?.stop(
|
|
11041
|
+
edgePropagating ? `Rolled back to ${result.rolledBackTo ?? releaseId} (edge propagation still in progress after 90s).` : `Rolled back to ${result.rolledBackTo ?? releaseId}.`
|
|
11042
|
+
);
|
|
10666
11043
|
const doClassGuard = result.doClassGuard === "unverified" ? "unverified" : void 0;
|
|
10667
11044
|
if (!args.json) {
|
|
10668
|
-
if (result.url)
|
|
11045
|
+
if (result.url) {
|
|
11046
|
+
if (edgePropagating) p22.log.warn(`URL: ${result.url} (accepted; serving not yet verified)`);
|
|
11047
|
+
else p22.log.success(`Live at: ${result.url}`);
|
|
11048
|
+
}
|
|
10669
11049
|
if (result.bundleRetained === false) {
|
|
10670
11050
|
p22.log.warn(
|
|
10671
11051
|
"The rollback is live, but its bundle was concurrently retired and is not available for a future rollback."
|
|
@@ -10689,6 +11069,7 @@ Re-run with --allow-do-deletion to accept the data loss.`,
|
|
|
10689
11069
|
url: result.url ?? null,
|
|
10690
11070
|
versionId: result.versionId ?? null,
|
|
10691
11071
|
wranglerEnv: wranglerEnv ?? null,
|
|
11072
|
+
...edgePropagating ? { edgePropagating: true } : {},
|
|
10692
11073
|
...doClassGuard ? { doClassGuard } : {}
|
|
10693
11074
|
}
|
|
10694
11075
|
};
|
|
@@ -11573,27 +11954,6 @@ var syncWorkspaceCommand = defineDeepspaceCommand({
|
|
|
11573
11954
|
|
|
11574
11955
|
// src/cli/commands/workspace/list.ts
|
|
11575
11956
|
import * as p28 from "@clack/prompts";
|
|
11576
|
-
|
|
11577
|
-
// src/cli/lib/actor-labels.ts
|
|
11578
|
-
var API_URL9 = process.env.DEEPSPACE_API_URL ?? PLATFORM_URLS.api;
|
|
11579
|
-
async function actorLabels(token, appId) {
|
|
11580
|
-
const labels = /* @__PURE__ */ new Map();
|
|
11581
|
-
try {
|
|
11582
|
-
const { sub, email } = decodeJwtPayload(token);
|
|
11583
|
-
if (sub && email) labels.set(sub, `${email} (you)`);
|
|
11584
|
-
} catch {
|
|
11585
|
-
}
|
|
11586
|
-
try {
|
|
11587
|
-
const { collaborators } = await apiFetch(API_URL9, token, `/api/app-collaborators/${encodeURIComponent(appId)}`);
|
|
11588
|
-
for (const c of collaborators) {
|
|
11589
|
-
if (!labels.has(c.userId)) labels.set(c.userId, c.emailDisplay);
|
|
11590
|
-
}
|
|
11591
|
-
} catch {
|
|
11592
|
-
}
|
|
11593
|
-
return labels;
|
|
11594
|
-
}
|
|
11595
|
-
|
|
11596
|
-
// src/cli/commands/workspace/list.ts
|
|
11597
11957
|
function withWorkspaceOverlaps(views, overlapsById) {
|
|
11598
11958
|
return views.map((view) => ({
|
|
11599
11959
|
...view,
|
|
@@ -13363,7 +13723,7 @@ function commandTree() {
|
|
|
13363
13723
|
return main.subCommands ?? {};
|
|
13364
13724
|
}
|
|
13365
13725
|
function unknownCommandMessage(unknown) {
|
|
13366
|
-
return `Unknown command: ${unknown.attemptedPath
|
|
13726
|
+
return `Unknown command: ${humanCommand(unknown.attemptedPath)} \u2014 did you mean \`${humanCommand(unknown.suggestion)}\`?` + (unknown.quotedToken ? " The whole command arrived as one quoted argument; pass each word separately." : "");
|
|
13367
13727
|
}
|
|
13368
13728
|
function assertKnownCommandPath(argv) {
|
|
13369
13729
|
const unknown = findUnknownCommand(argv, commandTree());
|
|
@@ -13372,7 +13732,7 @@ function assertKnownCommandPath(argv) {
|
|
|
13372
13732
|
`${unknownCommandMessage(unknown)}
|
|
13373
13733
|
Run \`${unknown.helpPath.join(" ")} --help\` for the command list.`
|
|
13374
13734
|
);
|
|
13375
|
-
printAction({ cwd: process.cwd(), argv: unknown.suggestion });
|
|
13735
|
+
if (unknown.executable) printAction({ cwd: process.cwd(), argv: unknown.suggestion });
|
|
13376
13736
|
process.exit(1);
|
|
13377
13737
|
}
|
|
13378
13738
|
var rawArgs = process.argv.slice(2);
|
|
@@ -13394,7 +13754,7 @@ if (rawArgs.includes("--json") && !wantsHelp) {
|
|
|
13394
13754
|
ok: false,
|
|
13395
13755
|
code: "unknown_command",
|
|
13396
13756
|
error: unknownCommandMessage(unknown),
|
|
13397
|
-
action: { cwd: process.cwd(), argv: unknown.suggestion }
|
|
13757
|
+
...unknown.executable ? { action: { cwd: process.cwd(), argv: unknown.suggestion } } : {}
|
|
13398
13758
|
})
|
|
13399
13759
|
);
|
|
13400
13760
|
process.exit(1);
|
|
@@ -13403,16 +13763,20 @@ if (rawArgs.includes("--json") && !wantsHelp) {
|
|
|
13403
13763
|
stopActiveSpinner();
|
|
13404
13764
|
const cittyCode = err instanceof Error && err.name === "CLIError" ? err.code : void 0;
|
|
13405
13765
|
const code = cittyCode === "EARG" ? "missing_argument" : cittyCode === "E_UNKNOWN_COMMAND" ? "unknown_command" : cittyCode === "E_NO_COMMAND" ? "no_command" : errorCode(err);
|
|
13406
|
-
const message = (err instanceof Error ? err.message : String(err))
|
|
13407
|
-
// eslint-disable-next-line no-control-regex
|
|
13408
|
-
/\u001b\[[0-9;]*m/g,
|
|
13409
|
-
""
|
|
13410
|
-
);
|
|
13766
|
+
const message = stripAnsi(err instanceof Error ? err.message : String(err));
|
|
13411
13767
|
console.log(JSON.stringify({ ok: false, error: message, ...code ? { code } : {} }));
|
|
13412
13768
|
process.exit(1);
|
|
13413
13769
|
});
|
|
13414
13770
|
} else {
|
|
13415
13771
|
assertKnownCommandPath(rawArgs);
|
|
13416
|
-
runMain(wrapCommandErrors(main)
|
|
13772
|
+
runMain(wrapCommandErrors(main), {
|
|
13773
|
+
showUsage: async (cmd, parent) => {
|
|
13774
|
+
try {
|
|
13775
|
+
console.log(forTerminal(await renderUsage(cmd, parent)) + "\n");
|
|
13776
|
+
} catch (error) {
|
|
13777
|
+
console.error(error);
|
|
13778
|
+
}
|
|
13779
|
+
}
|
|
13780
|
+
});
|
|
13417
13781
|
}
|
|
13418
13782
|
//# sourceMappingURL=cli.js.map
|