@arcote.tech/arc-cli 0.8.4 → 0.8.6

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
@@ -10191,8 +10191,72 @@ function apply(state, patches, applyOptions) {
10191
10191
  }
10192
10192
  return create(state, mutate, Object.assign(Object.assign({}, applyOptions), { enablePatches: false }));
10193
10193
  }
10194
- function hasLocalStorage() {
10195
- return typeof localStorage !== "undefined";
10194
+ function hasDocument() {
10195
+ return typeof document !== "undefined";
10196
+ }
10197
+ function signalCrossTabChange() {
10198
+ if (typeof localStorage === "undefined")
10199
+ return;
10200
+ try {
10201
+ localStorage.setItem(TOKEN_BUMP_KEY, String(Date.now()));
10202
+ } catch {}
10203
+ }
10204
+ function isSecureContext() {
10205
+ return typeof location !== "undefined" && location.protocol === "https:";
10206
+ }
10207
+ function tokenCookieName(scopeKey) {
10208
+ return scopeKey === "default" ? COOKIE_PREFIX : `${COOKIE_PREFIX}_${scopeKey.replace(/:/g, ".")}`;
10209
+ }
10210
+ function scopeKeyFromCookieName(name) {
10211
+ if (name === COOKIE_PREFIX)
10212
+ return "default";
10213
+ if (!name.startsWith(`${COOKIE_PREFIX}_`))
10214
+ return null;
10215
+ return name.slice(COOKIE_PREFIX.length + 1).replace(/\./g, ":");
10216
+ }
10217
+ function maxAgeFromExp(exp) {
10218
+ const THIRTY_DAYS = 30 * 24 * 60 * 60;
10219
+ if (typeof exp !== "number" || !Number.isFinite(exp))
10220
+ return THIRTY_DAYS;
10221
+ const expMs = exp > 1000000000000 ? exp : exp * 1000;
10222
+ const secs = Math.floor((expMs - Date.now()) / 1000);
10223
+ return secs > 0 ? secs : THIRTY_DAYS;
10224
+ }
10225
+ function writeTokenCookie(scopeKey, jwt, exp) {
10226
+ if (!hasDocument())
10227
+ return;
10228
+ const attrs = [
10229
+ "Path=/",
10230
+ "SameSite=Lax",
10231
+ `Max-Age=${maxAgeFromExp(exp)}`
10232
+ ];
10233
+ if (isSecureContext())
10234
+ attrs.push("Secure");
10235
+ document.cookie = `${tokenCookieName(scopeKey)}=${encodeURIComponent(jwt)}; ${attrs.join("; ")}`;
10236
+ signalCrossTabChange();
10237
+ }
10238
+ function removeTokenCookie(scopeKey) {
10239
+ if (!hasDocument())
10240
+ return;
10241
+ document.cookie = `${tokenCookieName(scopeKey)}=; Path=/; SameSite=Lax; Max-Age=0`;
10242
+ signalCrossTabChange();
10243
+ }
10244
+ function readAllTokenCookies() {
10245
+ if (!hasDocument() || !document.cookie)
10246
+ return [];
10247
+ const out = [];
10248
+ for (const part of document.cookie.split(";")) {
10249
+ const eq = part.indexOf("=");
10250
+ if (eq < 0)
10251
+ continue;
10252
+ const scopeKey = scopeKeyFromCookieName(part.slice(0, eq).trim());
10253
+ if (scopeKey === null)
10254
+ continue;
10255
+ const jwt = decodeURIComponent(part.slice(eq + 1).trim());
10256
+ if (jwt)
10257
+ out.push({ scopeKey, jwt });
10258
+ }
10259
+ return out;
10196
10260
  }
10197
10261
  function notifyTokenChange(scope) {
10198
10262
  if (typeof window !== "undefined") {
@@ -10208,24 +10272,21 @@ class AuthAdapter {
10208
10272
  constructor(options) {
10209
10273
  this.namespace = options?.storageNamespace || undefined;
10210
10274
  }
10211
- storageKey(scope) {
10212
- return this.namespace ? `${TOKEN_PREFIX}${this.namespace}:${scope}` : TOKEN_PREFIX + scope;
10275
+ scopeKey(scope) {
10276
+ return this.namespace ? `${this.namespace}:${scope}` : scope;
10213
10277
  }
10214
10278
  setToken(token, scope = "default") {
10215
10279
  if (!token) {
10216
10280
  this.scopes.delete(scope);
10217
- if (hasLocalStorage()) {
10218
- localStorage.removeItem(this.storageKey(scope));
10219
- notifyTokenChange(scope);
10220
- }
10281
+ removeTokenCookie(this.scopeKey(scope));
10282
+ notifyTokenChange(scope);
10221
10283
  return;
10222
10284
  }
10223
10285
  try {
10224
10286
  const parts = token.split(".");
10225
10287
  if (parts.length !== 3) {
10226
10288
  this.scopes.delete(scope);
10227
- if (hasLocalStorage())
10228
- localStorage.removeItem(this.storageKey(scope));
10289
+ removeTokenCookie(this.scopeKey(scope));
10229
10290
  return;
10230
10291
  }
10231
10292
  const payload = JSON.parse(atob(parts[1]));
@@ -10238,49 +10299,45 @@ class AuthAdapter {
10238
10299
  exp: payload.exp
10239
10300
  }
10240
10301
  });
10241
- if (hasLocalStorage()) {
10242
- localStorage.setItem(this.storageKey(scope), token);
10243
- notifyTokenChange(scope);
10244
- }
10302
+ writeTokenCookie(this.scopeKey(scope), token, payload.exp);
10303
+ notifyTokenChange(scope);
10245
10304
  } catch {
10246
10305
  this.scopes.delete(scope);
10247
- if (hasLocalStorage())
10248
- localStorage.removeItem(this.storageKey(scope));
10306
+ removeTokenCookie(this.scopeKey(scope));
10249
10307
  }
10250
10308
  }
10251
10309
  setDecoded(decoded, scope = "default") {
10252
10310
  this.scopes.set(scope, { raw: "", decoded });
10253
10311
  }
10254
10312
  loadPersisted() {
10255
- if (!hasLocalStorage())
10256
- return;
10257
- const prefix = this.namespace ? `${TOKEN_PREFIX}${this.namespace}:` : TOKEN_PREFIX;
10258
- for (let i = 0;i < localStorage.length; i++) {
10259
- const key = localStorage.key(i);
10260
- if (key?.startsWith(prefix)) {
10261
- const scope = key.slice(prefix.length);
10262
- if (!this.namespace && scope.includes(":"))
10313
+ const nsPrefix = this.namespace ? `${this.namespace}:` : "";
10314
+ for (const { scopeKey, jwt } of readAllTokenCookies()) {
10315
+ let scope;
10316
+ if (this.namespace) {
10317
+ if (!scopeKey.startsWith(nsPrefix))
10263
10318
  continue;
10264
- const raw = localStorage.getItem(key);
10265
- if (raw) {
10266
- try {
10267
- const parts = raw.split(".");
10268
- if (parts.length !== 3)
10269
- continue;
10270
- const payload = JSON.parse(atob(parts[1]));
10271
- this.scopes.set(scope, {
10272
- raw,
10273
- decoded: {
10274
- tokenName: payload.tokenName,
10275
- params: payload.params || {},
10276
- iat: payload.iat,
10277
- exp: payload.exp
10278
- }
10279
- });
10280
- } catch {
10281
- localStorage.removeItem(key);
10319
+ scope = scopeKey.slice(nsPrefix.length);
10320
+ } else {
10321
+ if (scopeKey.includes(":"))
10322
+ continue;
10323
+ scope = scopeKey;
10324
+ }
10325
+ try {
10326
+ const parts = jwt.split(".");
10327
+ if (parts.length !== 3)
10328
+ continue;
10329
+ const payload = JSON.parse(atob(parts[1]));
10330
+ this.scopes.set(scope, {
10331
+ raw: jwt,
10332
+ decoded: {
10333
+ tokenName: payload.tokenName,
10334
+ params: payload.params || {},
10335
+ iat: payload.iat,
10336
+ exp: payload.exp
10282
10337
  }
10283
- }
10338
+ });
10339
+ } catch {
10340
+ removeTokenCookie(scopeKey);
10284
10341
  }
10285
10342
  }
10286
10343
  }
@@ -10312,10 +10369,8 @@ class AuthAdapter {
10312
10369
  return Array.from(this.scopes.keys());
10313
10370
  }
10314
10371
  clear() {
10315
- if (hasLocalStorage()) {
10316
- for (const scope of this.scopes.keys()) {
10317
- localStorage.removeItem(this.storageKey(scope));
10318
- }
10372
+ for (const scope of this.scopes.keys()) {
10373
+ removeTokenCookie(this.scopeKey(scope));
10319
10374
  }
10320
10375
  this.scopes.clear();
10321
10376
  }
@@ -14595,7 +14650,7 @@ var Operation, PROXY_DRAFT, RAW_RETURN_SYMBOL, iteratorSymbol, dataTypes, intern
14595
14650
  }
14596
14651
  return returnValue(result);
14597
14652
  };
14598
- }, create, constructorString, TOKEN_PREFIX = "arc:token:", DEFAULT_TIMEOUT_MS = 8000, provider = null, latestSync = null, syncSeq = 0, eventWireInstanceCounter = 0, EVENT_TABLES, arrayValidator, ArcArray, objectValidator, ArcObject, ScopedDataStorage, ArcAuthenticationError, ArcAuthorizationError2, ArcValidationError2, ArcPrimitive, stringValidator, ArcString, ArcContextElement, ArcBoolean, ArcId, numberValidator, ArcNumber, ArcEvent, ArcCommand, ArcListener, ArcRoute, ForkedStoreState, ForkedDataStorage, MasterStoreState, MasterDataStorage2, dateValidator, _te, _td, originCache, originStackCache, originError, CLOSE, Query, PostgresError, Errors, types2, Identifier, Parameter, Builder, defaultHandlers, builders, serializers, parsers, mergeUserTypes = function(types22) {
14653
+ }, create, constructorString, COOKIE_PREFIX = "arc_token", TOKEN_BUMP_KEY = "arc:token-bump", DEFAULT_TIMEOUT_MS = 8000, provider = null, latestSync = null, syncSeq = 0, eventWireInstanceCounter = 0, EVENT_TABLES, arrayValidator, ArcArray, objectValidator, ArcObject, ScopedDataStorage, ArcAuthenticationError, ArcAuthorizationError2, ArcValidationError2, ArcPrimitive, stringValidator, ArcString, ArcContextElement, ArcBoolean, ArcId, numberValidator, ArcNumber, ArcEvent, ArcCommand, ArcListener, ArcRoute, ForkedStoreState, ForkedDataStorage, MasterStoreState, MasterDataStorage2, dateValidator, _te, _td, originCache, originStackCache, originError, CLOSE, Query, PostgresError, Errors, types2, Identifier, Parameter, Builder, defaultHandlers, builders, serializers, parsers, mergeUserTypes = function(types22) {
14599
14654
  const user = typeHandlers(types22 || {});
14600
14655
  return {
14601
14656
  serializers: Object.assign({}, serializers, user.serializers),
@@ -17838,8 +17893,72 @@ function apply2(state, patches, applyOptions) {
17838
17893
  }
17839
17894
  return create2(state, mutate, Object.assign(Object.assign({}, applyOptions), { enablePatches: false }));
17840
17895
  }
17841
- function hasLocalStorage2() {
17842
- return typeof localStorage !== "undefined";
17896
+ function hasDocument2() {
17897
+ return typeof document !== "undefined";
17898
+ }
17899
+ function signalCrossTabChange2() {
17900
+ if (typeof localStorage === "undefined")
17901
+ return;
17902
+ try {
17903
+ localStorage.setItem(TOKEN_BUMP_KEY2, String(Date.now()));
17904
+ } catch {}
17905
+ }
17906
+ function isSecureContext2() {
17907
+ return typeof location !== "undefined" && location.protocol === "https:";
17908
+ }
17909
+ function tokenCookieName2(scopeKey) {
17910
+ return scopeKey === "default" ? COOKIE_PREFIX2 : `${COOKIE_PREFIX2}_${scopeKey.replace(/:/g, ".")}`;
17911
+ }
17912
+ function scopeKeyFromCookieName2(name) {
17913
+ if (name === COOKIE_PREFIX2)
17914
+ return "default";
17915
+ if (!name.startsWith(`${COOKIE_PREFIX2}_`))
17916
+ return null;
17917
+ return name.slice(COOKIE_PREFIX2.length + 1).replace(/\./g, ":");
17918
+ }
17919
+ function maxAgeFromExp2(exp) {
17920
+ const THIRTY_DAYS = 30 * 24 * 60 * 60;
17921
+ if (typeof exp !== "number" || !Number.isFinite(exp))
17922
+ return THIRTY_DAYS;
17923
+ const expMs = exp > 1000000000000 ? exp : exp * 1000;
17924
+ const secs = Math.floor((expMs - Date.now()) / 1000);
17925
+ return secs > 0 ? secs : THIRTY_DAYS;
17926
+ }
17927
+ function writeTokenCookie2(scopeKey, jwt, exp) {
17928
+ if (!hasDocument2())
17929
+ return;
17930
+ const attrs = [
17931
+ "Path=/",
17932
+ "SameSite=Lax",
17933
+ `Max-Age=${maxAgeFromExp2(exp)}`
17934
+ ];
17935
+ if (isSecureContext2())
17936
+ attrs.push("Secure");
17937
+ document.cookie = `${tokenCookieName2(scopeKey)}=${encodeURIComponent(jwt)}; ${attrs.join("; ")}`;
17938
+ signalCrossTabChange2();
17939
+ }
17940
+ function removeTokenCookie2(scopeKey) {
17941
+ if (!hasDocument2())
17942
+ return;
17943
+ document.cookie = `${tokenCookieName2(scopeKey)}=; Path=/; SameSite=Lax; Max-Age=0`;
17944
+ signalCrossTabChange2();
17945
+ }
17946
+ function readAllTokenCookies2() {
17947
+ if (!hasDocument2() || !document.cookie)
17948
+ return [];
17949
+ const out = [];
17950
+ for (const part of document.cookie.split(";")) {
17951
+ const eq = part.indexOf("=");
17952
+ if (eq < 0)
17953
+ continue;
17954
+ const scopeKey = scopeKeyFromCookieName2(part.slice(0, eq).trim());
17955
+ if (scopeKey === null)
17956
+ continue;
17957
+ const jwt = decodeURIComponent(part.slice(eq + 1).trim());
17958
+ if (jwt)
17959
+ out.push({ scopeKey, jwt });
17960
+ }
17961
+ return out;
17843
17962
  }
17844
17963
  function notifyTokenChange2(scope) {
17845
17964
  if (typeof window !== "undefined") {
@@ -17855,24 +17974,21 @@ class AuthAdapter2 {
17855
17974
  constructor(options) {
17856
17975
  this.namespace = options?.storageNamespace || undefined;
17857
17976
  }
17858
- storageKey(scope) {
17859
- return this.namespace ? `${TOKEN_PREFIX2}${this.namespace}:${scope}` : TOKEN_PREFIX2 + scope;
17977
+ scopeKey(scope) {
17978
+ return this.namespace ? `${this.namespace}:${scope}` : scope;
17860
17979
  }
17861
17980
  setToken(token, scope = "default") {
17862
17981
  if (!token) {
17863
17982
  this.scopes.delete(scope);
17864
- if (hasLocalStorage2()) {
17865
- localStorage.removeItem(this.storageKey(scope));
17866
- notifyTokenChange2(scope);
17867
- }
17983
+ removeTokenCookie2(this.scopeKey(scope));
17984
+ notifyTokenChange2(scope);
17868
17985
  return;
17869
17986
  }
17870
17987
  try {
17871
17988
  const parts = token.split(".");
17872
17989
  if (parts.length !== 3) {
17873
17990
  this.scopes.delete(scope);
17874
- if (hasLocalStorage2())
17875
- localStorage.removeItem(this.storageKey(scope));
17991
+ removeTokenCookie2(this.scopeKey(scope));
17876
17992
  return;
17877
17993
  }
17878
17994
  const payload = JSON.parse(atob(parts[1]));
@@ -17885,49 +18001,45 @@ class AuthAdapter2 {
17885
18001
  exp: payload.exp
17886
18002
  }
17887
18003
  });
17888
- if (hasLocalStorage2()) {
17889
- localStorage.setItem(this.storageKey(scope), token);
17890
- notifyTokenChange2(scope);
17891
- }
18004
+ writeTokenCookie2(this.scopeKey(scope), token, payload.exp);
18005
+ notifyTokenChange2(scope);
17892
18006
  } catch {
17893
18007
  this.scopes.delete(scope);
17894
- if (hasLocalStorage2())
17895
- localStorage.removeItem(this.storageKey(scope));
18008
+ removeTokenCookie2(this.scopeKey(scope));
17896
18009
  }
17897
18010
  }
17898
18011
  setDecoded(decoded, scope = "default") {
17899
18012
  this.scopes.set(scope, { raw: "", decoded });
17900
18013
  }
17901
18014
  loadPersisted() {
17902
- if (!hasLocalStorage2())
17903
- return;
17904
- const prefix = this.namespace ? `${TOKEN_PREFIX2}${this.namespace}:` : TOKEN_PREFIX2;
17905
- for (let i = 0;i < localStorage.length; i++) {
17906
- const key = localStorage.key(i);
17907
- if (key?.startsWith(prefix)) {
17908
- const scope = key.slice(prefix.length);
17909
- if (!this.namespace && scope.includes(":"))
18015
+ const nsPrefix = this.namespace ? `${this.namespace}:` : "";
18016
+ for (const { scopeKey, jwt } of readAllTokenCookies2()) {
18017
+ let scope;
18018
+ if (this.namespace) {
18019
+ if (!scopeKey.startsWith(nsPrefix))
17910
18020
  continue;
17911
- const raw = localStorage.getItem(key);
17912
- if (raw) {
17913
- try {
17914
- const parts = raw.split(".");
17915
- if (parts.length !== 3)
17916
- continue;
17917
- const payload = JSON.parse(atob(parts[1]));
17918
- this.scopes.set(scope, {
17919
- raw,
17920
- decoded: {
17921
- tokenName: payload.tokenName,
17922
- params: payload.params || {},
17923
- iat: payload.iat,
17924
- exp: payload.exp
17925
- }
17926
- });
17927
- } catch {
17928
- localStorage.removeItem(key);
18021
+ scope = scopeKey.slice(nsPrefix.length);
18022
+ } else {
18023
+ if (scopeKey.includes(":"))
18024
+ continue;
18025
+ scope = scopeKey;
18026
+ }
18027
+ try {
18028
+ const parts = jwt.split(".");
18029
+ if (parts.length !== 3)
18030
+ continue;
18031
+ const payload = JSON.parse(atob(parts[1]));
18032
+ this.scopes.set(scope, {
18033
+ raw: jwt,
18034
+ decoded: {
18035
+ tokenName: payload.tokenName,
18036
+ params: payload.params || {},
18037
+ iat: payload.iat,
18038
+ exp: payload.exp
17929
18039
  }
17930
- }
18040
+ });
18041
+ } catch {
18042
+ removeTokenCookie2(scopeKey);
17931
18043
  }
17932
18044
  }
17933
18045
  }
@@ -17959,10 +18071,8 @@ class AuthAdapter2 {
17959
18071
  return Array.from(this.scopes.keys());
17960
18072
  }
17961
18073
  clear() {
17962
- if (hasLocalStorage2()) {
17963
- for (const scope of this.scopes.keys()) {
17964
- localStorage.removeItem(this.storageKey(scope));
17965
- }
18074
+ for (const scope of this.scopes.keys()) {
18075
+ removeTokenCookie2(this.scopeKey(scope));
17966
18076
  }
17967
18077
  this.scopes.clear();
17968
18078
  }
@@ -20673,7 +20783,7 @@ var Operation2, PROXY_DRAFT2, RAW_RETURN_SYMBOL2, iteratorSymbol2, dataTypes2, i
20673
20783
  }
20674
20784
  return returnValue(result);
20675
20785
  };
20676
- }, create2, constructorString2, TOKEN_PREFIX2 = "arc:token:", DEFAULT_TIMEOUT_MS2 = 8000, provider2 = null, latestSync2 = null, syncSeq2 = 0, eventWireInstanceCounter2 = 0, EVENT_TABLES2, arrayValidator2, ArcArray2, objectValidator2, ArcObject2, ScopedDataStorage2, ArcAuthenticationError2, ArcAuthorizationError3, ArcValidationError3, ArcPrimitive2, stringValidator2, ArcString2, ArcContextElement2, ArcBoolean2, ArcId2, numberValidator2, ArcNumber2, ArcEvent2, ArcCommand2, ArcListener2, ArcRoute2, ForkedStoreState2, ForkedDataStorage2, MasterStoreState2, MasterDataStorage3, dateValidator2, _te2, _td2, SQLiteReadWriteTransaction, createSQLiteAdapterFactory = (db) => {
20786
+ }, create2, constructorString2, COOKIE_PREFIX2 = "arc_token", TOKEN_BUMP_KEY2 = "arc:token-bump", DEFAULT_TIMEOUT_MS2 = 8000, provider2 = null, latestSync2 = null, syncSeq2 = 0, eventWireInstanceCounter2 = 0, EVENT_TABLES2, arrayValidator2, ArcArray2, objectValidator2, ArcObject2, ScopedDataStorage2, ArcAuthenticationError2, ArcAuthorizationError3, ArcValidationError3, ArcPrimitive2, stringValidator2, ArcString2, ArcContextElement2, ArcBoolean2, ArcId2, numberValidator2, ArcNumber2, ArcEvent2, ArcCommand2, ArcListener2, ArcRoute2, ForkedStoreState2, ForkedDataStorage2, MasterStoreState2, MasterDataStorage3, dateValidator2, _te2, _td2, SQLiteReadWriteTransaction, createSQLiteAdapterFactory = (db) => {
20677
20787
  return async (context) => {
20678
20788
  const adapter = new SQLiteAdapter(db, context);
20679
20789
  await adapter.initialize();
@@ -31322,8 +31432,8 @@ ${colors3.yellow}Type declaration errors:${colors3.reset}`);
31322
31432
  }
31323
31433
 
31324
31434
  // 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";
31435
+ import { copyFileSync, existsSync as existsSync12, mkdirSync as mkdirSync10, readdirSync as readdirSync7, readFileSync as readFileSync13, writeFileSync as writeFileSync10 } from "fs";
31436
+ import { dirname as dirname8, join as join14 } from "path";
31327
31437
 
31328
31438
  // src/builder/module-builder.ts
31329
31439
  import { execSync } from "child_process";
@@ -31692,7 +31802,7 @@ function workspaceSourcePlugin(srcByName) {
31692
31802
  }
31693
31803
  };
31694
31804
  }
31695
- var SERVER_ONLY_NODE_BUILTINS = new Set([
31805
+ var SERVER_ONLY_NODE_BUILTINS = [
31696
31806
  "crypto",
31697
31807
  "stream",
31698
31808
  "zlib",
@@ -31720,15 +31830,13 @@ var SERVER_ONLY_NODE_BUILTINS = new Set([
31720
31830
  "diagnostics_channel",
31721
31831
  "module",
31722
31832
  "constants"
31723
- ]);
31833
+ ];
31834
+ var NODE_STUB_FILTER = new RegExp(`^(node:)?(${SERVER_ONLY_NODE_BUILTINS.map((b) => b.replace(/[.*+?^${}()|[\]\\/]/g, "\\$&")).join("|")})$`);
31724
31835
  function nodeServerBuiltinStubPlugin() {
31725
31836
  return {
31726
31837
  name: "node-server-builtin-stub",
31727
31838
  setup(build2) {
31728
- build2.onResolve({ filter: /^(node:)?[a-z_/]+$/ }, (args) => {
31729
- const bare = args.path.replace(/^node:/, "");
31730
- if (!SERVER_ONLY_NODE_BUILTINS.has(bare))
31731
- return;
31839
+ build2.onResolve({ filter: NODE_STUB_FILTER }, (args) => {
31732
31840
  return { path: args.path, namespace: "node-server-stub" };
31733
31841
  });
31734
31842
  build2.onLoad({ filter: /.*/, namespace: "node-server-stub" }, (args) => ({
@@ -32023,6 +32131,26 @@ function readServerExternals(path4) {
32023
32131
  return [];
32024
32132
  }
32025
32133
  }
32134
+ var STATIC_CHUNK_IMPORT = /(?:^|[;}\s])import\s*["']\.\/(chunk-[a-z0-9]+\.js)["']|from\s*["']\.\/(chunk-[a-z0-9]+\.js)["']/g;
32135
+ function staticChunkClosure(entryBytes, chunkBytes) {
32136
+ const seen = new Set;
32137
+ const stack = [entryBytes];
32138
+ while (stack.length) {
32139
+ const src = Buffer.from(stack.pop()).toString("utf8");
32140
+ STATIC_CHUNK_IMPORT.lastIndex = 0;
32141
+ let m;
32142
+ while (m = STATIC_CHUNK_IMPORT.exec(src)) {
32143
+ const chunk = m[1] ?? m[2];
32144
+ if (seen.has(chunk))
32145
+ continue;
32146
+ seen.add(chunk);
32147
+ const b = chunkBytes.get(chunk);
32148
+ if (b)
32149
+ stack.push(b);
32150
+ }
32151
+ }
32152
+ return [...seen];
32153
+ }
32026
32154
  function buildStatsEnabled() {
32027
32155
  return process.env.ARC_BUILD_STATS === "1";
32028
32156
  }
@@ -32322,22 +32450,31 @@ export { startApp } from "@arcote.tech/platform";
32322
32450
  }
32323
32451
  let initialFile = "";
32324
32452
  let initialHash = "";
32453
+ let initialStaticChunks = [];
32325
32454
  const groups = {};
32326
32455
  const sharedChunks = [];
32456
+ const chunkBytes = new Map;
32457
+ for (const out of outFiles) {
32458
+ if (out.kind === "chunk")
32459
+ chunkBytes.set(out.name, out.bytes);
32460
+ }
32327
32461
  for (const out of outFiles) {
32328
32462
  if (out.kind === "entry-point") {
32329
32463
  const hash = sha256Hex(out.bytes).slice(0, 16);
32330
32464
  const stem = out.name.replace(/\.js$/, "");
32331
32465
  const finalName = `${stem}.${hash}.js`;
32332
32466
  writeFileSync7(join9(outDir, finalName), out.bytes);
32467
+ const staticChunks = staticChunkClosure(out.bytes, chunkBytes);
32333
32468
  if (stem === "initial") {
32334
32469
  initialFile = finalName;
32335
32470
  initialHash = hash;
32471
+ initialStaticChunks = staticChunks;
32336
32472
  } else {
32337
32473
  groups[stem] = {
32338
32474
  file: finalName,
32339
32475
  hash,
32340
- modules: groupModuleMap.get(stem) ?? []
32476
+ modules: groupModuleMap.get(stem) ?? [],
32477
+ staticChunks
32341
32478
  };
32342
32479
  }
32343
32480
  } else if (out.kind === "chunk") {
@@ -32365,7 +32502,7 @@ export { startApp } from "@arcote.tech/platform";
32365
32502
  }
32366
32503
  }
32367
32504
  const manifest = {
32368
- initial: { file: initialFile, hash: initialHash },
32505
+ initial: { file: initialFile, hash: initialHash, staticChunks: initialStaticChunks },
32369
32506
  groups,
32370
32507
  sharedChunks,
32371
32508
  cached: false
@@ -32629,9 +32766,86 @@ const { writeFileSync } = await import("node:fs");
32629
32766
  writeFileSync(out, JSON.stringify({ access, exposure }, null, 2) + "\\n");
32630
32767
  `.trim();
32631
32768
 
32769
+ // src/builder/seed-guard.ts
32770
+ import { existsSync as existsSync10, readdirSync as readdirSync5, readFileSync as readFileSync10 } from "fs";
32771
+ import { join as join11, relative as relative4, sep as sep3 } from "path";
32772
+ var CALL = /\.(?:seedWith|withSeeds)\s*\(/g;
32773
+ var GATED = /^\.(?:seedWith|withSeeds)\s*\(\s*ONLY_SERVER\b/;
32774
+ function walkTsFiles(dir, out) {
32775
+ for (const entry of readdirSync5(dir, { withFileTypes: true })) {
32776
+ if (entry.name === "node_modules" || entry.name === "dist")
32777
+ continue;
32778
+ const abs = join11(dir, entry.name);
32779
+ if (entry.isDirectory()) {
32780
+ if (entry.name === "__tests__")
32781
+ continue;
32782
+ walkTsFiles(abs, out);
32783
+ } else if (entry.isFile() && /\.(ts|tsx)$/.test(entry.name) && !entry.name.endsWith(".d.ts")) {
32784
+ out.push(abs);
32785
+ }
32786
+ }
32787
+ }
32788
+ function findUngatedSeeds(pkgs, rootDir) {
32789
+ const leaks = [];
32790
+ const scanned = new Set;
32791
+ for (const pkg of pkgs) {
32792
+ const srcDir = join11(pkg.path, "src");
32793
+ if (scanned.has(srcDir) || !existsSync10(srcDir))
32794
+ continue;
32795
+ scanned.add(srcDir);
32796
+ const files = [];
32797
+ walkTsFiles(srcDir, files);
32798
+ for (const abs of files) {
32799
+ const content = readFileSync10(abs, "utf-8");
32800
+ CALL.lastIndex = 0;
32801
+ let m;
32802
+ while ((m = CALL.exec(content)) !== null) {
32803
+ const rest = content.slice(m.index);
32804
+ if (GATED.test(rest))
32805
+ continue;
32806
+ const lineStart = content.lastIndexOf(`
32807
+ `, m.index) + 1;
32808
+ if (content.slice(lineStart, m.index).includes("//"))
32809
+ continue;
32810
+ const before = content.slice(0, m.index);
32811
+ if (before.lastIndexOf("/*") > before.lastIndexOf("*/"))
32812
+ continue;
32813
+ const nlAfter = content.indexOf(`
32814
+ `, m.index);
32815
+ const lineEnd = nlAfter === -1 ? content.length : nlAfter;
32816
+ const line = content.slice(0, m.index).split(`
32817
+ `).length;
32818
+ const relpath = relative4(rootDir, abs).split(sep3).join("/");
32819
+ leaks.push({
32820
+ relpath,
32821
+ line,
32822
+ snippet: content.slice(lineStart, lineEnd).trim().slice(0, 120)
32823
+ });
32824
+ }
32825
+ }
32826
+ }
32827
+ return leaks;
32828
+ }
32829
+ function assertSeedsServerGated(pkgs, rootDir) {
32830
+ const leaks = findUngatedSeeds(pkgs, rootDir);
32831
+ if (leaks.length === 0)
32832
+ return;
32833
+ const lines = leaks.map((l) => ` \u2022 ${l.relpath}:${l.line}
32834
+ ${l.snippet}`).join(`
32835
+ `);
32836
+ throw new Error(`Seed leak do bundla klienta: ${leaks.length} wywo\u0142a\u0144 .seedWith(...)/.withSeeds(...) ` + `nie jest owini\u0119tych w ONLY_SERVER.
32837
+
32838
+ ${lines}
32839
+
32840
+ ` + `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:
32841
+ ` + ` .seedWith(ONLY_SERVER ? [ /* wiersze */ ] : [])
32842
+ ` + ` .seedWith(ONLY_SERVER ? (await import("./seeds.server")).rows : [])
32843
+ ` + `Statyczny import z osobnego pliku NIE pomaga (build wymusza sideEffects:true).`);
32844
+ }
32845
+
32632
32846
  // 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";
32847
+ import { readFileSync as readFileSync11, readdirSync as readdirSync6, statSync as statSync2 } from "fs";
32848
+ import { basename as basename4, join as join12 } from "path";
32635
32849
  var PUBLIC_CHUNK = "public";
32636
32850
  function planChunks(packages, accessMap) {
32637
32851
  const assignments = new Map;
@@ -32667,14 +32881,14 @@ var MODULE_CALL = /\bmodule\(\s*["'`]([a-zA-Z0-9_-]+)["'`]/g;
32667
32881
  function collectModuleNames(dir, acc) {
32668
32882
  let entries;
32669
32883
  try {
32670
- entries = readdirSync5(dir);
32884
+ entries = readdirSync6(dir);
32671
32885
  } catch {
32672
32886
  return;
32673
32887
  }
32674
32888
  for (const e of entries) {
32675
32889
  if (e === "node_modules" || e === "dist")
32676
32890
  continue;
32677
- const full = join11(dir, e);
32891
+ const full = join12(dir, e);
32678
32892
  let isDir = false;
32679
32893
  try {
32680
32894
  isDir = statSync2(full).isDirectory();
@@ -32684,7 +32898,7 @@ function collectModuleNames(dir, acc) {
32684
32898
  if (isDir) {
32685
32899
  collectModuleNames(full, acc);
32686
32900
  } else if (e.endsWith(".ts") || e.endsWith(".tsx")) {
32687
- const src = readFileSync10(full, "utf-8");
32901
+ const src = readFileSync11(full, "utf-8");
32688
32902
  MODULE_CALL.lastIndex = 0;
32689
32903
  let m;
32690
32904
  while (m = MODULE_CALL.exec(src))
@@ -32694,14 +32908,14 @@ function collectModuleNames(dir, acc) {
32694
32908
  }
32695
32909
  function packageDeclaresModule(pkg) {
32696
32910
  const names = new Set;
32697
- collectModuleNames(join11(pkg.path, "src"), names);
32911
+ collectModuleNames(join12(pkg.path, "src"), names);
32698
32912
  return names.size > 0;
32699
32913
  }
32700
32914
  function assertOneModulePerPackage(packages) {
32701
32915
  const offenders = [];
32702
32916
  for (const pkg of packages) {
32703
32917
  const names = new Set;
32704
- collectModuleNames(join11(pkg.path, "src"), names);
32918
+ collectModuleNames(join12(pkg.path, "src"), names);
32705
32919
  if (names.size > 1) {
32706
32920
  offenders.push({ pkg: pkg.name, modules: [...names].sort() });
32707
32921
  }
@@ -32733,8 +32947,8 @@ function resolveChunk(moduleName, access) {
32733
32947
 
32734
32948
  // src/builder/dependency-collector.ts
32735
32949
  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";
32950
+ import { existsSync as existsSync11, mkdirSync as mkdirSync9, readFileSync as readFileSync12, writeFileSync as writeFileSync9 } from "fs";
32951
+ import { basename as basename5, dirname as dirname7, join as join13 } from "path";
32738
32952
  import { fileURLToPath as fileURLToPath6 } from "url";
32739
32953
  function collectFrameworkDeps(arcDir, rootDir, packages, sharedDeps = [], serverExternals = []) {
32740
32954
  mkdirSync9(arcDir, { recursive: true });
@@ -32746,7 +32960,7 @@ function collectFrameworkDeps(arcDir, rootDir, packages, sharedDeps = [], server
32746
32960
  try {
32747
32961
  const cliDir = dirname7(fileURLToPath6(import.meta.url));
32748
32962
  const arcOtelPkgPath = Bun.resolveSync("@arcote.tech/arc-otel/package.json", cliDir);
32749
- const arcOtelPkg = JSON.parse(readFileSync11(arcOtelPkgPath, "utf-8"));
32963
+ const arcOtelPkg = JSON.parse(readFileSync12(arcOtelPkgPath, "utf-8"));
32750
32964
  for (const [name, spec] of Object.entries(arcOtelPkg.dependencies ?? {})) {
32751
32965
  if (name.startsWith("@opentelemetry/")) {
32752
32966
  versions[name] = spec;
@@ -32757,10 +32971,10 @@ function collectFrameworkDeps(arcDir, rootDir, packages, sharedDeps = [], server
32757
32971
  console.warn(`[arc-otel] could not resolve @arcote.tech/arc-otel \u2014 image will run without telemetry deps: ${e.message}`);
32758
32972
  }
32759
32973
  let rootArc;
32760
- const rootPkgPath = join12(rootDir, "package.json");
32761
- if (existsSync10(rootPkgPath)) {
32974
+ const rootPkgPath = join13(rootDir, "package.json");
32975
+ if (existsSync11(rootPkgPath)) {
32762
32976
  try {
32763
- const rootPkg = JSON.parse(readFileSync11(rootPkgPath, "utf-8"));
32977
+ const rootPkg = JSON.parse(readFileSync12(rootPkgPath, "utf-8"));
32764
32978
  if (rootPkg.arc && typeof rootPkg.arc === "object")
32765
32979
  rootArc = rootPkg.arc;
32766
32980
  } catch {}
@@ -32772,11 +32986,11 @@ function collectFrameworkDeps(arcDir, rootDir, packages, sharedDeps = [], server
32772
32986
  dependencies: versions,
32773
32987
  ...rootArc ? { arc: rootArc } : {}
32774
32988
  };
32775
- const manifestPath = join12(arcDir, "package.json");
32989
+ const manifestPath = join13(arcDir, "package.json");
32776
32990
  writeFileSync9(manifestPath, JSON.stringify(manifest, null, 2) + `
32777
32991
  `);
32778
- const hash = sha256Hex2(readFileSync11(manifestPath));
32779
- writeFileSync9(join12(arcDir, ".deps-hash"), hash + `
32992
+ const hash = sha256Hex2(readFileSync12(manifestPath));
32993
+ writeFileSync9(join13(arcDir, ".deps-hash"), hash + `
32780
32994
  `);
32781
32995
  return { hash, manifestPath };
32782
32996
  }
@@ -32784,7 +32998,7 @@ function sha256Hex2(bytes) {
32784
32998
  return createHash("sha256").update(bytes).digest("hex");
32785
32999
  }
32786
33000
  function resolveFrameworkVersions(rootDir, packages) {
32787
- const rootPkg = JSON.parse(readFileSync11(join12(rootDir, "package.json"), "utf-8"));
33001
+ const rootPkg = JSON.parse(readFileSync12(join13(rootDir, "package.json"), "utf-8"));
32788
33002
  const rootDeps = rootPkg.dependencies ?? {};
32789
33003
  const rootDevDeps = rootPkg.devDependencies ?? {};
32790
33004
  const required = new Set(FRAMEWORK_PEERS);
@@ -32815,7 +33029,7 @@ function findWorkspaceSpec(packages, name) {
32815
33029
  return;
32816
33030
  }
32817
33031
  function mergeServerExternals(versions, rootDir, packages, externals) {
32818
- const rootPkg = JSON.parse(readFileSync11(join12(rootDir, "package.json"), "utf-8"));
33032
+ const rootPkg = JSON.parse(readFileSync12(join13(rootDir, "package.json"), "utf-8"));
32819
33033
  const rootDeps = rootPkg.dependencies ?? {};
32820
33034
  const rootDevDeps = rootPkg.devDependencies ?? {};
32821
33035
  for (const { name, version } of externals) {
@@ -32843,9 +33057,9 @@ function resolveWorkspace() {
32843
33057
  process.exit(1);
32844
33058
  }
32845
33059
  const rootDir = dirname8(packageJsonPath);
32846
- const rootPkg = JSON.parse(readFileSync12(packageJsonPath, "utf-8"));
33060
+ const rootPkg = JSON.parse(readFileSync13(packageJsonPath, "utf-8"));
32847
33061
  const appName = rootPkg.name ?? "Arc App";
32848
- const arcDir = join13(rootDir, ".arc", "platform");
33062
+ const arcDir = join14(rootDir, ".arc", "platform");
32849
33063
  log2("Scanning workspaces...");
32850
33064
  const packages = discoverPackages(rootDir);
32851
33065
  if (packages.length > 0) {
@@ -32855,10 +33069,10 @@ function resolveWorkspace() {
32855
33069
  }
32856
33070
  let manifest;
32857
33071
  for (const name of ["manifest.json", "manifest.webmanifest"]) {
32858
- const manifestPath = join13(rootDir, name);
32859
- if (existsSync11(manifestPath)) {
33072
+ const manifestPath = join14(rootDir, name);
33073
+ if (existsSync12(manifestPath)) {
32860
33074
  try {
32861
- const data = JSON.parse(readFileSync12(manifestPath, "utf-8"));
33075
+ const data = JSON.parse(readFileSync13(manifestPath, "utf-8"));
32862
33076
  const icons = data.icons;
32863
33077
  manifest = {
32864
33078
  path: manifestPath,
@@ -32877,9 +33091,9 @@ function resolveWorkspace() {
32877
33091
  rootPkg,
32878
33092
  appName,
32879
33093
  arcDir,
32880
- browserDir: join13(arcDir, "browser"),
32881
- assetsDir: join13(arcDir, "assets"),
32882
- publicDir: join13(rootDir, "public"),
33094
+ browserDir: join14(arcDir, "browser"),
33095
+ assetsDir: join14(arcDir, "assets"),
33096
+ publicDir: join14(rootDir, "public"),
32883
33097
  packages,
32884
33098
  manifest
32885
33099
  };
@@ -32892,12 +33106,13 @@ async function buildAll(ws, opts = {}) {
32892
33106
  const federation = getFederationConfig(ws);
32893
33107
  log2(`Building (concurrency parallel${noCache ? ", no-cache" : ""})...`);
32894
33108
  assertOneModulePerPackage(ws.packages);
33109
+ assertSeedsServerGated(ws.packages, ws.rootDir);
32895
33110
  await buildContextPackages(ws.rootDir, ws.packages, cache, noCache);
32896
- const serverDir = join13(ws.arcDir, "server");
33111
+ const serverDir = join14(ws.arcDir, "server");
32897
33112
  const { entryFile: serverEntry, externals: serverExternals } = await buildServerApp(ws.rootDir, serverDir, ws.packages, cache, noCache);
32898
- const accessMap = await extractAccessMap(ws.rootDir, join13(serverDir, serverEntry));
33113
+ const accessMap = await extractAccessMap(ws.rootDir, join14(serverDir, serverEntry));
32899
33114
  mkdirSync10(ws.arcDir, { recursive: true });
32900
- writeFileSync10(join13(ws.arcDir, "access.json"), JSON.stringify(accessMap.access, null, 2) + `
33115
+ writeFileSync10(join14(ws.arcDir, "access.json"), JSON.stringify(accessMap.access, null, 2) + `
32901
33116
  `);
32902
33117
  const isHost = Boolean(federation?.host);
32903
33118
  const moduleNameOf2 = (name) => name.split("/").pop() ?? name;
@@ -32917,7 +33132,7 @@ async function buildAll(ws, opts = {}) {
32917
33132
  const i18nCollector = new Map;
32918
33133
  const browserSequence = (async () => {
32919
33134
  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;
33135
+ 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
33136
  return { bundled, fed };
32922
33137
  })();
32923
33138
  const [{ bundled: browserResult, fed: fedResult }, , , , shellResult] = await Promise.all([
@@ -32925,7 +33140,7 @@ async function buildAll(ws, opts = {}) {
32925
33140
  buildStyles(ws.rootDir, ws.arcDir, ws.packages, themePath, cache, noCache),
32926
33141
  copyBrowserAssets(ws, cache, noCache),
32927
33142
  buildTranslations(ws.rootDir, ws.arcDir, cache, noCache),
32928
- needsPeerShell ? buildPeerShell(ws.rootDir, join13(ws.arcDir, "shell"), cache, noCache) : Promise.resolve(undefined)
33143
+ needsPeerShell ? buildPeerShell(ws.rootDir, join14(ws.arcDir, "shell"), cache, noCache) : Promise.resolve(undefined)
32929
33144
  ]);
32930
33145
  const { finalizeTranslations: finalizeTranslations3 } = await Promise.resolve().then(() => (init_i18n(), exports_i18n));
32931
33146
  await finalizeTranslations3(ws.rootDir, ws.arcDir, i18nCollector);
@@ -32950,7 +33165,7 @@ async function buildAll(ws, opts = {}) {
32950
33165
  }
32951
33166
  } : undefined;
32952
33167
  const finalManifest = assembleManifest(ws, browserResult, cache, shellResult, federationBuild);
32953
- writeFileSync10(join13(ws.arcDir, "manifest.json"), JSON.stringify(finalManifest, null, 2));
33168
+ writeFileSync10(join14(ws.arcDir, "manifest.json"), JSON.stringify(finalManifest, null, 2));
32954
33169
  return finalManifest;
32955
33170
  }
32956
33171
  function assembleManifest(ws, browser, cache, shell, federation) {
@@ -32976,35 +33191,35 @@ function getFederationConfig(ws) {
32976
33191
  }
32977
33192
  function resolveAssetSource(from, pkgDir, rootDir) {
32978
33193
  if (from.startsWith("./") || from.startsWith("../")) {
32979
- const resolved = join13(pkgDir, from);
32980
- return existsSync11(resolved) ? resolved : null;
33194
+ const resolved = join14(pkgDir, from);
33195
+ return existsSync12(resolved) ? resolved : null;
32981
33196
  }
32982
33197
  const candidates = [
32983
- join13(rootDir, "node_modules", from),
32984
- join13(pkgDir, "node_modules", from)
33198
+ join14(rootDir, "node_modules", from),
33199
+ join14(pkgDir, "node_modules", from)
32985
33200
  ];
32986
33201
  for (const c of candidates) {
32987
- if (existsSync11(c))
33202
+ if (existsSync12(c))
32988
33203
  return c;
32989
33204
  }
32990
- const bunCacheDir = join13(rootDir, "node_modules", ".bun");
32991
- if (existsSync11(bunCacheDir)) {
32992
- for (const entry of readdirSync6(bunCacheDir, { withFileTypes: true })) {
33205
+ const bunCacheDir = join14(rootDir, "node_modules", ".bun");
33206
+ if (existsSync12(bunCacheDir)) {
33207
+ for (const entry of readdirSync7(bunCacheDir, { withFileTypes: true })) {
32993
33208
  if (!entry.isDirectory())
32994
33209
  continue;
32995
- const candidate = join13(bunCacheDir, entry.name, "node_modules", from);
32996
- if (existsSync11(candidate))
33210
+ const candidate = join14(bunCacheDir, entry.name, "node_modules", from);
33211
+ if (existsSync12(candidate))
32997
33212
  return candidate;
32998
33213
  }
32999
33214
  }
33000
33215
  return null;
33001
33216
  }
33002
33217
  function readBrowserAssets(pkgDir) {
33003
- const pkgJsonPath = join13(pkgDir, "package.json");
33004
- if (!existsSync11(pkgJsonPath))
33218
+ const pkgJsonPath = join14(pkgDir, "package.json");
33219
+ if (!existsSync12(pkgJsonPath))
33005
33220
  return [];
33006
33221
  try {
33007
- const pkg = JSON.parse(readFileSync12(pkgJsonPath, "utf-8"));
33222
+ const pkg = JSON.parse(readFileSync13(pkgJsonPath, "utf-8"));
33008
33223
  const assets = pkg.arc?.browserAssets;
33009
33224
  if (!Array.isArray(assets))
33010
33225
  return [];
@@ -33014,14 +33229,14 @@ function readBrowserAssets(pkgDir) {
33014
33229
  }
33015
33230
  }
33016
33231
  function discoverBrowserAssets(ws) {
33017
- const arcDir = join13(ws.rootDir, "node_modules", "@arcote.tech");
33018
- if (!existsSync11(arcDir))
33232
+ const arcDir = join14(ws.rootDir, "node_modules", "@arcote.tech");
33233
+ if (!existsSync12(arcDir))
33019
33234
  return [];
33020
33235
  const out = [];
33021
- for (const entry of readdirSync6(arcDir, { withFileTypes: true })) {
33236
+ for (const entry of readdirSync7(arcDir, { withFileTypes: true })) {
33022
33237
  if (!entry.isDirectory() && !entry.isSymbolicLink())
33023
33238
  continue;
33024
- const pkgDir = join13(arcDir, entry.name);
33239
+ const pkgDir = join14(arcDir, entry.name);
33025
33240
  const assets = readBrowserAssets(pkgDir);
33026
33241
  for (const asset of assets) {
33027
33242
  const src = resolveAssetSource(asset.from, pkgDir, ws.rootDir);
@@ -33046,7 +33261,7 @@ async function copyBrowserAssets(ws, cache, noCache) {
33046
33261
  to: a.to,
33047
33262
  mtime: mtimeOf(a.src)
33048
33263
  })));
33049
- const requiredOutputs = assets.map((a) => join13(ws.assetsDir, a.to));
33264
+ const requiredOutputs = assets.map((a) => join14(ws.assetsDir, a.to));
33050
33265
  if (!noCache && isCacheHit(cache, unitId, inputHash, requiredOutputs)) {
33051
33266
  console.log(` \u2713 cached: browser-assets (${assets.length})`);
33052
33267
  return;
@@ -33054,10 +33269,10 @@ async function copyBrowserAssets(ws, cache, noCache) {
33054
33269
  console.log(` building: browser-assets (${assets.length})`);
33055
33270
  const outputHashes = {};
33056
33271
  for (const asset of assets) {
33057
- const dest = join13(ws.assetsDir, asset.to);
33272
+ const dest = join14(ws.assetsDir, asset.to);
33058
33273
  mkdirSync10(dirname8(dest), { recursive: true });
33059
33274
  copyFileSync(asset.src, dest);
33060
- outputHashes[asset.to] = sha256Hex(readFileSync12(dest));
33275
+ outputHashes[asset.to] = sha256Hex(readFileSync13(dest));
33061
33276
  }
33062
33277
  updateCache(cache, unitId, inputHash, { outputHashes });
33063
33278
  }
@@ -33065,12 +33280,12 @@ async function loadServerContext(ws) {
33065
33280
  globalThis.ONLY_SERVER = true;
33066
33281
  globalThis.ONLY_BROWSER = false;
33067
33282
  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");
33283
+ const platformDir = join14(process.cwd(), "node_modules", "@arcote.tech", "platform");
33284
+ const platformPkg = JSON.parse(readFileSync13(join14(platformDir, "package.json"), "utf-8"));
33285
+ const platformEntry = join14(platformDir, platformPkg.main ?? "src/index.ts");
33071
33286
  await import(platformEntry);
33072
- const serverEntry = join13(ws.arcDir, "server", SERVER_ENTRY_FILE);
33073
- if (!existsSync11(serverEntry)) {
33287
+ const serverEntry = join14(ws.arcDir, "server", SERVER_ENTRY_FILE);
33288
+ if (!existsSync12(serverEntry)) {
33074
33289
  return { context: null, moduleAccess: new Map };
33075
33290
  }
33076
33291
  let serverError;
@@ -33100,21 +33315,21 @@ async function platformBuild(opts = {}) {
33100
33315
 
33101
33316
  // src/commands/platform-deploy.ts
33102
33317
  import { randomBytes } from "crypto";
33103
- import { existsSync as existsSync18, readFileSync as readFileSync16 } from "fs";
33104
- import { dirname as dirname11, join as join21 } from "path";
33318
+ import { existsSync as existsSync19, readFileSync as readFileSync17 } from "fs";
33319
+ import { dirname as dirname11, join as join22 } from "path";
33105
33320
  import { fileURLToPath as fileURLToPath8 } from "url";
33106
33321
 
33107
33322
  // src/deploy/bootstrap.ts
33108
33323
  var {spawn: spawn4 } = globalThis.Bun;
33109
33324
  import { mkdirSync as mkdirSync13, writeFileSync as writeFileSync14 } from "fs";
33110
33325
  import { tmpdir as tmpdir2 } from "os";
33111
- import { dirname as dirname9, join as join19 } from "path";
33326
+ import { dirname as dirname9, join as join20 } from "path";
33112
33327
 
33113
33328
  // src/deploy/ansible.ts
33114
33329
  import { spawn as nodeSpawn } from "child_process";
33115
- import { existsSync as existsSync12, mkdirSync as mkdirSync11, writeFileSync as writeFileSync11 } from "fs";
33330
+ import { existsSync as existsSync13, mkdirSync as mkdirSync11, writeFileSync as writeFileSync11 } from "fs";
33116
33331
  import { homedir, tmpdir } from "os";
33117
- import { join as join14 } from "path";
33332
+ import { join as join15 } from "path";
33118
33333
 
33119
33334
  // src/deploy/assets.ts
33120
33335
  var TERRAFORM_MAIN_TF = `terraform {
@@ -33428,28 +33643,28 @@ var ASSETS = {
33428
33643
  };
33429
33644
  async function materializeAssets(targetDir, files) {
33430
33645
  const { mkdirSync: mkdirSync11, writeFileSync: writeFileSync11 } = await import("fs");
33431
- const { join: join14 } = await import("path");
33646
+ const { join: join15 } = await import("path");
33432
33647
  mkdirSync11(targetDir, { recursive: true });
33433
33648
  for (const [name, content] of Object.entries(files)) {
33434
- writeFileSync11(join14(targetDir, name), content);
33649
+ writeFileSync11(join15(targetDir, name), content);
33435
33650
  }
33436
33651
  }
33437
33652
 
33438
33653
  // src/deploy/ansible.ts
33439
33654
  function pickSshKeyForAnsible(configured) {
33440
33655
  if (configured) {
33441
- const expanded = configured.startsWith("~") ? join14(homedir(), configured.slice(1)) : configured;
33442
- return existsSync12(expanded) ? expanded : null;
33656
+ const expanded = configured.startsWith("~") ? join15(homedir(), configured.slice(1)) : configured;
33657
+ return existsSync13(expanded) ? expanded : null;
33443
33658
  }
33444
33659
  for (const name of ["id_ed25519", "id_ecdsa", "id_rsa"]) {
33445
- const path4 = join14(homedir(), ".ssh", name);
33446
- if (existsSync12(path4))
33660
+ const path4 = join15(homedir(), ".ssh", name);
33661
+ if (existsSync13(path4))
33447
33662
  return path4;
33448
33663
  }
33449
33664
  return null;
33450
33665
  }
33451
33666
  async function runAnsible(inputs) {
33452
- const workDir = join14(tmpdir(), "arc-deploy", `ansible-${Date.now()}`);
33667
+ const workDir = join15(tmpdir(), "arc-deploy", `ansible-${Date.now()}`);
33453
33668
  mkdirSync11(workDir, { recursive: true });
33454
33669
  await materializeAssets(workDir, ASSETS.ansible);
33455
33670
  const user = inputs.asRoot ? "root" : inputs.target.user;
@@ -33466,7 +33681,7 @@ async function runAnsible(inputs) {
33466
33681
  ""
33467
33682
  ].join(`
33468
33683
  `);
33469
- writeFileSync11(join14(workDir, "inventory.ini"), inventory);
33684
+ writeFileSync11(join15(workDir, "inventory.ini"), inventory);
33470
33685
  const extraVarsJson = JSON.stringify({
33471
33686
  username: inputs.target.user,
33472
33687
  ssh_port: port,
@@ -35026,16 +35241,16 @@ function panelTimeseries(title, gridPos, query, legend, unit, datasource = PROME
35026
35241
  // src/deploy/terraform.ts
35027
35242
  import { spawn as nodeSpawn2 } from "child_process";
35028
35243
  import { createHash as createHash2 } from "crypto";
35029
- import { existsSync as existsSync13, mkdirSync as mkdirSync12, writeFileSync as writeFileSync12 } from "fs";
35244
+ import { existsSync as existsSync14, mkdirSync as mkdirSync12, writeFileSync as writeFileSync12 } from "fs";
35030
35245
  import { homedir as homedir2 } from "os";
35031
- import { join as join15 } from "path";
35246
+ import { join as join16 } from "path";
35032
35247
  async function runTerraform(inputs) {
35033
35248
  const wsHash = createHash2("sha256").update(inputs.workspaceDir).digest("hex").slice(0, 16);
35034
- const workDir = join15(homedir2(), ".arc-deploy", wsHash, "tf");
35249
+ const workDir = join16(homedir2(), ".arc-deploy", wsHash, "tf");
35035
35250
  mkdirSync12(workDir, { recursive: true });
35036
35251
  await materializeAssets(workDir, ASSETS.terraform);
35037
35252
  const sshPubKey = inputs.tf.sshPublicKey ?? expandHome("~/.ssh/id_ed25519.pub");
35038
- if (!existsSync13(expandHome(sshPubKey))) {
35253
+ if (!existsSync14(expandHome(sshPubKey))) {
35039
35254
  throw new Error(`SSH public key not found at ${sshPubKey}. Set provision.terraform.sshPublicKey in deploy.arc.json.`);
35040
35255
  }
35041
35256
  const tfvars = [
@@ -35049,7 +35264,7 @@ async function runTerraform(inputs) {
35049
35264
  ].join(`
35050
35265
  `) + `
35051
35266
  `;
35052
- writeFileSync12(join15(workDir, "terraform.tfvars"), tfvars);
35267
+ writeFileSync12(join16(workDir, "terraform.tfvars"), tfvars);
35053
35268
  await runTf(workDir, ["init", "-input=false", "-no-color"]);
35054
35269
  await runTf(workDir, [
35055
35270
  "apply",
@@ -35107,20 +35322,20 @@ function expandHome(p) {
35107
35322
  }
35108
35323
 
35109
35324
  // src/deploy/config.ts
35110
- import { existsSync as existsSync15, readFileSync as readFileSync14, writeFileSync as writeFileSync13 } from "fs";
35111
- import { join as join17 } from "path";
35325
+ import { existsSync as existsSync16, readFileSync as readFileSync15, writeFileSync as writeFileSync13 } from "fs";
35326
+ import { join as join18 } from "path";
35112
35327
 
35113
35328
  // src/deploy/env-file.ts
35114
- import { appendFileSync, existsSync as existsSync14, readFileSync as readFileSync13 } from "fs";
35115
- import { join as join16 } from "path";
35329
+ import { appendFileSync, existsSync as existsSync15, readFileSync as readFileSync14 } from "fs";
35330
+ import { join as join17 } from "path";
35116
35331
  function loadDeployEnvFiles(rootDir, envNames) {
35117
- const globalsPath = join16(rootDir, "deploy.arc.env");
35118
- const globals = existsSync14(globalsPath) ? parseEnvFile(readFileSync13(globalsPath, "utf-8"), globalsPath) : {};
35332
+ const globalsPath = join17(rootDir, "deploy.arc.env");
35333
+ const globals = existsSync15(globalsPath) ? parseEnvFile(readFileSync14(globalsPath, "utf-8"), globalsPath) : {};
35119
35334
  const perEnv = {};
35120
35335
  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);
35336
+ const envPath = join17(rootDir, `deploy.arc.${name}.env`);
35337
+ if (existsSync15(envPath)) {
35338
+ perEnv[name] = parseEnvFile(readFileSync14(envPath, "utf-8"), envPath);
35124
35339
  }
35125
35340
  }
35126
35341
  return { globals, perEnv };
@@ -35136,16 +35351,16 @@ function ensurePersistedSecret(rootDir, scope, key, generate) {
35136
35351
  if (process.env[key])
35137
35352
  return process.env[key];
35138
35353
  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);
35354
+ const path4 = join17(rootDir, fileName);
35355
+ if (existsSync15(path4)) {
35356
+ const existing = parseEnvFile(readFileSync14(path4, "utf-8"), path4);
35142
35357
  if (existing[key]) {
35143
35358
  process.env[key] = existing[key];
35144
35359
  return existing[key];
35145
35360
  }
35146
35361
  }
35147
35362
  const value = generate();
35148
- const prefix = existsSync14(path4) && !readFileSync13(path4, "utf-8").endsWith(`
35363
+ const prefix = existsSync15(path4) && !readFileSync14(path4, "utf-8").endsWith(`
35149
35364
  `) ? `
35150
35365
  ` : "";
35151
35366
  appendFileSync(path4, `${prefix}${key}=${value}
@@ -35181,17 +35396,17 @@ function parseEnvFile(content, pathForErrors) {
35181
35396
  // src/deploy/config.ts
35182
35397
  var DEPLOY_CONFIG_FILE = "deploy.arc.json";
35183
35398
  function deployConfigPath(rootDir) {
35184
- return join17(rootDir, DEPLOY_CONFIG_FILE);
35399
+ return join18(rootDir, DEPLOY_CONFIG_FILE);
35185
35400
  }
35186
35401
  function deployConfigExists(rootDir) {
35187
- return existsSync15(deployConfigPath(rootDir));
35402
+ return existsSync16(deployConfigPath(rootDir));
35188
35403
  }
35189
35404
  function loadDeployConfig(rootDir) {
35190
35405
  const path4 = deployConfigPath(rootDir);
35191
- if (!existsSync15(path4)) {
35406
+ if (!existsSync16(path4)) {
35192
35407
  throw new Error(`Missing ${DEPLOY_CONFIG_FILE} at ${path4}`);
35193
35408
  }
35194
- const raw = readFileSync14(path4, "utf-8");
35409
+ const raw = readFileSync15(path4, "utf-8");
35195
35410
  let parsed;
35196
35411
  try {
35197
35412
  parsed = JSON.parse(raw);
@@ -35214,7 +35429,7 @@ function loadDeployConfig(rootDir) {
35214
35429
  }
35215
35430
  function saveDeployConfig(rootDir, cfg) {
35216
35431
  const path4 = deployConfigPath(rootDir);
35217
- const raw = existsSync15(path4) ? JSON.parse(readFileSync14(path4, "utf-8")) : {};
35432
+ const raw = existsSync16(path4) ? JSON.parse(readFileSync15(path4, "utf-8")) : {};
35218
35433
  raw.target = { ...raw.target, ...cfg.target };
35219
35434
  writeFileSync13(path4, JSON.stringify(raw, null, 2) + `
35220
35435
  `);
@@ -35451,17 +35666,17 @@ function cfgErr(path4, expected) {
35451
35666
 
35452
35667
  // src/deploy/ssh.ts
35453
35668
  var {spawn: spawn3 } = globalThis.Bun;
35454
- import { existsSync as existsSync16 } from "fs";
35669
+ import { existsSync as existsSync17 } from "fs";
35455
35670
  import { homedir as homedir3 } from "os";
35456
- import { join as join18 } from "path";
35671
+ import { join as join19 } from "path";
35457
35672
  function pickSshKey(target) {
35458
35673
  if (target.sshKey) {
35459
- const expanded = target.sshKey.startsWith("~") ? join18(homedir3(), target.sshKey.slice(1)) : target.sshKey;
35460
- return existsSync16(expanded) ? expanded : null;
35674
+ const expanded = target.sshKey.startsWith("~") ? join19(homedir3(), target.sshKey.slice(1)) : target.sshKey;
35675
+ return existsSync17(expanded) ? expanded : null;
35461
35676
  }
35462
35677
  for (const name of ["id_ed25519", "id_ecdsa", "id_rsa"]) {
35463
- const path4 = join18(homedir3(), ".ssh", name);
35464
- if (existsSync16(path4))
35678
+ const path4 = join19(homedir3(), ".ssh", name);
35679
+ if (existsSync17(path4))
35465
35680
  return path4;
35466
35681
  }
35467
35682
  return null;
@@ -35476,7 +35691,7 @@ function sshMuxArgs() {
35476
35691
  "-o",
35477
35692
  "ControlMaster=auto",
35478
35693
  "-o",
35479
- `ControlPath=${join18(homedir3(), ".ssh", "cm-arc-%C")}`,
35694
+ `ControlPath=${join19(homedir3(), ".ssh", "cm-arc-%C")}`,
35480
35695
  "-o",
35481
35696
  "ControlPersist=120"
35482
35697
  ];
@@ -35747,7 +35962,7 @@ async function isRegistryRunning(cfg) {
35747
35962
  }
35748
35963
  async function upStack(inputs) {
35749
35964
  const { cfg } = inputs;
35750
- const workDir = join19(tmpdir2(), "arc-deploy", `stack-${Date.now()}`);
35965
+ const workDir = join20(tmpdir2(), "arc-deploy", `stack-${Date.now()}`);
35751
35966
  mkdirSync13(workDir, { recursive: true });
35752
35967
  await assertRegistryDnsResolves(cfg);
35753
35968
  const password = process.env[cfg.registry.passwordEnv];
@@ -35755,9 +35970,9 @@ async function upStack(inputs) {
35755
35970
  throw new Error(`Registry password env var ${cfg.registry.passwordEnv} is not set. ` + `Set it (e.g. \`export ${cfg.registry.passwordEnv}=...\`) before bootstrap.`);
35756
35971
  }
35757
35972
  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 }));
35973
+ writeFileSync14(join20(workDir, "htpasswd"), htpasswdLine);
35974
+ writeFileSync14(join20(workDir, "Caddyfile"), generateCaddyfile(cfg));
35975
+ writeFileSync14(join20(workDir, "docker-compose.yml"), generateCompose({ cfg }));
35761
35976
  let observabilityFiles = null;
35762
35977
  let observabilityHtpasswd = null;
35763
35978
  if (cfg.observability?.enabled) {
@@ -35769,30 +35984,30 @@ async function upStack(inputs) {
35769
35984
  }
35770
35985
  observabilityHtpasswd = await generateCaddyBasicAuthLine("admin", adminPassword);
35771
35986
  for (const [relPath, contents] of Object.entries(observabilityFiles)) {
35772
- const fullPath = join19(workDir, relPath);
35987
+ const fullPath = join20(workDir, relPath);
35773
35988
  mkdirSync13(dirname9(fullPath), { recursive: true });
35774
35989
  writeFileSync14(fullPath, contents);
35775
35990
  }
35776
- writeFileSync14(join19(workDir, "observability-htpasswd"), observabilityHtpasswd);
35991
+ writeFileSync14(join20(workDir, "observability-htpasswd"), observabilityHtpasswd);
35777
35992
  }
35778
35993
  await assertExec(cfg.target, `sudo mkdir -p ${cfg.target.remoteDir} && sudo chown ${cfg.target.user}:${cfg.target.user} ${cfg.target.remoteDir}`);
35779
35994
  for (const name of Object.keys(cfg.envs)) {
35780
35995
  await assertExec(cfg.target, `mkdir -p ${cfg.target.remoteDir}/${name}`);
35781
35996
  }
35782
35997
  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`);
35998
+ await scpUpload(cfg.target, join20(workDir, "Caddyfile"), `${cfg.target.remoteDir}/Caddyfile`);
35999
+ await scpUpload(cfg.target, join20(workDir, "docker-compose.yml"), `${cfg.target.remoteDir}/docker-compose.yml`);
36000
+ await scpUpload(cfg.target, join20(workDir, "htpasswd"), `${cfg.target.remoteDir}/registry-auth/htpasswd`);
35786
36001
  if (observabilityFiles && observabilityHtpasswd) {
35787
36002
  await assertExec(cfg.target, `mkdir -p ${cfg.target.remoteDir}/observability/grafana-dashboards ${cfg.target.remoteDir}/observability/grafana-alerting`);
35788
36003
  for (const relPath of Object.keys(observabilityFiles)) {
35789
- const localDir = dirname9(join19(workDir, relPath));
36004
+ const localDir = dirname9(join20(workDir, relPath));
35790
36005
  mkdirSync13(localDir, { recursive: true });
35791
36006
  }
35792
36007
  for (const relPath of Object.keys(observabilityFiles)) {
35793
- await scpUpload(cfg.target, join19(workDir, relPath), `${cfg.target.remoteDir}/${relPath}`);
36008
+ await scpUpload(cfg.target, join20(workDir, relPath), `${cfg.target.remoteDir}/${relPath}`);
35794
36009
  }
35795
- await scpUpload(cfg.target, join19(workDir, "observability-htpasswd"), `${cfg.target.remoteDir}/observability-htpasswd`);
36010
+ await scpUpload(cfg.target, join20(workDir, "observability-htpasswd"), `${cfg.target.remoteDir}/observability-htpasswd`);
35796
36011
  }
35797
36012
  await assertExec(cfg.target, `touch ${cfg.target.remoteDir}/.env`);
35798
36013
  if (cfg.observability?.enabled) {
@@ -35814,6 +36029,7 @@ async function upStack(inputs) {
35814
36029
  await writeEnvLine(cfg.target, `${cfg.target.remoteDir}/.env`, key, value);
35815
36030
  }
35816
36031
  await assertExec(cfg.target, `cd ${cfg.target.remoteDir} && docker compose pull --ignore-pull-failures caddy registry && docker compose up -d caddy registry`);
36032
+ await assertExec(cfg.target, `cd ${cfg.target.remoteDir} && docker compose restart caddy`);
35817
36033
  await sshDockerLogin(cfg);
35818
36034
  const knownEnvs = await listConfiguredEnvs(cfg);
35819
36035
  if (knownEnvs.length > 0) {
@@ -35947,14 +36163,14 @@ var {spawn: spawn5 } = globalThis.Bun;
35947
36163
  import { createHash as createHash3 } from "crypto";
35948
36164
  import {
35949
36165
  copyFileSync as copyFileSync2,
35950
- existsSync as existsSync17,
36166
+ existsSync as existsSync18,
35951
36167
  mkdirSync as mkdirSync14,
35952
- readFileSync as readFileSync15,
36168
+ readFileSync as readFileSync16,
35953
36169
  realpathSync as realpathSync2,
35954
36170
  writeFileSync as writeFileSync15
35955
36171
  } from "fs";
35956
36172
  import { tmpdir as tmpdir3 } from "os";
35957
- import { dirname as dirname10, join as join20 } from "path";
36173
+ import { dirname as dirname10, join as join21 } from "path";
35958
36174
  import { fileURLToPath as fileURLToPath7 } from "url";
35959
36175
 
35960
36176
  // src/deploy/image-template.ts
@@ -36004,8 +36220,8 @@ function generateDockerfile(inputs) {
36004
36220
  // src/deploy/image.ts
36005
36221
  async function buildImage(ws, opts) {
36006
36222
  await ensureDocker();
36007
- const manifestPath = join20(ws.arcDir, "manifest.json");
36008
- if (!existsSync17(manifestPath)) {
36223
+ const manifestPath = join21(ws.arcDir, "manifest.json");
36224
+ if (!existsSync18(manifestPath)) {
36009
36225
  throw new Error(`No build manifest at ${manifestPath}. Run \`arc platform build\` first or omit --skip-build.`);
36010
36226
  }
36011
36227
  embedCliBundle(ws);
@@ -36015,9 +36231,9 @@ async function buildImage(ws, opts) {
36015
36231
  const dockerfileInputs = collectDockerfileInputs(ws);
36016
36232
  const dockerfile = generateDockerfile(dockerfileInputs);
36017
36233
  const buildContextDir = ws.rootDir;
36018
- const dockerfileDir = join20(tmpdir3(), `arc-image-${Date.now()}`);
36234
+ const dockerfileDir = join21(tmpdir3(), `arc-image-${Date.now()}`);
36019
36235
  mkdirSync14(dockerfileDir, { recursive: true });
36020
- const dockerfilePath = join20(dockerfileDir, "Dockerfile");
36236
+ const dockerfilePath = join21(dockerfileDir, "Dockerfile");
36021
36237
  writeFileSync15(dockerfilePath, dockerfile);
36022
36238
  const buildArgs = [
36023
36239
  "build",
@@ -36043,20 +36259,20 @@ async function buildImage(ws, opts) {
36043
36259
  }
36044
36260
  function embedCliBundle(ws) {
36045
36261
  const source = locateCliBundle();
36046
- const target = join20(ws.arcDir, "host.js");
36262
+ const target = join21(ws.arcDir, "host.js");
36047
36263
  copyFileSync2(source, target);
36048
36264
  }
36049
36265
  function locateCliBundle() {
36050
36266
  const here = fileURLToPath7(import.meta.url);
36051
36267
  let cur = dirname10(here);
36052
36268
  while (cur !== "/" && cur !== "") {
36053
- const candidate = join20(cur, "package.json");
36054
- if (existsSync17(candidate)) {
36269
+ const candidate = join21(cur, "package.json");
36270
+ if (existsSync18(candidate)) {
36055
36271
  try {
36056
- const pkg = JSON.parse(readFileSync15(candidate, "utf-8"));
36272
+ const pkg = JSON.parse(readFileSync16(candidate, "utf-8"));
36057
36273
  if (pkg.name === "@arcote.tech/arc-cli") {
36058
- const distIndex = join20(realpathSync2(cur), "dist", "index.js");
36059
- if (!existsSync17(distIndex)) {
36274
+ const distIndex = join21(realpathSync2(cur), "dist", "index.js");
36275
+ if (!existsSync18(distIndex)) {
36060
36276
  throw new Error(`arc-cli bundle missing at ${distIndex}. Run \`bun run build\` in packages/cli/.`);
36061
36277
  }
36062
36278
  return distIndex;
@@ -36088,17 +36304,17 @@ async function ensureDocker() {
36088
36304
  }
36089
36305
  }
36090
36306
  function computeContentHash(manifestPath) {
36091
- const raw = JSON.parse(readFileSync15(manifestPath, "utf-8"));
36307
+ const raw = JSON.parse(readFileSync16(manifestPath, "utf-8"));
36092
36308
  delete raw.buildTime;
36093
36309
  const canonical = JSON.stringify(raw);
36094
36310
  return createHash3("sha256").update(canonical).digest("hex").slice(0, 12);
36095
36311
  }
36096
36312
  function collectDockerfileInputs(ws) {
36097
- const hasPublicDir = existsSync17(join20(ws.rootDir, "public"));
36098
- const hasLocales = existsSync17(join20(ws.rootDir, "locales"));
36313
+ const hasPublicDir = existsSync18(join21(ws.rootDir, "public"));
36314
+ const hasLocales = existsSync18(join21(ws.rootDir, "locales"));
36099
36315
  let manifestPath;
36100
36316
  for (const name of ["manifest.webmanifest", "manifest.json"]) {
36101
- if (existsSync17(join20(ws.rootDir, name))) {
36317
+ if (existsSync18(join21(ws.rootDir, name))) {
36102
36318
  manifestPath = name;
36103
36319
  break;
36104
36320
  }
@@ -36809,11 +37025,11 @@ async function runSurvey(appName) {
36809
37025
  });
36810
37026
  if (BD(serverType))
36811
37027
  cancel();
36812
- const location = await ue({
37028
+ const location2 = await ue({
36813
37029
  message: "Hetzner datacenter location",
36814
37030
  initialValue: "nbg1"
36815
37031
  });
36816
- if (BD(location))
37032
+ if (BD(location2))
36817
37033
  cancel();
36818
37034
  const firstEnv = Object.keys(envs)[0] ?? "host";
36819
37035
  const appSlug = sanitizeImageName(appName ?? "arc-app").replace(/[^a-z0-9-]+/g, "-");
@@ -36821,7 +37037,7 @@ async function runSurvey(appName) {
36821
37037
  const terraform = {
36822
37038
  provider: "hcloud",
36823
37039
  serverType,
36824
- location,
37040
+ location: location2,
36825
37041
  image: "ubuntu-22.04",
36826
37042
  tokenEnv,
36827
37043
  serverName,
@@ -36942,14 +37158,14 @@ async function platformDeploy(envArg, options = {}) {
36942
37158
  err(`Unknown env "${envArg}". Known: ${Object.keys(cfg.envs).join(", ")}`);
36943
37159
  process.exit(1);
36944
37160
  })() : Object.keys(cfg.envs);
36945
- const manifestPath = join21(ws.arcDir, "manifest.json");
37161
+ const manifestPath = join22(ws.arcDir, "manifest.json");
36946
37162
  if (!options.imageTag) {
36947
- const needBuild = options.rebuild || !existsSync18(manifestPath);
37163
+ const needBuild = options.rebuild || !existsSync19(manifestPath);
36948
37164
  if (needBuild && !options.skipBuild) {
36949
37165
  log2("Building platform...");
36950
37166
  await buildAll(ws, { noCache: options.rebuild });
36951
37167
  ok("Build complete");
36952
- } else if (!existsSync18(manifestPath)) {
37168
+ } else if (!existsSync19(manifestPath)) {
36953
37169
  err("No build found and --skip-build was set.");
36954
37170
  process.exit(1);
36955
37171
  }
@@ -37019,9 +37235,9 @@ function readCliVersion2() {
37019
37235
  let cur = dirname11(fileURLToPath8(import.meta.url));
37020
37236
  const root = dirname11(cur).startsWith("/") ? "/" : ".";
37021
37237
  while (cur !== root && cur !== "") {
37022
- const candidate = join21(cur, "package.json");
37023
- if (existsSync18(candidate)) {
37024
- const pkg = JSON.parse(readFileSync16(candidate, "utf-8"));
37238
+ const candidate = join22(cur, "package.json");
37239
+ if (existsSync19(candidate)) {
37240
+ const pkg = JSON.parse(readFileSync17(candidate, "utf-8"));
37025
37241
  if (pkg.name === "@arcote.tech/arc-cli") {
37026
37242
  return pkg.version ?? "unknown";
37027
37243
  }
@@ -37037,8 +37253,8 @@ function readCliVersion2() {
37037
37253
  }
37038
37254
  }
37039
37255
  async function hashDeployConfig(rootDir) {
37040
- const p2 = join21(rootDir, "deploy.arc.json");
37041
- const content = readFileSync16(p2);
37256
+ const p2 = join22(rootDir, "deploy.arc.json");
37257
+ const content = readFileSync17(p2);
37042
37258
  const hasher = new Bun.CryptoHasher("sha256");
37043
37259
  hasher.update(content);
37044
37260
  hasher.update(readCliVersion2());
@@ -37047,8 +37263,8 @@ async function hashDeployConfig(rootDir) {
37047
37263
 
37048
37264
  // src/platform/startup.ts
37049
37265
  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";
37266
+ import { existsSync as existsSync21, mkdirSync as mkdirSync16, readFileSync as readFileSync19, watch, writeFileSync as writeFileSync16 } from "fs";
37267
+ import { join as join24 } from "path";
37052
37268
 
37053
37269
  // ../host/src/connection-manager.ts
37054
37270
  class ConnectionManager {
@@ -38677,8 +38893,8 @@ async function createArcServer(config) {
38677
38893
  // src/platform/server.ts
38678
38894
  init_i18n();
38679
38895
  import { timingSafeEqual } from "crypto";
38680
- import { existsSync as existsSync19, mkdirSync as mkdirSync15 } from "fs";
38681
- import { join as join22 } from "path";
38896
+ import { existsSync as existsSync20, mkdirSync as mkdirSync15, readFileSync as readFileSync18 } from "fs";
38897
+ import { join as join23 } from "path";
38682
38898
  async function initContextHandler(context2, dbPath) {
38683
38899
  const factory = await resolveDbAdapterFactory(dbPath);
38684
38900
  const dbAdapter = factory(context2);
@@ -38698,7 +38914,61 @@ async function resolveDbAdapterFactory(dbPath) {
38698
38914
  mkdirSync15(dbDir, { recursive: true });
38699
38915
  return createBunSQLiteAdapterFactory2(dbPath);
38700
38916
  }
38701
- function generateShellHtml(appName, manifest, initial, stylesHash, shell) {
38917
+ function inlineJson(value) {
38918
+ return JSON.stringify(value).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/[\u2028\u2029]/g, (c2) => `\\u${c2.charCodeAt(0).toString(16)}`);
38919
+ }
38920
+ function tokenPayloadsFromCookies(cookieHeader) {
38921
+ if (!cookieHeader)
38922
+ return [];
38923
+ const payloads = [];
38924
+ for (const part of cookieHeader.split(";")) {
38925
+ const eq = part.indexOf("=");
38926
+ if (eq < 0)
38927
+ continue;
38928
+ const name = part.slice(0, eq).trim();
38929
+ if (name !== "arc_token" && !name.startsWith("arc_token_"))
38930
+ continue;
38931
+ const payload = decodeTokenPayload(decodeURIComponent(part.slice(eq + 1).trim()));
38932
+ if (payload)
38933
+ payloads.push(payload);
38934
+ }
38935
+ return payloads;
38936
+ }
38937
+ function pickLocale(cookieHeader, acceptLanguage, locales, sourceLocale) {
38938
+ const fromCookie = cookieHeader?.match(/(?:^|;)\s*arc-locale=([^;]+)/)?.[1];
38939
+ if (fromCookie && locales.includes(decodeURIComponent(fromCookie))) {
38940
+ return decodeURIComponent(fromCookie);
38941
+ }
38942
+ for (const tag of (acceptLanguage ?? "").split(",")) {
38943
+ const lang = tag.split(";")[0].trim();
38944
+ if (!lang)
38945
+ continue;
38946
+ const exact = locales.find((l2) => l2.toLowerCase() === lang.toLowerCase());
38947
+ if (exact)
38948
+ return exact;
38949
+ const prefix = locales.find((l2) => l2.toLowerCase().split("-")[0] === lang.toLowerCase().split("-")[0]);
38950
+ if (prefix)
38951
+ return prefix;
38952
+ }
38953
+ return sourceLocale;
38954
+ }
38955
+ async function generateShellHtml(opts) {
38956
+ const {
38957
+ appName,
38958
+ appManifest,
38959
+ buildManifest,
38960
+ moduleAccessMap,
38961
+ arcDir,
38962
+ rootDir,
38963
+ cookieHeader,
38964
+ acceptLanguage
38965
+ } = opts;
38966
+ if (!buildManifest?.initial) {
38967
+ throw new Error("generateShellHtml: initial bundle missing from manifest");
38968
+ }
38969
+ const initial = buildManifest.initial;
38970
+ const initialUrl = `/browser/${initial.file}`;
38971
+ const shell = buildManifest.shell;
38702
38972
  const otelConfig = process.env.ARC_OTEL_ENABLED === "true" ? {
38703
38973
  enabled: true,
38704
38974
  endpoint: "/otel",
@@ -38707,26 +38977,58 @@ function generateShellHtml(appName, manifest, initial, stylesHash, shell) {
38707
38977
  sampleRate: Number(process.env.ARC_OTEL_BROWSER_SAMPLE_RATE ?? "0.1")
38708
38978
  } : null;
38709
38979
  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
- }
38980
+ <script>window.__ARC_OTEL_CONFIG=${inlineJson(otelConfig)};</script>` : "";
38715
38981
  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)}` : "";
38982
+ <script type="importmap">${inlineJson({ imports: shell.imports })}</script>
38983
+ <script>window.__ARC_PEERS__=${inlineJson(shell.peers)};</script>` : "";
38984
+ const stylesQs = buildManifest.stylesHash ? `?v=${buildManifest.stylesHash.slice(0, 16)}` : "";
38985
+ const tokenPayloads = tokenPayloadsFromCookies(cookieHeader);
38986
+ const filtered = await filterManifestForTokens(buildManifest, moduleAccessMap, tokenPayloads);
38987
+ const preloadUrls = new Set;
38988
+ preloadUrls.add(initialUrl);
38989
+ for (const c2 of initial.staticChunks ?? [])
38990
+ preloadUrls.add(`/browser/${c2}`);
38991
+ for (const group of Object.values(filtered.groups)) {
38992
+ if (group.url)
38993
+ preloadUrls.add(group.url);
38994
+ for (const c2 of group.staticChunks ?? [])
38995
+ preloadUrls.add(`/browser/${c2}`);
38996
+ }
38997
+ const preloadTags = [...preloadUrls].map((u2) => `
38998
+ <link rel="modulepreload" href="${u2}" />`).join("");
38999
+ const manifestTag = `
39000
+ <script>window.__ARC_MANIFEST__=${inlineJson({
39001
+ initial: filtered.initial,
39002
+ groups: filtered.groups,
39003
+ sharedChunks: filtered.sharedChunks,
39004
+ stylesHash: filtered.stylesHash,
39005
+ buildTime: filtered.buildTime
39006
+ })};</script>`;
39007
+ let lang = "en";
39008
+ const tconfig = readTranslationsConfig(rootDir);
39009
+ let messages2 = {};
39010
+ if (tconfig) {
39011
+ lang = pickLocale(cookieHeader, acceptLanguage, tconfig.locales, tconfig.sourceLocale);
39012
+ try {
39013
+ messages2 = JSON.parse(readFileSync18(join23(arcDir, "locales", `${lang}.json`), "utf-8"));
39014
+ } catch {}
39015
+ }
39016
+ const i18nTag = `
39017
+ <script>window.__ARC_I18N__=${inlineJson({
39018
+ locale: lang,
39019
+ config: tconfig,
39020
+ messages: messages2
39021
+ })};</script>`;
38719
39022
  return `<!doctype html>
38720
- <html lang="en">
39023
+ <html lang="${lang}">
38721
39024
  <head>
38722
39025
  <meta charset="UTF-8" />
38723
39026
  <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 ? `
39027
+ <title>${appManifest?.title ?? appName}</title>${appManifest?.favicon ? `
39028
+ <link rel="icon" href="${appManifest.favicon}">` : ""}${appManifest ? `
38726
39029
  <link rel="manifest" href="/manifest.json${stylesQs}">` : ""}
38727
39030
  <link rel="stylesheet" href="/styles.css${stylesQs}" />
38728
- <link rel="stylesheet" href="/theme.css${stylesQs}" />${importMapTag}
38729
- <link rel="modulepreload" href="${initialUrl}" />${otelTag}
39031
+ <link rel="stylesheet" href="/theme.css${stylesQs}" />${importMapTag}${preloadTags}${manifestTag}${i18nTag}${otelTag}
38730
39032
  </head>
38731
39033
  <body>
38732
39034
  <div id="root"></div>
@@ -38757,7 +39059,7 @@ function getMime(path4) {
38757
39059
  return MIME[ext2] ?? "application/octet-stream";
38758
39060
  }
38759
39061
  function serveFile(filePath, headers = {}) {
38760
- if (!existsSync19(filePath))
39062
+ if (!existsSync20(filePath))
38761
39063
  return new Response("Not Found", { status: 404 });
38762
39064
  return new Response(Bun.file(filePath), {
38763
39065
  headers: { "Content-Type": getMime(filePath), ...headers }
@@ -38879,7 +39181,7 @@ function staticFilesHandler(ws, devMode, getManifest) {
38879
39181
  return new Response("Forbidden", { status: 403, headers: ctx.corsHeaders });
38880
39182
  }
38881
39183
  }
38882
- return serveFile(join22(ws.browserDir, file), {
39184
+ return serveFile(join23(ws.browserDir, file), {
38883
39185
  ...ctx.corsHeaders,
38884
39186
  "Cache-Control": devMode ? "no-cache" : "max-age=31536000,immutable"
38885
39187
  });
@@ -38889,7 +39191,7 @@ function staticFilesHandler(ws, devMode, getManifest) {
38889
39191
  if (!BROWSER_FILE_RE.test(file)) {
38890
39192
  return new Response("Not Found", { status: 404, headers: ctx.corsHeaders });
38891
39193
  }
38892
- return serveFile(join22(ws.arcDir, "shell", file), {
39194
+ return serveFile(join23(ws.arcDir, "shell", file), {
38893
39195
  ...ctx.corsHeaders,
38894
39196
  "Cross-Origin-Resource-Policy": "cross-origin",
38895
39197
  "Cache-Control": devMode ? "no-cache" : "max-age=31536000,immutable"
@@ -38908,29 +39210,29 @@ function staticFilesHandler(ws, devMode, getManifest) {
38908
39210
  return new Response("Forbidden", { status: 403, headers: ctx.corsHeaders });
38909
39211
  }
38910
39212
  }
38911
- return serveFile(join22(ws.arcDir, "browser-fed", file), {
39213
+ return serveFile(join23(ws.arcDir, "browser-fed", file), {
38912
39214
  ...ctx.corsHeaders,
38913
39215
  "Cross-Origin-Resource-Policy": "cross-origin",
38914
39216
  "Cache-Control": devMode ? "no-cache" : "max-age=31536000,immutable"
38915
39217
  });
38916
39218
  }
38917
39219
  if (path4.startsWith("/locales/"))
38918
- return serveFile(join22(ws.arcDir, path4.slice(1)), {
39220
+ return serveFile(join23(ws.arcDir, path4.slice(1)), {
38919
39221
  ...ctx.corsHeaders,
38920
39222
  "Cache-Control": devMode ? "no-cache" : "max-age=300,stale-while-revalidate=3600"
38921
39223
  });
38922
39224
  if (path4.startsWith("/assets/"))
38923
- return serveFile(join22(ws.assetsDir, path4.slice(8)), {
39225
+ return serveFile(join23(ws.assetsDir, path4.slice(8)), {
38924
39226
  ...ctx.corsHeaders,
38925
39227
  "Cache-Control": devMode ? "no-cache" : "max-age=31536000,immutable"
38926
39228
  });
38927
39229
  if (path4 === "/styles.css")
38928
- return serveFile(join22(ws.arcDir, "styles.css"), {
39230
+ return serveFile(join23(ws.arcDir, "styles.css"), {
38929
39231
  ...ctx.corsHeaders,
38930
39232
  "Cache-Control": devMode ? "no-cache" : "max-age=31536000,immutable"
38931
39233
  });
38932
39234
  if (path4 === "/theme.css")
38933
- return serveFile(join22(ws.arcDir, "theme.css"), {
39235
+ return serveFile(join23(ws.arcDir, "theme.css"), {
38934
39236
  ...ctx.corsHeaders,
38935
39237
  "Cache-Control": devMode ? "no-cache" : "max-age=31536000,immutable"
38936
39238
  });
@@ -38941,8 +39243,8 @@ function staticFilesHandler(ws, devMode, getManifest) {
38941
39243
  });
38942
39244
  }
38943
39245
  if (path4.lastIndexOf(".") > path4.lastIndexOf("/")) {
38944
- const publicFile = join22(ws.publicDir, path4.slice(1));
38945
- if (existsSync19(publicFile))
39246
+ const publicFile = join23(ws.publicDir, path4.slice(1));
39247
+ if (existsSync20(publicFile))
38946
39248
  return serveFile(publicFile, ctx.corsHeaders);
38947
39249
  }
38948
39250
  return null;
@@ -39142,12 +39444,13 @@ function headlessFallbackHandler(ws, getManifest) {
39142
39444
  };
39143
39445
  }
39144
39446
  function spaFallbackHandler(getShellHtml) {
39145
- return (_req, _url, ctx) => {
39146
- return new Response(getShellHtml(), {
39447
+ return async (req, _url, ctx) => {
39448
+ return new Response(await getShellHtml(req), {
39147
39449
  headers: {
39148
39450
  ...ctx.corsHeaders,
39149
39451
  "Content-Type": "text/html",
39150
- "Cache-Control": "no-cache, must-revalidate"
39452
+ "Cache-Control": "no-cache, must-revalidate, private",
39453
+ Vary: "Cookie, Accept-Language"
39151
39454
  }
39152
39455
  });
39153
39456
  };
@@ -39188,7 +39491,16 @@ async function startPlatformServer(opts) {
39188
39491
  mapUrl = u2;
39189
39492
  };
39190
39493
  const getMapUrl = () => mapUrl;
39191
- const getShellHtml = () => generateShellHtml(ws.appName, ws.manifest, manifest?.initial, manifest?.stylesHash, manifest?.shell);
39494
+ const getShellHtml = (req) => generateShellHtml({
39495
+ appName: ws.appName,
39496
+ appManifest: ws.manifest,
39497
+ buildManifest: manifest,
39498
+ moduleAccessMap,
39499
+ arcDir: ws.arcDir,
39500
+ rootDir: ws.rootDir,
39501
+ cookieHeader: req.headers.get("Cookie"),
39502
+ acceptLanguage: req.headers.get("Accept-Language")
39503
+ });
39192
39504
  const sseClients = new Set;
39193
39505
  const fallbackHandler = opts.headless ? headlessFallbackHandler(ws, getManifest) : spaFallbackHandler(getShellHtml);
39194
39506
  const notifyReload = (m4) => {
@@ -39252,7 +39564,7 @@ async function startPlatformServer(opts) {
39252
39564
  stop: () => server.stop()
39253
39565
  };
39254
39566
  }
39255
- const dbPath = opts.dbPath || join22(ws.arcDir, "data", "arc.db");
39567
+ const dbPath = opts.dbPath || join23(ws.arcDir, "data", "arc.db");
39256
39568
  const baseDbFactory = await resolveDbAdapterFactory(dbPath);
39257
39569
  let dbAdapterFactory = baseDbFactory;
39258
39570
  if (telemetry) {
@@ -39297,17 +39609,17 @@ async function startPlatformServer(opts) {
39297
39609
  async function startPlatform(opts) {
39298
39610
  const { ws, devMode } = opts;
39299
39611
  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");
39612
+ const dbPath = opts.dbPath ?? join24(ws.rootDir, ".arc", "data", devMode ? "dev.db" : "prod.db");
39301
39613
  let manifest;
39302
39614
  if (devMode) {
39303
39615
  manifest = await buildAll(ws, { minify: false });
39304
39616
  } else {
39305
- const manifestPath = join23(ws.arcDir, "manifest.json");
39306
- if (!existsSync20(manifestPath)) {
39617
+ const manifestPath = join24(ws.arcDir, "manifest.json");
39618
+ if (!existsSync21(manifestPath)) {
39307
39619
  err("No build found. Run `arc platform build` first.");
39308
39620
  process.exit(1);
39309
39621
  }
39310
- manifest = JSON.parse(readFileSync17(manifestPath, "utf-8"));
39622
+ manifest = JSON.parse(readFileSync19(manifestPath, "utf-8"));
39311
39623
  }
39312
39624
  assertProdFederationSecrets(devMode, !!manifest.federation);
39313
39625
  const needsPairing = !!manifest.federation || devMode && (opts.map || opts.headless);
@@ -39391,8 +39703,8 @@ async function startMapTool(ws, port, authToken, platformServer, platform3) {
39391
39703
  try {
39392
39704
  const { startMapServer, MAP_SCHEMA_VERSION } = await import("@arcote.tech/arc-map");
39393
39705
  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;
39706
+ const globs = ws.packages.map((p3) => join24(p3.path, "src", "**", "*.{ts,tsx}"));
39707
+ const packageOf = (absFile) => ws.packages.find((p3) => absFile.startsWith(join24(p3.path, "src")))?.name;
39396
39708
  const meta = readAppMeta(ws.rootDir, MAP_SCHEMA_VERSION);
39397
39709
  const map = await startMapServer({
39398
39710
  getContext: () => getContext(),
@@ -39427,15 +39739,15 @@ function resolveAppSecret(rootDir) {
39427
39739
  const fromEnv = process.env.ARC_APP_SECRET;
39428
39740
  if (fromEnv)
39429
39741
  return fromEnv;
39430
- const file = join23(rootDir, ".arc", "app-secret");
39742
+ const file = join24(rootDir, ".arc", "app-secret");
39431
39743
  try {
39432
- const saved = readFileSync17(file, "utf-8").trim();
39744
+ const saved = readFileSync19(file, "utf-8").trim();
39433
39745
  if (saved)
39434
39746
  return saved;
39435
39747
  } catch {}
39436
39748
  const secret = randomBytes2(32).toString("base64url");
39437
39749
  try {
39438
- mkdirSync16(join23(rootDir, ".arc"), { recursive: true });
39750
+ mkdirSync16(join24(rootDir, ".arc"), { recursive: true });
39439
39751
  writeFileSync16(file, secret, { mode: 384 });
39440
39752
  } catch (e2) {
39441
39753
  err(`App secret not persisted (${e2.message}) \u2014 hosts will need re-install after restart`);
@@ -39446,15 +39758,15 @@ function resolvePairingToken(rootDir) {
39446
39758
  const fromEnv = process.env.ARC_PAIRING_TOKEN || process.env.ARC_MAP_TOKEN;
39447
39759
  if (fromEnv)
39448
39760
  return fromEnv;
39449
- const file = join23(rootDir, ".arc", "pairing-token");
39761
+ const file = join24(rootDir, ".arc", "pairing-token");
39450
39762
  try {
39451
- const saved = readFileSync17(file, "utf-8").trim();
39763
+ const saved = readFileSync19(file, "utf-8").trim();
39452
39764
  if (saved)
39453
39765
  return saved;
39454
39766
  } catch {}
39455
39767
  const token = randomBytes2(16).toString("base64url");
39456
39768
  try {
39457
- mkdirSync16(join23(rootDir, ".arc"), { recursive: true });
39769
+ mkdirSync16(join24(rootDir, ".arc"), { recursive: true });
39458
39770
  writeFileSync16(file, token, { mode: 384 });
39459
39771
  } catch (e2) {
39460
39772
  err(`Pairing token not persisted (${e2.message}) \u2014 it will change on restart`);
@@ -39463,7 +39775,7 @@ function resolvePairingToken(rootDir) {
39463
39775
  }
39464
39776
  function readAppMeta(rootDir, schemaVersion) {
39465
39777
  try {
39466
- const pkg = JSON.parse(readFileSync17(join23(rootDir, "package.json"), "utf-8"));
39778
+ const pkg = JSON.parse(readFileSync19(join24(rootDir, "package.json"), "utf-8"));
39467
39779
  return {
39468
39780
  schemaVersion,
39469
39781
  name: pkg.name ?? rootDir.split("/").pop() ?? "arc-app",
@@ -39499,8 +39811,8 @@ function attachDevWatcher(ws, platform3, onReload) {
39499
39811
  }, 300);
39500
39812
  };
39501
39813
  for (const pkg of ws.packages) {
39502
- const srcDir = join23(pkg.path, "src");
39503
- if (!existsSync20(srcDir))
39814
+ const srcDir = join24(pkg.path, "src");
39815
+ if (!existsSync21(srcDir))
39504
39816
  continue;
39505
39817
  watch(srcDir, { recursive: true }, (_event, filename) => {
39506
39818
  if (!filename || filename.includes(".arc") || filename.endsWith(".d.ts") || filename.includes("node_modules") || filename.includes("dist"))
@@ -39510,8 +39822,8 @@ function attachDevWatcher(ws, platform3, onReload) {
39510
39822
  triggerRebuild();
39511
39823
  });
39512
39824
  }
39513
- const localesDir = join23(ws.rootDir, "locales");
39514
- if (existsSync20(localesDir)) {
39825
+ const localesDir = join24(ws.rootDir, "locales");
39826
+ if (existsSync21(localesDir)) {
39515
39827
  watch(localesDir, { recursive: false }, (_event, filename) => {
39516
39828
  if (!filename?.endsWith(".po"))
39517
39829
  return;
@@ -39533,7 +39845,7 @@ async function platformDev(opts = {}) {
39533
39845
 
39534
39846
  // src/commands/platform-pairing-token.ts
39535
39847
  import { randomBytes as randomBytes3 } from "crypto";
39536
- import { join as join24 } from "path";
39848
+ import { join as join25 } from "path";
39537
39849
  async function platformPairingToken() {
39538
39850
  const ws = resolveWorkspace();
39539
39851
  const { context: context2 } = await loadServerContext(ws);
@@ -39542,7 +39854,7 @@ async function platformPairingToken() {
39542
39854
  process.exit(1);
39543
39855
  }
39544
39856
  const isProd = false;
39545
- const dbPath = join24(ws.rootDir, ".arc", "data", isProd ? "prod.db" : "dev.db");
39857
+ const dbPath = join25(ws.rootDir, ".arc", "data", isProd ? "prod.db" : "dev.db");
39546
39858
  const handler = await initContextHandler(context2, dbPath);
39547
39859
  const code = randomBytes3(24).toString("base64url");
39548
39860
  const res = await handler.executeCommand("pairingCode.issue", { code }, null, { internal: true });