@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 +610 -298
- package/package.json +10 -10
- package/src/builder/module-builder.ts +61 -7
- package/src/builder/seed-guard.ts +143 -0
- package/src/deploy/bootstrap.ts +13 -0
- package/src/platform/server.ts +190 -52
- package/src/platform/shared.ts +8 -2
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
|
|
10195
|
-
return typeof
|
|
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
|
-
|
|
10212
|
-
return this.namespace ? `${
|
|
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
|
-
|
|
10218
|
-
|
|
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
|
-
|
|
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
|
-
|
|
10242
|
-
|
|
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
|
-
|
|
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
|
-
|
|
10256
|
-
|
|
10257
|
-
|
|
10258
|
-
|
|
10259
|
-
|
|
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
|
-
|
|
10265
|
-
|
|
10266
|
-
|
|
10267
|
-
|
|
10268
|
-
|
|
10269
|
-
|
|
10270
|
-
|
|
10271
|
-
|
|
10272
|
-
|
|
10273
|
-
|
|
10274
|
-
|
|
10275
|
-
|
|
10276
|
-
|
|
10277
|
-
|
|
10278
|
-
|
|
10279
|
-
}
|
|
10280
|
-
|
|
10281
|
-
|
|
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
|
-
|
|
10316
|
-
|
|
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,
|
|
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
|
|
17842
|
-
return typeof
|
|
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
|
-
|
|
17859
|
-
return this.namespace ? `${
|
|
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
|
-
|
|
17865
|
-
|
|
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
|
-
|
|
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
|
-
|
|
17889
|
-
|
|
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
|
-
|
|
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
|
-
|
|
17903
|
-
|
|
17904
|
-
|
|
17905
|
-
|
|
17906
|
-
|
|
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
|
-
|
|
17912
|
-
|
|
17913
|
-
|
|
17914
|
-
|
|
17915
|
-
|
|
17916
|
-
|
|
17917
|
-
|
|
17918
|
-
|
|
17919
|
-
|
|
17920
|
-
|
|
17921
|
-
|
|
17922
|
-
|
|
17923
|
-
|
|
17924
|
-
|
|
17925
|
-
|
|
17926
|
-
}
|
|
17927
|
-
|
|
17928
|
-
|
|
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
|
-
|
|
17963
|
-
|
|
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,
|
|
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
|
|
31326
|
-
import { dirname as dirname8, join as
|
|
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 =
|
|
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:
|
|
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
|
|
32634
|
-
import { basename as basename4, join as
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(
|
|
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(
|
|
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
|
|
32737
|
-
import { basename as basename5, dirname as dirname7, join as
|
|
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(
|
|
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 =
|
|
32761
|
-
if (
|
|
32974
|
+
const rootPkgPath = join13(rootDir, "package.json");
|
|
32975
|
+
if (existsSync11(rootPkgPath)) {
|
|
32762
32976
|
try {
|
|
32763
|
-
const rootPkg = JSON.parse(
|
|
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 =
|
|
32989
|
+
const manifestPath = join13(arcDir, "package.json");
|
|
32776
32990
|
writeFileSync9(manifestPath, JSON.stringify(manifest, null, 2) + `
|
|
32777
32991
|
`);
|
|
32778
|
-
const hash = sha256Hex2(
|
|
32779
|
-
writeFileSync9(
|
|
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(
|
|
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(
|
|
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(
|
|
33060
|
+
const rootPkg = JSON.parse(readFileSync13(packageJsonPath, "utf-8"));
|
|
32847
33061
|
const appName = rootPkg.name ?? "Arc App";
|
|
32848
|
-
const arcDir =
|
|
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 =
|
|
32859
|
-
if (
|
|
33072
|
+
const manifestPath = join14(rootDir, name);
|
|
33073
|
+
if (existsSync12(manifestPath)) {
|
|
32860
33074
|
try {
|
|
32861
|
-
const data = JSON.parse(
|
|
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:
|
|
32881
|
-
assetsDir:
|
|
32882
|
-
publicDir:
|
|
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 =
|
|
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,
|
|
33113
|
+
const accessMap = await extractAccessMap(ws.rootDir, join14(serverDir, serverEntry));
|
|
32899
33114
|
mkdirSync10(ws.arcDir, { recursive: true });
|
|
32900
|
-
writeFileSync10(
|
|
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,
|
|
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,
|
|
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(
|
|
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 =
|
|
32980
|
-
return
|
|
33194
|
+
const resolved = join14(pkgDir, from);
|
|
33195
|
+
return existsSync12(resolved) ? resolved : null;
|
|
32981
33196
|
}
|
|
32982
33197
|
const candidates = [
|
|
32983
|
-
|
|
32984
|
-
|
|
33198
|
+
join14(rootDir, "node_modules", from),
|
|
33199
|
+
join14(pkgDir, "node_modules", from)
|
|
32985
33200
|
];
|
|
32986
33201
|
for (const c of candidates) {
|
|
32987
|
-
if (
|
|
33202
|
+
if (existsSync12(c))
|
|
32988
33203
|
return c;
|
|
32989
33204
|
}
|
|
32990
|
-
const bunCacheDir =
|
|
32991
|
-
if (
|
|
32992
|
-
for (const entry of
|
|
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 =
|
|
32996
|
-
if (
|
|
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 =
|
|
33004
|
-
if (!
|
|
33218
|
+
const pkgJsonPath = join14(pkgDir, "package.json");
|
|
33219
|
+
if (!existsSync12(pkgJsonPath))
|
|
33005
33220
|
return [];
|
|
33006
33221
|
try {
|
|
33007
|
-
const pkg = JSON.parse(
|
|
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 =
|
|
33018
|
-
if (!
|
|
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
|
|
33236
|
+
for (const entry of readdirSync7(arcDir, { withFileTypes: true })) {
|
|
33022
33237
|
if (!entry.isDirectory() && !entry.isSymbolicLink())
|
|
33023
33238
|
continue;
|
|
33024
|
-
const pkgDir =
|
|
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) =>
|
|
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 =
|
|
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(
|
|
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 =
|
|
33069
|
-
const platformPkg = JSON.parse(
|
|
33070
|
-
const platformEntry =
|
|
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 =
|
|
33073
|
-
if (!
|
|
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
|
|
33104
|
-
import { dirname as dirname11, join as
|
|
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
|
|
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
|
|
33330
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync11, writeFileSync as writeFileSync11 } from "fs";
|
|
33116
33331
|
import { homedir, tmpdir } from "os";
|
|
33117
|
-
import { join as
|
|
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:
|
|
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(
|
|
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("~") ?
|
|
33442
|
-
return
|
|
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 =
|
|
33446
|
-
if (
|
|
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 =
|
|
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(
|
|
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
|
|
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
|
|
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 =
|
|
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 (!
|
|
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(
|
|
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
|
|
35111
|
-
import { join as
|
|
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
|
|
35115
|
-
import { join as
|
|
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 =
|
|
35118
|
-
const globals =
|
|
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 =
|
|
35122
|
-
if (
|
|
35123
|
-
perEnv[name] = parseEnvFile(
|
|
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 =
|
|
35140
|
-
if (
|
|
35141
|
-
const existing = parseEnvFile(
|
|
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 =
|
|
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
|
|
35399
|
+
return join18(rootDir, DEPLOY_CONFIG_FILE);
|
|
35185
35400
|
}
|
|
35186
35401
|
function deployConfigExists(rootDir) {
|
|
35187
|
-
return
|
|
35402
|
+
return existsSync16(deployConfigPath(rootDir));
|
|
35188
35403
|
}
|
|
35189
35404
|
function loadDeployConfig(rootDir) {
|
|
35190
35405
|
const path4 = deployConfigPath(rootDir);
|
|
35191
|
-
if (!
|
|
35406
|
+
if (!existsSync16(path4)) {
|
|
35192
35407
|
throw new Error(`Missing ${DEPLOY_CONFIG_FILE} at ${path4}`);
|
|
35193
35408
|
}
|
|
35194
|
-
const raw =
|
|
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 =
|
|
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
|
|
35669
|
+
import { existsSync as existsSync17 } from "fs";
|
|
35455
35670
|
import { homedir as homedir3 } from "os";
|
|
35456
|
-
import { join as
|
|
35671
|
+
import { join as join19 } from "path";
|
|
35457
35672
|
function pickSshKey(target) {
|
|
35458
35673
|
if (target.sshKey) {
|
|
35459
|
-
const expanded = target.sshKey.startsWith("~") ?
|
|
35460
|
-
return
|
|
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 =
|
|
35464
|
-
if (
|
|
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=${
|
|
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 =
|
|
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(
|
|
35759
|
-
writeFileSync14(
|
|
35760
|
-
writeFileSync14(
|
|
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 =
|
|
35987
|
+
const fullPath = join20(workDir, relPath);
|
|
35773
35988
|
mkdirSync13(dirname9(fullPath), { recursive: true });
|
|
35774
35989
|
writeFileSync14(fullPath, contents);
|
|
35775
35990
|
}
|
|
35776
|
-
writeFileSync14(
|
|
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,
|
|
35784
|
-
await scpUpload(cfg.target,
|
|
35785
|
-
await scpUpload(cfg.target,
|
|
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(
|
|
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,
|
|
36008
|
+
await scpUpload(cfg.target, join20(workDir, relPath), `${cfg.target.remoteDir}/${relPath}`);
|
|
35794
36009
|
}
|
|
35795
|
-
await scpUpload(cfg.target,
|
|
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
|
|
36166
|
+
existsSync as existsSync18,
|
|
35951
36167
|
mkdirSync as mkdirSync14,
|
|
35952
|
-
readFileSync as
|
|
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
|
|
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 =
|
|
36008
|
-
if (!
|
|
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 =
|
|
36234
|
+
const dockerfileDir = join21(tmpdir3(), `arc-image-${Date.now()}`);
|
|
36019
36235
|
mkdirSync14(dockerfileDir, { recursive: true });
|
|
36020
|
-
const dockerfilePath =
|
|
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 =
|
|
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 =
|
|
36054
|
-
if (
|
|
36269
|
+
const candidate = join21(cur, "package.json");
|
|
36270
|
+
if (existsSync18(candidate)) {
|
|
36055
36271
|
try {
|
|
36056
|
-
const pkg = JSON.parse(
|
|
36272
|
+
const pkg = JSON.parse(readFileSync16(candidate, "utf-8"));
|
|
36057
36273
|
if (pkg.name === "@arcote.tech/arc-cli") {
|
|
36058
|
-
const distIndex =
|
|
36059
|
-
if (!
|
|
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(
|
|
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 =
|
|
36098
|
-
const hasLocales =
|
|
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 (
|
|
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
|
|
37028
|
+
const location2 = await ue({
|
|
36813
37029
|
message: "Hetzner datacenter location",
|
|
36814
37030
|
initialValue: "nbg1"
|
|
36815
37031
|
});
|
|
36816
|
-
if (BD(
|
|
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 =
|
|
37161
|
+
const manifestPath = join22(ws.arcDir, "manifest.json");
|
|
36946
37162
|
if (!options.imageTag) {
|
|
36947
|
-
const needBuild = options.rebuild || !
|
|
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 (!
|
|
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 =
|
|
37023
|
-
if (
|
|
37024
|
-
const pkg = JSON.parse(
|
|
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 =
|
|
37041
|
-
const content =
|
|
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
|
|
37051
|
-
import { join as
|
|
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
|
|
38681
|
-
import { join as
|
|
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
|
|
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=${
|
|
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">${
|
|
38717
|
-
<script>window.__ARC_PEERS__=${
|
|
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="
|
|
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>${
|
|
38725
|
-
<link rel="icon" href="${
|
|
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 (!
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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 =
|
|
38945
|
-
if (
|
|
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 (
|
|
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(
|
|
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 ||
|
|
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 ??
|
|
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 =
|
|
39306
|
-
if (!
|
|
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(
|
|
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) =>
|
|
39395
|
-
const packageOf = (absFile) => ws.packages.find((p3) => absFile.startsWith(
|
|
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 =
|
|
39742
|
+
const file = join24(rootDir, ".arc", "app-secret");
|
|
39431
39743
|
try {
|
|
39432
|
-
const saved =
|
|
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(
|
|
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 =
|
|
39761
|
+
const file = join24(rootDir, ".arc", "pairing-token");
|
|
39450
39762
|
try {
|
|
39451
|
-
const saved =
|
|
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(
|
|
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(
|
|
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 =
|
|
39503
|
-
if (!
|
|
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 =
|
|
39514
|
-
if (
|
|
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
|
|
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 =
|
|
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 });
|