@stacksjs/ts-cloud 0.7.45 → 0.7.47

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.
@@ -1201,7 +1201,7 @@ async function resolveDashboardData(config, environment) {
1201
1201
  return out;
1202
1202
  }
1203
1203
  // src/deploy/local-dashboard-server.ts
1204
- import { existsSync as existsSync18, statSync as statSync3 } from "node:fs";
1204
+ import { existsSync as existsSync18, readdirSync as readdirSync7, rmSync, statSync as statSync3 } from "node:fs";
1205
1205
  import { readFile, writeFile as writeFile4 } from "node:fs/promises";
1206
1206
  import { mkdtempSync } from "node:fs";
1207
1207
  import { tmpdir } from "node:os";
@@ -12819,7 +12819,35 @@ function createTerminalSession(onData, options = {}) {
12819
12819
  var DEFAULT_HOST = "127.0.0.1";
12820
12820
  var DEFAULT_PORT = 7676;
12821
12821
  var MAX_OUTPUT_BYTES3 = 64 * 1024;
12822
+ var DASHBOARD_TEMP_PREFIX = "ts-cloud-dashboard-";
12822
12823
  var here = dirname8(fileURLToPath(import.meta.url));
12824
+ function isProcessRunning(pid) {
12825
+ try {
12826
+ process.kill(pid, 0);
12827
+ return true;
12828
+ } catch (error2) {
12829
+ return error2?.code !== "ESRCH";
12830
+ }
12831
+ }
12832
+ function pruneDashboardTempRoots(root = tmpdir(), running = isProcessRunning) {
12833
+ let removed = 0;
12834
+ for (const entry of readdirSync7(root, { withFileTypes: true })) {
12835
+ if (!entry.isDirectory() || !entry.name.startsWith(DASHBOARD_TEMP_PREFIX))
12836
+ continue;
12837
+ const path = join12(root, entry.name);
12838
+ const owned = entry.name.match(/^ts-cloud-dashboard-(\d+)-/);
12839
+ if (owned) {
12840
+ const pid = Number(owned[1]);
12841
+ if (pid === process.pid || running(pid))
12842
+ continue;
12843
+ } else if (readdirSync7(path).length > 0) {
12844
+ continue;
12845
+ }
12846
+ rmSync(path, { recursive: true, force: true });
12847
+ removed += 1;
12848
+ }
12849
+ return removed;
12850
+ }
12823
12851
  var contentTypes = {
12824
12852
  ".html": "text/html; charset=utf-8",
12825
12853
  ".css": "text/css; charset=utf-8",
@@ -12940,8 +12968,9 @@ async function buildLiveUi(cwd, data) {
12940
12968
  const uiDir = resolveUiSourceDir(cwd);
12941
12969
  if (!uiDir)
12942
12970
  return null;
12971
+ let outDir;
12943
12972
  try {
12944
- const outDir = mkdtempSync(join12(tmpdir(), "ts-cloud-dashboard-"));
12973
+ outDir = mkdtempSync(join12(tmpdir(), `${DASHBOARD_TEMP_PREFIX}${process.pid}-`));
12945
12974
  const localStx = join12(uiDir, "node_modules", ".bin", "stx");
12946
12975
  const cmd = existsSync18(localStx) ? [localStx, "build", "--pages", "pages", "--out", outDir, "--no-sitemap", "--no-cache"] : ["bunx", "--bun", "@stacksjs/stx", "build", "--pages", "pages", "--out", outDir, "--no-sitemap", "--no-cache"];
12947
12976
  const proc = Bun.spawn(cmd, {
@@ -12959,6 +12988,7 @@ async function buildLiveUi(cwd, data) {
12959
12988
  proc.exited
12960
12989
  ]);
12961
12990
  if (exitCode !== 0) {
12991
+ rmSync(outDir, { recursive: true, force: true });
12962
12992
  if (process.env.TSCLOUD_DASHBOARD_VERBOSE)
12963
12993
  console.warn(`ts-cloud dashboard: live UI build failed; serving the pre-built UI.
12964
12994
  ${stdout}
@@ -12967,6 +12997,8 @@ ${stderr}`);
12967
12997
  }
12968
12998
  return outDir;
12969
12999
  } catch (err) {
13000
+ if (outDir)
13001
+ rmSync(outDir, { recursive: true, force: true });
12970
13002
  if (process.env.TSCLOUD_DASHBOARD_VERBOSE)
12971
13003
  console.warn(`ts-cloud dashboard: live UI build errored; serving the pre-built UI. ${err.message}`);
12972
13004
  return null;
@@ -13116,6 +13148,7 @@ async function serveStatic(uiRoot, pathname) {
13116
13148
  return new Response(body, { headers: { "content-type": type } });
13117
13149
  }
13118
13150
  async function startLocalDashboardServer(options = {}) {
13151
+ pruneDashboardTempRoots();
13119
13152
  const cwd = options.cwd ?? process.cwd();
13120
13153
  const host = options.host ?? DEFAULT_HOST;
13121
13154
  const port = options.port ?? DEFAULT_PORT;
@@ -13132,20 +13165,49 @@ async function startLocalDashboardServer(options = {}) {
13132
13165
  let latestData = initialData;
13133
13166
  const packagedUi = resolveUiSource(cwd);
13134
13167
  const uiCache = new Map;
13168
+ const uiBuilds = new Map;
13169
+ const ownedUiRoots = new Set;
13170
+ let uiGeneration = 0;
13171
+ function clearUiCache() {
13172
+ uiGeneration += 1;
13173
+ uiCache.clear();
13174
+ for (const root of ownedUiRoots)
13175
+ rmSync(root, { recursive: true, force: true });
13176
+ ownedUiRoots.clear();
13177
+ }
13135
13178
  const scopeKey = (user) => user.role === "admin" ? "admin" : `member:${Object.entries(user.sites).sort(([a], [b]) => a.localeCompare(b)).map(([site, role]) => `${site}=${role}`).join(",")}`;
13136
13179
  async function uiRootFor(user) {
13137
13180
  const key = scopeKey(user);
13138
13181
  const cached = uiCache.get(key);
13139
13182
  if (cached)
13140
13183
  return cached;
13141
- const scoped = {
13142
- ...scopeDashboardData(latestData, { user, slug: config6.project.slug }),
13143
- viewer: { role: user.role }
13144
- };
13145
- const root = await buildLiveUi(cwd, scoped) ?? packagedUi?.uiRoot;
13146
- if (root)
13147
- uiCache.set(key, root);
13148
- return root;
13184
+ const pending = uiBuilds.get(key);
13185
+ if (pending)
13186
+ return pending;
13187
+ const generation = uiGeneration;
13188
+ const build = (async () => {
13189
+ const scoped = {
13190
+ ...scopeDashboardData(latestData, { user, slug: config6.project.slug }),
13191
+ viewer: { role: user.role }
13192
+ };
13193
+ const liveRoot = await buildLiveUi(cwd, scoped);
13194
+ if (liveRoot && generation !== uiGeneration) {
13195
+ rmSync(liveRoot, { recursive: true, force: true });
13196
+ return packagedUi?.uiRoot;
13197
+ }
13198
+ if (liveRoot)
13199
+ ownedUiRoots.add(liveRoot);
13200
+ const root = liveRoot ?? packagedUi?.uiRoot;
13201
+ if (root)
13202
+ uiCache.set(key, root);
13203
+ return root;
13204
+ })();
13205
+ uiBuilds.set(key, build);
13206
+ try {
13207
+ return await build;
13208
+ } finally {
13209
+ uiBuilds.delete(key);
13210
+ }
13149
13211
  }
13150
13212
  const adminUiRoot = await uiRootFor({ username: "", passwordHash: "", role: "admin", sites: {} });
13151
13213
  if (!adminUiRoot)
@@ -13288,7 +13350,7 @@ async function startLocalDashboardServer(options = {}) {
13288
13350
  environment = requested;
13289
13351
  actions = dashboardActions(environment);
13290
13352
  latestData = await resolveLiveDashboardData(config6, environment);
13291
- uiCache.clear();
13353
+ clearUiCache();
13292
13354
  }
13293
13355
  return json({ ok: true, environment, environments: availableEnvironments });
13294
13356
  }
@@ -13560,7 +13622,7 @@ async function startLocalDashboardServer(options = {}) {
13560
13622
  if (password && password.length < 12)
13561
13623
  return json({ ok: false, error: "Password must be at least 12 characters." }, 422);
13562
13624
  const result = upsertMember(cwd, { username, password, name: typeof body.name === "string" ? body.name : undefined, sites });
13563
- uiCache.clear();
13625
+ clearUiCache();
13564
13626
  return json({ ok: true, user: describeUser(result.user), password: result.password });
13565
13627
  }
13566
13628
  if (url.pathname === "/api/users" && req.method === "DELETE") {
@@ -13714,6 +13776,12 @@ async function startLocalDashboardServer(options = {}) {
13714
13776
  }
13715
13777
  }
13716
13778
  });
13779
+ const stop = server.stop.bind(server);
13780
+ server.stop = (closeActiveConnections) => {
13781
+ clearInterval(throttleSweep);
13782
+ clearUiCache();
13783
+ return stop(closeActiveConnections);
13784
+ };
13717
13785
  return { server, url: `http://${host}:${server.port}/` };
13718
13786
  }
13719
13787
  export { defaultConfig4 as defaultConfig, getConfig, loadCloudConfig, config5 as config, collectServerDnsDomains, removeStaleServerAddressRecords, deploySite, infraEnvFromOutputs, buildFunctionEnv, deployServerlessApp, redeployServerlessApp, rollbackServerlessApp, setMaintenance, runRemoteCommand, resolveDashboardData, sanitizeCloudConfig, dashboardActions, resolveDashboardAction, startLocalDashboardServer };
@@ -14,7 +14,7 @@ import {
14
14
  sanitizeCloudConfig,
15
15
  setMaintenance,
16
16
  startLocalDashboardServer
17
- } from "../chunk-qdsvsrbt.js";
17
+ } from "../chunk-2mw2566h.js";
18
18
  import {
19
19
  buildAndPushServerlessImage
20
20
  } from "../chunk-tskj9fay.js";
@@ -25,6 +25,7 @@ export interface DashboardAction {
25
25
  mutates: boolean;
26
26
  confirm?: string;
27
27
  }
28
+ export declare function pruneDashboardTempRoots(root?: string, running?: (pid: number) => boolean): number;
28
29
  export declare function sanitizeCloudConfig(config: CloudConfig): Record<string, any>;
29
30
  export declare function dashboardActions(environment: EnvironmentType): DashboardAction[];
30
31
  export declare function resolveDashboardAction(id: string, environment: EnvironmentType): DashboardAction | undefined;
package/dist/index.js CHANGED
@@ -57,7 +57,7 @@ import {
57
57
  sanitizeCloudConfig,
58
58
  setMaintenance,
59
59
  startLocalDashboardServer
60
- } from "./chunk-qdsvsrbt.js";
60
+ } from "./chunk-2mw2566h.js";
61
61
  import {
62
62
  buildAndPushServerlessImage
63
63
  } from "./chunk-tskj9fay.js";