@kryd/cli 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +2 -0
  2. package/dist/index.js +31 -19
  3. package/package.json +4 -4
package/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  The command-line client for **[Kryd](https://kryd.eu)** — the **European cloud for your AI**. Push a React / Vite / Next.js app and seconds later it's live on a real URL with SSL, one-click managed Postgres and object storage, and an EU-hosted AI gateway already wired in. The same instant `git push → live` loop you know from Vercel/Netlify, on infrastructure that is genuinely European — code **and** AI inference stay inside the EU.
4
4
 
5
+ **Kryd is in beta.** `kryd login` needs a Kryd account: sign up for a beta account at **[kryd.eu/beta](https://kryd.eu/beta)**.
6
+
5
7
  ## Install
6
8
 
7
9
  ```sh
package/dist/index.js CHANGED
@@ -15433,7 +15433,7 @@ function parseDomainRecord(body) {
15433
15433
  function parseProjectDomain(body, label) {
15434
15434
  const d = body;
15435
15435
  const bad = () => new ApiError(`The API returned an unexpected ${label} response.`);
15436
- if (!d || typeof d.id !== "string" || typeof d.host !== "string" || typeof d.status !== "string" || !DOMAIN_STATUSES.includes(d.status) || typeof d.detail !== "string" && d.detail !== null || typeof d.checkedAt !== "string" && d.checkedAt !== null || typeof d.createdAt !== "string" || !Array.isArray(d.records)) {
15436
+ if (!d || typeof d.id !== "string" || typeof d.host !== "string" || typeof d.status !== "string" || !DOMAIN_STATUSES.includes(d.status) || typeof d.detail !== "string" && d.detail !== null || typeof d.checkedAt !== "string" && d.checkedAt !== null || typeof d.createdAt !== "string" || !Array.isArray(d.records) || d.redirectTo !== void 0 && typeof d.redirectTo !== "string") {
15437
15437
  throw bad();
15438
15438
  }
15439
15439
  const records = d.records.map(parseDomainRecord);
@@ -15443,6 +15443,8 @@ function parseProjectDomain(body, label) {
15443
15443
  host: d.host,
15444
15444
  // KRYD-381a — absent from an older API: then it is `web`, the only app there was.
15445
15445
  ...typeof d.app === "string" ? { app: d.app } : {},
15446
+ // KRYD-541 — present only on a redirect domain.
15447
+ ...typeof d.redirectTo === "string" ? { redirectTo: d.redirectTo } : {},
15446
15448
  status: d.status,
15447
15449
  detail: d.detail,
15448
15450
  checkedAt: d.checkedAt,
@@ -15469,11 +15471,11 @@ async function listDomains(apiUrl, token, projectId) {
15469
15471
  domains: body.domains.map((d) => parseProjectDomain(d, "domain-list"))
15470
15472
  };
15471
15473
  }
15472
- async function addDomain(apiUrl, token, projectId, host, app) {
15474
+ async function addDomain(apiUrl, token, projectId, host, app, redirectTo) {
15473
15475
  const res = await fetch(domainsUrl(apiUrl, projectId), {
15474
15476
  method: "POST",
15475
15477
  headers: { "content-type": "application/json", authorization: `Bearer ${token}` },
15476
- body: JSON.stringify({ host, ...app ? { app } : {} })
15478
+ body: JSON.stringify({ host, ...app ? { app } : {}, ...redirectTo !== void 0 ? { redirectTo } : {} })
15477
15479
  });
15478
15480
  if (!res.ok) {
15479
15481
  throw new ApiError(`Domain add failed (${res.status})`, await parseEnvelope(res), res.status);
@@ -18135,7 +18137,7 @@ async function resolveProjectIdByName(apiUrl, token, name) {
18135
18137
  const matches = projects.filter((p) => p.name === name);
18136
18138
  if (matches.length === 0) {
18137
18139
  process.stderr.write(
18138
- `No project named ${name} on this account. Run \`kryd project list\` to see the names.
18140
+ `No project named ${name} on this account. Run \`kryd project list\` and use the NAME column, not SUBDOMAIN.
18139
18141
  `
18140
18142
  );
18141
18143
  process.exitCode = 1;
@@ -18631,22 +18633,22 @@ async function runDomainAdd(opts) {
18631
18633
  if (!ctx) return;
18632
18634
  try {
18633
18635
  const [domain3, list] = await Promise.all([
18634
- addDomain(ctx.apiUrl, ctx.token, ctx.project, opts.host, opts.app),
18636
+ addDomain(ctx.apiUrl, ctx.token, ctx.project, opts.host, opts.app, opts.redirect),
18635
18637
  listDomains(ctx.apiUrl, ctx.token, ctx.project).catch(() => null)
18636
18638
  ]);
18637
18639
  if (domain3.status !== "pending") {
18638
18640
  process.stdout.write(
18639
- `${domain3.host} is already on ${ctx.project}${appSuffix(domain3.app)}: ${DOMAIN_STATUS_TEXT[domain3.status]}.
18641
+ `${domain3.host} is already on ${ctx.project}${domainRole(domain3)}: ${DOMAIN_STATUS_TEXT[domain3.status]}.
18640
18642
  `
18641
18643
  );
18642
18644
  return;
18643
18645
  }
18644
18646
  process.stdout.write(
18645
- `${domain3.host} added to ${ctx.project}${appSuffix(domain3.app)} \u2014 pending until its DNS records exist.
18647
+ `${domain3.host} added to ${ctx.project}${domainRole(domain3)} \u2014 pending until its DNS records exist.
18646
18648
 
18647
18649
  Create these records at your DNS provider:
18648
18650
  ` + formatDomainRecords(domain3.records) + `
18649
- Kryd checks every minute; once they are right it issues a certificate and serves ${domain3.host} from ${domain3.app && domain3.app !== "web" ? `app ${domain3.app}'s` : "your"} production deploy. Follow it with \`kryd domain status ${domain3.host}\`.
18651
+ Kryd checks every minute; once they are right it issues a certificate and ` + (domain3.redirectTo ? `answers every request on ${domain3.host} with a permanent redirect (301) to https://${domain3.redirectTo}, path and query kept.` : `serves ${domain3.host} from ${domain3.app && domain3.app !== "web" ? `app ${domain3.app}'s` : "your"} production deploy.`) + ` Follow it with \`kryd domain status ${domain3.host}\`.
18650
18652
  ` + (list?.projectHost ? `${ctx.project} keeps its own host, ${list.projectHost}.
18651
18653
  ` : "")
18652
18654
  );
@@ -18688,6 +18690,9 @@ async function runDeployHookRemove(opts) {
18688
18690
  function appSuffix(app) {
18689
18691
  return app && app !== "web" ? ` (app ${app})` : "";
18690
18692
  }
18693
+ function domainRole(d) {
18694
+ return d.redirectTo ? ` \u2192 redirects to ${d.redirectTo}` : appSuffix(d.app);
18695
+ }
18691
18696
  async function runDomainRemove(opts) {
18692
18697
  const ctx = domainContext(opts, "kryd domain remove <host> --project <projectId>");
18693
18698
  if (!ctx) return;
@@ -18727,7 +18732,7 @@ ${own}`);
18727
18732
  let out2 = `${ctx.project}: ${list.domains.length} custom domain${list.domains.length === 1 ? "" : "s"}.
18728
18733
  `;
18729
18734
  for (const d2 of list.domains) {
18730
- out2 += ` ${d2.host} ${DOMAIN_STATUS_TEXT[d2.status]}
18735
+ out2 += ` ${d2.host} ${DOMAIN_STATUS_TEXT[d2.status]}${d2.redirectTo ? ` \u2192 redirects to ${d2.redirectTo}` : ""}
18731
18736
  `;
18732
18737
  if (d2.detail) out2 += ` ${d2.detail}
18733
18738
  `;
@@ -18744,6 +18749,8 @@ ${own}`);
18744
18749
  return;
18745
18750
  }
18746
18751
  let out = `${d.host}: ${DOMAIN_STATUS_TEXT[d.status]}.
18752
+ `;
18753
+ if (d.redirectTo) out += ` \u2192 redirects to ${d.redirectTo}
18747
18754
  `;
18748
18755
  if (d.detail) out += ` ${d.detail}
18749
18756
  `;
@@ -19096,15 +19103,17 @@ async function runProjectList(opts) {
19096
19103
  return;
19097
19104
  }
19098
19105
  const linkedId = resolveProjectId(void 0, opts.cwd);
19099
- const nameWidth = projects.reduce((max, p) => Math.max(max, p.name.length), 0);
19100
- const subWidth = projects.reduce((max, p) => Math.max(max, p.subdomain.length), 0);
19101
- const statusWidth = projects.reduce((max, p) => Math.max(max, p.status.length), 0);
19106
+ const nameWidth = projects.reduce((max, p) => Math.max(max, p.name.length), "NAME".length);
19107
+ const subWidth = projects.reduce(
19108
+ (max, p) => Math.max(max, p.subdomain.length),
19109
+ "SUBDOMAIN".length
19110
+ );
19111
+ const statusWidth = projects.reduce((max, p) => Math.max(max, p.status.length), "STATUS".length);
19112
+ const row = (mark, name, sub, status, id) => `${mark} ${name.padEnd(nameWidth)} ${sub.padEnd(subWidth)} ${status.padEnd(statusWidth)} ${id}
19113
+ `;
19114
+ process.stdout.write(row(" ", "NAME", "SUBDOMAIN", "STATUS", "ID"));
19102
19115
  for (const p of projects) {
19103
- const mark = p.id === linkedId ? "*" : " ";
19104
- process.stdout.write(
19105
- `${mark} ${p.name.padEnd(nameWidth)} ${p.subdomain.padEnd(subWidth)} ${p.status.padEnd(statusWidth)} ${p.id}
19106
- `
19107
- );
19116
+ process.stdout.write(row(p.id === linkedId ? "*" : " ", p.name, p.subdomain, p.status, p.id));
19108
19117
  }
19109
19118
  if (projects.some((p) => p.id === linkedId)) {
19110
19119
  process.stdout.write("\n* linked to this directory\n");
@@ -19499,7 +19508,7 @@ Run \`kryd env list\` to see what is set. (If you meant the runtime variable of
19499
19508
  await reportError(err);
19500
19509
  }
19501
19510
  }
19502
- var CLI_VERSION = true ? "0.11.0" : "0.0.0-dev";
19511
+ var CLI_VERSION = true ? "0.12.0" : "0.0.0-dev";
19503
19512
  var program = new Command();
19504
19513
  program.name("kryd").description("Kryd CLI").version(CLI_VERSION);
19505
19514
  program.hook("postAction", async () => {
@@ -19632,7 +19641,10 @@ workflow.command("init").description(
19632
19641
  `worker language: ${SCAFFOLD_LANGUAGES.join(" | ")}`
19633
19642
  ).option("--path <folder>", "the worker's folder inside the app (default: workflows)").option("--only", "a project that runs ONLY a worker: scaffold it at the root, git init, and link").option("--dir <path>", "the project directory, instead of the current one").option("--name <name>", "worker name (and, with --only, project name); defaults to the directory name").option("--no-link", "with --only: only write the files; do not create a Kryd project").option("--api-url <url>", "control-plane API base URL").action((opts) => runWorkflowInit(opts));
19634
19643
  var domain2 = program.command("domain").description("Serve the project on your own hostname (custom domains)");
19635
- domain2.command("add <host>").description("Add a custom domain and print the DNS records to create").option("--project <projectId>", "the project (default: the one linked here)").option("--app <name>", "a project with several web apps: the app the domain serves (default: web)").option("--api-url <url>", "control-plane API base URL").action((host, opts) => runDomainAdd({ ...opts, host }));
19644
+ domain2.command("add <host>").description("Add a custom domain and print the DNS records to create").option("--project <projectId>", "the project (default: the one linked here)").option("--app <name>", "a project with several web apps: the app the domain serves (default: web)").option(
19645
+ "--redirect <host>",
19646
+ "redirect instead of serving: every request answers 301 to https://<host>, path and query kept"
19647
+ ).option("--api-url <url>", "control-plane API base URL").action((host, opts) => runDomainAdd({ ...opts, host }));
19636
19648
  domain2.command("remove <host>").description("Remove a custom domain \u2014 its route and certificate go (asks for confirmation)").option("--project <projectId>", "the project (default: the one linked here)").option("--yes", "skip the confirmation prompt").option("--api-url <url>", "control-plane API base URL").action((host, opts) => runDomainRemove({ ...opts, host }));
19637
19649
  domain2.command("status [host]").description("Show the project's custom domains, or one in detail with what is missing").option("--project <projectId>", "the project (default: the one linked here)").option("--api-url <url>", "control-plane API base URL").action((host, opts) => runDomainStatus({ ...opts, host }));
19638
19650
  function invokedDirectly() {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kryd/cli",
3
- "version": "0.11.0",
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.",
3
+ "version": "0.12.0",
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. Kryd is in beta: sign up for a beta account at https://kryd.eu/beta.",
5
5
  "keywords": [
6
6
  "kryd",
7
7
  "deploy",
@@ -41,9 +41,9 @@
41
41
  "tsx": "^4.19.2",
42
42
  "typescript": "^5.6.3",
43
43
  "vitest": "^2.1.8",
44
+ "@kryd/config-eslint": "0.0.0",
44
45
  "@kryd/shared-types": "0.0.0",
45
- "@kryd/config-ts": "0.0.0",
46
- "@kryd/config-eslint": "0.0.0"
46
+ "@kryd/config-ts": "0.0.0"
47
47
  },
48
48
  "scripts": {
49
49
  "build": "esbuild src/index.ts --bundle --platform=node --format=esm --external:commander --define:__KRYD_VERSION__=\\\"$npm_package_version\\\" --outfile=dist/index.js",