@absolutejs/absolute 0.20.0-beta.65 → 0.20.0-beta.67
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/angular/components/core/streamingSlotRegistrar.js +1 -1
- package/dist/angular/components/core/streamingSlotRegistry.js +2 -2
- package/dist/build.js +768 -544
- package/dist/build.js.map +10 -8
- package/dist/cli/index.js +148 -5
- package/dist/dev/serverBootstrap.js +544 -6
- package/dist/index.js +905 -619
- package/dist/index.js.map +14 -11
- package/dist/mobile/index.js +5430 -5
- package/dist/mobile/index.js.map +11 -8
- package/dist/mobile/mobilePreviewClient.ts +246 -0
- package/dist/mobile/remoteMacAgentEntry.js +241 -180
- package/dist/mobile/shellAuth.js +16 -0
- package/dist/mobile/shellBootstrap.js +5427 -117
- package/dist/mobile/shellExpoAuth.js +16 -0
- package/dist/mobile/shellExpoDevices.js +16 -0
- package/dist/mobile/shellExpoSync.js +16 -0
- package/dist/mobile/shellSync.js +16 -0
- package/dist/mobile/shellUpdate.js +16 -0
- package/dist/mobile/uiPrimitives.js +16 -0
- package/dist/src/build/chainInlineSourcemaps.d.ts +2 -0
- package/dist/src/build/vueCompileCache.d.ts +43 -0
- package/dist/src/cli/config/server.d.ts +1 -1
- package/dist/src/dev/bootLifecycle.d.ts +11 -0
- package/dist/src/dev/earlyListener.d.ts +41 -0
- package/dist/src/mobile/capacitorBundle.d.ts +8 -1
- package/dist/src/mobile/config.d.ts +6 -0
- package/dist/src/mobile/index.d.ts +1 -0
- package/dist/src/mobile/mobileInspect.d.ts +14 -0
- package/dist/src/mobile/mobilePreview.d.ts +1 -1
- package/dist/src/mobile/shellBootstrap.d.ts +2 -0
- package/dist/src/mobile/shellObservability.d.ts +11 -0
- package/dist/src/mobile/transport.d.ts +6 -0
- package/dist/src/plugins/imageOptimizer.d.ts +1 -1
- package/dist/src/utils/startupTimings.d.ts +4 -0
- package/dist/types/build.d.ts +12 -0
- package/dist/types/globals.d.ts +15 -0
- package/package.json +9 -7
|
@@ -1,7 +1,520 @@
|
|
|
1
1
|
// @bun
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __returnValue = (v) => v;
|
|
4
|
+
function __exportSetter(name, newValue) {
|
|
5
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
6
|
+
}
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, {
|
|
10
|
+
get: all[name],
|
|
11
|
+
enumerable: true,
|
|
12
|
+
configurable: true,
|
|
13
|
+
set: __exportSetter.bind(all, name)
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
17
|
+
|
|
18
|
+
// src/constants.ts
|
|
19
|
+
var DEFAULT_PORT = 3000, HOURS_IN_DAY = 24, MILLISECONDS_IN_A_SECOND = 1000, MINUTES_IN_AN_HOUR = 60, SECONDS_IN_A_MINUTE = 60, MILLISECONDS_IN_A_MINUTE, MILLISECONDS_IN_A_DAY, TWO_THIRDS;
|
|
20
|
+
var init_constants = __esm(() => {
|
|
21
|
+
MILLISECONDS_IN_A_MINUTE = MILLISECONDS_IN_A_SECOND * SECONDS_IN_A_MINUTE;
|
|
22
|
+
MILLISECONDS_IN_A_DAY = MILLISECONDS_IN_A_SECOND * SECONDS_IN_A_MINUTE * MINUTES_IN_AN_HOUR * HOURS_IN_DAY;
|
|
23
|
+
TWO_THIRDS = 2 / 3;
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// src/dev/bootLifecycle.ts
|
|
27
|
+
var getBootPhase = () => globalThis.__absoluteBootPhase;
|
|
28
|
+
var init_bootLifecycle = __esm(() => {
|
|
29
|
+
init_constants();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// src/dev/earlyListener.ts
|
|
33
|
+
var exports_earlyListener = {};
|
|
34
|
+
__export(exports_earlyListener, {
|
|
35
|
+
BOOT_STATUS_HEADER: () => BOOT_STATUS_HEADER,
|
|
36
|
+
bootStatusSnapshot: () => bootStatusSnapshot,
|
|
37
|
+
buildingResponse: () => buildingResponse,
|
|
38
|
+
installEarlyListenerServeGuard: () => installEarlyListenerServeGuard,
|
|
39
|
+
releaseEarlyListener: () => releaseEarlyListener,
|
|
40
|
+
startEarlyListener: () => startEarlyListener
|
|
41
|
+
});
|
|
42
|
+
var HTTP_SERVICE_UNAVAILABLE = 503, RETRY_AFTER_SECONDS = 2, BIND_RETRY_INTERVAL_MS = 250, BIND_RETRY_LIMIT = 40, POLL_INTERVAL_MS, NOSCRIPT_REFRESH_SECONDS = 10, BOOT_STATUS_HEADER = "X-Absolute-Boot", bindingPlaceholder = false, escapeHtml = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """), bootStatusSnapshot = (startedAt) => {
|
|
43
|
+
const elapsedMs = Math.max(0, Date.now() - startedAt);
|
|
44
|
+
return {
|
|
45
|
+
elapsedMs,
|
|
46
|
+
elapsedSeconds: Math.floor(elapsedMs / MILLISECONDS_IN_A_SECOND),
|
|
47
|
+
phase: getBootPhase() ?? "starting",
|
|
48
|
+
status: "building"
|
|
49
|
+
};
|
|
50
|
+
}, buildingPage = (snapshot) => `<!doctype html>
|
|
51
|
+
<html lang="en">
|
|
52
|
+
<head>
|
|
53
|
+
<meta charset="utf-8">
|
|
54
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
55
|
+
<meta http-equiv="refresh" content="${NOSCRIPT_REFRESH_SECONDS}">
|
|
56
|
+
<title>Building\u2026</title>
|
|
57
|
+
<style>
|
|
58
|
+
:root{color-scheme:light dark}
|
|
59
|
+
body{margin:0;min-height:100vh;display:grid;place-items:center;font:15px/1.5 system-ui,-apple-system,"Segoe UI",sans-serif;background:#0f1115;color:#e6e8ee}
|
|
60
|
+
main{text-align:center;padding:2rem}
|
|
61
|
+
.spin{width:36px;height:36px;margin:0 auto 1rem;border:3px solid rgba(255,255,255,.15);border-top-color:#8ab4ff;border-radius:50%;animation:s 1s linear infinite}
|
|
62
|
+
@keyframes s{to{transform:rotate(360deg)}}
|
|
63
|
+
h1{font-size:1.15rem;font-weight:600;margin:0 0 .25rem}
|
|
64
|
+
p{margin:0;opacity:.6;font-size:.85rem}
|
|
65
|
+
code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}
|
|
66
|
+
</style>
|
|
67
|
+
</head>
|
|
68
|
+
<body>
|
|
69
|
+
<main>
|
|
70
|
+
<div class="spin" aria-hidden="true"></div>
|
|
71
|
+
<h1>Building\u2026 <span id="t">${snapshot.elapsedSeconds}</span>s</h1>
|
|
72
|
+
<p>AbsoluteJS dev server \xB7 <code id="p">${escapeHtml(snapshot.phase)}</code></p>
|
|
73
|
+
</main>
|
|
74
|
+
<script>
|
|
75
|
+
(function(){
|
|
76
|
+
var started=Date.now()-${snapshot.elapsedMs};
|
|
77
|
+
var t=document.getElementById('t');
|
|
78
|
+
setInterval(function(){t.textContent=String(Math.floor((Date.now()-started)/1000));},1000);
|
|
79
|
+
function poll(){
|
|
80
|
+
fetch(location.href,{cache:'no-store',headers:{accept:'application/json'}}).then(function(r){
|
|
81
|
+
if(r.headers.get('${BOOT_STATUS_HEADER.toLowerCase()}')!=='building'){location.reload();return;}
|
|
82
|
+
return r.json().then(function(j){if(j&&j.phase){document.getElementById('p').textContent=j.phase;}});
|
|
83
|
+
}).catch(function(){}).then(function(){setTimeout(poll,${POLL_INTERVAL_MS});});
|
|
84
|
+
}
|
|
85
|
+
setTimeout(poll,${POLL_INTERVAL_MS});
|
|
86
|
+
})();
|
|
87
|
+
</script>
|
|
88
|
+
</body>
|
|
89
|
+
</html>
|
|
90
|
+
`, buildingResponse = (request, startedAt) => {
|
|
91
|
+
const snapshot = bootStatusSnapshot(startedAt);
|
|
92
|
+
const headers = {
|
|
93
|
+
"Cache-Control": "no-store",
|
|
94
|
+
"Retry-After": String(RETRY_AFTER_SECONDS),
|
|
95
|
+
"X-Absolute-Boot": "building"
|
|
96
|
+
};
|
|
97
|
+
const isUpgrade = request.headers.get("upgrade")?.toLowerCase() === "websocket";
|
|
98
|
+
const accept = request.headers.get("accept") ?? "";
|
|
99
|
+
if (!isUpgrade && accept.includes("text/html")) {
|
|
100
|
+
headers["Content-Type"] = "text/html; charset=utf-8";
|
|
101
|
+
return new Response(buildingPage(snapshot), {
|
|
102
|
+
headers,
|
|
103
|
+
status: HTTP_SERVICE_UNAVAILABLE
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
if (!isUpgrade && accept.includes("application/json")) {
|
|
107
|
+
headers["Content-Type"] = "application/json; charset=utf-8";
|
|
108
|
+
return new Response(JSON.stringify(snapshot), {
|
|
109
|
+
headers,
|
|
110
|
+
status: HTTP_SERVICE_UNAVAILABLE
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
headers["Content-Type"] = "text/plain; charset=utf-8";
|
|
114
|
+
return new Response(`AbsoluteJS dev server is building (${snapshot.elapsedSeconds}s, ${snapshot.phase}). Retry shortly.
|
|
115
|
+
`, { headers, status: HTTP_SERVICE_UNAVAILABLE });
|
|
116
|
+
}, installEarlyListenerServeGuard = (port) => {
|
|
117
|
+
if (globalThis.__absoluteEarlyListenerServeGuard)
|
|
118
|
+
return;
|
|
119
|
+
const originalServe = Bun.serve;
|
|
120
|
+
const guardedServe = (serveOptions) => {
|
|
121
|
+
const requested = Number(serveOptions.port ?? port);
|
|
122
|
+
const listener = globalThis.__absoluteEarlyListener;
|
|
123
|
+
if (!bindingPlaceholder && listener && (requested === port || Number.isNaN(requested))) {
|
|
124
|
+
releaseEarlyListener();
|
|
125
|
+
}
|
|
126
|
+
return originalServe.call(Bun, serveOptions);
|
|
127
|
+
};
|
|
128
|
+
if (Reflect.set(Bun, "serve", guardedServe)) {
|
|
129
|
+
globalThis.__absoluteEarlyListenerServeGuard = true;
|
|
130
|
+
}
|
|
131
|
+
}, releaseEarlyListener = () => {
|
|
132
|
+
const listener = globalThis.__absoluteEarlyListener;
|
|
133
|
+
if (!listener)
|
|
134
|
+
return false;
|
|
135
|
+
const hadServer = listener.server !== null;
|
|
136
|
+
listener.release();
|
|
137
|
+
globalThis.__absoluteEarlyListener = undefined;
|
|
138
|
+
return hadServer;
|
|
139
|
+
}, startEarlyListener = (options) => {
|
|
140
|
+
const startedAt = Date.now();
|
|
141
|
+
let server = null;
|
|
142
|
+
let released = false;
|
|
143
|
+
let attempts = 0;
|
|
144
|
+
let retryTimer;
|
|
145
|
+
const tryBind = () => {
|
|
146
|
+
if (released)
|
|
147
|
+
return;
|
|
148
|
+
attempts += 1;
|
|
149
|
+
bindingPlaceholder = true;
|
|
150
|
+
try {
|
|
151
|
+
server = Bun.serve({
|
|
152
|
+
hostname: options.host,
|
|
153
|
+
port: options.port,
|
|
154
|
+
fetch: (request) => buildingResponse(request, startedAt),
|
|
155
|
+
...options.tls ? { tls: options.tls } : {}
|
|
156
|
+
});
|
|
157
|
+
} catch {
|
|
158
|
+
if (attempts >= BIND_RETRY_LIMIT)
|
|
159
|
+
return;
|
|
160
|
+
retryTimer = setTimeout(tryBind, BIND_RETRY_INTERVAL_MS);
|
|
161
|
+
retryTimer.unref();
|
|
162
|
+
} finally {
|
|
163
|
+
bindingPlaceholder = false;
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
const release = () => {
|
|
167
|
+
if (released)
|
|
168
|
+
return;
|
|
169
|
+
released = true;
|
|
170
|
+
if (retryTimer)
|
|
171
|
+
clearTimeout(retryTimer);
|
|
172
|
+
const active = server;
|
|
173
|
+
server = null;
|
|
174
|
+
if (!active)
|
|
175
|
+
return;
|
|
176
|
+
try {
|
|
177
|
+
active.stop(true);
|
|
178
|
+
} catch {}
|
|
179
|
+
};
|
|
180
|
+
tryBind();
|
|
181
|
+
const listener = {
|
|
182
|
+
release,
|
|
183
|
+
startedAt,
|
|
184
|
+
get released() {
|
|
185
|
+
return released;
|
|
186
|
+
},
|
|
187
|
+
get server() {
|
|
188
|
+
return server;
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
globalThis.__absoluteEarlyListener = listener;
|
|
192
|
+
return listener;
|
|
193
|
+
};
|
|
194
|
+
var init_earlyListener = __esm(() => {
|
|
195
|
+
init_constants();
|
|
196
|
+
init_bootLifecycle();
|
|
197
|
+
POLL_INTERVAL_MS = RETRY_AFTER_SECONDS * MILLISECONDS_IN_A_SECOND;
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
// src/dev/devCert.ts
|
|
201
|
+
var exports_devCert = {};
|
|
202
|
+
__export(exports_devCert, {
|
|
203
|
+
ensureDevCert: () => ensureDevCert,
|
|
204
|
+
getDevCertificateAuthorityPath: () => getDevCertificateAuthorityPath,
|
|
205
|
+
hasCert: () => hasCert,
|
|
206
|
+
hasMkcert: () => hasMkcert,
|
|
207
|
+
loadDevCert: () => loadDevCert,
|
|
208
|
+
normalizeDevCertificateHosts: () => normalizeDevCertificateHosts,
|
|
209
|
+
setupMkcert: () => setupMkcert
|
|
210
|
+
});
|
|
211
|
+
import {
|
|
212
|
+
copyFileSync,
|
|
213
|
+
existsSync,
|
|
214
|
+
mkdirSync,
|
|
215
|
+
readFileSync,
|
|
216
|
+
rmSync
|
|
217
|
+
} from "fs";
|
|
218
|
+
import { X509Certificate } from "crypto";
|
|
219
|
+
import { isIP } from "net";
|
|
220
|
+
import { platform } from "os";
|
|
221
|
+
import { join } from "path";
|
|
222
|
+
var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE_HOSTS, CERTIFICATE_HOSTNAME_PATTERN, devLog = (msg) => console.log(`\x1B[2m${new Date().toLocaleTimeString()}\x1B[0m \x1B[36m[dev]\x1B[0m ${msg}`), devWarn = (msg) => console.log(`\x1B[2m${new Date().toLocaleTimeString()}\x1B[0m \x1B[33m[dev]\x1B[0m \x1B[33m${msg}\x1B[0m`), certFilesExist = () => existsSync(CERT_PATH) && existsSync(KEY_PATH), normalizeDevCertificateHosts = (hosts = []) => {
|
|
223
|
+
const normalized = new Set(DEFAULT_CERTIFICATE_HOSTS);
|
|
224
|
+
for (const host of hosts) {
|
|
225
|
+
const value = host.trim().toLowerCase();
|
|
226
|
+
if (!value || value === "0.0.0.0" || value === "::")
|
|
227
|
+
continue;
|
|
228
|
+
if (isIP(value) === 0 && !CERTIFICATE_HOSTNAME_PATTERN.test(value)) {
|
|
229
|
+
throw new TypeError(`Invalid development certificate host: ${host}`);
|
|
230
|
+
}
|
|
231
|
+
normalized.add(value);
|
|
232
|
+
}
|
|
233
|
+
return [...normalized];
|
|
234
|
+
}, certificateIsUsable = (hosts) => {
|
|
235
|
+
try {
|
|
236
|
+
const certPem = readFileSync(CERT_PATH, "utf-8");
|
|
237
|
+
const certificate = new X509Certificate(certPem);
|
|
238
|
+
if (new Date(certificate.validTo).getTime() <= Date.now())
|
|
239
|
+
return false;
|
|
240
|
+
return normalizeDevCertificateHosts(hosts).every((host) => isIP(host) ? certificate.checkIP(host) !== undefined : certificate.checkHost(host) !== undefined);
|
|
241
|
+
} catch {
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
}, hasMkcert = () => {
|
|
245
|
+
try {
|
|
246
|
+
const result = Bun.spawnSync(["mkcert", "-version"], {
|
|
247
|
+
stderr: "pipe",
|
|
248
|
+
stdout: "pipe"
|
|
249
|
+
});
|
|
250
|
+
return result.exitCode === 0;
|
|
251
|
+
} catch {
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
}, generateWithMkcert = (hosts = []) => {
|
|
255
|
+
const result = Bun.spawnSync([
|
|
256
|
+
"mkcert",
|
|
257
|
+
"-cert-file",
|
|
258
|
+
CERT_PATH,
|
|
259
|
+
"-key-file",
|
|
260
|
+
KEY_PATH,
|
|
261
|
+
...normalizeDevCertificateHosts(hosts)
|
|
262
|
+
], { stderr: "pipe", stdout: "pipe" });
|
|
263
|
+
if (result.exitCode !== 0) {
|
|
264
|
+
const err = new TextDecoder().decode(result.stderr);
|
|
265
|
+
throw new Error(`mkcert failed: ${err}`);
|
|
266
|
+
}
|
|
267
|
+
}, generateSelfSigned = (hosts = []) => {
|
|
268
|
+
const subjectAlternativeNames = normalizeDevCertificateHosts(hosts).map((host) => `${isIP(host) ? "IP" : "DNS"}:${host}`).join(",");
|
|
269
|
+
const proc = Bun.spawnSync([
|
|
270
|
+
"openssl",
|
|
271
|
+
"req",
|
|
272
|
+
"-x509",
|
|
273
|
+
"-newkey",
|
|
274
|
+
"ec",
|
|
275
|
+
"-pkeyopt",
|
|
276
|
+
"ec_paramgen_curve:prime256v1",
|
|
277
|
+
"-days",
|
|
278
|
+
String(CERT_VALIDITY_DAYS),
|
|
279
|
+
"-nodes",
|
|
280
|
+
"-keyout",
|
|
281
|
+
KEY_PATH,
|
|
282
|
+
"-out",
|
|
283
|
+
CERT_PATH,
|
|
284
|
+
"-subj",
|
|
285
|
+
"/CN=localhost",
|
|
286
|
+
"-addext",
|
|
287
|
+
`subjectAltName=${subjectAlternativeNames}`
|
|
288
|
+
], { stderr: "pipe", stdout: "pipe" });
|
|
289
|
+
if (proc.exitCode !== 0) {
|
|
290
|
+
const err = new TextDecoder().decode(proc.stderr);
|
|
291
|
+
throw new Error(`openssl failed: ${err}`);
|
|
292
|
+
}
|
|
293
|
+
devLog("Using self-signed certificate \u2014 browser will show a one-time warning");
|
|
294
|
+
}, generateCert = (hosts = []) => {
|
|
295
|
+
if (hasMkcert()) {
|
|
296
|
+
generateWithMkcert(hosts);
|
|
297
|
+
} else {
|
|
298
|
+
generateSelfSigned(hosts);
|
|
299
|
+
}
|
|
300
|
+
}, ensureDevCert = (hosts = []) => {
|
|
301
|
+
mkdirSync(CERT_DIR, { recursive: true });
|
|
302
|
+
if (hasCert(hosts)) {
|
|
303
|
+
return { cert: CERT_PATH, key: KEY_PATH };
|
|
304
|
+
}
|
|
305
|
+
if (certFilesExist()) {
|
|
306
|
+
devLog("Certificate is expired or missing a required host, regenerating...");
|
|
307
|
+
}
|
|
308
|
+
try {
|
|
309
|
+
generateCert(hosts);
|
|
310
|
+
} catch (err) {
|
|
311
|
+
devWarn(`Failed to generate certificate: ${err instanceof Error ? err.message : err}`);
|
|
312
|
+
return null;
|
|
313
|
+
}
|
|
314
|
+
return { cert: CERT_PATH, key: KEY_PATH };
|
|
315
|
+
}, hasCert = (hosts = []) => certFilesExist() && certificateIsUsable(hosts), loadDevCert = (hosts = []) => {
|
|
316
|
+
const paths = ensureDevCert(hosts);
|
|
317
|
+
if (!paths)
|
|
318
|
+
return null;
|
|
319
|
+
try {
|
|
320
|
+
return {
|
|
321
|
+
cert: readFileSync(paths.cert, "utf-8"),
|
|
322
|
+
key: readFileSync(paths.key, "utf-8")
|
|
323
|
+
};
|
|
324
|
+
} catch {
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
}, commandExists = (cmd) => {
|
|
328
|
+
try {
|
|
329
|
+
const check = platform() === "win32" ? ["where", cmd] : ["which", cmd];
|
|
330
|
+
const result = Bun.spawnSync(check, {
|
|
331
|
+
stderr: "pipe",
|
|
332
|
+
stdout: "pipe"
|
|
333
|
+
});
|
|
334
|
+
return result.exitCode === 0;
|
|
335
|
+
} catch {
|
|
336
|
+
return false;
|
|
337
|
+
}
|
|
338
|
+
}, installMkcertDarwin = () => {
|
|
339
|
+
if (!commandExists("brew")) {
|
|
340
|
+
devWarn("Install Homebrew first: https://brew.sh");
|
|
341
|
+
return false;
|
|
342
|
+
}
|
|
343
|
+
devLog("Installing mkcert with Homebrew...");
|
|
344
|
+
const result = Bun.spawnSync(["brew", "install", "mkcert"], {
|
|
345
|
+
stderr: "pipe",
|
|
346
|
+
stdout: "pipe"
|
|
347
|
+
});
|
|
348
|
+
return result.exitCode === 0;
|
|
349
|
+
}, installMkcertLinux = () => {
|
|
350
|
+
const sudoOpts = {
|
|
351
|
+
stderr: "inherit",
|
|
352
|
+
stdin: "inherit",
|
|
353
|
+
stdout: "pipe"
|
|
354
|
+
};
|
|
355
|
+
if (commandExists("apt-get")) {
|
|
356
|
+
devLog("Installing mkcert (may prompt for password)...");
|
|
357
|
+
const result = Bun.spawnSync(["sudo", "apt-get", "install", "-y", "mkcert", "libnss3-tools"], sudoOpts);
|
|
358
|
+
if (result.exitCode === 0)
|
|
359
|
+
return true;
|
|
360
|
+
}
|
|
361
|
+
if (commandExists("dnf")) {
|
|
362
|
+
devLog("Installing mkcert (may prompt for password)...");
|
|
363
|
+
const result = Bun.spawnSync(["sudo", "dnf", "install", "-y", "mkcert"], sudoOpts);
|
|
364
|
+
if (result.exitCode === 0)
|
|
365
|
+
return true;
|
|
366
|
+
}
|
|
367
|
+
if (commandExists("pacman")) {
|
|
368
|
+
devLog("Installing mkcert (may prompt for password)...");
|
|
369
|
+
const result = Bun.spawnSync(["sudo", "pacman", "-S", "--noconfirm", "mkcert"], sudoOpts);
|
|
370
|
+
if (result.exitCode === 0)
|
|
371
|
+
return true;
|
|
372
|
+
}
|
|
373
|
+
devWarn("Could not install mkcert automatically.");
|
|
374
|
+
console.log(" See: https://github.com/FiloSottile/mkcert#installation");
|
|
375
|
+
return false;
|
|
376
|
+
}, installMkcertWin32 = () => {
|
|
377
|
+
if (commandExists("choco")) {
|
|
378
|
+
devLog("Installing mkcert with Chocolatey...");
|
|
379
|
+
const result = Bun.spawnSync(["choco", "install", "-y", "mkcert"], {
|
|
380
|
+
stderr: "pipe",
|
|
381
|
+
stdout: "pipe"
|
|
382
|
+
});
|
|
383
|
+
if (result.exitCode === 0)
|
|
384
|
+
return true;
|
|
385
|
+
}
|
|
386
|
+
if (commandExists("winget")) {
|
|
387
|
+
devLog("Installing mkcert with winget...");
|
|
388
|
+
const result = Bun.spawnSync(["winget", "install", "--id", "FiloSottile.mkcert", "-e"], { stderr: "pipe", stdout: "pipe" });
|
|
389
|
+
if (result.exitCode === 0)
|
|
390
|
+
return true;
|
|
391
|
+
}
|
|
392
|
+
devWarn("Could not install mkcert automatically.");
|
|
393
|
+
console.log(" See: https://github.com/FiloSottile/mkcert#installation");
|
|
394
|
+
return false;
|
|
395
|
+
}, installMkcert = () => {
|
|
396
|
+
const osPlatform = platform();
|
|
397
|
+
if (osPlatform === "darwin")
|
|
398
|
+
return installMkcertDarwin();
|
|
399
|
+
if (osPlatform === "linux")
|
|
400
|
+
return installMkcertLinux();
|
|
401
|
+
if (osPlatform === "win32")
|
|
402
|
+
return installMkcertWin32();
|
|
403
|
+
return false;
|
|
404
|
+
}, ensureMkcert = () => {
|
|
405
|
+
if (hasMkcert())
|
|
406
|
+
return true;
|
|
407
|
+
if (!installMkcert())
|
|
408
|
+
return false;
|
|
409
|
+
if (!hasMkcert()) {
|
|
410
|
+
devWarn("mkcert installed but not found in PATH. Restart your terminal and try again.");
|
|
411
|
+
return false;
|
|
412
|
+
}
|
|
413
|
+
return true;
|
|
414
|
+
}, isWSL = () => {
|
|
415
|
+
if (platform() !== "linux")
|
|
416
|
+
return false;
|
|
417
|
+
try {
|
|
418
|
+
return /microsoft|wsl/i.test(readFileSync("/proc/version", "utf-8"));
|
|
419
|
+
} catch {
|
|
420
|
+
return false;
|
|
421
|
+
}
|
|
422
|
+
}, runCapture = (cmd) => {
|
|
423
|
+
try {
|
|
424
|
+
const result = Bun.spawnSync(cmd, { stderr: "pipe", stdout: "pipe" });
|
|
425
|
+
if (result.exitCode !== 0)
|
|
426
|
+
return null;
|
|
427
|
+
const out = new TextDecoder().decode(result.stdout).trim();
|
|
428
|
+
return out || null;
|
|
429
|
+
} catch {
|
|
430
|
+
return null;
|
|
431
|
+
}
|
|
432
|
+
}, mkcertCaRoot = () => runCapture(["mkcert", "-CAROOT"]), getDevCertificateAuthorityPath = () => {
|
|
433
|
+
const caRoot = hasMkcert() ? mkcertCaRoot() : null;
|
|
434
|
+
const rootCertificate = caRoot ? join(caRoot, "rootCA.pem") : null;
|
|
435
|
+
if (rootCertificate && existsSync(rootCertificate))
|
|
436
|
+
return rootCertificate;
|
|
437
|
+
if (certFilesExist())
|
|
438
|
+
return CERT_PATH;
|
|
439
|
+
return null;
|
|
440
|
+
}, toWindowsPath = (linuxPath) => runCapture(["wslpath", "-w", linuxPath]), windowsTempDir = () => {
|
|
441
|
+
const winTemp = runCapture(["cmd.exe", "/c", "echo %TEMP%"]);
|
|
442
|
+
if (!winTemp)
|
|
443
|
+
return null;
|
|
444
|
+
return runCapture(["wslpath", "-u", winTemp]);
|
|
445
|
+
}, trustCaOnWindows = () => {
|
|
446
|
+
const caRoot = mkcertCaRoot();
|
|
447
|
+
if (!caRoot)
|
|
448
|
+
return false;
|
|
449
|
+
const rootCa = join(caRoot, "rootCA.pem");
|
|
450
|
+
if (!existsSync(rootCa))
|
|
451
|
+
return false;
|
|
452
|
+
const winTemp = windowsTempDir();
|
|
453
|
+
if (!winTemp)
|
|
454
|
+
return false;
|
|
455
|
+
const staged = join(winTemp, "absolutejs-mkcert-rootCA.crt");
|
|
456
|
+
try {
|
|
457
|
+
copyFileSync(rootCa, staged);
|
|
458
|
+
} catch {
|
|
459
|
+
return false;
|
|
460
|
+
}
|
|
461
|
+
const stagedWin = toWindowsPath(staged);
|
|
462
|
+
if (!stagedWin) {
|
|
463
|
+
rmSync(staged, { force: true });
|
|
464
|
+
return false;
|
|
465
|
+
}
|
|
466
|
+
const result = Bun.spawnSync([
|
|
467
|
+
"powershell.exe",
|
|
468
|
+
"-NoProfile",
|
|
469
|
+
"-Command",
|
|
470
|
+
`Import-Certificate -FilePath '${stagedWin}' -CertStoreLocation Cert:\\CurrentUser\\Root`
|
|
471
|
+
], { stderr: "pipe", stdout: "pipe" });
|
|
472
|
+
rmSync(staged, { force: true });
|
|
473
|
+
return result.exitCode === 0;
|
|
474
|
+
}, setupMkcert = (hosts = []) => {
|
|
475
|
+
if (!ensureMkcert())
|
|
476
|
+
return false;
|
|
477
|
+
const installResult = Bun.spawnSync(["mkcert", "-install"], {
|
|
478
|
+
stderr: "pipe",
|
|
479
|
+
stdin: "inherit",
|
|
480
|
+
stdout: "pipe"
|
|
481
|
+
});
|
|
482
|
+
if (installResult.exitCode !== 0) {
|
|
483
|
+
devWarn("Failed to install local CA");
|
|
484
|
+
return false;
|
|
485
|
+
}
|
|
486
|
+
if (isWSL()) {
|
|
487
|
+
if (trustCaOnWindows()) {
|
|
488
|
+
devLog("Trusted the local CA in the Windows store \u2014 Chrome/Edge on Windows now accept dev HTTPS");
|
|
489
|
+
} else {
|
|
490
|
+
const caRoot = mkcertCaRoot();
|
|
491
|
+
const hint = caRoot ? toWindowsPath(join(caRoot, "rootCA.pem")) : null;
|
|
492
|
+
devWarn("Could not auto-trust the local CA on Windows; Windows browsers may warn.");
|
|
493
|
+
if (hint) {
|
|
494
|
+
console.log(` Run in PowerShell: Import-Certificate -FilePath "${hint}" -CertStoreLocation Cert:\\CurrentUser\\Root`);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
rmSync(CERT_PATH, { force: true });
|
|
499
|
+
rmSync(KEY_PATH, { force: true });
|
|
500
|
+
mkdirSync(CERT_DIR, { recursive: true });
|
|
501
|
+
generateWithMkcert(hosts);
|
|
502
|
+
console.log("");
|
|
503
|
+
devLog("mkcert installed \u2014 HTTPS certificates are now locally trusted");
|
|
504
|
+
return true;
|
|
505
|
+
};
|
|
506
|
+
var init_devCert = __esm(() => {
|
|
507
|
+
CERT_DIR = join(process.cwd(), ".absolutejs");
|
|
508
|
+
CERT_PATH = join(CERT_DIR, "cert.pem");
|
|
509
|
+
KEY_PATH = join(CERT_DIR, "key.pem");
|
|
510
|
+
DEFAULT_CERTIFICATE_HOSTS = ["localhost", "127.0.0.1", "::1"];
|
|
511
|
+
CERTIFICATE_HOSTNAME_PATTERN = /^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)(?:\.(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?))*$/u;
|
|
512
|
+
});
|
|
513
|
+
|
|
2
514
|
// src/dev/serverBootstrap.ts
|
|
3
|
-
|
|
4
|
-
import {
|
|
515
|
+
init_constants();
|
|
516
|
+
import { copyFileSync as copyFileSync2, existsSync as existsSync2, readdirSync, unlinkSync } from "fs";
|
|
517
|
+
import { dirname, extname, join as join2, resolve } from "path";
|
|
5
518
|
|
|
6
519
|
// src/dev/serverEntryCopies.ts
|
|
7
520
|
var ENTRY_COPY_OWNER_PATTERN = /^\.absolutejs-hmr-(\d+)-(?:bootstrap-)?\d+\.[^.]+$/;
|
|
@@ -33,7 +546,7 @@ if (!originalEntry) {
|
|
|
33
546
|
throw new Error("ABSOLUTE_SERVER_ENTRY is required by the AbsoluteJS dev bootstrap");
|
|
34
547
|
}
|
|
35
548
|
var entryPath = resolve(originalEntry);
|
|
36
|
-
if (!
|
|
549
|
+
if (!existsSync2(entryPath)) {
|
|
37
550
|
throw new Error(`AbsoluteJS server entry does not exist: ${entryPath}`);
|
|
38
551
|
}
|
|
39
552
|
var entryDir = dirname(entryPath);
|
|
@@ -52,13 +565,13 @@ if (!isHotReevaluation) {
|
|
|
52
565
|
}
|
|
53
566
|
if (!isStaleAbsoluteServerEntryCopy(name))
|
|
54
567
|
continue;
|
|
55
|
-
removeEntryCopy(
|
|
568
|
+
removeEntryCopy(join2(entryDir, name));
|
|
56
569
|
}
|
|
57
570
|
}
|
|
58
571
|
var bootstrapSequence = (globalThis.__absoluteEntryBootstrapSequence ?? 0) + 1;
|
|
59
572
|
globalThis.__absoluteEntryBootstrapSequence = bootstrapSequence;
|
|
60
|
-
var bootstrapCopy =
|
|
61
|
-
|
|
573
|
+
var bootstrapCopy = join2(entryDir, `${copyPrefix}${process.pid}-bootstrap-${bootstrapSequence}${entryExtension}`);
|
|
574
|
+
copyFileSync2(entryPath, bootstrapCopy);
|
|
62
575
|
var entryCopies = globalThis.__absoluteEntryCopies ?? new Set;
|
|
63
576
|
entryCopies.add(bootstrapCopy);
|
|
64
577
|
globalThis.__absoluteEntryCopies = entryCopies;
|
|
@@ -70,4 +583,29 @@ if (!globalThis.__absoluteEntryCleanupRegistered) {
|
|
|
70
583
|
}
|
|
71
584
|
});
|
|
72
585
|
}
|
|
586
|
+
if (!isHotReevaluation && !globalThis.__absoluteBunServer && process.env.ABSOLUTE_EARLY_LISTEN !== "0") {
|
|
587
|
+
const { startEarlyListener: startEarlyListener2, installEarlyListenerServeGuard: installEarlyListenerServeGuard2 } = await Promise.resolve().then(() => (init_earlyListener(), exports_earlyListener));
|
|
588
|
+
const earlyHost = process.env.ABSOLUTE_HOST ?? process.env.HOST ?? "localhost";
|
|
589
|
+
const earlyPort = Number(process.env.ABSOLUTE_PORT ?? process.env.PORT ?? DEFAULT_PORT);
|
|
590
|
+
const loadEarlyTls = async () => {
|
|
591
|
+
if (false)
|
|
592
|
+
;
|
|
593
|
+
if (process.env.ABSOLUTE_HTTPS !== "true")
|
|
594
|
+
return null;
|
|
595
|
+
try {
|
|
596
|
+
const { loadDevCert: loadDevCert2 } = await Promise.resolve().then(() => (init_devCert(), exports_devCert));
|
|
597
|
+
return loadDevCert2();
|
|
598
|
+
} catch {
|
|
599
|
+
return null;
|
|
600
|
+
}
|
|
601
|
+
};
|
|
602
|
+
if (Number.isInteger(earlyPort) && earlyPort > 0) {
|
|
603
|
+
startEarlyListener2({
|
|
604
|
+
host: earlyHost,
|
|
605
|
+
port: earlyPort,
|
|
606
|
+
tls: await loadEarlyTls()
|
|
607
|
+
});
|
|
608
|
+
installEarlyListenerServeGuard2(earlyPort);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
73
611
|
await import(bootstrapCopy);
|