oc-codex-multi-auth 6.13.0 → 6.14.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.
Files changed (46) hide show
  1. package/README.md +3 -0
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +305 -47
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/accounts/state.d.ts.map +1 -1
  6. package/dist/lib/accounts/state.js +2 -2
  7. package/dist/lib/accounts/state.js.map +1 -1
  8. package/dist/lib/codex-usage.d.ts.map +1 -1
  9. package/dist/lib/codex-usage.js +14 -79
  10. package/dist/lib/codex-usage.js.map +1 -1
  11. package/dist/lib/errors.d.ts +7 -0
  12. package/dist/lib/errors.d.ts.map +1 -1
  13. package/dist/lib/errors.js +14 -0
  14. package/dist/lib/errors.js.map +1 -1
  15. package/dist/lib/proactive-refresh.d.ts.map +1 -1
  16. package/dist/lib/proactive-refresh.js +14 -3
  17. package/dist/lib/proactive-refresh.js.map +1 -1
  18. package/dist/lib/request/fetch-helpers.d.ts +2 -1
  19. package/dist/lib/request/fetch-helpers.d.ts.map +1 -1
  20. package/dist/lib/request/fetch-helpers.js +17 -4
  21. package/dist/lib/request/fetch-helpers.js.map +1 -1
  22. package/dist/lib/storage/coordinated-refresh.d.ts +15 -0
  23. package/dist/lib/storage/coordinated-refresh.d.ts.map +1 -0
  24. package/dist/lib/storage/coordinated-refresh.js +246 -0
  25. package/dist/lib/storage/coordinated-refresh.js.map +1 -0
  26. package/dist/lib/storage/flagged.d.ts.map +1 -1
  27. package/dist/lib/storage/flagged.js +13 -3
  28. package/dist/lib/storage/flagged.js.map +1 -1
  29. package/dist/lib/storage/load-save.d.ts.map +1 -1
  30. package/dist/lib/storage/load-save.js +6 -3
  31. package/dist/lib/storage/load-save.js.map +1 -1
  32. package/dist/lib/storage/transaction-lock.d.ts +21 -0
  33. package/dist/lib/storage/transaction-lock.d.ts.map +1 -0
  34. package/dist/lib/storage/transaction-lock.js +194 -0
  35. package/dist/lib/storage/transaction-lock.js.map +1 -0
  36. package/dist/lib/tools/codex-note.d.ts.map +1 -1
  37. package/dist/lib/tools/codex-note.js +19 -9
  38. package/dist/lib/tools/codex-note.js.map +1 -1
  39. package/dist/lib/tools/codex-tag.d.ts.map +1 -1
  40. package/dist/lib/tools/codex-tag.js +23 -12
  41. package/dist/lib/tools/codex-tag.js.map +1 -1
  42. package/dist/lib/tools/refresh-account.d.ts +5 -15
  43. package/dist/lib/tools/refresh-account.d.ts.map +1 -1
  44. package/dist/lib/tools/refresh-account.js +17 -110
  45. package/dist/lib/tools/refresh-account.js.map +1 -1
  46. package/package.json +1 -1
@@ -1,118 +1,22 @@
1
1
  /**
2
2
  * Shared token refresh persistence for the account-management tools.
3
3
  *
4
- * OpenAI refresh tokens are single-use and rotate on exchange. Any tool that
5
- * calls `queuedRefresh()` must persist the rotated credential immediately;
6
- * otherwise the on-disk refresh token is already consumed and the next load
7
- * reports `refresh_token_reused` for every account.
4
+ * OpenAI refresh tokens are single-use and rotate on exchange. Production
5
+ * refreshes flow through `coordinatePersistedRefresh()`, which owns the
6
+ * authoritative reload, exchange, and durable commit under one lease.
8
7
  */
9
- import { queuedRefresh } from "../refresh-queue.js";
10
8
  import { extractAccountUserId } from "../auth/token-utils.js";
11
- import { withAccountStorageTransaction, } from "../storage.js";
12
9
  import { findAccountIndexByIdentityKeys, toAccountIdentityKeys, } from "../storage/identity.js";
10
+ import { coordinatePersistedRefresh } from "../storage/coordinated-refresh.js";
13
11
  export function findAccountIndexByIdentity(accounts, identity) {
14
12
  return findAccountIndexByIdentityKeys(accounts, toAccountIdentityKeys(identity));
15
13
  }
16
- /**
17
- * Persists one successful refresh in a short storage transaction. The account
18
- * is re-located from a freshly re-read snapshot, and sibling accounts that
19
- * share the consumed single-use refresh token are rotated atomically with it.
20
- */
21
- export async function persistRefreshResult(index, identity, refreshResult) {
22
- const rotated = refreshResult.refresh !== identity.refreshToken;
23
- const rotatedAt = rotated ? Date.now() : undefined;
24
- try {
25
- return await withAccountStorageTransaction(async (current, persist) => {
26
- if (!current) {
27
- throw new Error("Account storage is unavailable");
28
- }
29
- const idx = findAccountIndexByIdentity(current.accounts, identity);
30
- if (idx < 0) {
31
- throw new Error("Account was removed while its token was refreshing");
32
- }
33
- const target = current.accounts[idx];
34
- if (!target) {
35
- throw new Error("Account was removed while its token was refreshing");
36
- }
37
- if (target.refreshToken === identity.refreshToken) {
38
- if (rotated) {
39
- // A login can produce sibling org/workspace records sharing one
40
- // single-use refresh token. Mirror the account-state propagation used
41
- // by request-time refresh: update those records with the new token and
42
- // expire their workspace-specific access tokens so they refresh cleanly.
43
- // Do this before assigning the target, since siblings are matched by
44
- // the consumed token and the target starts with that token too.
45
- for (const sibling of current.accounts) {
46
- if (sibling === target)
47
- continue;
48
- if (sibling.refreshToken !== identity.refreshToken)
49
- continue;
50
- sibling.refreshToken = refreshResult.refresh;
51
- sibling.expiresAt = 0;
52
- if (rotatedAt !== undefined) {
53
- sibling.tokenRotatedAt = rotatedAt;
54
- }
55
- }
56
- }
57
- target.refreshToken = refreshResult.refresh;
58
- target.accountUserId =
59
- extractAccountUserId(refreshResult.access) ?? target.accountUserId;
60
- target.accessToken = refreshResult.access;
61
- target.expiresAt = refreshResult.expires;
62
- if (rotatedAt !== undefined) {
63
- target.tokenRotatedAt = rotatedAt;
64
- }
65
- }
66
- else if (target.refreshToken === refreshResult.refresh) {
67
- // A sibling account in this process just persisted the same rotation
68
- // and propagated the new token to this workspace record. Apply only
69
- // this workspace's freshly returned access token; do not overwrite
70
- // non-credential state in the fresh snapshot.
71
- target.accessToken = refreshResult.access;
72
- target.accountUserId =
73
- extractAccountUserId(refreshResult.access) ?? target.accountUserId;
74
- target.expiresAt = refreshResult.expires;
75
- }
76
- else {
77
- // The refresh was keyed off `identity.refreshToken` (the consumed,
78
- // pre-rotation value). If storage carries neither that token nor the
79
- // exact rotation returned by this refresh, another process rotated
80
- // this credential while this network-bound refresh was in flight. We
81
- // cannot know which resulting chain is live, so fail this
82
- // verification rather than clobber whatever the other process wrote.
83
- throw new Error("Refresh token changed concurrently while verification was in progress");
84
- }
85
- await persist(current);
86
- return {
87
- index,
88
- identity,
89
- refreshToken: refreshResult.refresh,
90
- accessToken: refreshResult.access,
91
- expiresAt: refreshResult.expires,
92
- rotatedAt,
93
- persisted: true,
94
- };
95
- });
96
- }
97
- catch (error) {
98
- return {
99
- index,
100
- identity,
101
- refreshToken: refreshResult.refresh,
102
- accessToken: refreshResult.access,
103
- expiresAt: refreshResult.expires,
104
- rotatedAt,
105
- persisted: false,
106
- persistError: error instanceof Error ? error.message : String(error),
107
- };
108
- }
109
- }
110
14
  /**
111
15
  * Refreshes one account and persists the rotated credential before reporting
112
16
  * success. Disabled standalone accounts are skipped: refreshing them is wrong
113
17
  * (they may intentionally retain a dead duplicate credential), while disabled
114
18
  * siblings sharing an enabled account's consumed token are still updated by
115
- * `persistRefreshResult()` so the shared credential remains consistent.
19
+ * `coordinatePersistedRefresh()` so the shared credential remains consistent.
116
20
  */
117
21
  export async function refreshAndPersistAccount(account) {
118
22
  const { index, identity } = account;
@@ -121,7 +25,7 @@ export async function refreshAndPersistAccount(account) {
121
25
  }
122
26
  let refreshResult;
123
27
  try {
124
- refreshResult = await queuedRefresh(identity.refreshToken);
28
+ refreshResult = await coordinatePersistedRefresh(identity);
125
29
  }
126
30
  catch (error) {
127
31
  return {
@@ -139,16 +43,19 @@ export async function refreshAndPersistAccount(account) {
139
43
  error: refreshResult.message ?? refreshResult.reason ?? "token refresh failed",
140
44
  };
141
45
  }
142
- const persisted = await persistRefreshResult(index, identity, refreshResult);
143
- if (!persisted.persisted) {
144
- return {
145
- status: "failed",
46
+ return {
47
+ status: "refreshed",
48
+ index,
49
+ result: {
146
50
  index,
147
51
  identity,
148
- error: persisted.persistError ?? "Failed to persist rotated credential",
149
- };
150
- }
151
- return { status: "refreshed", index, result: persisted };
52
+ refreshToken: refreshResult.refresh,
53
+ accessToken: refreshResult.access,
54
+ expiresAt: refreshResult.expires,
55
+ rotatedAt: refreshResult.rotatedAt,
56
+ persisted: true,
57
+ },
58
+ };
152
59
  }
153
60
  export function buildRefreshInputs(accounts) {
154
61
  return accounts.map((account, index) => ({
@@ -1 +1 @@
1
- {"version":3,"file":"refresh-account.js","sourceRoot":"","sources":["../../../lib/tools/refresh-account.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"refresh-account.js","sourceRoot":"","sources":["../../../lib/tools/refresh-account.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D,OAAO,EACN,8BAA8B,EAC9B,qBAAqB,GACrB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,0BAA0B,EAAE,MAAM,mCAAmC,CAAC;AA+B/E,MAAM,UAAU,0BAA0B,CACzC,QAAkC,EAClC,QAAgC;IAEhC,OAAO,8BAA8B,CAAC,QAAQ,EAAE,qBAAqB,CAAC,QAAQ,CAAC,CAAC,CAAC;AAClF,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC7C,OAA4B;IAE5B,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IACpC,IAAI,OAAO,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;QAC/B,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;IAC/C,CAAC;IAED,IAAI,aAAqE,CAAC;IAC1E,IAAI,CAAC;QACJ,aAAa,GAAG,MAAM,0BAA0B,CAAC,QAAQ,CAAC,CAAC;IAC5D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,OAAO;YACN,MAAM,EAAE,QAAQ;YAChB,KAAK;YACL,QAAQ;YACR,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;SAC7D,CAAC;IACH,CAAC;IAED,IAAI,aAAa,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QACtC,OAAO;YACN,MAAM,EAAE,QAAQ;YAChB,KAAK;YACL,QAAQ;YACR,KAAK,EACJ,aAAa,CAAC,OAAO,IAAI,aAAa,CAAC,MAAM,IAAI,sBAAsB;SACxE,CAAC;IACH,CAAC;IAED,OAAO;QACN,MAAM,EAAE,WAAW;QACnB,KAAK;QACL,MAAM,EAAE;YACP,KAAK;YACL,QAAQ;YACR,YAAY,EAAE,aAAa,CAAC,OAAO;YACnC,WAAW,EAAE,aAAa,CAAC,MAAM;YACjC,SAAS,EAAE,aAAa,CAAC,OAAO;YAChC,SAAS,EAAE,aAAa,CAAC,SAAS;YAClC,SAAS,EAAE,IAAI;SACf;KACD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB,CACjC,QAA6B;IAE7B,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;QACxC,KAAK;QACL,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,QAAQ,EAAE;YACT,cAAc,EAAE,OAAO,CAAC,cAAc;YACtC,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,aAAa,EACZ,OAAO,CAAC,aAAa,EAAE,IAAI,EAAE,IAAI,oBAAoB,CAAC,OAAO,CAAC,WAAW,CAAC;YAC3E,YAAY,EAAE,OAAO,CAAC,YAAY;SAClC;KACD,CAAC,CAAC,CAAC;AACL,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oc-codex-multi-auth",
3
- "version": "6.13.0",
3
+ "version": "6.14.0",
4
4
  "description": "OpenCode plugin for ChatGPT Plus/Pro OAuth with Codex/GPT-5 routing, multi-account rotation, account switching, health checks, diagnostics, and recovery tools",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",