@dashai/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.
package/dist/bin.js CHANGED
@@ -1382,8 +1382,13 @@ import { NextResponse } from 'next/server';
1382
1382
  import { db } from '@dashai/generated';
1383
1383
 
1384
1384
  export async function GET() {
1385
- const page = await db.items.list({ limit: 50 });
1386
- return NextResponse.json(page.rows);
1385
+ // \`db.<table>.list()\` resolves to the rows array itself \u2014 the typed
1386
+ // client unwraps the \`{ rows, total, ... }\` page envelope (see the
1387
+ // generated \`client/tables.d.ts\`: \`list(): Promise<ItemsRow[]>\`).
1388
+ // Don't reach for \`.rows\` here: it's \`undefined\` on an array, and
1389
+ // \`NextResponse.json(undefined)\` throws "Value is not JSON serializable".
1390
+ const rows = await db.items.list({ limit: 50 });
1391
+ return NextResponse.json(rows);
1387
1392
  }
1388
1393
 
1389
1394
  export async function POST(request: Request) {
@@ -2504,6 +2509,9 @@ async function tryProvisionDevInstall(args) {
2504
2509
  apiKey: response.api_key,
2505
2510
  apiKeyId: response.api_key_id,
2506
2511
  installationId: response.installation.id,
2512
+ // Cache the workspace so `dashwise dev` can default its dev-SSO-session
2513
+ // workspace to it — no re-passing `--workspace` for multi-workspace users.
2514
+ workspaceId: workspace2.id,
2507
2515
  expiresAt: response.api_key_expires_at
2508
2516
  });
2509
2517
  } catch (err) {
@@ -3427,9 +3435,14 @@ async function devCommand(options) {
3427
3435
  if (explicitInstallationId && explicitInstallationId !== "local") {
3428
3436
  installationIdEnv = explicitInstallationId;
3429
3437
  } else if (reuseDevSessionId) ; else {
3438
+ const effectiveWorkspace = options.workspace ?? moduleEntry?.workspaceId?.toString();
3430
3439
  let workspaceContext;
3431
3440
  try {
3432
- workspaceContext = await resolveTargetWorkspace(apiUrl, apiToken, options.workspace);
3441
+ workspaceContext = await resolveTargetWorkspace(
3442
+ apiUrl,
3443
+ apiToken,
3444
+ effectiveWorkspace
3445
+ );
3433
3446
  } catch (err) {
3434
3447
  fail(err.message);
3435
3448
  return 1;
@@ -5522,7 +5535,11 @@ async function modulePublishCommand(options) {
5522
5535
  method: "POST",
5523
5536
  headers: {
5524
5537
  Accept: "application/json",
5525
- Authorization: `Bearer ${cfg.token}`
5538
+ Authorization: `Bearer ${cfg.token}`,
5539
+ // Opt into the async (202 + poll) contract. On the CodeBuild backend a
5540
+ // markerless client is rejected with 426; the E2B backend ignores it
5541
+ // and still responds synchronously (201).
5542
+ "X-Dashwise-CLI-Async": "1"
5526
5543
  },
5527
5544
  body: form
5528
5545
  });
@@ -5533,6 +5550,12 @@ async function modulePublishCommand(options) {
5533
5550
  const body = await res.json().catch(() => null);
5534
5551
  if (!res.ok) {
5535
5552
  const env = body && typeof body === "object" ? body : null;
5553
+ if (res.status === 426) {
5554
+ fail(
5555
+ `Your @dashai/cli is out of date for this backend. Upgrade with ${code("npm i -g @dashai/cli@latest")}, then re-run ${code("dashwise module publish")}.`
5556
+ );
5557
+ return 1;
5558
+ }
5536
5559
  fail(
5537
5560
  `Publish failed (${res.status}${env?.code ? ` ${env.code}` : ""}): ${env?.message ?? "(no message)"}`
5538
5561
  );
@@ -5541,16 +5564,40 @@ async function modulePublishCommand(options) {
5541
5564
  }
5542
5565
  return 1;
5543
5566
  }
5567
+ if (options.dryRun) {
5568
+ const dr = body;
5569
+ const target = dr.target_version ?? dr.version;
5570
+ if (options.json) out(JSON.stringify(body));
5571
+ else success(`Dry run OK \u2014 would publish ${code(`v${target ?? "?"}`)}`);
5572
+ return 0;
5573
+ }
5574
+ if (res.status === 202) {
5575
+ const enq = body;
5576
+ if (!enq?.build_id) {
5577
+ fail("Publish enqueued but the response was missing a build id.");
5578
+ return 1;
5579
+ }
5580
+ if (options.noWait) {
5581
+ success(`Build ${code(`#${enq.build_id}`)} queued for ${code(mod.slug)}.`);
5582
+ info(`Not waiting (${code("--no-wait")}). Re-run publish or poll the build to check.`);
5583
+ if (options.json) out(JSON.stringify(enq));
5584
+ return 0;
5585
+ }
5586
+ if (!options.json) {
5587
+ info(`Build ${code(`#${enq.build_id}`)} queued \u2014 building on the platform\u2026`);
5588
+ }
5589
+ return pollBuild(enq.build_id, enq.module_id, mod.slug, options);
5590
+ }
5544
5591
  const result = body;
5545
5592
  if (!result) {
5546
5593
  fail("Publish succeeded but the response body was empty or malformed.");
5547
5594
  return 1;
5548
5595
  }
5549
- if (options.dryRun) {
5550
- success(`Dry run OK \u2014 would publish ${code(`v${result.version}`)}`);
5551
- } else {
5552
- success(`Published ${code(mod.slug)} ${code(`v${result.version}`)}`);
5596
+ if (options.json) {
5597
+ out(JSON.stringify(result));
5598
+ return 0;
5553
5599
  }
5600
+ success(`Published ${code(mod.slug)} ${code(`v${result.version}`)}`);
5554
5601
  info(`Bundle: ${code(result.bundle_url)}`);
5555
5602
  info(`Hash: ${dim(result.bundle_hash)}`);
5556
5603
  info(`Size: ${formatBytes2(result.bytes_uploaded)}`);
@@ -5560,9 +5607,61 @@ async function modulePublishCommand(options) {
5560
5607
  out(` ${dim("\u2022")} ${w}`);
5561
5608
  }
5562
5609
  }
5563
- if (process.stdout.isTTY && !options.dryRun) outro("Done.");
5610
+ if (process.stdout.isTTY) outro("Done.");
5611
+ return 0;
5612
+ }
5613
+ async function pollBuild(buildId, moduleId, slug, options) {
5614
+ const timeoutMs = (options.timeoutSec ?? 360) * 1e3;
5615
+ const intervalMs = options.pollIntervalMs ?? 4e3;
5616
+ const deadline = Date.now() + timeoutMs;
5617
+ let lastStatus = "";
5618
+ while (Date.now() < deadline) {
5619
+ let build;
5620
+ try {
5621
+ build = await apiRequest(
5622
+ "GET",
5623
+ `/api/modules/${moduleId}/builds/${buildId}`
5624
+ );
5625
+ } catch {
5626
+ await sleep2(intervalMs);
5627
+ continue;
5628
+ }
5629
+ if (!options.json && build.status !== lastStatus) {
5630
+ info(`Build ${code(`#${buildId}`)}: ${build.status}`);
5631
+ lastStatus = build.status;
5632
+ }
5633
+ if (build.status === "succeeded") {
5634
+ if (options.json) {
5635
+ out(JSON.stringify(build));
5636
+ } else {
5637
+ success(`Published ${code(slug)} ${code(`v${build.version ?? "?"}`)}`);
5638
+ info(`Build: ${dim(`#${buildId}`)}`);
5639
+ if (process.stdout.isTTY) outro("Done.");
5640
+ }
5641
+ return 0;
5642
+ }
5643
+ if (build.status === "failed") {
5644
+ if (options.json) {
5645
+ out(JSON.stringify(build));
5646
+ } else {
5647
+ fail(
5648
+ `Build ${code(`#${buildId}`)} failed (${build.error_code ?? "BUILD_FAILED"}): ${build.error_message ?? "(no detail)"}`
5649
+ );
5650
+ if (build.log_url) info(`Logs: ${code(build.log_url)}`);
5651
+ info(`Re-run ${code("dashwise module publish")} to try again.`);
5652
+ }
5653
+ return 1;
5654
+ }
5655
+ await sleep2(intervalMs);
5656
+ }
5657
+ warn(
5658
+ `Still building after ${options.timeoutSec ?? 360}s \u2014 the build is likely still running. Re-run ${code("dashwise module publish")} to check, or inspect build ${code(`#${buildId}`)}.`
5659
+ );
5564
5660
  return 0;
5565
5661
  }
5662
+ function sleep2(ms) {
5663
+ return new Promise((r) => setTimeout(r, ms));
5664
+ }
5566
5665
  function formatBytes2(n) {
5567
5666
  if (n < 1024) return `${n}B`;
5568
5667
  if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)}KB`;
@@ -8347,7 +8446,7 @@ async function runTail(moduleId, options) {
8347
8446
  } catch (err) {
8348
8447
  info(dim(`(tail poll error: ${err.message})`));
8349
8448
  }
8350
- await sleep2(POLL_INTERVAL_MS);
8449
+ await sleep3(POLL_INTERVAL_MS);
8351
8450
  }
8352
8451
  }
8353
8452
  function buildTailParams(options) {
@@ -8460,7 +8559,7 @@ function formatRow(row) {
8460
8559
  function formatTimestamp(iso) {
8461
8560
  return iso.slice(0, 19).replace("T", " ");
8462
8561
  }
8463
- function sleep2(ms) {
8562
+ function sleep3(ms) {
8464
8563
  return new Promise((resolve13) => setTimeout(resolve13, ms));
8465
8564
  }
8466
8565
 
@@ -9083,14 +9182,25 @@ envCmd.command("export").description(
9083
9182
  moduleCmd.command("publish").description("Pack the current directory + upload it as a new module version.").option("--dir <path>", "Project root (default: current directory).").option("--bump <direction>", "Semver bump: patch | minor | major.").option("--dry-run", "Validate + upload but do not persist the version row.").option("-y, --yes", "Skip the confirmation prompt (for CI / scripted use).").option(
9084
9183
  "--exclude <pattern...>",
9085
9184
  "Extra exclude patterns (segment-matched) appended to the defaults."
9086
- ).action(
9185
+ ).option(
9186
+ "--no-wait",
9187
+ "Enqueue the build and exit immediately (print the build id) instead of polling to completion."
9188
+ ).option(
9189
+ "--timeout <seconds>",
9190
+ "Max seconds to wait for an async build before giving up polling (default 360)."
9191
+ ).option("--json", "Emit the final build result as machine-readable JSON.").action(
9087
9192
  async (cmdOpts) => {
9193
+ const timeoutSec = cmdOpts.timeout !== void 0 ? Number(cmdOpts.timeout) : void 0;
9088
9194
  process.exitCode = await modulePublishCommand({
9089
9195
  ...cmdOpts.dir !== void 0 ? { dir: cmdOpts.dir } : {},
9090
9196
  ...cmdOpts.bump !== void 0 ? { bump: cmdOpts.bump } : {},
9091
9197
  ...cmdOpts.dryRun !== void 0 ? { dryRun: cmdOpts.dryRun } : {},
9092
9198
  ...cmdOpts.yes !== void 0 ? { yes: cmdOpts.yes } : {},
9093
- ...cmdOpts.exclude !== void 0 ? { exclude: cmdOpts.exclude } : {}
9199
+ ...cmdOpts.exclude !== void 0 ? { exclude: cmdOpts.exclude } : {},
9200
+ // commander maps `--no-wait` to `wait === false`.
9201
+ ...cmdOpts.wait === false ? { noWait: true } : {},
9202
+ ...timeoutSec !== void 0 && Number.isFinite(timeoutSec) ? { timeoutSec } : {},
9203
+ ...cmdOpts.json !== void 0 ? { json: cmdOpts.json } : {}
9094
9204
  });
9095
9205
  }
9096
9206
  );
@@ -9271,7 +9381,7 @@ fieldCmd.command("set-type <table-slug> <field-slug> <new-type>").description(
9271
9381
  }
9272
9382
  })();
9273
9383
  function getVersion() {
9274
- return "0.11.0";
9384
+ return "0.12.0";
9275
9385
  }
9276
9386
  function parseIntOption(value) {
9277
9387
  const n = Number.parseInt(value, 10);