deepspace 0.13.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 +9 -0
- package/dist/cli.js +97 -7
- package/dist/cli.js.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +50 -5
- package/dist/server.js +95 -12
- package/dist/server.js.map +1 -1
- package/dist/worker.d.ts +46 -1
- package/dist/worker.js +95 -12
- package/dist/worker.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# deepspace
|
|
2
2
|
|
|
3
|
+
## 0.14.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Enforce the per-tier storage quota on app files. An app's file allocation had per-file, per-part and per-request ceilings but no admission against the owner's plan, so a free-tier app could hold 202 MiB against a 128 MiB limit with every upload reporting success and no surface reporting usage. One per-tier table now serves both storage allocations (the repo store and app files), and the shared files handler admits every write: the single-request upload before the put, a chunked upload against its declared total at init, and again against the object R2 actually assembled at complete — an over-limit assembly is deleted rather than left in the allocation. An upsert is charged only for the bytes it adds. The owner's tier caps the allocation whoever writes, so an app writing at runtime and its owner's CLI meet the same limit; a billing lookup that fails refuses writes rather than admitting unmetered storage, and leaves reads working. Refusals answer `storage_quota_exceeded` with the used and limit byte counts and name the recovery, and `deepspace app files list` now prints storage used against the limit.
|
|
8
|
+
- `deepspace deploy` and `deepspace rollback` now wait for the release they just published, not merely for the app to answer. Every upload carries a synthetic `/.well-known/deepspace/release.json` asset naming its own version, injected by the platform at upload time — so this holds for every app already deployed, including rollbacks of bundles that predate the change, with no app code and no redeploy. Cloudflare serves assets atomically with the version, so the CLI polls that path until the edge returns the release it shipped; without a stamp (an older platform, or a resumed activation) it falls back to the previous reachability probe. "Deployed!" previously landed 30–60 seconds before the edge agreed, which made any deploy-then-assert script flaky by construction.
|
|
9
|
+
|
|
10
|
+
Invites can now be accepted without the emailed link. `deepspace app collaborators invites` lists the invites waiting for your signed-in email and `deepspace app collaborators accept <app-id>` accepts one — the same authority the `/join` page enforces (the signed-in email must match the invited address), reachable from a terminal. Previously an invitee who had never signed in could reach a state with no way forward: signing in did not grant access, the CLI said it would, and only the emailed link could complete it. That CLI message now describes what actually happens.
|
|
11
|
+
|
|
3
12
|
## 0.13.0
|
|
4
13
|
|
|
5
14
|
### Minor Changes
|
package/dist/cli.js
CHANGED
|
@@ -3798,6 +3798,36 @@ import { resolve as resolve12 } from "path";
|
|
|
3798
3798
|
|
|
3799
3799
|
// src/cli/lib/edge-propagation.ts
|
|
3800
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
|
+
}
|
|
3801
3831
|
async function waitForEdgePropagation(url, timeoutMs) {
|
|
3802
3832
|
const deadline = Date.now() + timeoutMs;
|
|
3803
3833
|
let attempt = 0;
|
|
@@ -3840,6 +3870,13 @@ function planUploadParts(totalBytes, partSize) {
|
|
|
3840
3870
|
}
|
|
3841
3871
|
return parts;
|
|
3842
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
|
+
};
|
|
3843
3880
|
var MAX_DEPLOY_ASSET_FILE_BYTES = 25 * 1024 * 1024;
|
|
3844
3881
|
var DANGEROUS_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
3845
3882
|
"text/html",
|
|
@@ -6040,7 +6077,7 @@ var deploy_default = defineCommand3({
|
|
|
6040
6077
|
});
|
|
6041
6078
|
if (body.url) {
|
|
6042
6079
|
spinner2.message("Waiting for edge propagation...");
|
|
6043
|
-
const ready = await
|
|
6080
|
+
const ready = await waitForLiveRelease(body.url, body.releaseStamp, 9e4);
|
|
6044
6081
|
if (!ready) {
|
|
6045
6082
|
spinner2.stop("Deployed (edge propagation still in progress after 90s)");
|
|
6046
6083
|
p12.log.warn(
|
|
@@ -8458,8 +8495,14 @@ var list3 = defineDeepspaceCommand({
|
|
|
8458
8495
|
const more = limit < MAX_LIST_LIMIT ? "raise --limit or narrow with --prefix" : "narrow with --prefix";
|
|
8459
8496
|
if (result.truncated) console.log(`(truncated at ${limit} \u2014 ${more})`);
|
|
8460
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
|
+
}
|
|
8461
8504
|
}
|
|
8462
|
-
return { data: { appId, files, truncated: result.truncated } };
|
|
8505
|
+
return { data: { appId, files, truncated: result.truncated, storage: result.storage ?? null } };
|
|
8463
8506
|
}
|
|
8464
8507
|
});
|
|
8465
8508
|
var get = defineDeepspaceCommand({
|
|
@@ -8587,7 +8630,7 @@ var add = defineDeepspaceCommand({
|
|
|
8587
8630
|
}
|
|
8588
8631
|
if (!args.json) {
|
|
8589
8632
|
console.log(
|
|
8590
|
-
`\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}\`.`
|
|
8591
8634
|
);
|
|
8592
8635
|
}
|
|
8593
8636
|
return { data: { ...res } };
|
|
@@ -8656,9 +8699,56 @@ var cancel3 = defineDeepspaceCommand({
|
|
|
8656
8699
|
return { data: { cancelled: found } };
|
|
8657
8700
|
}
|
|
8658
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
|
+
});
|
|
8659
8749
|
var collaborators_default = defineCommand7({
|
|
8660
8750
|
meta: { name: "collaborators", description: "Manage who can deploy your app" },
|
|
8661
|
-
subCommands: { list: list4, add, remove, cancel: cancel3 }
|
|
8751
|
+
subCommands: { list: list4, add, remove, cancel: cancel3, invites, accept }
|
|
8662
8752
|
});
|
|
8663
8753
|
|
|
8664
8754
|
// src/cli/commands/transfer.ts
|
|
@@ -8743,7 +8833,7 @@ var status2 = defineDeepspaceCommand({
|
|
|
8743
8833
|
return { data: { app: app2, transfer } };
|
|
8744
8834
|
}
|
|
8745
8835
|
});
|
|
8746
|
-
var
|
|
8836
|
+
var accept2 = defineDeepspaceCommand({
|
|
8747
8837
|
meta: { name: "accept", description: "Accept a transfer offered to you" },
|
|
8748
8838
|
args: {
|
|
8749
8839
|
app: { type: "string", alias: "a", description: "App id of the offered app", required: true }
|
|
@@ -8784,7 +8874,7 @@ var cancel4 = defineDeepspaceCommand({
|
|
|
8784
8874
|
});
|
|
8785
8875
|
var transfer_default = defineCommand8({
|
|
8786
8876
|
meta: { name: "transfer", description: "Transfer app ownership to another user" },
|
|
8787
|
-
subCommands: { offer, status: status2, accept, cancel: cancel4 }
|
|
8877
|
+
subCommands: { offer, status: status2, accept: accept2, cancel: cancel4 }
|
|
8788
8878
|
});
|
|
8789
8879
|
|
|
8790
8880
|
// src/cli/commands/integrations.ts
|
|
@@ -10945,7 +11035,7 @@ Re-run with --allow-do-deletion to accept the data loss.`,
|
|
|
10945
11035
|
let edgePropagating = false;
|
|
10946
11036
|
if (result.url) {
|
|
10947
11037
|
spinner2?.message("Waiting for edge propagation...");
|
|
10948
|
-
edgePropagating = !await
|
|
11038
|
+
edgePropagating = !await waitForLiveRelease(result.url, result.releaseStamp, 9e4);
|
|
10949
11039
|
}
|
|
10950
11040
|
spinner2?.stop(
|
|
10951
11041
|
edgePropagating ? `Rolled back to ${result.rolledBackTo ?? releaseId} (edge propagation still in progress after 90s).` : `Rolled back to ${result.rolledBackTo ?? releaseId}.`
|