@tnnevol/dsh-codex-auth 0.1.0-rc.7 → 0.1.0-rc.7.2
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 +0 -2
- package/lib/auth-paths.d.ts +3 -1
- package/lib/auth-paths.js +3 -1
- package/lib/client.js +121 -2
- package/lib/index.d.ts +1 -0
- package/lib/index.js +86 -7
- package/package.json +1 -1
package/README.md
CHANGED
package/lib/auth-paths.d.ts
CHANGED
|
@@ -6,5 +6,7 @@ declare const CODEX_AUTH_STATUS_PATH = "/plugins/dsh-codex-auth-plugin/auth/stat
|
|
|
6
6
|
declare const CODEX_AUTH_LOGIN_PATH = "/plugins/dsh-codex-auth-plugin/auth/login";
|
|
7
7
|
declare const CODEX_AUTH_LOGOUT_PATH = "/plugins/dsh-codex-auth-plugin/auth/logout";
|
|
8
8
|
declare const CODEX_USAGE_PATH = "/plugins/dsh-codex-auth-plugin/auth/usage";
|
|
9
|
+
/** Same-origin settings endpoint used when DSH marks a NAS browser as remote. */
|
|
10
|
+
declare const CODEX_AUTH_SETTINGS_PATH = "/plugins/dsh-codex-auth-plugin/auth/settings";
|
|
9
11
|
//#endregion
|
|
10
|
-
export { CODEX_AUTH_LOGIN_PATH, CODEX_AUTH_LOGOUT_PATH, CODEX_AUTH_SETTINGS_NAMESPACE, CODEX_AUTH_STATUS_PATH, CODEX_USAGE_PATH };
|
|
12
|
+
export { CODEX_AUTH_LOGIN_PATH, CODEX_AUTH_LOGOUT_PATH, CODEX_AUTH_SETTINGS_NAMESPACE, CODEX_AUTH_SETTINGS_PATH, CODEX_AUTH_STATUS_PATH, CODEX_USAGE_PATH };
|
package/lib/auth-paths.js
CHANGED
|
@@ -6,5 +6,7 @@ const CODEX_AUTH_STATUS_PATH = "/plugins/dsh-codex-auth-plugin/auth/status";
|
|
|
6
6
|
const CODEX_AUTH_LOGIN_PATH = "/plugins/dsh-codex-auth-plugin/auth/login";
|
|
7
7
|
const CODEX_AUTH_LOGOUT_PATH = "/plugins/dsh-codex-auth-plugin/auth/logout";
|
|
8
8
|
const CODEX_USAGE_PATH = "/plugins/dsh-codex-auth-plugin/auth/usage";
|
|
9
|
+
/** Same-origin settings endpoint used when DSH marks a NAS browser as remote. */
|
|
10
|
+
const CODEX_AUTH_SETTINGS_PATH = "/plugins/dsh-codex-auth-plugin/auth/settings";
|
|
9
11
|
//#endregion
|
|
10
|
-
export { CODEX_AUTH_LOGIN_PATH, CODEX_AUTH_LOGOUT_PATH, CODEX_AUTH_SETTINGS_NAMESPACE, CODEX_AUTH_STATUS_PATH, CODEX_USAGE_PATH };
|
|
12
|
+
export { CODEX_AUTH_LOGIN_PATH, CODEX_AUTH_LOGOUT_PATH, CODEX_AUTH_SETTINGS_NAMESPACE, CODEX_AUTH_SETTINGS_PATH, CODEX_AUTH_STATUS_PATH, CODEX_USAGE_PATH };
|
package/lib/client.js
CHANGED
|
@@ -300,6 +300,8 @@ window.__ModuleLoader__.load({
|
|
|
300
300
|
const CODEX_AUTH_LOGIN_PATH = "/plugins/dsh-codex-auth-plugin/auth/login";
|
|
301
301
|
const CODEX_AUTH_LOGOUT_PATH = "/plugins/dsh-codex-auth-plugin/auth/logout";
|
|
302
302
|
const CODEX_USAGE_PATH = "/plugins/dsh-codex-auth-plugin/auth/usage";
|
|
303
|
+
/** Same-origin settings endpoint used when DSH marks a NAS browser as remote. */
|
|
304
|
+
const CODEX_AUTH_SETTINGS_PATH = "/plugins/dsh-codex-auth-plugin/auth/settings";
|
|
303
305
|
//#endregion
|
|
304
306
|
//#region src/client/CodexAuthCard.tsx
|
|
305
307
|
/** Expandable account card for the DSH Plugins settings section. */
|
|
@@ -1515,6 +1517,116 @@ window.__ModuleLoader__.load({
|
|
|
1515
1517
|
};
|
|
1516
1518
|
}
|
|
1517
1519
|
//#endregion
|
|
1520
|
+
//#region src/client/remote-settings-scope.ts
|
|
1521
|
+
const INITIAL_SNAPSHOT = {
|
|
1522
|
+
status: "loading",
|
|
1523
|
+
value: void 0,
|
|
1524
|
+
base: void 0,
|
|
1525
|
+
user: void 0,
|
|
1526
|
+
revision: void 0,
|
|
1527
|
+
writable: false,
|
|
1528
|
+
mode: "host"
|
|
1529
|
+
};
|
|
1530
|
+
async function requestSettings(method, value) {
|
|
1531
|
+
const response = await fetch(CODEX_AUTH_SETTINGS_PATH, {
|
|
1532
|
+
method,
|
|
1533
|
+
headers: {
|
|
1534
|
+
accept: "application/json",
|
|
1535
|
+
...value === void 0 ? {} : { "content-type": "application/json" }
|
|
1536
|
+
},
|
|
1537
|
+
...value === void 0 ? {} : { body: JSON.stringify(value) },
|
|
1538
|
+
credentials: "same-origin"
|
|
1539
|
+
});
|
|
1540
|
+
const payload = await response.json().catch(() => void 0);
|
|
1541
|
+
if (!response.ok) {
|
|
1542
|
+
const error = typeof payload === "object" && payload !== null && "error" in payload && typeof payload.error === "string" ? payload.error : `HTTP ${String(response.status)}`;
|
|
1543
|
+
throw new Error(error);
|
|
1544
|
+
}
|
|
1545
|
+
const settings = decodeCodexAuthSettings(payload);
|
|
1546
|
+
if (settings === void 0) throw new Error("Host returned invalid Codex settings");
|
|
1547
|
+
return settings;
|
|
1548
|
+
}
|
|
1549
|
+
/**
|
|
1550
|
+
* The official settings RPC is intentionally unavailable to non-loopback
|
|
1551
|
+
* browser authorities. This small scope talks only to the plugin-owned,
|
|
1552
|
+
* same-origin endpoint and carries no settings schema or credential data.
|
|
1553
|
+
*/
|
|
1554
|
+
var CodexAuthRemoteSettingsScope = class {
|
|
1555
|
+
snapshot = INITIAL_SNAPSHOT;
|
|
1556
|
+
listeners = /* @__PURE__ */ new Set();
|
|
1557
|
+
tail = Promise.resolve();
|
|
1558
|
+
disposed = false;
|
|
1559
|
+
getSnapshot() {
|
|
1560
|
+
return this.snapshot;
|
|
1561
|
+
}
|
|
1562
|
+
subscribe(listener) {
|
|
1563
|
+
this.listeners.add(listener);
|
|
1564
|
+
return () => {
|
|
1565
|
+
this.listeners.delete(listener);
|
|
1566
|
+
};
|
|
1567
|
+
}
|
|
1568
|
+
load() {
|
|
1569
|
+
return this.enqueue(async () => {
|
|
1570
|
+
try {
|
|
1571
|
+
const settings = await requestSettings("GET");
|
|
1572
|
+
if (this.disposed) return;
|
|
1573
|
+
this.publish({
|
|
1574
|
+
...this.snapshot,
|
|
1575
|
+
status: "ready",
|
|
1576
|
+
value: settings,
|
|
1577
|
+
writable: true
|
|
1578
|
+
});
|
|
1579
|
+
} catch {
|
|
1580
|
+
if (this.disposed) return;
|
|
1581
|
+
this.publish({
|
|
1582
|
+
...this.snapshot,
|
|
1583
|
+
status: "unavailable",
|
|
1584
|
+
writable: false
|
|
1585
|
+
});
|
|
1586
|
+
}
|
|
1587
|
+
});
|
|
1588
|
+
}
|
|
1589
|
+
set(field, value) {
|
|
1590
|
+
if (field !== "enableImageTool" && field !== "enableImageUpload") return Promise.reject(/* @__PURE__ */ new Error(`Unsupported Codex settings field: ${field}`));
|
|
1591
|
+
if (typeof value !== "boolean") return Promise.reject(/* @__PURE__ */ new TypeError(`Codex setting ${field} must be boolean`));
|
|
1592
|
+
return this.enqueue(async () => {
|
|
1593
|
+
const current = this.getSnapshot().value;
|
|
1594
|
+
if (current === void 0) throw new Error("Codex settings are not loaded");
|
|
1595
|
+
const accepted = await requestSettings("PUT", {
|
|
1596
|
+
...current,
|
|
1597
|
+
[field]: value
|
|
1598
|
+
});
|
|
1599
|
+
if (this.disposed) return;
|
|
1600
|
+
this.publish({
|
|
1601
|
+
...this.snapshot,
|
|
1602
|
+
status: "ready",
|
|
1603
|
+
value: accepted,
|
|
1604
|
+
writable: true
|
|
1605
|
+
});
|
|
1606
|
+
});
|
|
1607
|
+
}
|
|
1608
|
+
unset(field) {
|
|
1609
|
+
return this.set(field, false);
|
|
1610
|
+
}
|
|
1611
|
+
async dispose() {
|
|
1612
|
+
this.disposed = true;
|
|
1613
|
+
await this.tail;
|
|
1614
|
+
}
|
|
1615
|
+
enqueue(operation) {
|
|
1616
|
+
if (this.disposed) return Promise.resolve();
|
|
1617
|
+
const task = this.tail.then(async () => {
|
|
1618
|
+
if (this.disposed) return;
|
|
1619
|
+
await operation();
|
|
1620
|
+
});
|
|
1621
|
+
this.tail = task.catch(() => void 0);
|
|
1622
|
+
return task;
|
|
1623
|
+
}
|
|
1624
|
+
publish(next) {
|
|
1625
|
+
this.snapshot = next;
|
|
1626
|
+
for (const listener of [...this.listeners]) listener();
|
|
1627
|
+
}
|
|
1628
|
+
};
|
|
1629
|
+
//#endregion
|
|
1518
1630
|
//#region src/client/locales.ts
|
|
1519
1631
|
/** Browser copy for the standalone Codex authentication card. */
|
|
1520
1632
|
const en = {
|
|
@@ -1639,10 +1751,17 @@ window.__ModuleLoader__.load({
|
|
|
1639
1751
|
en
|
|
1640
1752
|
}), "dsh-codex-auth-plugin: locale");
|
|
1641
1753
|
const t = ctx.locale.bind(namespace);
|
|
1642
|
-
const
|
|
1643
|
-
|
|
1754
|
+
const remoteScope = ctx.get("connection").isLoopback ? void 0 : new CodexAuthRemoteSettingsScope();
|
|
1755
|
+
const configScope = remoteScope ?? ctx.settingsScope.bind({
|
|
1756
|
+
namespace: "dsh-codex-auth",
|
|
1644
1757
|
decode: decodeCodexAuthSettings
|
|
1645
1758
|
});
|
|
1759
|
+
if (remoteScope !== void 0) ctx.effect(() => {
|
|
1760
|
+
remoteScope.load();
|
|
1761
|
+
return async () => {
|
|
1762
|
+
await remoteScope.dispose();
|
|
1763
|
+
};
|
|
1764
|
+
}, "dsh-codex-auth-plugin: remote settings scope");
|
|
1646
1765
|
ctx.slots.inject("settings.plugin.item", () => ctx.slots.register({
|
|
1647
1766
|
name: "settings.plugin.item",
|
|
1648
1767
|
key: CODEX_AUTH_SETTINGS_NAMESPACE,
|
package/lib/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { CODEX_AUTH_LOGIN_PATH, CODEX_AUTH_LOGOUT_PATH, CODEX_AUTH_SETTINGS_NAMESPACE, CODEX_AUTH_STATUS_PATH } from "./auth-paths.js";
|
|
2
2
|
import { a as CODEX_AUTH_FILENAME, c as codexAuthPath, i as logoutCodex, n as codexAuthStatus, o as CODEX_PROVIDER, r as loginCodex, s as CodexCredentialStore, t as CodexAuthStatus } from "./auth-BBBeI24-.js";
|
|
3
3
|
import { CredentialProvider } from "@deepseek-ai/dsh-credentials";
|
|
4
|
+
import "@deepseek-ai/dsh-settings";
|
|
4
5
|
import { AttachmentStore } from "@deepseek-ai/dsh-attachment";
|
|
5
6
|
import { PiAiAdapter } from "@deepseek-ai/dsh-llm-pi-ai";
|
|
6
7
|
import { Context } from "@deepseek-ai/cordis";
|
package/lib/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as CODEX_PROVIDER, i as CODEX_AUTH_FILENAME, n as loginCodex, o as CodexCredentialStore, r as logoutCodex, s as codexAuthPath, t as codexAuthStatus } from "./auth-DQ2F4vc6.js";
|
|
2
|
-
import { CODEX_AUTH_LOGIN_PATH, CODEX_AUTH_LOGOUT_PATH, CODEX_AUTH_SETTINGS_NAMESPACE, CODEX_AUTH_STATUS_PATH, CODEX_USAGE_PATH } from "./auth-paths.js";
|
|
2
|
+
import { CODEX_AUTH_LOGIN_PATH, CODEX_AUTH_LOGOUT_PATH, CODEX_AUTH_SETTINGS_NAMESPACE, CODEX_AUTH_SETTINGS_PATH, CODEX_AUTH_STATUS_PATH, CODEX_USAGE_PATH } from "./auth-paths.js";
|
|
3
3
|
import { createModels } from "@earendil-works/pi-ai";
|
|
4
4
|
import { openaiCodexProvider } from "@earendil-works/pi-ai/providers/openai-codex";
|
|
5
5
|
import { basename } from "node:path";
|
|
@@ -136,10 +136,29 @@ var CodexUsageService = class {
|
|
|
136
136
|
}
|
|
137
137
|
};
|
|
138
138
|
//#endregion
|
|
139
|
+
//#region src/settings-contract.ts
|
|
140
|
+
const DEFAULT_CODEX_AUTH_SETTINGS = Object.freeze({
|
|
141
|
+
enableImageTool: false,
|
|
142
|
+
enableImageUpload: false
|
|
143
|
+
});
|
|
144
|
+
function isRecord(value) {
|
|
145
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
146
|
+
}
|
|
147
|
+
/** Narrow the settings wire payload before it enters React state. */
|
|
148
|
+
function decodeCodexAuthSettings(value) {
|
|
149
|
+
if (!isRecord(value) || typeof value["enableImageTool"] !== "boolean") return void 0;
|
|
150
|
+
return {
|
|
151
|
+
enableImageTool: value["enableImageTool"],
|
|
152
|
+
enableImageUpload: typeof value["enableImageUpload"] === "boolean" ? value["enableImageUpload"] : DEFAULT_CODEX_AUTH_SETTINGS.enableImageUpload
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
//#endregion
|
|
139
156
|
//#region src/auth-routes.ts
|
|
140
157
|
const CODEX_AUTH_URL_TIMEOUT_MS = 3e4;
|
|
141
158
|
const REMOTE_WEB_ORIGIN_NOT_TRUSTED = "remote-web-origin-not-trusted";
|
|
142
159
|
const CODEX_USAGE_UNAVAILABLE = "codex-usage-unavailable";
|
|
160
|
+
const CODEX_SETTINGS_INVALID = "codex-settings-invalid";
|
|
161
|
+
const CODEX_SETTINGS_BODY_LIMIT = 8192;
|
|
143
162
|
function signedInStatus(expiresAt) {
|
|
144
163
|
return expiresAt === void 0 ? { status: "signed-in" } : {
|
|
145
164
|
status: "signed-in",
|
|
@@ -336,6 +355,71 @@ function json(res, status, value) {
|
|
|
336
355
|
});
|
|
337
356
|
res.end(JSON.stringify(value));
|
|
338
357
|
}
|
|
358
|
+
function readJsonBody(req) {
|
|
359
|
+
return new Promise((resolve, reject) => {
|
|
360
|
+
let body = "";
|
|
361
|
+
let size = 0;
|
|
362
|
+
let finished = false;
|
|
363
|
+
req.setEncoding("utf8");
|
|
364
|
+
req.on("data", (chunk) => {
|
|
365
|
+
if (finished) return;
|
|
366
|
+
size += Buffer.byteLength(chunk);
|
|
367
|
+
if (size > CODEX_SETTINGS_BODY_LIMIT) {
|
|
368
|
+
finished = true;
|
|
369
|
+
reject(/* @__PURE__ */ new Error("request body is too large"));
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
body += chunk;
|
|
373
|
+
});
|
|
374
|
+
req.on("end", () => {
|
|
375
|
+
if (finished) return;
|
|
376
|
+
finished = true;
|
|
377
|
+
try {
|
|
378
|
+
resolve(JSON.parse(body));
|
|
379
|
+
} catch {
|
|
380
|
+
reject(/* @__PURE__ */ new Error("request body is not valid JSON"));
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
req.on("error", (error) => {
|
|
384
|
+
if (finished) return;
|
|
385
|
+
finished = true;
|
|
386
|
+
reject(error);
|
|
387
|
+
});
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
function decodeSettingsWrite(value) {
|
|
391
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
392
|
+
const record = value;
|
|
393
|
+
if (typeof record["enableImageTool"] !== "boolean" || typeof record["enableImageUpload"] !== "boolean") return;
|
|
394
|
+
return decodeCodexAuthSettings(record);
|
|
395
|
+
}
|
|
396
|
+
/** Register the plugin-owned settings endpoint for browsers opened through a NAS authority. */
|
|
397
|
+
function registerCodexSettingsRoute(ctx, settings) {
|
|
398
|
+
ctx.effect(() => {
|
|
399
|
+
const authorize = (req, res) => {
|
|
400
|
+
if (trustedRequest(req)) return true;
|
|
401
|
+
json(res, 403, { error: REMOTE_WEB_ORIGIN_NOT_TRUSTED });
|
|
402
|
+
return false;
|
|
403
|
+
};
|
|
404
|
+
return ctx.webServer.register({
|
|
405
|
+
kind: "exact",
|
|
406
|
+
path: CODEX_AUTH_SETTINGS_PATH,
|
|
407
|
+
handler: async (req, res) => {
|
|
408
|
+
if (req.method !== "GET" && req.method !== "PUT") return json(res, 405, { error: "method not allowed" });
|
|
409
|
+
if (!authorize(req, res)) return;
|
|
410
|
+
if (req.method === "GET") return json(res, 200, settings.get());
|
|
411
|
+
try {
|
|
412
|
+
const next = decodeSettingsWrite(await readJsonBody(req));
|
|
413
|
+
if (next === void 0) return json(res, 400, { error: CODEX_SETTINGS_INVALID });
|
|
414
|
+
await settings.update(next);
|
|
415
|
+
json(res, 200, settings.get());
|
|
416
|
+
} catch (error) {
|
|
417
|
+
json(res, 400, { error: safeMessage(error) });
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
}, "dsh-codex-auth-plugin: remote settings route");
|
|
422
|
+
}
|
|
339
423
|
/** Register the auth endpoints when the DSH Web server is available. */
|
|
340
424
|
function registerCodexAuthRoutes(ctx, store, mirror) {
|
|
341
425
|
const auth = new CodexWebAuth(store, CODEX_AUTH_URL_TIMEOUT_MS, mirror);
|
|
@@ -460,12 +544,6 @@ var CodexCredentialMirror = class {
|
|
|
460
544
|
}
|
|
461
545
|
};
|
|
462
546
|
//#endregion
|
|
463
|
-
//#region src/settings-contract.ts
|
|
464
|
-
const DEFAULT_CODEX_AUTH_SETTINGS = Object.freeze({
|
|
465
|
-
enableImageTool: false,
|
|
466
|
-
enableImageUpload: false
|
|
467
|
-
});
|
|
468
|
-
//#endregion
|
|
469
547
|
//#region src/settings.ts
|
|
470
548
|
/** Host settings registration that makes the standalone auth card discoverable. */
|
|
471
549
|
/** Branded namespace used by the Host settings service. */
|
|
@@ -706,6 +784,7 @@ function apply(ctx) {
|
|
|
706
784
|
};
|
|
707
785
|
}, "dsh-codex-auth: credential mirror");
|
|
708
786
|
registerCodexAuthRoutes(ctx, store, mirror);
|
|
787
|
+
registerCodexSettingsRoute(ctx, settings);
|
|
709
788
|
let stopped = false;
|
|
710
789
|
let imageFiber;
|
|
711
790
|
let imageTail = Promise.resolve();
|
package/package.json
CHANGED