@stacksjs/ts-cloud 0.7.91 → 0.7.93

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 (59) hide show
  1. package/dist/bin/cli.js +403 -344
  2. package/dist/bin/dashboard-server.js +280 -221
  3. package/dist/{chunk-3scf213a.js → chunk-fbwcv2vf.js} +53 -9
  4. package/dist/{chunk-j1kkmmrz.js → chunk-y5wrqyyz.js} +92 -21
  5. package/dist/control-plane/store.d.ts +1 -0
  6. package/dist/deploy/index.js +2 -2
  7. package/dist/drivers/index.js +1 -1
  8. package/dist/drivers/shared/rpx-gateway.d.ts +4 -0
  9. package/dist/index.js +2 -2
  10. package/dist/telemetry/store.d.ts +1 -0
  11. package/dist/ui/access-denied.html +2 -2
  12. package/dist/ui/account/automation.html +4 -4
  13. package/dist/ui/account/security.html +2 -2
  14. package/dist/ui/applications/compose.html +4 -4
  15. package/dist/ui/applications/new.html +2 -2
  16. package/dist/ui/data/backups.html +4 -4
  17. package/dist/ui/data/services.html +4 -4
  18. package/dist/ui/data/volumes.html +4 -4
  19. package/dist/ui/index.html +4 -4
  20. package/dist/ui/integrations.html +2 -2
  21. package/dist/ui/operations/alerts.html +4 -4
  22. package/dist/ui/operations/configuration.html +4 -4
  23. package/dist/ui/operations/jobs.html +4 -4
  24. package/dist/ui/operations/maintenance.html +4 -4
  25. package/dist/ui/operations/observability.html +4 -4
  26. package/dist/ui/operations/previews.html +4 -4
  27. package/dist/ui/operations/queue.html +4 -4
  28. package/dist/ui/operations/regions.html +4 -4
  29. package/dist/ui/operations/releases.html +4 -4
  30. package/dist/ui/operations/workloads.html +4 -4
  31. package/dist/ui/security.html +2 -2
  32. package/dist/ui/server/actions.html +4 -4
  33. package/dist/ui/server/activity.html +2 -2
  34. package/dist/ui/server/capacity.html +3 -3
  35. package/dist/ui/server/database.html +4 -4
  36. package/dist/ui/server/deployments.html +4 -4
  37. package/dist/ui/server/diagnostics.html +2 -2
  38. package/dist/ui/server/firewall.html +4 -4
  39. package/dist/ui/server/fleet.html +4 -4
  40. package/dist/ui/server/logs.html +4 -4
  41. package/dist/ui/server/metrics.html +4 -4
  42. package/dist/ui/server/security.html +2 -2
  43. package/dist/ui/server/services.html +2 -2
  44. package/dist/ui/server/sites.html +4 -4
  45. package/dist/ui/server/ssh-keys.html +4 -4
  46. package/dist/ui/server/team.html +4 -4
  47. package/dist/ui/server/terminal.html +2 -2
  48. package/dist/ui/serverless/alarms.html +4 -4
  49. package/dist/ui/serverless/cost.html +2 -2
  50. package/dist/ui/serverless/data.html +4 -4
  51. package/dist/ui/serverless/firewall.html +2 -2
  52. package/dist/ui/serverless/functions.html +4 -4
  53. package/dist/ui/serverless/logs.html +4 -4
  54. package/dist/ui/serverless/metrics.html +2 -2
  55. package/dist/ui/serverless/queues.html +4 -4
  56. package/dist/ui/serverless/secrets.html +4 -4
  57. package/dist/ui/serverless/traces.html +4 -4
  58. package/dist/ui/serverless.html +3 -3
  59. package/package.json +3 -3
@@ -1347,6 +1347,35 @@ function writeFileHeredoc(path, content, delimiter, mode = "0644") {
1347
1347
  `chmod ${mode} ${path}`
1348
1348
  ];
1349
1349
  }
1350
+ function shellSingleQuote(value) {
1351
+ return `'${value.replaceAll("'", "'\\''")}'`;
1352
+ }
1353
+ function writeRpxFragment(path, content, delimiter, options) {
1354
+ if (!options.preserveManagementDashboardRoutes)
1355
+ return writeFileHeredoc(path, content, delimiter, "0600");
1356
+ const mergeScript = `
1357
+ const { readFileSync, writeFileSync } = require('node:fs')
1358
+ const currentPath = process.env.TS_CLOUD_RPX_CURRENT_FRAGMENT
1359
+ const candidatePath = process.env.TS_CLOUD_RPX_CANDIDATE_FRAGMENT
1360
+ const isDashboard = route => /^(?:dashboard|cloud)\\./i.test(String(route?.to || ''))
1361
+ const current = JSON.parse(readFileSync(currentPath, 'utf8'))
1362
+ const candidate = JSON.parse(readFileSync(candidatePath, 'utf8'))
1363
+ const retained = Array.isArray(current.proxies) ? current.proxies.filter(isDashboard) : []
1364
+ const next = Array.isArray(candidate.proxies) ? candidate.proxies.filter(route => !isDashboard(route)) : []
1365
+ candidate.proxies = [...next, ...retained]
1366
+ writeFileSync(candidatePath, JSON.stringify(candidate, null, 2) + '\\n', { mode: 0o600 })
1367
+ `.trim();
1368
+ return [
1369
+ `__tsc_fragment_candidate="$(mktemp "${path}.candidate.XXXXXX")"`,
1370
+ `cat > "$__tsc_fragment_candidate" <<'${delimiter}'`,
1371
+ content,
1372
+ delimiter,
1373
+ 'chmod 0600 "$__tsc_fragment_candidate"',
1374
+ `if [ -f ${path} ]; then TS_CLOUD_RPX_CURRENT_FRAGMENT=${path} TS_CLOUD_RPX_CANDIDATE_FRAGMENT="$__tsc_fragment_candidate" ${options.bunBin} -e ${shellSingleQuote(mergeScript)}; fi`,
1375
+ `mv -f "$__tsc_fragment_candidate" ${path}`,
1376
+ `chmod 0600 ${path}`
1377
+ ];
1378
+ }
1350
1379
  function rpxCertRenewServiceName(slug) {
1351
1380
  const safeSlug = (slug || "app").replace(/[^a-z0-9._-]+/gi, "-");
1352
1381
  return `rpx-cert-renew-${safeSlug}.service`;
@@ -1459,7 +1488,10 @@ function buildRpxProvisionScript(options) {
1459
1488
  `mv ${RPX_INSTALL_DIR}.next ${RPX_INSTALL_DIR}`,
1460
1489
  `rm -rf ${RPX_INSTALL_DIR}.prev`,
1461
1490
  `ln -sfn ${RPX_INSTALL_DIR}/node_modules ${RPX_DIR}/node_modules`,
1462
- ...writeFileHeredoc(`${RPX_SITES_DIR}/${slug}.json`, fragment, "TS_CLOUD_RPX_FRAGMENT_EOF", "0600"),
1491
+ ...writeRpxFragment(`${RPX_SITES_DIR}/${slug}.json`, fragment, "TS_CLOUD_RPX_FRAGMENT_EOF", {
1492
+ bunBin,
1493
+ preserveManagementDashboardRoutes: options.preserveManagementDashboardRoutes
1494
+ }),
1463
1495
  ...writeFileHeredoc(RPX_LAUNCHER_PATH, assembler, "TS_CLOUD_RPX_EOF"),
1464
1496
  `${bunBin} build --production --compile --outfile ${RPX_BINARY_PATH}.next ${RPX_LAUNCHER_PATH}`,
1465
1497
  `chmod 0755 ${RPX_BINARY_PATH}.next`,
@@ -1508,7 +1540,10 @@ function buildRpxFragmentRefreshScript(options) {
1508
1540
  return [
1509
1541
  "set -euo pipefail",
1510
1542
  `mkdir -p ${RPX_SITES_DIR}`,
1511
- ...writeFileHeredoc(`${RPX_SITES_DIR}/${slug}.json`, fragment, "TS_CLOUD_RPX_FRAGMENT_EOF", "0600"),
1543
+ ...writeRpxFragment(`${RPX_SITES_DIR}/${slug}.json`, fragment, "TS_CLOUD_RPX_FRAGMENT_EOF", {
1544
+ bunBin: "/usr/local/bin/bun",
1545
+ preserveManagementDashboardRoutes: options.preserveManagementDashboardRoutes
1546
+ }),
1512
1547
  `systemctl restart ${RPX_SERVICE_NAME}`
1513
1548
  ];
1514
1549
  }
@@ -5909,16 +5944,16 @@ async function deploySiteRelease(driver, options, logger = noopLogger2) {
5909
5944
  perInstance: result.perInstance
5910
5945
  };
5911
5946
  }
5912
- function shellSingleQuote(value) {
5947
+ function shellSingleQuote2(value) {
5913
5948
  return `'${value.replaceAll("'", "'\\''")}'`;
5914
5949
  }
5915
5950
  function buildManagementDashboardServiceReconciliationScript(slug, desiredSiteNames, serverOwner = false, desiredDomains = []) {
5916
5951
  const prefix = `${slug}-dashboard-`;
5917
5952
  const desiredUnits = desiredSiteNames.map((siteName) => `${slug}-${siteName}.service`);
5918
5953
  const routeReconciliation = serverOwner ? [
5919
- `export TS_CLOUD_DASHBOARD_KEEP_DOMAINS=${shellSingleQuote(JSON.stringify(desiredDomains))}`,
5954
+ `export TS_CLOUD_DASHBOARD_KEEP_DOMAINS=${shellSingleQuote2(JSON.stringify(desiredDomains))}`,
5920
5955
  "rm -f /run/ts-cloud-dashboard-routes-changed",
5921
- `/usr/local/bin/bun --bun -e ${shellSingleQuote(`
5956
+ `/usr/local/bin/bun --bun -e ${shellSingleQuote2(`
5922
5957
  const { chmodSync, existsSync, readdirSync, readFileSync, renameSync, statSync, writeFileSync } = require('node:fs')
5923
5958
  const { basename, join } = require('node:path')
5924
5959
  const root = '/etc/rpx/sites.d'
@@ -5954,9 +5989,9 @@ function buildManagementDashboardServiceReconciliationScript(slug, desiredSiteNa
5954
5989
  ] : [];
5955
5990
  return [
5956
5991
  "set -euo pipefail",
5957
- `TS_CLOUD_DASHBOARD_PREFIX=${shellSingleQuote(prefix)}`,
5992
+ `TS_CLOUD_DASHBOARD_PREFIX=${shellSingleQuote2(prefix)}`,
5958
5993
  `TS_CLOUD_DASHBOARD_SERVER_OWNER=${serverOwner ? "1" : "0"}`,
5959
- `TS_CLOUD_DASHBOARD_DESIRED=${shellSingleQuote(` ${desiredUnits.join(" ")} `)}`,
5994
+ `TS_CLOUD_DASHBOARD_DESIRED=${shellSingleQuote2(` ${desiredUnits.join(" ")} `)}`,
5960
5995
  "for TS_CLOUD_UNIT_FILE in /etc/systemd/system/*.service; do",
5961
5996
  ' [ -e "$TS_CLOUD_UNIT_FILE" ] || continue',
5962
5997
  ' TS_CLOUD_UNIT=$(basename "$TS_CLOUD_UNIT_FILE")',
@@ -6169,7 +6204,11 @@ async function reloadRpxGateway(options) {
6169
6204
  logger.step(`Reloading the load balancer's rpx gateway with ${lbConfig.proxies.length} route(s)...`);
6170
6205
  const result2 = await driver.runRemoteDeploy({
6171
6206
  targets: lbTargets,
6172
- commands: buildRpxFragmentRefreshScript({ config: lbConfig, slug }),
6207
+ commands: buildRpxFragmentRefreshScript({
6208
+ config: lbConfig,
6209
+ slug,
6210
+ preserveManagementDashboardRoutes: options.managementDashboard === false
6211
+ }),
6173
6212
  comment: `ts-cloud rpx gateway reload ${slug}`,
6174
6213
  tags: {
6175
6214
  Project: slug,
@@ -6200,7 +6239,12 @@ async function reloadRpxGateway(options) {
6200
6239
  return true;
6201
6240
  }
6202
6241
  logger.step(`Reloading rpx gateway with ${rpxConfig.proxies.length} route(s)...`);
6203
- const script = buildRpxProvisionScript({ proxy, config: rpxConfig, slug });
6242
+ const script = buildRpxProvisionScript({
6243
+ proxy,
6244
+ config: rpxConfig,
6245
+ slug,
6246
+ preserveManagementDashboardRoutes: options.managementDashboard === false
6247
+ });
6204
6248
  const result = await driver.runRemoteDeploy({
6205
6249
  targets,
6206
6250
  commands: script,
@@ -45,7 +45,7 @@ import {
45
45
  resolveSiteKind,
46
46
  resolveUiSource,
47
47
  siteInstallBase
48
- } from "./chunk-3scf213a.js";
48
+ } from "./chunk-fbwcv2vf.js";
49
49
  import {
50
50
  artifactKey,
51
51
  buildCloudFormationTemplate,
@@ -92,7 +92,7 @@ import {
92
92
  import { createHash as createHash5 } from "node:crypto";
93
93
 
94
94
  // src/control-plane/migrations.ts
95
- var CONTROL_PLANE_SCHEMA_VERSION = 35;
95
+ var CONTROL_PLANE_SCHEMA_VERSION = 36;
96
96
  var controlPlaneMigrations = [
97
97
  {
98
98
  version: 1,
@@ -1506,11 +1506,56 @@ var controlPlaneMigrations = [
1506
1506
  CREATE INDEX cleanup_plan_status ON cleanup_plans(project_id,status,expires_at);
1507
1507
  CREATE INDEX dr_drill_status ON disaster_recovery_drills(project_id,status,created_at DESC);
1508
1508
  `
1509
+ },
1510
+ {
1511
+ version: 36,
1512
+ name: "telemetry_source_rollups",
1513
+ sql: `
1514
+ CREATE TABLE telemetry_source_rollups (
1515
+ project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
1516
+ environment_id TEXT NOT NULL DEFAULT '',
1517
+ resource_id TEXT NOT NULL DEFAULT '',
1518
+ source TEXT NOT NULL,
1519
+ first_observed_at TEXT NOT NULL,
1520
+ latest_observed_at TEXT NOT NULL,
1521
+ ingested_bytes INTEGER NOT NULL DEFAULT 0 CHECK (ingested_bytes >= 0),
1522
+ record_count INTEGER NOT NULL DEFAULT 0 CHECK (record_count >= 0),
1523
+ PRIMARY KEY(project_id, environment_id, resource_id, source)
1524
+ ) STRICT;
1525
+
1526
+ INSERT INTO telemetry_source_rollups (
1527
+ project_id, environment_id, resource_id, source,
1528
+ first_observed_at, latest_observed_at, ingested_bytes, record_count
1529
+ )
1530
+ SELECT
1531
+ project_id, COALESCE(environment_id, ''), COALESCE(resource_id, ''), source,
1532
+ MIN(observed_at), MAX(observed_at), SUM(ingested_bytes), COUNT(*)
1533
+ FROM telemetry_records
1534
+ GROUP BY project_id, COALESCE(environment_id, ''), COALESCE(resource_id, ''), source;
1535
+
1536
+ CREATE TRIGGER telemetry_source_rollups_insert
1537
+ AFTER INSERT ON telemetry_records
1538
+ BEGIN
1539
+ INSERT INTO telemetry_source_rollups (
1540
+ project_id, environment_id, resource_id, source,
1541
+ first_observed_at, latest_observed_at, ingested_bytes, record_count
1542
+ )
1543
+ VALUES (
1544
+ NEW.project_id, COALESCE(NEW.environment_id, ''), COALESCE(NEW.resource_id, ''), NEW.source,
1545
+ NEW.observed_at, NEW.observed_at, NEW.ingested_bytes, 1
1546
+ )
1547
+ ON CONFLICT(project_id, environment_id, resource_id, source) DO UPDATE SET
1548
+ first_observed_at = MIN(first_observed_at, excluded.first_observed_at),
1549
+ latest_observed_at = MAX(latest_observed_at, excluded.latest_observed_at),
1550
+ ingested_bytes = ingested_bytes + excluded.ingested_bytes,
1551
+ record_count = record_count + 1;
1552
+ END;
1553
+ `
1509
1554
  }
1510
1555
  ];
1511
1556
  // src/control-plane/store.ts
1512
1557
  import { createHash, randomBytes } from "node:crypto";
1513
- import { chmodSync, existsSync, mkdirSync, statSync, writeFileSync } from "node:fs";
1558
+ import { chmodSync, existsSync, mkdirSync, statSync } from "node:fs";
1514
1559
  import { dirname } from "node:path";
1515
1560
  import { Database } from "bun:sqlite";
1516
1561
 
@@ -1978,6 +2023,12 @@ class ControlPlaneStore {
1978
2023
  } catch {}
1979
2024
  }
1980
2025
  }
2026
+ backupTo(path) {
2027
+ this.database.run("VACUUM INTO ?", [path]);
2028
+ try {
2029
+ chmodSync(path, 384);
2030
+ } catch {}
2031
+ }
1981
2032
  migrate() {
1982
2033
  const row = this.database.query("PRAGMA user_version").get();
1983
2034
  const current = Number(row?.user_version ?? 0);
@@ -1988,7 +2039,7 @@ class ControlPlaneStore {
1988
2039
  let backupPath;
1989
2040
  if (current > 0 && this.path !== ":memory:") {
1990
2041
  backupPath = `${this.path}.v${current}.${Date.now()}.bak`;
1991
- writeFileSync(backupPath, this.database.serialize(), { mode: 384 });
2042
+ this.backupTo(backupPath);
1992
2043
  }
1993
2044
  try {
1994
2045
  const apply = this.database.transaction(() => {
@@ -2263,7 +2314,7 @@ class ControlPlaneStore {
2263
2314
  return row ? mapMembership(row) : undefined;
2264
2315
  }
2265
2316
  listMemberships(organizationId, options = {}) {
2266
- const revoked = options.includeRevoked ? "" : "AND status = 'active'";
2317
+ const revoked = options.includeRevoked ? "" : `AND status = 'active'`;
2267
2318
  return this.database.query(`SELECT * FROM organization_memberships WHERE organization_id = ? ${revoked} ORDER BY created_at, id`).all(organizationId).map(mapMembership);
2268
2319
  }
2269
2320
  updateMembership(input) {
@@ -2314,7 +2365,7 @@ class ControlPlaneStore {
2314
2365
  return membership;
2315
2366
  }
2316
2367
  assertAnotherOwner(current) {
2317
- const owners = Number(this.database.query("SELECT COUNT(*) AS count FROM organization_memberships WHERE organization_id = ? AND status = ? AND role_template = 'owner'").get(current.organizationId, "active")?.count ?? 0);
2368
+ const owners = Number(this.database.query(`SELECT COUNT(*) AS count FROM organization_memberships WHERE organization_id = ? AND status = ? AND role_template = 'owner'`).get(current.organizationId, "active")?.count ?? 0);
2318
2369
  if (owners <= 1)
2319
2370
  throw new Error("Cannot remove or demote the last organization owner");
2320
2371
  }
@@ -2873,7 +2924,7 @@ class ControlPlaneStore {
2873
2924
  if (this.path === ":memory:")
2874
2925
  throw new Error("Cannot create a filesystem backup for an in-memory control plane");
2875
2926
  const backupPath = `${this.path}.${Date.now()}.bak`;
2876
- writeFileSync(backupPath, this.database.serialize(), { mode: 384 });
2927
+ this.backupTo(backupPath);
2877
2928
  this.setSetting("storage.last_backup", { path: backupPath, createdAt: this.now(), reason });
2878
2929
  return backupPath;
2879
2930
  }
@@ -7990,7 +8041,7 @@ function estimateExistingStaticFullStackMonthlyCost(options = {}) {
7990
8041
  // src/deploy/container-image.ts
7991
8042
  import { execFileSync } from "node:child_process";
7992
8043
  import { createHash as createHash8 } from "node:crypto";
7993
- import { existsSync as existsSync3, mkdirSync as mkdirSync2, mkdtempSync, readdirSync, readFileSync, rmSync, statSync as statSync2, writeFileSync as writeFileSync2 } from "node:fs";
8044
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, mkdtempSync, readdirSync, readFileSync, rmSync, statSync as statSync2, writeFileSync } from "node:fs";
7994
8045
  import { tmpdir } from "node:os";
7995
8046
  import { basename as basename2, join as join3, relative, resolve as resolve2 } from "node:path";
7996
8047
  var IGNORED_DIRECTORIES = new Set([".git", "node_modules", "dist", "coverage"]);
@@ -8093,7 +8144,7 @@ async function buildAndPushContainerImage(options, injected) {
8093
8144
  const registry = auth.proxyEndpoint.replace(/^https?:\/\//, "");
8094
8145
  const dockerConfig = join3(temporaryDirectory, "docker");
8095
8146
  mkdirSync2(dockerConfig, { recursive: true });
8096
- writeFileSync2(join3(dockerConfig, "config.json"), JSON.stringify({ auths: { [registry]: { auth: auth.authorizationToken } } }), { mode: 384 });
8147
+ writeFileSync(join3(dockerConfig, "config.json"), JSON.stringify({ auths: { [registry]: { auth: auth.authorizationToken } } }), { mode: 384 });
8097
8148
  dependencies2.run("docker", ["push", imageUri], { env: { ...process.env, DOCKER_CONFIG: dockerConfig } });
8098
8149
  } finally {
8099
8150
  rmSync(temporaryDirectory, { recursive: true, force: true });
@@ -10895,9 +10946,11 @@ class TelemetryStore {
10895
10946
  if (environmentId)
10896
10947
  bindings.push(environmentId);
10897
10948
  const boundedResources = [...new Set(resourceIds ?? [])].slice(0, 100);
10949
+ if (resourceIds && boundedResources.length === 0)
10950
+ return [];
10898
10951
  const resources = resourceIds ? ` AND resource_id IN (${boundedResources.map(() => "?").join(",") || "''"})` : "";
10899
10952
  bindings.push(...boundedResources);
10900
- const rows = this.controlPlane.database.query(`SELECT source, MAX(observed_at) latest, SUM(ingested_bytes) bytes, COUNT(*) count, MIN(observed_at) first FROM telemetry_records WHERE project_id=?${environment2}${resources} GROUP BY source`).all(...bindings);
10953
+ const rows = this.controlPlane.database.query(`SELECT source, MAX(latest_observed_at) latest, SUM(ingested_bytes) bytes, SUM(record_count) count, MIN(first_observed_at) first FROM telemetry_source_rollups WHERE project_id=?${environment2}${resources} GROUP BY source`).all(...bindings);
10901
10954
  const now = this.now().getTime();
10902
10955
  return rows.map((row) => {
10903
10956
  const latest = String(row.latest);
@@ -11016,8 +11069,26 @@ class TelemetryStore {
11016
11069
  const excess = Number(this.controlPlane.database.query(`SELECT MAX(0, COUNT(*)-?) excess FROM telemetry_records${projectId ? " WHERE project_id=?" : ""}`).get(policy.maxRecords, ...projectId ? [projectId] : [])?.excess ?? 0);
11017
11070
  if (excess > 0)
11018
11071
  this.controlPlane.database.run(`DELETE FROM telemetry_records WHERE id IN (SELECT id FROM telemetry_records${projectId ? " WHERE project_id=?" : ""} ORDER BY timestamp ASC LIMIT ?)`, projectId ? [projectId, excess] : [excess]);
11072
+ this.rebuildStatusRollups(projectId);
11019
11073
  return { deleted: removed + excess, ...downsampled };
11020
11074
  }
11075
+ rebuildStatusRollups(projectId) {
11076
+ const scope = projectId ? " WHERE project_id=?" : "";
11077
+ const bindings = projectId ? [projectId] : [];
11078
+ const rebuild = this.controlPlane.database.transaction(() => {
11079
+ this.controlPlane.database.run(`DELETE FROM telemetry_source_rollups${scope}`, bindings);
11080
+ this.controlPlane.database.run(`INSERT INTO telemetry_source_rollups (
11081
+ project_id, environment_id, resource_id, source,
11082
+ first_observed_at, latest_observed_at, ingested_bytes, record_count
11083
+ )
11084
+ SELECT
11085
+ project_id, COALESCE(environment_id, ''), COALESCE(resource_id, ''), source,
11086
+ MIN(observed_at), MAX(observed_at), SUM(ingested_bytes), COUNT(*)
11087
+ FROM telemetry_records${scope}
11088
+ GROUP BY project_id, COALESCE(environment_id, ''), COALESCE(resource_id, ''), source`, bindings);
11089
+ });
11090
+ rebuild();
11091
+ }
11021
11092
  }
11022
11093
  // src/alerts/telemetry.ts
11023
11094
  function evaluateTelemetryAlertRules(store4, projectId, environmentId, now = new Date) {
@@ -12075,7 +12146,7 @@ async function manifestRequest(fetchFn, root, image, token, signal, authorizatio
12075
12146
  }
12076
12147
  // src/onboarding/artifact-store.ts
12077
12148
  import { createHash as createHash12 } from "node:crypto";
12078
- import { chmodSync as chmodSync2, existsSync as existsSync5, mkdirSync as mkdirSync3, renameSync, unlinkSync, writeFileSync as writeFileSync3 } from "node:fs";
12149
+ import { chmodSync as chmodSync2, existsSync as existsSync5, mkdirSync as mkdirSync3, renameSync, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
12079
12150
  import { basename as basename3, join as join5 } from "node:path";
12080
12151
  function map2(row) {
12081
12152
  return {
@@ -12122,7 +12193,7 @@ class ApplicationArtifactStore {
12122
12193
  const path = join5(this.root, `${id}.archive`);
12123
12194
  const temporary = `${path}.partial`;
12124
12195
  try {
12125
- writeFileSync3(temporary, input.bytes, { mode: 384, flag: "wx" });
12196
+ writeFileSync2(temporary, input.bytes, { mode: 384, flag: "wx" });
12126
12197
  renameSync(temporary, path);
12127
12198
  chmodSync2(path, 384);
12128
12199
  this.controlPlane.database.run("INSERT INTO application_artifacts (id, organization_id, project_id, filename, storage_path, sha256, size, format, entry_count, expanded_bytes, created_by_actor_id, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", [
@@ -14755,7 +14826,7 @@ function webhookEndpoint(baseUrl, webhook) {
14755
14826
  return new URL(`/api/source/webhooks/${encodeURIComponent(webhook.endpointToken)}`, base).href;
14756
14827
  }
14757
14828
  // src/source/git-workspace.ts
14758
- import { chmodSync as chmodSync3, mkdtempSync as mkdtempSync2, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "node:fs";
14829
+ import { chmodSync as chmodSync3, mkdtempSync as mkdtempSync2, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "node:fs";
14759
14830
  import { tmpdir as tmpdir2 } from "node:os";
14760
14831
  import { join as join6, resolve as resolve5 } from "node:path";
14761
14832
  function validateRemote(value, deployKey) {
@@ -14802,8 +14873,8 @@ function transportEnvironment(options) {
14802
14873
  directory = mkdtempSync2(join6(tmpdir2(), "ts-cloud-git-transport-"));
14803
14874
  const keyPath = join6(directory, "key");
14804
14875
  const knownHostsPath = join6(directory, "known_hosts");
14805
- writeFileSync4(keyPath, options.deployKey.privateKey, { mode: 384 });
14806
- writeFileSync4(knownHostsPath, `${options.deployKey.host} ${options.deployKey.hostKey}
14876
+ writeFileSync3(keyPath, options.deployKey.privateKey, { mode: 384 });
14877
+ writeFileSync3(knownHostsPath, `${options.deployKey.host} ${options.deployKey.hostKey}
14807
14878
  `, { mode: 384 });
14808
14879
  chmodSync3(keyPath, 384);
14809
14880
  chmodSync3(knownHostsPath, 384);
@@ -18280,7 +18351,7 @@ async function sendAuthenticationEmail(config, message) {
18280
18351
  }
18281
18352
  // src/auth/encryption.ts
18282
18353
  import { randomBytes as randomBytes6 } from "node:crypto";
18283
- import { chmodSync as chmodSync4, existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync5 } from "node:fs";
18354
+ import { chmodSync as chmodSync4, existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "node:fs";
18284
18355
  import { dirname as dirname2 } from "node:path";
18285
18356
  function authEncryptionKeyFile() {
18286
18357
  return statePath("auth-encryption-key");
@@ -18300,7 +18371,7 @@ function resolveAuthEncryptionKey(cwd) {
18300
18371
  const key = randomBytes6(32).toString("base64url");
18301
18372
  try {
18302
18373
  mkdirSync4(dirname2(file), { recursive: true, mode: 448 });
18303
- writeFileSync5(file, `${key}
18374
+ writeFileSync4(file, `${key}
18304
18375
  `, { mode: 384 });
18305
18376
  chmodSync4(file, 384);
18306
18377
  } catch {}
@@ -23027,7 +23098,7 @@ import { homedir as homedir3 } from "os";
23027
23098
  import { dirname as dirname4, resolve as resolve12 } from "path";
23028
23099
  import process20 from "process";
23029
23100
  import { existsSync as existsSync22, statSync as statSync22 } from "fs";
23030
- import { existsSync as existsSync82, mkdirSync as mkdirSync32, readdirSync as readdirSync32, writeFileSync as writeFileSync52 } from "fs";
23101
+ import { existsSync as existsSync82, mkdirSync as mkdirSync32, readdirSync as readdirSync32, writeFileSync as writeFileSync5 } from "fs";
23031
23102
  import { homedir as homedir2 } from "os";
23032
23103
  import { dirname as dirname3, resolve as resolve72 } from "path";
23033
23104
  import process12 from "process";
@@ -28162,7 +28233,7 @@ function generateConfigTypes(options) {
28162
28233
  const content = `// Generated by bunfig v${version}
28163
28234
  export type ConfigNames = ${files.length ? `'${files.join("' | '")}'` : "string"}
28164
28235
  `;
28165
- writeFileSync52(outputFile, content, { mode: 438 });
28236
+ writeFileSync5(outputFile, content, { mode: 438 });
28166
28237
  }
28167
28238
  function createLibraryConfig(options) {
28168
28239
  let configCache = null;
@@ -40133,7 +40204,7 @@ function clearSessionCookie(options = { secure: true }) {
40133
40204
  }
40134
40205
 
40135
40206
  // src/deploy/dashboard-users.ts
40136
- import { chmodSync as chmodSync6, existsSync as existsSync19, mkdirSync as mkdirSync7, readFileSync as readFileSync10, writeFileSync as writeFileSync10 } from "node:fs";
40207
+ import { chmodSync as chmodSync6, existsSync as existsSync19, mkdirSync as mkdirSync7, readFileSync as readFileSync10, writeFileSync as writeFileSync9 } from "node:fs";
40137
40208
  import { dirname as dirname8 } from "node:path";
40138
40209
  function usersFile() {
40139
40210
  return statePath("dashboard-users.json");
@@ -40188,7 +40259,7 @@ function loadUsers(cwd) {
40188
40259
  function saveUsers(cwd, users) {
40189
40260
  const file = usersFilePath(cwd);
40190
40261
  mkdirSync7(dirname8(file), { recursive: true });
40191
- writeFileSync10(file, `${JSON.stringify({ users }, null, 2)}
40262
+ writeFileSync9(file, `${JSON.stringify({ users }, null, 2)}
40192
40263
  `);
40193
40264
  chmodSync6(file, 384);
40194
40265
  }
@@ -13,6 +13,7 @@ export declare class ControlPlaneStore {
13
13
  constructor(options?: ControlPlaneStoreOptions);
14
14
  private now;
15
15
  private secureDatabaseFiles;
16
+ private backupTo;
16
17
  private migrate;
17
18
  close(): void;
18
19
  transaction<T>(callback: () => T): T;
@@ -30,7 +30,7 @@ import {
30
30
  synchronizeDashboardUsers,
31
31
  trackDashboardOperation,
32
32
  verifyStaticApiOrigin
33
- } from "../chunk-j1kkmmrz.js";
33
+ } from "../chunk-y5wrqyyz.js";
34
34
  import {
35
35
  deleteStaticSite,
36
36
  deployStaticSite,
@@ -70,7 +70,7 @@ import {
70
70
  siteInstallBase,
71
71
  validateDeploymentConfig,
72
72
  verifyAddressRecord
73
- } from "../chunk-3scf213a.js";
73
+ } from "../chunk-fbwcv2vf.js";
74
74
  import"../chunk-hmehkeqx.js";
75
75
  import"../chunk-7m60qnc8.js";
76
76
  import"../chunk-4cjrg98a.js";
@@ -68,7 +68,7 @@ import {
68
68
  waitForSsh,
69
69
  wrapCloudInitUserData,
70
70
  writeResizeCheckpoint
71
- } from "../chunk-3scf213a.js";
71
+ } from "../chunk-fbwcv2vf.js";
72
72
  import"../chunk-hmehkeqx.js";
73
73
  import"../chunk-7m60qnc8.js";
74
74
  import"../chunk-4cjrg98a.js";
@@ -272,6 +272,8 @@ export interface BuildRpxProvisionOptions {
272
272
  slug?: string;
273
273
  /** Absolute path to the `bun` binary on the box. @default '/usr/local/bin/bun' */
274
274
  bunBin?: string;
275
+ /** Keep the dashboard route currently running on the box during an app-only deploy. */
276
+ preserveManagementDashboardRoutes?: boolean;
275
277
  }
276
278
  export declare const RPX_CERT_RENEW_SCRIPT = "/etc/rpx/renew-certs.sh";
277
279
  export declare const RPX_CERT_RENEW_SERVICE = "rpx-cert-renew.service";
@@ -310,6 +312,8 @@ export interface BuildRpxFragmentRefreshOptions {
310
312
  * Defaults to `'app'`.
311
313
  */
312
314
  slug?: string;
315
+ /** Keep the dashboard route currently running on the box during an app-only deploy. */
316
+ preserveManagementDashboardRoutes?: boolean;
313
317
  }
314
318
  /**
315
319
  * Build the shell commands that rewrite ONLY this app's rpx route fragment
package/dist/index.js CHANGED
@@ -283,7 +283,7 @@ import {
283
283
  volumeCapabilities,
284
284
  webhookEndpoint,
285
285
  zeroCapacity
286
- } from "./chunk-j1kkmmrz.js";
286
+ } from "./chunk-y5wrqyyz.js";
287
287
  import {
288
288
  deleteStaticSite,
289
289
  deployStaticSite,
@@ -403,7 +403,7 @@ import {
403
403
  waitForCloudInit,
404
404
  waitForSsh,
405
405
  wrapCloudInitUserData
406
- } from "./chunk-3scf213a.js";
406
+ } from "./chunk-fbwcv2vf.js";
407
407
  import {
408
408
  ABTestManager,
409
409
  AI,
@@ -31,4 +31,5 @@ export declare class TelemetryStore {
31
31
  compacted: number;
32
32
  rollups: number;
33
33
  };
34
+ private rebuildStatusRollups;
34
35
  }