@kryd/cli 0.8.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +272 -74
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -14855,6 +14855,10 @@ function validateBuildEnvVarValue(value) {
|
|
|
14855
14855
|
var BUILD_ENV_PUBLIC_WARNING = "\u26A0 Build-time values are compiled into your app's public bundle \u2014 anyone who loads your site can read them. Never put a secret here.";
|
|
14856
14856
|
var BUILD_ENV_REBUILD_NOTE = "This takes effect at your next BUILD, not your next deploy \u2014 the value is compiled into the image, so redeploying the existing image keeps the old value. Push a commit (`kryd push`) to rebuild.";
|
|
14857
14857
|
|
|
14858
|
+
// ../../packages/shared-types/dist/workflow-run.js
|
|
14859
|
+
var MAX_WEBHOOK_NAME = 32;
|
|
14860
|
+
var WEBHOOK_NAME_RE = new RegExp(`^[a-z0-9](?:[a-z0-9-]{0,${MAX_WEBHOOK_NAME - 2}}[a-z0-9])?$`);
|
|
14861
|
+
|
|
14858
14862
|
// ../../packages/shared-types/dist/index.js
|
|
14859
14863
|
var DEPLOY_STATES = [
|
|
14860
14864
|
"queued",
|
|
@@ -14956,8 +14960,13 @@ function clearToken() {
|
|
|
14956
14960
|
delete config2.token;
|
|
14957
14961
|
writeConfig(config2);
|
|
14958
14962
|
}
|
|
14963
|
+
var lastApiUrl = null;
|
|
14959
14964
|
function resolveApiUrl(flag) {
|
|
14960
|
-
|
|
14965
|
+
lastApiUrl = flag ?? process.env.KRYD_API_URL ?? loadConfig().apiUrl ?? DEFAULT_API_URL;
|
|
14966
|
+
return lastApiUrl;
|
|
14967
|
+
}
|
|
14968
|
+
function currentApiUrl() {
|
|
14969
|
+
return lastApiUrl ?? resolveApiUrl();
|
|
14961
14970
|
}
|
|
14962
14971
|
var DEFAULT_DASHBOARD_URL = "https://app.kryd.eu";
|
|
14963
14972
|
function resolveDashboardUrl(flag) {
|
|
@@ -15046,9 +15055,33 @@ function clearProjectLinkIfMatches(projectId, cwd = process.cwd()) {
|
|
|
15046
15055
|
return false;
|
|
15047
15056
|
}
|
|
15048
15057
|
}
|
|
15058
|
+
function resolvedLink() {
|
|
15059
|
+
return lastLinkResolution;
|
|
15060
|
+
}
|
|
15061
|
+
var lastLinkResolution = null;
|
|
15049
15062
|
function resolveProjectId(explicit, cwd = process.cwd()) {
|
|
15063
|
+
lastLinkResolution = null;
|
|
15050
15064
|
if (explicit) return explicit;
|
|
15051
|
-
|
|
15065
|
+
const root = findProjectLinkDir(cwd);
|
|
15066
|
+
if (!root) return null;
|
|
15067
|
+
const link = loadProjectLink(cwd);
|
|
15068
|
+
if (!link) return null;
|
|
15069
|
+
lastLinkResolution = { root, link };
|
|
15070
|
+
return link.projectId;
|
|
15071
|
+
}
|
|
15072
|
+
function rememberLinkAccount(root, account) {
|
|
15073
|
+
if (!account.accountId) return false;
|
|
15074
|
+
const link = directoryIsLinked(root);
|
|
15075
|
+
if (!link) return false;
|
|
15076
|
+
const slug = account.accountSlug ?? link.accountSlug;
|
|
15077
|
+
if (link.accountId === account.accountId && link.accountSlug === slug) return false;
|
|
15078
|
+
saveProjectLink(root, {
|
|
15079
|
+
...link,
|
|
15080
|
+
accountId: account.accountId,
|
|
15081
|
+
// `exactOptionalPropertyTypes`: an absent key and an explicit `undefined` are different types.
|
|
15082
|
+
...slug ? { accountSlug: slug } : {}
|
|
15083
|
+
});
|
|
15084
|
+
return true;
|
|
15052
15085
|
}
|
|
15053
15086
|
|
|
15054
15087
|
// src/browser-login.ts
|
|
@@ -15136,7 +15169,15 @@ Waiting for approval\u2026
|
|
|
15136
15169
|
// src/client.ts
|
|
15137
15170
|
var ApiError = class extends Error {
|
|
15138
15171
|
envelope;
|
|
15139
|
-
/**
|
|
15172
|
+
/**
|
|
15173
|
+
* The HTTP status of the failed response, when it came from one (used to detect a 404 = gone).
|
|
15174
|
+
*
|
|
15175
|
+
* ⚠️ Still optional because an `ApiError` is also thrown for a well-formed response the CLI
|
|
15176
|
+
* cannot use ("the API returned an unexpected …") and for a stream's own error frame — neither
|
|
15177
|
+
* has a status. Every throw that DOES hold a `Response` now passes it (KRYD-481): the 404
|
|
15178
|
+
* diagnosis keys on the status, and a third of them used to omit it, which made the same
|
|
15179
|
+
* failure explainable or unexplainable depending on which verb the customer typed.
|
|
15180
|
+
*/
|
|
15140
15181
|
status;
|
|
15141
15182
|
constructor(message, envelope, status) {
|
|
15142
15183
|
super(message);
|
|
@@ -15161,7 +15202,8 @@ async function login(apiUrl, creds) {
|
|
|
15161
15202
|
if (!res.ok) {
|
|
15162
15203
|
throw new ApiError(
|
|
15163
15204
|
`Login failed (${res.status})`,
|
|
15164
|
-
await parseEnvelope(res)
|
|
15205
|
+
await parseEnvelope(res),
|
|
15206
|
+
res.status
|
|
15165
15207
|
);
|
|
15166
15208
|
}
|
|
15167
15209
|
const token = res.headers.get("set-auth-token");
|
|
@@ -15177,7 +15219,8 @@ async function whoami(apiUrl, token) {
|
|
|
15177
15219
|
if (!res.ok) {
|
|
15178
15220
|
throw new ApiError(
|
|
15179
15221
|
`Request failed (${res.status})`,
|
|
15180
|
-
await parseEnvelope(res)
|
|
15222
|
+
await parseEnvelope(res),
|
|
15223
|
+
res.status
|
|
15181
15224
|
);
|
|
15182
15225
|
}
|
|
15183
15226
|
return await res.json();
|
|
@@ -15194,7 +15237,8 @@ async function linkProject(apiUrl, token, input) {
|
|
|
15194
15237
|
if (!res.ok) {
|
|
15195
15238
|
throw new ApiError(
|
|
15196
15239
|
`Repo linking failed (${res.status})`,
|
|
15197
|
-
await parseEnvelope(res)
|
|
15240
|
+
await parseEnvelope(res),
|
|
15241
|
+
res.status
|
|
15198
15242
|
);
|
|
15199
15243
|
}
|
|
15200
15244
|
const parsed = await res.json().catch(() => void 0);
|
|
@@ -15222,7 +15266,8 @@ async function attachDatabase(apiUrl, token, input) {
|
|
|
15222
15266
|
if (!res.ok) {
|
|
15223
15267
|
throw new ApiError(
|
|
15224
15268
|
`Database attach failed (${res.status})`,
|
|
15225
|
-
await parseEnvelope(res)
|
|
15269
|
+
await parseEnvelope(res),
|
|
15270
|
+
res.status
|
|
15226
15271
|
);
|
|
15227
15272
|
}
|
|
15228
15273
|
const parsed = await res.json().catch(() => void 0);
|
|
@@ -15247,7 +15292,8 @@ async function createStorage(apiUrl, token, input) {
|
|
|
15247
15292
|
if (!res.ok) {
|
|
15248
15293
|
throw new ApiError(
|
|
15249
15294
|
`Storage create failed (${res.status})`,
|
|
15250
|
-
await parseEnvelope(res)
|
|
15295
|
+
await parseEnvelope(res),
|
|
15296
|
+
res.status
|
|
15251
15297
|
);
|
|
15252
15298
|
}
|
|
15253
15299
|
const parsed = await res.json().catch(() => void 0);
|
|
@@ -15449,7 +15495,8 @@ async function detachDatabase(apiUrl, token, projectId) {
|
|
|
15449
15495
|
if (!res.ok) {
|
|
15450
15496
|
throw new ApiError(
|
|
15451
15497
|
`Database detach failed (${res.status})`,
|
|
15452
|
-
await parseEnvelope(res)
|
|
15498
|
+
await parseEnvelope(res),
|
|
15499
|
+
res.status
|
|
15453
15500
|
);
|
|
15454
15501
|
}
|
|
15455
15502
|
}
|
|
@@ -15459,7 +15506,7 @@ async function getProject(apiUrl, token, projectId) {
|
|
|
15459
15506
|
});
|
|
15460
15507
|
if (res.status === 404) return null;
|
|
15461
15508
|
if (!res.ok) {
|
|
15462
|
-
throw new ApiError(`Reading the project failed (${res.status})`, await parseEnvelope(res));
|
|
15509
|
+
throw new ApiError(`Reading the project failed (${res.status})`, await parseEnvelope(res), res.status);
|
|
15463
15510
|
}
|
|
15464
15511
|
return await res.json();
|
|
15465
15512
|
}
|
|
@@ -15468,7 +15515,7 @@ async function listProjects(apiUrl, token) {
|
|
|
15468
15515
|
headers: { authorization: `Bearer ${token}` }
|
|
15469
15516
|
});
|
|
15470
15517
|
if (!res.ok) {
|
|
15471
|
-
throw new ApiError(`Listing projects failed (${res.status})`, await parseEnvelope(res));
|
|
15518
|
+
throw new ApiError(`Listing projects failed (${res.status})`, await parseEnvelope(res), res.status);
|
|
15472
15519
|
}
|
|
15473
15520
|
return (await res.json()).items;
|
|
15474
15521
|
}
|
|
@@ -15478,7 +15525,7 @@ async function deleteProject(apiUrl, token, projectId) {
|
|
|
15478
15525
|
headers: { authorization: `Bearer ${token}` }
|
|
15479
15526
|
});
|
|
15480
15527
|
if (!res.ok) {
|
|
15481
|
-
throw new ApiError(`Project delete failed (${res.status})`, await parseEnvelope(res));
|
|
15528
|
+
throw new ApiError(`Project delete failed (${res.status})`, await parseEnvelope(res), res.status);
|
|
15482
15529
|
}
|
|
15483
15530
|
return await res.json();
|
|
15484
15531
|
}
|
|
@@ -15513,7 +15560,8 @@ async function detachStorage(apiUrl, token, projectId) {
|
|
|
15513
15560
|
if (!res.ok) {
|
|
15514
15561
|
throw new ApiError(
|
|
15515
15562
|
`Storage detach failed (${res.status})`,
|
|
15516
|
-
await parseEnvelope(res)
|
|
15563
|
+
await parseEnvelope(res),
|
|
15564
|
+
res.status
|
|
15517
15565
|
);
|
|
15518
15566
|
}
|
|
15519
15567
|
}
|
|
@@ -15679,7 +15727,7 @@ async function triggerDeploy(apiUrl, token, projectId) {
|
|
|
15679
15727
|
body: JSON.stringify({ projectId })
|
|
15680
15728
|
});
|
|
15681
15729
|
if (!res.ok) {
|
|
15682
|
-
throw new ApiError(`Deploy trigger failed (${res.status})`, await parseEnvelope(res));
|
|
15730
|
+
throw new ApiError(`Deploy trigger failed (${res.status})`, await parseEnvelope(res), res.status);
|
|
15683
15731
|
}
|
|
15684
15732
|
return (await res.json()).deploymentId;
|
|
15685
15733
|
}
|
|
@@ -15696,7 +15744,7 @@ async function rollbackDeploy(apiUrl, token, projectId, deploymentId) {
|
|
|
15696
15744
|
})
|
|
15697
15745
|
});
|
|
15698
15746
|
if (!res.ok) {
|
|
15699
|
-
throw new ApiError(`Rollback failed (${res.status})`, await parseEnvelope(res));
|
|
15747
|
+
throw new ApiError(`Rollback failed (${res.status})`, await parseEnvelope(res), res.status);
|
|
15700
15748
|
}
|
|
15701
15749
|
return await res.json();
|
|
15702
15750
|
}
|
|
@@ -15710,7 +15758,7 @@ async function redeployProject(apiUrl, token, projectId) {
|
|
|
15710
15758
|
body: JSON.stringify({ projectId })
|
|
15711
15759
|
});
|
|
15712
15760
|
if (!res.ok) {
|
|
15713
|
-
throw new ApiError(`Redeploy failed (${res.status})`, await parseEnvelope(res));
|
|
15761
|
+
throw new ApiError(`Redeploy failed (${res.status})`, await parseEnvelope(res), res.status);
|
|
15714
15762
|
}
|
|
15715
15763
|
return await res.json();
|
|
15716
15764
|
}
|
|
@@ -15719,7 +15767,7 @@ async function listDeployments(apiUrl, token, projectId) {
|
|
|
15719
15767
|
if (projectId) url2.searchParams.set("projectId", projectId);
|
|
15720
15768
|
const res = await fetch(url2, { headers: { authorization: `Bearer ${token}` } });
|
|
15721
15769
|
if (!res.ok) {
|
|
15722
|
-
throw new ApiError(`Listing deploys failed (${res.status})`, await parseEnvelope(res));
|
|
15770
|
+
throw new ApiError(`Listing deploys failed (${res.status})`, await parseEnvelope(res), res.status);
|
|
15723
15771
|
}
|
|
15724
15772
|
return (await res.json()).items;
|
|
15725
15773
|
}
|
|
@@ -15798,7 +15846,7 @@ async function streamDeploy(apiUrl, token, deploymentId, handlers, opts = {}) {
|
|
|
15798
15846
|
headers: { authorization: `Bearer ${token}`, accept: "text/event-stream" }
|
|
15799
15847
|
});
|
|
15800
15848
|
if (!res.ok) {
|
|
15801
|
-
throw new ApiError(`Log stream failed (${res.status})`, await parseEnvelope(res));
|
|
15849
|
+
throw new ApiError(`Log stream failed (${res.status})`, await parseEnvelope(res), res.status);
|
|
15802
15850
|
}
|
|
15803
15851
|
if (!res.body) throw new Error("The log stream returned no body.");
|
|
15804
15852
|
for await (const data of readSseFrames(res.body)) {
|
|
@@ -15842,7 +15890,8 @@ async function streamRuntime(apiUrl, token, id, handlers, opts = {}) {
|
|
|
15842
15890
|
if (!res.ok) {
|
|
15843
15891
|
throw new ApiError(
|
|
15844
15892
|
`Runtime log stream failed (${res.status})`,
|
|
15845
|
-
await parseEnvelope(res)
|
|
15893
|
+
await parseEnvelope(res),
|
|
15894
|
+
res.status
|
|
15846
15895
|
);
|
|
15847
15896
|
}
|
|
15848
15897
|
if (!res.body) throw new Error("The runtime log stream returned no body.");
|
|
@@ -15871,11 +15920,59 @@ async function fetchDeployLog(apiUrl, token, deploymentId, opts = {}) {
|
|
|
15871
15920
|
if (!res.ok) {
|
|
15872
15921
|
throw new ApiError(
|
|
15873
15922
|
`Fetching the stored log failed (${res.status})`,
|
|
15874
|
-
await parseEnvelope(res)
|
|
15923
|
+
await parseEnvelope(res),
|
|
15924
|
+
res.status
|
|
15875
15925
|
);
|
|
15876
15926
|
}
|
|
15877
15927
|
return (await res.json()).log;
|
|
15878
15928
|
}
|
|
15929
|
+
async function fetchPushCredential(apiUrl, token, projectId) {
|
|
15930
|
+
const res = await fetch(
|
|
15931
|
+
`${apiUrl}/repos/${encodeURIComponent(projectId)}/push-credential`,
|
|
15932
|
+
{ headers: { authorization: `Bearer ${token}` } }
|
|
15933
|
+
);
|
|
15934
|
+
if (!res.ok) {
|
|
15935
|
+
throw new ApiError(
|
|
15936
|
+
`Could not fetch the push credential (${res.status})`,
|
|
15937
|
+
await parseEnvelope(res),
|
|
15938
|
+
res.status
|
|
15939
|
+
);
|
|
15940
|
+
}
|
|
15941
|
+
const parsed = await res.json().catch(() => void 0);
|
|
15942
|
+
if (!parsed || typeof parsed.username !== "string" || typeof parsed.password !== "string" || parsed.password.length === 0) {
|
|
15943
|
+
throw new ApiError("The API returned an unexpected push-credential response.");
|
|
15944
|
+
}
|
|
15945
|
+
return { username: parsed.username, password: parsed.password };
|
|
15946
|
+
}
|
|
15947
|
+
|
|
15948
|
+
// src/git-credential.ts
|
|
15949
|
+
async function runGitCredential(operation, opts = {}) {
|
|
15950
|
+
if (operation !== "get") return;
|
|
15951
|
+
const input = parseCredentialInput(opts.stdin ?? "");
|
|
15952
|
+
if (input.protocol && input.protocol !== "https") return;
|
|
15953
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
15954
|
+
const token = loadConfig().token;
|
|
15955
|
+
if (!token) return;
|
|
15956
|
+
const projectId = resolveProjectId(void 0, cwd);
|
|
15957
|
+
if (!projectId) return;
|
|
15958
|
+
try {
|
|
15959
|
+
const cred = await fetchPushCredential(resolveApiUrl(opts.apiUrl), token, projectId);
|
|
15960
|
+
process.stdout.write(`username=${cred.username}
|
|
15961
|
+
password=${cred.password}
|
|
15962
|
+
`);
|
|
15963
|
+
} catch {
|
|
15964
|
+
}
|
|
15965
|
+
}
|
|
15966
|
+
function parseCredentialInput(raw) {
|
|
15967
|
+
const out = {};
|
|
15968
|
+
for (const line of raw.split("\n")) {
|
|
15969
|
+
if (line === "") continue;
|
|
15970
|
+
const eq = line.indexOf("=");
|
|
15971
|
+
if (eq <= 0) continue;
|
|
15972
|
+
out[line.slice(0, eq)] = line.slice(eq + 1);
|
|
15973
|
+
}
|
|
15974
|
+
return out;
|
|
15975
|
+
}
|
|
15879
15976
|
|
|
15880
15977
|
// src/framework.ts
|
|
15881
15978
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
@@ -16863,12 +16960,6 @@ async function promptConfirm(question, io) {
|
|
|
16863
16960
|
// src/git.ts
|
|
16864
16961
|
import { execFileSync, spawnSync } from "node:child_process";
|
|
16865
16962
|
import { resolve } from "node:path";
|
|
16866
|
-
function authenticatedRemoteUrl(cloneUrl, username, token) {
|
|
16867
|
-
const prefix = "https://";
|
|
16868
|
-
if (!cloneUrl.startsWith(prefix)) return cloneUrl;
|
|
16869
|
-
const creds = `${encodeURIComponent(username)}:${encodeURIComponent(token)}@`;
|
|
16870
|
-
return prefix + creds + cloneUrl.slice(prefix.length);
|
|
16871
|
-
}
|
|
16872
16963
|
function configureGitRemote(cwd, remote, url2) {
|
|
16873
16964
|
const run = (args) => execFileSync("git", args, { cwd, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
16874
16965
|
try {
|
|
@@ -16961,9 +17052,32 @@ function pushBranch(cwd, remote, branch, extraArgs) {
|
|
|
16961
17052
|
if (res.status === 0) return { status: "ok" };
|
|
16962
17053
|
return { status: "failed", code: res.status ?? 1 };
|
|
16963
17054
|
}
|
|
17055
|
+
function configureCredentialHelper(cwd, cloneUrl) {
|
|
17056
|
+
const origin = originOf(cloneUrl);
|
|
17057
|
+
if (!origin) return "unavailable";
|
|
17058
|
+
const run = (args) => {
|
|
17059
|
+
try {
|
|
17060
|
+
execFileSync("git", args, { cwd, stdio: ["ignore", "ignore", "ignore"] });
|
|
17061
|
+
return true;
|
|
17062
|
+
} catch {
|
|
17063
|
+
return false;
|
|
17064
|
+
}
|
|
17065
|
+
};
|
|
17066
|
+
const ok = run(["config", `credential.${origin}.helper`, ""]) && run(["config", "--add", `credential.${origin}.helper`, "!kryd git-credential"]) && run(["config", `credential.${origin}.useHttpPath`, "true"]);
|
|
17067
|
+
return ok ? "set" : "unavailable";
|
|
17068
|
+
}
|
|
17069
|
+
function originOf(url2) {
|
|
17070
|
+
try {
|
|
17071
|
+
const parsed = new URL(url2);
|
|
17072
|
+
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") return null;
|
|
17073
|
+
return `${parsed.protocol}//${parsed.host}`;
|
|
17074
|
+
} catch {
|
|
17075
|
+
return null;
|
|
17076
|
+
}
|
|
17077
|
+
}
|
|
16964
17078
|
|
|
16965
17079
|
// src/index.ts
|
|
16966
|
-
function reportError(err) {
|
|
17080
|
+
async function reportError(err) {
|
|
16967
17081
|
if (err instanceof ApiError && err.envelope) {
|
|
16968
17082
|
process.stderr.write(
|
|
16969
17083
|
`${err.envelope.error.code}: ${err.envelope.error.message}
|
|
@@ -16974,6 +17088,63 @@ function reportError(err) {
|
|
|
16974
17088
|
`);
|
|
16975
17089
|
}
|
|
16976
17090
|
process.exitCode = 1;
|
|
17091
|
+
if (err instanceof ApiError) {
|
|
17092
|
+
process.stderr.write(await explainMissingProject(err));
|
|
17093
|
+
}
|
|
17094
|
+
}
|
|
17095
|
+
async function projectIsVisible(token, projectId) {
|
|
17096
|
+
try {
|
|
17097
|
+
return await getProject(currentApiUrl(), token, projectId) !== null;
|
|
17098
|
+
} catch {
|
|
17099
|
+
return null;
|
|
17100
|
+
}
|
|
17101
|
+
}
|
|
17102
|
+
function accountLabel(slug, id) {
|
|
17103
|
+
return slug ?? id;
|
|
17104
|
+
}
|
|
17105
|
+
async function explainMissingProject(err) {
|
|
17106
|
+
if (err.status !== 404) return "";
|
|
17107
|
+
const resolution = resolvedLink();
|
|
17108
|
+
if (!resolution) return "";
|
|
17109
|
+
const token = loadConfig().token;
|
|
17110
|
+
if (!token) return "";
|
|
17111
|
+
if (await projectIsVisible(token, resolution.link.projectId) !== false) return "";
|
|
17112
|
+
let session;
|
|
17113
|
+
try {
|
|
17114
|
+
session = await whoami(currentApiUrl(), token);
|
|
17115
|
+
} catch {
|
|
17116
|
+
return "";
|
|
17117
|
+
}
|
|
17118
|
+
if (!session.accountId) return "";
|
|
17119
|
+
const signedInAs = accountLabel(session.accountSlug, session.accountId);
|
|
17120
|
+
const linkedAccount = resolution.link.accountId;
|
|
17121
|
+
if (!linkedAccount) {
|
|
17122
|
+
return `This folder is linked to project ${resolution.link.projectId}, and you are signed in as ${signedInAs}. That project is not on this account \u2014 if it belongs to another one, switch with \`kryd login\` and run this again.
|
|
17123
|
+
`;
|
|
17124
|
+
}
|
|
17125
|
+
if (linkedAccount === session.accountId) {
|
|
17126
|
+
return `This folder is linked to project ${resolution.link.projectId} on ${signedInAs}, which is the account you are signed in as \u2014 so that project no longer exists.
|
|
17127
|
+
`;
|
|
17128
|
+
}
|
|
17129
|
+
return `This folder is linked to a project of account ${accountLabel(resolution.link.accountSlug, linkedAccount)}, but you are signed in as ${signedInAs}. Switch with \`kryd login\` and run this again.
|
|
17130
|
+
`;
|
|
17131
|
+
}
|
|
17132
|
+
async function backfillLinkAccount() {
|
|
17133
|
+
if (process.exitCode) return;
|
|
17134
|
+
const resolution = resolvedLink();
|
|
17135
|
+
if (!resolution) return;
|
|
17136
|
+
if (resolution.link.accountId && resolution.link.accountSlug) return;
|
|
17137
|
+
const token = loadConfig().token;
|
|
17138
|
+
if (!token) return;
|
|
17139
|
+
if (await projectIsVisible(token, resolution.link.projectId) !== true) return;
|
|
17140
|
+
try {
|
|
17141
|
+
const session = await whoami(currentApiUrl(), token);
|
|
17142
|
+
rememberLinkAccount(resolution.root, {
|
|
17143
|
+
accountId: session.accountId,
|
|
17144
|
+
accountSlug: session.accountSlug
|
|
17145
|
+
});
|
|
17146
|
+
} catch {
|
|
17147
|
+
}
|
|
16977
17148
|
}
|
|
16978
17149
|
function reportNotLinked(example) {
|
|
16979
17150
|
process.stderr.write(
|
|
@@ -17014,7 +17185,7 @@ async function runWhoami(opts = {}) {
|
|
|
17014
17185
|
`
|
|
17015
17186
|
);
|
|
17016
17187
|
} catch (err) {
|
|
17017
|
-
reportError(err);
|
|
17188
|
+
await reportError(err);
|
|
17018
17189
|
}
|
|
17019
17190
|
}
|
|
17020
17191
|
function runLogout() {
|
|
@@ -17073,7 +17244,7 @@ To deploy it: \`kryd push\`. To start over: \`kryd project rm\` first, or delete
|
|
|
17073
17244
|
}
|
|
17074
17245
|
const name = opts.name ?? detected.name;
|
|
17075
17246
|
try {
|
|
17076
|
-
const { project: project2, repo
|
|
17247
|
+
const { project: project2, repo } = await linkProject(apiUrl, token, {
|
|
17077
17248
|
name,
|
|
17078
17249
|
framework,
|
|
17079
17250
|
// First `kryd init` for the account claims the tenant slug (the vanity routing key in
|
|
@@ -17087,6 +17258,14 @@ To deploy it: \`kryd push\`. To start over: \`kryd project rm\` first, or delete
|
|
|
17087
17258
|
let linkNote = "";
|
|
17088
17259
|
try {
|
|
17089
17260
|
saveProjectLink(cwd, { projectId: project2.id });
|
|
17261
|
+
try {
|
|
17262
|
+
const session = await whoami(apiUrl, token);
|
|
17263
|
+
rememberLinkAccount(cwd, {
|
|
17264
|
+
accountId: session.accountId,
|
|
17265
|
+
accountSlug: session.accountSlug
|
|
17266
|
+
});
|
|
17267
|
+
} catch {
|
|
17268
|
+
}
|
|
17090
17269
|
linkNote = "Linked this folder \u2192 .kryd/project.json \u2014 `kryd deploy` / `kryd logs` now work here with no id.\n";
|
|
17091
17270
|
try {
|
|
17092
17271
|
ensureKrydIgnored(cwd);
|
|
@@ -17103,44 +17282,49 @@ To deploy it: \`kryd push\`. To start over: \`kryd project rm\` first, or delete
|
|
|
17103
17282
|
);
|
|
17104
17283
|
}
|
|
17105
17284
|
const branch = repo.defaultBranch;
|
|
17106
|
-
const
|
|
17107
|
-
const
|
|
17108
|
-
const remote = configureGitRemote(cwd, "kryd", authedUrl);
|
|
17285
|
+
const remote = configureGitRemote(cwd, "kryd", repo.cloneUrl);
|
|
17286
|
+
const helper = configureCredentialHelper(cwd, repo.cloneUrl);
|
|
17109
17287
|
let nextStep;
|
|
17110
17288
|
switch (remote.status) {
|
|
17111
17289
|
case "added":
|
|
17112
17290
|
case "updated":
|
|
17113
|
-
nextStep = `${remote.status === "added" ? "Added" : "Updated"} git remote "${remote.remote}"
|
|
17114
|
-
` + (
|
|
17291
|
+
nextStep = `${remote.status === "added" ? "Added" : "Updated"} git remote "${remote.remote}".
|
|
17292
|
+
` + (helper === "set" ? "" : `\u26A0\uFE0F Could not register the credential helper, so git will ask for a password on push.
|
|
17293
|
+
Run \`kryd login\` and re-run \`kryd init\` here to fix it.
|
|
17294
|
+
`) + (remote.tracking === "set" ? `Tracking set: \`git push\` and \`kryd push\` both deploy this branch.
|
|
17115
17295
|
` : remote.tracking === "kept-existing" ? `This branch already tracks another remote, so it was left alone \u2014 deploy with \`kryd push\`.
|
|
17116
17296
|
` : "") + `Next: kryd push # push to deploy (same as \`git push ${remote.remote} ${branch}\`)
|
|
17117
17297
|
`;
|
|
17118
17298
|
break;
|
|
17119
17299
|
case "not-a-repo":
|
|
17120
|
-
nextStep = `No git repo here yet. To deploy
|
|
17300
|
+
nextStep = `No git repo here yet. To deploy:
|
|
17121
17301
|
git init && git add -A && git commit -m "init"
|
|
17122
|
-
git remote add kryd ${
|
|
17302
|
+
git remote add kryd ${repo.cloneUrl}
|
|
17303
|
+
kryd init # again, to register the credential helper
|
|
17123
17304
|
kryd push
|
|
17124
17305
|
`;
|
|
17125
17306
|
break;
|
|
17126
17307
|
case "unavailable":
|
|
17127
17308
|
nextStep = gitAvailable(cwd).status === "no-git" ? `git is not installed, so the deploy remote could not be configured.
|
|
17128
17309
|
Install git (https://git-scm.com/downloads), then re-run \`kryd init\` here.
|
|
17129
|
-
` : `Add the remote, then push to deploy
|
|
17130
|
-
git remote add kryd ${
|
|
17310
|
+
` : `Add the remote, then push to deploy:
|
|
17311
|
+
git remote add kryd ${repo.cloneUrl}
|
|
17131
17312
|
kryd push
|
|
17132
17313
|
`;
|
|
17133
17314
|
break;
|
|
17134
17315
|
}
|
|
17316
|
+
const routing = project2.framework === "workflow" ? `No public URL: a workflow worker dials out to the engine and serves nothing.
|
|
17317
|
+
Scheduled and triggered work runs on your production deploy; preview branches build but do not start a worker.
|
|
17318
|
+
` : `Production URL: https://${project2.subdomain}.${PRODUCTION_TLD}
|
|
17319
|
+
Preview branches deploy to https://<branch>-<hash>-${project2.subdomain}.${PREVIEW_TLD}
|
|
17320
|
+
`;
|
|
17135
17321
|
process.stdout.write(
|
|
17136
17322
|
`Linked "${name}" (${project2.framework}) \u2192 ${repo.htmlUrl}
|
|
17137
|
-
|
|
17138
|
-
Preview branches deploy to https://<branch>-<hash>-${project2.subdomain}.${PREVIEW_TLD}
|
|
17139
|
-
${linkNote}
|
|
17323
|
+
` + routing + `${linkNote}
|
|
17140
17324
|
${nextStep}`
|
|
17141
17325
|
);
|
|
17142
17326
|
} catch (err) {
|
|
17143
|
-
reportError(err);
|
|
17327
|
+
await reportError(err);
|
|
17144
17328
|
}
|
|
17145
17329
|
}
|
|
17146
17330
|
function formatStatus(event) {
|
|
@@ -17256,7 +17440,7 @@ async function runLogs(opts) {
|
|
|
17256
17440
|
}
|
|
17257
17441
|
await followDeploy(apiUrl, token, deploymentId);
|
|
17258
17442
|
} catch (err) {
|
|
17259
|
-
reportError(err);
|
|
17443
|
+
await reportError(err);
|
|
17260
17444
|
}
|
|
17261
17445
|
}
|
|
17262
17446
|
async function runRuntimeLogs(opts) {
|
|
@@ -17303,7 +17487,7 @@ async function runRuntimeLogs(opts) {
|
|
|
17303
17487
|
}
|
|
17304
17488
|
);
|
|
17305
17489
|
} catch (err) {
|
|
17306
|
-
reportError(err);
|
|
17490
|
+
await reportError(err);
|
|
17307
17491
|
} finally {
|
|
17308
17492
|
process.off("SIGINT", onSigint);
|
|
17309
17493
|
}
|
|
@@ -17327,7 +17511,7 @@ async function runDeploy(opts) {
|
|
|
17327
17511
|
`);
|
|
17328
17512
|
await followDeploy(apiUrl, token, deploymentId, { render: renderFor(opts.logs) });
|
|
17329
17513
|
} catch (err) {
|
|
17330
|
-
reportError(err);
|
|
17514
|
+
await reportError(err);
|
|
17331
17515
|
}
|
|
17332
17516
|
}
|
|
17333
17517
|
function renderFor(logs) {
|
|
@@ -17465,7 +17649,7 @@ async function runPush(opts) {
|
|
|
17465
17649
|
estimateFrom: recent
|
|
17466
17650
|
});
|
|
17467
17651
|
} catch (err) {
|
|
17468
|
-
reportError(err);
|
|
17652
|
+
await reportError(err);
|
|
17469
17653
|
}
|
|
17470
17654
|
}
|
|
17471
17655
|
async function runRollback(opts) {
|
|
@@ -17495,7 +17679,7 @@ async function runRollback(opts) {
|
|
|
17495
17679
|
);
|
|
17496
17680
|
await followDeploy(apiUrl, token, deploymentId, { render: renderFor(opts.logs) });
|
|
17497
17681
|
} catch (err) {
|
|
17498
|
-
reportError(err);
|
|
17682
|
+
await reportError(err);
|
|
17499
17683
|
}
|
|
17500
17684
|
}
|
|
17501
17685
|
async function runRedeploy(opts) {
|
|
@@ -17524,7 +17708,7 @@ ${note}
|
|
|
17524
17708
|
);
|
|
17525
17709
|
await followDeploy(apiUrl, token, deploymentId, { render: renderFor(opts.logs) });
|
|
17526
17710
|
} catch (err) {
|
|
17527
|
-
reportError(err);
|
|
17711
|
+
await reportError(err);
|
|
17528
17712
|
}
|
|
17529
17713
|
}
|
|
17530
17714
|
async function runDbAdd(opts) {
|
|
@@ -17589,7 +17773,7 @@ The connection string will be injected as DATABASE_URL on your next deploy.
|
|
|
17589
17773
|
retryCmd: `kryd db status ${project2}`
|
|
17590
17774
|
});
|
|
17591
17775
|
} catch (err) {
|
|
17592
|
-
reportError(err);
|
|
17776
|
+
await reportError(err);
|
|
17593
17777
|
}
|
|
17594
17778
|
}
|
|
17595
17779
|
function reportSettleResult(result, opts) {
|
|
@@ -17636,7 +17820,7 @@ Its S3 credentials will be injected on your next deploy.
|
|
|
17636
17820
|
retryCmd: `kryd storage status ${project2}`
|
|
17637
17821
|
});
|
|
17638
17822
|
} catch (err) {
|
|
17639
|
-
reportError(err);
|
|
17823
|
+
await reportError(err);
|
|
17640
17824
|
}
|
|
17641
17825
|
}
|
|
17642
17826
|
function reportDetachResult(result, opts) {
|
|
@@ -17679,7 +17863,7 @@ async function resolveProjectIdByName(apiUrl, token, name) {
|
|
|
17679
17863
|
try {
|
|
17680
17864
|
projects = await listProjects(apiUrl, token);
|
|
17681
17865
|
} catch (err) {
|
|
17682
|
-
reportError(err);
|
|
17866
|
+
await reportError(err);
|
|
17683
17867
|
return null;
|
|
17684
17868
|
}
|
|
17685
17869
|
const matches = projects.filter((p) => p.name === name);
|
|
@@ -17740,7 +17924,7 @@ async function runProjectRemove(opts) {
|
|
|
17740
17924
|
}
|
|
17741
17925
|
resources = project2.status === "delete_failed" ? ["whatever the previous attempt did not manage to remove"] : await describeProjectResources(apiUrl, token, projectId);
|
|
17742
17926
|
} catch (err) {
|
|
17743
|
-
reportError(err);
|
|
17927
|
+
await reportError(err);
|
|
17744
17928
|
return;
|
|
17745
17929
|
}
|
|
17746
17930
|
if (!opts.yes) {
|
|
@@ -17777,7 +17961,7 @@ async function runProjectRemove(opts) {
|
|
|
17777
17961
|
);
|
|
17778
17962
|
await followProjectDeletion(apiUrl, token, projectId, project2.name, opts);
|
|
17779
17963
|
} catch (err) {
|
|
17780
|
-
reportError(err);
|
|
17964
|
+
await reportError(err);
|
|
17781
17965
|
}
|
|
17782
17966
|
}
|
|
17783
17967
|
async function followProjectDeletion(apiUrl, token, projectId, name, opts) {
|
|
@@ -17853,7 +18037,7 @@ async function runDbRemove(opts) {
|
|
|
17853
18037
|
retryCmd: `kryd db remove ${project2}`
|
|
17854
18038
|
});
|
|
17855
18039
|
} catch (err) {
|
|
17856
|
-
reportError(err);
|
|
18040
|
+
await reportError(err);
|
|
17857
18041
|
}
|
|
17858
18042
|
}
|
|
17859
18043
|
async function runAiAdd(opts) {
|
|
@@ -17878,7 +18062,7 @@ async function runAiAdd(opts) {
|
|
|
17878
18062
|
`
|
|
17879
18063
|
);
|
|
17880
18064
|
} catch (err) {
|
|
17881
|
-
reportError(err);
|
|
18065
|
+
await reportError(err);
|
|
17882
18066
|
}
|
|
17883
18067
|
}
|
|
17884
18068
|
async function runAiRemove(opts) {
|
|
@@ -17898,7 +18082,7 @@ async function runAiRemove(opts) {
|
|
|
17898
18082
|
try {
|
|
17899
18083
|
current = await getAiStatus(apiUrl, token, project2);
|
|
17900
18084
|
} catch (err) {
|
|
17901
|
-
reportError(err);
|
|
18085
|
+
await reportError(err);
|
|
17902
18086
|
return;
|
|
17903
18087
|
}
|
|
17904
18088
|
if (!current.enabled) {
|
|
@@ -17923,7 +18107,7 @@ AI_GATEWAY_URL and AI_GATEWAY_TOKEN stop being injected from your next deploy (k
|
|
|
17923
18107
|
`
|
|
17924
18108
|
);
|
|
17925
18109
|
} catch (err) {
|
|
17926
|
-
reportError(err);
|
|
18110
|
+
await reportError(err);
|
|
17927
18111
|
}
|
|
17928
18112
|
}
|
|
17929
18113
|
async function reportResourceStatus(opts) {
|
|
@@ -17940,12 +18124,12 @@ Remove it before attaching another.
|
|
|
17940
18124
|
process.stdout.write(`${opts.project}: ${opts.noun} ${result.status}.
|
|
17941
18125
|
`);
|
|
17942
18126
|
} catch (err) {
|
|
17943
|
-
if (err instanceof ApiError && err.status === 404) {
|
|
18127
|
+
if (err instanceof ApiError && err.status === 404 && await projectIsVisible(opts.token, opts.project) === true) {
|
|
17944
18128
|
process.stdout.write(`${opts.project}: no ${opts.noun} attached.
|
|
17945
18129
|
`);
|
|
17946
18130
|
return;
|
|
17947
18131
|
}
|
|
17948
|
-
reportError(err);
|
|
18132
|
+
await reportError(err);
|
|
17949
18133
|
}
|
|
17950
18134
|
}
|
|
17951
18135
|
async function runDbStatus(opts) {
|
|
@@ -17964,7 +18148,8 @@ async function runDbStatus(opts) {
|
|
|
17964
18148
|
await reportResourceStatus({
|
|
17965
18149
|
read: () => getDatabaseStatus(apiUrl, token, project2),
|
|
17966
18150
|
noun: "database",
|
|
17967
|
-
project: project2
|
|
18151
|
+
project: project2,
|
|
18152
|
+
token
|
|
17968
18153
|
});
|
|
17969
18154
|
}
|
|
17970
18155
|
async function runStorageStatus(opts) {
|
|
@@ -17983,7 +18168,8 @@ async function runStorageStatus(opts) {
|
|
|
17983
18168
|
await reportResourceStatus({
|
|
17984
18169
|
read: () => getStorageStatus(apiUrl, token, project2),
|
|
17985
18170
|
noun: "object storage",
|
|
17986
|
-
project: project2
|
|
18171
|
+
project: project2,
|
|
18172
|
+
token
|
|
17987
18173
|
});
|
|
17988
18174
|
}
|
|
17989
18175
|
async function runAiStatus(opts) {
|
|
@@ -18012,7 +18198,7 @@ async function runAiStatus(opts) {
|
|
|
18012
18198
|
`
|
|
18013
18199
|
);
|
|
18014
18200
|
} catch (err) {
|
|
18015
|
-
reportError(err);
|
|
18201
|
+
await reportError(err);
|
|
18016
18202
|
}
|
|
18017
18203
|
}
|
|
18018
18204
|
function isoDay(iso) {
|
|
@@ -18052,7 +18238,7 @@ HATCHET_CLIENT_TOKEN will be injected on your next deploy (kryd deploy)` + (stat
|
|
|
18052
18238
|
` : ".\n")
|
|
18053
18239
|
);
|
|
18054
18240
|
} catch (err) {
|
|
18055
|
-
reportError(err);
|
|
18241
|
+
await reportError(err);
|
|
18056
18242
|
}
|
|
18057
18243
|
}
|
|
18058
18244
|
async function runWorkflowRemove(opts) {
|
|
@@ -18072,7 +18258,7 @@ async function runWorkflowRemove(opts) {
|
|
|
18072
18258
|
try {
|
|
18073
18259
|
current = await getWorkflowStatus(apiUrl, token, project2);
|
|
18074
18260
|
} catch (err) {
|
|
18075
|
-
reportError(err);
|
|
18261
|
+
await reportError(err);
|
|
18076
18262
|
return;
|
|
18077
18263
|
}
|
|
18078
18264
|
if (!current.enabled) {
|
|
@@ -18097,7 +18283,7 @@ Workflow history, crons and schedules stay until the project is deleted.
|
|
|
18097
18283
|
`
|
|
18098
18284
|
);
|
|
18099
18285
|
} catch (err) {
|
|
18100
|
-
reportError(err);
|
|
18286
|
+
await reportError(err);
|
|
18101
18287
|
}
|
|
18102
18288
|
}
|
|
18103
18289
|
async function runWorkflowStatus(opts) {
|
|
@@ -18137,7 +18323,7 @@ async function runWorkflowStatus(opts) {
|
|
|
18137
18323
|
);
|
|
18138
18324
|
}
|
|
18139
18325
|
} catch (err) {
|
|
18140
|
-
reportError(err);
|
|
18326
|
+
await reportError(err);
|
|
18141
18327
|
}
|
|
18142
18328
|
}
|
|
18143
18329
|
async function runWorkflowInit(opts) {
|
|
@@ -18290,7 +18476,7 @@ async function runStorageRemove(opts) {
|
|
|
18290
18476
|
retryCmd: `kryd storage remove ${project2}`
|
|
18291
18477
|
});
|
|
18292
18478
|
} catch (err) {
|
|
18293
|
-
reportError(err);
|
|
18479
|
+
await reportError(err);
|
|
18294
18480
|
}
|
|
18295
18481
|
}
|
|
18296
18482
|
function splitKeyValue(spec) {
|
|
@@ -18329,7 +18515,7 @@ async function runProjectList(opts) {
|
|
|
18329
18515
|
try {
|
|
18330
18516
|
projects = await listProjects(apiUrl, token);
|
|
18331
18517
|
} catch (err) {
|
|
18332
|
-
reportError(err);
|
|
18518
|
+
await reportError(err);
|
|
18333
18519
|
return;
|
|
18334
18520
|
}
|
|
18335
18521
|
if (projects.length === 0) {
|
|
@@ -18437,7 +18623,7 @@ Set one with \`kryd env set KEY --stdin\`, or attach a database, storage or the
|
|
|
18437
18623
|
out += "\nValues are never shown. This is the stored set \u2014 runtime changes reach your container at its next deploy (run `kryd redeploy` to apply them now)" + (buildVars.length > 0 ? ", and build-time changes at its next build.\n" : ".\n");
|
|
18438
18624
|
process.stdout.write(out);
|
|
18439
18625
|
} catch (err) {
|
|
18440
|
-
reportError(err);
|
|
18626
|
+
await reportError(err);
|
|
18441
18627
|
}
|
|
18442
18628
|
}
|
|
18443
18629
|
function toDotenvLine(key, value) {
|
|
@@ -18506,7 +18692,7 @@ ${body}
|
|
|
18506
18692
|
"These are your own values, read back from Kryd. Managed values (DATABASE_URL, storage, the AI gateway) are never pulled.\n"
|
|
18507
18693
|
);
|
|
18508
18694
|
} catch (err) {
|
|
18509
|
-
reportError(err);
|
|
18695
|
+
await reportError(err);
|
|
18510
18696
|
}
|
|
18511
18697
|
}
|
|
18512
18698
|
async function resolveEnvValue(inline, opts) {
|
|
@@ -18639,7 +18825,7 @@ async function runEnvSet(opts) {
|
|
|
18639
18825
|
${NEXT_BUILD_NOTE}` : NEXT_DEPLOY_NOTE)
|
|
18640
18826
|
);
|
|
18641
18827
|
} catch (err) {
|
|
18642
|
-
reportError(err);
|
|
18828
|
+
await reportError(err);
|
|
18643
18829
|
}
|
|
18644
18830
|
}
|
|
18645
18831
|
async function runEnvRemove(opts) {
|
|
@@ -18699,7 +18885,7 @@ Run \`kryd env list\` to see what is set. (If you meant the runtime variable of
|
|
|
18699
18885
|
return;
|
|
18700
18886
|
}
|
|
18701
18887
|
} catch (err) {
|
|
18702
|
-
reportError(err);
|
|
18888
|
+
await reportError(err);
|
|
18703
18889
|
return;
|
|
18704
18890
|
}
|
|
18705
18891
|
}
|
|
@@ -18737,18 +18923,29 @@ Run \`kryd env list\` to see what is set. (If you meant the runtime variable of
|
|
|
18737
18923
|
`)
|
|
18738
18924
|
);
|
|
18739
18925
|
} catch (err) {
|
|
18740
|
-
reportError(err);
|
|
18926
|
+
await reportError(err);
|
|
18741
18927
|
}
|
|
18742
18928
|
}
|
|
18743
|
-
var CLI_VERSION = true ? "0.8.
|
|
18929
|
+
var CLI_VERSION = true ? "0.8.1" : "0.0.0-dev";
|
|
18744
18930
|
var program = new Command();
|
|
18745
18931
|
program.name("kryd").description("Kryd CLI").version(CLI_VERSION);
|
|
18932
|
+
program.hook("postAction", async () => {
|
|
18933
|
+
await backfillLinkAccount();
|
|
18934
|
+
});
|
|
18746
18935
|
program.command("login").description("Sign in via the browser (default) and store a token").option("--email <email>", "account email (with --password; non-interactive escape hatch)").option("--password <password>", "account password (with --email; visible in `ps` \u2014 prefer the browser flow)").option(
|
|
18747
18936
|
"--token <token>",
|
|
18748
18937
|
"supply a token instead of the browser flow (prefer $KRYD_TOKEN \u2014 flags are visible in `ps`)"
|
|
18749
18938
|
).option("--api-url <url>", "control-plane API base URL").option("--dashboard-url <url>", "dashboard base URL for the browser approve page (default app.kryd.eu)").action((opts) => runLogin(opts));
|
|
18750
18939
|
program.command("whoami").description("Show the current account").option("--api-url <url>", "control-plane API base URL").action((opts) => runWhoami(opts));
|
|
18751
18940
|
program.command("logout").description("Clear the stored token").action(() => runLogout());
|
|
18941
|
+
program.command("git-credential <operation>", { hidden: true }).description("git credential helper (invoked by git, not by you)").option("--api-url <url>", "control-plane API base URL").action(async (operation, opts) => {
|
|
18942
|
+
const chunks = [];
|
|
18943
|
+
for await (const chunk of process.stdin) chunks.push(Buffer.from(chunk));
|
|
18944
|
+
await runGitCredential(operation, {
|
|
18945
|
+
stdin: Buffer.concat(chunks).toString("utf8"),
|
|
18946
|
+
...opts.apiUrl ? { apiUrl: opts.apiUrl } : {}
|
|
18947
|
+
});
|
|
18948
|
+
});
|
|
18752
18949
|
program.command("init").description("Link this project's repo + register its push webhook").option("--name <name>", "project name (defaults to package.json name / dir)").option(
|
|
18753
18950
|
"--framework <framework>",
|
|
18754
18951
|
"react-router | nextjs | vite-spa | node (auto-detected if omitted; `workflow` comes from a committed kryd.json)"
|
|
@@ -18865,6 +19062,7 @@ if (invokedDirectly()) {
|
|
|
18865
19062
|
});
|
|
18866
19063
|
}
|
|
18867
19064
|
export {
|
|
19065
|
+
backfillLinkAccount,
|
|
18868
19066
|
program,
|
|
18869
19067
|
runAiAdd,
|
|
18870
19068
|
runAiRemove,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kryd/cli",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "Kryd CLI — push a React / Vite / Next.js app to the European cloud for your AI: git push → live with SSL, one-click managed Postgres & object storage, and an EU-hosted AI gateway already wired in. Your code and your model calls stay in the EU.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"kryd",
|
|
@@ -50,8 +50,8 @@
|
|
|
50
50
|
"typescript": "^5.6.3",
|
|
51
51
|
"vitest": "^2.1.8",
|
|
52
52
|
"@kryd/shared-types": "0.0.0",
|
|
53
|
-
"@kryd/config-
|
|
54
|
-
"@kryd/config-
|
|
53
|
+
"@kryd/config-ts": "0.0.0",
|
|
54
|
+
"@kryd/config-eslint": "0.0.0"
|
|
55
55
|
},
|
|
56
56
|
"scripts": {
|
|
57
57
|
"build": "esbuild src/index.ts --bundle --platform=node --format=esm --external:commander --define:__KRYD_VERSION__=\\\"$npm_package_version\\\" --outfile=dist/index.js",
|