codex-multi-auth 0.1.4 → 0.1.7
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/LICENSE +1 -1
- package/README.md +3 -3
- package/assets/readme-hero.svg +31 -31
- package/dist/lib/codex-cli/state.js +4 -4
- package/dist/lib/codex-cli/state.js.map +1 -1
- package/dist/lib/codex-cli/writer.d.ts.map +1 -1
- package/dist/lib/codex-cli/writer.js +62 -5
- package/dist/lib/codex-cli/writer.js.map +1 -1
- package/dist/lib/context-overflow.js +10 -10
- package/dist/lib/oauth-success.html +66 -210
- package/dist/lib/prompts/codex.js +2 -2
- package/dist/lib/runtime-paths.d.ts.map +1 -1
- package/dist/lib/runtime-paths.js +23 -1
- package/dist/lib/runtime-paths.js.map +1 -1
- package/dist/lib/storage.d.ts.map +1 -1
- package/dist/lib/storage.js +119 -2
- package/dist/lib/storage.js.map +1 -1
- package/dist/lib/ui/auth-menu.d.ts.map +1 -1
- package/dist/lib/ui/auth-menu.js +13 -1
- package/dist/lib/ui/auth-menu.js.map +1 -1
- package/package.json +1 -1
- package/scripts/bench-format/hashline-v2.mjs +642 -642
- package/scripts/bench-format/render.mjs +496 -496
- package/scripts/bench-format/stats.mjs +54 -54
- package/scripts/bench-format/tasks.mjs +151 -151
- package/scripts/benchmark-render-dashboard.mjs +49 -49
- package/scripts/codex-multi-auth.js +13 -1
- package/scripts/codex.js +345 -28
- package/scripts/install-codex-auth.js +9 -9
- package/scripts/test-all-models.sh +7 -7
- package/scripts/test-model-matrix.js +59 -24
- package/scripts/validate-model-map.sh +7 -7
|
@@ -2,21 +2,17 @@
|
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
|
6
|
-
<title>
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>Codex Sign-In Complete</title>
|
|
7
7
|
<style>
|
|
8
|
-
/* Space Grotesk import removed to avoid CSP font-src violations; rely on system stack. */
|
|
9
|
-
|
|
10
8
|
:root {
|
|
11
|
-
|
|
12
|
-
--
|
|
13
|
-
--
|
|
14
|
-
--
|
|
15
|
-
--
|
|
16
|
-
--
|
|
17
|
-
--
|
|
18
|
-
--accent: #49f1a8;
|
|
19
|
-
--accent-soft: rgba(73, 241, 168, 0.15);
|
|
9
|
+
color-scheme: dark;
|
|
10
|
+
--bg: #0b0b0b;
|
|
11
|
+
--panel: #111111;
|
|
12
|
+
--text: #f2f2f2;
|
|
13
|
+
--muted: #a3a3a3;
|
|
14
|
+
--line: #232323;
|
|
15
|
+
--ok: #7cf0a6;
|
|
20
16
|
}
|
|
21
17
|
|
|
22
18
|
* {
|
|
@@ -26,245 +22,105 @@
|
|
|
26
22
|
body {
|
|
27
23
|
margin: 0;
|
|
28
24
|
min-height: 100vh;
|
|
29
|
-
font-family: "Segoe UI", system-ui, -apple-system, "IBM Plex Sans", sans-serif;
|
|
30
|
-
background: radial-gradient(circle at top, rgba(73, 241, 168, 0.12), transparent 55%),
|
|
31
|
-
linear-gradient(180deg, var(--bg), var(--bg2));
|
|
32
|
-
color: var(--text);
|
|
33
25
|
display: grid;
|
|
34
26
|
place-items: center;
|
|
35
|
-
|
|
27
|
+
background: var(--bg);
|
|
28
|
+
color: var(--text);
|
|
29
|
+
font-family: "Geist Mono", "GeistMono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
|
30
|
+
padding: 24px;
|
|
36
31
|
}
|
|
37
32
|
|
|
38
33
|
main {
|
|
39
|
-
width: min(
|
|
40
|
-
background: var(--
|
|
41
|
-
border
|
|
42
|
-
border:
|
|
43
|
-
padding:
|
|
44
|
-
box-shadow: 0 24px 60px rgba(0, 0, 0, 0.55);
|
|
45
|
-
display: flex;
|
|
46
|
-
flex-direction: column;
|
|
47
|
-
gap: 18px;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
.eyebrow {
|
|
51
|
-
font-size: 12px;
|
|
52
|
-
text-transform: uppercase;
|
|
53
|
-
letter-spacing: 0.22em;
|
|
54
|
-
color: var(--muted);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
.icon {
|
|
58
|
-
width: 64px;
|
|
59
|
-
height: 64px;
|
|
60
|
-
border-radius: 16px;
|
|
61
|
-
border: 1px solid var(--border);
|
|
62
|
-
background: var(--accent-soft);
|
|
34
|
+
width: min(520px, 100%);
|
|
35
|
+
background: var(--panel);
|
|
36
|
+
border: 1px solid var(--line);
|
|
37
|
+
border-radius: 12px;
|
|
38
|
+
padding: 20px;
|
|
63
39
|
display: grid;
|
|
64
|
-
|
|
65
|
-
color: var(--accent);
|
|
66
|
-
margin: 4px 0 6px;
|
|
67
|
-
position: relative;
|
|
68
|
-
animation: fade 1s ease both;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
.icon::after {
|
|
72
|
-
content: "";
|
|
73
|
-
width: 20px;
|
|
74
|
-
height: 12px;
|
|
75
|
-
border-left: 3px solid currentColor;
|
|
76
|
-
border-bottom: 3px solid currentColor;
|
|
77
|
-
transform: rotate(-45deg);
|
|
40
|
+
gap: 14px;
|
|
78
41
|
}
|
|
79
42
|
|
|
80
43
|
h1 {
|
|
81
44
|
margin: 0;
|
|
82
|
-
font-size:
|
|
45
|
+
font-size: 20px;
|
|
46
|
+
font-weight: 600;
|
|
83
47
|
letter-spacing: -0.02em;
|
|
84
48
|
}
|
|
85
49
|
|
|
86
|
-
|
|
50
|
+
p {
|
|
87
51
|
margin: 0;
|
|
88
52
|
color: var(--muted);
|
|
89
|
-
font-size: 15px;
|
|
90
|
-
line-height: 1.6;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
.state {
|
|
94
|
-
display: flex;
|
|
95
|
-
align-items: baseline;
|
|
96
|
-
justify-content: space-between;
|
|
97
|
-
padding: 16px 18px;
|
|
98
|
-
border-radius: 16px;
|
|
99
|
-
background: rgba(8, 14, 11, 0.75);
|
|
100
|
-
border: 1px solid var(--border);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
.state span {
|
|
104
|
-
font-size: 13px;
|
|
105
|
-
text-transform: uppercase;
|
|
106
|
-
letter-spacing: 0.15em;
|
|
107
|
-
color: var(--muted);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
.state strong {
|
|
111
|
-
font-size: 20px;
|
|
112
|
-
color: var(--accent);
|
|
113
|
-
font-weight: 600;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
.status-list {
|
|
117
|
-
list-style: none;
|
|
118
|
-
margin: 8px 0 0;
|
|
119
|
-
padding: 0;
|
|
120
|
-
display: flex;
|
|
121
|
-
flex-direction: column;
|
|
122
|
-
gap: 10px;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
.status-list li {
|
|
126
|
-
display: flex;
|
|
127
|
-
align-items: center;
|
|
128
|
-
justify-content: space-between;
|
|
129
|
-
border-bottom: 1px solid var(--divider);
|
|
130
|
-
padding-bottom: 8px;
|
|
131
53
|
font-size: 14px;
|
|
54
|
+
line-height: 1.5;
|
|
132
55
|
}
|
|
133
56
|
|
|
134
|
-
.status
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
.status-list span {
|
|
140
|
-
color: var(--muted);
|
|
57
|
+
.status {
|
|
58
|
+
display: inline-flex;
|
|
59
|
+
align-items: center;
|
|
60
|
+
gap: 8px;
|
|
61
|
+
color: var(--ok);
|
|
141
62
|
font-size: 13px;
|
|
142
|
-
letter-spacing: 0.02em;
|
|
143
63
|
}
|
|
144
64
|
|
|
145
|
-
.
|
|
146
|
-
|
|
147
|
-
|
|
65
|
+
.dot {
|
|
66
|
+
width: 8px;
|
|
67
|
+
height: 8px;
|
|
68
|
+
border-radius: 50%;
|
|
69
|
+
background: currentColor;
|
|
148
70
|
}
|
|
149
71
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
padding-top: 14px;
|
|
72
|
+
dl {
|
|
73
|
+
margin: 0;
|
|
153
74
|
display: grid;
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
.meta-row {
|
|
158
|
-
display: flex;
|
|
159
|
-
justify-content: space-between;
|
|
160
|
-
align-items: baseline;
|
|
75
|
+
grid-template-columns: 120px 1fr;
|
|
76
|
+
gap: 8px 12px;
|
|
161
77
|
font-size: 13px;
|
|
162
|
-
color: var(--muted);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
.meta-row code {
|
|
166
|
-
font-family: "Segoe UI", system-ui, -apple-system, "SFMono-Regular", Menlo, monospace;
|
|
167
|
-
background: rgba(255, 255, 255, 0.04);
|
|
168
|
-
border-radius: 8px;
|
|
169
|
-
padding: 4px 8px;
|
|
170
|
-
color: var(--text);
|
|
171
78
|
}
|
|
172
79
|
|
|
173
|
-
|
|
174
|
-
margin: 0;
|
|
175
|
-
font-size: 13px;
|
|
80
|
+
dt {
|
|
176
81
|
color: var(--muted);
|
|
177
|
-
border-top: 1px solid var(--divider);
|
|
178
|
-
padding-top: 14px;
|
|
179
82
|
}
|
|
180
83
|
|
|
181
|
-
|
|
84
|
+
dd {
|
|
85
|
+
margin: 0;
|
|
182
86
|
color: var(--text);
|
|
87
|
+
word-break: break-word;
|
|
183
88
|
}
|
|
184
89
|
|
|
185
|
-
|
|
90
|
+
code {
|
|
91
|
+
background: #171717;
|
|
92
|
+
border: 1px solid var(--line);
|
|
93
|
+
border-radius: 6px;
|
|
94
|
+
padding: 2px 6px;
|
|
95
|
+
font-family: inherit;
|
|
186
96
|
font-size: 12px;
|
|
187
|
-
color: var(--muted);
|
|
188
|
-
text-align: center;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
@keyframes fade {
|
|
192
|
-
from { opacity: 0; transform: translateY(6px); }
|
|
193
|
-
to { opacity: 1; transform: translateY(0); }
|
|
194
97
|
}
|
|
195
98
|
|
|
196
|
-
@media (
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
@media (max-width: 480px) {
|
|
203
|
-
main {
|
|
204
|
-
padding: 24px;
|
|
205
|
-
border-radius: 18px;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
.state {
|
|
209
|
-
flex-direction: column;
|
|
210
|
-
align-items: flex-start;
|
|
211
|
-
gap: 4px;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
.status-list li {
|
|
215
|
-
flex-direction: column;
|
|
216
|
-
align-items: flex-start;
|
|
217
|
-
gap: 2px;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
.meta-row {
|
|
221
|
-
flex-direction: column;
|
|
222
|
-
gap: 4px;
|
|
99
|
+
@media (max-width: 520px) {
|
|
100
|
+
dl {
|
|
101
|
+
grid-template-columns: 1fr;
|
|
223
102
|
}
|
|
224
103
|
}
|
|
225
104
|
</style>
|
|
226
105
|
</head>
|
|
227
106
|
<body>
|
|
228
107
|
<main role="main" aria-label="OAuth callback received">
|
|
229
|
-
<
|
|
230
|
-
<
|
|
231
|
-
|
|
232
|
-
<
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
<strong>Processing</strong>
|
|
108
|
+
<h1>Sign-in complete</h1>
|
|
109
|
+
<p>Return to your terminal to finish Codex login.</p>
|
|
110
|
+
|
|
111
|
+
<div class="status" aria-live="polite">
|
|
112
|
+
<span class="dot" aria-hidden="true"></span>
|
|
113
|
+
Callback received
|
|
236
114
|
</div>
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
</
|
|
242
|
-
<
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
<li>
|
|
247
|
-
<span>Credentials</span>
|
|
248
|
-
<span>persisting after terminal completes</span>
|
|
249
|
-
</li>
|
|
250
|
-
<li>
|
|
251
|
-
<span>Session</span>
|
|
252
|
-
<span>activating in terminal</span>
|
|
253
|
-
</li>
|
|
254
|
-
</ul>
|
|
255
|
-
<section class="meta" aria-label="Callback summary">
|
|
256
|
-
<div class="meta-row">
|
|
257
|
-
<span>Callback</span>
|
|
258
|
-
<!-- Port 1455 is fixed by design via REDIRECT_URI -->
|
|
259
|
-
<code>localhost:1455</code>
|
|
260
|
-
</div>
|
|
261
|
-
<div class="meta-row">
|
|
262
|
-
<span>Tip</span>
|
|
263
|
-
<span>Close this tab when you are done.</span>
|
|
264
|
-
</div>
|
|
265
|
-
</section>
|
|
266
|
-
<p class="tip"><strong>Next:</strong> return to the terminal window to continue.</p>
|
|
267
|
-
<footer>Back to terminal to continue.</footer>
|
|
115
|
+
|
|
116
|
+
<dl>
|
|
117
|
+
<dt>Endpoint</dt>
|
|
118
|
+
<dd><code>localhost:1455</code></dd>
|
|
119
|
+
<dt>Flow</dt>
|
|
120
|
+
<dd>OAuth callback captured</dd>
|
|
121
|
+
<dt>Next</dt>
|
|
122
|
+
<dd>Close this tab and continue in terminal</dd>
|
|
123
|
+
</dl>
|
|
268
124
|
</main>
|
|
269
125
|
</body>
|
|
270
|
-
</html>
|
|
126
|
+
</html>
|
|
@@ -307,7 +307,7 @@ YOU ARE IN A DIFFERENT ENVIRONMENT. These instructions override ALL previous too
|
|
|
307
307
|
|
|
308
308
|
<tool_replacements priority="0">
|
|
309
309
|
<critical_rule priority="0">
|
|
310
|
-
apply_patch/applyPatch are Codex names, but host tool names vary by version.
|
|
310
|
+
apply_patch/applyPatch are Codex names, but host tool names vary by version.
|
|
311
311
|
- Inspect the actual tool list before editing.
|
|
312
312
|
- If edit exists: use edit for precise in-place string replacements and hashline edits.
|
|
313
313
|
- If edit is absent and apply_patch exists: use apply_patch for those precise/hashline edits in this plugin.
|
|
@@ -329,7 +329,7 @@ File Operations:
|
|
|
329
329
|
- write - Create new files (if available)
|
|
330
330
|
- edit - Modify existing files with string replacement (version-dependent)
|
|
331
331
|
- oldString must be literal text from the current file; never pass unresolved placeholders like \${TARGET_SNIPPET}
|
|
332
|
-
- apply_patch - May be the edit/patch tool name in newer host builds (version-dependent)
|
|
332
|
+
- apply_patch - May be the edit/patch tool name in newer host builds (version-dependent)
|
|
333
333
|
- hashline_read - Read lines with hashline refs (L<line>#<hash>) for deterministic edits
|
|
334
334
|
- patch - Apply diff patches (version-dependent)
|
|
335
335
|
- read - Read file contents
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-paths.d.ts","sourceRoot":"","sources":["../../lib/runtime-paths.ts"],"names":[],"mappings":"AAkCA;;;;;;GAMG;AAEH,wBAAgB,eAAe,IAAI,MAAM,CAGxC;
|
|
1
|
+
{"version":3,"file":"runtime-paths.d.ts","sourceRoot":"","sources":["../../lib/runtime-paths.ts"],"names":[],"mappings":"AAkCA;;;;;;GAMG;AAEH,wBAAgB,eAAe,IAAI,MAAM,CAGxC;AA2GD;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAiC7C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { homedir } from "node:os";
|
|
2
2
|
import { join, win32 } from "node:path";
|
|
3
|
-
import { existsSync } from "node:fs";
|
|
3
|
+
import { existsSync, readdirSync } from "node:fs";
|
|
4
4
|
function firstNonEmpty(values) {
|
|
5
5
|
for (const value of values) {
|
|
6
6
|
const trimmed = (value ?? "").trim();
|
|
@@ -100,6 +100,28 @@ function hasAccountsStorage(dir) {
|
|
|
100
100
|
if (existsSync(join(dir, fileName))) {
|
|
101
101
|
return true;
|
|
102
102
|
}
|
|
103
|
+
if (existsSync(join(dir, `${fileName}.wal`))) {
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
109
|
+
for (const entry of entries) {
|
|
110
|
+
if (!entry.isFile())
|
|
111
|
+
continue;
|
|
112
|
+
for (const fileName of accountFiles) {
|
|
113
|
+
if (!entry.name.startsWith(`${fileName}.`))
|
|
114
|
+
continue;
|
|
115
|
+
if (entry.name.endsWith(".tmp"))
|
|
116
|
+
continue;
|
|
117
|
+
if (entry.name.includes(".rotate."))
|
|
118
|
+
continue;
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// Ignore unreadable directories and fall back to known filename probes.
|
|
103
125
|
}
|
|
104
126
|
return false;
|
|
105
127
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-paths.js","sourceRoot":"","sources":["../../lib/runtime-paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"runtime-paths.js","sourceRoot":"","sources":["../../lib/runtime-paths.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../lib/storage.ts"],"names":[],"mappings":"AAeA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACtB,MAAM,yBAAyB,CAAC;AAEjC,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,CAAC;AAe3H,MAAM,WAAW,wBAAyB,SAAQ,iBAAiB;IAClE,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,uBAAuB;IACvC,OAAO,EAAE,CAAC,CAAC;IACX,QAAQ,EAAE,wBAAwB,EAAE,CAAC;CACrC;AAED;;GAEG;AACH,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAOrF;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAsB3E;
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../lib/storage.ts"],"names":[],"mappings":"AAeA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACtB,MAAM,yBAAyB,CAAC;AAEjC,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,CAAC;AAe3H,MAAM,WAAW,wBAAyB,SAAQ,iBAAiB;IAClE,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,uBAAuB;IACvC,OAAO,EAAE,CAAC,CAAC;IACX,QAAQ,EAAE,wBAAwB,EAAE,CAAC;CACrC;AAED;;GAEG;AACH,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAOrF;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAsB3E;AAmFD,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAE9D;AA+ND,wBAAgB,4BAA4B,IAAI,MAAM,CAErD;AAED,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CA2B/D;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAK9D;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAKvC;AAED,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAmLD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,SAAS;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,EAC7H,QAAQ,EAAE,CAAC,EAAE,GACZ,CAAC,EAAE,CAEL;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAK/E;AAED,wBAAgB,0BAA0B,CAAC,CAAC,SAAS;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,EAC1G,QAAQ,EAAE,CAAC,EAAE,GACZ,CAAC,EAAE,CAsDL;AA+BD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,OAAO,GAAG,gBAAgB,GAAG,IAAI,CAyF9E;AAED;;;;GAIG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAErE;AAqSD,wBAAsB,6BAA6B,CAAC,CAAC,EACnD,OAAO,EAAE,CACP,OAAO,EAAE,gBAAgB,GAAG,IAAI,EAChC,OAAO,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,KAClD,OAAO,CAAC,CAAC,CAAC,GACd,OAAO,CAAC,CAAC,CAAC,CAKZ;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAI3E;AAED;;;GAGG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAyBnD;AA8ED,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,uBAAuB,CAAC,CA+C5E;AAED,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBzF;AAED,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAW1D;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,UAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBlF;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAyDpH"}
|
package/dist/lib/storage.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { promises as fs, existsSync } from "node:fs";
|
|
2
|
-
import { dirname, join } from "node:path";
|
|
2
|
+
import { basename, dirname, join } from "node:path";
|
|
3
3
|
import { createHash } from "node:crypto";
|
|
4
4
|
import { ACCOUNT_LIMITS } from "./constants.js";
|
|
5
5
|
import { createLogger } from "./logger.js";
|
|
@@ -67,6 +67,28 @@ function withStorageLock(fn) {
|
|
|
67
67
|
});
|
|
68
68
|
return previousMutex.then(fn).finally(() => releaseLock());
|
|
69
69
|
}
|
|
70
|
+
function looksLikeSyntheticFixtureAccount(account) {
|
|
71
|
+
const email = typeof account.email === "string" ? account.email.trim().toLowerCase() : "";
|
|
72
|
+
const refreshToken = typeof account.refreshToken === "string" ? account.refreshToken.trim().toLowerCase() : "";
|
|
73
|
+
const accountId = typeof account.accountId === "string" ? account.accountId.trim().toLowerCase() : "";
|
|
74
|
+
if (!/^account\d+@example\.com$/.test(email)) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
const hasSyntheticRefreshToken = refreshToken.startsWith("fake_refresh") ||
|
|
78
|
+
/^fake_refresh_token_\d+(_for_testing_only)?$/.test(refreshToken);
|
|
79
|
+
if (!hasSyntheticRefreshToken) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
if (accountId.length === 0) {
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
return /^acc(_|-)?\d+$/.test(accountId);
|
|
86
|
+
}
|
|
87
|
+
function looksLikeSyntheticFixtureStorage(storage) {
|
|
88
|
+
if (!storage || storage.accounts.length === 0)
|
|
89
|
+
return false;
|
|
90
|
+
return storage.accounts.every((account) => looksLikeSyntheticFixtureAccount(account));
|
|
91
|
+
}
|
|
70
92
|
async function ensureGitignore(storagePath) {
|
|
71
93
|
if (!currentStoragePath)
|
|
72
94
|
return;
|
|
@@ -117,6 +139,43 @@ function getAccountsBackupRecoveryCandidates(path) {
|
|
|
117
139
|
}
|
|
118
140
|
return candidates;
|
|
119
141
|
}
|
|
142
|
+
async function getAccountsBackupRecoveryCandidatesWithDiscovery(path) {
|
|
143
|
+
const knownCandidates = getAccountsBackupRecoveryCandidates(path);
|
|
144
|
+
const discoveredCandidates = new Set();
|
|
145
|
+
const candidatePrefix = `${basename(path)}.`;
|
|
146
|
+
const knownCandidateSet = new Set(knownCandidates);
|
|
147
|
+
const directoryPath = dirname(path);
|
|
148
|
+
try {
|
|
149
|
+
const entries = await fs.readdir(directoryPath, { withFileTypes: true });
|
|
150
|
+
for (const entry of entries) {
|
|
151
|
+
if (!entry.isFile())
|
|
152
|
+
continue;
|
|
153
|
+
if (!entry.name.startsWith(candidatePrefix))
|
|
154
|
+
continue;
|
|
155
|
+
if (entry.name.endsWith(".tmp"))
|
|
156
|
+
continue;
|
|
157
|
+
if (entry.name.includes(".rotate."))
|
|
158
|
+
continue;
|
|
159
|
+
if (entry.name.endsWith(ACCOUNTS_WAL_SUFFIX))
|
|
160
|
+
continue;
|
|
161
|
+
const candidatePath = join(directoryPath, entry.name);
|
|
162
|
+
if (knownCandidateSet.has(candidatePath))
|
|
163
|
+
continue;
|
|
164
|
+
discoveredCandidates.add(candidatePath);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
const code = error.code;
|
|
169
|
+
if (code !== "ENOENT") {
|
|
170
|
+
log.warn("Failed to discover account backup candidates", {
|
|
171
|
+
path,
|
|
172
|
+
error: String(error),
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
const discoveredOrdered = Array.from(discoveredCandidates).sort((a, b) => a.localeCompare(b, undefined, { sensitivity: "base" }));
|
|
177
|
+
return [...knownCandidates, ...discoveredOrdered];
|
|
178
|
+
}
|
|
120
179
|
function getAccountsWalPath(path) {
|
|
121
180
|
return `${path}${ACCOUNTS_WAL_SUFFIX}`;
|
|
122
181
|
}
|
|
@@ -690,6 +749,50 @@ async function loadAccountsInternal(persistMigration) {
|
|
|
690
749
|
}
|
|
691
750
|
}
|
|
692
751
|
}
|
|
752
|
+
const primaryLooksSynthetic = looksLikeSyntheticFixtureStorage(normalized);
|
|
753
|
+
if (storageBackupEnabled && normalized && primaryLooksSynthetic) {
|
|
754
|
+
const backupCandidates = await getAccountsBackupRecoveryCandidatesWithDiscovery(path);
|
|
755
|
+
for (const backupPath of backupCandidates) {
|
|
756
|
+
if (backupPath === path)
|
|
757
|
+
continue;
|
|
758
|
+
try {
|
|
759
|
+
const backup = await loadAccountsFromPath(backupPath);
|
|
760
|
+
if (!backup.normalized)
|
|
761
|
+
continue;
|
|
762
|
+
if (looksLikeSyntheticFixtureStorage(backup.normalized))
|
|
763
|
+
continue;
|
|
764
|
+
if (backup.normalized.accounts.length <= 0)
|
|
765
|
+
continue;
|
|
766
|
+
log.warn("Detected synthetic primary account storage; promoting backup", {
|
|
767
|
+
path,
|
|
768
|
+
backupPath,
|
|
769
|
+
primaryAccounts: normalized.accounts.length,
|
|
770
|
+
backupAccounts: backup.normalized.accounts.length,
|
|
771
|
+
});
|
|
772
|
+
if (persistMigration) {
|
|
773
|
+
try {
|
|
774
|
+
await persistMigration(backup.normalized);
|
|
775
|
+
}
|
|
776
|
+
catch (persistError) {
|
|
777
|
+
log.warn("Failed to persist promoted backup storage", {
|
|
778
|
+
path,
|
|
779
|
+
error: String(persistError),
|
|
780
|
+
});
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
return backup.normalized;
|
|
784
|
+
}
|
|
785
|
+
catch (backupError) {
|
|
786
|
+
const backupCode = backupError.code;
|
|
787
|
+
if (backupCode !== "ENOENT") {
|
|
788
|
+
log.warn("Failed to load candidate backup for synthetic-primary promotion", {
|
|
789
|
+
path: backupPath,
|
|
790
|
+
error: String(backupError),
|
|
791
|
+
});
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
}
|
|
693
796
|
return normalized;
|
|
694
797
|
}
|
|
695
798
|
catch (error) {
|
|
@@ -713,7 +816,7 @@ async function loadAccountsInternal(persistMigration) {
|
|
|
713
816
|
return recoveredFromWal;
|
|
714
817
|
}
|
|
715
818
|
if (storageBackupEnabled) {
|
|
716
|
-
const backupCandidates =
|
|
819
|
+
const backupCandidates = await getAccountsBackupRecoveryCandidatesWithDiscovery(path);
|
|
717
820
|
for (const backupPath of backupCandidates) {
|
|
718
821
|
try {
|
|
719
822
|
const backup = await loadAccountsFromPath(backupPath);
|
|
@@ -764,6 +867,20 @@ async function saveAccountsUnlocked(storage) {
|
|
|
764
867
|
try {
|
|
765
868
|
await fs.mkdir(dirname(path), { recursive: true });
|
|
766
869
|
await ensureGitignore(path);
|
|
870
|
+
if (looksLikeSyntheticFixtureStorage(storage)) {
|
|
871
|
+
try {
|
|
872
|
+
const existing = await loadNormalizedStorageFromPath(path, "existing account storage");
|
|
873
|
+
if (existing && existing.accounts.length > 0 && !looksLikeSyntheticFixtureStorage(existing)) {
|
|
874
|
+
throw new StorageError("Refusing to overwrite non-synthetic account storage with synthetic fixture payload", "EINVALID", path, "Detected synthetic fixture-like account payload. Use explicit account import/login commands instead.");
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
catch (error) {
|
|
878
|
+
if (error instanceof StorageError) {
|
|
879
|
+
throw error;
|
|
880
|
+
}
|
|
881
|
+
// Ignore existing-file probe failures and continue with normal save flow.
|
|
882
|
+
}
|
|
883
|
+
}
|
|
767
884
|
if (storageBackupEnabled && existsSync(path)) {
|
|
768
885
|
try {
|
|
769
886
|
await createRotatingAccountsBackup(path);
|