@arcote.tech/arc-cli 0.8.4 → 0.8.5

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/index.js CHANGED
@@ -31322,8 +31322,8 @@ ${colors3.yellow}Type declaration errors:${colors3.reset}`);
31322
31322
  }
31323
31323
 
31324
31324
  // src/platform/shared.ts
31325
- import { copyFileSync, existsSync as existsSync11, mkdirSync as mkdirSync10, readdirSync as readdirSync6, readFileSync as readFileSync12, writeFileSync as writeFileSync10 } from "fs";
31326
- import { dirname as dirname8, join as join13 } from "path";
31325
+ import { copyFileSync, existsSync as existsSync12, mkdirSync as mkdirSync10, readdirSync as readdirSync7, readFileSync as readFileSync13, writeFileSync as writeFileSync10 } from "fs";
31326
+ import { dirname as dirname8, join as join14 } from "path";
31327
31327
 
31328
31328
  // src/builder/module-builder.ts
31329
31329
  import { execSync } from "child_process";
@@ -32023,6 +32023,26 @@ function readServerExternals(path4) {
32023
32023
  return [];
32024
32024
  }
32025
32025
  }
32026
+ var STATIC_CHUNK_IMPORT = /(?:^|[;}\s])import\s*["']\.\/(chunk-[a-z0-9]+\.js)["']|from\s*["']\.\/(chunk-[a-z0-9]+\.js)["']/g;
32027
+ function staticChunkClosure(entryBytes, chunkBytes) {
32028
+ const seen = new Set;
32029
+ const stack = [entryBytes];
32030
+ while (stack.length) {
32031
+ const src = Buffer.from(stack.pop()).toString("utf8");
32032
+ STATIC_CHUNK_IMPORT.lastIndex = 0;
32033
+ let m;
32034
+ while (m = STATIC_CHUNK_IMPORT.exec(src)) {
32035
+ const chunk = m[1] ?? m[2];
32036
+ if (seen.has(chunk))
32037
+ continue;
32038
+ seen.add(chunk);
32039
+ const b = chunkBytes.get(chunk);
32040
+ if (b)
32041
+ stack.push(b);
32042
+ }
32043
+ }
32044
+ return [...seen];
32045
+ }
32026
32046
  function buildStatsEnabled() {
32027
32047
  return process.env.ARC_BUILD_STATS === "1";
32028
32048
  }
@@ -32322,22 +32342,31 @@ export { startApp } from "@arcote.tech/platform";
32322
32342
  }
32323
32343
  let initialFile = "";
32324
32344
  let initialHash = "";
32345
+ let initialStaticChunks = [];
32325
32346
  const groups = {};
32326
32347
  const sharedChunks = [];
32348
+ const chunkBytes = new Map;
32349
+ for (const out of outFiles) {
32350
+ if (out.kind === "chunk")
32351
+ chunkBytes.set(out.name, out.bytes);
32352
+ }
32327
32353
  for (const out of outFiles) {
32328
32354
  if (out.kind === "entry-point") {
32329
32355
  const hash = sha256Hex(out.bytes).slice(0, 16);
32330
32356
  const stem = out.name.replace(/\.js$/, "");
32331
32357
  const finalName = `${stem}.${hash}.js`;
32332
32358
  writeFileSync7(join9(outDir, finalName), out.bytes);
32359
+ const staticChunks = staticChunkClosure(out.bytes, chunkBytes);
32333
32360
  if (stem === "initial") {
32334
32361
  initialFile = finalName;
32335
32362
  initialHash = hash;
32363
+ initialStaticChunks = staticChunks;
32336
32364
  } else {
32337
32365
  groups[stem] = {
32338
32366
  file: finalName,
32339
32367
  hash,
32340
- modules: groupModuleMap.get(stem) ?? []
32368
+ modules: groupModuleMap.get(stem) ?? [],
32369
+ staticChunks
32341
32370
  };
32342
32371
  }
32343
32372
  } else if (out.kind === "chunk") {
@@ -32365,7 +32394,7 @@ export { startApp } from "@arcote.tech/platform";
32365
32394
  }
32366
32395
  }
32367
32396
  const manifest = {
32368
- initial: { file: initialFile, hash: initialHash },
32397
+ initial: { file: initialFile, hash: initialHash, staticChunks: initialStaticChunks },
32369
32398
  groups,
32370
32399
  sharedChunks,
32371
32400
  cached: false
@@ -32629,9 +32658,86 @@ const { writeFileSync } = await import("node:fs");
32629
32658
  writeFileSync(out, JSON.stringify({ access, exposure }, null, 2) + "\\n");
32630
32659
  `.trim();
32631
32660
 
32661
+ // src/builder/seed-guard.ts
32662
+ import { existsSync as existsSync10, readdirSync as readdirSync5, readFileSync as readFileSync10 } from "fs";
32663
+ import { join as join11, relative as relative4, sep as sep3 } from "path";
32664
+ var CALL = /\.(?:seedWith|withSeeds)\s*\(/g;
32665
+ var GATED = /^\.(?:seedWith|withSeeds)\s*\(\s*ONLY_SERVER\b/;
32666
+ function walkTsFiles(dir, out) {
32667
+ for (const entry of readdirSync5(dir, { withFileTypes: true })) {
32668
+ if (entry.name === "node_modules" || entry.name === "dist")
32669
+ continue;
32670
+ const abs = join11(dir, entry.name);
32671
+ if (entry.isDirectory()) {
32672
+ if (entry.name === "__tests__")
32673
+ continue;
32674
+ walkTsFiles(abs, out);
32675
+ } else if (entry.isFile() && /\.(ts|tsx)$/.test(entry.name) && !entry.name.endsWith(".d.ts")) {
32676
+ out.push(abs);
32677
+ }
32678
+ }
32679
+ }
32680
+ function findUngatedSeeds(pkgs, rootDir) {
32681
+ const leaks = [];
32682
+ const scanned = new Set;
32683
+ for (const pkg of pkgs) {
32684
+ const srcDir = join11(pkg.path, "src");
32685
+ if (scanned.has(srcDir) || !existsSync10(srcDir))
32686
+ continue;
32687
+ scanned.add(srcDir);
32688
+ const files = [];
32689
+ walkTsFiles(srcDir, files);
32690
+ for (const abs of files) {
32691
+ const content = readFileSync10(abs, "utf-8");
32692
+ CALL.lastIndex = 0;
32693
+ let m;
32694
+ while ((m = CALL.exec(content)) !== null) {
32695
+ const rest = content.slice(m.index);
32696
+ if (GATED.test(rest))
32697
+ continue;
32698
+ const lineStart = content.lastIndexOf(`
32699
+ `, m.index) + 1;
32700
+ if (content.slice(lineStart, m.index).includes("//"))
32701
+ continue;
32702
+ const before = content.slice(0, m.index);
32703
+ if (before.lastIndexOf("/*") > before.lastIndexOf("*/"))
32704
+ continue;
32705
+ const nlAfter = content.indexOf(`
32706
+ `, m.index);
32707
+ const lineEnd = nlAfter === -1 ? content.length : nlAfter;
32708
+ const line = content.slice(0, m.index).split(`
32709
+ `).length;
32710
+ const relpath = relative4(rootDir, abs).split(sep3).join("/");
32711
+ leaks.push({
32712
+ relpath,
32713
+ line,
32714
+ snippet: content.slice(lineStart, lineEnd).trim().slice(0, 120)
32715
+ });
32716
+ }
32717
+ }
32718
+ }
32719
+ return leaks;
32720
+ }
32721
+ function assertSeedsServerGated(pkgs, rootDir) {
32722
+ const leaks = findUngatedSeeds(pkgs, rootDir);
32723
+ if (leaks.length === 0)
32724
+ return;
32725
+ const lines = leaks.map((l) => ` \u2022 ${l.relpath}:${l.line}
32726
+ ${l.snippet}`).join(`
32727
+ `);
32728
+ throw new Error(`Seed leak do bundla klienta: ${leaks.length} wywo\u0142a\u0144 .seedWith(...)/.withSeeds(...) ` + `nie jest owini\u0119tych w ONLY_SERVER.
32729
+
32730
+ ${lines}
32731
+
32732
+ ` + `Dane seed czyta wy\u0142\u0105cznie host (runSeeds) \u2014 po stronie klienta s\u0105 zb\u0119dne i ` + `wyciekaj\u0105 do PUBLICZNEGO bundla przegl\u0105darki. Zgejtuj argument w miejscu:
32733
+ ` + ` .seedWith(ONLY_SERVER ? [ /* wiersze */ ] : [])
32734
+ ` + ` .seedWith(ONLY_SERVER ? (await import("./seeds.server")).rows : [])
32735
+ ` + `Statyczny import z osobnego pliku NIE pomaga (build wymusza sideEffects:true).`);
32736
+ }
32737
+
32632
32738
  // src/builder/chunk-planner.ts
32633
- import { readFileSync as readFileSync10, readdirSync as readdirSync5, statSync as statSync2 } from "fs";
32634
- import { basename as basename4, join as join11 } from "path";
32739
+ import { readFileSync as readFileSync11, readdirSync as readdirSync6, statSync as statSync2 } from "fs";
32740
+ import { basename as basename4, join as join12 } from "path";
32635
32741
  var PUBLIC_CHUNK = "public";
32636
32742
  function planChunks(packages, accessMap) {
32637
32743
  const assignments = new Map;
@@ -32667,14 +32773,14 @@ var MODULE_CALL = /\bmodule\(\s*["'`]([a-zA-Z0-9_-]+)["'`]/g;
32667
32773
  function collectModuleNames(dir, acc) {
32668
32774
  let entries;
32669
32775
  try {
32670
- entries = readdirSync5(dir);
32776
+ entries = readdirSync6(dir);
32671
32777
  } catch {
32672
32778
  return;
32673
32779
  }
32674
32780
  for (const e of entries) {
32675
32781
  if (e === "node_modules" || e === "dist")
32676
32782
  continue;
32677
- const full = join11(dir, e);
32783
+ const full = join12(dir, e);
32678
32784
  let isDir = false;
32679
32785
  try {
32680
32786
  isDir = statSync2(full).isDirectory();
@@ -32684,7 +32790,7 @@ function collectModuleNames(dir, acc) {
32684
32790
  if (isDir) {
32685
32791
  collectModuleNames(full, acc);
32686
32792
  } else if (e.endsWith(".ts") || e.endsWith(".tsx")) {
32687
- const src = readFileSync10(full, "utf-8");
32793
+ const src = readFileSync11(full, "utf-8");
32688
32794
  MODULE_CALL.lastIndex = 0;
32689
32795
  let m;
32690
32796
  while (m = MODULE_CALL.exec(src))
@@ -32694,14 +32800,14 @@ function collectModuleNames(dir, acc) {
32694
32800
  }
32695
32801
  function packageDeclaresModule(pkg) {
32696
32802
  const names = new Set;
32697
- collectModuleNames(join11(pkg.path, "src"), names);
32803
+ collectModuleNames(join12(pkg.path, "src"), names);
32698
32804
  return names.size > 0;
32699
32805
  }
32700
32806
  function assertOneModulePerPackage(packages) {
32701
32807
  const offenders = [];
32702
32808
  for (const pkg of packages) {
32703
32809
  const names = new Set;
32704
- collectModuleNames(join11(pkg.path, "src"), names);
32810
+ collectModuleNames(join12(pkg.path, "src"), names);
32705
32811
  if (names.size > 1) {
32706
32812
  offenders.push({ pkg: pkg.name, modules: [...names].sort() });
32707
32813
  }
@@ -32733,8 +32839,8 @@ function resolveChunk(moduleName, access) {
32733
32839
 
32734
32840
  // src/builder/dependency-collector.ts
32735
32841
  import { createHash } from "crypto";
32736
- import { existsSync as existsSync10, mkdirSync as mkdirSync9, readFileSync as readFileSync11, writeFileSync as writeFileSync9 } from "fs";
32737
- import { basename as basename5, dirname as dirname7, join as join12 } from "path";
32842
+ import { existsSync as existsSync11, mkdirSync as mkdirSync9, readFileSync as readFileSync12, writeFileSync as writeFileSync9 } from "fs";
32843
+ import { basename as basename5, dirname as dirname7, join as join13 } from "path";
32738
32844
  import { fileURLToPath as fileURLToPath6 } from "url";
32739
32845
  function collectFrameworkDeps(arcDir, rootDir, packages, sharedDeps = [], serverExternals = []) {
32740
32846
  mkdirSync9(arcDir, { recursive: true });
@@ -32746,7 +32852,7 @@ function collectFrameworkDeps(arcDir, rootDir, packages, sharedDeps = [], server
32746
32852
  try {
32747
32853
  const cliDir = dirname7(fileURLToPath6(import.meta.url));
32748
32854
  const arcOtelPkgPath = Bun.resolveSync("@arcote.tech/arc-otel/package.json", cliDir);
32749
- const arcOtelPkg = JSON.parse(readFileSync11(arcOtelPkgPath, "utf-8"));
32855
+ const arcOtelPkg = JSON.parse(readFileSync12(arcOtelPkgPath, "utf-8"));
32750
32856
  for (const [name, spec] of Object.entries(arcOtelPkg.dependencies ?? {})) {
32751
32857
  if (name.startsWith("@opentelemetry/")) {
32752
32858
  versions[name] = spec;
@@ -32757,10 +32863,10 @@ function collectFrameworkDeps(arcDir, rootDir, packages, sharedDeps = [], server
32757
32863
  console.warn(`[arc-otel] could not resolve @arcote.tech/arc-otel \u2014 image will run without telemetry deps: ${e.message}`);
32758
32864
  }
32759
32865
  let rootArc;
32760
- const rootPkgPath = join12(rootDir, "package.json");
32761
- if (existsSync10(rootPkgPath)) {
32866
+ const rootPkgPath = join13(rootDir, "package.json");
32867
+ if (existsSync11(rootPkgPath)) {
32762
32868
  try {
32763
- const rootPkg = JSON.parse(readFileSync11(rootPkgPath, "utf-8"));
32869
+ const rootPkg = JSON.parse(readFileSync12(rootPkgPath, "utf-8"));
32764
32870
  if (rootPkg.arc && typeof rootPkg.arc === "object")
32765
32871
  rootArc = rootPkg.arc;
32766
32872
  } catch {}
@@ -32772,11 +32878,11 @@ function collectFrameworkDeps(arcDir, rootDir, packages, sharedDeps = [], server
32772
32878
  dependencies: versions,
32773
32879
  ...rootArc ? { arc: rootArc } : {}
32774
32880
  };
32775
- const manifestPath = join12(arcDir, "package.json");
32881
+ const manifestPath = join13(arcDir, "package.json");
32776
32882
  writeFileSync9(manifestPath, JSON.stringify(manifest, null, 2) + `
32777
32883
  `);
32778
- const hash = sha256Hex2(readFileSync11(manifestPath));
32779
- writeFileSync9(join12(arcDir, ".deps-hash"), hash + `
32884
+ const hash = sha256Hex2(readFileSync12(manifestPath));
32885
+ writeFileSync9(join13(arcDir, ".deps-hash"), hash + `
32780
32886
  `);
32781
32887
  return { hash, manifestPath };
32782
32888
  }
@@ -32784,7 +32890,7 @@ function sha256Hex2(bytes) {
32784
32890
  return createHash("sha256").update(bytes).digest("hex");
32785
32891
  }
32786
32892
  function resolveFrameworkVersions(rootDir, packages) {
32787
- const rootPkg = JSON.parse(readFileSync11(join12(rootDir, "package.json"), "utf-8"));
32893
+ const rootPkg = JSON.parse(readFileSync12(join13(rootDir, "package.json"), "utf-8"));
32788
32894
  const rootDeps = rootPkg.dependencies ?? {};
32789
32895
  const rootDevDeps = rootPkg.devDependencies ?? {};
32790
32896
  const required = new Set(FRAMEWORK_PEERS);
@@ -32815,7 +32921,7 @@ function findWorkspaceSpec(packages, name) {
32815
32921
  return;
32816
32922
  }
32817
32923
  function mergeServerExternals(versions, rootDir, packages, externals) {
32818
- const rootPkg = JSON.parse(readFileSync11(join12(rootDir, "package.json"), "utf-8"));
32924
+ const rootPkg = JSON.parse(readFileSync12(join13(rootDir, "package.json"), "utf-8"));
32819
32925
  const rootDeps = rootPkg.dependencies ?? {};
32820
32926
  const rootDevDeps = rootPkg.devDependencies ?? {};
32821
32927
  for (const { name, version } of externals) {
@@ -32843,9 +32949,9 @@ function resolveWorkspace() {
32843
32949
  process.exit(1);
32844
32950
  }
32845
32951
  const rootDir = dirname8(packageJsonPath);
32846
- const rootPkg = JSON.parse(readFileSync12(packageJsonPath, "utf-8"));
32952
+ const rootPkg = JSON.parse(readFileSync13(packageJsonPath, "utf-8"));
32847
32953
  const appName = rootPkg.name ?? "Arc App";
32848
- const arcDir = join13(rootDir, ".arc", "platform");
32954
+ const arcDir = join14(rootDir, ".arc", "platform");
32849
32955
  log2("Scanning workspaces...");
32850
32956
  const packages = discoverPackages(rootDir);
32851
32957
  if (packages.length > 0) {
@@ -32855,10 +32961,10 @@ function resolveWorkspace() {
32855
32961
  }
32856
32962
  let manifest;
32857
32963
  for (const name of ["manifest.json", "manifest.webmanifest"]) {
32858
- const manifestPath = join13(rootDir, name);
32859
- if (existsSync11(manifestPath)) {
32964
+ const manifestPath = join14(rootDir, name);
32965
+ if (existsSync12(manifestPath)) {
32860
32966
  try {
32861
- const data = JSON.parse(readFileSync12(manifestPath, "utf-8"));
32967
+ const data = JSON.parse(readFileSync13(manifestPath, "utf-8"));
32862
32968
  const icons = data.icons;
32863
32969
  manifest = {
32864
32970
  path: manifestPath,
@@ -32877,9 +32983,9 @@ function resolveWorkspace() {
32877
32983
  rootPkg,
32878
32984
  appName,
32879
32985
  arcDir,
32880
- browserDir: join13(arcDir, "browser"),
32881
- assetsDir: join13(arcDir, "assets"),
32882
- publicDir: join13(rootDir, "public"),
32986
+ browserDir: join14(arcDir, "browser"),
32987
+ assetsDir: join14(arcDir, "assets"),
32988
+ publicDir: join14(rootDir, "public"),
32883
32989
  packages,
32884
32990
  manifest
32885
32991
  };
@@ -32892,12 +32998,13 @@ async function buildAll(ws, opts = {}) {
32892
32998
  const federation = getFederationConfig(ws);
32893
32999
  log2(`Building (concurrency parallel${noCache ? ", no-cache" : ""})...`);
32894
33000
  assertOneModulePerPackage(ws.packages);
33001
+ assertSeedsServerGated(ws.packages, ws.rootDir);
32895
33002
  await buildContextPackages(ws.rootDir, ws.packages, cache, noCache);
32896
- const serverDir = join13(ws.arcDir, "server");
33003
+ const serverDir = join14(ws.arcDir, "server");
32897
33004
  const { entryFile: serverEntry, externals: serverExternals } = await buildServerApp(ws.rootDir, serverDir, ws.packages, cache, noCache);
32898
- const accessMap = await extractAccessMap(ws.rootDir, join13(serverDir, serverEntry));
33005
+ const accessMap = await extractAccessMap(ws.rootDir, join14(serverDir, serverEntry));
32899
33006
  mkdirSync10(ws.arcDir, { recursive: true });
32900
- writeFileSync10(join13(ws.arcDir, "access.json"), JSON.stringify(accessMap.access, null, 2) + `
33007
+ writeFileSync10(join14(ws.arcDir, "access.json"), JSON.stringify(accessMap.access, null, 2) + `
32901
33008
  `);
32902
33009
  const isHost = Boolean(federation?.host);
32903
33010
  const moduleNameOf2 = (name) => name.split("/").pop() ?? name;
@@ -32917,7 +33024,7 @@ async function buildAll(ws, opts = {}) {
32917
33024
  const i18nCollector = new Map;
32918
33025
  const browserSequence = (async () => {
32919
33026
  const bundled = await buildBrowserApp(ws.rootDir, ws.browserDir, plan, cache, noCache, i18nCollector, { federated: false, exposeRuntime: isHost, minify });
32920
- const fed = fedPlan ? await buildBrowserApp(ws.rootDir, join13(ws.arcDir, "browser-fed"), fedPlan, cache, noCache, i18nCollector, { federated: true, unitId: "browser-app-fed", minify }) : undefined;
33027
+ const fed = fedPlan ? await buildBrowserApp(ws.rootDir, join14(ws.arcDir, "browser-fed"), fedPlan, cache, noCache, i18nCollector, { federated: true, unitId: "browser-app-fed", minify }) : undefined;
32921
33028
  return { bundled, fed };
32922
33029
  })();
32923
33030
  const [{ bundled: browserResult, fed: fedResult }, , , , shellResult] = await Promise.all([
@@ -32925,7 +33032,7 @@ async function buildAll(ws, opts = {}) {
32925
33032
  buildStyles(ws.rootDir, ws.arcDir, ws.packages, themePath, cache, noCache),
32926
33033
  copyBrowserAssets(ws, cache, noCache),
32927
33034
  buildTranslations(ws.rootDir, ws.arcDir, cache, noCache),
32928
- needsPeerShell ? buildPeerShell(ws.rootDir, join13(ws.arcDir, "shell"), cache, noCache) : Promise.resolve(undefined)
33035
+ needsPeerShell ? buildPeerShell(ws.rootDir, join14(ws.arcDir, "shell"), cache, noCache) : Promise.resolve(undefined)
32929
33036
  ]);
32930
33037
  const { finalizeTranslations: finalizeTranslations3 } = await Promise.resolve().then(() => (init_i18n(), exports_i18n));
32931
33038
  await finalizeTranslations3(ws.rootDir, ws.arcDir, i18nCollector);
@@ -32950,7 +33057,7 @@ async function buildAll(ws, opts = {}) {
32950
33057
  }
32951
33058
  } : undefined;
32952
33059
  const finalManifest = assembleManifest(ws, browserResult, cache, shellResult, federationBuild);
32953
- writeFileSync10(join13(ws.arcDir, "manifest.json"), JSON.stringify(finalManifest, null, 2));
33060
+ writeFileSync10(join14(ws.arcDir, "manifest.json"), JSON.stringify(finalManifest, null, 2));
32954
33061
  return finalManifest;
32955
33062
  }
32956
33063
  function assembleManifest(ws, browser, cache, shell, federation) {
@@ -32976,35 +33083,35 @@ function getFederationConfig(ws) {
32976
33083
  }
32977
33084
  function resolveAssetSource(from, pkgDir, rootDir) {
32978
33085
  if (from.startsWith("./") || from.startsWith("../")) {
32979
- const resolved = join13(pkgDir, from);
32980
- return existsSync11(resolved) ? resolved : null;
33086
+ const resolved = join14(pkgDir, from);
33087
+ return existsSync12(resolved) ? resolved : null;
32981
33088
  }
32982
33089
  const candidates = [
32983
- join13(rootDir, "node_modules", from),
32984
- join13(pkgDir, "node_modules", from)
33090
+ join14(rootDir, "node_modules", from),
33091
+ join14(pkgDir, "node_modules", from)
32985
33092
  ];
32986
33093
  for (const c of candidates) {
32987
- if (existsSync11(c))
33094
+ if (existsSync12(c))
32988
33095
  return c;
32989
33096
  }
32990
- const bunCacheDir = join13(rootDir, "node_modules", ".bun");
32991
- if (existsSync11(bunCacheDir)) {
32992
- for (const entry of readdirSync6(bunCacheDir, { withFileTypes: true })) {
33097
+ const bunCacheDir = join14(rootDir, "node_modules", ".bun");
33098
+ if (existsSync12(bunCacheDir)) {
33099
+ for (const entry of readdirSync7(bunCacheDir, { withFileTypes: true })) {
32993
33100
  if (!entry.isDirectory())
32994
33101
  continue;
32995
- const candidate = join13(bunCacheDir, entry.name, "node_modules", from);
32996
- if (existsSync11(candidate))
33102
+ const candidate = join14(bunCacheDir, entry.name, "node_modules", from);
33103
+ if (existsSync12(candidate))
32997
33104
  return candidate;
32998
33105
  }
32999
33106
  }
33000
33107
  return null;
33001
33108
  }
33002
33109
  function readBrowserAssets(pkgDir) {
33003
- const pkgJsonPath = join13(pkgDir, "package.json");
33004
- if (!existsSync11(pkgJsonPath))
33110
+ const pkgJsonPath = join14(pkgDir, "package.json");
33111
+ if (!existsSync12(pkgJsonPath))
33005
33112
  return [];
33006
33113
  try {
33007
- const pkg = JSON.parse(readFileSync12(pkgJsonPath, "utf-8"));
33114
+ const pkg = JSON.parse(readFileSync13(pkgJsonPath, "utf-8"));
33008
33115
  const assets = pkg.arc?.browserAssets;
33009
33116
  if (!Array.isArray(assets))
33010
33117
  return [];
@@ -33014,14 +33121,14 @@ function readBrowserAssets(pkgDir) {
33014
33121
  }
33015
33122
  }
33016
33123
  function discoverBrowserAssets(ws) {
33017
- const arcDir = join13(ws.rootDir, "node_modules", "@arcote.tech");
33018
- if (!existsSync11(arcDir))
33124
+ const arcDir = join14(ws.rootDir, "node_modules", "@arcote.tech");
33125
+ if (!existsSync12(arcDir))
33019
33126
  return [];
33020
33127
  const out = [];
33021
- for (const entry of readdirSync6(arcDir, { withFileTypes: true })) {
33128
+ for (const entry of readdirSync7(arcDir, { withFileTypes: true })) {
33022
33129
  if (!entry.isDirectory() && !entry.isSymbolicLink())
33023
33130
  continue;
33024
- const pkgDir = join13(arcDir, entry.name);
33131
+ const pkgDir = join14(arcDir, entry.name);
33025
33132
  const assets = readBrowserAssets(pkgDir);
33026
33133
  for (const asset of assets) {
33027
33134
  const src = resolveAssetSource(asset.from, pkgDir, ws.rootDir);
@@ -33046,7 +33153,7 @@ async function copyBrowserAssets(ws, cache, noCache) {
33046
33153
  to: a.to,
33047
33154
  mtime: mtimeOf(a.src)
33048
33155
  })));
33049
- const requiredOutputs = assets.map((a) => join13(ws.assetsDir, a.to));
33156
+ const requiredOutputs = assets.map((a) => join14(ws.assetsDir, a.to));
33050
33157
  if (!noCache && isCacheHit(cache, unitId, inputHash, requiredOutputs)) {
33051
33158
  console.log(` \u2713 cached: browser-assets (${assets.length})`);
33052
33159
  return;
@@ -33054,10 +33161,10 @@ async function copyBrowserAssets(ws, cache, noCache) {
33054
33161
  console.log(` building: browser-assets (${assets.length})`);
33055
33162
  const outputHashes = {};
33056
33163
  for (const asset of assets) {
33057
- const dest = join13(ws.assetsDir, asset.to);
33164
+ const dest = join14(ws.assetsDir, asset.to);
33058
33165
  mkdirSync10(dirname8(dest), { recursive: true });
33059
33166
  copyFileSync(asset.src, dest);
33060
- outputHashes[asset.to] = sha256Hex(readFileSync12(dest));
33167
+ outputHashes[asset.to] = sha256Hex(readFileSync13(dest));
33061
33168
  }
33062
33169
  updateCache(cache, unitId, inputHash, { outputHashes });
33063
33170
  }
@@ -33065,12 +33172,12 @@ async function loadServerContext(ws) {
33065
33172
  globalThis.ONLY_SERVER = true;
33066
33173
  globalThis.ONLY_BROWSER = false;
33067
33174
  globalThis.ONLY_CLIENT = false;
33068
- const platformDir = join13(process.cwd(), "node_modules", "@arcote.tech", "platform");
33069
- const platformPkg = JSON.parse(readFileSync12(join13(platformDir, "package.json"), "utf-8"));
33070
- const platformEntry = join13(platformDir, platformPkg.main ?? "src/index.ts");
33175
+ const platformDir = join14(process.cwd(), "node_modules", "@arcote.tech", "platform");
33176
+ const platformPkg = JSON.parse(readFileSync13(join14(platformDir, "package.json"), "utf-8"));
33177
+ const platformEntry = join14(platformDir, platformPkg.main ?? "src/index.ts");
33071
33178
  await import(platformEntry);
33072
- const serverEntry = join13(ws.arcDir, "server", SERVER_ENTRY_FILE);
33073
- if (!existsSync11(serverEntry)) {
33179
+ const serverEntry = join14(ws.arcDir, "server", SERVER_ENTRY_FILE);
33180
+ if (!existsSync12(serverEntry)) {
33074
33181
  return { context: null, moduleAccess: new Map };
33075
33182
  }
33076
33183
  let serverError;
@@ -33100,21 +33207,21 @@ async function platformBuild(opts = {}) {
33100
33207
 
33101
33208
  // src/commands/platform-deploy.ts
33102
33209
  import { randomBytes } from "crypto";
33103
- import { existsSync as existsSync18, readFileSync as readFileSync16 } from "fs";
33104
- import { dirname as dirname11, join as join21 } from "path";
33210
+ import { existsSync as existsSync19, readFileSync as readFileSync17 } from "fs";
33211
+ import { dirname as dirname11, join as join22 } from "path";
33105
33212
  import { fileURLToPath as fileURLToPath8 } from "url";
33106
33213
 
33107
33214
  // src/deploy/bootstrap.ts
33108
33215
  var {spawn: spawn4 } = globalThis.Bun;
33109
33216
  import { mkdirSync as mkdirSync13, writeFileSync as writeFileSync14 } from "fs";
33110
33217
  import { tmpdir as tmpdir2 } from "os";
33111
- import { dirname as dirname9, join as join19 } from "path";
33218
+ import { dirname as dirname9, join as join20 } from "path";
33112
33219
 
33113
33220
  // src/deploy/ansible.ts
33114
33221
  import { spawn as nodeSpawn } from "child_process";
33115
- import { existsSync as existsSync12, mkdirSync as mkdirSync11, writeFileSync as writeFileSync11 } from "fs";
33222
+ import { existsSync as existsSync13, mkdirSync as mkdirSync11, writeFileSync as writeFileSync11 } from "fs";
33116
33223
  import { homedir, tmpdir } from "os";
33117
- import { join as join14 } from "path";
33224
+ import { join as join15 } from "path";
33118
33225
 
33119
33226
  // src/deploy/assets.ts
33120
33227
  var TERRAFORM_MAIN_TF = `terraform {
@@ -33428,28 +33535,28 @@ var ASSETS = {
33428
33535
  };
33429
33536
  async function materializeAssets(targetDir, files) {
33430
33537
  const { mkdirSync: mkdirSync11, writeFileSync: writeFileSync11 } = await import("fs");
33431
- const { join: join14 } = await import("path");
33538
+ const { join: join15 } = await import("path");
33432
33539
  mkdirSync11(targetDir, { recursive: true });
33433
33540
  for (const [name, content] of Object.entries(files)) {
33434
- writeFileSync11(join14(targetDir, name), content);
33541
+ writeFileSync11(join15(targetDir, name), content);
33435
33542
  }
33436
33543
  }
33437
33544
 
33438
33545
  // src/deploy/ansible.ts
33439
33546
  function pickSshKeyForAnsible(configured) {
33440
33547
  if (configured) {
33441
- const expanded = configured.startsWith("~") ? join14(homedir(), configured.slice(1)) : configured;
33442
- return existsSync12(expanded) ? expanded : null;
33548
+ const expanded = configured.startsWith("~") ? join15(homedir(), configured.slice(1)) : configured;
33549
+ return existsSync13(expanded) ? expanded : null;
33443
33550
  }
33444
33551
  for (const name of ["id_ed25519", "id_ecdsa", "id_rsa"]) {
33445
- const path4 = join14(homedir(), ".ssh", name);
33446
- if (existsSync12(path4))
33552
+ const path4 = join15(homedir(), ".ssh", name);
33553
+ if (existsSync13(path4))
33447
33554
  return path4;
33448
33555
  }
33449
33556
  return null;
33450
33557
  }
33451
33558
  async function runAnsible(inputs) {
33452
- const workDir = join14(tmpdir(), "arc-deploy", `ansible-${Date.now()}`);
33559
+ const workDir = join15(tmpdir(), "arc-deploy", `ansible-${Date.now()}`);
33453
33560
  mkdirSync11(workDir, { recursive: true });
33454
33561
  await materializeAssets(workDir, ASSETS.ansible);
33455
33562
  const user = inputs.asRoot ? "root" : inputs.target.user;
@@ -33466,7 +33573,7 @@ async function runAnsible(inputs) {
33466
33573
  ""
33467
33574
  ].join(`
33468
33575
  `);
33469
- writeFileSync11(join14(workDir, "inventory.ini"), inventory);
33576
+ writeFileSync11(join15(workDir, "inventory.ini"), inventory);
33470
33577
  const extraVarsJson = JSON.stringify({
33471
33578
  username: inputs.target.user,
33472
33579
  ssh_port: port,
@@ -35026,16 +35133,16 @@ function panelTimeseries(title, gridPos, query, legend, unit, datasource = PROME
35026
35133
  // src/deploy/terraform.ts
35027
35134
  import { spawn as nodeSpawn2 } from "child_process";
35028
35135
  import { createHash as createHash2 } from "crypto";
35029
- import { existsSync as existsSync13, mkdirSync as mkdirSync12, writeFileSync as writeFileSync12 } from "fs";
35136
+ import { existsSync as existsSync14, mkdirSync as mkdirSync12, writeFileSync as writeFileSync12 } from "fs";
35030
35137
  import { homedir as homedir2 } from "os";
35031
- import { join as join15 } from "path";
35138
+ import { join as join16 } from "path";
35032
35139
  async function runTerraform(inputs) {
35033
35140
  const wsHash = createHash2("sha256").update(inputs.workspaceDir).digest("hex").slice(0, 16);
35034
- const workDir = join15(homedir2(), ".arc-deploy", wsHash, "tf");
35141
+ const workDir = join16(homedir2(), ".arc-deploy", wsHash, "tf");
35035
35142
  mkdirSync12(workDir, { recursive: true });
35036
35143
  await materializeAssets(workDir, ASSETS.terraform);
35037
35144
  const sshPubKey = inputs.tf.sshPublicKey ?? expandHome("~/.ssh/id_ed25519.pub");
35038
- if (!existsSync13(expandHome(sshPubKey))) {
35145
+ if (!existsSync14(expandHome(sshPubKey))) {
35039
35146
  throw new Error(`SSH public key not found at ${sshPubKey}. Set provision.terraform.sshPublicKey in deploy.arc.json.`);
35040
35147
  }
35041
35148
  const tfvars = [
@@ -35049,7 +35156,7 @@ async function runTerraform(inputs) {
35049
35156
  ].join(`
35050
35157
  `) + `
35051
35158
  `;
35052
- writeFileSync12(join15(workDir, "terraform.tfvars"), tfvars);
35159
+ writeFileSync12(join16(workDir, "terraform.tfvars"), tfvars);
35053
35160
  await runTf(workDir, ["init", "-input=false", "-no-color"]);
35054
35161
  await runTf(workDir, [
35055
35162
  "apply",
@@ -35107,20 +35214,20 @@ function expandHome(p) {
35107
35214
  }
35108
35215
 
35109
35216
  // src/deploy/config.ts
35110
- import { existsSync as existsSync15, readFileSync as readFileSync14, writeFileSync as writeFileSync13 } from "fs";
35111
- import { join as join17 } from "path";
35217
+ import { existsSync as existsSync16, readFileSync as readFileSync15, writeFileSync as writeFileSync13 } from "fs";
35218
+ import { join as join18 } from "path";
35112
35219
 
35113
35220
  // src/deploy/env-file.ts
35114
- import { appendFileSync, existsSync as existsSync14, readFileSync as readFileSync13 } from "fs";
35115
- import { join as join16 } from "path";
35221
+ import { appendFileSync, existsSync as existsSync15, readFileSync as readFileSync14 } from "fs";
35222
+ import { join as join17 } from "path";
35116
35223
  function loadDeployEnvFiles(rootDir, envNames) {
35117
- const globalsPath = join16(rootDir, "deploy.arc.env");
35118
- const globals = existsSync14(globalsPath) ? parseEnvFile(readFileSync13(globalsPath, "utf-8"), globalsPath) : {};
35224
+ const globalsPath = join17(rootDir, "deploy.arc.env");
35225
+ const globals = existsSync15(globalsPath) ? parseEnvFile(readFileSync14(globalsPath, "utf-8"), globalsPath) : {};
35119
35226
  const perEnv = {};
35120
35227
  for (const name of envNames) {
35121
- const envPath = join16(rootDir, `deploy.arc.${name}.env`);
35122
- if (existsSync14(envPath)) {
35123
- perEnv[name] = parseEnvFile(readFileSync13(envPath, "utf-8"), envPath);
35228
+ const envPath = join17(rootDir, `deploy.arc.${name}.env`);
35229
+ if (existsSync15(envPath)) {
35230
+ perEnv[name] = parseEnvFile(readFileSync14(envPath, "utf-8"), envPath);
35124
35231
  }
35125
35232
  }
35126
35233
  return { globals, perEnv };
@@ -35136,16 +35243,16 @@ function ensurePersistedSecret(rootDir, scope, key, generate) {
35136
35243
  if (process.env[key])
35137
35244
  return process.env[key];
35138
35245
  const fileName = scope === "globals" ? "deploy.arc.env" : `deploy.arc.${scope}.env`;
35139
- const path4 = join16(rootDir, fileName);
35140
- if (existsSync14(path4)) {
35141
- const existing = parseEnvFile(readFileSync13(path4, "utf-8"), path4);
35246
+ const path4 = join17(rootDir, fileName);
35247
+ if (existsSync15(path4)) {
35248
+ const existing = parseEnvFile(readFileSync14(path4, "utf-8"), path4);
35142
35249
  if (existing[key]) {
35143
35250
  process.env[key] = existing[key];
35144
35251
  return existing[key];
35145
35252
  }
35146
35253
  }
35147
35254
  const value = generate();
35148
- const prefix = existsSync14(path4) && !readFileSync13(path4, "utf-8").endsWith(`
35255
+ const prefix = existsSync15(path4) && !readFileSync14(path4, "utf-8").endsWith(`
35149
35256
  `) ? `
35150
35257
  ` : "";
35151
35258
  appendFileSync(path4, `${prefix}${key}=${value}
@@ -35181,17 +35288,17 @@ function parseEnvFile(content, pathForErrors) {
35181
35288
  // src/deploy/config.ts
35182
35289
  var DEPLOY_CONFIG_FILE = "deploy.arc.json";
35183
35290
  function deployConfigPath(rootDir) {
35184
- return join17(rootDir, DEPLOY_CONFIG_FILE);
35291
+ return join18(rootDir, DEPLOY_CONFIG_FILE);
35185
35292
  }
35186
35293
  function deployConfigExists(rootDir) {
35187
- return existsSync15(deployConfigPath(rootDir));
35294
+ return existsSync16(deployConfigPath(rootDir));
35188
35295
  }
35189
35296
  function loadDeployConfig(rootDir) {
35190
35297
  const path4 = deployConfigPath(rootDir);
35191
- if (!existsSync15(path4)) {
35298
+ if (!existsSync16(path4)) {
35192
35299
  throw new Error(`Missing ${DEPLOY_CONFIG_FILE} at ${path4}`);
35193
35300
  }
35194
- const raw = readFileSync14(path4, "utf-8");
35301
+ const raw = readFileSync15(path4, "utf-8");
35195
35302
  let parsed;
35196
35303
  try {
35197
35304
  parsed = JSON.parse(raw);
@@ -35214,7 +35321,7 @@ function loadDeployConfig(rootDir) {
35214
35321
  }
35215
35322
  function saveDeployConfig(rootDir, cfg) {
35216
35323
  const path4 = deployConfigPath(rootDir);
35217
- const raw = existsSync15(path4) ? JSON.parse(readFileSync14(path4, "utf-8")) : {};
35324
+ const raw = existsSync16(path4) ? JSON.parse(readFileSync15(path4, "utf-8")) : {};
35218
35325
  raw.target = { ...raw.target, ...cfg.target };
35219
35326
  writeFileSync13(path4, JSON.stringify(raw, null, 2) + `
35220
35327
  `);
@@ -35451,17 +35558,17 @@ function cfgErr(path4, expected) {
35451
35558
 
35452
35559
  // src/deploy/ssh.ts
35453
35560
  var {spawn: spawn3 } = globalThis.Bun;
35454
- import { existsSync as existsSync16 } from "fs";
35561
+ import { existsSync as existsSync17 } from "fs";
35455
35562
  import { homedir as homedir3 } from "os";
35456
- import { join as join18 } from "path";
35563
+ import { join as join19 } from "path";
35457
35564
  function pickSshKey(target) {
35458
35565
  if (target.sshKey) {
35459
- const expanded = target.sshKey.startsWith("~") ? join18(homedir3(), target.sshKey.slice(1)) : target.sshKey;
35460
- return existsSync16(expanded) ? expanded : null;
35566
+ const expanded = target.sshKey.startsWith("~") ? join19(homedir3(), target.sshKey.slice(1)) : target.sshKey;
35567
+ return existsSync17(expanded) ? expanded : null;
35461
35568
  }
35462
35569
  for (const name of ["id_ed25519", "id_ecdsa", "id_rsa"]) {
35463
- const path4 = join18(homedir3(), ".ssh", name);
35464
- if (existsSync16(path4))
35570
+ const path4 = join19(homedir3(), ".ssh", name);
35571
+ if (existsSync17(path4))
35465
35572
  return path4;
35466
35573
  }
35467
35574
  return null;
@@ -35476,7 +35583,7 @@ function sshMuxArgs() {
35476
35583
  "-o",
35477
35584
  "ControlMaster=auto",
35478
35585
  "-o",
35479
- `ControlPath=${join18(homedir3(), ".ssh", "cm-arc-%C")}`,
35586
+ `ControlPath=${join19(homedir3(), ".ssh", "cm-arc-%C")}`,
35480
35587
  "-o",
35481
35588
  "ControlPersist=120"
35482
35589
  ];
@@ -35747,7 +35854,7 @@ async function isRegistryRunning(cfg) {
35747
35854
  }
35748
35855
  async function upStack(inputs) {
35749
35856
  const { cfg } = inputs;
35750
- const workDir = join19(tmpdir2(), "arc-deploy", `stack-${Date.now()}`);
35857
+ const workDir = join20(tmpdir2(), "arc-deploy", `stack-${Date.now()}`);
35751
35858
  mkdirSync13(workDir, { recursive: true });
35752
35859
  await assertRegistryDnsResolves(cfg);
35753
35860
  const password = process.env[cfg.registry.passwordEnv];
@@ -35755,9 +35862,9 @@ async function upStack(inputs) {
35755
35862
  throw new Error(`Registry password env var ${cfg.registry.passwordEnv} is not set. ` + `Set it (e.g. \`export ${cfg.registry.passwordEnv}=...\`) before bootstrap.`);
35756
35863
  }
35757
35864
  const htpasswdLine = await generateHtpasswd(cfg.registry.username, password);
35758
- writeFileSync14(join19(workDir, "htpasswd"), htpasswdLine);
35759
- writeFileSync14(join19(workDir, "Caddyfile"), generateCaddyfile(cfg));
35760
- writeFileSync14(join19(workDir, "docker-compose.yml"), generateCompose({ cfg }));
35865
+ writeFileSync14(join20(workDir, "htpasswd"), htpasswdLine);
35866
+ writeFileSync14(join20(workDir, "Caddyfile"), generateCaddyfile(cfg));
35867
+ writeFileSync14(join20(workDir, "docker-compose.yml"), generateCompose({ cfg }));
35761
35868
  let observabilityFiles = null;
35762
35869
  let observabilityHtpasswd = null;
35763
35870
  if (cfg.observability?.enabled) {
@@ -35769,30 +35876,30 @@ async function upStack(inputs) {
35769
35876
  }
35770
35877
  observabilityHtpasswd = await generateCaddyBasicAuthLine("admin", adminPassword);
35771
35878
  for (const [relPath, contents] of Object.entries(observabilityFiles)) {
35772
- const fullPath = join19(workDir, relPath);
35879
+ const fullPath = join20(workDir, relPath);
35773
35880
  mkdirSync13(dirname9(fullPath), { recursive: true });
35774
35881
  writeFileSync14(fullPath, contents);
35775
35882
  }
35776
- writeFileSync14(join19(workDir, "observability-htpasswd"), observabilityHtpasswd);
35883
+ writeFileSync14(join20(workDir, "observability-htpasswd"), observabilityHtpasswd);
35777
35884
  }
35778
35885
  await assertExec(cfg.target, `sudo mkdir -p ${cfg.target.remoteDir} && sudo chown ${cfg.target.user}:${cfg.target.user} ${cfg.target.remoteDir}`);
35779
35886
  for (const name of Object.keys(cfg.envs)) {
35780
35887
  await assertExec(cfg.target, `mkdir -p ${cfg.target.remoteDir}/${name}`);
35781
35888
  }
35782
35889
  await assertExec(cfg.target, `mkdir -p ${cfg.target.remoteDir}/registry-auth`);
35783
- await scpUpload(cfg.target, join19(workDir, "Caddyfile"), `${cfg.target.remoteDir}/Caddyfile`);
35784
- await scpUpload(cfg.target, join19(workDir, "docker-compose.yml"), `${cfg.target.remoteDir}/docker-compose.yml`);
35785
- await scpUpload(cfg.target, join19(workDir, "htpasswd"), `${cfg.target.remoteDir}/registry-auth/htpasswd`);
35890
+ await scpUpload(cfg.target, join20(workDir, "Caddyfile"), `${cfg.target.remoteDir}/Caddyfile`);
35891
+ await scpUpload(cfg.target, join20(workDir, "docker-compose.yml"), `${cfg.target.remoteDir}/docker-compose.yml`);
35892
+ await scpUpload(cfg.target, join20(workDir, "htpasswd"), `${cfg.target.remoteDir}/registry-auth/htpasswd`);
35786
35893
  if (observabilityFiles && observabilityHtpasswd) {
35787
35894
  await assertExec(cfg.target, `mkdir -p ${cfg.target.remoteDir}/observability/grafana-dashboards ${cfg.target.remoteDir}/observability/grafana-alerting`);
35788
35895
  for (const relPath of Object.keys(observabilityFiles)) {
35789
- const localDir = dirname9(join19(workDir, relPath));
35896
+ const localDir = dirname9(join20(workDir, relPath));
35790
35897
  mkdirSync13(localDir, { recursive: true });
35791
35898
  }
35792
35899
  for (const relPath of Object.keys(observabilityFiles)) {
35793
- await scpUpload(cfg.target, join19(workDir, relPath), `${cfg.target.remoteDir}/${relPath}`);
35900
+ await scpUpload(cfg.target, join20(workDir, relPath), `${cfg.target.remoteDir}/${relPath}`);
35794
35901
  }
35795
- await scpUpload(cfg.target, join19(workDir, "observability-htpasswd"), `${cfg.target.remoteDir}/observability-htpasswd`);
35902
+ await scpUpload(cfg.target, join20(workDir, "observability-htpasswd"), `${cfg.target.remoteDir}/observability-htpasswd`);
35796
35903
  }
35797
35904
  await assertExec(cfg.target, `touch ${cfg.target.remoteDir}/.env`);
35798
35905
  if (cfg.observability?.enabled) {
@@ -35814,6 +35921,7 @@ async function upStack(inputs) {
35814
35921
  await writeEnvLine(cfg.target, `${cfg.target.remoteDir}/.env`, key, value);
35815
35922
  }
35816
35923
  await assertExec(cfg.target, `cd ${cfg.target.remoteDir} && docker compose pull --ignore-pull-failures caddy registry && docker compose up -d caddy registry`);
35924
+ await assertExec(cfg.target, `cd ${cfg.target.remoteDir} && docker compose restart caddy`);
35817
35925
  await sshDockerLogin(cfg);
35818
35926
  const knownEnvs = await listConfiguredEnvs(cfg);
35819
35927
  if (knownEnvs.length > 0) {
@@ -35947,14 +36055,14 @@ var {spawn: spawn5 } = globalThis.Bun;
35947
36055
  import { createHash as createHash3 } from "crypto";
35948
36056
  import {
35949
36057
  copyFileSync as copyFileSync2,
35950
- existsSync as existsSync17,
36058
+ existsSync as existsSync18,
35951
36059
  mkdirSync as mkdirSync14,
35952
- readFileSync as readFileSync15,
36060
+ readFileSync as readFileSync16,
35953
36061
  realpathSync as realpathSync2,
35954
36062
  writeFileSync as writeFileSync15
35955
36063
  } from "fs";
35956
36064
  import { tmpdir as tmpdir3 } from "os";
35957
- import { dirname as dirname10, join as join20 } from "path";
36065
+ import { dirname as dirname10, join as join21 } from "path";
35958
36066
  import { fileURLToPath as fileURLToPath7 } from "url";
35959
36067
 
35960
36068
  // src/deploy/image-template.ts
@@ -36004,8 +36112,8 @@ function generateDockerfile(inputs) {
36004
36112
  // src/deploy/image.ts
36005
36113
  async function buildImage(ws, opts) {
36006
36114
  await ensureDocker();
36007
- const manifestPath = join20(ws.arcDir, "manifest.json");
36008
- if (!existsSync17(manifestPath)) {
36115
+ const manifestPath = join21(ws.arcDir, "manifest.json");
36116
+ if (!existsSync18(manifestPath)) {
36009
36117
  throw new Error(`No build manifest at ${manifestPath}. Run \`arc platform build\` first or omit --skip-build.`);
36010
36118
  }
36011
36119
  embedCliBundle(ws);
@@ -36015,9 +36123,9 @@ async function buildImage(ws, opts) {
36015
36123
  const dockerfileInputs = collectDockerfileInputs(ws);
36016
36124
  const dockerfile = generateDockerfile(dockerfileInputs);
36017
36125
  const buildContextDir = ws.rootDir;
36018
- const dockerfileDir = join20(tmpdir3(), `arc-image-${Date.now()}`);
36126
+ const dockerfileDir = join21(tmpdir3(), `arc-image-${Date.now()}`);
36019
36127
  mkdirSync14(dockerfileDir, { recursive: true });
36020
- const dockerfilePath = join20(dockerfileDir, "Dockerfile");
36128
+ const dockerfilePath = join21(dockerfileDir, "Dockerfile");
36021
36129
  writeFileSync15(dockerfilePath, dockerfile);
36022
36130
  const buildArgs = [
36023
36131
  "build",
@@ -36043,20 +36151,20 @@ async function buildImage(ws, opts) {
36043
36151
  }
36044
36152
  function embedCliBundle(ws) {
36045
36153
  const source = locateCliBundle();
36046
- const target = join20(ws.arcDir, "host.js");
36154
+ const target = join21(ws.arcDir, "host.js");
36047
36155
  copyFileSync2(source, target);
36048
36156
  }
36049
36157
  function locateCliBundle() {
36050
36158
  const here = fileURLToPath7(import.meta.url);
36051
36159
  let cur = dirname10(here);
36052
36160
  while (cur !== "/" && cur !== "") {
36053
- const candidate = join20(cur, "package.json");
36054
- if (existsSync17(candidate)) {
36161
+ const candidate = join21(cur, "package.json");
36162
+ if (existsSync18(candidate)) {
36055
36163
  try {
36056
- const pkg = JSON.parse(readFileSync15(candidate, "utf-8"));
36164
+ const pkg = JSON.parse(readFileSync16(candidate, "utf-8"));
36057
36165
  if (pkg.name === "@arcote.tech/arc-cli") {
36058
- const distIndex = join20(realpathSync2(cur), "dist", "index.js");
36059
- if (!existsSync17(distIndex)) {
36166
+ const distIndex = join21(realpathSync2(cur), "dist", "index.js");
36167
+ if (!existsSync18(distIndex)) {
36060
36168
  throw new Error(`arc-cli bundle missing at ${distIndex}. Run \`bun run build\` in packages/cli/.`);
36061
36169
  }
36062
36170
  return distIndex;
@@ -36088,17 +36196,17 @@ async function ensureDocker() {
36088
36196
  }
36089
36197
  }
36090
36198
  function computeContentHash(manifestPath) {
36091
- const raw = JSON.parse(readFileSync15(manifestPath, "utf-8"));
36199
+ const raw = JSON.parse(readFileSync16(manifestPath, "utf-8"));
36092
36200
  delete raw.buildTime;
36093
36201
  const canonical = JSON.stringify(raw);
36094
36202
  return createHash3("sha256").update(canonical).digest("hex").slice(0, 12);
36095
36203
  }
36096
36204
  function collectDockerfileInputs(ws) {
36097
- const hasPublicDir = existsSync17(join20(ws.rootDir, "public"));
36098
- const hasLocales = existsSync17(join20(ws.rootDir, "locales"));
36205
+ const hasPublicDir = existsSync18(join21(ws.rootDir, "public"));
36206
+ const hasLocales = existsSync18(join21(ws.rootDir, "locales"));
36099
36207
  let manifestPath;
36100
36208
  for (const name of ["manifest.webmanifest", "manifest.json"]) {
36101
- if (existsSync17(join20(ws.rootDir, name))) {
36209
+ if (existsSync18(join21(ws.rootDir, name))) {
36102
36210
  manifestPath = name;
36103
36211
  break;
36104
36212
  }
@@ -36942,14 +37050,14 @@ async function platformDeploy(envArg, options = {}) {
36942
37050
  err(`Unknown env "${envArg}". Known: ${Object.keys(cfg.envs).join(", ")}`);
36943
37051
  process.exit(1);
36944
37052
  })() : Object.keys(cfg.envs);
36945
- const manifestPath = join21(ws.arcDir, "manifest.json");
37053
+ const manifestPath = join22(ws.arcDir, "manifest.json");
36946
37054
  if (!options.imageTag) {
36947
- const needBuild = options.rebuild || !existsSync18(manifestPath);
37055
+ const needBuild = options.rebuild || !existsSync19(manifestPath);
36948
37056
  if (needBuild && !options.skipBuild) {
36949
37057
  log2("Building platform...");
36950
37058
  await buildAll(ws, { noCache: options.rebuild });
36951
37059
  ok("Build complete");
36952
- } else if (!existsSync18(manifestPath)) {
37060
+ } else if (!existsSync19(manifestPath)) {
36953
37061
  err("No build found and --skip-build was set.");
36954
37062
  process.exit(1);
36955
37063
  }
@@ -37019,9 +37127,9 @@ function readCliVersion2() {
37019
37127
  let cur = dirname11(fileURLToPath8(import.meta.url));
37020
37128
  const root = dirname11(cur).startsWith("/") ? "/" : ".";
37021
37129
  while (cur !== root && cur !== "") {
37022
- const candidate = join21(cur, "package.json");
37023
- if (existsSync18(candidate)) {
37024
- const pkg = JSON.parse(readFileSync16(candidate, "utf-8"));
37130
+ const candidate = join22(cur, "package.json");
37131
+ if (existsSync19(candidate)) {
37132
+ const pkg = JSON.parse(readFileSync17(candidate, "utf-8"));
37025
37133
  if (pkg.name === "@arcote.tech/arc-cli") {
37026
37134
  return pkg.version ?? "unknown";
37027
37135
  }
@@ -37037,8 +37145,8 @@ function readCliVersion2() {
37037
37145
  }
37038
37146
  }
37039
37147
  async function hashDeployConfig(rootDir) {
37040
- const p2 = join21(rootDir, "deploy.arc.json");
37041
- const content = readFileSync16(p2);
37148
+ const p2 = join22(rootDir, "deploy.arc.json");
37149
+ const content = readFileSync17(p2);
37042
37150
  const hasher = new Bun.CryptoHasher("sha256");
37043
37151
  hasher.update(content);
37044
37152
  hasher.update(readCliVersion2());
@@ -37047,8 +37155,8 @@ async function hashDeployConfig(rootDir) {
37047
37155
 
37048
37156
  // src/platform/startup.ts
37049
37157
  import { randomBytes as randomBytes2 } from "crypto";
37050
- import { existsSync as existsSync20, mkdirSync as mkdirSync16, readFileSync as readFileSync17, watch, writeFileSync as writeFileSync16 } from "fs";
37051
- import { join as join23 } from "path";
37158
+ import { existsSync as existsSync21, mkdirSync as mkdirSync16, readFileSync as readFileSync19, watch, writeFileSync as writeFileSync16 } from "fs";
37159
+ import { join as join24 } from "path";
37052
37160
 
37053
37161
  // ../host/src/connection-manager.ts
37054
37162
  class ConnectionManager {
@@ -38677,8 +38785,8 @@ async function createArcServer(config) {
38677
38785
  // src/platform/server.ts
38678
38786
  init_i18n();
38679
38787
  import { timingSafeEqual } from "crypto";
38680
- import { existsSync as existsSync19, mkdirSync as mkdirSync15 } from "fs";
38681
- import { join as join22 } from "path";
38788
+ import { existsSync as existsSync20, mkdirSync as mkdirSync15, readFileSync as readFileSync18 } from "fs";
38789
+ import { join as join23 } from "path";
38682
38790
  async function initContextHandler(context2, dbPath) {
38683
38791
  const factory = await resolveDbAdapterFactory(dbPath);
38684
38792
  const dbAdapter = factory(context2);
@@ -38698,7 +38806,61 @@ async function resolveDbAdapterFactory(dbPath) {
38698
38806
  mkdirSync15(dbDir, { recursive: true });
38699
38807
  return createBunSQLiteAdapterFactory2(dbPath);
38700
38808
  }
38701
- function generateShellHtml(appName, manifest, initial, stylesHash, shell) {
38809
+ function inlineJson(value) {
38810
+ return JSON.stringify(value).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/[\u2028\u2029]/g, (c2) => `\\u${c2.charCodeAt(0).toString(16)}`);
38811
+ }
38812
+ function tokenPayloadsFromCookies(cookieHeader) {
38813
+ if (!cookieHeader)
38814
+ return [];
38815
+ const payloads = [];
38816
+ for (const part of cookieHeader.split(";")) {
38817
+ const eq = part.indexOf("=");
38818
+ if (eq < 0)
38819
+ continue;
38820
+ const name = part.slice(0, eq).trim();
38821
+ if (name !== "arc_token" && !name.startsWith("arc_token_"))
38822
+ continue;
38823
+ const payload = decodeTokenPayload(decodeURIComponent(part.slice(eq + 1).trim()));
38824
+ if (payload)
38825
+ payloads.push(payload);
38826
+ }
38827
+ return payloads;
38828
+ }
38829
+ function pickLocale(cookieHeader, acceptLanguage, locales, sourceLocale) {
38830
+ const fromCookie = cookieHeader?.match(/(?:^|;)\s*arc-locale=([^;]+)/)?.[1];
38831
+ if (fromCookie && locales.includes(decodeURIComponent(fromCookie))) {
38832
+ return decodeURIComponent(fromCookie);
38833
+ }
38834
+ for (const tag of (acceptLanguage ?? "").split(",")) {
38835
+ const lang = tag.split(";")[0].trim();
38836
+ if (!lang)
38837
+ continue;
38838
+ const exact = locales.find((l2) => l2.toLowerCase() === lang.toLowerCase());
38839
+ if (exact)
38840
+ return exact;
38841
+ const prefix = locales.find((l2) => l2.toLowerCase().split("-")[0] === lang.toLowerCase().split("-")[0]);
38842
+ if (prefix)
38843
+ return prefix;
38844
+ }
38845
+ return sourceLocale;
38846
+ }
38847
+ async function generateShellHtml(opts) {
38848
+ const {
38849
+ appName,
38850
+ appManifest,
38851
+ buildManifest,
38852
+ moduleAccessMap,
38853
+ arcDir,
38854
+ rootDir,
38855
+ cookieHeader,
38856
+ acceptLanguage
38857
+ } = opts;
38858
+ if (!buildManifest?.initial) {
38859
+ throw new Error("generateShellHtml: initial bundle missing from manifest");
38860
+ }
38861
+ const initial = buildManifest.initial;
38862
+ const initialUrl = `/browser/${initial.file}`;
38863
+ const shell = buildManifest.shell;
38702
38864
  const otelConfig = process.env.ARC_OTEL_ENABLED === "true" ? {
38703
38865
  enabled: true,
38704
38866
  endpoint: "/otel",
@@ -38707,26 +38869,58 @@ function generateShellHtml(appName, manifest, initial, stylesHash, shell) {
38707
38869
  sampleRate: Number(process.env.ARC_OTEL_BROWSER_SAMPLE_RATE ?? "0.1")
38708
38870
  } : null;
38709
38871
  const otelTag = otelConfig ? `
38710
- <script>window.__ARC_OTEL_CONFIG=${JSON.stringify(otelConfig)};</script>` : "";
38711
- const initialUrl = initial ? `/browser/${initial.file}` : null;
38712
- if (!initialUrl) {
38713
- throw new Error("generateShellHtml: initial bundle missing from manifest");
38714
- }
38872
+ <script>window.__ARC_OTEL_CONFIG=${inlineJson(otelConfig)};</script>` : "";
38715
38873
  const importMapTag = shell ? `
38716
- <script type="importmap">${JSON.stringify({ imports: shell.imports })}</script>
38717
- <script>window.__ARC_PEERS__=${JSON.stringify(shell.peers)};</script>` : "";
38718
- const stylesQs = stylesHash ? `?v=${stylesHash.slice(0, 16)}` : "";
38874
+ <script type="importmap">${inlineJson({ imports: shell.imports })}</script>
38875
+ <script>window.__ARC_PEERS__=${inlineJson(shell.peers)};</script>` : "";
38876
+ const stylesQs = buildManifest.stylesHash ? `?v=${buildManifest.stylesHash.slice(0, 16)}` : "";
38877
+ const tokenPayloads = tokenPayloadsFromCookies(cookieHeader);
38878
+ const filtered = await filterManifestForTokens(buildManifest, moduleAccessMap, tokenPayloads);
38879
+ const preloadUrls = new Set;
38880
+ preloadUrls.add(initialUrl);
38881
+ for (const c2 of initial.staticChunks ?? [])
38882
+ preloadUrls.add(`/browser/${c2}`);
38883
+ for (const group of Object.values(filtered.groups)) {
38884
+ if (group.url)
38885
+ preloadUrls.add(group.url);
38886
+ for (const c2 of group.staticChunks ?? [])
38887
+ preloadUrls.add(`/browser/${c2}`);
38888
+ }
38889
+ const preloadTags = [...preloadUrls].map((u2) => `
38890
+ <link rel="modulepreload" href="${u2}" />`).join("");
38891
+ const manifestTag = `
38892
+ <script>window.__ARC_MANIFEST__=${inlineJson({
38893
+ initial: filtered.initial,
38894
+ groups: filtered.groups,
38895
+ sharedChunks: filtered.sharedChunks,
38896
+ stylesHash: filtered.stylesHash,
38897
+ buildTime: filtered.buildTime
38898
+ })};</script>`;
38899
+ let lang = "en";
38900
+ const tconfig = readTranslationsConfig(rootDir);
38901
+ let messages2 = {};
38902
+ if (tconfig) {
38903
+ lang = pickLocale(cookieHeader, acceptLanguage, tconfig.locales, tconfig.sourceLocale);
38904
+ try {
38905
+ messages2 = JSON.parse(readFileSync18(join23(arcDir, "locales", `${lang}.json`), "utf-8"));
38906
+ } catch {}
38907
+ }
38908
+ const i18nTag = `
38909
+ <script>window.__ARC_I18N__=${inlineJson({
38910
+ locale: lang,
38911
+ config: tconfig,
38912
+ messages: messages2
38913
+ })};</script>`;
38719
38914
  return `<!doctype html>
38720
- <html lang="en">
38915
+ <html lang="${lang}">
38721
38916
  <head>
38722
38917
  <meta charset="UTF-8" />
38723
38918
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
38724
- <title>${manifest?.title ?? appName}</title>${manifest?.favicon ? `
38725
- <link rel="icon" href="${manifest.favicon}">` : ""}${manifest ? `
38919
+ <title>${appManifest?.title ?? appName}</title>${appManifest?.favicon ? `
38920
+ <link rel="icon" href="${appManifest.favicon}">` : ""}${appManifest ? `
38726
38921
  <link rel="manifest" href="/manifest.json${stylesQs}">` : ""}
38727
38922
  <link rel="stylesheet" href="/styles.css${stylesQs}" />
38728
- <link rel="stylesheet" href="/theme.css${stylesQs}" />${importMapTag}
38729
- <link rel="modulepreload" href="${initialUrl}" />${otelTag}
38923
+ <link rel="stylesheet" href="/theme.css${stylesQs}" />${importMapTag}${preloadTags}${manifestTag}${i18nTag}${otelTag}
38730
38924
  </head>
38731
38925
  <body>
38732
38926
  <div id="root"></div>
@@ -38757,7 +38951,7 @@ function getMime(path4) {
38757
38951
  return MIME[ext2] ?? "application/octet-stream";
38758
38952
  }
38759
38953
  function serveFile(filePath, headers = {}) {
38760
- if (!existsSync19(filePath))
38954
+ if (!existsSync20(filePath))
38761
38955
  return new Response("Not Found", { status: 404 });
38762
38956
  return new Response(Bun.file(filePath), {
38763
38957
  headers: { "Content-Type": getMime(filePath), ...headers }
@@ -38879,7 +39073,7 @@ function staticFilesHandler(ws, devMode, getManifest) {
38879
39073
  return new Response("Forbidden", { status: 403, headers: ctx.corsHeaders });
38880
39074
  }
38881
39075
  }
38882
- return serveFile(join22(ws.browserDir, file), {
39076
+ return serveFile(join23(ws.browserDir, file), {
38883
39077
  ...ctx.corsHeaders,
38884
39078
  "Cache-Control": devMode ? "no-cache" : "max-age=31536000,immutable"
38885
39079
  });
@@ -38889,7 +39083,7 @@ function staticFilesHandler(ws, devMode, getManifest) {
38889
39083
  if (!BROWSER_FILE_RE.test(file)) {
38890
39084
  return new Response("Not Found", { status: 404, headers: ctx.corsHeaders });
38891
39085
  }
38892
- return serveFile(join22(ws.arcDir, "shell", file), {
39086
+ return serveFile(join23(ws.arcDir, "shell", file), {
38893
39087
  ...ctx.corsHeaders,
38894
39088
  "Cross-Origin-Resource-Policy": "cross-origin",
38895
39089
  "Cache-Control": devMode ? "no-cache" : "max-age=31536000,immutable"
@@ -38908,29 +39102,29 @@ function staticFilesHandler(ws, devMode, getManifest) {
38908
39102
  return new Response("Forbidden", { status: 403, headers: ctx.corsHeaders });
38909
39103
  }
38910
39104
  }
38911
- return serveFile(join22(ws.arcDir, "browser-fed", file), {
39105
+ return serveFile(join23(ws.arcDir, "browser-fed", file), {
38912
39106
  ...ctx.corsHeaders,
38913
39107
  "Cross-Origin-Resource-Policy": "cross-origin",
38914
39108
  "Cache-Control": devMode ? "no-cache" : "max-age=31536000,immutable"
38915
39109
  });
38916
39110
  }
38917
39111
  if (path4.startsWith("/locales/"))
38918
- return serveFile(join22(ws.arcDir, path4.slice(1)), {
39112
+ return serveFile(join23(ws.arcDir, path4.slice(1)), {
38919
39113
  ...ctx.corsHeaders,
38920
39114
  "Cache-Control": devMode ? "no-cache" : "max-age=300,stale-while-revalidate=3600"
38921
39115
  });
38922
39116
  if (path4.startsWith("/assets/"))
38923
- return serveFile(join22(ws.assetsDir, path4.slice(8)), {
39117
+ return serveFile(join23(ws.assetsDir, path4.slice(8)), {
38924
39118
  ...ctx.corsHeaders,
38925
39119
  "Cache-Control": devMode ? "no-cache" : "max-age=31536000,immutable"
38926
39120
  });
38927
39121
  if (path4 === "/styles.css")
38928
- return serveFile(join22(ws.arcDir, "styles.css"), {
39122
+ return serveFile(join23(ws.arcDir, "styles.css"), {
38929
39123
  ...ctx.corsHeaders,
38930
39124
  "Cache-Control": devMode ? "no-cache" : "max-age=31536000,immutable"
38931
39125
  });
38932
39126
  if (path4 === "/theme.css")
38933
- return serveFile(join22(ws.arcDir, "theme.css"), {
39127
+ return serveFile(join23(ws.arcDir, "theme.css"), {
38934
39128
  ...ctx.corsHeaders,
38935
39129
  "Cache-Control": devMode ? "no-cache" : "max-age=31536000,immutable"
38936
39130
  });
@@ -38941,8 +39135,8 @@ function staticFilesHandler(ws, devMode, getManifest) {
38941
39135
  });
38942
39136
  }
38943
39137
  if (path4.lastIndexOf(".") > path4.lastIndexOf("/")) {
38944
- const publicFile = join22(ws.publicDir, path4.slice(1));
38945
- if (existsSync19(publicFile))
39138
+ const publicFile = join23(ws.publicDir, path4.slice(1));
39139
+ if (existsSync20(publicFile))
38946
39140
  return serveFile(publicFile, ctx.corsHeaders);
38947
39141
  }
38948
39142
  return null;
@@ -39142,12 +39336,13 @@ function headlessFallbackHandler(ws, getManifest) {
39142
39336
  };
39143
39337
  }
39144
39338
  function spaFallbackHandler(getShellHtml) {
39145
- return (_req, _url, ctx) => {
39146
- return new Response(getShellHtml(), {
39339
+ return async (req, _url, ctx) => {
39340
+ return new Response(await getShellHtml(req), {
39147
39341
  headers: {
39148
39342
  ...ctx.corsHeaders,
39149
39343
  "Content-Type": "text/html",
39150
- "Cache-Control": "no-cache, must-revalidate"
39344
+ "Cache-Control": "no-cache, must-revalidate, private",
39345
+ Vary: "Cookie, Accept-Language"
39151
39346
  }
39152
39347
  });
39153
39348
  };
@@ -39188,7 +39383,16 @@ async function startPlatformServer(opts) {
39188
39383
  mapUrl = u2;
39189
39384
  };
39190
39385
  const getMapUrl = () => mapUrl;
39191
- const getShellHtml = () => generateShellHtml(ws.appName, ws.manifest, manifest?.initial, manifest?.stylesHash, manifest?.shell);
39386
+ const getShellHtml = (req) => generateShellHtml({
39387
+ appName: ws.appName,
39388
+ appManifest: ws.manifest,
39389
+ buildManifest: manifest,
39390
+ moduleAccessMap,
39391
+ arcDir: ws.arcDir,
39392
+ rootDir: ws.rootDir,
39393
+ cookieHeader: req.headers.get("Cookie"),
39394
+ acceptLanguage: req.headers.get("Accept-Language")
39395
+ });
39192
39396
  const sseClients = new Set;
39193
39397
  const fallbackHandler = opts.headless ? headlessFallbackHandler(ws, getManifest) : spaFallbackHandler(getShellHtml);
39194
39398
  const notifyReload = (m4) => {
@@ -39252,7 +39456,7 @@ async function startPlatformServer(opts) {
39252
39456
  stop: () => server.stop()
39253
39457
  };
39254
39458
  }
39255
- const dbPath = opts.dbPath || join22(ws.arcDir, "data", "arc.db");
39459
+ const dbPath = opts.dbPath || join23(ws.arcDir, "data", "arc.db");
39256
39460
  const baseDbFactory = await resolveDbAdapterFactory(dbPath);
39257
39461
  let dbAdapterFactory = baseDbFactory;
39258
39462
  if (telemetry) {
@@ -39297,17 +39501,17 @@ async function startPlatformServer(opts) {
39297
39501
  async function startPlatform(opts) {
39298
39502
  const { ws, devMode } = opts;
39299
39503
  const port = opts.port ?? parseInt(process.env.PORT || "5005", 10);
39300
- const dbPath = opts.dbPath ?? join23(ws.rootDir, ".arc", "data", devMode ? "dev.db" : "prod.db");
39504
+ const dbPath = opts.dbPath ?? join24(ws.rootDir, ".arc", "data", devMode ? "dev.db" : "prod.db");
39301
39505
  let manifest;
39302
39506
  if (devMode) {
39303
39507
  manifest = await buildAll(ws, { minify: false });
39304
39508
  } else {
39305
- const manifestPath = join23(ws.arcDir, "manifest.json");
39306
- if (!existsSync20(manifestPath)) {
39509
+ const manifestPath = join24(ws.arcDir, "manifest.json");
39510
+ if (!existsSync21(manifestPath)) {
39307
39511
  err("No build found. Run `arc platform build` first.");
39308
39512
  process.exit(1);
39309
39513
  }
39310
- manifest = JSON.parse(readFileSync17(manifestPath, "utf-8"));
39514
+ manifest = JSON.parse(readFileSync19(manifestPath, "utf-8"));
39311
39515
  }
39312
39516
  assertProdFederationSecrets(devMode, !!manifest.federation);
39313
39517
  const needsPairing = !!manifest.federation || devMode && (opts.map || opts.headless);
@@ -39391,8 +39595,8 @@ async function startMapTool(ws, port, authToken, platformServer, platform3) {
39391
39595
  try {
39392
39596
  const { startMapServer, MAP_SCHEMA_VERSION } = await import("@arcote.tech/arc-map");
39393
39597
  const { getContext } = await import("@arcote.tech/platform");
39394
- const globs = ws.packages.map((p3) => join23(p3.path, "src", "**", "*.{ts,tsx}"));
39395
- const packageOf = (absFile) => ws.packages.find((p3) => absFile.startsWith(join23(p3.path, "src")))?.name;
39598
+ const globs = ws.packages.map((p3) => join24(p3.path, "src", "**", "*.{ts,tsx}"));
39599
+ const packageOf = (absFile) => ws.packages.find((p3) => absFile.startsWith(join24(p3.path, "src")))?.name;
39396
39600
  const meta = readAppMeta(ws.rootDir, MAP_SCHEMA_VERSION);
39397
39601
  const map = await startMapServer({
39398
39602
  getContext: () => getContext(),
@@ -39427,15 +39631,15 @@ function resolveAppSecret(rootDir) {
39427
39631
  const fromEnv = process.env.ARC_APP_SECRET;
39428
39632
  if (fromEnv)
39429
39633
  return fromEnv;
39430
- const file = join23(rootDir, ".arc", "app-secret");
39634
+ const file = join24(rootDir, ".arc", "app-secret");
39431
39635
  try {
39432
- const saved = readFileSync17(file, "utf-8").trim();
39636
+ const saved = readFileSync19(file, "utf-8").trim();
39433
39637
  if (saved)
39434
39638
  return saved;
39435
39639
  } catch {}
39436
39640
  const secret = randomBytes2(32).toString("base64url");
39437
39641
  try {
39438
- mkdirSync16(join23(rootDir, ".arc"), { recursive: true });
39642
+ mkdirSync16(join24(rootDir, ".arc"), { recursive: true });
39439
39643
  writeFileSync16(file, secret, { mode: 384 });
39440
39644
  } catch (e2) {
39441
39645
  err(`App secret not persisted (${e2.message}) \u2014 hosts will need re-install after restart`);
@@ -39446,15 +39650,15 @@ function resolvePairingToken(rootDir) {
39446
39650
  const fromEnv = process.env.ARC_PAIRING_TOKEN || process.env.ARC_MAP_TOKEN;
39447
39651
  if (fromEnv)
39448
39652
  return fromEnv;
39449
- const file = join23(rootDir, ".arc", "pairing-token");
39653
+ const file = join24(rootDir, ".arc", "pairing-token");
39450
39654
  try {
39451
- const saved = readFileSync17(file, "utf-8").trim();
39655
+ const saved = readFileSync19(file, "utf-8").trim();
39452
39656
  if (saved)
39453
39657
  return saved;
39454
39658
  } catch {}
39455
39659
  const token = randomBytes2(16).toString("base64url");
39456
39660
  try {
39457
- mkdirSync16(join23(rootDir, ".arc"), { recursive: true });
39661
+ mkdirSync16(join24(rootDir, ".arc"), { recursive: true });
39458
39662
  writeFileSync16(file, token, { mode: 384 });
39459
39663
  } catch (e2) {
39460
39664
  err(`Pairing token not persisted (${e2.message}) \u2014 it will change on restart`);
@@ -39463,7 +39667,7 @@ function resolvePairingToken(rootDir) {
39463
39667
  }
39464
39668
  function readAppMeta(rootDir, schemaVersion) {
39465
39669
  try {
39466
- const pkg = JSON.parse(readFileSync17(join23(rootDir, "package.json"), "utf-8"));
39670
+ const pkg = JSON.parse(readFileSync19(join24(rootDir, "package.json"), "utf-8"));
39467
39671
  return {
39468
39672
  schemaVersion,
39469
39673
  name: pkg.name ?? rootDir.split("/").pop() ?? "arc-app",
@@ -39499,8 +39703,8 @@ function attachDevWatcher(ws, platform3, onReload) {
39499
39703
  }, 300);
39500
39704
  };
39501
39705
  for (const pkg of ws.packages) {
39502
- const srcDir = join23(pkg.path, "src");
39503
- if (!existsSync20(srcDir))
39706
+ const srcDir = join24(pkg.path, "src");
39707
+ if (!existsSync21(srcDir))
39504
39708
  continue;
39505
39709
  watch(srcDir, { recursive: true }, (_event, filename) => {
39506
39710
  if (!filename || filename.includes(".arc") || filename.endsWith(".d.ts") || filename.includes("node_modules") || filename.includes("dist"))
@@ -39510,8 +39714,8 @@ function attachDevWatcher(ws, platform3, onReload) {
39510
39714
  triggerRebuild();
39511
39715
  });
39512
39716
  }
39513
- const localesDir = join23(ws.rootDir, "locales");
39514
- if (existsSync20(localesDir)) {
39717
+ const localesDir = join24(ws.rootDir, "locales");
39718
+ if (existsSync21(localesDir)) {
39515
39719
  watch(localesDir, { recursive: false }, (_event, filename) => {
39516
39720
  if (!filename?.endsWith(".po"))
39517
39721
  return;
@@ -39533,7 +39737,7 @@ async function platformDev(opts = {}) {
39533
39737
 
39534
39738
  // src/commands/platform-pairing-token.ts
39535
39739
  import { randomBytes as randomBytes3 } from "crypto";
39536
- import { join as join24 } from "path";
39740
+ import { join as join25 } from "path";
39537
39741
  async function platformPairingToken() {
39538
39742
  const ws = resolveWorkspace();
39539
39743
  const { context: context2 } = await loadServerContext(ws);
@@ -39542,7 +39746,7 @@ async function platformPairingToken() {
39542
39746
  process.exit(1);
39543
39747
  }
39544
39748
  const isProd = false;
39545
- const dbPath = join24(ws.rootDir, ".arc", "data", isProd ? "prod.db" : "dev.db");
39749
+ const dbPath = join25(ws.rootDir, ".arc", "data", isProd ? "prod.db" : "dev.db");
39546
39750
  const handler = await initContextHandler(context2, dbPath);
39547
39751
  const code = randomBytes3(24).toString("base64url");
39548
39752
  const res = await handler.executeCommand("pairingCode.issue", { code }, null, { internal: true });