oc-codex-multi-auth 6.0.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/LICENSE +21 -0
- package/README.md +162 -0
- package/assets/opencode-logo-ornate-dark.svg +18 -0
- package/assets/readme-hero.svg +31 -0
- package/config/README.md +96 -0
- package/config/minimal-opencode.json +13 -0
- package/config/opencode-legacy.json +871 -0
- package/config/opencode-modern.json +358 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5008 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/accounts/rate-limits.d.ts +22 -0
- package/dist/lib/accounts/rate-limits.d.ts.map +1 -0
- package/dist/lib/accounts/rate-limits.js +63 -0
- package/dist/lib/accounts/rate-limits.js.map +1 -0
- package/dist/lib/accounts.d.ts +134 -0
- package/dist/lib/accounts.d.ts.map +1 -0
- package/dist/lib/accounts.js +795 -0
- package/dist/lib/accounts.js.map +1 -0
- package/dist/lib/audit.d.ts +45 -0
- package/dist/lib/audit.d.ts.map +1 -0
- package/dist/lib/audit.js +154 -0
- package/dist/lib/audit.js.map +1 -0
- package/dist/lib/auth/auth.d.ts +51 -0
- package/dist/lib/auth/auth.d.ts.map +1 -0
- package/dist/lib/auth/auth.js +191 -0
- package/dist/lib/auth/auth.js.map +1 -0
- package/dist/lib/auth/browser.d.ts +17 -0
- package/dist/lib/auth/browser.d.ts.map +1 -0
- package/dist/lib/auth/browser.js +90 -0
- package/dist/lib/auth/browser.js.map +1 -0
- package/dist/lib/auth/device-code.d.ts +28 -0
- package/dist/lib/auth/device-code.d.ts.map +1 -0
- package/dist/lib/auth/device-code.js +215 -0
- package/dist/lib/auth/device-code.js.map +1 -0
- package/dist/lib/auth/login-runner.d.ts +55 -0
- package/dist/lib/auth/login-runner.d.ts.map +1 -0
- package/dist/lib/auth/login-runner.js +631 -0
- package/dist/lib/auth/login-runner.js.map +1 -0
- package/dist/lib/auth/server.d.ts +10 -0
- package/dist/lib/auth/server.d.ts.map +1 -0
- package/dist/lib/auth/server.js +98 -0
- package/dist/lib/auth/server.js.map +1 -0
- package/dist/lib/auth/token-utils.d.ts +60 -0
- package/dist/lib/auth/token-utils.d.ts.map +1 -0
- package/dist/lib/auth/token-utils.js +416 -0
- package/dist/lib/auth/token-utils.js.map +1 -0
- package/dist/lib/auth-rate-limit.d.ts +20 -0
- package/dist/lib/auth-rate-limit.d.ts.map +1 -0
- package/dist/lib/auth-rate-limit.js +91 -0
- package/dist/lib/auth-rate-limit.js.map +1 -0
- package/dist/lib/auto-update-checker.d.ts +10 -0
- package/dist/lib/auto-update-checker.d.ts.map +1 -0
- package/dist/lib/auto-update-checker.js +129 -0
- package/dist/lib/auto-update-checker.js.map +1 -0
- package/dist/lib/circuit-breaker.d.ts +34 -0
- package/dist/lib/circuit-breaker.d.ts.map +1 -0
- package/dist/lib/circuit-breaker.js +124 -0
- package/dist/lib/circuit-breaker.js.map +1 -0
- package/dist/lib/cli.d.ts +46 -0
- package/dist/lib/cli.d.ts.map +1 -0
- package/dist/lib/cli.js +192 -0
- package/dist/lib/cli.js.map +1 -0
- package/dist/lib/config.d.ts +42 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +314 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/constants.d.ts +90 -0
- package/dist/lib/constants.d.ts.map +1 -0
- package/dist/lib/constants.js +90 -0
- package/dist/lib/constants.js.map +1 -0
- package/dist/lib/context-overflow.d.ts +27 -0
- package/dist/lib/context-overflow.d.ts.map +1 -0
- package/dist/lib/context-overflow.js +124 -0
- package/dist/lib/context-overflow.js.map +1 -0
- package/dist/lib/errors.d.ts +113 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +103 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/health.d.ts +33 -0
- package/dist/lib/health.d.ts.map +1 -0
- package/dist/lib/health.js +70 -0
- package/dist/lib/health.js.map +1 -0
- package/dist/lib/index.d.ts +20 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +20 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/logger.d.ts +40 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +337 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/oauth-success.html +712 -0
- package/dist/lib/parallel-probe.d.ts +28 -0
- package/dist/lib/parallel-probe.d.ts.map +1 -0
- package/dist/lib/parallel-probe.js +97 -0
- package/dist/lib/parallel-probe.js.map +1 -0
- package/dist/lib/proactive-refresh.d.ts +67 -0
- package/dist/lib/proactive-refresh.d.ts.map +1 -0
- package/dist/lib/proactive-refresh.js +161 -0
- package/dist/lib/proactive-refresh.js.map +1 -0
- package/dist/lib/prompts/codex-opencode-bridge.d.ts +20 -0
- package/dist/lib/prompts/codex-opencode-bridge.d.ts.map +1 -0
- package/dist/lib/prompts/codex-opencode-bridge.js +126 -0
- package/dist/lib/prompts/codex-opencode-bridge.js.map +1 -0
- package/dist/lib/prompts/codex.d.ts +41 -0
- package/dist/lib/prompts/codex.d.ts.map +1 -0
- package/dist/lib/prompts/codex.js +400 -0
- package/dist/lib/prompts/codex.js.map +1 -0
- package/dist/lib/prompts/opencode-codex.d.ts +25 -0
- package/dist/lib/prompts/opencode-codex.d.ts.map +1 -0
- package/dist/lib/prompts/opencode-codex.js +223 -0
- package/dist/lib/prompts/opencode-codex.js.map +1 -0
- package/dist/lib/recovery/constants.d.ts +12 -0
- package/dist/lib/recovery/constants.d.ts.map +1 -0
- package/dist/lib/recovery/constants.js +25 -0
- package/dist/lib/recovery/constants.js.map +1 -0
- package/dist/lib/recovery/index.d.ts +12 -0
- package/dist/lib/recovery/index.d.ts.map +1 -0
- package/dist/lib/recovery/index.js +12 -0
- package/dist/lib/recovery/index.js.map +1 -0
- package/dist/lib/recovery/storage.d.ts +24 -0
- package/dist/lib/recovery/storage.d.ts.map +1 -0
- package/dist/lib/recovery/storage.js +362 -0
- package/dist/lib/recovery/storage.js.map +1 -0
- package/dist/lib/recovery/types.d.ts +116 -0
- package/dist/lib/recovery/types.d.ts.map +1 -0
- package/dist/lib/recovery/types.js +7 -0
- package/dist/lib/recovery/types.js.map +1 -0
- package/dist/lib/recovery.d.ts +31 -0
- package/dist/lib/recovery.d.ts.map +1 -0
- package/dist/lib/recovery.js +313 -0
- package/dist/lib/recovery.js.map +1 -0
- package/dist/lib/refresh-queue.d.ts +131 -0
- package/dist/lib/refresh-queue.d.ts.map +1 -0
- package/dist/lib/refresh-queue.js +297 -0
- package/dist/lib/refresh-queue.js.map +1 -0
- package/dist/lib/request/fetch-helpers.d.ts +142 -0
- package/dist/lib/request/fetch-helpers.d.ts.map +1 -0
- package/dist/lib/request/fetch-helpers.js +749 -0
- package/dist/lib/request/fetch-helpers.js.map +1 -0
- package/dist/lib/request/helpers/input-utils.d.ts +7 -0
- package/dist/lib/request/helpers/input-utils.d.ts.map +1 -0
- package/dist/lib/request/helpers/input-utils.js +214 -0
- package/dist/lib/request/helpers/input-utils.js.map +1 -0
- package/dist/lib/request/helpers/model-map.d.ts +22 -0
- package/dist/lib/request/helpers/model-map.d.ts.map +1 -0
- package/dist/lib/request/helpers/model-map.js +183 -0
- package/dist/lib/request/helpers/model-map.js.map +1 -0
- package/dist/lib/request/helpers/tool-utils.d.ts +29 -0
- package/dist/lib/request/helpers/tool-utils.d.ts.map +1 -0
- package/dist/lib/request/helpers/tool-utils.js +117 -0
- package/dist/lib/request/helpers/tool-utils.js.map +1 -0
- package/dist/lib/request/rate-limit-backoff.d.ts +17 -0
- package/dist/lib/request/rate-limit-backoff.d.ts.map +1 -0
- package/dist/lib/request/rate-limit-backoff.js +83 -0
- package/dist/lib/request/rate-limit-backoff.js.map +1 -0
- package/dist/lib/request/request-transformer.d.ts +107 -0
- package/dist/lib/request/request-transformer.d.ts.map +1 -0
- package/dist/lib/request/request-transformer.js +930 -0
- package/dist/lib/request/request-transformer.js.map +1 -0
- package/dist/lib/request/response-handler.d.ts +23 -0
- package/dist/lib/request/response-handler.d.ts.map +1 -0
- package/dist/lib/request/response-handler.js +245 -0
- package/dist/lib/request/response-handler.js.map +1 -0
- package/dist/lib/request/retry-budget.d.ts +19 -0
- package/dist/lib/request/retry-budget.d.ts.map +1 -0
- package/dist/lib/request/retry-budget.js +99 -0
- package/dist/lib/request/retry-budget.js.map +1 -0
- package/dist/lib/rotation.d.ts +130 -0
- package/dist/lib/rotation.d.ts.map +1 -0
- package/dist/lib/rotation.js +301 -0
- package/dist/lib/rotation.js.map +1 -0
- package/dist/lib/runtime-contracts.d.ts +16 -0
- package/dist/lib/runtime-contracts.d.ts.map +1 -0
- package/dist/lib/runtime-contracts.js +24 -0
- package/dist/lib/runtime-contracts.js.map +1 -0
- package/dist/lib/schemas.d.ts +457 -0
- package/dist/lib/schemas.d.ts.map +1 -0
- package/dist/lib/schemas.js +283 -0
- package/dist/lib/schemas.js.map +1 -0
- package/dist/lib/shutdown.d.ts +7 -0
- package/dist/lib/shutdown.d.ts.map +1 -0
- package/dist/lib/shutdown.js +43 -0
- package/dist/lib/shutdown.js.map +1 -0
- package/dist/lib/storage/migrations.d.ts +65 -0
- package/dist/lib/storage/migrations.d.ts.map +1 -0
- package/dist/lib/storage/migrations.js +44 -0
- package/dist/lib/storage/migrations.js.map +1 -0
- package/dist/lib/storage/paths.d.ts +16 -0
- package/dist/lib/storage/paths.d.ts.map +1 -0
- package/dist/lib/storage/paths.js +92 -0
- package/dist/lib/storage/paths.js.map +1 -0
- package/dist/lib/storage.d.ts +157 -0
- package/dist/lib/storage.d.ts.map +1 -0
- package/dist/lib/storage.js +1169 -0
- package/dist/lib/storage.js.map +1 -0
- package/dist/lib/table-formatter.d.ts +32 -0
- package/dist/lib/table-formatter.d.ts.map +1 -0
- package/dist/lib/table-formatter.js +44 -0
- package/dist/lib/table-formatter.js.map +1 -0
- package/dist/lib/types.d.ts +131 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/types.js +2 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/lib/ui/ansi.d.ts +22 -0
- package/dist/lib/ui/ansi.d.ts.map +1 -0
- package/dist/lib/ui/ansi.js +38 -0
- package/dist/lib/ui/ansi.js.map +1 -0
- package/dist/lib/ui/auth-menu.d.ts +39 -0
- package/dist/lib/ui/auth-menu.d.ts.map +1 -0
- package/dist/lib/ui/auth-menu.js +186 -0
- package/dist/lib/ui/auth-menu.js.map +1 -0
- package/dist/lib/ui/beginner.d.ts +62 -0
- package/dist/lib/ui/beginner.d.ts.map +1 -0
- package/dist/lib/ui/beginner.js +259 -0
- package/dist/lib/ui/beginner.js.map +1 -0
- package/dist/lib/ui/confirm.d.ts +2 -0
- package/dist/lib/ui/confirm.d.ts.map +1 -0
- package/dist/lib/ui/confirm.js +21 -0
- package/dist/lib/ui/confirm.js.map +1 -0
- package/dist/lib/ui/format.d.ts +9 -0
- package/dist/lib/ui/format.d.ts.map +1 -0
- package/dist/lib/ui/format.js +49 -0
- package/dist/lib/ui/format.js.map +1 -0
- package/dist/lib/ui/runtime.d.ts +11 -0
- package/dist/lib/ui/runtime.d.ts.map +1 -0
- package/dist/lib/ui/runtime.js +31 -0
- package/dist/lib/ui/runtime.js.map +1 -0
- package/dist/lib/ui/select.d.ts +20 -0
- package/dist/lib/ui/select.d.ts.map +1 -0
- package/dist/lib/ui/select.js +343 -0
- package/dist/lib/ui/select.js.map +1 -0
- package/dist/lib/ui/theme.d.ts +34 -0
- package/dist/lib/ui/theme.d.ts.map +1 -0
- package/dist/lib/ui/theme.js +84 -0
- package/dist/lib/ui/theme.js.map +1 -0
- package/dist/lib/utils.d.ts +29 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +54 -0
- package/dist/lib/utils.js.map +1 -0
- package/package.json +113 -0
- package/scripts/audit-dev-allowlist.js +114 -0
- package/scripts/copy-oauth-success.js +37 -0
- package/scripts/install-oc-codex-multi-auth-core.js +381 -0
- package/scripts/install-oc-codex-multi-auth.js +15 -0
- package/scripts/test-all-models.sh +260 -0
- package/scripts/validate-model-map.sh +97 -0
|
@@ -0,0 +1,631 @@
|
|
|
1
|
+
import { extractAccountEmail, extractAccountId, getAccountIdCandidates, sanitizeEmail, selectBestAccountCandidate, } from "../accounts.js";
|
|
2
|
+
import { logInfo } from "../logger.js";
|
|
3
|
+
import { MODEL_FAMILIES } from "../prompts/codex.js";
|
|
4
|
+
import { withAccountStorageTransaction } from "../storage.js";
|
|
5
|
+
const PERSIST_AUTHENTICATED_SELECTIONS_ERROR = "Failed to persist authenticated account selections.";
|
|
6
|
+
const createSelectionVariant = (tokens, candidate) => ({
|
|
7
|
+
...tokens,
|
|
8
|
+
accountIdOverride: candidate.accountId,
|
|
9
|
+
organizationIdOverride: candidate.organizationId,
|
|
10
|
+
accountIdSource: candidate.source,
|
|
11
|
+
accountLabel: candidate.label,
|
|
12
|
+
});
|
|
13
|
+
export function resolveAccountSelection(tokens) {
|
|
14
|
+
const override = (process.env.CODEX_AUTH_ACCOUNT_ID ?? "").trim();
|
|
15
|
+
if (override) {
|
|
16
|
+
const suffix = override.length > 6 ? override.slice(-6) : override;
|
|
17
|
+
logInfo(`Using account override from CODEX_AUTH_ACCOUNT_ID (id:${suffix}).`);
|
|
18
|
+
const primary = {
|
|
19
|
+
...tokens,
|
|
20
|
+
accountIdOverride: override,
|
|
21
|
+
accountIdSource: "manual",
|
|
22
|
+
accountLabel: `Override [id:${suffix}]`,
|
|
23
|
+
};
|
|
24
|
+
return {
|
|
25
|
+
primary,
|
|
26
|
+
variantsForPersistence: [primary],
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
const candidates = getAccountIdCandidates(tokens.access, tokens.idToken);
|
|
30
|
+
if (candidates.length === 0) {
|
|
31
|
+
return {
|
|
32
|
+
primary: tokens,
|
|
33
|
+
variantsForPersistence: [tokens],
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const choice = selectBestAccountCandidate(candidates);
|
|
37
|
+
if (!choice) {
|
|
38
|
+
return {
|
|
39
|
+
primary: tokens,
|
|
40
|
+
variantsForPersistence: [tokens],
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const primary = createSelectionVariant(tokens, {
|
|
44
|
+
accountId: choice.accountId,
|
|
45
|
+
organizationId: choice.organizationId,
|
|
46
|
+
source: choice.source ?? "token",
|
|
47
|
+
label: choice.label,
|
|
48
|
+
});
|
|
49
|
+
const variantsForPersistence = [primary];
|
|
50
|
+
for (const candidate of candidates) {
|
|
51
|
+
if (candidate.accountId === primary.accountIdOverride &&
|
|
52
|
+
(candidate.organizationId ?? "") === (primary.organizationIdOverride ?? "")) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
variantsForPersistence.push(createSelectionVariant(tokens, {
|
|
56
|
+
accountId: candidate.accountId,
|
|
57
|
+
organizationId: candidate.organizationId,
|
|
58
|
+
source: candidate.source,
|
|
59
|
+
label: candidate.label,
|
|
60
|
+
}));
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
primary,
|
|
64
|
+
variantsForPersistence,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
export function applyAccountSelectionFallbacks(selection, fallbacks) {
|
|
68
|
+
const primary = { ...selection.primary };
|
|
69
|
+
const primaryAccountId = selection.primary.accountIdOverride?.trim();
|
|
70
|
+
const primaryOrganizationId = selection.primary.organizationIdOverride?.trim();
|
|
71
|
+
const shouldReusePrimaryVariant = (primaryAccountId?.length ?? 0) > 0 || (primaryOrganizationId?.length ?? 0) > 0;
|
|
72
|
+
// Callers may deep-clone `selection.primary`, so reuse the updated primary by
|
|
73
|
+
// persisted account identity instead of relying on object aliasing.
|
|
74
|
+
let variantsForPersistence = selection.variantsForPersistence.map((variant) => variant === selection.primary ||
|
|
75
|
+
(shouldReusePrimaryVariant &&
|
|
76
|
+
(variant.accountIdOverride?.trim() ?? "") === (primaryAccountId ?? "") &&
|
|
77
|
+
(variant.organizationIdOverride?.trim() ?? "") === (primaryOrganizationId ?? ""))
|
|
78
|
+
? primary
|
|
79
|
+
: { ...variant });
|
|
80
|
+
const accountIdOverride = fallbacks.accountIdOverride?.trim();
|
|
81
|
+
if (!primary.accountIdOverride && accountIdOverride) {
|
|
82
|
+
primary.accountIdOverride = accountIdOverride;
|
|
83
|
+
primary.accountIdSource = fallbacks.accountIdSource ?? "manual";
|
|
84
|
+
variantsForPersistence = [primary];
|
|
85
|
+
}
|
|
86
|
+
const organizationIdOverride = fallbacks.organizationIdOverride?.trim();
|
|
87
|
+
if (!primary.organizationIdOverride && organizationIdOverride) {
|
|
88
|
+
primary.organizationIdOverride = organizationIdOverride;
|
|
89
|
+
}
|
|
90
|
+
const accountLabel = fallbacks.accountLabel?.trim();
|
|
91
|
+
if (!primary.accountLabel && accountLabel) {
|
|
92
|
+
primary.accountLabel = accountLabel;
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
primary,
|
|
96
|
+
variantsForPersistence,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Persists the already-resolved selection through the caller's
|
|
101
|
+
* `persistSelections` callback. Windows filesystem safety remains delegated to
|
|
102
|
+
* that callback, so callers should use `persistAccountPool` or
|
|
103
|
+
* `withAccountStorageTransaction` to keep the rename retry and serialized
|
|
104
|
+
* read-modify-write behavior covered by `test/login-runner.test.ts`.
|
|
105
|
+
* Callback failures are rethrown with a redacted message so callers can log the
|
|
106
|
+
* wrapper safely without leaking token-file paths or account identifiers.
|
|
107
|
+
*/
|
|
108
|
+
export async function persistResolvedAccountSelection(selection, options) {
|
|
109
|
+
if (!options?.persistSelections) {
|
|
110
|
+
return selection;
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
await options.persistSelections(selection.variantsForPersistence, options.replaceAll ?? false);
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
throw new Error(PERSIST_AUTHENTICATED_SELECTIONS_ERROR, {
|
|
117
|
+
cause: error,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
return selection;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Finalizes a resolved selection by delegating persistence to the caller's
|
|
124
|
+
* `persistSelections` callback. Windows lock-retry and read-modify-write
|
|
125
|
+
* serialization remain the callback's responsibility, so callers should route
|
|
126
|
+
* through `persistAccountPool` or `withAccountStorageTransaction` to preserve
|
|
127
|
+
* the guarantees covered by `test/login-runner.test.ts`.
|
|
128
|
+
* Persistence callback failures are redacted inside
|
|
129
|
+
* `persistResolvedAccountSelection()` before they propagate back to callers.
|
|
130
|
+
*/
|
|
131
|
+
export async function resolveAndPersistAccountSelection(tokens, options) {
|
|
132
|
+
let selection = resolveAccountSelection(tokens);
|
|
133
|
+
if (options?.fallbacks) {
|
|
134
|
+
selection = applyAccountSelectionFallbacks(selection, options.fallbacks);
|
|
135
|
+
}
|
|
136
|
+
return persistResolvedAccountSelection(selection, options);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Persists login results through the shared storage transaction so overlapping
|
|
140
|
+
* login retries serialize their read-modify-write cycle instead of racing stale
|
|
141
|
+
* snapshots. `withAccountStorageTransaction` also routes the final rename
|
|
142
|
+
* through the Windows lock retry path in `lib/storage.ts`; see
|
|
143
|
+
* `test/login-runner.test.ts` for the concurrent persist regression coverage.
|
|
144
|
+
*/
|
|
145
|
+
export async function persistAccountPool(results, replaceAll = false) {
|
|
146
|
+
if (results.length === 0)
|
|
147
|
+
return;
|
|
148
|
+
await withAccountStorageTransaction(async (loadedStorage, persist) => {
|
|
149
|
+
const now = Date.now();
|
|
150
|
+
const stored = replaceAll ? null : loadedStorage;
|
|
151
|
+
let accounts = stored?.accounts ? [...stored.accounts] : [];
|
|
152
|
+
const pushIndex = (map, key, index) => {
|
|
153
|
+
const existing = map.get(key);
|
|
154
|
+
if (existing) {
|
|
155
|
+
existing.push(index);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
map.set(key, [index]);
|
|
159
|
+
};
|
|
160
|
+
const asUniqueIndex = (indices) => {
|
|
161
|
+
if (!indices || indices.length !== 1)
|
|
162
|
+
return undefined;
|
|
163
|
+
const [onlyIndex] = indices;
|
|
164
|
+
return typeof onlyIndex === "number" ? onlyIndex : undefined;
|
|
165
|
+
};
|
|
166
|
+
const pickNewestAccountIndex = (existingIndex, candidateIndex) => {
|
|
167
|
+
const existing = accounts[existingIndex];
|
|
168
|
+
const candidate = accounts[candidateIndex];
|
|
169
|
+
if (!existing)
|
|
170
|
+
return candidateIndex;
|
|
171
|
+
if (!candidate)
|
|
172
|
+
return existingIndex;
|
|
173
|
+
const existingLastUsed = existing.lastUsed ?? 0;
|
|
174
|
+
const candidateLastUsed = candidate.lastUsed ?? 0;
|
|
175
|
+
if (candidateLastUsed > existingLastUsed)
|
|
176
|
+
return candidateIndex;
|
|
177
|
+
if (candidateLastUsed < existingLastUsed)
|
|
178
|
+
return existingIndex;
|
|
179
|
+
const existingAddedAt = existing.addedAt ?? 0;
|
|
180
|
+
const candidateAddedAt = candidate.addedAt ?? 0;
|
|
181
|
+
return candidateAddedAt >= existingAddedAt ? candidateIndex : existingIndex;
|
|
182
|
+
};
|
|
183
|
+
const mergeAccountRecords = (targetIndex, sourceIndex) => {
|
|
184
|
+
const target = accounts[targetIndex];
|
|
185
|
+
const source = accounts[sourceIndex];
|
|
186
|
+
if (!target || !source)
|
|
187
|
+
return;
|
|
188
|
+
const targetLastUsed = target.lastUsed ?? 0;
|
|
189
|
+
const sourceLastUsed = source.lastUsed ?? 0;
|
|
190
|
+
const targetAddedAt = target.addedAt ?? 0;
|
|
191
|
+
const sourceAddedAt = source.addedAt ?? 0;
|
|
192
|
+
const sourceIsNewer = sourceLastUsed > targetLastUsed ||
|
|
193
|
+
(sourceLastUsed === targetLastUsed && sourceAddedAt > targetAddedAt);
|
|
194
|
+
const newer = sourceIsNewer ? source : target;
|
|
195
|
+
const older = sourceIsNewer ? target : source;
|
|
196
|
+
const mergedRateLimitResetTimes = {};
|
|
197
|
+
const rateLimitResetKeys = new Set([
|
|
198
|
+
...Object.keys(older.rateLimitResetTimes ?? {}),
|
|
199
|
+
...Object.keys(newer.rateLimitResetTimes ?? {}),
|
|
200
|
+
]);
|
|
201
|
+
for (const key of rateLimitResetKeys) {
|
|
202
|
+
const olderRaw = older.rateLimitResetTimes?.[key];
|
|
203
|
+
const newerRaw = newer.rateLimitResetTimes?.[key];
|
|
204
|
+
const olderValue = typeof olderRaw === "number" && Number.isFinite(olderRaw) ? olderRaw : 0;
|
|
205
|
+
const newerValue = typeof newerRaw === "number" && Number.isFinite(newerRaw) ? newerRaw : 0;
|
|
206
|
+
const resolved = Math.max(olderValue, newerValue);
|
|
207
|
+
if (resolved > 0) {
|
|
208
|
+
mergedRateLimitResetTimes[key] = resolved;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
const mergedEnabled = target.enabled === false || source.enabled === false
|
|
212
|
+
? false
|
|
213
|
+
: target.enabled ?? source.enabled;
|
|
214
|
+
const targetCoolingDownUntil = typeof target.coolingDownUntil === "number" && Number.isFinite(target.coolingDownUntil)
|
|
215
|
+
? target.coolingDownUntil
|
|
216
|
+
: 0;
|
|
217
|
+
const sourceCoolingDownUntil = typeof source.coolingDownUntil === "number" && Number.isFinite(source.coolingDownUntil)
|
|
218
|
+
? source.coolingDownUntil
|
|
219
|
+
: 0;
|
|
220
|
+
const mergedCoolingDownUntilValue = Math.max(targetCoolingDownUntil, sourceCoolingDownUntil);
|
|
221
|
+
const mergedCoolingDownUntil = mergedCoolingDownUntilValue > 0 ? mergedCoolingDownUntilValue : undefined;
|
|
222
|
+
const mergedCooldownReason = (() => {
|
|
223
|
+
if (mergedCoolingDownUntilValue <= 0) {
|
|
224
|
+
return target.cooldownReason ?? source.cooldownReason;
|
|
225
|
+
}
|
|
226
|
+
if (sourceCoolingDownUntil > targetCoolingDownUntil) {
|
|
227
|
+
return source.cooldownReason ?? target.cooldownReason;
|
|
228
|
+
}
|
|
229
|
+
if (targetCoolingDownUntil > sourceCoolingDownUntil) {
|
|
230
|
+
return target.cooldownReason ?? source.cooldownReason;
|
|
231
|
+
}
|
|
232
|
+
return source.cooldownReason ?? target.cooldownReason;
|
|
233
|
+
})();
|
|
234
|
+
accounts[targetIndex] = {
|
|
235
|
+
...target,
|
|
236
|
+
accountId: target.accountId ?? source.accountId,
|
|
237
|
+
organizationId: target.organizationId ?? source.organizationId,
|
|
238
|
+
accountIdSource: target.accountIdSource ?? source.accountIdSource,
|
|
239
|
+
accountLabel: target.accountLabel ?? source.accountLabel,
|
|
240
|
+
email: target.email ?? source.email,
|
|
241
|
+
refreshToken: newer.refreshToken || older.refreshToken,
|
|
242
|
+
accessToken: newer.accessToken || older.accessToken,
|
|
243
|
+
expiresAt: newer.expiresAt ?? older.expiresAt,
|
|
244
|
+
enabled: mergedEnabled,
|
|
245
|
+
addedAt: Math.max(target.addedAt ?? 0, source.addedAt ?? 0),
|
|
246
|
+
lastUsed: Math.max(target.lastUsed ?? 0, source.lastUsed ?? 0),
|
|
247
|
+
lastSwitchReason: target.lastSwitchReason ?? source.lastSwitchReason,
|
|
248
|
+
rateLimitResetTimes: mergedRateLimitResetTimes,
|
|
249
|
+
coolingDownUntil: mergedCoolingDownUntil,
|
|
250
|
+
cooldownReason: mergedCooldownReason,
|
|
251
|
+
};
|
|
252
|
+
};
|
|
253
|
+
const normalizeStoredAccountId = (account) => {
|
|
254
|
+
const accountId = account?.accountId?.trim();
|
|
255
|
+
return accountId && accountId.length > 0 ? accountId : undefined;
|
|
256
|
+
};
|
|
257
|
+
const canCollapseWithCandidateAccountId = (existing, candidateAccountId) => {
|
|
258
|
+
const existingAccountId = normalizeStoredAccountId(existing);
|
|
259
|
+
const normalizedCandidate = candidateAccountId?.trim() || undefined;
|
|
260
|
+
if (!existingAccountId || !normalizedCandidate) {
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
263
|
+
return existingAccountId === normalizedCandidate;
|
|
264
|
+
};
|
|
265
|
+
const resolveOrganizationMatch = (indexes, organizationId, candidateAccountId) => {
|
|
266
|
+
const matches = indexes.byOrganizationId.get(organizationId);
|
|
267
|
+
if (!matches || matches.length === 0)
|
|
268
|
+
return undefined;
|
|
269
|
+
const candidateId = candidateAccountId?.trim() || undefined;
|
|
270
|
+
let newestNoAccountId;
|
|
271
|
+
let newestExactAccountId;
|
|
272
|
+
let newestAnyNonEmptyAccountId;
|
|
273
|
+
const distinctNonEmptyAccountIds = new Set();
|
|
274
|
+
for (const index of matches) {
|
|
275
|
+
const existing = accounts[index];
|
|
276
|
+
if (!existing)
|
|
277
|
+
continue;
|
|
278
|
+
const existingAccountId = normalizeStoredAccountId(existing);
|
|
279
|
+
if (!existingAccountId) {
|
|
280
|
+
newestNoAccountId =
|
|
281
|
+
typeof newestNoAccountId === "number"
|
|
282
|
+
? pickNewestAccountIndex(newestNoAccountId, index)
|
|
283
|
+
: index;
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
distinctNonEmptyAccountIds.add(existingAccountId);
|
|
287
|
+
newestAnyNonEmptyAccountId =
|
|
288
|
+
typeof newestAnyNonEmptyAccountId === "number"
|
|
289
|
+
? pickNewestAccountIndex(newestAnyNonEmptyAccountId, index)
|
|
290
|
+
: index;
|
|
291
|
+
if (candidateId && existingAccountId === candidateId) {
|
|
292
|
+
newestExactAccountId =
|
|
293
|
+
typeof newestExactAccountId === "number"
|
|
294
|
+
? pickNewestAccountIndex(newestExactAccountId, index)
|
|
295
|
+
: index;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
if (candidateId) {
|
|
299
|
+
return newestExactAccountId ?? newestNoAccountId;
|
|
300
|
+
}
|
|
301
|
+
if (typeof newestNoAccountId === "number") {
|
|
302
|
+
return newestNoAccountId;
|
|
303
|
+
}
|
|
304
|
+
if (distinctNonEmptyAccountIds.size === 1) {
|
|
305
|
+
return newestAnyNonEmptyAccountId;
|
|
306
|
+
}
|
|
307
|
+
return undefined;
|
|
308
|
+
};
|
|
309
|
+
const resolveNoOrgRefreshMatch = (indexes, refreshToken, candidateAccountId) => {
|
|
310
|
+
const candidateId = candidateAccountId?.trim() || undefined;
|
|
311
|
+
const matches = indexes.byRefreshTokenNoOrg.get(refreshToken);
|
|
312
|
+
if (!matches || matches.length === 0)
|
|
313
|
+
return undefined;
|
|
314
|
+
let newestNoAccountId;
|
|
315
|
+
let newestExactAccountId;
|
|
316
|
+
for (const index of matches) {
|
|
317
|
+
const existing = accounts[index];
|
|
318
|
+
const existingAccountId = normalizeStoredAccountId(existing);
|
|
319
|
+
if (!existingAccountId) {
|
|
320
|
+
newestNoAccountId =
|
|
321
|
+
typeof newestNoAccountId === "number"
|
|
322
|
+
? pickNewestAccountIndex(newestNoAccountId, index)
|
|
323
|
+
: index;
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
if (candidateId && existingAccountId === candidateId) {
|
|
327
|
+
newestExactAccountId =
|
|
328
|
+
typeof newestExactAccountId === "number"
|
|
329
|
+
? pickNewestAccountIndex(newestExactAccountId, index)
|
|
330
|
+
: index;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return newestExactAccountId ?? newestNoAccountId;
|
|
334
|
+
};
|
|
335
|
+
const resolveUniqueOrgScopedMatch = (indexes, accountId, refreshToken) => {
|
|
336
|
+
const byAccountId = accountId
|
|
337
|
+
? asUniqueIndex(indexes.byAccountIdOrgScoped.get(accountId))
|
|
338
|
+
: undefined;
|
|
339
|
+
if (byAccountId !== undefined)
|
|
340
|
+
return byAccountId;
|
|
341
|
+
if (accountId) {
|
|
342
|
+
const accountMatches = indexes.byAccountIdOrgScoped.get(accountId);
|
|
343
|
+
if (accountMatches && accountMatches.length > 1) {
|
|
344
|
+
let newestRefreshMatch;
|
|
345
|
+
for (const index of accountMatches) {
|
|
346
|
+
const existing = accounts[index];
|
|
347
|
+
if (!existing)
|
|
348
|
+
continue;
|
|
349
|
+
const existingRefresh = existing.refreshToken?.trim();
|
|
350
|
+
if (!existingRefresh || existingRefresh !== refreshToken) {
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
newestRefreshMatch =
|
|
354
|
+
typeof newestRefreshMatch === "number"
|
|
355
|
+
? pickNewestAccountIndex(newestRefreshMatch, index)
|
|
356
|
+
: index;
|
|
357
|
+
}
|
|
358
|
+
if (typeof newestRefreshMatch === "number") {
|
|
359
|
+
return newestRefreshMatch;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
if (accountId)
|
|
364
|
+
return undefined;
|
|
365
|
+
return asUniqueIndex(indexes.byRefreshTokenOrgScoped.get(refreshToken));
|
|
366
|
+
};
|
|
367
|
+
const buildIdentityIndexes = () => {
|
|
368
|
+
const byOrganizationId = new Map();
|
|
369
|
+
const byAccountIdNoOrg = new Map();
|
|
370
|
+
const byRefreshTokenNoOrg = new Map();
|
|
371
|
+
const byEmailNoOrg = new Map();
|
|
372
|
+
const byAccountIdOrgScoped = new Map();
|
|
373
|
+
const byRefreshTokenOrgScoped = new Map();
|
|
374
|
+
const byRefreshTokenGlobal = new Map();
|
|
375
|
+
for (let i = 0; i < accounts.length; i += 1) {
|
|
376
|
+
const account = accounts[i];
|
|
377
|
+
if (!account)
|
|
378
|
+
continue;
|
|
379
|
+
const organizationId = account.organizationId?.trim();
|
|
380
|
+
const accountId = account.accountId?.trim();
|
|
381
|
+
const refreshToken = account.refreshToken?.trim();
|
|
382
|
+
const email = account.email?.trim();
|
|
383
|
+
if (refreshToken) {
|
|
384
|
+
pushIndex(byRefreshTokenGlobal, refreshToken, i);
|
|
385
|
+
}
|
|
386
|
+
if (organizationId) {
|
|
387
|
+
pushIndex(byOrganizationId, organizationId, i);
|
|
388
|
+
if (accountId) {
|
|
389
|
+
pushIndex(byAccountIdOrgScoped, accountId, i);
|
|
390
|
+
}
|
|
391
|
+
if (refreshToken) {
|
|
392
|
+
pushIndex(byRefreshTokenOrgScoped, refreshToken, i);
|
|
393
|
+
}
|
|
394
|
+
continue;
|
|
395
|
+
}
|
|
396
|
+
if (accountId) {
|
|
397
|
+
byAccountIdNoOrg.set(accountId, i);
|
|
398
|
+
}
|
|
399
|
+
if (refreshToken) {
|
|
400
|
+
pushIndex(byRefreshTokenNoOrg, refreshToken, i);
|
|
401
|
+
}
|
|
402
|
+
if (email) {
|
|
403
|
+
byEmailNoOrg.set(email, i);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
return {
|
|
407
|
+
byOrganizationId,
|
|
408
|
+
byAccountIdNoOrg,
|
|
409
|
+
byRefreshTokenNoOrg,
|
|
410
|
+
byEmailNoOrg,
|
|
411
|
+
byAccountIdOrgScoped,
|
|
412
|
+
byRefreshTokenOrgScoped,
|
|
413
|
+
byRefreshTokenGlobal,
|
|
414
|
+
};
|
|
415
|
+
};
|
|
416
|
+
let identityIndexes = buildIdentityIndexes();
|
|
417
|
+
for (const result of results) {
|
|
418
|
+
const accountId = result.accountIdOverride ?? extractAccountId(result.access);
|
|
419
|
+
const normalizedAccountId = accountId?.trim() || undefined;
|
|
420
|
+
const organizationId = result.organizationIdOverride?.trim() || undefined;
|
|
421
|
+
const accountIdSource = normalizedAccountId
|
|
422
|
+
? result.accountIdSource ??
|
|
423
|
+
(result.accountIdOverride ? "manual" : "token")
|
|
424
|
+
: undefined;
|
|
425
|
+
const accountLabel = result.accountLabel;
|
|
426
|
+
const accountEmail = sanitizeEmail(extractAccountEmail(result.access, result.idToken));
|
|
427
|
+
const existingIndex = (() => {
|
|
428
|
+
if (organizationId) {
|
|
429
|
+
return resolveOrganizationMatch(identityIndexes, organizationId, normalizedAccountId);
|
|
430
|
+
}
|
|
431
|
+
if (normalizedAccountId) {
|
|
432
|
+
const byAccountId = identityIndexes.byAccountIdNoOrg.get(normalizedAccountId);
|
|
433
|
+
if (byAccountId !== undefined) {
|
|
434
|
+
return byAccountId;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
const byRefreshToken = resolveNoOrgRefreshMatch(identityIndexes, result.refresh, normalizedAccountId);
|
|
438
|
+
if (byRefreshToken !== undefined) {
|
|
439
|
+
return byRefreshToken;
|
|
440
|
+
}
|
|
441
|
+
if (accountEmail && !normalizedAccountId) {
|
|
442
|
+
const byEmail = identityIndexes.byEmailNoOrg.get(accountEmail);
|
|
443
|
+
if (byEmail !== undefined) {
|
|
444
|
+
return byEmail;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
const orgScoped = resolveUniqueOrgScopedMatch(identityIndexes, normalizedAccountId, result.refresh);
|
|
448
|
+
if (orgScoped !== undefined)
|
|
449
|
+
return orgScoped;
|
|
450
|
+
const globalRefreshMatch = asUniqueIndex(identityIndexes.byRefreshTokenGlobal.get(result.refresh));
|
|
451
|
+
if (globalRefreshMatch === undefined) {
|
|
452
|
+
return undefined;
|
|
453
|
+
}
|
|
454
|
+
const existing = accounts[globalRefreshMatch];
|
|
455
|
+
if (!canCollapseWithCandidateAccountId(existing, normalizedAccountId)) {
|
|
456
|
+
return undefined;
|
|
457
|
+
}
|
|
458
|
+
return globalRefreshMatch;
|
|
459
|
+
})();
|
|
460
|
+
if (existingIndex === undefined) {
|
|
461
|
+
accounts.push({
|
|
462
|
+
accountId: normalizedAccountId,
|
|
463
|
+
organizationId,
|
|
464
|
+
accountIdSource,
|
|
465
|
+
accountLabel,
|
|
466
|
+
email: accountEmail,
|
|
467
|
+
refreshToken: result.refresh,
|
|
468
|
+
accessToken: result.access,
|
|
469
|
+
expiresAt: result.expires,
|
|
470
|
+
addedAt: now,
|
|
471
|
+
lastUsed: now,
|
|
472
|
+
});
|
|
473
|
+
identityIndexes = buildIdentityIndexes();
|
|
474
|
+
continue;
|
|
475
|
+
}
|
|
476
|
+
const existing = accounts[existingIndex];
|
|
477
|
+
if (!existing)
|
|
478
|
+
continue;
|
|
479
|
+
const nextEmail = accountEmail ?? existing.email;
|
|
480
|
+
const nextOrganizationId = organizationId ?? existing.organizationId;
|
|
481
|
+
const preserveOrgIdentity = typeof existing.organizationId === "string" &&
|
|
482
|
+
existing.organizationId.trim().length > 0 &&
|
|
483
|
+
!organizationId;
|
|
484
|
+
const nextAccountId = preserveOrgIdentity
|
|
485
|
+
? existing.accountId ?? normalizedAccountId
|
|
486
|
+
: normalizedAccountId ?? existing.accountId;
|
|
487
|
+
const nextAccountIdSource = preserveOrgIdentity
|
|
488
|
+
? existing.accountIdSource ?? accountIdSource
|
|
489
|
+
: normalizedAccountId
|
|
490
|
+
? accountIdSource ?? existing.accountIdSource
|
|
491
|
+
: existing.accountIdSource;
|
|
492
|
+
const nextAccountLabel = preserveOrgIdentity
|
|
493
|
+
? existing.accountLabel ?? accountLabel
|
|
494
|
+
: accountLabel ?? existing.accountLabel;
|
|
495
|
+
accounts[existingIndex] = {
|
|
496
|
+
...existing,
|
|
497
|
+
accountId: nextAccountId,
|
|
498
|
+
organizationId: nextOrganizationId,
|
|
499
|
+
accountIdSource: nextAccountIdSource,
|
|
500
|
+
accountLabel: nextAccountLabel,
|
|
501
|
+
email: nextEmail,
|
|
502
|
+
refreshToken: result.refresh,
|
|
503
|
+
accessToken: result.access,
|
|
504
|
+
expiresAt: result.expires,
|
|
505
|
+
lastUsed: now,
|
|
506
|
+
};
|
|
507
|
+
identityIndexes = buildIdentityIndexes();
|
|
508
|
+
}
|
|
509
|
+
const pruneRefreshTokenCollisions = () => {
|
|
510
|
+
const indicesToRemove = new Set();
|
|
511
|
+
const exactIdentityToIndex = new Map();
|
|
512
|
+
const getExactIdentityKey = (account) => {
|
|
513
|
+
const organizationId = account?.organizationId?.trim() ?? "";
|
|
514
|
+
const accountId = normalizeStoredAccountId(account) ?? "";
|
|
515
|
+
const email = account?.email?.trim().toLowerCase() ?? "";
|
|
516
|
+
const refreshToken = account?.refreshToken?.trim() ?? "";
|
|
517
|
+
if (organizationId || accountId) {
|
|
518
|
+
return `org:${organizationId}|account:${accountId}|refresh:${refreshToken}`;
|
|
519
|
+
}
|
|
520
|
+
return `email:${email}|refresh:${refreshToken}`;
|
|
521
|
+
};
|
|
522
|
+
for (let i = 0; i < accounts.length; i += 1) {
|
|
523
|
+
const account = accounts[i];
|
|
524
|
+
if (!account)
|
|
525
|
+
continue;
|
|
526
|
+
const identityKey = getExactIdentityKey(account);
|
|
527
|
+
const existingIndex = exactIdentityToIndex.get(identityKey);
|
|
528
|
+
if (existingIndex === undefined) {
|
|
529
|
+
exactIdentityToIndex.set(identityKey, i);
|
|
530
|
+
continue;
|
|
531
|
+
}
|
|
532
|
+
const newestIndex = pickNewestAccountIndex(existingIndex, i);
|
|
533
|
+
const obsoleteIndex = newestIndex === existingIndex ? i : existingIndex;
|
|
534
|
+
mergeAccountRecords(newestIndex, obsoleteIndex);
|
|
535
|
+
indicesToRemove.add(obsoleteIndex);
|
|
536
|
+
exactIdentityToIndex.set(identityKey, newestIndex);
|
|
537
|
+
}
|
|
538
|
+
if (indicesToRemove.size > 0) {
|
|
539
|
+
accounts = accounts.filter((_, index) => !indicesToRemove.has(index));
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
const collectIdentityKeys = (account) => {
|
|
543
|
+
const keys = [];
|
|
544
|
+
const organizationId = account?.organizationId?.trim();
|
|
545
|
+
if (organizationId)
|
|
546
|
+
keys.push(`org:${organizationId}`);
|
|
547
|
+
const accountId = account?.accountId?.trim();
|
|
548
|
+
if (accountId)
|
|
549
|
+
keys.push(`account:${accountId}`);
|
|
550
|
+
const refreshToken = account?.refreshToken?.trim();
|
|
551
|
+
if (refreshToken)
|
|
552
|
+
keys.push(`refresh:${refreshToken}`);
|
|
553
|
+
return keys;
|
|
554
|
+
};
|
|
555
|
+
const getStoredAccountAtIndex = (rawIndex) => {
|
|
556
|
+
const storedAccounts = stored?.accounts;
|
|
557
|
+
if (!storedAccounts)
|
|
558
|
+
return undefined;
|
|
559
|
+
if (typeof rawIndex !== "number" || !Number.isFinite(rawIndex))
|
|
560
|
+
return undefined;
|
|
561
|
+
const candidate = Math.floor(rawIndex);
|
|
562
|
+
if (candidate < 0 || candidate >= storedAccounts.length)
|
|
563
|
+
return undefined;
|
|
564
|
+
return storedAccounts[candidate];
|
|
565
|
+
};
|
|
566
|
+
const storedActiveKeys = replaceAll
|
|
567
|
+
? []
|
|
568
|
+
: collectIdentityKeys(getStoredAccountAtIndex(stored?.activeIndex));
|
|
569
|
+
const storedActiveKeysByFamily = {};
|
|
570
|
+
if (!replaceAll) {
|
|
571
|
+
for (const family of MODEL_FAMILIES) {
|
|
572
|
+
const familyKeys = collectIdentityKeys(getStoredAccountAtIndex(stored?.activeIndexByFamily?.[family]));
|
|
573
|
+
if (familyKeys.length > 0) {
|
|
574
|
+
storedActiveKeysByFamily[family] = familyKeys;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
pruneRefreshTokenCollisions();
|
|
579
|
+
if (accounts.length === 0)
|
|
580
|
+
return;
|
|
581
|
+
const resolveIndexByIdentityKeys = (identityKeys) => {
|
|
582
|
+
if (!identityKeys || identityKeys.length === 0)
|
|
583
|
+
return undefined;
|
|
584
|
+
for (const identityKey of identityKeys) {
|
|
585
|
+
const index = accounts.findIndex((account) => collectIdentityKeys(account).includes(identityKey));
|
|
586
|
+
if (index >= 0) {
|
|
587
|
+
return index;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
return undefined;
|
|
591
|
+
};
|
|
592
|
+
const fallbackActiveIndex = replaceAll
|
|
593
|
+
? 0
|
|
594
|
+
: typeof stored?.activeIndex === "number" && Number.isFinite(stored.activeIndex)
|
|
595
|
+
? stored.activeIndex
|
|
596
|
+
: 0;
|
|
597
|
+
const remappedActiveIndex = replaceAll
|
|
598
|
+
? undefined
|
|
599
|
+
: resolveIndexByIdentityKeys(storedActiveKeys);
|
|
600
|
+
const activeIndex = remappedActiveIndex ?? fallbackActiveIndex;
|
|
601
|
+
const clampedActiveIndex = Math.max(0, Math.min(Math.floor(activeIndex), accounts.length - 1));
|
|
602
|
+
const activeIndexByFamily = {};
|
|
603
|
+
const familiesToPersist = replaceAll
|
|
604
|
+
? []
|
|
605
|
+
: MODEL_FAMILIES.filter((family) => {
|
|
606
|
+
const storedFamilyIndex = stored?.activeIndexByFamily?.[family];
|
|
607
|
+
return typeof storedFamilyIndex === "number" && Number.isFinite(storedFamilyIndex);
|
|
608
|
+
});
|
|
609
|
+
for (const family of familiesToPersist) {
|
|
610
|
+
const storedFamilyIndex = stored?.activeIndexByFamily?.[family];
|
|
611
|
+
const remappedFamilyIndex = replaceAll
|
|
612
|
+
? undefined
|
|
613
|
+
: resolveIndexByIdentityKeys(storedActiveKeysByFamily[family]);
|
|
614
|
+
const rawFamilyIndex = replaceAll
|
|
615
|
+
? 0
|
|
616
|
+
: typeof remappedFamilyIndex === "number"
|
|
617
|
+
? remappedFamilyIndex
|
|
618
|
+
: typeof storedFamilyIndex === "number" && Number.isFinite(storedFamilyIndex)
|
|
619
|
+
? storedFamilyIndex
|
|
620
|
+
: clampedActiveIndex;
|
|
621
|
+
activeIndexByFamily[family] = Math.max(0, Math.min(Math.floor(rawFamilyIndex), accounts.length - 1));
|
|
622
|
+
}
|
|
623
|
+
await persist({
|
|
624
|
+
version: 3,
|
|
625
|
+
accounts,
|
|
626
|
+
activeIndex: clampedActiveIndex,
|
|
627
|
+
activeIndexByFamily,
|
|
628
|
+
});
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
//# sourceMappingURL=login-runner.js.map
|