@pure01fx/dsh-openai-codex-auth 0.5.0 → 0.6.0

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/lib/usage.d.ts ADDED
@@ -0,0 +1,29 @@
1
+ /** Account-scoped subscription quota projection and reconciliation. */
2
+ import { type CodexRateLimitCredits, type CodexRateLimitUpdate } from './rate-limits.js';
3
+ export interface UsageWindow {
4
+ usedPercent: number;
5
+ windowSeconds?: number;
6
+ resetAt?: number;
7
+ }
8
+ export interface UsageLimitSummary {
9
+ id: string;
10
+ name?: string;
11
+ primary?: UsageWindow;
12
+ secondary?: UsageWindow;
13
+ limitReached?: boolean;
14
+ }
15
+ export interface UsageSummary {
16
+ planType?: string;
17
+ primary?: UsageWindow;
18
+ secondary?: UsageWindow;
19
+ limitReached?: boolean;
20
+ resetCredits?: number;
21
+ credits?: CodexRateLimitCredits;
22
+ limits?: UsageLimitSummary[];
23
+ source: 'response' | 'endpoint';
24
+ fetchedAt: number;
25
+ }
26
+ /** Reduce a full `wham/usage` payload to bounded fields displayed by the Web card. */
27
+ export declare function normalizeUsage(value: unknown): UsageSummary;
28
+ /** Merge sparse direct transport observations while retaining endpoint-only metadata. */
29
+ export declare function mergeDirectUsage(previous: UsageSummary | undefined, updates: readonly CodexRateLimitUpdate[]): UsageSummary;
package/lib/usage.js ADDED
@@ -0,0 +1,160 @@
1
+ /** Account-scoped subscription quota projection and reconciliation. */
2
+ import { parseCodexRateLimitCredits, } from './rate-limits.js';
3
+ function optionalNumber(value) {
4
+ return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
5
+ }
6
+ function usageWindow(value) {
7
+ if (value === null || typeof value !== 'object')
8
+ return undefined;
9
+ const row = value;
10
+ const usedPercent = optionalNumber(row.used_percent ?? row.usedPercent);
11
+ if (usedPercent === undefined)
12
+ return undefined;
13
+ const windowSeconds = optionalNumber(row.limit_window_seconds ?? row.windowDurationSecs);
14
+ const resetAt = optionalNumber(row.reset_at ?? row.resetsAt);
15
+ return {
16
+ usedPercent: Math.max(0, Math.min(100, usedPercent)),
17
+ ...windowSeconds === undefined ? {} : { windowSeconds },
18
+ ...resetAt === undefined ? {} : { resetAt },
19
+ };
20
+ }
21
+ function boundedUsageText(value) {
22
+ if (typeof value !== 'string')
23
+ return undefined;
24
+ const text = value.trim();
25
+ return text.length > 0 && text.length <= 128 ? text : undefined;
26
+ }
27
+ function normalizedUsageLimitId(value) {
28
+ return boundedUsageText(value)?.toLowerCase().replaceAll('-', '_');
29
+ }
30
+ function usageLimit(id, name, value) {
31
+ if (value === null || typeof value !== 'object' || Array.isArray(value))
32
+ return undefined;
33
+ const row = value;
34
+ const primary = usageWindow(row.primary_window ?? row.primary);
35
+ const secondary = usageWindow(row.secondary_window ?? row.secondary);
36
+ const limitReached = typeof row.limit_reached === 'boolean'
37
+ ? row.limit_reached
38
+ : typeof row.limitReached === 'boolean' ? row.limitReached : undefined;
39
+ if (primary === undefined && secondary === undefined && limitReached === undefined)
40
+ return undefined;
41
+ return {
42
+ id,
43
+ ...name === undefined ? {} : { name },
44
+ ...primary === undefined ? {} : { primary },
45
+ ...secondary === undefined ? {} : { secondary },
46
+ ...limitReached === undefined ? {} : { limitReached },
47
+ };
48
+ }
49
+ function sortedUsageLimits(limits) {
50
+ return [...limits].sort((left, right) => {
51
+ if (left.id === 'codex')
52
+ return right.id === 'codex' ? 0 : -1;
53
+ if (right.id === 'codex')
54
+ return 1;
55
+ return left.id.localeCompare(right.id);
56
+ }).slice(0, 32);
57
+ }
58
+ /** Reduce a full `wham/usage` payload to bounded fields displayed by the Web card. */
59
+ export function normalizeUsage(value) {
60
+ const root = value !== null && typeof value === 'object' ? value : {};
61
+ const defaultValue = root.rate_limit ?? root.rateLimits;
62
+ const defaultLimit = usageLimit('codex', undefined, defaultValue);
63
+ const limits = defaultLimit === undefined ? [] : [defaultLimit];
64
+ const additional = root.additional_rate_limits ?? root.additionalRateLimits;
65
+ if (Array.isArray(additional)) {
66
+ for (const value of additional.slice(0, 31)) {
67
+ if (value === null || typeof value !== 'object' || Array.isArray(value))
68
+ continue;
69
+ const row = value;
70
+ const id = normalizedUsageLimitId(row.metered_feature ?? row.meteredFeature);
71
+ if (id === undefined || id === 'codex' || limits.some(limit => limit.id === id))
72
+ continue;
73
+ const extra = usageLimit(id, boundedUsageText(row.limit_name ?? row.limitName), row.rate_limit ?? row.rateLimit);
74
+ if (extra !== undefined)
75
+ limits.push(extra);
76
+ }
77
+ }
78
+ const sortedLimits = sortedUsageLimits(limits);
79
+ const projected = sortedLimits.find(limit => limit.id === 'codex') ?? sortedLimits[0];
80
+ const resetCreditValue = root.rate_limit_reset_credits ?? root.rateLimitResetCredits;
81
+ const resetCreditRow = resetCreditValue !== null && typeof resetCreditValue === 'object'
82
+ ? resetCreditValue : undefined;
83
+ const resetCredits = optionalNumber(resetCreditRow?.available_count ?? resetCreditRow?.availableCount);
84
+ const planType = boundedUsageText(root.plan_type ?? root.planType);
85
+ const parsedCredits = parseCodexRateLimitCredits(root.credits);
86
+ return {
87
+ ...planType === undefined ? {} : { planType },
88
+ ...projected?.primary === undefined ? {} : { primary: projected.primary },
89
+ ...projected?.secondary === undefined ? {} : { secondary: projected.secondary },
90
+ ...projected?.limitReached === undefined ? {} : { limitReached: projected.limitReached },
91
+ ...resetCredits === undefined ? {} : { resetCredits },
92
+ ...parsedCredits === undefined ? {} : { credits: parsedCredits },
93
+ ...sortedLimits.length === 0 ? {} : { limits: sortedLimits },
94
+ source: 'endpoint',
95
+ fetchedAt: Date.now(),
96
+ };
97
+ }
98
+ function mergeUsageWindow(previous, update) {
99
+ return {
100
+ usedPercent: update.usedPercent,
101
+ ...update.windowSeconds === undefined
102
+ ? previous?.windowSeconds === undefined ? {} : { windowSeconds: previous.windowSeconds }
103
+ : { windowSeconds: update.windowSeconds },
104
+ ...update.resetAt === undefined
105
+ ? previous?.resetAt === undefined ? {} : { resetAt: previous.resetAt }
106
+ : { resetAt: update.resetAt },
107
+ };
108
+ }
109
+ function mergeUsageLimit(previous, update) {
110
+ const primary = update.primary === undefined ? previous?.primary
111
+ : update.primary === null ? undefined : mergeUsageWindow(previous?.primary, update.primary);
112
+ const secondary = update.secondary === undefined ? previous?.secondary
113
+ : update.secondary === null ? undefined : mergeUsageWindow(previous?.secondary, update.secondary);
114
+ const name = update.limitName ?? previous?.name;
115
+ const limitReached = update.limitReached ?? previous?.limitReached;
116
+ return {
117
+ id: update.limitId,
118
+ ...name === undefined ? {} : { name },
119
+ ...primary === undefined ? {} : { primary },
120
+ ...secondary === undefined ? {} : { secondary },
121
+ ...limitReached === undefined ? {} : { limitReached },
122
+ };
123
+ }
124
+ /** Merge sparse direct transport observations while retaining endpoint-only metadata. */
125
+ export function mergeDirectUsage(previous, updates) {
126
+ const byId = new Map((previous?.limits ?? []).map(limit => [limit.id, limit]));
127
+ if (byId.size === 0 && previous !== undefined
128
+ && (previous.primary !== undefined || previous.secondary !== undefined
129
+ || previous.limitReached !== undefined)) {
130
+ byId.set('codex', {
131
+ id: 'codex',
132
+ ...previous.primary === undefined ? {} : { primary: previous.primary },
133
+ ...previous.secondary === undefined ? {} : { secondary: previous.secondary },
134
+ ...previous.limitReached === undefined ? {} : { limitReached: previous.limitReached },
135
+ });
136
+ }
137
+ for (const update of updates.slice(0, 32)) {
138
+ byId.set(update.limitId, mergeUsageLimit(byId.get(update.limitId), update));
139
+ }
140
+ const limits = sortedUsageLimits(byId.values());
141
+ const projected = limits.find(limit => limit.id === 'codex') ?? limits[0];
142
+ const planType = updates.find(update => update.planType !== undefined)?.planType ?? previous?.planType;
143
+ const parsedCredits = updates.find(update => update.credits !== undefined)?.credits ?? previous?.credits;
144
+ const resetCredits = previous?.resetCredits;
145
+ const hasDirectDefault = updates.some(update => update.limitId === 'codex'
146
+ && (update.primary !== undefined || update.secondary !== undefined));
147
+ const source = hasDirectDefault ? 'response' : previous?.source ?? 'response';
148
+ const fetchedAt = hasDirectDefault ? Date.now() : previous?.fetchedAt ?? Date.now();
149
+ return {
150
+ ...planType === undefined ? {} : { planType },
151
+ ...projected?.primary === undefined ? {} : { primary: projected.primary },
152
+ ...projected?.secondary === undefined ? {} : { secondary: projected.secondary },
153
+ ...projected?.limitReached === undefined ? {} : { limitReached: projected.limitReached },
154
+ ...resetCredits === undefined ? {} : { resetCredits },
155
+ ...parsedCredits === undefined ? {} : { credits: parsedCredits },
156
+ ...limits.length === 0 ? {} : { limits },
157
+ source,
158
+ fetchedAt,
159
+ };
160
+ }
package/package.json CHANGED
@@ -1,8 +1,11 @@
1
1
  {
2
2
  "name": "@pure01fx/dsh-openai-codex-auth",
3
- "version": "0.5.0",
4
- "description": "Device-code-first OpenAI Codex login and same-origin Web integration for DeepSeek Harness",
3
+ "version": "0.6.0",
4
+ "description": "Native ChatGPT Codex provider, device-code-first login, and same-origin Web integration for DeepSeek Harness",
5
5
  "license": "MIT",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
6
9
  "repository": {
7
10
  "type": "git",
8
11
  "url": "git+https://github.com/pure01fx/dsh-openai-codex-auth.git"
@@ -30,16 +33,46 @@
30
33
  "files": [
31
34
  "lib/index.js",
32
35
  "lib/index.d.ts",
36
+ "lib/catalog.js",
37
+ "lib/catalog.d.ts",
38
+ "lib/endpoint.js",
39
+ "lib/endpoint.d.ts",
40
+ "lib/native-adapter.js",
41
+ "lib/native-adapter.d.ts",
42
+ "lib/native-http.js",
43
+ "lib/native-http.d.ts",
44
+ "lib/native-websocket.js",
45
+ "lib/native-websocket.d.ts",
46
+ "lib/native-websocket-session.js",
47
+ "lib/native-websocket-session.d.ts",
48
+ "lib/native-websocket-socket.js",
49
+ "lib/native-websocket-socket.d.ts",
50
+ "lib/responses.js",
51
+ "lib/responses.d.ts",
52
+ "lib/replay.js",
53
+ "lib/replay.d.ts",
54
+ "lib/rate-limits.js",
55
+ "lib/rate-limits.d.ts",
56
+ "lib/response-usage.js",
57
+ "lib/response-usage.d.ts",
58
+ "lib/upstream.js",
59
+ "lib/upstream.d.ts",
60
+ "lib/sse.js",
61
+ "lib/sse.d.ts",
62
+ "lib/usage.js",
63
+ "lib/usage.d.ts",
33
64
  "client.js",
34
65
  "cordis.patch.yml",
35
66
  "assets/readme/hero.svg",
36
67
  "assets/readme/workflow.svg",
37
68
  "README.md",
69
+ "CHANGELOG.md",
38
70
  "LICENSE"
39
71
  ],
40
72
  "scripts": {
41
73
  "build": "tsc",
42
- "test": "vitest run"
74
+ "test": "vitest run",
75
+ "prepack": "pnpm build"
43
76
  },
44
77
  "dsh": {
45
78
  "bundle": {
@@ -56,20 +89,23 @@
56
89
  },
57
90
  "peerDependencies": {
58
91
  "@deepseek-ai/cordis": "^4.0.1",
59
- "@deepseek-ai/dsh-credentials": "^0.1.0-rc.5",
60
- "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.6"
92
+ "@deepseek-ai/dsh-credentials": "0.1.0-rc.6",
93
+ "@deepseek-ai/dsh-host-webserver": "0.1.0-rc.6",
94
+ "@deepseek-ai/dsh-llm": "0.1.0-rc.6"
61
95
  },
62
96
  "dependencies": {
63
- "@deepseek-ai/dsh-atomic-write": "^0.1.0-rc.5",
64
- "@deepseek-ai/dsh-credentials": "^0.1.0-rc.5",
65
- "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.5",
66
- "@deepseek-ai/schemastery": "^3.18.1"
97
+ "@deepseek-ai/dsh-atomic-write": "0.1.0-rc.6",
98
+ "@deepseek-ai/dsh-credentials": "0.1.0-rc.6",
99
+ "@deepseek-ai/dsh-home-paths": "0.1.0-rc.6",
100
+ "@deepseek-ai/schemastery": "^3.18.1",
101
+ "ws": "8.21.3"
67
102
  },
68
103
  "devDependencies": {
69
104
  "@deepseek-ai/cordis": "^4.0.1",
70
105
  "@deepseek-ai/dsh-agent": "0.1.0-rc.6",
71
- "@deepseek-ai/dsh-credentials": "^0.1.0-rc.5",
72
- "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.6",
106
+ "@deepseek-ai/dsh-credentials": "0.1.0-rc.6",
107
+ "@deepseek-ai/dsh-host-webserver": "0.1.0-rc.6",
108
+ "@deepseek-ai/dsh-llm": "0.1.0-rc.6",
73
109
  "@deepseek-ai/dsh-session": "0.1.0-rc.6",
74
110
  "@types/node": "^22.20.0",
75
111
  "typescript": "^6.0.3",