deepspace 0.10.1 → 0.10.2
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 +8 -0
- package/dist/chunk-T7V4GUIN.js +1638 -0
- package/dist/chunk-T7V4GUIN.js.map +1 -0
- package/dist/cli.js +731 -324
- package/dist/cli.js.map +1 -1
- package/dist/documentation-client-core.d.ts +18 -0
- package/dist/documentation-client-core.js +395 -0
- package/dist/documentation-client-core.js.map +1 -0
- package/dist/documentation-default-renderer.cjs +124 -0
- package/dist/documentation-react.d.ts +2 -0
- package/dist/documentation-react.js +35 -0
- package/dist/documentation-react.js.map +1 -0
- package/dist/documentation-runtime.js +71 -0
- package/dist/documentation-server-core.d.ts +11 -0
- package/dist/documentation-server-core.js +48 -0
- package/dist/documentation-server-core.js.map +1 -0
- package/dist/documentation.d.ts +366 -0
- package/dist/documentation.js +3953 -0
- package/dist/documentation.js.map +1 -0
- package/dist/feature-installer.js +145 -0
- package/dist/feature-installer.js.map +1 -1
- package/dist/index.d.ts +177 -1
- package/dist/index.js +133 -0
- package/dist/index.js.map +1 -1
- package/dist/public-BGRX_Cjd.d.ts +234 -0
- package/dist/schema.d.ts +186 -0
- package/dist/schema.js +610 -0
- package/dist/schema.js.map +1 -0
- package/dist/server.d.ts +83 -4
- package/dist/server.js +296 -1
- package/dist/server.js.map +1 -1
- package/dist/testing.d.ts +5 -8
- package/dist/testing.js +48 -14
- package/dist/testing.js.map +1 -1
- package/dist/worker.d.ts +249 -5
- package/dist/worker.js +1438 -19
- package/dist/worker.js.map +1 -1
- package/features/admin-page/src/admin-schema.ts +1 -1
- package/features/ai-chat/feature.json +2 -2
- package/features/ai-chat/src/ChatPanel.tsx +6 -11
- package/features/ai-chat/src/ai-chat-schema.ts +1 -2
- package/features/canvas/src/canvas-schema.ts +1 -1
- package/features/documentation/content/index.mdx +14 -0
- package/features/documentation/content/quickstart.mdx +12 -0
- package/features/documentation/documentation.json +18 -0
- package/features/documentation/feature.json +68 -0
- package/features/{docs → documents}/feature.json +27 -27
- package/features/{docs/src/DocsEditorPage.tsx → documents/src/DocumentsEditorPage.tsx} +74 -74
- package/features/{docs/src/DocsListPage.tsx → documents/src/DocumentsListPage.tsx} +102 -102
- package/features/{docs/src/DocsOutlinePanel.tsx → documents/src/DocumentsOutlinePanel.tsx} +9 -9
- package/features/{docs/src/DocsPresence.tsx → documents/src/DocumentsPresence.tsx} +18 -18
- package/features/{docs → documents}/src/InviteDialog.tsx +21 -21
- package/features/{docs → documents}/src/LibrarySidebar.tsx +25 -25
- package/features/documents/src/__tests__/documents-presence-access.test.ts +71 -0
- package/features/{docs/src/docs-library-types.ts → documents/src/documents-library-types.ts} +3 -3
- package/features/{docs/src/docs-schema.ts → documents/src/documents-schema.ts} +6 -6
- package/features/{docs/src/docs-ui.css → documents/src/documents-ui.css} +89 -89
- package/features/{docs → documents}/src/editor/DocEditorSurface.tsx +11 -11
- package/features/{docs/src/editor/DocsTiptapToolbar.tsx → documents/src/editor/DocumentsTiptapToolbar.tsx} +21 -21
- package/features/{docs → documents}/src/editor/useDocEditor.ts +4 -4
- package/features/{docs/src/use-docs-presence-access.ts → documents/src/use-documents-presence-access.ts} +51 -51
- package/features/file-attachments/src/attachments-schema.ts +1 -1
- package/features/items/src/items-schema.ts +1 -1
- package/features/leaderboard/src/leaderboard-schema.ts +1 -1
- package/features/messaging/src/ChatMultiPage.tsx +1 -1
- package/features/messaging/src/ChatPage.tsx +1 -1
- package/features/messaging/src/messaging-schema.ts +2 -2
- package/features/tasks/src/tasks-schema.ts +1 -1
- package/features/testing/src/test-schema.ts +2 -2
- package/package.json +26 -1
- package/features/docs/src/__tests__/docs-presence-access.test.ts +0 -71
package/dist/cli.js
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
// src/cli/cli.ts
|
|
4
4
|
import { defineCommand as defineCommand14, runMain, runCommand } from "citty";
|
|
5
5
|
import { sync as spawnSync8 } from "cross-spawn";
|
|
6
|
-
import { readFileSync as
|
|
7
|
-
import { dirname as dirname10, join as
|
|
6
|
+
import { readFileSync as readFileSync28, existsSync as existsSync26 } from "fs";
|
|
7
|
+
import { dirname as dirname10, join as join25 } from "path";
|
|
8
8
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
9
9
|
|
|
10
10
|
// src/cli/lib/spinner.ts
|
|
@@ -1372,7 +1372,8 @@ var ALLOWED_BINDING_TYPES = /* @__PURE__ */ new Set([
|
|
|
1372
1372
|
"queue",
|
|
1373
1373
|
"browser_rendering",
|
|
1374
1374
|
"analytics_engine",
|
|
1375
|
-
"hyperdrive"
|
|
1375
|
+
"hyperdrive",
|
|
1376
|
+
"ratelimit"
|
|
1376
1377
|
]);
|
|
1377
1378
|
var RESERVED_BINDING_NAMES = /* @__PURE__ */ new Set([
|
|
1378
1379
|
"ASSETS",
|
|
@@ -1380,6 +1381,7 @@ var RESERVED_BINDING_NAMES = /* @__PURE__ */ new Set([
|
|
|
1380
1381
|
"API_WORKER",
|
|
1381
1382
|
"DEEPSPACE_APP_ID",
|
|
1382
1383
|
"DEEPSPACE_RESOURCE_ID",
|
|
1384
|
+
"DEEPSPACE_RELEASE_OPERATION_ID",
|
|
1383
1385
|
"APP_NAME",
|
|
1384
1386
|
"OWNER_USER_ID",
|
|
1385
1387
|
"AUTH_JWT_PUBLIC_KEY",
|
|
@@ -1470,6 +1472,17 @@ function requiredFieldError(b) {
|
|
|
1470
1472
|
return `hyperdrive binding "${b.name}": auto-provisioning not yet supported (provide a real id)`;
|
|
1471
1473
|
}
|
|
1472
1474
|
return null;
|
|
1475
|
+
case "ratelimit":
|
|
1476
|
+
if (!/^\d+$/u.test(b.namespace_id) || Number(b.namespace_id) <= 0) {
|
|
1477
|
+
return `ratelimit binding "${b.name}" requires a positive integer namespace_id string`;
|
|
1478
|
+
}
|
|
1479
|
+
if (!Number.isInteger(b.simple?.limit) || b.simple.limit <= 0) {
|
|
1480
|
+
return `ratelimit binding "${b.name}" requires simple.limit (positive integer)`;
|
|
1481
|
+
}
|
|
1482
|
+
if (b.simple.period !== 10 && b.simple.period !== 60) {
|
|
1483
|
+
return `ratelimit binding "${b.name}" requires simple.period (10 or 60)`;
|
|
1484
|
+
}
|
|
1485
|
+
return null;
|
|
1473
1486
|
case "ai":
|
|
1474
1487
|
case "browser_rendering":
|
|
1475
1488
|
case "analytics_engine":
|
|
@@ -1547,6 +1560,15 @@ function bindingManifestFromOutputConfig(outputConfig) {
|
|
|
1547
1560
|
const id = pluckString(h, "id");
|
|
1548
1561
|
if (name && id) out.push({ type: "hyperdrive", name, id });
|
|
1549
1562
|
}
|
|
1563
|
+
for (const r of asObjectArray(outputConfig.ratelimits)) {
|
|
1564
|
+
const name = pluckString(r, "name");
|
|
1565
|
+
const namespace_id = pluckString(r, "namespace_id");
|
|
1566
|
+
const simple = isObject(r.simple) ? r.simple : null;
|
|
1567
|
+
const limit = pluckNumber(simple, "limit");
|
|
1568
|
+
const period = pluckNumber(simple, "period");
|
|
1569
|
+
if (!name || !namespace_id || limit === null || period !== 10 && period !== 60) continue;
|
|
1570
|
+
out.push({ type: "ratelimit", name, namespace_id, simple: { limit, period } });
|
|
1571
|
+
}
|
|
1550
1572
|
return out;
|
|
1551
1573
|
}
|
|
1552
1574
|
function isObject(v) {
|
|
@@ -1897,6 +1919,7 @@ var NON_INHERITABLE_ENV_KEYS = /* @__PURE__ */ new Set([
|
|
|
1897
1919
|
"r2_buckets",
|
|
1898
1920
|
"ai_search_namespaces",
|
|
1899
1921
|
"ai_search",
|
|
1922
|
+
"ratelimits",
|
|
1900
1923
|
"vectorize",
|
|
1901
1924
|
"services",
|
|
1902
1925
|
"queues",
|
|
@@ -1998,6 +2021,13 @@ function flattenWranglerEnvConfig(config, envName) {
|
|
|
1998
2021
|
for (const [key, value] of Object.entries(envBlock)) {
|
|
1999
2022
|
flattened[key] = value;
|
|
2000
2023
|
}
|
|
2024
|
+
if (!("durable_objects" in envBlock) && config.durable_objects) {
|
|
2025
|
+
flattened.durable_objects = config.durable_objects;
|
|
2026
|
+
}
|
|
2027
|
+
const envVars = asTomlRecord(envBlock.vars) ?? {};
|
|
2028
|
+
if (!("APP_NAME" in envVars) && typeof envBlock.name === "string") {
|
|
2029
|
+
flattened.vars = { ...envVars, APP_NAME: envBlock.name };
|
|
2030
|
+
}
|
|
2001
2031
|
return flattened;
|
|
2002
2032
|
}
|
|
2003
2033
|
function asTomlRecord(value) {
|
|
@@ -2532,6 +2562,9 @@ function noAppDirMessage(start, children) {
|
|
|
2532
2562
|
}
|
|
2533
2563
|
return lines.join("\n");
|
|
2534
2564
|
}
|
|
2565
|
+
function devExitSucceeded(code, stopping) {
|
|
2566
|
+
return stopping || code === null || code === 0;
|
|
2567
|
+
}
|
|
2535
2568
|
var dev_default = defineDeepspaceCommand({
|
|
2536
2569
|
meta: {
|
|
2537
2570
|
name: "dev",
|
|
@@ -2668,7 +2701,9 @@ Free it with \`${killCmd}\`, or start on another port: \`deepspace dev start --p
|
|
|
2668
2701
|
stdio: "inherit",
|
|
2669
2702
|
env: wranglerViteEnv(process.env, wranglerConfig, { DEEPSPACE_PORT: String(port) })
|
|
2670
2703
|
});
|
|
2704
|
+
let stopping = false;
|
|
2671
2705
|
const stop = () => {
|
|
2706
|
+
stopping = true;
|
|
2672
2707
|
wranglerConfig.cleanup();
|
|
2673
2708
|
vite.kill();
|
|
2674
2709
|
};
|
|
@@ -2680,7 +2715,9 @@ Free it with \`${killCmd}\`, or start on another port: \`deepspace dev start --p
|
|
|
2680
2715
|
res(c);
|
|
2681
2716
|
});
|
|
2682
2717
|
});
|
|
2683
|
-
|
|
2718
|
+
process.off("SIGINT", stop);
|
|
2719
|
+
process.off("SIGTERM", stop);
|
|
2720
|
+
if (!devExitSucceeded(code, stopping)) {
|
|
2684
2721
|
throw new Refusal(`Dev server exited with code ${code}.`, "dev_server_failed", {
|
|
2685
2722
|
extra: { port, appDir, exitCode: code }
|
|
2686
2723
|
});
|
|
@@ -3000,6 +3037,169 @@ function ensurePlaywright(appDir) {
|
|
|
3000
3037
|
}
|
|
3001
3038
|
}
|
|
3002
3039
|
|
|
3040
|
+
// src/cli/lib/test-account-service.ts
|
|
3041
|
+
import { readFileSync as readFileSync14 } from "fs";
|
|
3042
|
+
|
|
3043
|
+
// src/testing/accounts.ts
|
|
3044
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync5, readFileSync as readFileSync13, writeFileSync as writeFileSync7 } from "fs";
|
|
3045
|
+
import { homedir as homedir3 } from "os";
|
|
3046
|
+
import { join as join13 } from "path";
|
|
3047
|
+
var TEST_ACCOUNTS_PATH = join13(homedir3(), ".deepspace", "test-accounts.json");
|
|
3048
|
+
var PRODUCTION_AUTH_ORIGIN = "https://auth.deep.space";
|
|
3049
|
+
var STAGING_AUTH_ORIGIN = "https://auth.deepspacesites.com";
|
|
3050
|
+
function currentTestAccountScope(env = process.env) {
|
|
3051
|
+
const selected = env.DEEPSPACE_AUTH_URL ?? (env.DEEPSPACE_ENV === "staging" ? STAGING_AUTH_ORIGIN : PRODUCTION_AUTH_ORIGIN);
|
|
3052
|
+
return normalizeTestAccountScope(selected);
|
|
3053
|
+
}
|
|
3054
|
+
function normalizeTestAccountScope(value) {
|
|
3055
|
+
try {
|
|
3056
|
+
return new URL(value).origin;
|
|
3057
|
+
} catch {
|
|
3058
|
+
return value;
|
|
3059
|
+
}
|
|
3060
|
+
}
|
|
3061
|
+
function loadAllTestAccounts(scope = currentTestAccountScope()) {
|
|
3062
|
+
const store = readTestAccountStore();
|
|
3063
|
+
return mergeTestAccounts(store.scopes[scope] ?? [], store.unscoped);
|
|
3064
|
+
}
|
|
3065
|
+
function reconcileTestAccountStore(remote, scope = currentTestAccountScope()) {
|
|
3066
|
+
const result = reconcileTestAccountScopes(readTestAccountStore(), remote, scope);
|
|
3067
|
+
saveTestAccountStore(result.store);
|
|
3068
|
+
return { accounts: result.accounts, removed: result.removed };
|
|
3069
|
+
}
|
|
3070
|
+
function reconcileTestAccountScopes(store, remote, scope) {
|
|
3071
|
+
const scoped = store.scopes[scope] ?? [];
|
|
3072
|
+
const current = reconcileTestAccounts(scoped, remote);
|
|
3073
|
+
const migrated = reconcileTestAccounts(store.unscoped, remote);
|
|
3074
|
+
const accounts = mergeTestAccounts(current, migrated);
|
|
3075
|
+
return {
|
|
3076
|
+
accounts,
|
|
3077
|
+
removed: Math.max(0, scoped.length - current.length),
|
|
3078
|
+
store: {
|
|
3079
|
+
version: 2,
|
|
3080
|
+
scopes: { ...store.scopes, [scope]: accounts },
|
|
3081
|
+
unscoped: store.unscoped.filter((account) => !remote.some((item) => accountMatchesRemote(account, item)))
|
|
3082
|
+
}
|
|
3083
|
+
};
|
|
3084
|
+
}
|
|
3085
|
+
function reconcileTestAccounts(local, remote) {
|
|
3086
|
+
const localById = new Map(local.filter((account) => account.id).map((account) => [account.id, account]));
|
|
3087
|
+
const legacyByEmail = new Map(local.filter((account) => !account.id).map((account) => [account.email, account]));
|
|
3088
|
+
return remote.flatMap((account) => {
|
|
3089
|
+
const stored = localById.get(account.id) ?? legacyByEmail.get(account.email);
|
|
3090
|
+
return stored ? [{ ...stored, ...account }] : [];
|
|
3091
|
+
});
|
|
3092
|
+
}
|
|
3093
|
+
function upsertTestAccount(account, scope = currentTestAccountScope()) {
|
|
3094
|
+
const store = readTestAccountStore();
|
|
3095
|
+
const accounts = (store.scopes[scope] ?? []).filter(
|
|
3096
|
+
(stored) => stored.id !== account.id && stored.email !== account.email
|
|
3097
|
+
);
|
|
3098
|
+
saveTestAccountStore({
|
|
3099
|
+
version: 2,
|
|
3100
|
+
scopes: { ...store.scopes, [scope]: [...accounts, account] },
|
|
3101
|
+
unscoped: store.unscoped.filter(
|
|
3102
|
+
(stored) => stored.id !== account.id && stored.email !== account.email
|
|
3103
|
+
)
|
|
3104
|
+
});
|
|
3105
|
+
}
|
|
3106
|
+
function removeTestAccounts(ids, emails = [], scope = currentTestAccountScope()) {
|
|
3107
|
+
const idSet = new Set(ids);
|
|
3108
|
+
const emailSet = new Set(emails);
|
|
3109
|
+
const keep = (account) => !idSet.has(account.id ?? "") && !emailSet.has(account.email);
|
|
3110
|
+
const store = readTestAccountStore();
|
|
3111
|
+
saveTestAccountStore({
|
|
3112
|
+
version: 2,
|
|
3113
|
+
scopes: { ...store.scopes, [scope]: (store.scopes[scope] ?? []).filter(keep) },
|
|
3114
|
+
unscoped: store.unscoped.filter(keep)
|
|
3115
|
+
});
|
|
3116
|
+
}
|
|
3117
|
+
function readTestAccountStore() {
|
|
3118
|
+
if (!existsSync12(TEST_ACCOUNTS_PATH)) return { version: 2, scopes: {}, unscoped: [] };
|
|
3119
|
+
try {
|
|
3120
|
+
const raw = JSON.parse(readFileSync13(TEST_ACCOUNTS_PATH, "utf-8"));
|
|
3121
|
+
if (Array.isArray(raw)) return { version: 2, scopes: {}, unscoped: validTestAccounts(raw) };
|
|
3122
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
3123
|
+
return { version: 2, scopes: {}, unscoped: [] };
|
|
3124
|
+
}
|
|
3125
|
+
const candidate = raw;
|
|
3126
|
+
const scopes = candidate.scopes && typeof candidate.scopes === "object" && !Array.isArray(candidate.scopes) ? Object.fromEntries(Object.entries(candidate.scopes).map(([key, value]) => [key, validTestAccounts(value)])) : {};
|
|
3127
|
+
return { version: 2, scopes, unscoped: validTestAccounts(candidate.unscoped) };
|
|
3128
|
+
} catch {
|
|
3129
|
+
return { version: 2, scopes: {}, unscoped: [] };
|
|
3130
|
+
}
|
|
3131
|
+
}
|
|
3132
|
+
function validTestAccounts(value) {
|
|
3133
|
+
if (!Array.isArray(value)) return [];
|
|
3134
|
+
return value.filter((item) => Boolean(
|
|
3135
|
+
item && typeof item === "object" && typeof item.email === "string" && typeof item.password === "string"
|
|
3136
|
+
));
|
|
3137
|
+
}
|
|
3138
|
+
function mergeTestAccounts(...groups) {
|
|
3139
|
+
const accounts = /* @__PURE__ */ new Map();
|
|
3140
|
+
for (const account of groups.flat()) {
|
|
3141
|
+
const key = account.id ? `id:${account.id}` : `email:${account.email}`;
|
|
3142
|
+
if (!accounts.has(key)) accounts.set(key, account);
|
|
3143
|
+
}
|
|
3144
|
+
return [...accounts.values()];
|
|
3145
|
+
}
|
|
3146
|
+
function accountMatchesRemote(local, remote) {
|
|
3147
|
+
return local.id ? local.id === remote.id : local.email === remote.email;
|
|
3148
|
+
}
|
|
3149
|
+
function saveTestAccountStore(store) {
|
|
3150
|
+
mkdirSync5(join13(homedir3(), ".deepspace"), { recursive: true });
|
|
3151
|
+
writeFileSync7(TEST_ACCOUNTS_PATH, JSON.stringify(store, null, 2), { mode: 384 });
|
|
3152
|
+
}
|
|
3153
|
+
|
|
3154
|
+
// src/cli/lib/test-account-service.ts
|
|
3155
|
+
var SESSION_COOKIE2 = "__Secure-better-auth.session_token";
|
|
3156
|
+
var AUTH_URL4 = process.env.DEEPSPACE_AUTH_URL ?? PLATFORM_URLS.auth;
|
|
3157
|
+
function sessionCookie() {
|
|
3158
|
+
const token = readFileSync14(SESSION_PATH, "utf-8").trim();
|
|
3159
|
+
return `${SESSION_COOKIE2}=${encodeURIComponent(token)}`;
|
|
3160
|
+
}
|
|
3161
|
+
async function fetchRemoteTestAccounts() {
|
|
3162
|
+
const response = await fetch(`${AUTH_URL4}/api/auth/test-accounts`, {
|
|
3163
|
+
headers: { Cookie: sessionCookie(), Origin: AUTH_URL4 }
|
|
3164
|
+
});
|
|
3165
|
+
const data = await response.json().catch(() => ({}));
|
|
3166
|
+
if (!response.ok || !data.accounts) {
|
|
3167
|
+
throw new Error(data.error ?? "Failed to list test accounts");
|
|
3168
|
+
}
|
|
3169
|
+
return data.accounts;
|
|
3170
|
+
}
|
|
3171
|
+
async function createRemoteTestAccount(input) {
|
|
3172
|
+
const response = await fetch(`${AUTH_URL4}/api/auth/test-accounts`, {
|
|
3173
|
+
method: "POST",
|
|
3174
|
+
headers: {
|
|
3175
|
+
"Content-Type": "application/json",
|
|
3176
|
+
Cookie: sessionCookie(),
|
|
3177
|
+
Origin: AUTH_URL4
|
|
3178
|
+
},
|
|
3179
|
+
body: JSON.stringify(input)
|
|
3180
|
+
});
|
|
3181
|
+
const data = await response.json().catch(() => ({}));
|
|
3182
|
+
if (!response.ok || typeof data.id !== "string" || typeof data.email !== "string" || typeof data.userId !== "string" || typeof data.createdAt !== "number") {
|
|
3183
|
+
throw new Error(data.error ?? "Unknown error");
|
|
3184
|
+
}
|
|
3185
|
+
return { ...data, label: data.label ?? null };
|
|
3186
|
+
}
|
|
3187
|
+
async function deleteRemoteTestAccount(id) {
|
|
3188
|
+
const response = await fetch(`${AUTH_URL4}/api/auth/test-accounts/${id}`, {
|
|
3189
|
+
method: "DELETE",
|
|
3190
|
+
headers: { Cookie: sessionCookie(), Origin: AUTH_URL4 }
|
|
3191
|
+
});
|
|
3192
|
+
if (!response.ok) {
|
|
3193
|
+
const data = await response.json().catch(() => ({}));
|
|
3194
|
+
throw new Error(data.error ?? `DELETE returned ${response.status}`);
|
|
3195
|
+
}
|
|
3196
|
+
}
|
|
3197
|
+
async function syncTestAccountStore() {
|
|
3198
|
+
const accounts = await fetchRemoteTestAccounts();
|
|
3199
|
+
const { removed } = reconcileTestAccountStore(accounts, normalizeTestAccountScope(AUTH_URL4));
|
|
3200
|
+
return { accounts, removed };
|
|
3201
|
+
}
|
|
3202
|
+
|
|
3003
3203
|
// src/cli/commands/test.ts
|
|
3004
3204
|
var DEPLOY_URL2 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
|
|
3005
3205
|
var test_default = defineDeepspaceCommand({
|
|
@@ -3075,6 +3275,14 @@ var test_default = defineDeepspaceCommand({
|
|
|
3075
3275
|
generatedSecretsCache,
|
|
3076
3276
|
sharedDevVarsCache
|
|
3077
3277
|
});
|
|
3278
|
+
if (suite !== "unit") {
|
|
3279
|
+
try {
|
|
3280
|
+
const { removed } = await syncTestAccountStore();
|
|
3281
|
+
if (removed > 0) say(`Removed ${removed} stale test account credential(s).`);
|
|
3282
|
+
} catch (error) {
|
|
3283
|
+
say(`Warning: could not reconcile test accounts: ${error instanceof Error ? error.message : String(error)}`);
|
|
3284
|
+
}
|
|
3285
|
+
}
|
|
3078
3286
|
if (suite !== "unit") {
|
|
3079
3287
|
preflightWindowsWorkerd(appDir);
|
|
3080
3288
|
ensurePlaywright(appDir);
|
|
@@ -3226,49 +3434,6 @@ var screenshot_default = defineDeepspaceCommand({
|
|
|
3226
3434
|
// src/cli/commands/test-accounts.ts
|
|
3227
3435
|
import { defineCommand as defineCommand2 } from "citty";
|
|
3228
3436
|
import * as p5 from "@clack/prompts";
|
|
3229
|
-
import { readFileSync as readFileSync13, writeFileSync as writeFileSync7, existsSync as existsSync12, mkdirSync as mkdirSync5 } from "fs";
|
|
3230
|
-
import { join as join13 } from "path";
|
|
3231
|
-
import { homedir as homedir3 } from "os";
|
|
3232
|
-
var SESSION_COOKIE2 = "__Secure-better-auth.session_token";
|
|
3233
|
-
var AUTH_URL4 = process.env.DEEPSPACE_AUTH_URL ?? PLATFORM_URLS.auth;
|
|
3234
|
-
var DIR2 = join13(homedir3(), ".deepspace");
|
|
3235
|
-
var ACCOUNTS_PATH = join13(DIR2, "test-accounts.json");
|
|
3236
|
-
function loadAccounts() {
|
|
3237
|
-
if (!existsSync12(ACCOUNTS_PATH)) return [];
|
|
3238
|
-
try {
|
|
3239
|
-
return JSON.parse(readFileSync13(ACCOUNTS_PATH, "utf-8"));
|
|
3240
|
-
} catch {
|
|
3241
|
-
return [];
|
|
3242
|
-
}
|
|
3243
|
-
}
|
|
3244
|
-
function saveAccounts(accounts) {
|
|
3245
|
-
mkdirSync5(DIR2, { recursive: true });
|
|
3246
|
-
writeFileSync7(ACCOUNTS_PATH, JSON.stringify(accounts, null, 2), { mode: 384 });
|
|
3247
|
-
}
|
|
3248
|
-
function sessionCookie() {
|
|
3249
|
-
const token = readFileSync13(SESSION_PATH, "utf-8").trim();
|
|
3250
|
-
return `${SESSION_COOKIE2}=${encodeURIComponent(token)}`;
|
|
3251
|
-
}
|
|
3252
|
-
async function fetchRemoteAccounts() {
|
|
3253
|
-
const res = await fetch(`${AUTH_URL4}/api/auth/test-accounts`, {
|
|
3254
|
-
headers: { Cookie: sessionCookie(), Origin: AUTH_URL4 }
|
|
3255
|
-
});
|
|
3256
|
-
const data = await res.json().catch(() => ({}));
|
|
3257
|
-
if (!res.ok || !data.accounts) {
|
|
3258
|
-
throw new Error(data.error ?? "Failed to list test accounts");
|
|
3259
|
-
}
|
|
3260
|
-
return data.accounts;
|
|
3261
|
-
}
|
|
3262
|
-
async function deleteRemote(id) {
|
|
3263
|
-
const res = await fetch(`${AUTH_URL4}/api/auth/test-accounts/${id}`, {
|
|
3264
|
-
method: "DELETE",
|
|
3265
|
-
headers: { Cookie: sessionCookie(), Origin: AUTH_URL4 }
|
|
3266
|
-
});
|
|
3267
|
-
if (!res.ok) {
|
|
3268
|
-
const data = await res.json().catch(() => ({}));
|
|
3269
|
-
throw new Error(data.error ?? `DELETE returned ${res.status}`);
|
|
3270
|
-
}
|
|
3271
|
-
}
|
|
3272
3437
|
var create = defineDeepspaceCommand({
|
|
3273
3438
|
meta: {
|
|
3274
3439
|
name: "create",
|
|
@@ -3298,45 +3463,37 @@ var create = defineDeepspaceCommand({
|
|
|
3298
3463
|
},
|
|
3299
3464
|
async run({ args }) {
|
|
3300
3465
|
await ensureToken();
|
|
3301
|
-
const
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
}
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
})
|
|
3314
|
-
});
|
|
3315
|
-
const data = await res.json().catch(() => ({}));
|
|
3316
|
-
if (!res.ok || !data.id) {
|
|
3317
|
-
throw new Refusal(`Failed: ${data.error ?? "Unknown error"}`, "test_account_create_failed");
|
|
3466
|
+
const email = args.email;
|
|
3467
|
+
const password = args.password;
|
|
3468
|
+
const name = args.name;
|
|
3469
|
+
const label = args.label;
|
|
3470
|
+
let account;
|
|
3471
|
+
try {
|
|
3472
|
+
account = await createRemoteTestAccount({ email, password, name, label });
|
|
3473
|
+
} catch (error) {
|
|
3474
|
+
throw new Refusal(
|
|
3475
|
+
`Failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
3476
|
+
"test_account_create_failed"
|
|
3477
|
+
);
|
|
3318
3478
|
}
|
|
3319
|
-
|
|
3320
|
-
const accounts = loadAccounts();
|
|
3321
|
-
accounts.push({
|
|
3479
|
+
upsertTestAccount({
|
|
3322
3480
|
id: account.id,
|
|
3323
|
-
email
|
|
3324
|
-
password
|
|
3481
|
+
email,
|
|
3482
|
+
password,
|
|
3325
3483
|
userId: account.userId,
|
|
3326
|
-
name
|
|
3484
|
+
name,
|
|
3327
3485
|
label: account.label,
|
|
3328
3486
|
createdAt: account.createdAt
|
|
3329
3487
|
});
|
|
3330
|
-
saveAccounts(accounts);
|
|
3331
3488
|
if (!args.json) {
|
|
3332
3489
|
console.log(`Created test account:`);
|
|
3333
3490
|
console.log(` ID: ${account.id}`);
|
|
3334
3491
|
console.log(` Email: ${account.email}`);
|
|
3335
|
-
console.log(` Password: ${
|
|
3492
|
+
console.log(` Password: ${password}`);
|
|
3336
3493
|
console.log(` UserID: ${account.userId}`);
|
|
3337
3494
|
if (account.label) console.log(` Label: ${account.label}`);
|
|
3338
3495
|
console.log(`
|
|
3339
|
-
Saved to ${
|
|
3496
|
+
Saved to ${TEST_ACCOUNTS_PATH}`);
|
|
3340
3497
|
}
|
|
3341
3498
|
return {
|
|
3342
3499
|
data: {
|
|
@@ -3345,11 +3502,11 @@ Saved to ${ACCOUNTS_PATH}`);
|
|
|
3345
3502
|
// The password is already echoed on the human path and stored 0600 in
|
|
3346
3503
|
// ACCOUNTS_PATH — withholding it from --json would only force scripts
|
|
3347
3504
|
// to parse the file themselves.
|
|
3348
|
-
password
|
|
3505
|
+
password,
|
|
3349
3506
|
userId: account.userId,
|
|
3350
3507
|
label: account.label ?? null,
|
|
3351
3508
|
createdAt: account.createdAt,
|
|
3352
|
-
savedTo:
|
|
3509
|
+
savedTo: TEST_ACCOUNTS_PATH
|
|
3353
3510
|
}
|
|
3354
3511
|
};
|
|
3355
3512
|
}
|
|
@@ -3363,11 +3520,11 @@ var list = defineDeepspaceCommand({
|
|
|
3363
3520
|
await ensureToken();
|
|
3364
3521
|
let remote;
|
|
3365
3522
|
try {
|
|
3366
|
-
remote = await
|
|
3523
|
+
remote = (await syncTestAccountStore()).accounts;
|
|
3367
3524
|
} catch (err) {
|
|
3368
3525
|
throw new Refusal(`Failed: ${err.message}`, "test_accounts_list_failed");
|
|
3369
3526
|
}
|
|
3370
|
-
const local =
|
|
3527
|
+
const local = loadAllTestAccounts();
|
|
3371
3528
|
const localByEmail = new Map(local.map((a) => [a.email, a]));
|
|
3372
3529
|
if (remote.length === 0) {
|
|
3373
3530
|
if (!args.json) {
|
|
@@ -3438,7 +3595,7 @@ var del = defineDeepspaceCommand({
|
|
|
3438
3595
|
if (targetEmail && !targetId) {
|
|
3439
3596
|
let remote;
|
|
3440
3597
|
try {
|
|
3441
|
-
remote = await
|
|
3598
|
+
remote = await fetchRemoteTestAccounts();
|
|
3442
3599
|
} catch (err) {
|
|
3443
3600
|
throw new Refusal(`Failed: ${err.message}`, "test_accounts_list_failed");
|
|
3444
3601
|
}
|
|
@@ -3451,14 +3608,11 @@ var del = defineDeepspaceCommand({
|
|
|
3451
3608
|
targetId = match.id;
|
|
3452
3609
|
}
|
|
3453
3610
|
try {
|
|
3454
|
-
await
|
|
3611
|
+
await deleteRemoteTestAccount(targetId);
|
|
3455
3612
|
} catch (err) {
|
|
3456
3613
|
throw new Refusal(`Failed: ${err.message}`, "test_account_delete_failed");
|
|
3457
3614
|
}
|
|
3458
|
-
|
|
3459
|
-
(a) => a.id !== targetId && (!targetEmail || a.email !== targetEmail)
|
|
3460
|
-
);
|
|
3461
|
-
saveAccounts(accounts);
|
|
3615
|
+
removeTestAccounts([targetId], targetEmail ? [targetEmail] : []);
|
|
3462
3616
|
if (!args.json) {
|
|
3463
3617
|
console.log(`Test account deleted${targetEmail ? `: ${targetEmail}` : `: ${targetId}`}`);
|
|
3464
3618
|
}
|
|
@@ -3487,7 +3641,7 @@ var clear = defineDeepspaceCommand({
|
|
|
3487
3641
|
await ensureToken();
|
|
3488
3642
|
let remote;
|
|
3489
3643
|
try {
|
|
3490
|
-
remote = await
|
|
3644
|
+
remote = await fetchRemoteTestAccounts();
|
|
3491
3645
|
} catch (err) {
|
|
3492
3646
|
throw new Refusal(`Failed: ${err.message}`, "test_accounts_list_failed");
|
|
3493
3647
|
}
|
|
@@ -3518,16 +3672,14 @@ var clear = defineDeepspaceCommand({
|
|
|
3518
3672
|
const failures = [];
|
|
3519
3673
|
for (const a of targets) {
|
|
3520
3674
|
try {
|
|
3521
|
-
await
|
|
3675
|
+
await deleteRemoteTestAccount(a.id);
|
|
3522
3676
|
ok2++;
|
|
3523
3677
|
} catch (err) {
|
|
3524
3678
|
failures.push({ email: a.email, error: err.message });
|
|
3525
3679
|
}
|
|
3526
3680
|
}
|
|
3527
|
-
const
|
|
3528
|
-
|
|
3529
|
-
);
|
|
3530
|
-
saveAccounts(loadAccounts().filter((a) => !deletedIds.has(a.id)));
|
|
3681
|
+
const deleted = targets.filter((target) => !failures.some((failure) => failure.email === target.email));
|
|
3682
|
+
removeTestAccounts(deleted.map((target) => target.id), deleted.map((target) => target.email));
|
|
3531
3683
|
if (failures.length > 0) {
|
|
3532
3684
|
throw new Refusal(
|
|
3533
3685
|
`Deleted ${ok2}/${targets.length} test account(s).
|
|
@@ -3562,22 +3714,36 @@ import { resolve as resolve12 } from "path";
|
|
|
3562
3714
|
// src/cli/commands/deploy/build.ts
|
|
3563
3715
|
import * as p6 from "@clack/prompts";
|
|
3564
3716
|
import { execSync as execSync2 } from "child_process";
|
|
3565
|
-
import { existsSync as
|
|
3566
|
-
import { dirname as dirname5, join as
|
|
3717
|
+
import { existsSync as existsSync15, readFileSync as readFileSync17, readdirSync as readdirSync4 } from "fs";
|
|
3718
|
+
import { dirname as dirname5, join as join16, resolve as resolve10 } from "path";
|
|
3719
|
+
|
|
3720
|
+
// src/documentation/deploy.ts
|
|
3721
|
+
import { existsSync as existsSync13, readFileSync as readFileSync15 } from "fs";
|
|
3722
|
+
import { join as join14 } from "path";
|
|
3723
|
+
function readDocumentationDeployManifest(appDir, clientDir) {
|
|
3724
|
+
if (!existsSync13(join14(appDir, "documentation.json"))) return void 0;
|
|
3725
|
+
const manifestPath = join14(clientDir, "_documentation", "manifest.json");
|
|
3726
|
+
if (!existsSync13(manifestPath)) {
|
|
3727
|
+
throw new Error(
|
|
3728
|
+
"documentation.json exists but the build produced no documentation manifest. Ensure vite.config.ts includes deepSpaceDocumentation() from deepspace/documentation."
|
|
3729
|
+
);
|
|
3730
|
+
}
|
|
3731
|
+
return JSON.parse(readFileSync15(manifestPath, "utf8"));
|
|
3732
|
+
}
|
|
3567
3733
|
|
|
3568
3734
|
// src/cli/commands/migrate/app-migrations.ts
|
|
3569
3735
|
import {
|
|
3570
3736
|
closeSync,
|
|
3571
3737
|
constants,
|
|
3572
|
-
existsSync as
|
|
3738
|
+
existsSync as existsSync14,
|
|
3573
3739
|
fstatSync,
|
|
3574
3740
|
ftruncateSync,
|
|
3575
3741
|
lstatSync,
|
|
3576
3742
|
openSync,
|
|
3577
|
-
readFileSync as
|
|
3743
|
+
readFileSync as readFileSync16,
|
|
3578
3744
|
writeSync
|
|
3579
3745
|
} from "fs";
|
|
3580
|
-
import { join as
|
|
3746
|
+
import { join as join15 } from "path";
|
|
3581
3747
|
|
|
3582
3748
|
// src/shared/protocol/app-migrations.ts
|
|
3583
3749
|
var APP_MIGRATION_ID_RE = /^[a-z0-9][a-z0-9._-]{0,127}$/;
|
|
@@ -3622,8 +3788,8 @@ var APP_MIGRATION_DEFINITIONS = SOURCE_MIGRATIONS.map(
|
|
|
3622
3788
|
({ id, description }) => ({ id, description })
|
|
3623
3789
|
);
|
|
3624
3790
|
function readAppliedAppMigrations(appDir) {
|
|
3625
|
-
const path =
|
|
3626
|
-
if (!
|
|
3791
|
+
const path = join15(appDir, APP_MIGRATIONS_MANIFEST);
|
|
3792
|
+
if (!existsSync14(path)) return [];
|
|
3627
3793
|
const source = readRegularFile(path);
|
|
3628
3794
|
let parsed;
|
|
3629
3795
|
try {
|
|
@@ -3649,7 +3815,7 @@ function planAppMigrations(appDir) {
|
|
|
3649
3815
|
const edits = [];
|
|
3650
3816
|
for (const repoPath of tracked) {
|
|
3651
3817
|
if (!isSourcePath(repoPath, appPrefix)) continue;
|
|
3652
|
-
const absolutePath =
|
|
3818
|
+
const absolutePath = join15(repo, repoPath);
|
|
3653
3819
|
let stat;
|
|
3654
3820
|
try {
|
|
3655
3821
|
stat = lstatSync(absolutePath);
|
|
@@ -3683,8 +3849,8 @@ function planAppMigrations(appDir) {
|
|
|
3683
3849
|
});
|
|
3684
3850
|
if (pending.length > 0 && blockers.length === 0) {
|
|
3685
3851
|
const manifestPath = `${appPrefix}${APP_MIGRATIONS_MANIFEST}`;
|
|
3686
|
-
const absoluteManifestPath =
|
|
3687
|
-
const before =
|
|
3852
|
+
const absoluteManifestPath = join15(repo, manifestPath);
|
|
3853
|
+
const before = existsSync14(absoluteManifestPath) ? readRegularFile(absoluteManifestPath) : null;
|
|
3688
3854
|
const after = `${JSON.stringify([...appliedIds, ...pending.map(({ id }) => id)], null, 2)}
|
|
3689
3855
|
`;
|
|
3690
3856
|
if (before !== after) edits.push({ path: manifestPath, before, after });
|
|
@@ -3702,13 +3868,13 @@ function applyAppMigrationPlan(appDir, plan) {
|
|
|
3702
3868
|
}
|
|
3703
3869
|
const repo = repoToplevel(appDir);
|
|
3704
3870
|
for (const edit of plan.edits) {
|
|
3705
|
-
const absolutePath =
|
|
3706
|
-
const current =
|
|
3871
|
+
const absolutePath = join15(repo, edit.path);
|
|
3872
|
+
const current = existsSync14(absolutePath) ? readRegularFile(absolutePath) : null;
|
|
3707
3873
|
if (current !== edit.before) {
|
|
3708
3874
|
throw new Error(`Migration input changed after planning: ${edit.path}`);
|
|
3709
3875
|
}
|
|
3710
3876
|
}
|
|
3711
|
-
for (const edit of plan.edits) writeRegularFile(
|
|
3877
|
+
for (const edit of plan.edits) writeRegularFile(join15(repo, edit.path), edit.before, edit.after);
|
|
3712
3878
|
}
|
|
3713
3879
|
function readRegularFile(path) {
|
|
3714
3880
|
const before = lstatSync(path);
|
|
@@ -3722,7 +3888,7 @@ function readRegularFile(path) {
|
|
|
3722
3888
|
if (!opened.isFile() || opened.dev !== after.dev || opened.ino !== after.ino) {
|
|
3723
3889
|
throw new Error(`Migration input changed while opening: ${path}`);
|
|
3724
3890
|
}
|
|
3725
|
-
return
|
|
3891
|
+
return readFileSync16(fd, "utf-8");
|
|
3726
3892
|
} finally {
|
|
3727
3893
|
closeSync(fd);
|
|
3728
3894
|
}
|
|
@@ -3748,7 +3914,7 @@ function writeRegularFile(path, before, after) {
|
|
|
3748
3914
|
if (!opened.isFile() || opened.dev !== currentPath.dev || opened.ino !== currentPath.ino) {
|
|
3749
3915
|
throw new Error(`Migration input changed while opening: ${path}`);
|
|
3750
3916
|
}
|
|
3751
|
-
if (
|
|
3917
|
+
if (readFileSync16(fd, "utf-8") !== before) {
|
|
3752
3918
|
throw new Error(`Migration input changed after planning: ${path}`);
|
|
3753
3919
|
}
|
|
3754
3920
|
ftruncateSync(fd, 0);
|
|
@@ -3859,10 +4025,14 @@ var RESERVED_RUN_WORKER_FIRST = /* @__PURE__ */ new Set([
|
|
|
3859
4025
|
"/ws/*",
|
|
3860
4026
|
"/internal/*",
|
|
3861
4027
|
"/v1/*",
|
|
3862
|
-
"/_deepspace/*"
|
|
4028
|
+
"/_deepspace/*",
|
|
4029
|
+
"/_documentation",
|
|
4030
|
+
"/_documentation/*",
|
|
4031
|
+
"/_documentation-root",
|
|
4032
|
+
"/_documentation-root/*"
|
|
3863
4033
|
]);
|
|
3864
4034
|
async function buildDeployBundle(options) {
|
|
3865
|
-
const { appDir, appName, envName, sharedDevVarsCache,
|
|
4035
|
+
const { appDir, appName, envName, sharedDevVarsCache, output, spinner: spinner2 } = options;
|
|
3866
4036
|
const junk = removeMacosJunk(appDir);
|
|
3867
4037
|
if (junk > 0) p6.log.info(`Removed ${junk} macOS metadata file(s) (._*, .DS_Store)`);
|
|
3868
4038
|
const lintFindings = await lintProjectSchemas(appDir);
|
|
@@ -3875,10 +4045,15 @@ async function buildDeployBundle(options) {
|
|
|
3875
4045
|
preparedWranglerConfig = prepareWranglerEnvConfig(appDir, envName, {
|
|
3876
4046
|
sharedDevVarsCache
|
|
3877
4047
|
});
|
|
4048
|
+
const appDomain = DEEPSPACE_ENV === "staging" ? "spacestest.com" : "app.space";
|
|
3878
4049
|
execSync2("npx vite build", {
|
|
3879
4050
|
cwd: appDir,
|
|
3880
4051
|
stdio: "pipe",
|
|
3881
|
-
env:
|
|
4052
|
+
env: {
|
|
4053
|
+
...wranglerViteEnv(process.env, preparedWranglerConfig),
|
|
4054
|
+
// The Vite plugin's one documentation compile stamps release URLs.
|
|
4055
|
+
DEEPSPACE_DOCUMENTATION_BASE_URL: `https://${appName}.${appDomain}/docs`
|
|
4056
|
+
}
|
|
3882
4057
|
});
|
|
3883
4058
|
} catch (error) {
|
|
3884
4059
|
spinner2.stop("Build failed");
|
|
@@ -3889,19 +4064,19 @@ async function buildDeployBundle(options) {
|
|
|
3889
4064
|
preparedWranglerConfig?.cleanup();
|
|
3890
4065
|
}
|
|
3891
4066
|
spinner2.stop("Built");
|
|
3892
|
-
const deployConfigPath =
|
|
3893
|
-
if (!
|
|
4067
|
+
const deployConfigPath = join16(appDir, ".wrangler", "deploy", "config.json");
|
|
4068
|
+
if (!existsSync15(deployConfigPath)) {
|
|
3894
4069
|
output.die(
|
|
3895
4070
|
"Build output config not found at .wrangler/deploy/config.json",
|
|
3896
4071
|
"build_output_missing"
|
|
3897
4072
|
);
|
|
3898
4073
|
}
|
|
3899
|
-
const deployConfig = JSON.parse(
|
|
4074
|
+
const deployConfig = JSON.parse(readFileSync17(deployConfigPath, "utf-8"));
|
|
3900
4075
|
const outputWranglerPath = resolve10(dirname5(deployConfigPath), deployConfig.configPath);
|
|
3901
|
-
if (!
|
|
4076
|
+
if (!existsSync15(outputWranglerPath)) {
|
|
3902
4077
|
output.die(`Output wrangler.json not found at ${outputWranglerPath}`, "build_output_missing");
|
|
3903
4078
|
}
|
|
3904
|
-
const outputConfig = JSON.parse(
|
|
4079
|
+
const outputConfig = JSON.parse(readFileSync17(outputWranglerPath, "utf-8"));
|
|
3905
4080
|
if (outputConfig.name && outputConfig.name !== appName) {
|
|
3906
4081
|
const envHint = envName ? ` (--env ${envName})` : "";
|
|
3907
4082
|
output.die(
|
|
@@ -3910,18 +4085,25 @@ async function buildDeployBundle(options) {
|
|
|
3910
4085
|
);
|
|
3911
4086
|
}
|
|
3912
4087
|
const workerDir = dirname5(outputWranglerPath);
|
|
3913
|
-
const workerBundlePath =
|
|
4088
|
+
const workerBundlePath = join16(workerDir, outputConfig.main);
|
|
3914
4089
|
const clientDir = outputConfig.assets?.directory ? resolve10(workerDir, outputConfig.assets.directory) : null;
|
|
3915
|
-
if (!
|
|
4090
|
+
if (!existsSync15(workerBundlePath)) {
|
|
3916
4091
|
output.die(`Worker bundle not found at ${workerBundlePath}`, "build_output_missing");
|
|
3917
4092
|
}
|
|
3918
|
-
if (!clientDir || !
|
|
4093
|
+
if (!clientDir || !existsSync15(clientDir)) {
|
|
3919
4094
|
return output.die(`Client assets not found at ${clientDir}`, "build_output_missing");
|
|
3920
4095
|
}
|
|
4096
|
+
try {
|
|
4097
|
+
const manifest = readDocumentationDeployManifest(appDir, clientDir);
|
|
4098
|
+
if (manifest) p6.log.info(`Documentation: ${manifest.pageCount} page(s)`);
|
|
4099
|
+
} catch (error) {
|
|
4100
|
+
output.die(errorMessage(error), "documentation_build_failed");
|
|
4101
|
+
}
|
|
3921
4102
|
spinner2.start("Collecting assets...");
|
|
3922
4103
|
const assets = collectAssets(clientDir);
|
|
4104
|
+
const assetConfig = readDeployAssetConfig(clientDir);
|
|
3923
4105
|
spinner2.stop(`Collected ${assets.length} assets`);
|
|
3924
|
-
const workerJs =
|
|
4106
|
+
const workerJs = readFileSync17(workerBundlePath, "utf-8");
|
|
3925
4107
|
const doBindings = outputConfig.durable_objects?.bindings;
|
|
3926
4108
|
const sqliteClasses = new Set(
|
|
3927
4109
|
outputConfig.migrations?.flatMap((migration) => migration.new_sqlite_classes ?? []) ?? []
|
|
@@ -3946,7 +4128,7 @@ async function buildDeployBundle(options) {
|
|
|
3946
4128
|
`Custom bindings: ${customBindings.map((binding) => `${binding.name} (${binding.type})`).join(", ")}`
|
|
3947
4129
|
);
|
|
3948
4130
|
}
|
|
3949
|
-
const extraRoutes =
|
|
4131
|
+
const extraRoutes = resolveDeployRunWorkerFirst(outputConfig);
|
|
3950
4132
|
let appMigrations = [];
|
|
3951
4133
|
try {
|
|
3952
4134
|
appMigrations = readAppliedAppMigrations(appDir);
|
|
@@ -3955,6 +4137,7 @@ async function buildDeployBundle(options) {
|
|
|
3955
4137
|
}
|
|
3956
4138
|
return {
|
|
3957
4139
|
assets,
|
|
4140
|
+
assetConfig,
|
|
3958
4141
|
workerJs,
|
|
3959
4142
|
appMigrations,
|
|
3960
4143
|
doManifest,
|
|
@@ -3963,8 +4146,7 @@ async function buildDeployBundle(options) {
|
|
|
3963
4146
|
};
|
|
3964
4147
|
}
|
|
3965
4148
|
function extractRunWorkerFirst(config) {
|
|
3966
|
-
const raw = config.assets?.run_worker_first;
|
|
3967
|
-
if (!Array.isArray(raw)) return [];
|
|
4149
|
+
const raw = Array.isArray(config.assets?.run_worker_first) ? config.assets.run_worker_first : [];
|
|
3968
4150
|
const routes = [];
|
|
3969
4151
|
const seen = /* @__PURE__ */ new Set();
|
|
3970
4152
|
for (const entry of raw) {
|
|
@@ -3976,19 +4158,24 @@ function extractRunWorkerFirst(config) {
|
|
|
3976
4158
|
}
|
|
3977
4159
|
return routes;
|
|
3978
4160
|
}
|
|
4161
|
+
function resolveDeployRunWorkerFirst(config) {
|
|
4162
|
+
if (config.assets?.run_worker_first === true) return true;
|
|
4163
|
+
const routes = extractRunWorkerFirst(config);
|
|
4164
|
+
return routes;
|
|
4165
|
+
}
|
|
3979
4166
|
function collectAssets(dir) {
|
|
3980
4167
|
const assets = [];
|
|
3981
4168
|
const walk = (currentDir, prefix) => {
|
|
3982
4169
|
for (const entry of readdirSync4(currentDir, { withFileTypes: true })) {
|
|
3983
|
-
if (entry.name
|
|
3984
|
-
const fullPath =
|
|
4170
|
+
if (isDeployAssetControlFile(entry.name)) continue;
|
|
4171
|
+
const fullPath = join16(currentDir, entry.name);
|
|
3985
4172
|
const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
3986
4173
|
if (entry.isDirectory()) {
|
|
3987
4174
|
walk(fullPath, relativePath);
|
|
3988
4175
|
} else {
|
|
3989
4176
|
assets.push({
|
|
3990
4177
|
path: `/${relativePath}`,
|
|
3991
|
-
contentBase64:
|
|
4178
|
+
contentBase64: readFileSync17(fullPath).toString("base64")
|
|
3992
4179
|
});
|
|
3993
4180
|
}
|
|
3994
4181
|
}
|
|
@@ -3996,24 +4183,37 @@ function collectAssets(dir) {
|
|
|
3996
4183
|
walk(dir, "");
|
|
3997
4184
|
return assets;
|
|
3998
4185
|
}
|
|
4186
|
+
function readDeployAssetConfig(clientDir) {
|
|
4187
|
+
const config = {};
|
|
4188
|
+
for (const [file, key] of [["_headers", "_headers"], ["_redirects", "_redirects"]]) {
|
|
4189
|
+
const filePath = join16(clientDir, file);
|
|
4190
|
+
if (!existsSync15(filePath)) continue;
|
|
4191
|
+
const content = readFileSync17(filePath, "utf8");
|
|
4192
|
+
if (content.trim()) config[key] = content;
|
|
4193
|
+
}
|
|
4194
|
+
return config;
|
|
4195
|
+
}
|
|
4196
|
+
function isDeployAssetControlFile(name) {
|
|
4197
|
+
return name === ".assetsignore" || name === "_headers" || name === "_redirects";
|
|
4198
|
+
}
|
|
3999
4199
|
function errorMessage(error) {
|
|
4000
4200
|
return error instanceof Error ? error.message : String(error);
|
|
4001
4201
|
}
|
|
4002
4202
|
|
|
4003
4203
|
// src/cli/commands/deploy/commerce.ts
|
|
4004
4204
|
import * as p7 from "@clack/prompts";
|
|
4005
|
-
import { existsSync as
|
|
4006
|
-
import { join as
|
|
4205
|
+
import { existsSync as existsSync16 } from "fs";
|
|
4206
|
+
import { join as join17 } from "path";
|
|
4007
4207
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
4008
4208
|
var API_URL2 = process.env.DEEPSPACE_API_URL ?? PLATFORM_URLS.api;
|
|
4009
4209
|
function errorMessage2(error) {
|
|
4010
4210
|
return error instanceof Error ? error.message : String(error);
|
|
4011
4211
|
}
|
|
4012
4212
|
async function loadDeclaration(appDir, sourceFile, outputFile, exportName) {
|
|
4013
|
-
const sourcePath =
|
|
4014
|
-
if (!
|
|
4213
|
+
const sourcePath = join17(appDir, "src", sourceFile);
|
|
4214
|
+
if (!existsSync16(sourcePath)) return void 0;
|
|
4015
4215
|
const esbuild = await import("esbuild");
|
|
4016
|
-
const outputPath =
|
|
4216
|
+
const outputPath = join17(appDir, ".wrangler", "deploy", outputFile);
|
|
4017
4217
|
await esbuild.build({
|
|
4018
4218
|
entryPoints: [sourcePath],
|
|
4019
4219
|
bundle: true,
|
|
@@ -4106,7 +4306,7 @@ Stripe will keep charging them until you cancel. Cancel at the end of their curr
|
|
|
4106
4306
|
}
|
|
4107
4307
|
}
|
|
4108
4308
|
async function syncSubscriptionPlans(appDir, appName, token, nonInteractive) {
|
|
4109
|
-
if (!
|
|
4309
|
+
if (!existsSync16(join17(appDir, "src", "subscriptions.ts"))) return;
|
|
4110
4310
|
let plans;
|
|
4111
4311
|
try {
|
|
4112
4312
|
plans = await loadDeclaration(
|
|
@@ -4161,7 +4361,7 @@ async function syncSubscriptionPlans(appDir, appName, token, nonInteractive) {
|
|
|
4161
4361
|
}
|
|
4162
4362
|
}
|
|
4163
4363
|
async function syncOneTimeProducts(appDir, appName, token) {
|
|
4164
|
-
if (!
|
|
4364
|
+
if (!existsSync16(join17(appDir, "src", "products.ts"))) return;
|
|
4165
4365
|
let products;
|
|
4166
4366
|
try {
|
|
4167
4367
|
products = await loadDeclaration(
|
|
@@ -4453,10 +4653,22 @@ function repoApi(deployUrl, token, appId) {
|
|
|
4453
4653
|
}
|
|
4454
4654
|
|
|
4455
4655
|
// src/cli/lib/vc-remote.ts
|
|
4456
|
-
import { existsSync as
|
|
4656
|
+
import { existsSync as existsSync17 } from "fs";
|
|
4457
4657
|
import { tmpdir } from "os";
|
|
4458
4658
|
import { isAbsolute as isAbsolute3, relative, resolve as resolve11 } from "path";
|
|
4459
|
-
|
|
4659
|
+
function spaceRemoteName(environment = DEEPSPACE_ENV) {
|
|
4660
|
+
if (environment === "staging") return "space-staging";
|
|
4661
|
+
if (environment === "production") return "space";
|
|
4662
|
+
return "space-invalid";
|
|
4663
|
+
}
|
|
4664
|
+
var SPACE_REMOTE = spaceRemoteName();
|
|
4665
|
+
function spaceTrackingRef(branch, remote = SPACE_REMOTE) {
|
|
4666
|
+
return `refs/remotes/${remote}/${branch}`;
|
|
4667
|
+
}
|
|
4668
|
+
function spacePrivateRef(path, environment = DEEPSPACE_ENV) {
|
|
4669
|
+
const root = environment === "production" ? "refs/deepspace" : `refs/deepspace/${environment}`;
|
|
4670
|
+
return `${root}/${path}`;
|
|
4671
|
+
}
|
|
4460
4672
|
function deployBaseUrl() {
|
|
4461
4673
|
return process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
|
|
4462
4674
|
}
|
|
@@ -4493,13 +4705,16 @@ function entryIsTransient(cwd) {
|
|
|
4493
4705
|
return rel === "" || !rel.startsWith("..") && !isAbsolute3(rel);
|
|
4494
4706
|
}
|
|
4495
4707
|
function helperEntryUsable(command) {
|
|
4496
|
-
const match = /^!'([^']*)' '([^']*)' git-credential$/.exec(command);
|
|
4497
|
-
|
|
4708
|
+
const match = /^!(?:DEEPSPACE_ENV=(production|staging) )?'([^']*)' '([^']*)' git-credential$/.exec(command);
|
|
4709
|
+
const expectedEnvironment = DEEPSPACE_ENV === "production" ? void 0 : DEEPSPACE_ENV;
|
|
4710
|
+
if (!match || match[1] !== expectedEnvironment) return false;
|
|
4711
|
+
return existsSync17(match[2]) && existsSync17(match[3]);
|
|
4498
4712
|
}
|
|
4499
|
-
function credentialHelperCommand() {
|
|
4713
|
+
function credentialHelperCommand(environment = DEEPSPACE_ENV) {
|
|
4500
4714
|
const entry = process.argv[1];
|
|
4501
4715
|
if (!entry) throw new Error("CLI entry path is unavailable");
|
|
4502
|
-
|
|
4716
|
+
const environmentPrefix = environment === "staging" ? "DEEPSPACE_ENV=staging " : "";
|
|
4717
|
+
return `!${environmentPrefix}${shQuote(process.execPath)} ${shQuote(entry)} git-credential`;
|
|
4503
4718
|
}
|
|
4504
4719
|
function installCredentialHelper(cwd, url) {
|
|
4505
4720
|
try {
|
|
@@ -4538,22 +4753,22 @@ function installCredentialHelper(cwd, url) {
|
|
|
4538
4753
|
} catch {
|
|
4539
4754
|
}
|
|
4540
4755
|
}
|
|
4541
|
-
function ensureSpaceRemote(cwd, appId) {
|
|
4756
|
+
function ensureSpaceRemote(cwd, appId, remote = SPACE_REMOTE) {
|
|
4542
4757
|
const url = repoUrl(appId);
|
|
4543
|
-
const current = runGit(cwd, ["remote", "get-url",
|
|
4758
|
+
const current = runGit(cwd, ["remote", "get-url", remote], { allowFail: true });
|
|
4544
4759
|
if (current.status !== 0) {
|
|
4545
|
-
runGit(cwd, ["remote", "add",
|
|
4760
|
+
runGit(cwd, ["remote", "add", remote, url]);
|
|
4546
4761
|
} else {
|
|
4547
4762
|
const existing = current.stdout.toString("utf-8").trim();
|
|
4548
4763
|
if (existing !== url) {
|
|
4549
4764
|
const priorApp = appIdFromRepoUrl(existing);
|
|
4550
4765
|
if (priorApp && priorApp !== appId && !process.argv.includes("--json")) {
|
|
4551
4766
|
process.stderr.write(
|
|
4552
|
-
`warning: remote '${
|
|
4767
|
+
`warning: remote '${remote}' was pointed at app ${priorApp}; re-aiming it at ${appId}.
|
|
4553
4768
|
`
|
|
4554
4769
|
);
|
|
4555
4770
|
}
|
|
4556
|
-
runGit(cwd, ["remote", "set-url",
|
|
4771
|
+
runGit(cwd, ["remote", "set-url", remote, url]);
|
|
4557
4772
|
}
|
|
4558
4773
|
}
|
|
4559
4774
|
installCredentialHelper(cwd, url);
|
|
@@ -4628,7 +4843,7 @@ function pushToSpace(cwd, token, refspec, opts = {}) {
|
|
|
4628
4843
|
const result = runGitRemote(
|
|
4629
4844
|
cwd,
|
|
4630
4845
|
token,
|
|
4631
|
-
["push", "--porcelain", ...opts.force ? ["--force"] : [], ...extra, SPACE_REMOTE, refspec],
|
|
4846
|
+
["push", "--porcelain", ...opts.force ? ["--force"] : [], ...extra, opts.remote ?? SPACE_REMOTE, refspec],
|
|
4632
4847
|
{ allowFail: true }
|
|
4633
4848
|
);
|
|
4634
4849
|
const parsed = parsePushPorcelain(result.stdout.toString("utf-8"));
|
|
@@ -4811,7 +5026,8 @@ async function syncDeployRepository(options) {
|
|
|
4811
5026
|
"source_unclaimed"
|
|
4812
5027
|
);
|
|
4813
5028
|
}
|
|
4814
|
-
|
|
5029
|
+
const sourceRemote = spaceRemoteName();
|
|
5030
|
+
ensureSpaceRemote(appDir, appId, sourceRemote);
|
|
4815
5031
|
const branch = currentBranch(appDir);
|
|
4816
5032
|
const workspaceBranchId = workspaceIdFromBranch(branch);
|
|
4817
5033
|
if (!isWorkTreeClean(appDir)) {
|
|
@@ -4855,7 +5071,9 @@ async function syncDeployRepository(options) {
|
|
|
4855
5071
|
);
|
|
4856
5072
|
} else {
|
|
4857
5073
|
const pushResult = await pushWithTransientRetry(
|
|
4858
|
-
() => pushToSpace(appDir, token, `refs/heads/${branch}:refs/heads/${branch}
|
|
5074
|
+
() => pushToSpace(appDir, token, `refs/heads/${branch}:refs/heads/${branch}`, {
|
|
5075
|
+
remote: sourceRemote
|
|
5076
|
+
})
|
|
4859
5077
|
);
|
|
4860
5078
|
if (pushResult.status === "committed" || pushResult.status === "up_to_date") {
|
|
4861
5079
|
recoverable = true;
|
|
@@ -4868,7 +5086,7 @@ async function syncDeployRepository(options) {
|
|
|
4868
5086
|
"vc_push_rejected"
|
|
4869
5087
|
);
|
|
4870
5088
|
} else {
|
|
4871
|
-
const remoteState = classifyRemoteState(appDir, token, branch, tip);
|
|
5089
|
+
const remoteState = classifyRemoteState(appDir, token, branch, tip, sourceRemote);
|
|
4872
5090
|
if (remoteState.strictlyBehind && !ignoreStale) {
|
|
4873
5091
|
let behind = "several";
|
|
4874
5092
|
try {
|
|
@@ -4913,16 +5131,17 @@ async function syncDeployRepository(options) {
|
|
|
4913
5131
|
}
|
|
4914
5132
|
return { commitOid, recoverable, deployKey, source, sourceRevision, baseReleaseId };
|
|
4915
5133
|
}
|
|
4916
|
-
function classifyRemoteState(appDir, token, branch, localTip) {
|
|
5134
|
+
function classifyRemoteState(appDir, token, branch, localTip, remote) {
|
|
4917
5135
|
let remoteTip = null;
|
|
5136
|
+
const remoteRef = `refs/remotes/${remote}/${branch}`;
|
|
4918
5137
|
try {
|
|
4919
5138
|
runGitRemote(appDir, token, [
|
|
4920
5139
|
"fetch",
|
|
4921
5140
|
"--quiet",
|
|
4922
|
-
|
|
4923
|
-
`+refs/heads/${branch}
|
|
5141
|
+
remote,
|
|
5142
|
+
`+refs/heads/${branch}:${remoteRef}`
|
|
4924
5143
|
]);
|
|
4925
|
-
remoteTip = resolveCommit(appDir,
|
|
5144
|
+
remoteTip = resolveCommit(appDir, remoteRef);
|
|
4926
5145
|
return {
|
|
4927
5146
|
remoteTip,
|
|
4928
5147
|
strictlyBehind: remoteTip !== null && remoteTip !== localTip && isAncestor(appDir, localTip, remoteTip)
|
|
@@ -5004,7 +5223,9 @@ async function deployBuiltBundle(options) {
|
|
|
5004
5223
|
spinner: spinner2
|
|
5005
5224
|
} = options;
|
|
5006
5225
|
spinner2.start(`Deploying ${appName}...`);
|
|
5007
|
-
if (bundle.extraRoutes
|
|
5226
|
+
if (bundle.extraRoutes === true) {
|
|
5227
|
+
p10.log.info("Worker-first routing: all requests");
|
|
5228
|
+
} else if (bundle.extraRoutes.length) {
|
|
5008
5229
|
p10.log.info(`Custom worker-first routes: ${bundle.extraRoutes.join(", ")}`);
|
|
5009
5230
|
}
|
|
5010
5231
|
const assetGroups = packAssetGroups(bundle.assets, GROUP_BYTES);
|
|
@@ -5074,9 +5295,12 @@ async function deployBuiltBundle(options) {
|
|
|
5074
5295
|
form.append("bindingManifest", JSON.stringify(bundle.customBindings));
|
|
5075
5296
|
}
|
|
5076
5297
|
if (secrets.names.length) form.append("userSecrets", JSON.stringify(secrets.values));
|
|
5077
|
-
if (bundle.extraRoutes.length) {
|
|
5298
|
+
if (bundle.extraRoutes === true || bundle.extraRoutes.length) {
|
|
5078
5299
|
form.append("extraRunWorkerFirst", JSON.stringify(bundle.extraRoutes));
|
|
5079
5300
|
}
|
|
5301
|
+
if (Object.keys(bundle.assetConfig).length) {
|
|
5302
|
+
form.append("assetConfig", JSON.stringify(bundle.assetConfig));
|
|
5303
|
+
}
|
|
5080
5304
|
form.append("name", appName);
|
|
5081
5305
|
if (confirmRename) form.append("confirmRename", "true");
|
|
5082
5306
|
if (shouldSendLineage(repository.commitOid, repository.recoverable)) {
|
|
@@ -5115,11 +5339,6 @@ async function deployBuiltBundle(options) {
|
|
|
5115
5339
|
throw error;
|
|
5116
5340
|
}
|
|
5117
5341
|
let body = await response.json().catch(() => ({}));
|
|
5118
|
-
for (let attempt = 0; response.status === 503 && body.code === "release_finalization_pending" && attempt < 3; attempt++) {
|
|
5119
|
-
await new Promise((resolve19) => setTimeout(resolve19, 250 * 2 ** attempt));
|
|
5120
|
-
response = await postCommit();
|
|
5121
|
-
body = await response.json().catch(() => ({}));
|
|
5122
|
-
}
|
|
5123
5342
|
if (response.status === 409 && body.code === "rename_required" && !confirmRename) {
|
|
5124
5343
|
spinner2.stop("Rename confirmation needed");
|
|
5125
5344
|
if (output.nonInteractive) {
|
|
@@ -5234,7 +5453,7 @@ async function postWithRetry(url, makeInit, {
|
|
|
5234
5453
|
|
|
5235
5454
|
// src/cli/commands/deploy/secrets.ts
|
|
5236
5455
|
import * as p11 from "@clack/prompts";
|
|
5237
|
-
import { existsSync as
|
|
5456
|
+
import { existsSync as existsSync18, readFileSync as readFileSync18 } from "fs";
|
|
5238
5457
|
function classifyDevVarsSecrets(options) {
|
|
5239
5458
|
const store = new Set(options.storeSecretNames);
|
|
5240
5459
|
const strayKeys = options.handEditedDevVarKeys.filter((key) => !store.has(key));
|
|
@@ -5332,8 +5551,8 @@ function prepareDeploySecrets(options) {
|
|
|
5332
5551
|
return { values, names };
|
|
5333
5552
|
}
|
|
5334
5553
|
function readCustomDevVars(path, output) {
|
|
5335
|
-
if (!
|
|
5336
|
-
const section = extractCustomDevVars(stripGeneratedSecretsCache(
|
|
5554
|
+
if (!existsSync18(path)) return {};
|
|
5555
|
+
const section = extractCustomDevVars(stripGeneratedSecretsCache(readFileSync18(path, "utf-8")));
|
|
5337
5556
|
if (!section) return {};
|
|
5338
5557
|
try {
|
|
5339
5558
|
return parseDevVars(section);
|
|
@@ -5502,7 +5721,6 @@ var deploy_default = defineCommand3({
|
|
|
5502
5721
|
appName,
|
|
5503
5722
|
envName,
|
|
5504
5723
|
sharedDevVarsCache: secretsCache.linked !== null,
|
|
5505
|
-
wranglerConfig,
|
|
5506
5724
|
output,
|
|
5507
5725
|
spinner: spinner2
|
|
5508
5726
|
});
|
|
@@ -5684,18 +5902,15 @@ async function resolveAppSelector(deployUrl, token, selector) {
|
|
|
5684
5902
|
"app_not_found"
|
|
5685
5903
|
);
|
|
5686
5904
|
}
|
|
5687
|
-
async function resolveAppTarget(deployUrl, token, explicit) {
|
|
5905
|
+
async function resolveAppTarget(deployUrl, token, explicit, options = {}) {
|
|
5906
|
+
assertAppTargetResolvable(explicit, options);
|
|
5688
5907
|
const { app: app2, error } = parseAppArg(explicit);
|
|
5689
5908
|
if (error) throw new InputError(error, "invalid_app");
|
|
5690
5909
|
if (app2 !== void 0) return resolveAppSelector(deployUrl, token, app2);
|
|
5910
|
+
const { wranglerEnv } = parseWranglerEnvArg(options.wranglerEnv);
|
|
5691
5911
|
const appDir = findAppDir();
|
|
5692
|
-
const id = appDir ? readAppId(appDir) : null;
|
|
5693
|
-
if (!id)
|
|
5694
|
-
throw new InputError(
|
|
5695
|
-
"No app id. Run from an app directory whose wrangler.toml carries DEEPSPACE_APP_ID, or pass --app <id or name>.",
|
|
5696
|
-
"not_in_app_repo"
|
|
5697
|
-
);
|
|
5698
|
-
}
|
|
5912
|
+
const id = appDir ? readAppId(appDir, wranglerEnv) : null;
|
|
5913
|
+
if (!id) throw appTargetMissingError(wranglerEnv);
|
|
5699
5914
|
return id;
|
|
5700
5915
|
}
|
|
5701
5916
|
function parseAppArg(raw) {
|
|
@@ -5721,17 +5936,42 @@ function parseAppArg(raw) {
|
|
|
5721
5936
|
}
|
|
5722
5937
|
return { app: selector };
|
|
5723
5938
|
}
|
|
5724
|
-
function
|
|
5939
|
+
function parseWranglerEnvArg(raw) {
|
|
5940
|
+
if (raw === void 0) return {};
|
|
5941
|
+
const wranglerEnv = raw.trim();
|
|
5942
|
+
if (!wranglerEnv) {
|
|
5943
|
+
return {
|
|
5944
|
+
error: "--env was given an empty environment name \u2014 pass a wrangler.toml environment name, or omit --env to use the top-level app."
|
|
5945
|
+
};
|
|
5946
|
+
}
|
|
5947
|
+
return { wranglerEnv };
|
|
5948
|
+
}
|
|
5949
|
+
function appTargetMissingError(wranglerEnv) {
|
|
5950
|
+
if (wranglerEnv) {
|
|
5951
|
+
return new InputError(
|
|
5952
|
+
`No app id for env "${wranglerEnv}" \u2014 wrangler.toml has no [env.${wranglerEnv}] block with its own DEEPSPACE_APP_ID.`,
|
|
5953
|
+
"no_app_id_for_env"
|
|
5954
|
+
);
|
|
5955
|
+
}
|
|
5956
|
+
return new InputError(
|
|
5957
|
+
"No app id. Run from an app directory whose wrangler.toml carries DEEPSPACE_APP_ID, or pass --app <id or name>.",
|
|
5958
|
+
"not_in_app_repo"
|
|
5959
|
+
);
|
|
5960
|
+
}
|
|
5961
|
+
function assertAppTargetResolvable(appArg, options = {}) {
|
|
5725
5962
|
const { app: app2, error } = parseAppArg(appArg);
|
|
5726
5963
|
if (error) throw new InputError(error, "invalid_app");
|
|
5727
|
-
|
|
5728
|
-
|
|
5729
|
-
if (
|
|
5964
|
+
const { wranglerEnv, error: envError } = parseWranglerEnvArg(options.wranglerEnv);
|
|
5965
|
+
if (envError) throw new InputError(envError, "invalid_env");
|
|
5966
|
+
if (app2 !== void 0 && wranglerEnv) {
|
|
5730
5967
|
throw new InputError(
|
|
5731
|
-
"
|
|
5732
|
-
"
|
|
5968
|
+
"Pass either --app or --env, not both \u2014 --env reads the [env.<name>] block's own app id, while --app names an app directly.",
|
|
5969
|
+
"ambiguous_target"
|
|
5733
5970
|
);
|
|
5734
5971
|
}
|
|
5972
|
+
if (app2 !== void 0) return;
|
|
5973
|
+
const appDir = findAppDir();
|
|
5974
|
+
if (!appDir || !readAppId(appDir, wranglerEnv)) throw appTargetMissingError(wranglerEnv);
|
|
5735
5975
|
}
|
|
5736
5976
|
async function warnIfPhantomApp(deployUrl, token, appId, explicit) {
|
|
5737
5977
|
if (!explicit || !STRICT_APP_ID_RE.test(explicit.trim())) return;
|
|
@@ -6058,28 +6298,10 @@ var logs_default = defineCommand4({
|
|
|
6058
6298
|
}
|
|
6059
6299
|
},
|
|
6060
6300
|
async run({ args }) {
|
|
6301
|
+
const envArg = args.env;
|
|
6302
|
+
assertAppTargetResolvable(args.app, { wranglerEnv: envArg });
|
|
6061
6303
|
const token = await ensureToken();
|
|
6062
|
-
const
|
|
6063
|
-
if (args.app && wranglerEnv) {
|
|
6064
|
-
throw new InputError(
|
|
6065
|
-
"Pass either --app or --env, not both \u2014 --env reads the [env.<name>] block\u2019s own app id, --app names an app directly.",
|
|
6066
|
-
"ambiguous_target"
|
|
6067
|
-
);
|
|
6068
|
-
}
|
|
6069
|
-
let appId;
|
|
6070
|
-
if (!args.app && wranglerEnv) {
|
|
6071
|
-
const appDir = findAppDir();
|
|
6072
|
-
const id = appDir ? readAppId(appDir, wranglerEnv) : null;
|
|
6073
|
-
if (!id) {
|
|
6074
|
-
throw new InputError(
|
|
6075
|
-
`No app id for env "${wranglerEnv}" \u2014 wrangler.toml has no [env.${wranglerEnv}] block with its own DEEPSPACE_APP_ID.`,
|
|
6076
|
-
"no_app_id_for_env"
|
|
6077
|
-
);
|
|
6078
|
-
}
|
|
6079
|
-
appId = id;
|
|
6080
|
-
} else {
|
|
6081
|
-
appId = await resolveAppTarget(DEPLOY_URL6, token, args.app);
|
|
6082
|
-
}
|
|
6304
|
+
const appId = await resolveAppTarget(DEPLOY_URL6, token, args.app, { wranglerEnv: envArg });
|
|
6083
6305
|
if (args.level && !LOG_LEVELS.includes(args.level)) {
|
|
6084
6306
|
throw new InputError(`Invalid --level "${args.level}". Use: ${LOG_LEVELS.join(", ")}`, "invalid_level");
|
|
6085
6307
|
}
|
|
@@ -6248,20 +6470,20 @@ var usage_default = defineDeepspaceCommand({
|
|
|
6248
6470
|
});
|
|
6249
6471
|
|
|
6250
6472
|
// src/cli/commands/add.ts
|
|
6251
|
-
import { existsSync as
|
|
6252
|
-
import { dirname as dirname7, join as
|
|
6473
|
+
import { existsSync as existsSync20, readFileSync as readFileSync20, realpathSync as realpathSync3 } from "fs";
|
|
6474
|
+
import { dirname as dirname7, join as join19, resolve as resolve14 } from "path";
|
|
6253
6475
|
import { pathToFileURL as pathToFileURL3 } from "url";
|
|
6254
6476
|
|
|
6255
6477
|
// src/cli/commands/feature-installer.ts
|
|
6256
6478
|
import {
|
|
6257
6479
|
closeSync as closeSync2,
|
|
6258
6480
|
copyFileSync,
|
|
6259
|
-
existsSync as
|
|
6481
|
+
existsSync as existsSync19,
|
|
6260
6482
|
fstatSync as fstatSync2,
|
|
6261
6483
|
mkdirSync as mkdirSync6,
|
|
6262
6484
|
mkdtempSync,
|
|
6263
6485
|
openSync as openSync2,
|
|
6264
|
-
readFileSync as
|
|
6486
|
+
readFileSync as readFileSync19,
|
|
6265
6487
|
readSync,
|
|
6266
6488
|
readdirSync as readdirSync5,
|
|
6267
6489
|
rmSync as rmSync4,
|
|
@@ -6269,16 +6491,16 @@ import {
|
|
|
6269
6491
|
} from "fs";
|
|
6270
6492
|
import { spawnSync as spawnSync6 } from "child_process";
|
|
6271
6493
|
import { tmpdir as tmpdir2 } from "os";
|
|
6272
|
-
import { dirname as dirname6, isAbsolute as isAbsolute4, join as
|
|
6494
|
+
import { dirname as dirname6, isAbsolute as isAbsolute4, join as join18, resolve as resolve13 } from "path";
|
|
6273
6495
|
import { fileURLToPath } from "url";
|
|
6274
6496
|
var NAV_MARKER = "// \u2500\u2500 Features add nav items below this line \u2500\u2500";
|
|
6275
6497
|
function featurePackageRoot(moduleUrl = import.meta.url) {
|
|
6276
6498
|
let dir = dirname6(fileURLToPath(moduleUrl));
|
|
6277
6499
|
for (; ; ) {
|
|
6278
|
-
const packagePath =
|
|
6279
|
-
if (
|
|
6500
|
+
const packagePath = join18(dir, "package.json");
|
|
6501
|
+
if (existsSync19(packagePath)) {
|
|
6280
6502
|
try {
|
|
6281
|
-
const pkg2 = JSON.parse(
|
|
6503
|
+
const pkg2 = JSON.parse(readFileSync19(packagePath, "utf-8"));
|
|
6282
6504
|
if (pkg2.name === "deepspace") return dir;
|
|
6283
6505
|
} catch {
|
|
6284
6506
|
}
|
|
@@ -6289,13 +6511,13 @@ function featurePackageRoot(moduleUrl = import.meta.url) {
|
|
|
6289
6511
|
}
|
|
6290
6512
|
}
|
|
6291
6513
|
function hasFeatureCatalog(packageRoot = featurePackageRoot()) {
|
|
6292
|
-
return
|
|
6514
|
+
return existsSync19(join18(packageRoot, "features"));
|
|
6293
6515
|
}
|
|
6294
6516
|
function readFeatureConfig(id, packageRoot = featurePackageRoot()) {
|
|
6295
|
-
const configPath =
|
|
6296
|
-
if (!
|
|
6517
|
+
const configPath = join18(packageRoot, "features", id, "feature.json");
|
|
6518
|
+
if (!existsSync19(configPath)) return null;
|
|
6297
6519
|
try {
|
|
6298
|
-
const config = JSON.parse(
|
|
6520
|
+
const config = JSON.parse(readFileSync19(configPath, "utf-8"));
|
|
6299
6521
|
if (typeof config.id !== "string" || typeof config.name !== "string" || !Array.isArray(config.files)) {
|
|
6300
6522
|
return null;
|
|
6301
6523
|
}
|
|
@@ -6305,8 +6527,8 @@ function readFeatureConfig(id, packageRoot = featurePackageRoot()) {
|
|
|
6305
6527
|
}
|
|
6306
6528
|
}
|
|
6307
6529
|
function listFeatureConfigs(packageRoot = featurePackageRoot()) {
|
|
6308
|
-
const featuresDir =
|
|
6309
|
-
if (!
|
|
6530
|
+
const featuresDir = join18(packageRoot, "features");
|
|
6531
|
+
if (!existsSync19(featuresDir)) return [];
|
|
6310
6532
|
return readdirSync5(featuresDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => readFeatureConfig(entry.name, packageRoot)).filter((config) => config !== null && !config.internal).sort((a, b) => a.id.localeCompare(b.id));
|
|
6311
6533
|
}
|
|
6312
6534
|
function featureCatalog(packageRoot = featurePackageRoot()) {
|
|
@@ -6360,7 +6582,7 @@ function copyFile(src, dest) {
|
|
|
6360
6582
|
function copyFileWithImportShift(src, dest, levels) {
|
|
6361
6583
|
mkdirSync6(dirname6(dest), { recursive: true });
|
|
6362
6584
|
const prefix = "../".repeat(levels);
|
|
6363
|
-
const shifted =
|
|
6585
|
+
const shifted = readFileSync19(src, "utf-8").replace(
|
|
6364
6586
|
/(from\s+|import\s+|import\()(['"])(\.\.\/)/g,
|
|
6365
6587
|
`$1$2${prefix}$3`
|
|
6366
6588
|
);
|
|
@@ -6373,12 +6595,12 @@ function installFiles(packageRoot, config, targetDir, emit) {
|
|
|
6373
6595
|
const preexisting = [];
|
|
6374
6596
|
const missing = [];
|
|
6375
6597
|
for (const file of config.files) {
|
|
6376
|
-
const srcPath =
|
|
6598
|
+
const srcPath = join18(packageRoot, "features", config.id, file.src);
|
|
6377
6599
|
const resolvedDest = resolveFeatureDestPath(file.dest, config.route);
|
|
6378
|
-
const destPath =
|
|
6379
|
-
const existed =
|
|
6600
|
+
const destPath = join18(targetDir, resolvedDest);
|
|
6601
|
+
const existed = existsSync19(destPath);
|
|
6380
6602
|
if (existed) preexisting.push(resolvedDest);
|
|
6381
|
-
if (!
|
|
6603
|
+
if (!existsSync19(srcPath)) {
|
|
6382
6604
|
emit(` Warning: source not found: ${file.src}`, "stderr");
|
|
6383
6605
|
if (!existed) missing.push(resolvedDest);
|
|
6384
6606
|
continue;
|
|
@@ -6415,11 +6637,11 @@ function unresolvedSchema(schema, reason, emit) {
|
|
|
6415
6637
|
}
|
|
6416
6638
|
function integrateSchema(config, targetDir, emit) {
|
|
6417
6639
|
if (!config.schema) return [];
|
|
6418
|
-
const schemasPath =
|
|
6419
|
-
if (!
|
|
6640
|
+
const schemasPath = join18(targetDir, "src", "schemas.ts");
|
|
6641
|
+
if (!existsSync19(schemasPath)) {
|
|
6420
6642
|
return [unresolvedSchema(config.schema, "src/schemas.ts was not found.", emit)];
|
|
6421
6643
|
}
|
|
6422
|
-
let content =
|
|
6644
|
+
let content = readFileSync19(schemasPath, "utf-8");
|
|
6423
6645
|
const { exportName, importPath, spreadOperator } = config.schema;
|
|
6424
6646
|
const importPattern = new RegExp(`^import\\s+\\{[^}]*\\b${exportName}\\b`, "m");
|
|
6425
6647
|
if (importPattern.test(content)) {
|
|
@@ -6472,11 +6694,11 @@ function unresolvedActions(actions, reason, emit) {
|
|
|
6472
6694
|
}
|
|
6473
6695
|
function integrateActions(config, targetDir, emit) {
|
|
6474
6696
|
if (!config.actions?.length) return [];
|
|
6475
|
-
const actionsPath =
|
|
6476
|
-
if (!
|
|
6697
|
+
const actionsPath = join18(targetDir, "src", "actions", "index.ts");
|
|
6698
|
+
if (!existsSync19(actionsPath)) {
|
|
6477
6699
|
return [unresolvedActions(config.actions, "src/actions/index.ts was not found.", emit)];
|
|
6478
6700
|
}
|
|
6479
|
-
let content =
|
|
6701
|
+
let content = readFileSync19(actionsPath, "utf-8");
|
|
6480
6702
|
const registryPattern = /export const actions:\s*Record<string,\s*ActionHandler(?:<[^>]*>)?>\s*=\s*\{/;
|
|
6481
6703
|
if (!registryPattern.test(content)) {
|
|
6482
6704
|
const reason = "src/actions/index.ts has an unexpected structure.";
|
|
@@ -6519,10 +6741,152 @@ ${registryEntry}`);
|
|
|
6519
6741
|
if (integrated > 0) writeFileSync8(actionsPath, content);
|
|
6520
6742
|
return unresolved;
|
|
6521
6743
|
}
|
|
6744
|
+
function integrateCode(config, targetDir, emit) {
|
|
6745
|
+
const unresolved = [];
|
|
6746
|
+
for (const insertion of config.code ?? []) {
|
|
6747
|
+
const targetPath = join18(targetDir, insertion.file);
|
|
6748
|
+
if (!existsSync19(targetPath)) {
|
|
6749
|
+
unresolved.push({
|
|
6750
|
+
area: "code",
|
|
6751
|
+
reason: `${insertion.file} was not found.`,
|
|
6752
|
+
steps: [`Add ${insertion.insert.trim()} to ${insertion.file}.`]
|
|
6753
|
+
});
|
|
6754
|
+
continue;
|
|
6755
|
+
}
|
|
6756
|
+
const original = readFileSync19(targetPath, "utf-8");
|
|
6757
|
+
if (original.includes(insertion.insert.trim())) {
|
|
6758
|
+
emit(` Integration already present: ${insertion.file}`);
|
|
6759
|
+
continue;
|
|
6760
|
+
}
|
|
6761
|
+
const markerIndex = original.indexOf(insertion.marker);
|
|
6762
|
+
if (markerIndex < 0) {
|
|
6763
|
+
unresolved.push({
|
|
6764
|
+
area: "code",
|
|
6765
|
+
reason: `${insertion.file} does not contain the expected insertion point.`,
|
|
6766
|
+
steps: [
|
|
6767
|
+
...insertion.import ? [`Add ${insertion.import} to ${insertion.file}.`] : [],
|
|
6768
|
+
`Add ${insertion.insert.trim()} to ${insertion.file}.`
|
|
6769
|
+
]
|
|
6770
|
+
});
|
|
6771
|
+
continue;
|
|
6772
|
+
}
|
|
6773
|
+
let content = original;
|
|
6774
|
+
if (insertion.import && !content.includes(insertion.import)) {
|
|
6775
|
+
const importIndex = content.search(/^import\s/m);
|
|
6776
|
+
content = `${content.slice(0, importIndex < 0 ? 0 : importIndex)}${insertion.import}
|
|
6777
|
+
${content.slice(importIndex < 0 ? 0 : importIndex)}`;
|
|
6778
|
+
}
|
|
6779
|
+
const currentMarkerIndex = content.indexOf(insertion.marker);
|
|
6780
|
+
const insertAt = insertion.placement === "before" ? currentMarkerIndex : currentMarkerIndex + insertion.marker.length;
|
|
6781
|
+
const prefix = insertion.placement === "before" ? "" : "\n";
|
|
6782
|
+
const suffix = insertion.placement === "before" ? "\n" : "";
|
|
6783
|
+
content = `${content.slice(0, insertAt)}${prefix}${insertion.insert}${suffix}${content.slice(insertAt)}`;
|
|
6784
|
+
writeFileSync8(targetPath, content);
|
|
6785
|
+
emit(` Integrated: ${insertion.file}`);
|
|
6786
|
+
}
|
|
6787
|
+
return unresolved;
|
|
6788
|
+
}
|
|
6789
|
+
function integrateIgnore(config, targetDir) {
|
|
6790
|
+
if (!config.ignore?.length) return;
|
|
6791
|
+
const targetPath = join18(targetDir, ".gitignore");
|
|
6792
|
+
const current = existsSync19(targetPath) ? readFileSync19(targetPath, "utf-8") : "";
|
|
6793
|
+
const present = new Set(current.split(/\r?\n/).map((line) => line.trim()));
|
|
6794
|
+
const missing = config.ignore.filter((pattern) => !present.has(pattern));
|
|
6795
|
+
if (missing.length === 0) return;
|
|
6796
|
+
const separator = current === "" || current.endsWith("\n") ? "" : "\n";
|
|
6797
|
+
writeFileSync8(targetPath, `${current}${separator}${missing.join("\n")}
|
|
6798
|
+
`);
|
|
6799
|
+
}
|
|
6800
|
+
function integrateWrangler(config, targetDir, emit) {
|
|
6801
|
+
const runWorkerFirst = config.wrangler?.runWorkerFirst === true;
|
|
6802
|
+
const rateLimits = config.wrangler?.rateLimits ?? [];
|
|
6803
|
+
if (!runWorkerFirst && rateLimits.length === 0) return [];
|
|
6804
|
+
const targetPath = join18(targetDir, "wrangler.toml");
|
|
6805
|
+
const steps = [
|
|
6806
|
+
...runWorkerFirst ? ["Set assets.run_worker_first = true in wrangler.toml."] : [],
|
|
6807
|
+
...rateLimits.map((binding) => `Add the ${binding.name} rate-limit binding to wrangler.toml.`)
|
|
6808
|
+
];
|
|
6809
|
+
if (!existsSync19(targetPath)) {
|
|
6810
|
+
return [{ area: "wrangler", reason: "wrangler.toml was not found.", steps }];
|
|
6811
|
+
}
|
|
6812
|
+
let source = readFileSync19(targetPath, "utf-8");
|
|
6813
|
+
if (runWorkerFirst && !/^\[assets\]\s*$/m.test(source)) {
|
|
6814
|
+
return [{ area: "wrangler", reason: "wrangler.toml has no [assets] section.", steps }];
|
|
6815
|
+
}
|
|
6816
|
+
let changed = false;
|
|
6817
|
+
if (runWorkerFirst) {
|
|
6818
|
+
const updated = setRunWorkerFirst(source);
|
|
6819
|
+
changed ||= updated !== source;
|
|
6820
|
+
source = updated;
|
|
6821
|
+
}
|
|
6822
|
+
const scopes = ["", ...wranglerEnvironmentNames(source)];
|
|
6823
|
+
for (const scope of scopes) {
|
|
6824
|
+
for (const binding of rateLimits) {
|
|
6825
|
+
if (hasRateLimitBinding(source, scope, binding.name)) continue;
|
|
6826
|
+
source = `${source.trimEnd()}
|
|
6827
|
+
|
|
6828
|
+
${rateLimitBindingBlock(scope, binding)}
|
|
6829
|
+
`;
|
|
6830
|
+
changed = true;
|
|
6831
|
+
}
|
|
6832
|
+
}
|
|
6833
|
+
if (changed) {
|
|
6834
|
+
writeFileSync8(targetPath, source);
|
|
6835
|
+
emit(" Integrated: wrangler.toml");
|
|
6836
|
+
} else emit(" Integration already present: wrangler.toml");
|
|
6837
|
+
return [];
|
|
6838
|
+
}
|
|
6839
|
+
function setRunWorkerFirst(source) {
|
|
6840
|
+
const headers = [...source.matchAll(/^\[(?:env\.[^\]]+\.)?assets\]\s*$/gm)];
|
|
6841
|
+
for (const header of headers.reverse()) {
|
|
6842
|
+
const start = header.index;
|
|
6843
|
+
const bodyStart = start + header[0].length;
|
|
6844
|
+
const nextHeader = source.slice(bodyStart).search(/^\[\[?[^\]]+\]\]?\s*$/m);
|
|
6845
|
+
const end = nextHeader < 0 ? source.length : bodyStart + nextHeader;
|
|
6846
|
+
const section = source.slice(start, end);
|
|
6847
|
+
if (/^\s*run_worker_first\s*=\s*true(?:\s*#.*)?$/m.test(section)) continue;
|
|
6848
|
+
const setting = /^(\s*)run_worker_first\s*=\s*(?:false|\[(?:[^\]"']|"(?:[^"\\]|\\[\s\S])*"|'[^']*')*\])(\s*(?:#.*)?)$/m;
|
|
6849
|
+
const updated = setting.test(section) ? section.replace(setting, "$1run_worker_first = true$2") : section.replace(/^\[(?:env\.[^\]]+\.)?assets\]\s*$/m, "$&\nrun_worker_first = true");
|
|
6850
|
+
source = source.slice(0, start) + updated + source.slice(end);
|
|
6851
|
+
}
|
|
6852
|
+
return source;
|
|
6853
|
+
}
|
|
6854
|
+
function wranglerEnvironmentNames(source) {
|
|
6855
|
+
return [
|
|
6856
|
+
...new Set(
|
|
6857
|
+
[...source.matchAll(/^\[\[?env\.([^.\]]+)(?:\.|\]\]?\s*$)/gm)].map((match) => match[1])
|
|
6858
|
+
)
|
|
6859
|
+
];
|
|
6860
|
+
}
|
|
6861
|
+
function hasRateLimitBinding(source, scope, name) {
|
|
6862
|
+
const header = scope ? `[[env.${scope}.ratelimits]]` : "[[ratelimits]]";
|
|
6863
|
+
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
6864
|
+
const namePattern = new RegExp(
|
|
6865
|
+
`^\\s*name\\s*=\\s*(?:"${escaped}"|'${escaped}')\\s*(?:#.*)?$`,
|
|
6866
|
+
"m"
|
|
6867
|
+
);
|
|
6868
|
+
let offset = 0;
|
|
6869
|
+
while ((offset = source.indexOf(header, offset)) >= 0) {
|
|
6870
|
+
const end = source.slice(offset + header.length).search(/^\[/m);
|
|
6871
|
+
const blockEnd = end < 0 ? source.length : offset + header.length + end;
|
|
6872
|
+
if (namePattern.test(source.slice(offset, blockEnd))) return true;
|
|
6873
|
+
offset += header.length;
|
|
6874
|
+
}
|
|
6875
|
+
return false;
|
|
6876
|
+
}
|
|
6877
|
+
function rateLimitBindingBlock(scope, binding) {
|
|
6878
|
+
const header = scope ? `[[env.${scope}.ratelimits]]` : "[[ratelimits]]";
|
|
6879
|
+
return [
|
|
6880
|
+
header,
|
|
6881
|
+
`name = ${JSON.stringify(binding.name)}`,
|
|
6882
|
+
`namespace_id = ${JSON.stringify(binding.namespaceId)}`,
|
|
6883
|
+
`simple = { limit = ${binding.limit}, period = ${binding.period} }`
|
|
6884
|
+
].join("\n");
|
|
6885
|
+
}
|
|
6522
6886
|
function integrateCss(packageRoot, config, targetDir, emit) {
|
|
6523
6887
|
if (!config.css?.length) return [];
|
|
6524
|
-
const stylesPath =
|
|
6525
|
-
if (!
|
|
6888
|
+
const stylesPath = join18(targetDir, "src", "styles.css");
|
|
6889
|
+
if (!existsSync19(stylesPath)) {
|
|
6526
6890
|
emit(" Warning: Cannot integrate CSS \u2014 src/styles.css not found");
|
|
6527
6891
|
return [
|
|
6528
6892
|
{
|
|
@@ -6534,12 +6898,12 @@ function integrateCss(packageRoot, config, targetDir, emit) {
|
|
|
6534
6898
|
}
|
|
6535
6899
|
];
|
|
6536
6900
|
}
|
|
6537
|
-
let styles =
|
|
6901
|
+
let styles = readFileSync19(stylesPath, "utf-8");
|
|
6538
6902
|
let integrated = 0;
|
|
6539
6903
|
const unresolved = [];
|
|
6540
6904
|
for (const cssFile of config.css) {
|
|
6541
|
-
const srcPath =
|
|
6542
|
-
if (!
|
|
6905
|
+
const srcPath = join18(packageRoot, "features", config.id, cssFile);
|
|
6906
|
+
if (!existsSync19(srcPath)) {
|
|
6543
6907
|
emit(` Warning: CSS source not found: ${cssFile}`, "stderr");
|
|
6544
6908
|
unresolved.push({
|
|
6545
6909
|
area: "css",
|
|
@@ -6548,7 +6912,7 @@ function integrateCss(packageRoot, config, targetDir, emit) {
|
|
|
6548
6912
|
});
|
|
6549
6913
|
continue;
|
|
6550
6914
|
}
|
|
6551
|
-
const css =
|
|
6915
|
+
const css = readFileSync19(srcPath, "utf-8");
|
|
6552
6916
|
const fingerprint = css.match(/\.([\w-]+)\s*\{|@keyframes\s+([\w-]+)/);
|
|
6553
6917
|
const marker = fingerprint?.[1] ?? fingerprint?.[2];
|
|
6554
6918
|
if (marker && styles.includes(marker)) {
|
|
@@ -6575,11 +6939,11 @@ function unresolvedRoute(route, config, reason, emit) {
|
|
|
6575
6939
|
}
|
|
6576
6940
|
function integrateRoute(config, targetDir, emit) {
|
|
6577
6941
|
if (!config.route) return [];
|
|
6578
|
-
const navPath =
|
|
6579
|
-
if (!
|
|
6942
|
+
const navPath = join18(targetDir, "src", "nav.ts");
|
|
6943
|
+
if (!existsSync19(navPath)) {
|
|
6580
6944
|
return [unresolvedRoute(config.route, config, "src/nav.ts was not found.", emit)];
|
|
6581
6945
|
}
|
|
6582
|
-
let content =
|
|
6946
|
+
let content = readFileSync19(navPath, "utf-8");
|
|
6583
6947
|
const routePath = config.route.path;
|
|
6584
6948
|
if (content.includes(`'${routePath}'`)) {
|
|
6585
6949
|
emit(` Nav already present: ${routePath}`);
|
|
@@ -6626,10 +6990,10 @@ function runPackageInstall(packageManager, targetDir, outputVisible) {
|
|
|
6626
6990
|
const child = spawnSync6(packageManager, ["install"], { ...options, stdio: "inherit" });
|
|
6627
6991
|
return { error: child.error, status: child.status };
|
|
6628
6992
|
}
|
|
6629
|
-
const captureDir = mkdtempSync(
|
|
6993
|
+
const captureDir = mkdtempSync(join18(tmpdir2(), "deepspace-add-install-"));
|
|
6630
6994
|
let outputFd;
|
|
6631
6995
|
try {
|
|
6632
|
-
outputFd = openSync2(
|
|
6996
|
+
outputFd = openSync2(join18(captureDir, "output.log"), "w+");
|
|
6633
6997
|
const child = spawnSync6(packageManager, ["install"], {
|
|
6634
6998
|
...options,
|
|
6635
6999
|
stdio: ["ignore", outputFd, outputFd]
|
|
@@ -6653,14 +7017,14 @@ function integrateDependencies(config, targetDir, runInstall, outputVisible, emi
|
|
|
6653
7017
|
if (declarations.every(({ values }) => !values || Object.keys(values).length === 0)) {
|
|
6654
7018
|
return { added: [], installRan: false, packageManager };
|
|
6655
7019
|
}
|
|
6656
|
-
const packagePath =
|
|
6657
|
-
if (!
|
|
7020
|
+
const packagePath = join18(targetDir, "package.json");
|
|
7021
|
+
if (!existsSync19(packagePath)) {
|
|
6658
7022
|
emit(" Could not patch package.json (file not found)");
|
|
6659
7023
|
return { added: [], installRan: false, packageManager };
|
|
6660
7024
|
}
|
|
6661
7025
|
let pkg2;
|
|
6662
7026
|
try {
|
|
6663
|
-
pkg2 = JSON.parse(
|
|
7027
|
+
pkg2 = JSON.parse(readFileSync19(packagePath, "utf-8"));
|
|
6664
7028
|
} catch (error) {
|
|
6665
7029
|
emit(
|
|
6666
7030
|
` Could not patch package.json (parse error: ${error instanceof Error ? error.message : String(error)})`
|
|
@@ -6720,7 +7084,7 @@ ${child.diagnosticTail}` : "";
|
|
|
6720
7084
|
}
|
|
6721
7085
|
function dependencySnapshot(targetDir) {
|
|
6722
7086
|
try {
|
|
6723
|
-
const pkg2 = JSON.parse(
|
|
7087
|
+
const pkg2 = JSON.parse(readFileSync19(join18(targetDir, "package.json"), "utf-8"));
|
|
6724
7088
|
return {
|
|
6725
7089
|
dependencies: pkg2.dependencies ?? {},
|
|
6726
7090
|
devDependencies: pkg2.devDependencies ?? {}
|
|
@@ -6732,7 +7096,7 @@ function dependencySnapshot(targetDir) {
|
|
|
6732
7096
|
function installedNavFeatures(packageRoot, targetDir) {
|
|
6733
7097
|
return listFeatureConfigs(packageRoot).filter((feature) => feature.category === "nav" && feature.files.length > 0).filter((feature) => {
|
|
6734
7098
|
const signature = resolveFeatureDestPath(feature.files[0].dest, feature.route);
|
|
6735
|
-
return
|
|
7099
|
+
return existsSync19(join18(targetDir, signature));
|
|
6736
7100
|
}).map((feature) => feature.id);
|
|
6737
7101
|
}
|
|
6738
7102
|
function warnNavConflicts(packageRoot, config, targetDir, emit) {
|
|
@@ -6770,6 +7134,7 @@ function installFeature(options) {
|
|
|
6770
7134
|
emit(` ${config.description ?? ""}`);
|
|
6771
7135
|
emit(` Target: ${targetDir}`);
|
|
6772
7136
|
const installedFiles = installFiles(packageRoot, config, targetDir, emit);
|
|
7137
|
+
integrateIgnore(config, targetDir);
|
|
6773
7138
|
emit("");
|
|
6774
7139
|
emit(
|
|
6775
7140
|
`Copied ${installedFiles.copied} file(s)${installedFiles.skipped > 0 ? `, skipped ${installedFiles.skipped} existing` : ""}`
|
|
@@ -6777,6 +7142,8 @@ function installFeature(options) {
|
|
|
6777
7142
|
const unresolvedIntegrations = [
|
|
6778
7143
|
...integrateSchema(config, targetDir, emit),
|
|
6779
7144
|
...integrateActions(config, targetDir, emit),
|
|
7145
|
+
...integrateWrangler(config, targetDir, emit),
|
|
7146
|
+
...integrateCode(config, targetDir, emit),
|
|
6780
7147
|
...integrateCss(packageRoot, config, targetDir, emit),
|
|
6781
7148
|
...integrateRoute(config, targetDir, emit)
|
|
6782
7149
|
];
|
|
@@ -6869,9 +7236,10 @@ var CATEGORY_LABELS = {
|
|
|
6869
7236
|
nav: "Navigation",
|
|
6870
7237
|
layout: "Layouts",
|
|
6871
7238
|
display: "Display",
|
|
6872
|
-
landing: "Landing Page Sections"
|
|
7239
|
+
landing: "Landing Page Sections",
|
|
7240
|
+
publishing: "Publishing"
|
|
6873
7241
|
};
|
|
6874
|
-
var CATEGORY_ORDER = ["assistant", "data", "nav", "layout", "display", "landing"];
|
|
7242
|
+
var CATEGORY_ORDER = ["assistant", "data", "publishing", "nav", "layout", "display", "landing"];
|
|
6875
7243
|
function groupByCategory(features) {
|
|
6876
7244
|
const groups = /* @__PURE__ */ new Map();
|
|
6877
7245
|
for (const feature of features) {
|
|
@@ -6961,11 +7329,11 @@ function renderFeatureInfo(config) {
|
|
|
6961
7329
|
return lines.join("\n");
|
|
6962
7330
|
}
|
|
6963
7331
|
function isDeepSpaceApp(dir) {
|
|
6964
|
-
if (
|
|
6965
|
-
const packagePath =
|
|
6966
|
-
if (!
|
|
7332
|
+
if (existsSync20(join19(dir, "wrangler.toml"))) return true;
|
|
7333
|
+
const packagePath = join19(dir, "package.json");
|
|
7334
|
+
if (!existsSync20(packagePath)) return false;
|
|
6967
7335
|
try {
|
|
6968
|
-
const pkg2 = JSON.parse(
|
|
7336
|
+
const pkg2 = JSON.parse(readFileSync20(packagePath, "utf-8"));
|
|
6969
7337
|
return Boolean(pkg2.dependencies?.deepspace || pkg2.devDependencies?.deepspace);
|
|
6970
7338
|
} catch {
|
|
6971
7339
|
return false;
|
|
@@ -6974,8 +7342,8 @@ function isDeepSpaceApp(dir) {
|
|
|
6974
7342
|
function installedPackageRoot(fromDir) {
|
|
6975
7343
|
let dir = fromDir;
|
|
6976
7344
|
for (; ; ) {
|
|
6977
|
-
const candidate =
|
|
6978
|
-
if (
|
|
7345
|
+
const candidate = join19(dir, "node_modules", "deepspace");
|
|
7346
|
+
if (existsSync20(join19(candidate, "package.json"))) return candidate;
|
|
6979
7347
|
const parent = dirname7(dir);
|
|
6980
7348
|
if (parent === dir) return null;
|
|
6981
7349
|
dir = parent;
|
|
@@ -6992,9 +7360,9 @@ async function targetInstaller(appDir) {
|
|
|
6992
7360
|
if (realpathSync3(installedRoot) === realpathSync3(featurePackageRoot())) {
|
|
6993
7361
|
return { installFeature };
|
|
6994
7362
|
}
|
|
6995
|
-
const entry =
|
|
6996
|
-
const catalog =
|
|
6997
|
-
if (!
|
|
7363
|
+
const entry = join19(installedRoot, "dist", "feature-installer.js");
|
|
7364
|
+
const catalog = join19(installedRoot, "features");
|
|
7365
|
+
if (!existsSync20(entry) || !existsSync20(catalog)) {
|
|
6998
7366
|
throw new Refusal(
|
|
6999
7367
|
`The app's installed deepspace package does not contain the typed feature installer.
|
|
7000
7368
|
Expected: ${entry}
|
|
@@ -7087,7 +7455,7 @@ var add_default = defineDeepspaceCommand({
|
|
|
7087
7455
|
return { data: { features: featureCatalog(root) } };
|
|
7088
7456
|
}
|
|
7089
7457
|
const appDir = resolve14(args.dir ?? ".");
|
|
7090
|
-
if (!
|
|
7458
|
+
if (!existsSync20(appDir)) {
|
|
7091
7459
|
throw new Refusal(
|
|
7092
7460
|
`Target directory not found: ${appDir}
|
|
7093
7461
|
Create a new app first: deepspace app create <name>`,
|
|
@@ -7748,7 +8116,7 @@ var transfer_default = defineCommand7({
|
|
|
7748
8116
|
import { defineCommand as defineCommand8 } from "citty";
|
|
7749
8117
|
|
|
7750
8118
|
// src/cli/commands/_invoke-impl.ts
|
|
7751
|
-
import { readFileSync as
|
|
8119
|
+
import { readFileSync as readFileSync21 } from "fs";
|
|
7752
8120
|
import * as p15 from "@clack/prompts";
|
|
7753
8121
|
var API_URL7 = process.env.DEEPSPACE_API_URL ?? PLATFORM_URLS.api;
|
|
7754
8122
|
var DEFAULT_TIMEOUT_MS = 12e4;
|
|
@@ -7789,7 +8157,7 @@ function resolveBody(opts) {
|
|
|
7789
8157
|
if (opts.body != null) {
|
|
7790
8158
|
raw = opts.body;
|
|
7791
8159
|
} else if (opts.bodyFile != null) {
|
|
7792
|
-
raw = opts.bodyFile === "-" ?
|
|
8160
|
+
raw = opts.bodyFile === "-" ? readFileSync21(0, "utf-8") : readFileSync21(opts.bodyFile, "utf-8");
|
|
7793
8161
|
} else {
|
|
7794
8162
|
return "{}";
|
|
7795
8163
|
}
|
|
@@ -8068,8 +8436,8 @@ var integrations_default = defineCommand8({
|
|
|
8068
8436
|
|
|
8069
8437
|
// src/cli/commands/library.ts
|
|
8070
8438
|
import { defineCommand as defineCommand9 } from "citty";
|
|
8071
|
-
import { existsSync as
|
|
8072
|
-
import { join as
|
|
8439
|
+
import { existsSync as existsSync21, readFileSync as readFileSync22 } from "fs";
|
|
8440
|
+
import { join as join20, resolve as resolve15 } from "path";
|
|
8073
8441
|
import { parse as parseToml4 } from "smol-toml";
|
|
8074
8442
|
import * as p16 from "@clack/prompts";
|
|
8075
8443
|
var DEFAULT_LIBRARY_APP = "deepdotspace-site";
|
|
@@ -8140,14 +8508,14 @@ var publish = defineDeepspaceCommand({
|
|
|
8140
8508
|
let appName = str(args.app)?.trim();
|
|
8141
8509
|
if (!appName) {
|
|
8142
8510
|
const appDir = resolve15(str(args.dir) ?? ".");
|
|
8143
|
-
const wranglerPath =
|
|
8144
|
-
if (!
|
|
8511
|
+
const wranglerPath = join20(appDir, "wrangler.toml");
|
|
8512
|
+
if (!existsSync21(wranglerPath)) {
|
|
8145
8513
|
throw new Refusal(
|
|
8146
8514
|
"No --app provided and no wrangler.toml found. Either pass --app <name> or run from your app's directory.",
|
|
8147
8515
|
"not_in_app_repo"
|
|
8148
8516
|
);
|
|
8149
8517
|
}
|
|
8150
|
-
const cfg = parseToml4(
|
|
8518
|
+
const cfg = parseToml4(readFileSync22(wranglerPath, "utf-8"));
|
|
8151
8519
|
const nameRes = resolveAppName(cfg.name);
|
|
8152
8520
|
if (!nameRes.ok) throw new Refusal(`wrangler.toml: ${nameRes.reason}`, "invalid_config");
|
|
8153
8521
|
appName = nameRes.name;
|
|
@@ -8285,8 +8653,8 @@ var library_default = defineCommand9({
|
|
|
8285
8653
|
|
|
8286
8654
|
// src/cli/commands/feedback.ts
|
|
8287
8655
|
import * as p17 from "@clack/prompts";
|
|
8288
|
-
import { existsSync as
|
|
8289
|
-
import { dirname as dirname8, join as
|
|
8656
|
+
import { existsSync as existsSync22, readFileSync as readFileSync23 } from "fs";
|
|
8657
|
+
import { dirname as dirname8, join as join21 } from "path";
|
|
8290
8658
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
8291
8659
|
import { release } from "os";
|
|
8292
8660
|
var API_URL8 = process.env.DEEPSPACE_API_URL ?? PLATFORM_URLS.api;
|
|
@@ -8309,12 +8677,12 @@ function readCliVersion() {
|
|
|
8309
8677
|
try {
|
|
8310
8678
|
const here = dirname8(fileURLToPath2(import.meta.url));
|
|
8311
8679
|
const candidates = [
|
|
8312
|
-
|
|
8313
|
-
|
|
8680
|
+
join21(here, "..", "package.json"),
|
|
8681
|
+
join21(here, "..", "..", "..", "package.json")
|
|
8314
8682
|
];
|
|
8315
8683
|
for (const path of candidates) {
|
|
8316
|
-
if (!
|
|
8317
|
-
const pkg2 = JSON.parse(
|
|
8684
|
+
if (!existsSync22(path)) continue;
|
|
8685
|
+
const pkg2 = JSON.parse(readFileSync23(path, "utf-8"));
|
|
8318
8686
|
if (pkg2.name === "deepspace" && pkg2.version) return pkg2.version;
|
|
8319
8687
|
}
|
|
8320
8688
|
} catch {
|
|
@@ -8510,7 +8878,7 @@ Context: deepspace ${payload.cliVersion} \xB7 ${payload.nodeVersion} \xB7 ${payl
|
|
|
8510
8878
|
|
|
8511
8879
|
// src/cli/commands/secrets.ts
|
|
8512
8880
|
import { defineCommand as defineCommand10 } from "citty";
|
|
8513
|
-
import { readFileSync as
|
|
8881
|
+
import { readFileSync as readFileSync24 } from "fs";
|
|
8514
8882
|
|
|
8515
8883
|
// src/cli/lib/citty-args.ts
|
|
8516
8884
|
function dedupePositionals(bound, rest) {
|
|
@@ -8780,7 +9148,7 @@ var upload = defineCommand10({
|
|
|
8780
9148
|
async run({ args }) {
|
|
8781
9149
|
try {
|
|
8782
9150
|
const t = await resolveTarget(args);
|
|
8783
|
-
const content = args.file === "-" ?
|
|
9151
|
+
const content = args.file === "-" ? readFileSync24(0, "utf-8") : readFileSync24(args.file, "utf-8");
|
|
8784
9152
|
const secrets = parseSecretsUpload(content);
|
|
8785
9153
|
if (Object.keys(secrets).length === 0)
|
|
8786
9154
|
fail(new InputError("No secrets found in the input.", "empty_input"));
|
|
@@ -9036,7 +9404,7 @@ var init_default = defineDeepspaceCommand({
|
|
|
9036
9404
|
// src/cli/commands/status.ts
|
|
9037
9405
|
import { defineCommand as defineCommand11 } from "citty";
|
|
9038
9406
|
import * as p18 from "@clack/prompts";
|
|
9039
|
-
import { existsSync as
|
|
9407
|
+
import { existsSync as existsSync23, readFileSync as readFileSync25 } from "fs";
|
|
9040
9408
|
function timeAgo(iso) {
|
|
9041
9409
|
const ms = Date.now() - Date.parse(iso);
|
|
9042
9410
|
if (!Number.isFinite(ms) || ms < 0) return iso;
|
|
@@ -9061,6 +9429,14 @@ function statusRemoteFailure(error) {
|
|
|
9061
9429
|
json: { state: "unavailable", error: message, ...code ? { code } : {} }
|
|
9062
9430
|
};
|
|
9063
9431
|
}
|
|
9432
|
+
function resolveStatusApp(appDir, wranglerEnv) {
|
|
9433
|
+
if (!wranglerEnv) {
|
|
9434
|
+
return { appName: detectAppName(appDir) ?? "(unnamed)", appId: readAppId(appDir) };
|
|
9435
|
+
}
|
|
9436
|
+
const resolved = resolveAppNameForEnv(readWranglerConfig(appDir), wranglerEnv);
|
|
9437
|
+
if (!resolved.ok) throw new InputError(resolved.reason, "invalid_env");
|
|
9438
|
+
return { appName: resolved.name, appId: readAppId(appDir, wranglerEnv) };
|
|
9439
|
+
}
|
|
9064
9440
|
var status_default = defineCommand11({
|
|
9065
9441
|
meta: {
|
|
9066
9442
|
name: "status",
|
|
@@ -9071,9 +9447,17 @@ var status_default = defineCommand11({
|
|
|
9071
9447
|
type: "boolean",
|
|
9072
9448
|
description: "Emit a single-line JSON result for scripts/agents",
|
|
9073
9449
|
default: false
|
|
9450
|
+
},
|
|
9451
|
+
env: {
|
|
9452
|
+
type: "string",
|
|
9453
|
+
alias: "e",
|
|
9454
|
+
description: "wrangler.toml [env.<name>] slot \u2014 reads that environment\u2019s app identity",
|
|
9455
|
+
required: false
|
|
9074
9456
|
}
|
|
9075
9457
|
},
|
|
9076
9458
|
async run({ args }) {
|
|
9459
|
+
const { wranglerEnv, error: envError } = parseWranglerEnvArg(args.env);
|
|
9460
|
+
if (envError) throw new InputError(envError, "invalid_env");
|
|
9077
9461
|
const lines = [];
|
|
9078
9462
|
const facts = {
|
|
9079
9463
|
loggedIn: false,
|
|
@@ -9105,7 +9489,7 @@ var status_default = defineCommand11({
|
|
|
9105
9489
|
json.services = urls;
|
|
9106
9490
|
if (urlOverrides.length > 0) json.urlOverrides = urlOverrides;
|
|
9107
9491
|
}
|
|
9108
|
-
facts.loggedIn =
|
|
9492
|
+
facts.loggedIn = existsSync23(SESSION_PATH);
|
|
9109
9493
|
let userId = null;
|
|
9110
9494
|
if (!facts.loggedIn) {
|
|
9111
9495
|
lines.push(["Session", "not logged in"]);
|
|
@@ -9114,7 +9498,7 @@ var status_default = defineCommand11({
|
|
|
9114
9498
|
let who = "logged in";
|
|
9115
9499
|
try {
|
|
9116
9500
|
const payload = decodeJwtPayload(
|
|
9117
|
-
|
|
9501
|
+
readFileSync25(TOKEN_PATH, "utf-8").trim()
|
|
9118
9502
|
);
|
|
9119
9503
|
if (payload.email) who = payload.email;
|
|
9120
9504
|
userId = payload.sub ?? null;
|
|
@@ -9129,15 +9513,15 @@ var status_default = defineCommand11({
|
|
|
9129
9513
|
lines.push(["App", "not inside a DeepSpace app directory"]);
|
|
9130
9514
|
json.inApp = false;
|
|
9131
9515
|
} else {
|
|
9132
|
-
const appName =
|
|
9133
|
-
const appId = readAppId(appDir);
|
|
9516
|
+
const { appName, appId } = resolveStatusApp(appDir, wranglerEnv);
|
|
9134
9517
|
lines.push([
|
|
9135
9518
|
"App",
|
|
9136
|
-
`${appName}${appId ? ` (${appId})` : " \u2014 no DEEPSPACE_APP_ID; run `deepspace app init`"}`
|
|
9519
|
+
`${appName}${wranglerEnv ? ` [env.${wranglerEnv}]` : ""}${appId ? ` (${appId})` : " \u2014 no DEEPSPACE_APP_ID; run `deepspace app init`"}`
|
|
9137
9520
|
]);
|
|
9138
9521
|
json.inApp = true;
|
|
9139
9522
|
json.appName = appName;
|
|
9140
9523
|
json.appId = appId;
|
|
9524
|
+
if (wranglerEnv) json.wranglerEnv = wranglerEnv;
|
|
9141
9525
|
const deps = installState(appDir);
|
|
9142
9526
|
const depsInstallCommand = installCommand(appDir);
|
|
9143
9527
|
lines.push([
|
|
@@ -9425,7 +9809,7 @@ var push_default = defineDeepspaceCommand({
|
|
|
9425
9809
|
ensureSpaceRemote(appDir, appId);
|
|
9426
9810
|
if (force) {
|
|
9427
9811
|
spinner2?.message(`Checking the cloud ${branch} tip before force-push\u2026`);
|
|
9428
|
-
const lastPushed = resolveCommit(appDir, `
|
|
9812
|
+
const lastPushed = resolveCommit(appDir, spacePrivateRef(`pushed/${branch}`));
|
|
9429
9813
|
let remoteTip = null;
|
|
9430
9814
|
try {
|
|
9431
9815
|
runGitRemote(appDir, token, [
|
|
@@ -9470,7 +9854,7 @@ var push_default = defineDeepspaceCommand({
|
|
|
9470
9854
|
);
|
|
9471
9855
|
const ok2 = result.status === "up_to_date" || result.status === "committed";
|
|
9472
9856
|
if (ok2) {
|
|
9473
|
-
updateRef(appDir, `
|
|
9857
|
+
updateRef(appDir, spacePrivateRef(`pushed/${branch}`), tipOid);
|
|
9474
9858
|
}
|
|
9475
9859
|
const recoverable = isRecoverablePushFailure(result.status);
|
|
9476
9860
|
const rejectReason = result.reason ?? result.summary;
|
|
@@ -9512,7 +9896,7 @@ function workspaceBranchPullRefusal(branch, trunkBranch) {
|
|
|
9512
9896
|
const id = workspaceIdFromBranch(branch);
|
|
9513
9897
|
if (!id) return null;
|
|
9514
9898
|
const trunk = trunkBranch || "main";
|
|
9515
|
-
const merge = `git merge
|
|
9899
|
+
const merge = `git merge ${spaceTrackingRef(shQuote(trunk))}`;
|
|
9516
9900
|
return {
|
|
9517
9901
|
code: "workspace_branch",
|
|
9518
9902
|
trunk,
|
|
@@ -9535,7 +9919,7 @@ function worktreeHoldingBranch(worktrees, branch, selfPath) {
|
|
|
9535
9919
|
}
|
|
9536
9920
|
function divergedMergeAdvice(branch, hasSelectedCheckout) {
|
|
9537
9921
|
const b = shQuote(branch);
|
|
9538
|
-
return hasSelectedCheckout ? `git merge
|
|
9922
|
+
return hasSelectedCheckout ? `git merge ${spaceTrackingRef(b)}` : `git checkout ${b} && git merge ${spaceTrackingRef(b)}`;
|
|
9539
9923
|
}
|
|
9540
9924
|
var pull_default = defineDeepspaceCommand({
|
|
9541
9925
|
meta: {
|
|
@@ -9608,11 +9992,12 @@ var pull_default = defineDeepspaceCommand({
|
|
|
9608
9992
|
const wsRefusal = workspaceBranchPullRefusal(branch, trunkBranch);
|
|
9609
9993
|
if (wsRefusal) {
|
|
9610
9994
|
const trunkRef = `refs/heads/${wsRefusal.trunk}`;
|
|
9995
|
+
const trunkTrackingRef = spaceTrackingRef(wsRefusal.trunk);
|
|
9611
9996
|
runGitRemote(appDir, token, [
|
|
9612
9997
|
"fetch",
|
|
9613
9998
|
"--quiet",
|
|
9614
9999
|
SPACE_REMOTE,
|
|
9615
|
-
`+${trunkRef}
|
|
10000
|
+
`+${trunkRef}:${trunkTrackingRef}`
|
|
9616
10001
|
]);
|
|
9617
10002
|
spinner2?.stop("Workspace branch.");
|
|
9618
10003
|
const { path: branchWorktreePath2 } = selectedBranchCheckout2();
|
|
@@ -9625,7 +10010,7 @@ var pull_default = defineDeepspaceCommand({
|
|
|
9625
10010
|
const step = branchWorktreePath2 ? selectedCheckoutClean2 ? `Merge the fetched trunk in the checkout that owns ${branch} (${branchWorktreePath2}).` : `The checkout that owns ${branch} (${branchWorktreePath2}) is dirty. Commit or stash there, then rerun \`${pullCommand2}\` from that checkout.` : localBranchExists ? canCheckoutHere2 ? `The branch is not checked out. Check it out here, then rerun \`${pullCommand2}\` to receive the merge step.` : `The branch is not checked out and this checkout is dirty. Commit or stash first (or use a clean worktree), check out ${shQuote(branch)}, then rerun \`${pullCommand2}\`.` : `This clone has not attached the workspace. Attach ${workspaceId}, then rerun \`${pullCommand2}\` from its checkout.`;
|
|
9626
10011
|
const action = branchWorktreePath2 && selectedCheckoutClean2 ? {
|
|
9627
10012
|
cwd: branchWorktreePath2,
|
|
9628
|
-
argv: ["git", "merge",
|
|
10013
|
+
argv: ["git", "merge", trunkTrackingRef]
|
|
9629
10014
|
} : canCheckoutHere2 ? { cwd: appDir, argv: ["git", "checkout", branch] } : !localBranchExists ? {
|
|
9630
10015
|
cwd: appDir,
|
|
9631
10016
|
argv: ["deepspace", "workspace", "attach", workspaceId, "--app", appId]
|
|
@@ -9649,17 +10034,18 @@ var pull_default = defineDeepspaceCommand({
|
|
|
9649
10034
|
);
|
|
9650
10035
|
}
|
|
9651
10036
|
spinner2?.message(`Fetching ${branch} from the cloud repo\u2026`);
|
|
10037
|
+
const trackingRef = spaceTrackingRef(branch);
|
|
9652
10038
|
runGitRemote(appDir, token, [
|
|
9653
10039
|
"fetch",
|
|
9654
10040
|
"--quiet",
|
|
9655
10041
|
SPACE_REMOTE,
|
|
9656
|
-
`+${refName}
|
|
10042
|
+
`+${refName}:${trackingRef}`
|
|
9657
10043
|
]);
|
|
9658
|
-
const remoteOid = resolveCommit(appDir,
|
|
10044
|
+
const remoteOid = resolveCommit(appDir, trackingRef);
|
|
9659
10045
|
if (!remoteOid) {
|
|
9660
10046
|
spinner2?.stop("Fetch failed.");
|
|
9661
10047
|
throw new Refusal(
|
|
9662
|
-
`Fetched, but
|
|
10048
|
+
`Fetched, but ${trackingRef} did not materialize \u2014 retry; if it persists, report it with \`deepspace feedback\`.`,
|
|
9663
10049
|
"fetch_incomplete"
|
|
9664
10050
|
);
|
|
9665
10051
|
}
|
|
@@ -9696,8 +10082,8 @@ var pull_default = defineDeepspaceCommand({
|
|
|
9696
10082
|
integration = "fetched_only_diverged";
|
|
9697
10083
|
}
|
|
9698
10084
|
const qBranch = shQuote(branch);
|
|
9699
|
-
const ffRef = `git merge --ff-only
|
|
9700
|
-
const mergeRef = `git merge
|
|
10085
|
+
const ffRef = `git merge --ff-only ${spaceTrackingRef(qBranch)}`;
|
|
10086
|
+
const mergeRef = `git merge ${spaceTrackingRef(qBranch)}`;
|
|
9701
10087
|
const pullCommand = targetedVcCommand("pull", appId, branch);
|
|
9702
10088
|
const pushCommand = targetedVcCommand("push", appId, branch);
|
|
9703
10089
|
const selectedCheckoutClean = branchWorktreePath !== null && isWorkTreeClean(branchWorktreePath);
|
|
@@ -9719,35 +10105,35 @@ var pull_default = defineDeepspaceCommand({
|
|
|
9719
10105
|
codeForState = "diverged";
|
|
9720
10106
|
if (branchWorktreePath && selectedCheckoutClean) {
|
|
9721
10107
|
const mergeAdvice = divergedMergeAdvice(branch, true);
|
|
9722
|
-
line = `Fetched
|
|
10108
|
+
line = `Fetched ${SPACE_REMOTE}/${branch}. ${branch} and the cloud repo diverged \u2014 run \`${mergeAdvice}\` in ${branchWorktreePath} (no network needed), then \`${pushCommand}\`.`;
|
|
9723
10109
|
recoveryAction = {
|
|
9724
10110
|
cwd: branchWorktreePath,
|
|
9725
|
-
argv: ["git", "merge",
|
|
10111
|
+
argv: ["git", "merge", trackingRef]
|
|
9726
10112
|
};
|
|
9727
10113
|
} else if (branchWorktreePath) {
|
|
9728
|
-
line = `Fetched
|
|
10114
|
+
line = `Fetched ${SPACE_REMOTE}/${branch}. ${branch} and the cloud repo diverged, but its checkout (${branchWorktreePath}) is dirty. Commit or stash there, then rerun \`${pullCommand}\` from that checkout.`;
|
|
9729
10115
|
} else if (canCheckoutHere) {
|
|
9730
|
-
line = `Fetched
|
|
10116
|
+
line = `Fetched ${SPACE_REMOTE}/${branch}. ${branch} and the cloud repo diverged, but ${branch} is not checked out. Check it out here, then rerun \`${pullCommand}\` to receive the merge step.`;
|
|
9731
10117
|
recoveryAction = { cwd: appDir, argv: ["git", "checkout", branch] };
|
|
9732
10118
|
} else {
|
|
9733
|
-
line = `Fetched
|
|
10119
|
+
line = `Fetched ${SPACE_REMOTE}/${branch}. ${branch} and the cloud repo diverged, but ${branch} is not checked out and this checkout is dirty. Commit or stash first (or use a clean worktree), check out ${qBranch}, then rerun \`${pullCommand}\`.`;
|
|
9734
10120
|
}
|
|
9735
10121
|
break;
|
|
9736
10122
|
case "fetched_only_dirty":
|
|
9737
10123
|
codeForState = "dirty_worktree";
|
|
9738
|
-
line = `Fetched
|
|
10124
|
+
line = `Fetched ${SPACE_REMOTE}/${branch}, but the worktree is dirty. Either stash \u2192 \`${ffRef}\` \u2192 \`git stash pop\`, or commit first \u2192 \`${mergeRef}\` (or \`git rebase\`).`;
|
|
9739
10125
|
break;
|
|
9740
10126
|
case "fetched_only_unborn":
|
|
9741
10127
|
codeForState = "dirty_worktree";
|
|
9742
|
-
line = `Fetched
|
|
10128
|
+
line = `Fetched ${SPACE_REMOTE}/${branch} and created ${branch}, but the worktree has uncommitted files. Preserve them in a commit or stash (including untracked files), then restore the checkout; do not run reset --hard until \`git status\` confirms nothing worth keeping remains.`;
|
|
9743
10129
|
break;
|
|
9744
10130
|
case "fetched_only_worktree":
|
|
9745
10131
|
codeForState = "branch_in_worktree";
|
|
9746
10132
|
if (branchWorktreePath && selectedCheckoutClean) {
|
|
9747
|
-
line = `Fetched
|
|
10133
|
+
line = `Fetched ${SPACE_REMOTE}/${branch}, but ${branch} is checked out in another worktree (${branchWorktreePath}) \u2014 its ref was left untouched to keep that worktree in sync. Run \`${pullCommand}\` from there.`;
|
|
9748
10134
|
recoveryAction = targetedVcAction("pull", branchWorktreePath, appId, branch);
|
|
9749
10135
|
} else {
|
|
9750
|
-
line = `Fetched
|
|
10136
|
+
line = `Fetched ${SPACE_REMOTE}/${branch}, but its checkout (${branchWorktreePath ?? "a linked worktree"}) is dirty, so the ref and worktree were left untouched. Commit or stash there, then run \`${pullCommand}\` from that checkout.`;
|
|
9751
10137
|
}
|
|
9752
10138
|
break;
|
|
9753
10139
|
default: {
|
|
@@ -9756,8 +10142,8 @@ var pull_default = defineDeepspaceCommand({
|
|
|
9756
10142
|
}
|
|
9757
10143
|
}
|
|
9758
10144
|
const actionRequired = recoveryAction !== void 0;
|
|
9759
|
-
spinner2?.stop(codeForState ? `Fetched
|
|
9760
|
-
if (!args.json) p20.log.info(`App: ${appId} \xB7
|
|
10145
|
+
spinner2?.stop(codeForState ? `Fetched ${SPACE_REMOTE}/${branch}.` : line);
|
|
10146
|
+
if (!args.json) p20.log.info(`App: ${appId} \xB7 ${SPACE_REMOTE}/${branch} at ${remoteOid.slice(0, 10)}`);
|
|
9761
10147
|
if (codeForState) {
|
|
9762
10148
|
throw new Refusal(line, codeForState, {
|
|
9763
10149
|
actionRequired,
|
|
@@ -9777,18 +10163,18 @@ var pull_default = defineDeepspaceCommand({
|
|
|
9777
10163
|
|
|
9778
10164
|
// src/cli/commands/clone.ts
|
|
9779
10165
|
import * as p21 from "@clack/prompts";
|
|
9780
|
-
import { existsSync as
|
|
9781
|
-
import { resolve as resolve16, basename as basename3, join as
|
|
10166
|
+
import { existsSync as existsSync24, readdirSync as readdirSync6, rmSync as rmSync5 } from "fs";
|
|
10167
|
+
import { resolve as resolve16, basename as basename3, join as join22 } from "path";
|
|
9782
10168
|
function cleanFailedCloneDir(dir) {
|
|
9783
10169
|
let entries;
|
|
9784
10170
|
try {
|
|
9785
10171
|
entries = readdirSync6(dir);
|
|
9786
10172
|
} catch {
|
|
9787
|
-
return
|
|
10173
|
+
return existsSync24(dir) ? ["<unreadable>"] : [];
|
|
9788
10174
|
}
|
|
9789
10175
|
if (entries.length === 1 && entries[0] === ".git") {
|
|
9790
10176
|
try {
|
|
9791
|
-
rmSync5(
|
|
10177
|
+
rmSync5(join22(dir, ".git"), { recursive: true, force: true });
|
|
9792
10178
|
return [];
|
|
9793
10179
|
} catch {
|
|
9794
10180
|
return entries;
|
|
@@ -9797,7 +10183,7 @@ function cleanFailedCloneDir(dir) {
|
|
|
9797
10183
|
return entries;
|
|
9798
10184
|
}
|
|
9799
10185
|
function validateCloneTarget(dir) {
|
|
9800
|
-
if (!
|
|
10186
|
+
if (!existsSync24(dir)) return false;
|
|
9801
10187
|
let entries;
|
|
9802
10188
|
try {
|
|
9803
10189
|
entries = readdirSync6(dir);
|
|
@@ -9911,6 +10297,12 @@ var releases_default = defineDeepspaceCommand({
|
|
|
9911
10297
|
description: "App id or subdomain name (default: the surrounding app directory)",
|
|
9912
10298
|
required: false
|
|
9913
10299
|
},
|
|
10300
|
+
env: {
|
|
10301
|
+
type: "string",
|
|
10302
|
+
alias: "e",
|
|
10303
|
+
description: "wrangler.toml [env.<name>] slot \u2014 selects that environment's app id",
|
|
10304
|
+
required: false
|
|
10305
|
+
},
|
|
9914
10306
|
limit: {
|
|
9915
10307
|
type: "string",
|
|
9916
10308
|
description: "Max entries (default 20)",
|
|
@@ -9919,13 +10311,15 @@ var releases_default = defineDeepspaceCommand({
|
|
|
9919
10311
|
},
|
|
9920
10312
|
async run({ args }) {
|
|
9921
10313
|
const appArg = args.app;
|
|
10314
|
+
const envArg = args.env;
|
|
9922
10315
|
const { limit, error: limitError } = parseLimitArg(args.limit);
|
|
9923
10316
|
if (limitError) throw new Refusal(limitError, "invalid_limit");
|
|
9924
|
-
assertAppTargetResolvable(appArg);
|
|
10317
|
+
assertAppTargetResolvable(appArg, { wranglerEnv: envArg });
|
|
10318
|
+
const { wranglerEnv } = parseWranglerEnvArg(envArg);
|
|
9925
10319
|
const spinner2 = args.json ? null : createSpinner();
|
|
9926
10320
|
spinner2?.start("Loading release history\u2026");
|
|
9927
10321
|
const token = await ensureToken();
|
|
9928
|
-
const appId = await resolveAppTarget(DEPLOY_URL11, token, appArg);
|
|
10322
|
+
const appId = await resolveAppTarget(DEPLOY_URL11, token, appArg, { wranglerEnv: envArg });
|
|
9929
10323
|
const { releases } = await repoApi(DEPLOY_URL11, token, appId).listReleases(limit);
|
|
9930
10324
|
spinner2?.stop(`Loaded ${releases.length} ${releases.length === 1 ? "release" : "releases"}.`);
|
|
9931
10325
|
if (!args.json) {
|
|
@@ -9939,10 +10333,12 @@ var releases_default = defineDeepspaceCommand({
|
|
|
9939
10333
|
`#${r.seq} ${r.id} ${r.kind.padEnd(8)} ${r.createdAt} ${r.actor} ${source} ${rollback}`
|
|
9940
10334
|
);
|
|
9941
10335
|
}
|
|
9942
|
-
p22.log.info(
|
|
10336
|
+
p22.log.info(
|
|
10337
|
+
`Roll back an available release with: deepspace rollback <release-id>${wranglerEnv ? ` --env ${wranglerEnv}` : ""}`
|
|
10338
|
+
);
|
|
9943
10339
|
}
|
|
9944
10340
|
}
|
|
9945
|
-
return { data: { appId, releases } };
|
|
10341
|
+
return { data: { appId, wranglerEnv: wranglerEnv ?? null, releases } };
|
|
9946
10342
|
}
|
|
9947
10343
|
});
|
|
9948
10344
|
|
|
@@ -9986,6 +10382,12 @@ var rollback_default = defineDeepspaceCommand({
|
|
|
9986
10382
|
description: "App id or subdomain name (default: the surrounding app directory)",
|
|
9987
10383
|
required: false
|
|
9988
10384
|
},
|
|
10385
|
+
env: {
|
|
10386
|
+
type: "string",
|
|
10387
|
+
alias: "e",
|
|
10388
|
+
description: "wrangler.toml [env.<name>] slot \u2014 selects that environment's app id",
|
|
10389
|
+
required: false
|
|
10390
|
+
},
|
|
9989
10391
|
"allow-do-deletion": {
|
|
9990
10392
|
type: "boolean",
|
|
9991
10393
|
description: "Proceed even though the target release declares fewer Durable Object classes than the current one \u2014 THEIR STORED DATA IS DELETED.",
|
|
@@ -9994,6 +10396,7 @@ var rollback_default = defineDeepspaceCommand({
|
|
|
9994
10396
|
},
|
|
9995
10397
|
async run({ args }) {
|
|
9996
10398
|
const appArg = args.app;
|
|
10399
|
+
const envArg = args.env;
|
|
9997
10400
|
if (args.release !== void 0) {
|
|
9998
10401
|
const r = String(args.release).trim();
|
|
9999
10402
|
if (!r) {
|
|
@@ -10006,11 +10409,12 @@ var rollback_default = defineDeepspaceCommand({
|
|
|
10006
10409
|
throw new Refusal(`Invalid release id: ${r} (expected rel_<ULID>).`, "invalid_release");
|
|
10007
10410
|
}
|
|
10008
10411
|
}
|
|
10009
|
-
assertAppTargetResolvable(appArg);
|
|
10412
|
+
assertAppTargetResolvable(appArg, { wranglerEnv: envArg });
|
|
10413
|
+
const { wranglerEnv } = parseWranglerEnvArg(envArg);
|
|
10010
10414
|
const spinner2 = args.json ? null : createSpinner();
|
|
10011
10415
|
spinner2?.start("Preparing rollback\u2026");
|
|
10012
10416
|
const token = await ensureToken();
|
|
10013
|
-
const appId = await resolveAppTarget(DEPLOY_URL12, token, appArg);
|
|
10417
|
+
const appId = await resolveAppTarget(DEPLOY_URL12, token, appArg, { wranglerEnv: envArg });
|
|
10014
10418
|
const api4 = repoApi(DEPLOY_URL12, token, appId);
|
|
10015
10419
|
let releaseId = args.release ? String(args.release).trim() : "";
|
|
10016
10420
|
if (!releaseId) {
|
|
@@ -10075,6 +10479,7 @@ Re-run with --allow-do-deletion to accept the data loss.`,
|
|
|
10075
10479
|
bundleRetained: result.bundleRetained ?? null,
|
|
10076
10480
|
url: result.url ?? null,
|
|
10077
10481
|
versionId: result.versionId ?? null,
|
|
10482
|
+
wranglerEnv: wranglerEnv ?? null,
|
|
10078
10483
|
...doClassGuard ? { doClassGuard } : {}
|
|
10079
10484
|
}
|
|
10080
10485
|
};
|
|
@@ -10091,7 +10496,7 @@ import { isAbsolute as isAbsolute6, resolve as resolve17 } from "path";
|
|
|
10091
10496
|
// src/cli/commands/workspace/analysis.ts
|
|
10092
10497
|
import * as p24 from "@clack/prompts";
|
|
10093
10498
|
var MAX_OVERLAP_PATHS = 20;
|
|
10094
|
-
var PEER_REF_PREFIX = "
|
|
10499
|
+
var PEER_REF_PREFIX = `${spacePrivateRef("peers")}/`;
|
|
10095
10500
|
function peerWorkspaceRef(workspaceId) {
|
|
10096
10501
|
return `${PEER_REF_PREFIX}${workspaceId}`;
|
|
10097
10502
|
}
|
|
@@ -10102,7 +10507,7 @@ function formatCount(count) {
|
|
|
10102
10507
|
function fetchTrunk(appDir, token, head) {
|
|
10103
10508
|
if (!head?.startsWith("refs/heads/")) return null;
|
|
10104
10509
|
const branch = head.slice("refs/heads/".length);
|
|
10105
|
-
const remoteRef =
|
|
10510
|
+
const remoteRef = spaceTrackingRef(branch);
|
|
10106
10511
|
runGitRemote(appDir, token, ["fetch", "--quiet", SPACE_REMOTE, `+${head}:${remoteRef}`]);
|
|
10107
10512
|
const oid = resolveCommit(appDir, remoteRef);
|
|
10108
10513
|
return oid ? { branch, ref: remoteRef, oid } : null;
|
|
@@ -10112,7 +10517,7 @@ function localTrunkOid(appDir, refs) {
|
|
|
10112
10517
|
if (!head?.startsWith("refs/heads/")) return null;
|
|
10113
10518
|
const advertised = refs?.refs.find((ref) => ref.name === head)?.oid ?? null;
|
|
10114
10519
|
if (advertised && resolveCommit(appDir, advertised)) return advertised;
|
|
10115
|
-
return resolveCommit(appDir,
|
|
10520
|
+
return resolveCommit(appDir, spaceTrackingRef(head.slice("refs/heads/".length)));
|
|
10116
10521
|
}
|
|
10117
10522
|
function fetchPeerWorkspaceRefs(appDir, token) {
|
|
10118
10523
|
try {
|
|
@@ -10211,8 +10616,8 @@ function printOverlaps(overlaps, json) {
|
|
|
10211
10616
|
|
|
10212
10617
|
// src/cli/commands/workspace/local.ts
|
|
10213
10618
|
import * as p25 from "@clack/prompts";
|
|
10214
|
-
import { mkdirSync as mkdirSync7, readFileSync as
|
|
10215
|
-
import { dirname as dirname9, isAbsolute as isAbsolute5, join as
|
|
10619
|
+
import { mkdirSync as mkdirSync7, readFileSync as readFileSync26, realpathSync as realpathSync5, renameSync as renameSync2, statSync, writeFileSync as writeFileSync9 } from "fs";
|
|
10620
|
+
import { dirname as dirname9, isAbsolute as isAbsolute5, join as join23, relative as relative2, sep as sep2 } from "path";
|
|
10216
10621
|
var WORKSPACE_MARKER = "deepspace-workspace.json";
|
|
10217
10622
|
function excludeWorktreeDir(appDir, dir) {
|
|
10218
10623
|
try {
|
|
@@ -10233,7 +10638,7 @@ function worktreeMarkerPath(worktreeRoot) {
|
|
|
10233
10638
|
const result = runGit(worktreeRoot, ["rev-parse", "--absolute-git-dir"], { allowFail: true });
|
|
10234
10639
|
if (result.status !== 0) return null;
|
|
10235
10640
|
const gitDir = result.stdout.toString("utf-8").trim();
|
|
10236
|
-
return isAbsolute5(gitDir) ?
|
|
10641
|
+
return isAbsolute5(gitDir) ? join23(gitDir, WORKSPACE_MARKER) : null;
|
|
10237
10642
|
} catch {
|
|
10238
10643
|
return null;
|
|
10239
10644
|
}
|
|
@@ -10269,7 +10674,7 @@ function isManagedWorkspaceWorktree(worktreeRoot, workspaceId) {
|
|
|
10269
10674
|
const markerPath = worktreeMarkerPath(worktreeRoot);
|
|
10270
10675
|
if (!markerPath) return false;
|
|
10271
10676
|
try {
|
|
10272
|
-
const marker = JSON.parse(
|
|
10677
|
+
const marker = JSON.parse(readFileSync26(markerPath, "utf-8"));
|
|
10273
10678
|
return marker.version === 1 && marker.workspaceId === workspaceId && marker.mode === "managed-linked";
|
|
10274
10679
|
} catch {
|
|
10275
10680
|
return false;
|
|
@@ -10278,11 +10683,11 @@ function isManagedWorkspaceWorktree(worktreeRoot, workspaceId) {
|
|
|
10278
10683
|
function defaultWorkspaceRoot(appDir, workspaceId) {
|
|
10279
10684
|
const primary = listWorktrees(appDir)[0];
|
|
10280
10685
|
if (!primary) throw new Error("Git did not report a primary worktree");
|
|
10281
|
-
return
|
|
10686
|
+
return join23(primary.path, ".deepspace", "ws", workspaceId.slice(3).toLowerCase());
|
|
10282
10687
|
}
|
|
10283
10688
|
function appDirInWorktree(appDir, worktreeRoot) {
|
|
10284
10689
|
const appRelative = relative2(realpathSync5(repoToplevel(appDir)), realpathSync5(appDir));
|
|
10285
|
-
return appRelative ?
|
|
10690
|
+
return appRelative ? join23(worktreeRoot, appRelative) : worktreeRoot;
|
|
10286
10691
|
}
|
|
10287
10692
|
function materializeWorkspaceWorktree(appDir, worktreeRoot, branch, startPoint, workspaceId, options = {}) {
|
|
10288
10693
|
const createdOid = resolveCommit(appDir, startPoint);
|
|
@@ -10300,7 +10705,7 @@ function materializeWorkspaceWorktree(appDir, worktreeRoot, branch, startPoint,
|
|
|
10300
10705
|
function inOwnLinkedWorktree(appDir, id) {
|
|
10301
10706
|
if (workspaceIdFromBranch(currentBranch(appDir)) !== id) return false;
|
|
10302
10707
|
try {
|
|
10303
|
-
return statSync(
|
|
10708
|
+
return statSync(join23(repoToplevel(appDir), ".git")).isFile();
|
|
10304
10709
|
} catch {
|
|
10305
10710
|
return false;
|
|
10306
10711
|
}
|
|
@@ -10371,7 +10776,7 @@ function switchOffWsBranch(mainDir, trunkBranch) {
|
|
|
10371
10776
|
if (resolveCommit(mainDir, `refs/heads/${trunkBranch}`)) {
|
|
10372
10777
|
return runGit(mainDir, ["switch", "--quiet", trunkBranch], { allowFail: true }).status === 0;
|
|
10373
10778
|
}
|
|
10374
|
-
const remote = resolveCommit(mainDir,
|
|
10779
|
+
const remote = resolveCommit(mainDir, spaceTrackingRef(trunkBranch));
|
|
10375
10780
|
if (remote) {
|
|
10376
10781
|
return runGit(mainDir, ["switch", "--quiet", "-c", trunkBranch, remote], { allowFail: true }).status === 0;
|
|
10377
10782
|
}
|
|
@@ -10684,7 +11089,7 @@ var newWorkspaceCommand = defineDeepspaceCommand({
|
|
|
10684
11089
|
|
|
10685
11090
|
// src/cli/commands/workspace/attach.ts
|
|
10686
11091
|
import * as p27 from "@clack/prompts";
|
|
10687
|
-
import { existsSync as
|
|
11092
|
+
import { existsSync as existsSync25, readdirSync as readdirSync7, rmSync as rmSync6 } from "fs";
|
|
10688
11093
|
import { isAbsolute as isAbsolute7, resolve as resolve18 } from "path";
|
|
10689
11094
|
function finishedWorkspaceMessage(id, view) {
|
|
10690
11095
|
const workspace = view.workspace;
|
|
@@ -10694,7 +11099,7 @@ function finishedWorkspaceMessage(id, view) {
|
|
|
10694
11099
|
return `Workspace ${id} is ${workspace.status} \u2014 its ref is retained briefly (fetch ${workspace.ref} to inspect), but attach only works on active workspaces.`;
|
|
10695
11100
|
}
|
|
10696
11101
|
function cleanFailedFreshAttachDir(dir) {
|
|
10697
|
-
if (!
|
|
11102
|
+
if (!existsSync25(dir)) return [];
|
|
10698
11103
|
let entries;
|
|
10699
11104
|
try {
|
|
10700
11105
|
entries = readdirSync7(dir);
|
|
@@ -10754,11 +11159,12 @@ var attachWorkspaceCommand = defineDeepspaceCommand({
|
|
|
10754
11159
|
});
|
|
10755
11160
|
}
|
|
10756
11161
|
ensureSpaceRemote(appDir, appId2);
|
|
11162
|
+
const localWorkspaceRef = spacePrivateRef(`workspaces/${id}`);
|
|
10757
11163
|
runGitRemote(appDir, token2, [
|
|
10758
11164
|
"fetch",
|
|
10759
11165
|
"--quiet",
|
|
10760
11166
|
SPACE_REMOTE,
|
|
10761
|
-
`+${view2.workspace.ref}:${
|
|
11167
|
+
`+${view2.workspace.ref}:${localWorkspaceRef}`
|
|
10762
11168
|
]);
|
|
10763
11169
|
const tip2 = view2.tipOid ?? view2.workspace.baseOid;
|
|
10764
11170
|
if (!resolveCommit(appDir, tip2)) {
|
|
@@ -10812,7 +11218,7 @@ var attachWorkspaceCommand = defineDeepspaceCommand({
|
|
|
10812
11218
|
process.cwd(),
|
|
10813
11219
|
(typeof args.dir === "string" ? args.dir.trim() : "") || `ws-${id.slice(3).toLowerCase()}`
|
|
10814
11220
|
);
|
|
10815
|
-
if (
|
|
11221
|
+
if (existsSync25(dir)) {
|
|
10816
11222
|
spinner2?.stop("Target exists.");
|
|
10817
11223
|
throw new Refusal(`${dir} already exists \u2014 pass a different directory.`, "dir_exists");
|
|
10818
11224
|
}
|
|
@@ -10827,11 +11233,12 @@ var attachWorkspaceCommand = defineDeepspaceCommand({
|
|
|
10827
11233
|
try {
|
|
10828
11234
|
runGit(process.cwd(), ["init", "--quiet", dir]);
|
|
10829
11235
|
ensureSpaceRemote(dir, appId);
|
|
11236
|
+
const localWorkspaceRef = spacePrivateRef(`workspaces/${id}`);
|
|
10830
11237
|
runGitRemote(dir, token, [
|
|
10831
11238
|
"fetch",
|
|
10832
11239
|
"--quiet",
|
|
10833
11240
|
SPACE_REMOTE,
|
|
10834
|
-
`+${view.workspace.ref}:${
|
|
11241
|
+
`+${view.workspace.ref}:${localWorkspaceRef}`
|
|
10835
11242
|
]);
|
|
10836
11243
|
tip = view.tipOid ?? view.workspace.baseOid;
|
|
10837
11244
|
if (!resolveCommit(dir, tip)) {
|
|
@@ -11129,13 +11536,13 @@ import * as p31 from "@clack/prompts";
|
|
|
11129
11536
|
|
|
11130
11537
|
// src/cli/lib/validation.ts
|
|
11131
11538
|
import { sync as spawnSync7 } from "cross-spawn";
|
|
11132
|
-
import { readFileSync as
|
|
11133
|
-
import { join as
|
|
11539
|
+
import { readFileSync as readFileSync27 } from "fs";
|
|
11540
|
+
import { join as join24 } from "path";
|
|
11134
11541
|
var MAX_SUMMARY_CHARS = 4e3;
|
|
11135
11542
|
var MAX_OUTPUT_BUFFER = 64 * 1024 * 1024;
|
|
11136
11543
|
function configuredCommand(appDir) {
|
|
11137
11544
|
try {
|
|
11138
|
-
const pkg2 = JSON.parse(
|
|
11545
|
+
const pkg2 = JSON.parse(readFileSync27(join24(appDir, "package.json"), "utf-8"));
|
|
11139
11546
|
if (pkg2.scripts?.validate) return `${detectPackageManager(appDir)} run --silent validate`;
|
|
11140
11547
|
} catch {
|
|
11141
11548
|
}
|
|
@@ -11266,7 +11673,7 @@ var landWorkspaceCommand = defineDeepspaceCommand({
|
|
|
11266
11673
|
);
|
|
11267
11674
|
}
|
|
11268
11675
|
const intoRef = `refs/heads/${intoBranch}`;
|
|
11269
|
-
const remoteRef =
|
|
11676
|
+
const remoteRef = spaceTrackingRef(intoBranch);
|
|
11270
11677
|
runGitRemote(appDir, token, ["fetch", "--quiet", SPACE_REMOTE, `+${intoRef}:${remoteRef}`], {
|
|
11271
11678
|
allowFail: true
|
|
11272
11679
|
});
|
|
@@ -11811,7 +12218,7 @@ var git_credential_default = defineCommand13({
|
|
|
11811
12218
|
|
|
11812
12219
|
// src/cli/commands/source.ts
|
|
11813
12220
|
import * as p34 from "@clack/prompts";
|
|
11814
|
-
var TRANSFER_PREFIX = "
|
|
12221
|
+
var TRANSFER_PREFIX = spacePrivateRef("source-transfer");
|
|
11815
12222
|
var source_default = defineDeepspaceCommand({
|
|
11816
12223
|
meta: {
|
|
11817
12224
|
name: "source",
|
|
@@ -12629,8 +13036,8 @@ function reportMigration(migration, json) {
|
|
|
12629
13036
|
|
|
12630
13037
|
// src/cli/cli.ts
|
|
12631
13038
|
var __dirname = dirname10(fileURLToPath3(import.meta.url));
|
|
12632
|
-
var pkg = JSON.parse(
|
|
12633
|
-
if (process.platform === "linux" && !process.env.SSL_CERT_FILE &&
|
|
13039
|
+
var pkg = JSON.parse(readFileSync28(join25(__dirname, "..", "package.json"), "utf-8"));
|
|
13040
|
+
if (process.platform === "linux" && !process.env.SSL_CERT_FILE && existsSync26("/etc/ssl/certs/ca-certificates.crt")) {
|
|
12634
13041
|
process.env.SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt";
|
|
12635
13042
|
}
|
|
12636
13043
|
var create2 = defineCommand14({
|