lakebed 0.0.21 → 0.0.22

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lakebed",
3
- "version": "0.0.21",
3
+ "version": "0.0.22",
4
4
  "description": "Agent-native CLI and runtime for building and deploying Lakebed capsules.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -55,6 +55,9 @@
55
55
  "publishConfig": {
56
56
  "access": "public"
57
57
  },
58
+ "scripts": {
59
+ "check": "node --check src/cli.js && node --check src/runtime.js && node --check src/server.js && node --check src/client.js && node --check src/source-store.js && node --check src/source-runtime.js && node --check src/source-runtime-worker.js && node --check src/source-runtime-loader.mjs && node --check src/anonymous.js && node --check src/anonymous-server.js && node --check src/auth.js && node --check src/version.js && node --check src/services/all-in-one.js && node --check src/services/api-dashboard.js && node --check src/services/capsule-runner.js"
60
+ },
58
61
  "dependencies": {
59
62
  "esbuild": "^0.27.1",
60
63
  "pg": "^8.16.3",
@@ -63,8 +66,5 @@
63
66
  },
64
67
  "devDependencies": {
65
68
  "@types/ws": "^8.18.1"
66
- },
67
- "scripts": {
68
- "check": "node --check src/cli.js && node --check src/runtime.js && node --check src/server.js && node --check src/client.js && node --check src/source-store.js && node --check src/source-runtime.js && node --check src/source-runtime-worker.js && node --check src/source-runtime-loader.mjs && node --check src/anonymous.js && node --check src/anonymous-server.js && node --check src/auth.js && node --check src/version.js && node --check src/services/all-in-one.js && node --check src/services/api-dashboard.js && node --check src/services/capsule-runner.js"
69
69
  }
70
- }
70
+ }
@@ -436,6 +436,48 @@ function isApiDashboardRoute(pathname) {
436
436
  );
437
437
  }
438
438
 
439
+ function isDashboardBrowserRoute(pathname) {
440
+ return (
441
+ pathname === "/" ||
442
+ pathname === "/deploys" ||
443
+ pathname === "/dashboard" ||
444
+ pathname === "/auth" ||
445
+ pathname.startsWith("/auth/") ||
446
+ pathname === "/admin" ||
447
+ pathname.startsWith("/admin/") ||
448
+ pathname.startsWith("/claim/")
449
+ );
450
+ }
451
+
452
+ function normalizedUrlHost(value) {
453
+ try {
454
+ return new URL(value).host.toLowerCase();
455
+ } catch {
456
+ return "";
457
+ }
458
+ }
459
+
460
+ function dashboardRedirectLocation({ dashboardRootUrl, requestUrl }) {
461
+ const pathname = requestUrl.pathname === "/" ? "/deploys" : requestUrl.pathname;
462
+ const target = new URL(pathname, dashboardRootUrl);
463
+ target.search = requestUrl.search;
464
+ return target.href;
465
+ }
466
+
467
+ function shouldRedirectToDashboardHost({ dashboardRootUrl, host, publicRootUrl, requestUrl }) {
468
+ if (!isDashboardBrowserRoute(requestUrl.pathname)) {
469
+ return false;
470
+ }
471
+
472
+ const publicHost = normalizedUrlHost(publicRootUrl);
473
+ const dashboardHost = normalizedUrlHost(dashboardRootUrl);
474
+ if (!publicHost || !dashboardHost || publicHost === dashboardHost) {
475
+ return false;
476
+ }
477
+
478
+ return String(host).toLowerCase() === publicHost;
479
+ }
480
+
439
481
  function appUrlForSlug({ appBaseDomain, slug }) {
440
482
  if (!appBaseDomain) {
441
483
  throw new Error("LAKEBED_APP_BASE_DOMAIN is required to create hosted deploy URLs.");
@@ -6217,6 +6259,19 @@ export async function startAnonymousServer({
6217
6259
  return;
6218
6260
  }
6219
6261
 
6262
+ if (
6263
+ servesApiDashboard &&
6264
+ shouldRedirectToDashboardHost({
6265
+ dashboardRootUrl: resolvedDashboardRootUrl,
6266
+ host,
6267
+ publicRootUrl: resolvedPublicRootUrl,
6268
+ requestUrl
6269
+ })
6270
+ ) {
6271
+ redirect(res, dashboardRedirectLocation({ dashboardRootUrl: resolvedDashboardRootUrl, requestUrl }));
6272
+ return;
6273
+ }
6274
+
6220
6275
  if (servesApiDashboard && req.method === "GET" && (requestUrl.pathname === "/deploys" || requestUrl.pathname === "/dashboard")) {
6221
6276
  const authConfigured = developerAuthConfigured(resolvedGithubOAuth, resolvedDeveloperSessionSecret);
6222
6277
  const user = authConfigured ? currentDeveloper(req) : null;
package/src/cli.js CHANGED
@@ -31,6 +31,7 @@ const packageDir = resolve(dirname(fileURLToPath(import.meta.url)), "..");
31
31
  const packageNodeModules = resolve(packageDir, "node_modules");
32
32
  const sourceNamespace = "lakebed-source";
33
33
  const defaultDeployApiUrl = "https://api.lakebed.dev";
34
+ const legacyDeployApiUrl = "https://api.lakebed.app";
34
35
  const execFileAsync = promisify(execFile);
35
36
  const endpointBodyMaxBytes = 2 * 1024 * 1024;
36
37
 
@@ -1193,12 +1194,12 @@ function claimTokenFromDeployResponse(deployed) {
1193
1194
  return null;
1194
1195
  }
1195
1196
 
1196
- function claimUrlFromDeployMetadata(metadata) {
1197
+ function claimUrlFromDeployMetadata(metadata, api = metadata?.api) {
1197
1198
  if (!metadata?.api || !metadata?.deployId || !metadata?.claimToken) {
1198
1199
  return null;
1199
1200
  }
1200
1201
 
1201
- return `${String(metadata.api).replace(/\/+$/g, "")}/claim/${encodeURIComponent(metadata.deployId)}/${encodeURIComponent(metadata.claimToken)}`;
1202
+ return `${normalizeHostedUrl(api)}/claim/${encodeURIComponent(metadata.deployId)}/${encodeURIComponent(metadata.claimToken)}`;
1202
1203
  }
1203
1204
 
1204
1205
  function claimCommandText({ api, capsuleArg }) {
@@ -1330,6 +1331,15 @@ function normalizeHostedUrl(value) {
1330
1331
  }
1331
1332
  }
1332
1333
 
1334
+ function canonicalDeployApiUrl(value) {
1335
+ const normalized = normalizeHostedUrl(value);
1336
+ return normalized === legacyDeployApiUrl ? defaultDeployApiUrl : normalized;
1337
+ }
1338
+
1339
+ function deployApiUrlsMatch(left, right) {
1340
+ return canonicalDeployApiUrl(left) === canonicalDeployApiUrl(right);
1341
+ }
1342
+
1333
1343
  async function readResponseJson(response) {
1334
1344
  const body = await response.text();
1335
1345
  if (!response.ok) {
@@ -1354,7 +1364,7 @@ async function deployCommand(args) {
1354
1364
  const inspectPolicy = hasFlag(args, "--public-inspect") ? "public" : undefined;
1355
1365
  const metadata = await readDeployMetadata(capsuleDir);
1356
1366
  const canUpdate =
1357
- metadata?.api === api && typeof metadata?.deployId === "string" && typeof metadata?.claimToken === "string";
1367
+ deployApiUrlsMatch(metadata?.api, api) && typeof metadata?.deployId === "string" && typeof metadata?.claimToken === "string";
1358
1368
  let currentDeploy = null;
1359
1369
  if (canUpdate) {
1360
1370
  const currentResponse = await fetch(`${api}/v1/deploys/${encodeURIComponent(metadata.deployId)}`);
@@ -1498,11 +1508,11 @@ async function claimCommand(args) {
1498
1508
  throw new Error(`No Lakebed deploy metadata found at ${deployMetadataPath(capsuleDir)}. Run npx lakebed deploy from this project first.`);
1499
1509
  }
1500
1510
 
1501
- if (metadata.api !== api) {
1511
+ if (!deployApiUrlsMatch(metadata.api, api)) {
1502
1512
  throw new Error(`Saved deploy metadata is for ${metadata.api}, but this command is using ${api}. Pass --api ${metadata.api} to claim it.`);
1503
1513
  }
1504
1514
 
1505
- const claimUrl = claimUrlFromDeployMetadata(metadata);
1515
+ const claimUrl = claimUrlFromDeployMetadata(metadata, api);
1506
1516
  if (!claimUrl) {
1507
1517
  throw new Error("This project does not have a saved claim token. Redeploy to create a new claim URL.");
1508
1518
  }
@@ -1561,7 +1571,7 @@ async function domainsCommand(args) {
1561
1571
  if (!metadata) {
1562
1572
  throw new Error(`No Lakebed deploy metadata found at ${deployMetadataPath(capsuleDir)}. Run npx lakebed deploy from this project first.`);
1563
1573
  }
1564
- if (metadata.api !== api) {
1574
+ if (!deployApiUrlsMatch(metadata.api, api)) {
1565
1575
  throw new Error(`Saved deploy metadata is for ${metadata.api}, but this command is using ${api}. Pass --api ${metadata.api} to use it.`);
1566
1576
  }
1567
1577
  if (!metadata.deployId || !metadata.claimToken) {
@@ -1603,7 +1613,7 @@ async function anonymousServerCommand(args) {
1603
1613
 
1604
1614
  function deployLookupApiUrl(target, args, metadata) {
1605
1615
  if (!hasExplicitOption(args, "--api") && metadata?.api && metadata.deployId === target) {
1606
- return String(metadata.api).replace(/\/+$/g, "");
1616
+ return canonicalDeployApiUrl(metadata.api);
1607
1617
  }
1608
1618
 
1609
1619
  return deployApiUrl(args);
package/src/version.js CHANGED
@@ -1 +1 @@
1
- export const LAKEBED_VERSION = "0.0.21";
1
+ export const LAKEBED_VERSION = "0.0.22";