@adhdev/daemon-standalone 0.8.76 → 0.8.78
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/README.md +132 -20
- package/dist/index.js +510 -87
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/public/assets/index-D6Y5NQrt.js +72 -0
- package/public/assets/index-DMExkSPE.css +1 -0
- package/public/index.html +2 -2
- package/public/assets/index-99DIPRiD.js +0 -72
- package/public/assets/index-Bya1aCQ_.css +0 -1
package/dist/index.js
CHANGED
|
@@ -9244,7 +9244,7 @@ var require_dist = __commonJS({
|
|
|
9244
9244
|
}
|
|
9245
9245
|
}
|
|
9246
9246
|
};
|
|
9247
|
-
var
|
|
9247
|
+
var import_crypto3 = require("crypto");
|
|
9248
9248
|
var path5 = __toESM2(require("path"));
|
|
9249
9249
|
function normalizeSlug(input) {
|
|
9250
9250
|
return input.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
|
|
@@ -9360,7 +9360,7 @@ var require_dist = __commonJS({
|
|
|
9360
9360
|
var SessionHostRegistry = class {
|
|
9361
9361
|
sessions = /* @__PURE__ */ new Map();
|
|
9362
9362
|
createSession(payload) {
|
|
9363
|
-
const sessionId = payload.sessionId || (0,
|
|
9363
|
+
const sessionId = payload.sessionId || (0, import_crypto3.randomUUID)();
|
|
9364
9364
|
if (this.sessions.has(sessionId)) {
|
|
9365
9365
|
throw new Error(`Session already exists: ${sessionId}`);
|
|
9366
9366
|
}
|
|
@@ -26823,9 +26823,9 @@ var init_handler = __esm({
|
|
|
26823
26823
|
if (this.fsw.closed) {
|
|
26824
26824
|
return;
|
|
26825
26825
|
}
|
|
26826
|
-
const
|
|
26826
|
+
const dirname4 = sp.dirname(file2);
|
|
26827
26827
|
const basename3 = sp.basename(file2);
|
|
26828
|
-
const parent = this.fsw._getWatchedDir(
|
|
26828
|
+
const parent = this.fsw._getWatchedDir(dirname4);
|
|
26829
26829
|
let prevStats = stats;
|
|
26830
26830
|
if (parent.has(basename3))
|
|
26831
26831
|
return;
|
|
@@ -26852,7 +26852,7 @@ var init_handler = __esm({
|
|
|
26852
26852
|
prevStats = newStats2;
|
|
26853
26853
|
}
|
|
26854
26854
|
} catch (error48) {
|
|
26855
|
-
this.fsw._remove(
|
|
26855
|
+
this.fsw._remove(dirname4, basename3);
|
|
26856
26856
|
}
|
|
26857
26857
|
} else if (parent.has(basename3)) {
|
|
26858
26858
|
const at2 = newStats.atimeMs;
|
|
@@ -27927,7 +27927,7 @@ var require_dist2 = __commonJS({
|
|
|
27927
27927
|
};
|
|
27928
27928
|
}
|
|
27929
27929
|
function generateMachineId() {
|
|
27930
|
-
return `${MACHINE_ID_PREFIX}${(0,
|
|
27930
|
+
return `${MACHINE_ID_PREFIX}${(0, import_crypto3.randomUUID)().replace(/-/g, "")}`;
|
|
27931
27931
|
}
|
|
27932
27932
|
function isStableMachineId(machineId) {
|
|
27933
27933
|
return typeof machineId === "string" && machineId.startsWith(MACHINE_ID_PREFIX);
|
|
@@ -28046,7 +28046,7 @@ var require_dist2 = __commonJS({
|
|
|
28046
28046
|
var import_os2;
|
|
28047
28047
|
var import_path2;
|
|
28048
28048
|
var import_fs;
|
|
28049
|
-
var
|
|
28049
|
+
var import_crypto3;
|
|
28050
28050
|
var DEFAULT_CONFIG;
|
|
28051
28051
|
var MACHINE_ID_PREFIX;
|
|
28052
28052
|
var init_config = __esm2({
|
|
@@ -28055,7 +28055,7 @@ var require_dist2 = __commonJS({
|
|
|
28055
28055
|
import_os2 = require("os");
|
|
28056
28056
|
import_path2 = require("path");
|
|
28057
28057
|
import_fs = require("fs");
|
|
28058
|
-
|
|
28058
|
+
import_crypto3 = require("crypto");
|
|
28059
28059
|
DEFAULT_CONFIG = {
|
|
28060
28060
|
serverUrl: "https://api.adhf.dev",
|
|
28061
28061
|
allowServerApiProxy: false,
|
|
@@ -32229,12 +32229,66 @@ ${data.message || ""}`.trim();
|
|
|
32229
32229
|
const availableMem = darwinAvail != null ? darwinAvail : freeMem;
|
|
32230
32230
|
return { totalMem, freeMem, availableMem };
|
|
32231
32231
|
}
|
|
32232
|
+
var LIVE_LIFECYCLES = /* @__PURE__ */ new Set(["starting", "running", "stopping", "interrupted"]);
|
|
32233
|
+
function isSessionHostLiveRuntime(record2) {
|
|
32234
|
+
const lifecycle = String(record2?.lifecycle || "").trim();
|
|
32235
|
+
return LIVE_LIFECYCLES.has(lifecycle);
|
|
32236
|
+
}
|
|
32237
|
+
function getSessionHostRecoveryLabel(meta3) {
|
|
32238
|
+
const recoveryState = typeof meta3?.runtimeRecoveryState === "string" ? String(meta3.runtimeRecoveryState).trim() : "";
|
|
32239
|
+
if (!recoveryState) return null;
|
|
32240
|
+
if (recoveryState === "auto_resumed") return "restored after restart";
|
|
32241
|
+
if (recoveryState === "resume_failed") return "restore failed";
|
|
32242
|
+
if (recoveryState === "host_restart_interrupted") return "host restart interrupted";
|
|
32243
|
+
if (recoveryState === "orphan_snapshot") return "snapshot recovered";
|
|
32244
|
+
return recoveryState.replace(/_/g, " ");
|
|
32245
|
+
}
|
|
32246
|
+
function isSessionHostRecoverySnapshot(record2) {
|
|
32247
|
+
if (!record2) return false;
|
|
32248
|
+
if (isSessionHostLiveRuntime(record2)) return false;
|
|
32249
|
+
const lifecycle = String(record2.lifecycle || "").trim();
|
|
32250
|
+
if (lifecycle && lifecycle !== "stopped" && lifecycle !== "failed") {
|
|
32251
|
+
return false;
|
|
32252
|
+
}
|
|
32253
|
+
const meta3 = record2.meta || void 0;
|
|
32254
|
+
if (meta3?.restoredFromStorage === true) return true;
|
|
32255
|
+
return getSessionHostRecoveryLabel(meta3) !== null;
|
|
32256
|
+
}
|
|
32257
|
+
function getSessionHostSurfaceKind(record2) {
|
|
32258
|
+
if (isSessionHostLiveRuntime(record2)) return "live_runtime";
|
|
32259
|
+
if (isSessionHostRecoverySnapshot(record2)) return "recovery_snapshot";
|
|
32260
|
+
return "inactive_record";
|
|
32261
|
+
}
|
|
32262
|
+
function partitionSessionHostRecords(records) {
|
|
32263
|
+
const liveRuntimes = [];
|
|
32264
|
+
const recoverySnapshots = [];
|
|
32265
|
+
const inactiveRecords = [];
|
|
32266
|
+
for (const record2 of records) {
|
|
32267
|
+
const kind = getSessionHostSurfaceKind(record2);
|
|
32268
|
+
if (kind === "live_runtime") {
|
|
32269
|
+
liveRuntimes.push(record2);
|
|
32270
|
+
} else if (kind === "recovery_snapshot") {
|
|
32271
|
+
recoverySnapshots.push(record2);
|
|
32272
|
+
} else {
|
|
32273
|
+
inactiveRecords.push(record2);
|
|
32274
|
+
}
|
|
32275
|
+
}
|
|
32276
|
+
return {
|
|
32277
|
+
liveRuntimes,
|
|
32278
|
+
recoverySnapshots,
|
|
32279
|
+
inactiveRecords
|
|
32280
|
+
};
|
|
32281
|
+
}
|
|
32282
|
+
function partitionSessionHostDiagnosticsSessions(records) {
|
|
32283
|
+
return partitionSessionHostRecords(records || []);
|
|
32284
|
+
}
|
|
32232
32285
|
var DEFAULT_ACTIVE_CHAT_POLL_STATUSES = /* @__PURE__ */ new Set([
|
|
32233
32286
|
"generating",
|
|
32234
32287
|
"waiting_approval",
|
|
32235
32288
|
"starting"
|
|
32236
32289
|
]);
|
|
32237
32290
|
var DEFAULT_CHAT_TAIL_RECENT_MESSAGE_GRACE_MS = 8e3;
|
|
32291
|
+
var LIVE_RUNTIME_LIFECYCLES = /* @__PURE__ */ new Set(["starting", "running", "stopping", "interrupted"]);
|
|
32238
32292
|
function parseMessageTimestamp(value) {
|
|
32239
32293
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
32240
32294
|
if (typeof value === "string") {
|
|
@@ -32243,6 +32297,23 @@ ${data.message || ""}`.trim();
|
|
|
32243
32297
|
}
|
|
32244
32298
|
return 0;
|
|
32245
32299
|
}
|
|
32300
|
+
function isDefinitelyNonLiveRuntimeSession(session) {
|
|
32301
|
+
const surfaceKind = String(session?.runtimeSurfaceKind || "").trim();
|
|
32302
|
+
if (surfaceKind === "live_runtime") return false;
|
|
32303
|
+
if (surfaceKind === "recovery_snapshot") return true;
|
|
32304
|
+
if (surfaceKind === "inactive_record") return false;
|
|
32305
|
+
const lifecycle = String(session?.runtimeLifecycle || "").trim();
|
|
32306
|
+
if (lifecycle && LIVE_RUNTIME_LIFECYCLES.has(lifecycle)) return false;
|
|
32307
|
+
const inferredSurfaceKind = getSessionHostSurfaceKind({
|
|
32308
|
+
lifecycle: lifecycle || null,
|
|
32309
|
+
meta: {
|
|
32310
|
+
restoredFromStorage: session?.runtimeRestoredFromStorage === true,
|
|
32311
|
+
...session?.runtimeRecoveryState ? { runtimeRecoveryState: session.runtimeRecoveryState } : {}
|
|
32312
|
+
}
|
|
32313
|
+
});
|
|
32314
|
+
if (inferredSurfaceKind === "recovery_snapshot") return true;
|
|
32315
|
+
return false;
|
|
32316
|
+
}
|
|
32246
32317
|
function classifyHotChatSessionsForSubscriptionFlush2(sessions, previousHotSessionIds, options = {}) {
|
|
32247
32318
|
const now = options.now ?? Date.now();
|
|
32248
32319
|
const recentMessageGraceMs = Math.max(
|
|
@@ -32251,9 +32322,14 @@ ${data.message || ""}`.trim();
|
|
|
32251
32322
|
);
|
|
32252
32323
|
const activeStatuses = options.activeStatuses ?? DEFAULT_ACTIVE_CHAT_POLL_STATUSES;
|
|
32253
32324
|
const active = /* @__PURE__ */ new Set();
|
|
32325
|
+
const excluded = /* @__PURE__ */ new Set();
|
|
32254
32326
|
for (const session of sessions) {
|
|
32255
32327
|
const sessionId = typeof session?.id === "string" ? session.id : "";
|
|
32256
32328
|
if (!sessionId) continue;
|
|
32329
|
+
if (isDefinitelyNonLiveRuntimeSession(session)) {
|
|
32330
|
+
excluded.add(sessionId);
|
|
32331
|
+
continue;
|
|
32332
|
+
}
|
|
32257
32333
|
const status = String(session?.status || "").toLowerCase();
|
|
32258
32334
|
const lastMessageAt = parseMessageTimestamp(session?.lastMessageAt);
|
|
32259
32335
|
const recentlyUpdated = lastMessageAt > 0 && now - lastMessageAt <= recentMessageGraceMs;
|
|
@@ -32262,7 +32338,7 @@ ${data.message || ""}`.trim();
|
|
|
32262
32338
|
}
|
|
32263
32339
|
}
|
|
32264
32340
|
const finalizing = new Set(
|
|
32265
|
-
Array.from(previousHotSessionIds).filter((sessionId) => !active.has(sessionId))
|
|
32341
|
+
Array.from(previousHotSessionIds).filter((sessionId) => !active.has(sessionId) && !excluded.has(sessionId))
|
|
32266
32342
|
);
|
|
32267
32343
|
return { active, finalizing };
|
|
32268
32344
|
}
|
|
@@ -36481,7 +36557,7 @@ ${effect.notification.body || ""}`.trim();
|
|
|
36481
36557
|
return profile !== "live";
|
|
36482
36558
|
}
|
|
36483
36559
|
function shouldIncludeRuntimeMetadata(profile) {
|
|
36484
|
-
return
|
|
36560
|
+
return true;
|
|
36485
36561
|
}
|
|
36486
36562
|
function findCdpManager(cdpManagers, key) {
|
|
36487
36563
|
const exact = cdpManagers.get(key);
|
|
@@ -36636,8 +36712,12 @@ ${effect.notification.body || ""}`.trim();
|
|
|
36636
36712
|
runtimeKey: state.runtime?.runtimeKey,
|
|
36637
36713
|
runtimeDisplayName: state.runtime?.displayName,
|
|
36638
36714
|
runtimeWorkspaceLabel: state.runtime?.workspaceLabel,
|
|
36715
|
+
runtimeLifecycle: state.runtime?.lifecycle ?? null,
|
|
36716
|
+
runtimeSurfaceKind: state.runtime?.surfaceKind,
|
|
36639
36717
|
runtimeWriteOwner: state.runtime?.writeOwner || null,
|
|
36640
|
-
runtimeAttachedClients: state.runtime?.attachedClients || []
|
|
36718
|
+
runtimeAttachedClients: state.runtime?.attachedClients || [],
|
|
36719
|
+
runtimeRestoredFromStorage: state.runtime?.restoredFromStorage === true,
|
|
36720
|
+
runtimeRecoveryState: state.runtime?.recoveryState ?? null
|
|
36641
36721
|
},
|
|
36642
36722
|
mode: state.mode,
|
|
36643
36723
|
resume: state.resume,
|
|
@@ -39884,8 +39964,12 @@ ${effect.notification.body || ""}`.trim();
|
|
|
39884
39964
|
runtimeKey: runtime.runtimeKey,
|
|
39885
39965
|
displayName: runtime.displayName,
|
|
39886
39966
|
workspaceLabel: runtime.workspaceLabel,
|
|
39967
|
+
lifecycle: runtime.lifecycle ?? null,
|
|
39968
|
+
surfaceKind: runtime.surfaceKind,
|
|
39887
39969
|
writeOwner: runtime.writeOwner || null,
|
|
39888
|
-
attachedClients: runtime.attachedClients || []
|
|
39970
|
+
attachedClients: runtime.attachedClients || [],
|
|
39971
|
+
restoredFromStorage: runtime.restoredFromStorage === true,
|
|
39972
|
+
recoveryState: runtime.recoveryState ?? null
|
|
39889
39973
|
} : void 0,
|
|
39890
39974
|
resume: this.provider.resume,
|
|
39891
39975
|
controlValues: surface.controlValues,
|
|
@@ -44116,10 +44200,15 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
44116
44200
|
}
|
|
44117
44201
|
var SKIP_COMMANDS = /* @__PURE__ */ new Set([
|
|
44118
44202
|
"heartbeat",
|
|
44119
|
-
"status_report"
|
|
44203
|
+
"status_report",
|
|
44204
|
+
"read_chat",
|
|
44205
|
+
"mark_session_seen"
|
|
44120
44206
|
]);
|
|
44207
|
+
function shouldLogCommand(cmd) {
|
|
44208
|
+
return !SKIP_COMMANDS.has(cmd);
|
|
44209
|
+
}
|
|
44121
44210
|
function logCommand(entry) {
|
|
44122
|
-
if (
|
|
44211
|
+
if (!shouldLogCommand(entry.cmd)) return;
|
|
44123
44212
|
try {
|
|
44124
44213
|
if (++writeCount2 % 500 === 0) {
|
|
44125
44214
|
checkRotation();
|
|
@@ -44167,59 +44256,6 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
44167
44256
|
}
|
|
44168
44257
|
cleanOldFiles();
|
|
44169
44258
|
init_logger();
|
|
44170
|
-
var LIVE_LIFECYCLES = /* @__PURE__ */ new Set(["starting", "running", "stopping", "interrupted"]);
|
|
44171
|
-
function isSessionHostLiveRuntime(record2) {
|
|
44172
|
-
const lifecycle = String(record2?.lifecycle || "").trim();
|
|
44173
|
-
return LIVE_LIFECYCLES.has(lifecycle);
|
|
44174
|
-
}
|
|
44175
|
-
function getSessionHostRecoveryLabel(meta3) {
|
|
44176
|
-
const recoveryState = typeof meta3?.runtimeRecoveryState === "string" ? String(meta3.runtimeRecoveryState).trim() : "";
|
|
44177
|
-
if (!recoveryState) return null;
|
|
44178
|
-
if (recoveryState === "auto_resumed") return "restored after restart";
|
|
44179
|
-
if (recoveryState === "resume_failed") return "restore failed";
|
|
44180
|
-
if (recoveryState === "host_restart_interrupted") return "host restart interrupted";
|
|
44181
|
-
if (recoveryState === "orphan_snapshot") return "snapshot recovered";
|
|
44182
|
-
return recoveryState.replace(/_/g, " ");
|
|
44183
|
-
}
|
|
44184
|
-
function isSessionHostRecoverySnapshot(record2) {
|
|
44185
|
-
if (!record2) return false;
|
|
44186
|
-
if (isSessionHostLiveRuntime(record2)) return false;
|
|
44187
|
-
const lifecycle = String(record2.lifecycle || "").trim();
|
|
44188
|
-
if (lifecycle && lifecycle !== "stopped" && lifecycle !== "failed") {
|
|
44189
|
-
return false;
|
|
44190
|
-
}
|
|
44191
|
-
const meta3 = record2.meta || void 0;
|
|
44192
|
-
if (meta3?.restoredFromStorage === true) return true;
|
|
44193
|
-
return getSessionHostRecoveryLabel(meta3) !== null;
|
|
44194
|
-
}
|
|
44195
|
-
function getSessionHostSurfaceKind(record2) {
|
|
44196
|
-
if (isSessionHostLiveRuntime(record2)) return "live_runtime";
|
|
44197
|
-
if (isSessionHostRecoverySnapshot(record2)) return "recovery_snapshot";
|
|
44198
|
-
return "inactive_record";
|
|
44199
|
-
}
|
|
44200
|
-
function partitionSessionHostRecords(records) {
|
|
44201
|
-
const liveRuntimes = [];
|
|
44202
|
-
const recoverySnapshots = [];
|
|
44203
|
-
const inactiveRecords = [];
|
|
44204
|
-
for (const record2 of records) {
|
|
44205
|
-
const kind = getSessionHostSurfaceKind(record2);
|
|
44206
|
-
if (kind === "live_runtime") {
|
|
44207
|
-
liveRuntimes.push(record2);
|
|
44208
|
-
} else if (kind === "recovery_snapshot") {
|
|
44209
|
-
recoverySnapshots.push(record2);
|
|
44210
|
-
} else {
|
|
44211
|
-
inactiveRecords.push(record2);
|
|
44212
|
-
}
|
|
44213
|
-
}
|
|
44214
|
-
return {
|
|
44215
|
-
liveRuntimes,
|
|
44216
|
-
recoverySnapshots,
|
|
44217
|
-
inactiveRecords
|
|
44218
|
-
};
|
|
44219
|
-
}
|
|
44220
|
-
function partitionSessionHostDiagnosticsSessions(records) {
|
|
44221
|
-
return partitionSessionHostRecords(records || []);
|
|
44222
|
-
}
|
|
44223
44259
|
var os16 = __toESM2(require("os"));
|
|
44224
44260
|
init_config();
|
|
44225
44261
|
init_terminal_screen();
|
|
@@ -52547,6 +52583,8 @@ data: ${JSON.stringify(msg.data)}
|
|
|
52547
52583
|
runtimeKey: record2.runtimeKey,
|
|
52548
52584
|
displayName: record2.displayName,
|
|
52549
52585
|
workspaceLabel: record2.workspaceLabel,
|
|
52586
|
+
lifecycle: typeof record2.lifecycle === "string" ? record2.lifecycle : null,
|
|
52587
|
+
surfaceKind: record2.surfaceKind,
|
|
52550
52588
|
writeOwner: record2.writeOwner ? {
|
|
52551
52589
|
clientId: record2.writeOwner.clientId,
|
|
52552
52590
|
ownerType: record2.writeOwner.ownerType
|
|
@@ -53149,6 +53187,7 @@ var import_ws = require("ws");
|
|
|
53149
53187
|
var path4 = __toESM(require("path"));
|
|
53150
53188
|
var fs3 = __toESM(require("fs"));
|
|
53151
53189
|
var os5 = __toESM(require("os"));
|
|
53190
|
+
var import_crypto2 = require("crypto");
|
|
53152
53191
|
var import_daemon_core2 = __toESM(require_dist2());
|
|
53153
53192
|
|
|
53154
53193
|
// src/session-host.ts
|
|
@@ -53654,6 +53693,165 @@ async function getWorkspaceSocketInfo(workspaceName) {
|
|
|
53654
53693
|
var import_daemon_core3 = __toESM(require_dist2());
|
|
53655
53694
|
var DEFAULT_PORT = 3847;
|
|
53656
53695
|
var STATUS_INTERVAL = 2e3;
|
|
53696
|
+
var STANDALONE_AUTH_SESSION_COOKIE = "adhdev_standalone_session";
|
|
53697
|
+
var STANDALONE_PASSWORD_CONFIG_FILE = "standalone-auth.json";
|
|
53698
|
+
var STANDALONE_BIND_HOST_CONFIG_FILE = "standalone-network.json";
|
|
53699
|
+
var STANDALONE_BIND_HOST_DEFAULT = "127.0.0.1";
|
|
53700
|
+
var PASSWORD_KEYLEN = 64;
|
|
53701
|
+
var DEFAULT_SESSION_TTL_MS = 1e3 * 60 * 60 * 24 * 30;
|
|
53702
|
+
function getStandalonePasswordConfigPath() {
|
|
53703
|
+
const dir = path4.join(os5.homedir(), ".adhdev");
|
|
53704
|
+
if (!fs3.existsSync(dir)) {
|
|
53705
|
+
fs3.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
53706
|
+
}
|
|
53707
|
+
return path4.join(dir, STANDALONE_PASSWORD_CONFIG_FILE);
|
|
53708
|
+
}
|
|
53709
|
+
function getStandaloneConfigJsonPath() {
|
|
53710
|
+
const dir = path4.join(os5.homedir(), ".adhdev");
|
|
53711
|
+
if (!fs3.existsSync(dir)) {
|
|
53712
|
+
fs3.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
53713
|
+
}
|
|
53714
|
+
return path4.join(dir, STANDALONE_BIND_HOST_CONFIG_FILE);
|
|
53715
|
+
}
|
|
53716
|
+
function loadStandaloneBindHostPreference() {
|
|
53717
|
+
try {
|
|
53718
|
+
const configPath = getStandaloneConfigJsonPath();
|
|
53719
|
+
if (!fs3.existsSync(configPath)) return STANDALONE_BIND_HOST_DEFAULT;
|
|
53720
|
+
const parsed = JSON.parse(fs3.readFileSync(configPath, "utf8"));
|
|
53721
|
+
return parsed?.standaloneBindHost === "0.0.0.0" ? "0.0.0.0" : STANDALONE_BIND_HOST_DEFAULT;
|
|
53722
|
+
} catch {
|
|
53723
|
+
return STANDALONE_BIND_HOST_DEFAULT;
|
|
53724
|
+
}
|
|
53725
|
+
}
|
|
53726
|
+
function saveStandaloneBindHostPreference(bindHost) {
|
|
53727
|
+
const configPath = getStandaloneConfigJsonPath();
|
|
53728
|
+
let parsed = {};
|
|
53729
|
+
try {
|
|
53730
|
+
if (fs3.existsSync(configPath)) {
|
|
53731
|
+
const raw = fs3.readFileSync(configPath, "utf8");
|
|
53732
|
+
const next = JSON.parse(raw);
|
|
53733
|
+
if (next && typeof next === "object" && !Array.isArray(next)) parsed = next;
|
|
53734
|
+
}
|
|
53735
|
+
} catch {
|
|
53736
|
+
parsed = {};
|
|
53737
|
+
}
|
|
53738
|
+
parsed.standaloneBindHost = bindHost;
|
|
53739
|
+
fs3.writeFileSync(configPath, JSON.stringify(parsed, null, 2), { encoding: "utf8", mode: 384 });
|
|
53740
|
+
try {
|
|
53741
|
+
fs3.chmodSync(configPath, 384);
|
|
53742
|
+
} catch {
|
|
53743
|
+
}
|
|
53744
|
+
return bindHost;
|
|
53745
|
+
}
|
|
53746
|
+
function createPasswordRecord(password, salt = (0, import_crypto2.randomBytes)(16).toString("hex")) {
|
|
53747
|
+
return {
|
|
53748
|
+
passwordHash: (0, import_crypto2.scryptSync)(`${password || ""}`, salt, PASSWORD_KEYLEN).toString("hex"),
|
|
53749
|
+
passwordSalt: salt,
|
|
53750
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
53751
|
+
};
|
|
53752
|
+
}
|
|
53753
|
+
function verifyPassword(password, config2) {
|
|
53754
|
+
if (!config2?.passwordHash || !config2.passwordSalt) return false;
|
|
53755
|
+
const actual = Buffer.from((0, import_crypto2.scryptSync)(`${password || ""}`, config2.passwordSalt, PASSWORD_KEYLEN).toString("hex"), "utf8");
|
|
53756
|
+
const expected = Buffer.from(config2.passwordHash, "utf8");
|
|
53757
|
+
return actual.length === expected.length && (0, import_crypto2.timingSafeEqual)(actual, expected);
|
|
53758
|
+
}
|
|
53759
|
+
function loadStandalonePasswordConfig(filePath = getStandalonePasswordConfigPath()) {
|
|
53760
|
+
if (!fs3.existsSync(filePath)) return null;
|
|
53761
|
+
try {
|
|
53762
|
+
const parsed = JSON.parse(fs3.readFileSync(filePath, "utf8"));
|
|
53763
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
53764
|
+
if (typeof parsed.passwordHash !== "string" || typeof parsed.passwordSalt !== "string") return null;
|
|
53765
|
+
return {
|
|
53766
|
+
passwordHash: parsed.passwordHash,
|
|
53767
|
+
passwordSalt: parsed.passwordSalt,
|
|
53768
|
+
updatedAt: typeof parsed.updatedAt === "string" ? parsed.updatedAt : (/* @__PURE__ */ new Date(0)).toISOString()
|
|
53769
|
+
};
|
|
53770
|
+
} catch {
|
|
53771
|
+
return null;
|
|
53772
|
+
}
|
|
53773
|
+
}
|
|
53774
|
+
function saveStandalonePasswordConfig(filePath, config2) {
|
|
53775
|
+
const dir = path4.dirname(filePath);
|
|
53776
|
+
if (!fs3.existsSync(dir)) {
|
|
53777
|
+
fs3.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
53778
|
+
}
|
|
53779
|
+
fs3.writeFileSync(filePath, JSON.stringify(config2, null, 2), { encoding: "utf8", mode: 384 });
|
|
53780
|
+
try {
|
|
53781
|
+
fs3.chmodSync(filePath, 384);
|
|
53782
|
+
} catch {
|
|
53783
|
+
}
|
|
53784
|
+
}
|
|
53785
|
+
function clearStandalonePasswordConfig(filePath = getStandalonePasswordConfigPath()) {
|
|
53786
|
+
if (fs3.existsSync(filePath)) {
|
|
53787
|
+
fs3.rmSync(filePath, { force: true });
|
|
53788
|
+
}
|
|
53789
|
+
}
|
|
53790
|
+
function shouldWarnForPublicUnauthenticatedHost(input) {
|
|
53791
|
+
return input.host === "0.0.0.0" && !input.hasTokenAuth && !input.hasPasswordAuth;
|
|
53792
|
+
}
|
|
53793
|
+
function parseCookies(cookieHeader) {
|
|
53794
|
+
if (!cookieHeader) return {};
|
|
53795
|
+
return Object.fromEntries(
|
|
53796
|
+
cookieHeader.split(";").map((part) => part.trim()).filter(Boolean).map((part) => {
|
|
53797
|
+
const eq = part.indexOf("=");
|
|
53798
|
+
if (eq === -1) return [part, ""];
|
|
53799
|
+
return [part.slice(0, eq), decodeURIComponent(part.slice(eq + 1))];
|
|
53800
|
+
})
|
|
53801
|
+
);
|
|
53802
|
+
}
|
|
53803
|
+
function buildSessionCookie(sessionId, secure, maxAgeMs = DEFAULT_SESSION_TTL_MS) {
|
|
53804
|
+
const parts = [
|
|
53805
|
+
`${STANDALONE_AUTH_SESSION_COOKIE}=${encodeURIComponent(sessionId)}`,
|
|
53806
|
+
"Path=/",
|
|
53807
|
+
"HttpOnly",
|
|
53808
|
+
"SameSite=Lax",
|
|
53809
|
+
`Max-Age=${Math.max(0, Math.floor(maxAgeMs / 1e3))}`
|
|
53810
|
+
];
|
|
53811
|
+
if (secure) parts.push("Secure");
|
|
53812
|
+
return parts.join("; ");
|
|
53813
|
+
}
|
|
53814
|
+
function buildClearedSessionCookie(secure) {
|
|
53815
|
+
return buildSessionCookie("", secure, 0);
|
|
53816
|
+
}
|
|
53817
|
+
var StandaloneSessionStore = class {
|
|
53818
|
+
sessions = /* @__PURE__ */ new Map();
|
|
53819
|
+
create(ttlMs = DEFAULT_SESSION_TTL_MS) {
|
|
53820
|
+
const id = (0, import_crypto2.randomBytes)(24).toString("hex");
|
|
53821
|
+
this.sessions.set(id, Date.now() + ttlMs);
|
|
53822
|
+
return id;
|
|
53823
|
+
}
|
|
53824
|
+
has(sessionId) {
|
|
53825
|
+
if (!sessionId) return false;
|
|
53826
|
+
const expiresAt = this.sessions.get(sessionId);
|
|
53827
|
+
if (!expiresAt) return false;
|
|
53828
|
+
if (expiresAt <= Date.now()) {
|
|
53829
|
+
this.sessions.delete(sessionId);
|
|
53830
|
+
return false;
|
|
53831
|
+
}
|
|
53832
|
+
return true;
|
|
53833
|
+
}
|
|
53834
|
+
revoke(sessionId) {
|
|
53835
|
+
if (!sessionId) return;
|
|
53836
|
+
this.sessions.delete(sessionId);
|
|
53837
|
+
}
|
|
53838
|
+
clear() {
|
|
53839
|
+
this.sessions.clear();
|
|
53840
|
+
}
|
|
53841
|
+
};
|
|
53842
|
+
function isStandaloneRequestAuthenticated(input) {
|
|
53843
|
+
const hasTokenAuth = !!input.configuredToken;
|
|
53844
|
+
const hasPasswordAuth = !!input.passwordConfig;
|
|
53845
|
+
if (!hasTokenAuth && !hasPasswordAuth) return true;
|
|
53846
|
+
if (hasTokenAuth && (input.bearerToken === input.configuredToken || input.queryToken === input.configuredToken)) {
|
|
53847
|
+
return true;
|
|
53848
|
+
}
|
|
53849
|
+
if (hasPasswordAuth) {
|
|
53850
|
+
const cookies = parseCookies(input.cookieHeader);
|
|
53851
|
+
return input.sessionStore.has(cookies[STANDALONE_AUTH_SESSION_COOKIE]);
|
|
53852
|
+
}
|
|
53853
|
+
return false;
|
|
53854
|
+
}
|
|
53657
53855
|
var pkgVersion = process.env.ADHDEV_PKG_VERSION || "unknown";
|
|
53658
53856
|
if (pkgVersion === "unknown") {
|
|
53659
53857
|
try {
|
|
@@ -53702,6 +53900,10 @@ var StandaloneServer = class {
|
|
|
53702
53900
|
wsSessionModalSubscriptions = /* @__PURE__ */ new Map();
|
|
53703
53901
|
wsDaemonMetadataSubscriptions = /* @__PURE__ */ new Map();
|
|
53704
53902
|
authToken = null;
|
|
53903
|
+
passwordConfigPath = getStandalonePasswordConfigPath();
|
|
53904
|
+
passwordConfig = null;
|
|
53905
|
+
authSessions = new StandaloneSessionStore();
|
|
53906
|
+
listenHost = "127.0.0.1";
|
|
53705
53907
|
statusTimer = null;
|
|
53706
53908
|
lastStatusBroadcastAt = 0;
|
|
53707
53909
|
statusBroadcastPending = false;
|
|
@@ -53758,10 +53960,88 @@ var StandaloneServer = class {
|
|
|
53758
53960
|
const mode = this.getCliPresentationMode(sessionId);
|
|
53759
53961
|
return mode === "chat" || mode === "terminal";
|
|
53760
53962
|
}
|
|
53963
|
+
hasPasswordAuth() {
|
|
53964
|
+
return !!this.passwordConfig;
|
|
53965
|
+
}
|
|
53966
|
+
hasAnyAuth() {
|
|
53967
|
+
return !!this.authToken || this.hasPasswordAuth();
|
|
53968
|
+
}
|
|
53969
|
+
getCookieSecureFlag(req) {
|
|
53970
|
+
const forwardedProto = req.headers["x-forwarded-proto"];
|
|
53971
|
+
return !!req.socket.encrypted || typeof forwardedProto === "string" && forwardedProto.toLowerCase().includes("https");
|
|
53972
|
+
}
|
|
53973
|
+
getRequestTokens(req, rawUrl) {
|
|
53974
|
+
const authHeader = req.headers["authorization"];
|
|
53975
|
+
const bearerToken = typeof authHeader === "string" && authHeader.startsWith("Bearer ") ? authHeader.slice(7) : null;
|
|
53976
|
+
const queryToken = new URL(rawUrl, `http://${req.headers.host || "localhost"}`).searchParams.get("token");
|
|
53977
|
+
return { bearerToken, queryToken };
|
|
53978
|
+
}
|
|
53979
|
+
isRequestAuthenticated(req, rawUrl) {
|
|
53980
|
+
const { bearerToken, queryToken } = this.getRequestTokens(req, rawUrl);
|
|
53981
|
+
return isStandaloneRequestAuthenticated({
|
|
53982
|
+
configuredToken: this.authToken,
|
|
53983
|
+
passwordConfig: this.passwordConfig,
|
|
53984
|
+
bearerToken,
|
|
53985
|
+
queryToken,
|
|
53986
|
+
cookieHeader: typeof req.headers.cookie === "string" ? req.headers.cookie : void 0,
|
|
53987
|
+
sessionStore: this.authSessions
|
|
53988
|
+
});
|
|
53989
|
+
}
|
|
53990
|
+
getRequestSessionId(req) {
|
|
53991
|
+
const cookies = parseCookies(typeof req.headers.cookie === "string" ? req.headers.cookie : void 0);
|
|
53992
|
+
return cookies.adhdev_standalone_session || null;
|
|
53993
|
+
}
|
|
53994
|
+
buildAuthStatus(req, rawUrl) {
|
|
53995
|
+
const required2 = this.hasAnyAuth();
|
|
53996
|
+
return {
|
|
53997
|
+
required: required2,
|
|
53998
|
+
authenticated: this.isRequestAuthenticated(req, rawUrl),
|
|
53999
|
+
hasTokenAuth: !!this.authToken,
|
|
54000
|
+
hasPasswordAuth: this.hasPasswordAuth(),
|
|
54001
|
+
publicHostWarning: shouldWarnForPublicUnauthenticatedHost({
|
|
54002
|
+
host: this.listenHost,
|
|
54003
|
+
hasTokenAuth: !!this.authToken,
|
|
54004
|
+
hasPasswordAuth: this.hasPasswordAuth()
|
|
54005
|
+
}),
|
|
54006
|
+
boundHost: this.listenHost
|
|
54007
|
+
};
|
|
54008
|
+
}
|
|
54009
|
+
isTrustedStandaloneMutationRequest(req) {
|
|
54010
|
+
const originHeader = req.headers.origin;
|
|
54011
|
+
if (typeof originHeader !== "string" || !originHeader.trim()) return true;
|
|
54012
|
+
try {
|
|
54013
|
+
const origin = new URL(originHeader);
|
|
54014
|
+
const host = req.headers.host || "";
|
|
54015
|
+
return origin.host === host;
|
|
54016
|
+
} catch {
|
|
54017
|
+
return false;
|
|
54018
|
+
}
|
|
54019
|
+
}
|
|
54020
|
+
async readJsonBody(req) {
|
|
54021
|
+
return await new Promise((resolve4, reject) => {
|
|
54022
|
+
let body = "";
|
|
54023
|
+
req.on("data", (chunk) => {
|
|
54024
|
+
body += chunk;
|
|
54025
|
+
});
|
|
54026
|
+
req.on("end", () => {
|
|
54027
|
+
try {
|
|
54028
|
+
resolve4(body ? JSON.parse(body) : {});
|
|
54029
|
+
} catch (error48) {
|
|
54030
|
+
reject(error48);
|
|
54031
|
+
}
|
|
54032
|
+
});
|
|
54033
|
+
req.on("error", reject);
|
|
54034
|
+
});
|
|
54035
|
+
}
|
|
53761
54036
|
async start(options = {}) {
|
|
53762
|
-
const
|
|
53763
|
-
const host = options.host || "127.0.0.1";
|
|
54037
|
+
const persistedStandaloneBindHost = loadStandaloneBindHostPreference();
|
|
53764
54038
|
const cfg = (0, import_daemon_core2.loadConfig)();
|
|
54039
|
+
if (!options.host && persistedStandaloneBindHost !== STANDALONE_BIND_HOST_DEFAULT) {
|
|
54040
|
+
saveStandaloneBindHostPreference(persistedStandaloneBindHost);
|
|
54041
|
+
}
|
|
54042
|
+
const port = options.port || DEFAULT_PORT;
|
|
54043
|
+
const host = options.host || persistedStandaloneBindHost;
|
|
54044
|
+
this.listenHost = host;
|
|
53765
54045
|
const sessionHostEndpoint = await ensureSessionHostReady();
|
|
53766
54046
|
this.sessionHostEndpoint = sessionHostEndpoint;
|
|
53767
54047
|
const sessionHostControl = new StandaloneSessionHostControlPlane(
|
|
@@ -53769,6 +54049,7 @@ var StandaloneServer = class {
|
|
|
53769
54049
|
);
|
|
53770
54050
|
this.sessionHostControl = sessionHostControl;
|
|
53771
54051
|
this.authToken = options.token || process.env.ADHDEV_TOKEN || null;
|
|
54052
|
+
this.passwordConfig = loadStandalonePasswordConfig(this.passwordConfigPath);
|
|
53772
54053
|
const statusInstanceId = `standalone_${cfg.machineId || "mach_unknown"}`;
|
|
53773
54054
|
this.components = await (0, import_daemon_core2.initDaemonComponents)({
|
|
53774
54055
|
cliManagerDeps: {
|
|
@@ -53842,13 +54123,10 @@ var StandaloneServer = class {
|
|
|
53842
54123
|
this.httpServer.on("upgrade", (req, socket, head) => {
|
|
53843
54124
|
const wsUrl = new URL(req.url || "/", `http://${req.headers.host || "localhost"}`);
|
|
53844
54125
|
if (wsUrl.pathname === "/ws") {
|
|
53845
|
-
if (this.
|
|
53846
|
-
|
|
53847
|
-
|
|
53848
|
-
|
|
53849
|
-
socket.destroy();
|
|
53850
|
-
return;
|
|
53851
|
-
}
|
|
54126
|
+
if (!this.isRequestAuthenticated(req, req.url || "/")) {
|
|
54127
|
+
socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
|
|
54128
|
+
socket.destroy();
|
|
54129
|
+
return;
|
|
53852
54130
|
}
|
|
53853
54131
|
this.wss.handleUpgrade(req, socket, head, (ws2) => {
|
|
53854
54132
|
this.handleWsConnection(ws2);
|
|
@@ -53881,7 +54159,14 @@ var StandaloneServer = class {
|
|
|
53881
54159
|
}
|
|
53882
54160
|
}
|
|
53883
54161
|
if (this.authToken) {
|
|
53884
|
-
console.log(
|
|
54162
|
+
console.log(" \u{1F511} Token auth: enabled");
|
|
54163
|
+
}
|
|
54164
|
+
if (this.passwordConfig) {
|
|
54165
|
+
console.log(" \u{1F510} Password auth: enabled");
|
|
54166
|
+
}
|
|
54167
|
+
if (shouldWarnForPublicUnauthenticatedHost({ host, hasTokenAuth: !!this.authToken, hasPasswordAuth: !!this.passwordConfig })) {
|
|
54168
|
+
console.warn(" \u26A0\uFE0F Public host mode is enabled without any auth.");
|
|
54169
|
+
console.warn(" Anyone on your LAN can open and control this dashboard until you set a password or token.");
|
|
53885
54170
|
}
|
|
53886
54171
|
console.log("");
|
|
53887
54172
|
const cdpCount = [...this.components.cdpManagers.values()].filter((m) => m.isConnected).length;
|
|
@@ -53921,18 +54206,148 @@ var StandaloneServer = class {
|
|
|
53921
54206
|
res.end();
|
|
53922
54207
|
return;
|
|
53923
54208
|
}
|
|
53924
|
-
|
|
53925
|
-
|
|
53926
|
-
|
|
53927
|
-
|
|
53928
|
-
|
|
53929
|
-
|
|
53930
|
-
|
|
53931
|
-
|
|
53932
|
-
|
|
54209
|
+
const parsedUrl = new URL(url2, `http://${req.headers.host || "localhost"}`);
|
|
54210
|
+
if (parsedUrl.pathname === "/auth/session" && method === "GET") {
|
|
54211
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
54212
|
+
res.end(JSON.stringify(this.buildAuthStatus(req, url2)));
|
|
54213
|
+
return;
|
|
54214
|
+
}
|
|
54215
|
+
if (parsedUrl.pathname === "/auth/login" && method === "POST") {
|
|
54216
|
+
void (async () => {
|
|
54217
|
+
if (!this.passwordConfig) {
|
|
54218
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
54219
|
+
res.end(JSON.stringify({ error: "Password auth is not configured." }));
|
|
54220
|
+
return;
|
|
54221
|
+
}
|
|
54222
|
+
const body = await this.readJsonBody(req);
|
|
54223
|
+
if (!verifyPassword(typeof body.password === "string" ? body.password : "", this.passwordConfig)) {
|
|
54224
|
+
res.writeHead(401, { "Content-Type": "application/json" });
|
|
54225
|
+
res.end(JSON.stringify({ error: "Incorrect password." }));
|
|
54226
|
+
return;
|
|
54227
|
+
}
|
|
54228
|
+
this.authSessions.clear();
|
|
54229
|
+
const sessionId = this.authSessions.create();
|
|
54230
|
+
res.setHeader("Set-Cookie", buildSessionCookie(sessionId, this.getCookieSecureFlag(req)));
|
|
54231
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
54232
|
+
res.end(JSON.stringify({ ...this.buildAuthStatus(req, url2), authenticated: true }));
|
|
54233
|
+
})().catch((error48) => {
|
|
54234
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
54235
|
+
res.end(JSON.stringify({ error: error48?.message || String(error48) }));
|
|
54236
|
+
});
|
|
54237
|
+
return;
|
|
54238
|
+
}
|
|
54239
|
+
if (parsedUrl.pathname === "/auth/logout" && method === "POST") {
|
|
54240
|
+
this.authSessions.revoke(this.getRequestSessionId(req));
|
|
54241
|
+
res.setHeader("Set-Cookie", buildClearedSessionCookie(this.getCookieSecureFlag(req)));
|
|
54242
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
54243
|
+
res.end(JSON.stringify({ success: true }));
|
|
54244
|
+
return;
|
|
54245
|
+
}
|
|
54246
|
+
if (parsedUrl.pathname === "/auth/password" && method === "POST") {
|
|
54247
|
+
void (async () => {
|
|
54248
|
+
if (!this.hasAnyAuth() && !this.isTrustedStandaloneMutationRequest(req)) {
|
|
54249
|
+
res.writeHead(403, { "Content-Type": "application/json" });
|
|
54250
|
+
res.end(JSON.stringify({ error: "Cross-origin standalone settings changes are not allowed without existing auth." }));
|
|
54251
|
+
return;
|
|
54252
|
+
}
|
|
54253
|
+
if (this.hasAnyAuth() && !this.isRequestAuthenticated(req, url2)) {
|
|
54254
|
+
res.writeHead(401, { "Content-Type": "application/json" });
|
|
54255
|
+
res.end(JSON.stringify({ error: "Unauthorized" }));
|
|
54256
|
+
return;
|
|
54257
|
+
}
|
|
54258
|
+
const body = await this.readJsonBody(req);
|
|
54259
|
+
const currentPassword = typeof body.currentPassword === "string" ? body.currentPassword : "";
|
|
54260
|
+
const newPassword = typeof body.newPassword === "string" ? body.newPassword : "";
|
|
54261
|
+
const clearPassword = body.clear === true;
|
|
54262
|
+
if (this.passwordConfig && !verifyPassword(currentPassword, this.passwordConfig)) {
|
|
54263
|
+
res.writeHead(403, { "Content-Type": "application/json" });
|
|
54264
|
+
res.end(JSON.stringify({ error: "Current password is incorrect." }));
|
|
54265
|
+
return;
|
|
54266
|
+
}
|
|
54267
|
+
if (clearPassword) {
|
|
54268
|
+
clearStandalonePasswordConfig(this.passwordConfigPath);
|
|
54269
|
+
this.passwordConfig = null;
|
|
54270
|
+
this.authSessions.clear();
|
|
54271
|
+
res.setHeader("Set-Cookie", buildClearedSessionCookie(this.getCookieSecureFlag(req)));
|
|
54272
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
54273
|
+
res.end(JSON.stringify({ success: true, ...this.buildAuthStatus(req, url2), authenticated: !this.hasAnyAuth() }));
|
|
54274
|
+
return;
|
|
54275
|
+
}
|
|
54276
|
+
if (newPassword.trim().length < 4) {
|
|
54277
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
54278
|
+
res.end(JSON.stringify({ error: "Password must be at least 4 characters." }));
|
|
54279
|
+
return;
|
|
54280
|
+
}
|
|
54281
|
+
const nextConfig = createPasswordRecord(newPassword.trim());
|
|
54282
|
+
saveStandalonePasswordConfig(this.passwordConfigPath, nextConfig);
|
|
54283
|
+
this.passwordConfig = nextConfig;
|
|
54284
|
+
this.authSessions.clear();
|
|
54285
|
+
const sessionId = this.authSessions.create();
|
|
54286
|
+
res.setHeader("Set-Cookie", buildSessionCookie(sessionId, this.getCookieSecureFlag(req)));
|
|
54287
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
54288
|
+
res.end(JSON.stringify({ success: true, ...this.buildAuthStatus(req, url2), authenticated: true }));
|
|
54289
|
+
})().catch((error48) => {
|
|
54290
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
54291
|
+
res.end(JSON.stringify({ error: error48?.message || String(error48) }));
|
|
54292
|
+
});
|
|
54293
|
+
return;
|
|
54294
|
+
}
|
|
54295
|
+
if (parsedUrl.pathname === "/api/v1/standalone/preferences" && method === "GET") {
|
|
54296
|
+
const configuredBindHost = loadStandaloneBindHostPreference();
|
|
54297
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
54298
|
+
res.end(JSON.stringify({
|
|
54299
|
+
standaloneBindHost: configuredBindHost,
|
|
54300
|
+
currentBindHost: this.listenHost,
|
|
54301
|
+
hasPasswordAuth: !!this.passwordConfig,
|
|
54302
|
+
hasTokenAuth: !!this.authToken,
|
|
54303
|
+
publicHostWarning: shouldWarnForPublicUnauthenticatedHost({
|
|
54304
|
+
host: configuredBindHost,
|
|
54305
|
+
hasTokenAuth: !!this.authToken,
|
|
54306
|
+
hasPasswordAuth: !!this.passwordConfig
|
|
54307
|
+
})
|
|
54308
|
+
}));
|
|
54309
|
+
return;
|
|
54310
|
+
}
|
|
54311
|
+
if (parsedUrl.pathname === "/api/v1/standalone/preferences" && method === "POST") {
|
|
54312
|
+
void (async () => {
|
|
54313
|
+
if (!this.hasAnyAuth() && !this.isTrustedStandaloneMutationRequest(req)) {
|
|
54314
|
+
res.writeHead(403, { "Content-Type": "application/json" });
|
|
54315
|
+
res.end(JSON.stringify({ error: "Cross-origin standalone settings changes are not allowed without existing auth." }));
|
|
54316
|
+
return;
|
|
54317
|
+
}
|
|
54318
|
+
if (this.hasAnyAuth() && !this.isRequestAuthenticated(req, url2)) {
|
|
54319
|
+
res.writeHead(401, { "Content-Type": "application/json" });
|
|
54320
|
+
res.end(JSON.stringify({ error: "Unauthorized" }));
|
|
54321
|
+
return;
|
|
54322
|
+
}
|
|
54323
|
+
const body = await this.readJsonBody(req);
|
|
54324
|
+
const nextHost = body?.standaloneBindHost === "0.0.0.0" ? "0.0.0.0" : "127.0.0.1";
|
|
54325
|
+
const savedHost = saveStandaloneBindHostPreference(nextHost);
|
|
54326
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
54327
|
+
res.end(JSON.stringify({
|
|
54328
|
+
success: true,
|
|
54329
|
+
standaloneBindHost: savedHost,
|
|
54330
|
+
currentBindHost: this.listenHost,
|
|
54331
|
+
hasPasswordAuth: !!this.passwordConfig,
|
|
54332
|
+
hasTokenAuth: !!this.authToken,
|
|
54333
|
+
publicHostWarning: shouldWarnForPublicUnauthenticatedHost({
|
|
54334
|
+
host: savedHost,
|
|
54335
|
+
hasTokenAuth: !!this.authToken,
|
|
54336
|
+
hasPasswordAuth: !!this.passwordConfig
|
|
54337
|
+
})
|
|
54338
|
+
}));
|
|
54339
|
+
})().catch((error48) => {
|
|
54340
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
54341
|
+
res.end(JSON.stringify({ error: error48?.message || String(error48) }));
|
|
54342
|
+
});
|
|
54343
|
+
return;
|
|
54344
|
+
}
|
|
54345
|
+
if (url2.startsWith("/api/") && !this.isRequestAuthenticated(req, url2)) {
|
|
54346
|
+
res.writeHead(401, { "Content-Type": "application/json" });
|
|
54347
|
+
res.end(JSON.stringify({ error: "Unauthorized. Provide dashboard session cookie or token auth." }));
|
|
54348
|
+
return;
|
|
53933
54349
|
}
|
|
53934
54350
|
const apiPath = url2.startsWith("/api/v1/") ? url2.slice(7) : null;
|
|
53935
|
-
const parsedUrl = new URL(url2, `http://${req.headers.host || "localhost"}`);
|
|
53936
54351
|
if (apiPath === "/status" && method === "GET") {
|
|
53937
54352
|
const status = this.getStatus(getSharedSnapshot());
|
|
53938
54353
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
@@ -54820,6 +55235,7 @@ async function main() {
|
|
|
54820
55235
|
process.exit(exitCode);
|
|
54821
55236
|
}
|
|
54822
55237
|
const options = {};
|
|
55238
|
+
let hostExplicit = false;
|
|
54823
55239
|
for (let i = 0; i < args.length; i++) {
|
|
54824
55240
|
if ((args[i] === "--port" || args[i] === "-p") && args[i + 1]) {
|
|
54825
55241
|
options.port = parseInt(args[i + 1]);
|
|
@@ -54827,6 +55243,7 @@ async function main() {
|
|
|
54827
55243
|
}
|
|
54828
55244
|
if (args[i] === "--host" || args[i] === "-H") {
|
|
54829
55245
|
options.host = "0.0.0.0";
|
|
55246
|
+
hostExplicit = true;
|
|
54830
55247
|
}
|
|
54831
55248
|
if (args[i] === "--public" && args[i + 1]) {
|
|
54832
55249
|
options.publicDir = args[i + 1];
|
|
@@ -54868,6 +55285,9 @@ Runtime commands:
|
|
|
54868
55285
|
process.exit(0);
|
|
54869
55286
|
}
|
|
54870
55287
|
}
|
|
55288
|
+
if (!hostExplicit) {
|
|
55289
|
+
options.host = loadStandaloneBindHostPreference();
|
|
55290
|
+
}
|
|
54871
55291
|
if (!options.publicDir) {
|
|
54872
55292
|
const candidates = [
|
|
54873
55293
|
path4.join(__dirname, "../../web-standalone/dist"),
|
|
@@ -54883,6 +55303,9 @@ Runtime commands:
|
|
|
54883
55303
|
}
|
|
54884
55304
|
const server = new StandaloneServer();
|
|
54885
55305
|
await server.start(options);
|
|
55306
|
+
if (!hostExplicit) {
|
|
55307
|
+
saveStandaloneBindHostPreference(options.host === "0.0.0.0" ? "0.0.0.0" : "127.0.0.1");
|
|
55308
|
+
}
|
|
54886
55309
|
await new Promise(() => {
|
|
54887
55310
|
});
|
|
54888
55311
|
}
|