@omnicross/daemon 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +80 -50
- package/dist/cli.js +66 -36
- package/dist/index.cjs +85 -53
- package/dist/index.d.cts +7 -2
- package/dist/index.d.ts +7 -2
- package/dist/index.js +72 -40
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -80,6 +80,7 @@ var CodexOAuthSessionStore = class {
|
|
|
80
80
|
ttlMs;
|
|
81
81
|
sessions = /* @__PURE__ */ new Map();
|
|
82
82
|
activeSessionId = null;
|
|
83
|
+
aborters = /* @__PURE__ */ new Map();
|
|
83
84
|
/** Whether a codex sign-in is currently in flight (port 1455 held). */
|
|
84
85
|
isBusy() {
|
|
85
86
|
this.sweep();
|
|
@@ -91,13 +92,22 @@ var CodexOAuthSessionStore = class {
|
|
|
91
92
|
const sessionId = import_node_crypto.default.randomBytes(24).toString("base64url");
|
|
92
93
|
this.sessions.set(sessionId, { status: "pending", createdAt: Date.now() });
|
|
93
94
|
this.activeSessionId = sessionId;
|
|
94
|
-
|
|
95
|
+
const controller = new AbortController();
|
|
96
|
+
this.aborters.set(sessionId, controller);
|
|
97
|
+
return { sessionId, signal: controller.signal };
|
|
95
98
|
}
|
|
96
99
|
/** Settle a flow (done/error) + free the active slot. */
|
|
97
100
|
settle(sessionId, status, error) {
|
|
98
101
|
const prior = this.sessions.get(sessionId);
|
|
99
102
|
this.sessions.set(sessionId, { status, error, createdAt: prior?.createdAt ?? Date.now() });
|
|
100
103
|
if (this.activeSessionId === sessionId) this.activeSessionId = null;
|
|
104
|
+
this.aborters.delete(sessionId);
|
|
105
|
+
}
|
|
106
|
+
cancel(sessionId) {
|
|
107
|
+
if (!this.sessions.has(sessionId)) return false;
|
|
108
|
+
this.aborters.get(sessionId)?.abort();
|
|
109
|
+
this.settle(sessionId, "error", "login: cancelled");
|
|
110
|
+
return true;
|
|
101
111
|
}
|
|
102
112
|
/** Read a flow's status (token-free), or null when unknown/expired. */
|
|
103
113
|
get(sessionId) {
|
|
@@ -126,13 +136,13 @@ function handleCodexOAuthStart(deps) {
|
|
|
126
136
|
);
|
|
127
137
|
}
|
|
128
138
|
const { authUrl, codeVerifier, state } = import_subscriptions.codexOAuth.generateAuthParams();
|
|
129
|
-
const sessionId = deps.codexSessions.begin();
|
|
130
|
-
void runCodexLoopback(sessionId, codeVerifier, state, deps);
|
|
139
|
+
const { sessionId, signal } = deps.codexSessions.begin();
|
|
140
|
+
void runCodexLoopback(sessionId, codeVerifier, state, signal, deps);
|
|
131
141
|
return { status: 200, body: { authUrl, sessionId } };
|
|
132
142
|
}
|
|
133
|
-
async function runCodexLoopback(sessionId, codeVerifier, state, deps) {
|
|
143
|
+
async function runCodexLoopback(sessionId, codeVerifier, state, signal, deps) {
|
|
134
144
|
try {
|
|
135
|
-
const code = await deps.codexAwaitLoopback(state);
|
|
145
|
+
const code = await deps.codexAwaitLoopback(state, void 0, signal);
|
|
136
146
|
const result = await import_subscriptions.codexOAuth.exchangeCodeForTokens(
|
|
137
147
|
{ authorizationCode: code, codeVerifier, state },
|
|
138
148
|
deps.oauthExchangeFetch
|
|
@@ -154,6 +164,10 @@ async function runCodexLoopback(sessionId, codeVerifier, state, deps) {
|
|
|
154
164
|
deps.codexSessions.settle(sessionId, "error", reason);
|
|
155
165
|
}
|
|
156
166
|
}
|
|
167
|
+
function handleCodexOAuthCancel(sessionId, deps) {
|
|
168
|
+
if (!deps.codexSessions.cancel(sessionId)) return err(404, "unknown or expired codex sign-in session");
|
|
169
|
+
return { status: 200, body: { ok: true } };
|
|
170
|
+
}
|
|
157
171
|
function handleCodexOAuthStatus(sessionId, deps) {
|
|
158
172
|
const s = deps.codexSessions.get(sessionId);
|
|
159
173
|
if (!s) return err(404, "unknown or expired codex sign-in session");
|
|
@@ -1889,12 +1903,16 @@ function preserveWebhookSecrets(incoming, current) {
|
|
|
1889
1903
|
}
|
|
1890
1904
|
|
|
1891
1905
|
// src/audit/auditRuntime.ts
|
|
1906
|
+
var import_node_path3 = require("path");
|
|
1892
1907
|
var import_auditSink = require("@omnicross/core/pipeline/auditSink");
|
|
1908
|
+
var import_upstreamTrace = require("@omnicross/core/pipeline/upstreamTrace");
|
|
1893
1909
|
var writer = null;
|
|
1894
1910
|
var sweeper = null;
|
|
1895
|
-
|
|
1911
|
+
var auditDir = "";
|
|
1912
|
+
function setAuditRuntime(w, s, dir) {
|
|
1896
1913
|
writer = w;
|
|
1897
1914
|
sweeper = s;
|
|
1915
|
+
auditDir = dir;
|
|
1898
1916
|
}
|
|
1899
1917
|
function applyAuditConfig(config) {
|
|
1900
1918
|
const enabled = config?.enabled === true && writer !== null;
|
|
@@ -1906,9 +1924,11 @@ function applyAuditConfig(config) {
|
|
|
1906
1924
|
sweeper.configure(config);
|
|
1907
1925
|
sweeper.start();
|
|
1908
1926
|
}
|
|
1927
|
+
(0, import_upstreamTrace.setUpstreamTracePath)(config.captureBodies ? (0, import_node_path3.join)(auditDir, "upstream-trace.jsonl") : null);
|
|
1909
1928
|
} else {
|
|
1910
1929
|
(0, import_auditSink.setAuditCaptureConfig)(null);
|
|
1911
1930
|
(0, import_auditSink.setAuditSink)(null);
|
|
1931
|
+
(0, import_upstreamTrace.setUpstreamTracePath)(null);
|
|
1912
1932
|
if (sweeper) {
|
|
1913
1933
|
if (config) sweeper.configure(config);
|
|
1914
1934
|
sweeper.dispose();
|
|
@@ -1918,9 +1938,11 @@ function applyAuditConfig(config) {
|
|
|
1918
1938
|
function resetAuditRuntimeForTests() {
|
|
1919
1939
|
(0, import_auditSink.setAuditCaptureConfig)(null);
|
|
1920
1940
|
(0, import_auditSink.setAuditSink)(null);
|
|
1941
|
+
(0, import_upstreamTrace.setUpstreamTracePath)(null);
|
|
1921
1942
|
if (sweeper) sweeper.dispose();
|
|
1922
1943
|
writer = null;
|
|
1923
1944
|
sweeper = null;
|
|
1945
|
+
auditDir = "";
|
|
1924
1946
|
}
|
|
1925
1947
|
|
|
1926
1948
|
// src/billing/billingRuntime.ts
|
|
@@ -3535,6 +3557,10 @@ async function handleAccounts(req, res, method, rest, deps) {
|
|
|
3535
3557
|
const result = handleCodexOAuthStatus(rest[2], deps);
|
|
3536
3558
|
return writeJson2(res, result.status, result.body);
|
|
3537
3559
|
}
|
|
3560
|
+
if (method === "DELETE" && rest[0] === "codex" && rest[1] === "oauth" && rest[2]) {
|
|
3561
|
+
const result = handleCodexOAuthCancel(rest[2], deps);
|
|
3562
|
+
return writeJson2(res, result.status, result.body);
|
|
3563
|
+
}
|
|
3538
3564
|
if (method === "PUT" || method === "POST" || method === "DELETE") {
|
|
3539
3565
|
const providerId = asSubscriptionProviderId(rest[0]);
|
|
3540
3566
|
if (!providerId) {
|
|
@@ -3782,7 +3808,7 @@ function proxyToOutbound(res, outboundPort, path2, key, body) {
|
|
|
3782
3808
|
var import_node_fs4 = require("fs");
|
|
3783
3809
|
var import_promises = require("fs/promises");
|
|
3784
3810
|
var import_node_module = require("module");
|
|
3785
|
-
var
|
|
3811
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
3786
3812
|
var import_meta = {};
|
|
3787
3813
|
var CONTENT_TYPES = {
|
|
3788
3814
|
".html": "text/html; charset=utf-8",
|
|
@@ -3803,13 +3829,13 @@ var CONTENT_TYPES = {
|
|
|
3803
3829
|
function resolveUiDist() {
|
|
3804
3830
|
const fromEnv = process.env["OMNICROSS_UI_DIST"];
|
|
3805
3831
|
if (fromEnv) {
|
|
3806
|
-
return (0, import_node_fs4.existsSync)(
|
|
3832
|
+
return (0, import_node_fs4.existsSync)(import_node_path4.default.join(fromEnv, "index.html")) ? import_node_path4.default.resolve(fromEnv) : null;
|
|
3807
3833
|
}
|
|
3808
3834
|
try {
|
|
3809
3835
|
const req = (0, import_node_module.createRequire)(typeof __filename !== "undefined" ? __filename : import_meta.url);
|
|
3810
3836
|
const pkgJson = req.resolve("@omnicross/ui/package.json");
|
|
3811
|
-
const dist =
|
|
3812
|
-
return (0, import_node_fs4.existsSync)(
|
|
3837
|
+
const dist = import_node_path4.default.join(import_node_path4.default.dirname(pkgJson), "dist");
|
|
3838
|
+
return (0, import_node_fs4.existsSync)(import_node_path4.default.join(dist, "index.html")) ? dist : null;
|
|
3813
3839
|
} catch {
|
|
3814
3840
|
return null;
|
|
3815
3841
|
}
|
|
@@ -3851,16 +3877,16 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
|
|
|
3851
3877
|
res.end(JSON.stringify({ error: { type: "bad_request", message: "invalid path" } }));
|
|
3852
3878
|
return true;
|
|
3853
3879
|
}
|
|
3854
|
-
const filePath =
|
|
3855
|
-
if (filePath !== uiDist && !filePath.startsWith(uiDist +
|
|
3880
|
+
const filePath = import_node_path4.default.resolve(uiDist, rel === "" ? "index.html" : rel);
|
|
3881
|
+
if (filePath !== uiDist && !filePath.startsWith(uiDist + import_node_path4.default.sep)) {
|
|
3856
3882
|
res.writeHead(403, { "Content-Type": "application/json" });
|
|
3857
3883
|
res.end(JSON.stringify({ error: { type: "forbidden", message: "path outside ui root" } }));
|
|
3858
3884
|
return true;
|
|
3859
3885
|
}
|
|
3860
3886
|
let target = filePath;
|
|
3861
3887
|
if (!(0, import_node_fs4.existsSync)(target) || (0, import_node_fs4.statSync)(target).isDirectory()) {
|
|
3862
|
-
if (
|
|
3863
|
-
target =
|
|
3888
|
+
if (import_node_path4.default.extname(rel) === "") {
|
|
3889
|
+
target = import_node_path4.default.join(uiDist, "index.html");
|
|
3864
3890
|
} else {
|
|
3865
3891
|
res.writeHead(404, { "Content-Type": "application/json" });
|
|
3866
3892
|
res.end(JSON.stringify({ error: { type: "not_found", message: "no such ui asset" } }));
|
|
@@ -3868,14 +3894,14 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
|
|
|
3868
3894
|
}
|
|
3869
3895
|
}
|
|
3870
3896
|
const body = await (0, import_promises.readFile)(target);
|
|
3871
|
-
const type = CONTENT_TYPES[
|
|
3897
|
+
const type = CONTENT_TYPES[import_node_path4.default.extname(target).toLowerCase()] ?? "application/octet-stream";
|
|
3872
3898
|
res.writeHead(200, { "Content-Type": type, "Content-Length": body.length });
|
|
3873
3899
|
res.end(req.method === "HEAD" ? void 0 : body);
|
|
3874
3900
|
return true;
|
|
3875
3901
|
}
|
|
3876
3902
|
|
|
3877
3903
|
// src/admin/version.ts
|
|
3878
|
-
var DAEMON_VERSION = true ? "0.1.
|
|
3904
|
+
var DAEMON_VERSION = true ? "0.1.5" : "0.0.0-dev";
|
|
3879
3905
|
|
|
3880
3906
|
// src/admin/AdminServer.ts
|
|
3881
3907
|
var LOOPBACK_ADDR = "127.0.0.1";
|
|
@@ -4130,7 +4156,7 @@ var DEFAULT_TIMEOUT_MS = 5 * 6e4;
|
|
|
4130
4156
|
function pageHtml(message) {
|
|
4131
4157
|
return `<!doctype html><meta charset="utf-8"><title>omnicross login</title><body style="font-family:sans-serif;padding:2rem"><h2>${message}</h2><p>You can close this window and return to the terminal.</p></body>`;
|
|
4132
4158
|
}
|
|
4133
|
-
function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
4159
|
+
function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal) {
|
|
4134
4160
|
return new Promise((resolve, reject) => {
|
|
4135
4161
|
let settled = false;
|
|
4136
4162
|
const finish = (server2, fn) => {
|
|
@@ -4164,6 +4190,12 @@ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
|
4164
4190
|
res.end(pageHtml("Login complete."));
|
|
4165
4191
|
finish(server, () => resolve(code));
|
|
4166
4192
|
});
|
|
4193
|
+
const abort = () => finish(server, () => reject(new Error("login: cancelled")));
|
|
4194
|
+
if (signal?.aborted) {
|
|
4195
|
+
abort();
|
|
4196
|
+
return;
|
|
4197
|
+
}
|
|
4198
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
4167
4199
|
server.on("error", (err5) => {
|
|
4168
4200
|
if (settled) return;
|
|
4169
4201
|
settled = true;
|
|
@@ -4251,21 +4283,21 @@ function createPoolKeysLoader(getProviderRow, autoDisabled) {
|
|
|
4251
4283
|
}
|
|
4252
4284
|
|
|
4253
4285
|
// src/commands/paths.ts
|
|
4254
|
-
var
|
|
4286
|
+
var import_node_path5 = require("path");
|
|
4255
4287
|
function defaultVouchersPath(configPath) {
|
|
4256
|
-
return (0,
|
|
4288
|
+
return (0, import_node_path5.join)((0, import_node_path5.dirname)(configPath), "vouchers.json");
|
|
4257
4289
|
}
|
|
4258
4290
|
function defaultPricingPath(configPath) {
|
|
4259
|
-
return (0,
|
|
4291
|
+
return (0, import_node_path5.join)((0, import_node_path5.dirname)(configPath), "pricing.json");
|
|
4260
4292
|
}
|
|
4261
4293
|
function defaultUsageEventsPath(configPath) {
|
|
4262
|
-
return (0,
|
|
4294
|
+
return (0, import_node_path5.join)((0, import_node_path5.dirname)(configPath), "usage-events.jsonl");
|
|
4263
4295
|
}
|
|
4264
4296
|
function defaultAuditDir(configPath) {
|
|
4265
|
-
return (0,
|
|
4297
|
+
return (0, import_node_path5.join)((0, import_node_path5.dirname)(configPath), "audit");
|
|
4266
4298
|
}
|
|
4267
4299
|
function defaultBillingDir(configPath) {
|
|
4268
|
-
return (0,
|
|
4300
|
+
return (0, import_node_path5.join)((0, import_node_path5.dirname)(configPath), "billing");
|
|
4269
4301
|
}
|
|
4270
4302
|
|
|
4271
4303
|
// src/ports/ConfigFileProviderConfigSource.ts
|
|
@@ -5262,7 +5294,7 @@ var JsonVoucherDb = class {
|
|
|
5262
5294
|
|
|
5263
5295
|
// src/ports/JsonSubscriptionCredentialStore.ts
|
|
5264
5296
|
var import_node_fs13 = require("fs");
|
|
5265
|
-
var
|
|
5297
|
+
var import_node_path8 = require("path");
|
|
5266
5298
|
var import_SubscriptionAccountHealth = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
|
|
5267
5299
|
var import_upstreamFetch3 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
5268
5300
|
var import_SubscriptionIdentityStore = require("@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore");
|
|
@@ -5344,9 +5376,9 @@ function findDuplicateCredentialIds(accounts) {
|
|
|
5344
5376
|
// src/ports/external-cli-credentials.ts
|
|
5345
5377
|
var import_node_fs11 = require("fs");
|
|
5346
5378
|
var import_node_os2 = require("os");
|
|
5347
|
-
var
|
|
5379
|
+
var import_node_path6 = require("path");
|
|
5348
5380
|
function externalStorePath(provider, home = (0, import_node_os2.homedir)()) {
|
|
5349
|
-
return provider === "claude" ? (0,
|
|
5381
|
+
return provider === "claude" ? (0, import_node_path6.join)(home, ".claude", ".credentials.json") : (0, import_node_path6.join)(home, ".codex", "auth.json");
|
|
5350
5382
|
}
|
|
5351
5383
|
function decodeJwtExpiryMs(token) {
|
|
5352
5384
|
try {
|
|
@@ -5409,7 +5441,7 @@ function readExternalCliCredentials(provider, home = (0, import_node_os2.homedir
|
|
|
5409
5441
|
// src/ports/external-cli-store.ts
|
|
5410
5442
|
var import_node_fs12 = require("fs");
|
|
5411
5443
|
var import_node_os3 = require("os");
|
|
5412
|
-
var
|
|
5444
|
+
var import_node_path7 = require("path");
|
|
5413
5445
|
function markerPath(provider, home) {
|
|
5414
5446
|
return `${externalStorePath(provider, home)}.omnicross-managed`;
|
|
5415
5447
|
}
|
|
@@ -5444,7 +5476,7 @@ function readExistingObject(path2) {
|
|
|
5444
5476
|
}
|
|
5445
5477
|
}
|
|
5446
5478
|
function writeAtomic(path2, content) {
|
|
5447
|
-
(0, import_node_fs12.mkdirSync)((0,
|
|
5479
|
+
(0, import_node_fs12.mkdirSync)((0, import_node_path7.dirname)(path2), { recursive: true });
|
|
5448
5480
|
const temp = `${path2}.omnicross-tmp`;
|
|
5449
5481
|
(0, import_node_fs12.writeFileSync)(temp, content, "utf8");
|
|
5450
5482
|
(0, import_node_fs12.renameSync)(temp, path2);
|
|
@@ -6115,7 +6147,7 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
6115
6147
|
* → `enc:v1:`; already-`enc:`/`$ENV` untouched) before serializing, so any
|
|
6116
6148
|
* write — incl. child 4's future refresh writes — lands encrypted. */
|
|
6117
6149
|
persist(config) {
|
|
6118
|
-
(0, import_node_fs13.mkdirSync)((0,
|
|
6150
|
+
(0, import_node_fs13.mkdirSync)((0, import_node_path8.dirname)(this.tokensPath), { recursive: true });
|
|
6119
6151
|
const encrypted = encryptTokens(config, this.box);
|
|
6120
6152
|
(0, import_node_fs13.writeFileSync)(this.tokensPath, JSON.stringify(encrypted, null, 2) + "\n", "utf8");
|
|
6121
6153
|
}
|
|
@@ -6465,7 +6497,7 @@ var AccountHealthSweeper = class {
|
|
|
6465
6497
|
|
|
6466
6498
|
// src/audit/AuditPruneSweeper.ts
|
|
6467
6499
|
var import_node_fs14 = require("fs");
|
|
6468
|
-
var
|
|
6500
|
+
var import_node_path9 = require("path");
|
|
6469
6501
|
|
|
6470
6502
|
// src/audit/auditFiles.ts
|
|
6471
6503
|
var AUDIT_FILE_RE = /^audit-(\d{4})-(\d{2})-(\d{2})\.jsonl$/;
|
|
@@ -6491,8 +6523,8 @@ function auditFileDateMs(fileName) {
|
|
|
6491
6523
|
var DAY_MS = 24 * 60 * 6e4;
|
|
6492
6524
|
var SWEEP_INTERVAL_MS2 = 60 * 6e4;
|
|
6493
6525
|
var AuditPruneSweeper = class {
|
|
6494
|
-
constructor(
|
|
6495
|
-
this.auditDir =
|
|
6526
|
+
constructor(auditDir2, logger, config, intervalMs = SWEEP_INTERVAL_MS2, now = Date.now) {
|
|
6527
|
+
this.auditDir = auditDir2;
|
|
6496
6528
|
this.logger = logger;
|
|
6497
6529
|
this.config = config;
|
|
6498
6530
|
this.intervalMs = intervalMs;
|
|
@@ -6548,7 +6580,7 @@ var AuditPruneSweeper = class {
|
|
|
6548
6580
|
const dateMs = auditFileDateMs(file);
|
|
6549
6581
|
if (dateMs === null || dateMs >= cutoff) continue;
|
|
6550
6582
|
try {
|
|
6551
|
-
(0, import_node_fs14.unlinkSync)((0,
|
|
6583
|
+
(0, import_node_fs14.unlinkSync)((0, import_node_path9.join)(this.auditDir, file));
|
|
6552
6584
|
removed += 1;
|
|
6553
6585
|
} catch (error) {
|
|
6554
6586
|
this.logger.warn("[AuditPruneSweeper] failed to unlink expired audit file", {
|
|
@@ -6572,14 +6604,14 @@ var AuditPruneSweeper = class {
|
|
|
6572
6604
|
|
|
6573
6605
|
// src/audit/auditReader.ts
|
|
6574
6606
|
var import_node_fs15 = require("fs");
|
|
6575
|
-
var
|
|
6607
|
+
var import_node_path10 = require("path");
|
|
6576
6608
|
var DEFAULT_LIMIT = 200;
|
|
6577
6609
|
var MAX_LIMIT = 2e3;
|
|
6578
|
-
function readAuditRecords(
|
|
6579
|
-
if (!(0, import_node_fs15.existsSync)(
|
|
6610
|
+
function readAuditRecords(auditDir2, query = {}) {
|
|
6611
|
+
if (!(0, import_node_fs15.existsSync)(auditDir2)) return [];
|
|
6580
6612
|
let files;
|
|
6581
6613
|
try {
|
|
6582
|
-
files = (0, import_node_fs15.readdirSync)(
|
|
6614
|
+
files = (0, import_node_fs15.readdirSync)(auditDir2).filter((f) => AUDIT_FILE_RE.test(f));
|
|
6583
6615
|
} catch {
|
|
6584
6616
|
return [];
|
|
6585
6617
|
}
|
|
@@ -6590,7 +6622,7 @@ function readAuditRecords(auditDir, query = {}) {
|
|
|
6590
6622
|
for (const file of files.sort().reverse()) {
|
|
6591
6623
|
let raw;
|
|
6592
6624
|
try {
|
|
6593
|
-
raw = (0, import_node_fs15.readFileSync)((0,
|
|
6625
|
+
raw = (0, import_node_fs15.readFileSync)((0, import_node_path10.join)(auditDir2, file), "utf8");
|
|
6594
6626
|
} catch {
|
|
6595
6627
|
continue;
|
|
6596
6628
|
}
|
|
@@ -6620,10 +6652,10 @@ function isAuditRecord(value) {
|
|
|
6620
6652
|
|
|
6621
6653
|
// src/audit/AuditWriter.ts
|
|
6622
6654
|
var import_node_fs16 = require("fs");
|
|
6623
|
-
var
|
|
6655
|
+
var import_node_path11 = require("path");
|
|
6624
6656
|
var AuditWriter = class {
|
|
6625
|
-
constructor(
|
|
6626
|
-
this.auditDir =
|
|
6657
|
+
constructor(auditDir2, logger, defer = (fn) => setTimeout(fn, 0)) {
|
|
6658
|
+
this.auditDir = auditDir2;
|
|
6627
6659
|
this.logger = logger;
|
|
6628
6660
|
this.defer = defer;
|
|
6629
6661
|
}
|
|
@@ -6656,7 +6688,7 @@ var AuditWriter = class {
|
|
|
6656
6688
|
(0, import_node_fs16.mkdirSync)(this.auditDir, { recursive: true });
|
|
6657
6689
|
this.dirEnsured = true;
|
|
6658
6690
|
}
|
|
6659
|
-
const file = (0,
|
|
6691
|
+
const file = (0, import_node_path11.join)(this.auditDir, auditFileName(record.ts));
|
|
6660
6692
|
(0, import_node_fs16.appendFileSync)(file, JSON.stringify(record) + "\n", "utf8");
|
|
6661
6693
|
}
|
|
6662
6694
|
};
|
|
@@ -6664,7 +6696,7 @@ var AuditWriter = class {
|
|
|
6664
6696
|
// src/billing/BillingPublisher.ts
|
|
6665
6697
|
var import_node_fs17 = require("fs");
|
|
6666
6698
|
var import_node_crypto10 = require("crypto");
|
|
6667
|
-
var
|
|
6699
|
+
var import_node_path12 = require("path");
|
|
6668
6700
|
var import_upstreamFetch5 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
6669
6701
|
|
|
6670
6702
|
// src/billing/billingFiles.ts
|
|
@@ -6735,7 +6767,7 @@ var BillingPublisher = class {
|
|
|
6735
6767
|
*/
|
|
6736
6768
|
appendNow(event) {
|
|
6737
6769
|
this.ensureDir();
|
|
6738
|
-
const file = (0,
|
|
6770
|
+
const file = (0, import_node_path12.join)(this.billingDir, billingFileName(event.ts));
|
|
6739
6771
|
(0, import_node_fs17.appendFileSync)(file, JSON.stringify(event) + "\n", "utf8");
|
|
6740
6772
|
}
|
|
6741
6773
|
/**
|
|
@@ -6785,7 +6817,7 @@ var BillingPublisher = class {
|
|
|
6785
6817
|
markDelivered(event) {
|
|
6786
6818
|
try {
|
|
6787
6819
|
this.ensureDir();
|
|
6788
|
-
const file = (0,
|
|
6820
|
+
const file = (0, import_node_path12.join)(this.billingDir, deliveredFileName(event.ts));
|
|
6789
6821
|
(0, import_node_fs17.appendFileSync)(file, JSON.stringify({ id: event.id, deliveredAt: this.now() }) + "\n", "utf8");
|
|
6790
6822
|
} catch (error) {
|
|
6791
6823
|
this.logger.warn("[BillingPublisher] failed to append delivery marker", {
|
|
@@ -6802,7 +6834,7 @@ var BillingPublisher = class {
|
|
|
6802
6834
|
|
|
6803
6835
|
// src/billing/billingReader.ts
|
|
6804
6836
|
var import_node_fs18 = require("fs");
|
|
6805
|
-
var
|
|
6837
|
+
var import_node_path13 = require("path");
|
|
6806
6838
|
function readBillingLedger(billingDir) {
|
|
6807
6839
|
const view = { events: [], deliveredIds: /* @__PURE__ */ new Set() };
|
|
6808
6840
|
if (!(0, import_node_fs18.existsSync)(billingDir)) return view;
|
|
@@ -6839,7 +6871,7 @@ function readBillingStatus(billingDir) {
|
|
|
6839
6871
|
function parseLines(dir, file) {
|
|
6840
6872
|
let raw;
|
|
6841
6873
|
try {
|
|
6842
|
-
raw = (0, import_node_fs18.readFileSync)((0,
|
|
6874
|
+
raw = (0, import_node_fs18.readFileSync)((0, import_node_path13.join)(dir, file), "utf8");
|
|
6843
6875
|
} catch {
|
|
6844
6876
|
return [];
|
|
6845
6877
|
}
|
|
@@ -7280,7 +7312,7 @@ function buildDaemon(config, paths) {
|
|
|
7280
7312
|
// lines through the injected logger (honors level/format/file sink).
|
|
7281
7313
|
logger
|
|
7282
7314
|
});
|
|
7283
|
-
const
|
|
7315
|
+
const auditDir2 = defaultAuditDir(paths.configPath);
|
|
7284
7316
|
const billingDir = defaultBillingDir(paths.configPath);
|
|
7285
7317
|
const adminServer = new AdminServer({
|
|
7286
7318
|
configPath: paths.configPath,
|
|
@@ -7321,7 +7353,7 @@ function buildDaemon(config, paths) {
|
|
|
7321
7353
|
// the app polls the token-free status. A test seam (`paths.codexAwaitLoopback`)
|
|
7322
7354
|
// can inject a mock so no real port is bound.
|
|
7323
7355
|
codexSessions: new CodexOAuthSessionStore(),
|
|
7324
|
-
codexAwaitLoopback: paths.codexAwaitLoopback ?? ((state, timeoutMs) => awaitLoopbackCode(state, timeoutMs)),
|
|
7356
|
+
codexAwaitLoopback: paths.codexAwaitLoopback ?? ((state, timeoutMs, signal) => awaitLoopbackCode(state, timeoutMs, signal)),
|
|
7325
7357
|
// Migration pack (app-parity child 6, design D2/D3) — the concrete credential
|
|
7326
7358
|
// store provides BOTH the full DECRYPTED read (`getFullConfig`, export) and
|
|
7327
7359
|
// the multi-account append (`appendProviderAccount`, import re-encrypts at-
|
|
@@ -7356,7 +7388,7 @@ function buildDaemon(config, paths) {
|
|
|
7356
7388
|
// date-rotated audit store. Bound to the store dir here so the AdminServer
|
|
7357
7389
|
// carries no path/store coupling. Records hold IP/UA/bodies → admin-only,
|
|
7358
7390
|
// NEVER unauth, NEVER on `/health`. Routed in `AdminServer` (not `adminApi.ts`).
|
|
7359
|
-
auditReader: (query) => readAuditRecords(
|
|
7391
|
+
auditReader: (query) => readAuditRecords(auditDir2, query),
|
|
7360
7392
|
// billing-event-stream: the AUTHED `GET /admin/api/billing-status` returns the
|
|
7361
7393
|
// secret-free total/delivered/pending counts of the durable ledger.
|
|
7362
7394
|
billingStatusReader: () => readBillingStatus(billingDir)
|
|
@@ -7366,9 +7398,9 @@ function buildDaemon(config, paths) {
|
|
|
7366
7398
|
fetchImpl: (url, init) => (0, import_upstreamFetch7.fetchUpstream)(url, init)
|
|
7367
7399
|
});
|
|
7368
7400
|
setWebhookRuntime(webhookDispatcher, (0, import_SubscriptionAccountHealth2.getSharedAccountHealth)());
|
|
7369
|
-
const auditWriter = new AuditWriter(
|
|
7370
|
-
const auditPruneSweeper = new AuditPruneSweeper(
|
|
7371
|
-
setAuditRuntime(auditWriter, auditPruneSweeper);
|
|
7401
|
+
const auditWriter = new AuditWriter(auditDir2, logger);
|
|
7402
|
+
const auditPruneSweeper = new AuditPruneSweeper(auditDir2, logger, import_audit_types.DEFAULT_AUDIT_CONFIG);
|
|
7403
|
+
setAuditRuntime(auditWriter, auditPruneSweeper, auditDir2);
|
|
7372
7404
|
const billingPublisher = new BillingPublisher(billingDir, logger);
|
|
7373
7405
|
const billingRetrySweeper = new BillingRetrySweeper(
|
|
7374
7406
|
billingDir,
|
package/dist/index.d.cts
CHANGED
|
@@ -1048,7 +1048,7 @@ interface SubscriptionAccountAppender {
|
|
|
1048
1048
|
*/
|
|
1049
1049
|
|
|
1050
1050
|
/** The loopback-listener fn (injected so tests need not bind a real port). */
|
|
1051
|
-
type CodexLoopbackFn = (state: string, timeoutMs?: number) => Promise<string>;
|
|
1051
|
+
type CodexLoopbackFn = (state: string, timeoutMs?: number, signal?: AbortSignal) => Promise<string>;
|
|
1052
1052
|
/** One codex sign-in flow's polled status (NEVER carries a token). */
|
|
1053
1053
|
interface CodexFlowState {
|
|
1054
1054
|
status: 'pending' | 'done' | 'error';
|
|
@@ -1066,13 +1066,18 @@ declare class CodexOAuthSessionStore {
|
|
|
1066
1066
|
private readonly ttlMs;
|
|
1067
1067
|
private readonly sessions;
|
|
1068
1068
|
private activeSessionId;
|
|
1069
|
+
private readonly aborters;
|
|
1069
1070
|
constructor(ttlMs?: number);
|
|
1070
1071
|
/** Whether a codex sign-in is currently in flight (port 1455 held). */
|
|
1071
1072
|
isBusy(): boolean;
|
|
1072
1073
|
/** Mint a fresh sessionId, mark it pending + active, return the id. */
|
|
1073
|
-
begin():
|
|
1074
|
+
begin(): {
|
|
1075
|
+
sessionId: string;
|
|
1076
|
+
signal: AbortSignal;
|
|
1077
|
+
};
|
|
1074
1078
|
/** Settle a flow (done/error) + free the active slot. */
|
|
1075
1079
|
settle(sessionId: string, status: 'done' | 'error', error?: string): void;
|
|
1080
|
+
cancel(sessionId: string): boolean;
|
|
1076
1081
|
/** Read a flow's status (token-free), or null when unknown/expired. */
|
|
1077
1082
|
get(sessionId: string): CodexFlowState | null;
|
|
1078
1083
|
/** Drop expired flows; free the active slot if the active flow expired. */
|
package/dist/index.d.ts
CHANGED
|
@@ -1048,7 +1048,7 @@ interface SubscriptionAccountAppender {
|
|
|
1048
1048
|
*/
|
|
1049
1049
|
|
|
1050
1050
|
/** The loopback-listener fn (injected so tests need not bind a real port). */
|
|
1051
|
-
type CodexLoopbackFn = (state: string, timeoutMs?: number) => Promise<string>;
|
|
1051
|
+
type CodexLoopbackFn = (state: string, timeoutMs?: number, signal?: AbortSignal) => Promise<string>;
|
|
1052
1052
|
/** One codex sign-in flow's polled status (NEVER carries a token). */
|
|
1053
1053
|
interface CodexFlowState {
|
|
1054
1054
|
status: 'pending' | 'done' | 'error';
|
|
@@ -1066,13 +1066,18 @@ declare class CodexOAuthSessionStore {
|
|
|
1066
1066
|
private readonly ttlMs;
|
|
1067
1067
|
private readonly sessions;
|
|
1068
1068
|
private activeSessionId;
|
|
1069
|
+
private readonly aborters;
|
|
1069
1070
|
constructor(ttlMs?: number);
|
|
1070
1071
|
/** Whether a codex sign-in is currently in flight (port 1455 held). */
|
|
1071
1072
|
isBusy(): boolean;
|
|
1072
1073
|
/** Mint a fresh sessionId, mark it pending + active, return the id. */
|
|
1073
|
-
begin():
|
|
1074
|
+
begin(): {
|
|
1075
|
+
sessionId: string;
|
|
1076
|
+
signal: AbortSignal;
|
|
1077
|
+
};
|
|
1074
1078
|
/** Settle a flow (done/error) + free the active slot. */
|
|
1075
1079
|
settle(sessionId: string, status: 'done' | 'error', error?: string): void;
|
|
1080
|
+
cancel(sessionId: string): boolean;
|
|
1076
1081
|
/** Read a flow's status (token-free), or null when unknown/expired. */
|
|
1077
1082
|
get(sessionId: string): CodexFlowState | null;
|
|
1078
1083
|
/** Drop expired flows; free the active slot if the active flow expired. */
|