@modelprofile.com/authswitch 6.4.0 → 7.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/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/authority-contract.d.ts +302 -6
- package/dist_ts/authority-contract.js +1 -1
- package/dist_ts/authority-runtime-contract.d.ts +15 -0
- package/dist_ts/authorityrehearsal.child.d.ts +1 -0
- package/dist_ts/authorityrehearsal.child.js +395 -0
- package/dist_ts/classes.accountlist.js +4 -3
- package/dist_ts/classes.authoritybackup.d.ts +134 -0
- package/dist_ts/classes.authoritybackup.js +769 -0
- package/dist_ts/classes.authoritybroker.d.ts +29 -6
- package/dist_ts/classes.authoritybroker.js +413 -122
- package/dist_ts/classes.authoritycli.d.ts +24 -0
- package/dist_ts/classes.authoritycli.js +675 -0
- package/dist_ts/classes.authorityclient.d.ts +34 -9
- package/dist_ts/classes.authorityclient.js +136 -38
- package/dist_ts/classes.authoritydaemon.d.ts +47 -0
- package/dist_ts/classes.authoritydaemon.js +705 -16
- package/dist_ts/classes.authoritydatabase.d.ts +182 -8
- package/dist_ts/classes.authoritydatabase.js +1188 -41
- package/dist_ts/classes.authoritymodels.d.ts +247 -1
- package/dist_ts/classes.authoritymodels.js +870 -6
- package/dist_ts/classes.authoritypreuse.d.ts +47 -0
- package/dist_ts/classes.authoritypreuse.js +278 -0
- package/dist_ts/classes.authorityregistry.d.ts +24 -0
- package/dist_ts/classes.authorityregistry.js +88 -0
- package/dist_ts/classes.authorityrehearsal.d.ts +127 -0
- package/dist_ts/classes.authorityrehearsal.js +632 -0
- package/dist_ts/classes.authorityusage.d.ts +160 -0
- package/dist_ts/classes.authorityusage.js +429 -0
- package/dist_ts/classes.claudeauthority.d.ts +66 -0
- package/dist_ts/classes.claudeauthority.js +532 -0
- package/dist_ts/classes.claudecodeharness.js +3 -2
- package/dist_ts/classes.claudecodelocks.d.ts +13 -0
- package/dist_ts/classes.claudecodelocks.js +75 -3
- package/dist_ts/classes.claudenative.d.ts +137 -0
- package/dist_ts/classes.claudenative.js +731 -0
- package/dist_ts/classes.claudestatus.d.ts +9 -0
- package/dist_ts/classes.claudestatus.js +26 -9
- package/dist_ts/classes.claudetokenrefresh.d.ts +15 -1
- package/dist_ts/classes.claudetokenrefresh.js +74 -21
- package/dist_ts/classes.codexharness.js +4 -2
- package/dist_ts/classes.codexmanaged.d.ts +91 -0
- package/dist_ts/classes.codexmanaged.js +404 -0
- package/dist_ts/classes.codexpreuse.d.ts +8 -0
- package/dist_ts/classes.codexpreuse.js +24 -6
- package/dist_ts/classes.fileharness.d.ts +2 -0
- package/dist_ts/classes.fileharness.js +6 -4
- package/dist_ts/classes.limits.js +12 -7
- package/dist_ts/classes.opencodeharness.js +2 -2
- package/dist_ts/claudehttp.d.ts +10 -0
- package/dist_ts/claudehttp.js +29 -3
- package/dist_ts/index.d.ts +2 -0
- package/dist_ts/index.js +8 -1
- package/dist_ts/interfaces.harness.d.ts +6 -0
- package/dist_ts/interfaces.list.d.ts +9 -3
- package/dist_ts/plugins.d.ts +7 -3
- package/dist_ts/plugins.js +9 -4
- package/dist_ts/ts_migration/0001_authority_meta.d.ts +3 -0
- package/dist_ts/ts_migration/0001_authority_meta.js +32 -0
- package/dist_ts/ts_migration/index.d.ts +3 -0
- package/dist_ts/ts_migration/index.js +6 -0
- package/package.json +12 -2
- package/readme.md +205 -13
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/authority-contract.ts +264 -9
- package/ts/authority-runtime-contract.ts +21 -1
- package/ts/authorityrehearsal.child.ts +330 -0
- package/ts/classes.accountlist.ts +3 -2
- package/ts/classes.authoritybackup.ts +780 -0
- package/ts/classes.authoritybroker.ts +410 -120
- package/ts/classes.authoritycli.ts +719 -0
- package/ts/classes.authorityclient.ts +164 -38
- package/ts/classes.authoritydaemon.ts +614 -17
- package/ts/classes.authoritydatabase.ts +1229 -44
- package/ts/classes.authoritymodels.ts +579 -4
- package/ts/classes.authoritypreuse.ts +297 -0
- package/ts/classes.authorityregistry.ts +118 -0
- package/ts/classes.authorityrehearsal.ts +625 -0
- package/ts/classes.authorityusage.ts +527 -0
- package/ts/classes.claudeauthority.ts +541 -0
- package/ts/classes.claudecodeharness.ts +2 -1
- package/ts/classes.claudecodelocks.ts +70 -1
- package/ts/classes.claudenative.ts +816 -0
- package/ts/classes.claudestatus.ts +38 -9
- package/ts/classes.claudetokenrefresh.ts +82 -19
- package/ts/classes.codexharness.ts +3 -1
- package/ts/classes.codexmanaged.ts +402 -0
- package/ts/classes.codexpreuse.ts +33 -5
- package/ts/classes.fileharness.ts +7 -3
- package/ts/classes.limits.ts +11 -6
- package/ts/classes.opencodeharness.ts +1 -1
- package/ts/claudehttp.ts +31 -2
- package/ts/index.ts +7 -0
- package/ts/interfaces.harness.ts +6 -0
- package/ts/interfaces.list.ts +9 -3
- package/ts/plugins.ts +9 -3
- package/ts/ts_migration/0001_authority_meta.ts +33 -0
- package/ts/ts_migration/index.ts +7 -0
|
@@ -108,7 +108,7 @@ const claudeUsageWindows = (usage: Record<string, unknown>): IClaudeUsageWindows
|
|
|
108
108
|
type TClaudeProfile =
|
|
109
109
|
| { kind: 'found'; plan: string | undefined; facts: IHarnessStatusFact[] }
|
|
110
110
|
| { kind: 'mismatch' }
|
|
111
|
-
| { kind: 'unavailable'; problem: string };
|
|
111
|
+
| { kind: 'unavailable'; problem: string; credentialRejected: boolean };
|
|
112
112
|
|
|
113
113
|
/**
|
|
114
114
|
* One Claude OAuth login as a status lookup needs it: the token to ask with, and what the store that keeps it knows
|
|
@@ -125,6 +125,14 @@ export interface IClaudeLogin {
|
|
|
125
125
|
plan?: string;
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
+
/** Structured proof from the same profile and usage requests used for harness status. */
|
|
129
|
+
export interface IClaudeStatusRead {
|
|
130
|
+
status: IHarnessAccountStatus;
|
|
131
|
+
profile: 'verified' | 'unverified' | 'mismatch' | 'unavailable' | 'unsupported_scope';
|
|
132
|
+
usage: 'available' | 'unavailable' | 'unsupported_scope';
|
|
133
|
+
credentialRejected: boolean;
|
|
134
|
+
}
|
|
135
|
+
|
|
128
136
|
/**
|
|
129
137
|
* How long a session reuses an account's profile. The watch polls every few minutes, and the profile (plan,
|
|
130
138
|
* organization, billing type) changes far more rarely, so it is read at most hourly there.
|
|
@@ -167,7 +175,8 @@ export class ClaudeAccountStatus {
|
|
|
167
175
|
let body: Record<string, unknown>;
|
|
168
176
|
try { body = await this.get('profile', loginArg.accessToken, signal); }
|
|
169
177
|
catch (error) {
|
|
170
|
-
if (error instanceof ClaudeLoginRejectedError) return { kind: 'unavailable',
|
|
178
|
+
if (error instanceof ClaudeLoginRejectedError) return { kind: 'unavailable',
|
|
179
|
+
problem: `Profile: ${error.message}`, credentialRejected: true };
|
|
171
180
|
throw error;
|
|
172
181
|
}
|
|
173
182
|
try {
|
|
@@ -181,7 +190,8 @@ export class ClaudeAccountStatus {
|
|
|
181
190
|
if (credentialText(value)) facts.push({ section: 'Account', label: String(label), value: String(value) });
|
|
182
191
|
}
|
|
183
192
|
return { kind: 'found', plan: credentialText(organization.organization_type)?.replace(/^claude_/, ''), facts };
|
|
184
|
-
} catch { return { kind: 'unavailable',
|
|
193
|
+
} catch { return { kind: 'unavailable',
|
|
194
|
+
problem: 'Claude profile response is unsupported; no profile values were inferred.', credentialRejected: false }; }
|
|
185
195
|
}
|
|
186
196
|
|
|
187
197
|
/** The plan the login was saved with, the only one known while the service cannot be asked. */
|
|
@@ -195,25 +205,43 @@ export class ClaudeAccountStatus {
|
|
|
195
205
|
}
|
|
196
206
|
|
|
197
207
|
public async read(loginArg: IClaudeLogin, optionsArg: IHarnessStatusOptions = {}): Promise<IHarnessAccountStatus> {
|
|
208
|
+
return (await this.readDetailed(loginArg, optionsArg)).status;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** One request pair; callers requiring immutable identity use the proof rather than display text. */
|
|
212
|
+
public async readDetailed(loginArg: IClaudeLogin,
|
|
213
|
+
optionsArg: IHarnessStatusOptions = {}): Promise<IClaudeStatusRead> {
|
|
198
214
|
const result: IHarnessAccountStatus = { facts: [], problems: [], ...this.storedSummary(loginArg) };
|
|
199
215
|
// Only a store that keeps the login's scopes can tell beforehand that the service will not answer about the account.
|
|
200
216
|
if (loginArg.scopes.length && !loginArg.scopes.includes('user:profile')) {
|
|
201
217
|
result.facts.push({ section: 'Availability', label: 'Live account status', value: 'This login lacks the user:profile scope. Log in through Claude Code to obtain subscriber status.' });
|
|
202
|
-
return result;
|
|
218
|
+
return { status: result, profile: 'unsupported_scope', usage: 'unsupported_scope', credentialRejected: false };
|
|
203
219
|
}
|
|
204
220
|
const token = credentialText(loginArg.accessToken);
|
|
205
|
-
if (!token) return { facts: [], problems: ['No usable Claude Code access token is available.'] }
|
|
221
|
+
if (!token) return { status: { facts: [], problems: ['No usable Claude Code access token is available.'] },
|
|
222
|
+
profile: 'unavailable', usage: 'unavailable', credentialRejected: false };
|
|
206
223
|
const [profile, usage] = await Promise.allSettled([this.profile(loginArg, optionsArg), this.get('usage', token, optionsArg.signal)]);
|
|
207
224
|
const failure = (reason: unknown): string => reason instanceof ClaudeRequestError ? reason.message : 'Lookup failed.';
|
|
225
|
+
let profileOutcome: IClaudeStatusRead['profile'] = 'unavailable';
|
|
226
|
+
let usageOutcome: IClaudeStatusRead['usage'] = 'unavailable';
|
|
227
|
+
let credentialRejected = usage.status === 'rejected' && usage.reason instanceof ClaudeLoginRejectedError;
|
|
208
228
|
if (profile.status === 'fulfilled') {
|
|
209
229
|
const found = profile.value;
|
|
210
|
-
if (found.kind === 'mismatch') return { facts: [], problems: [MISMATCH] }
|
|
211
|
-
|
|
230
|
+
if (found.kind === 'mismatch') return { status: { facts: [], problems: [MISMATCH] },
|
|
231
|
+
profile: 'mismatch', usage: 'unavailable', credentialRejected: false };
|
|
232
|
+
if (found.kind === 'unavailable') {
|
|
233
|
+
result.problems.push(found.problem);
|
|
234
|
+
credentialRejected ||= found.credentialRejected;
|
|
235
|
+
}
|
|
212
236
|
else {
|
|
237
|
+
profileOutcome = loginArg.identity ? 'verified' : 'unverified';
|
|
213
238
|
if (found.plan) result.summary = { ...result.summary, subscription: { plan: found.plan, source: 'live' } };
|
|
214
239
|
result.facts.push(...found.facts.map(fact => ({ ...fact })));
|
|
215
240
|
}
|
|
216
|
-
} else
|
|
241
|
+
} else {
|
|
242
|
+
result.problems.push(`Profile: ${failure(profile.reason)}`);
|
|
243
|
+
credentialRejected ||= profile.reason instanceof ClaudeLoginRejectedError;
|
|
244
|
+
}
|
|
217
245
|
if (usage.status === 'fulfilled') {
|
|
218
246
|
try {
|
|
219
247
|
const { windows, unsupported } = claudeUsageWindows(usage.value);
|
|
@@ -232,12 +260,13 @@ export class ClaudeAccountStatus {
|
|
|
232
260
|
if (limit !== undefined && limit > 0 && used !== undefined) result.facts.push({ section: 'Extra usage', label: 'Monthly budget used', value: `${Math.round(used / limit * 10000) / 100}%` });
|
|
233
261
|
}
|
|
234
262
|
if (unsupported.length) result.facts.push({ section: 'Availability', label: 'Unsupported limits', value: `The service returned limits without a supported reset window, which are not shown: ${unsupported.join(', ')}.` });
|
|
263
|
+
usageOutcome = 'available';
|
|
235
264
|
} catch { result.problems.push('Claude usage response is unsupported; missing values were not inferred.'); }
|
|
236
265
|
} else result.problems.push(`Usage: ${failure(usage.reason)}`);
|
|
237
266
|
const limited = [profile, usage].flatMap(item => item.status === 'rejected' && item.reason instanceof ClaudeRateLimitError ? [item.reason] : []);
|
|
238
267
|
if (limited.length) result.rateLimit = { retryAt: latestRetryAt(limited.map(error => error.retryAt)) };
|
|
239
268
|
// The missing renewal dates are the harness's `renewalUnavailableReason`, stated once by the views that show them.
|
|
240
269
|
result.facts.push({ section: 'Availability', label: 'Earned resets', value: 'authswitch does not read earned reset credits for Claude Code logins.' });
|
|
241
|
-
return result;
|
|
270
|
+
return { status: result, profile: profileOutcome, usage: usageOutcome, credentialRejected };
|
|
242
271
|
}
|
|
243
272
|
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { claudeRequest, claudeRotatingRequest, ClaudeAccountOnHoldError, ClaudeLoginRejectedError,
|
|
2
|
+
ClaudeRequestError, ClaudeRotatingRequestError, oauthErrorCode } from './claudehttp.js';
|
|
3
|
+
|
|
4
|
+
const credentialText = (value: unknown): string | undefined =>
|
|
5
|
+
typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
3
6
|
|
|
4
7
|
/** Claude Code 2.1.273's token endpoint (`TOKEN_URL`, bundle offset @188533776). */
|
|
5
8
|
const TOKEN_URL = 'https://platform.claude.com/v1/oauth/token';
|
|
@@ -36,6 +39,13 @@ export interface IClaudeTokens {
|
|
|
36
39
|
scopes?: string[];
|
|
37
40
|
}
|
|
38
41
|
|
|
42
|
+
/** Authority callers persist a pre-send marker, then classify every failed rotating request. */
|
|
43
|
+
export type TClaudeAuthorityRefreshResult =
|
|
44
|
+
| { success: true; tokens: IClaudeTokens }
|
|
45
|
+
| { success: false; requestOutcome: 'notSent' | 'outcomeUnknown';
|
|
46
|
+
reason: 'not_refreshable' | 'provider_rejected' | 'account_on_hold' | 'provider_unavailable' | 'unsupported_response';
|
|
47
|
+
responseStatus?: number };
|
|
48
|
+
|
|
39
49
|
/** How Claude Code 2.1.273 builds one refresh request for a stored login. */
|
|
40
50
|
export interface IClaudeGrant {
|
|
41
51
|
/** The login's own OAuth client, or Claude Code's public one. */
|
|
@@ -104,10 +114,10 @@ export class ClaudeTokenRefresh {
|
|
|
104
114
|
* Whether Claude Code would refresh this login before using it: its access token expires within five minutes. A
|
|
105
115
|
* login without a numeric expiry or without a refresh token is used as it is, exactly as Claude Code does.
|
|
106
116
|
*/
|
|
107
|
-
public due(oauthArg: Record<string, unknown
|
|
117
|
+
public due(oauthArg: Record<string, unknown>, minValidityMs = CLAUDE_REFRESH_MARGIN_MS): boolean {
|
|
108
118
|
const expiresAt = oauthArg.expiresAt;
|
|
109
119
|
return typeof expiresAt === 'number' && Number.isFinite(expiresAt) && credentialText(oauthArg.refreshToken) !== undefined
|
|
110
|
-
&& this.now() + CLAUDE_REFRESH_MARGIN_MS >= expiresAt;
|
|
120
|
+
&& this.now() + Math.max(CLAUDE_REFRESH_MARGIN_MS, minValidityMs) >= expiresAt;
|
|
111
121
|
}
|
|
112
122
|
|
|
113
123
|
/** One refresh request, as Claude Code sends it: a JSON body, the login's client, and the scopes of this attempt. */
|
|
@@ -121,26 +131,56 @@ export class ClaudeTokenRefresh {
|
|
|
121
131
|
});
|
|
122
132
|
}
|
|
123
133
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
134
|
+
private attemptForAuthority(refreshTokenArg: string, grantArg: IClaudeGrant, scopesArg: readonly string[]) {
|
|
135
|
+
return claudeRotatingRequest(this.fetcher, {
|
|
136
|
+
url: TOKEN_URL, method: 'POST', headers: { 'Content-Type': 'application/json' }, subject: 'Claude sign-in',
|
|
137
|
+
body: JSON.stringify({ grant_type: 'refresh_token', refresh_token: refreshTokenArg,
|
|
138
|
+
client_id: grantArg.clientId, scope: grantScope(scopesArg) }),
|
|
139
|
+
timeoutMs: REFRESH_TIMEOUT_MS, readErrorBody: true, now: this.now,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** The authority must already have durably marked this grant as possibly sent. */
|
|
144
|
+
public async refreshForAuthority(oauthArg: Record<string, unknown>): Promise<TClaudeAuthorityRefreshResult> {
|
|
131
145
|
const refreshToken = credentialText(oauthArg.refreshToken);
|
|
132
146
|
const grant = claudeGrant(oauthArg);
|
|
133
147
|
if (!refreshToken || !grant) {
|
|
134
|
-
|
|
148
|
+
return { success: false, requestOutcome: 'notSent', reason: 'not_refreshable' };
|
|
135
149
|
}
|
|
136
|
-
let
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
150
|
+
let response: Awaited<ReturnType<typeof this.attemptForAuthority>>;
|
|
151
|
+
try {
|
|
152
|
+
response = await this.attemptForAuthority(refreshToken, grant, grant.scopes);
|
|
153
|
+
// A definitive invalid_scope response is the one safe condition in which Claude retries the same grant.
|
|
154
|
+
if (response.status === 400 && oauthErrorCode(response.body) === 'invalid_scope'
|
|
155
|
+
&& grant.fallbackScopes !== null) {
|
|
156
|
+
response = await this.attemptForAuthority(refreshToken, grant, grant.fallbackScopes);
|
|
157
|
+
}
|
|
158
|
+
} catch (error) {
|
|
159
|
+
return { success: false,
|
|
160
|
+
requestOutcome: error instanceof ClaudeRotatingRequestError ? error.requestOutcome : 'outcomeUnknown',
|
|
161
|
+
reason: 'provider_unavailable' };
|
|
140
162
|
}
|
|
141
|
-
if (accountOnHold(status, body))
|
|
142
|
-
|
|
143
|
-
|
|
163
|
+
if (accountOnHold(response.status, response.body)) {
|
|
164
|
+
return { success: false, requestOutcome: 'outcomeUnknown', reason: 'account_on_hold',
|
|
165
|
+
responseStatus: response.status };
|
|
166
|
+
}
|
|
167
|
+
if ((response.status === 400 || response.status === 401)
|
|
168
|
+
&& oauthErrorCode(response.body) === 'invalid_grant') {
|
|
169
|
+
return { success: false, requestOutcome: 'outcomeUnknown', reason: 'provider_rejected',
|
|
170
|
+
responseStatus: response.status };
|
|
171
|
+
}
|
|
172
|
+
if (response.status < 200 || response.status > 299) {
|
|
173
|
+
return { success: false, requestOutcome: 'outcomeUnknown', reason: 'provider_unavailable',
|
|
174
|
+
responseStatus: response.status };
|
|
175
|
+
}
|
|
176
|
+
try { return { success: true, tokens: this.tokensFromResponse(response.body, refreshToken) }; }
|
|
177
|
+
catch {
|
|
178
|
+
return { success: false, requestOutcome: 'outcomeUnknown', reason: 'unsupported_response',
|
|
179
|
+
responseStatus: response.status };
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
private tokensFromResponse(body: Record<string, unknown> | null, refreshToken: string): IClaudeTokens {
|
|
144
184
|
const receivedAt = this.now();
|
|
145
185
|
const accessToken = credentialText(body?.access_token);
|
|
146
186
|
const tokenType = body?.token_type;
|
|
@@ -158,4 +198,27 @@ export class ClaudeTokenRefresh {
|
|
|
158
198
|
...(scope === null || !scope.length ? {} : { scopes: scope }),
|
|
159
199
|
};
|
|
160
200
|
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* New tokens for the login. A response without a refresh token keeps the one sent, and one without a scope keeps the
|
|
204
|
+
* stored scopes, as Claude Code merges them. Throws `ClaudeRequestError` with a fixed diagnostic; a grant the service
|
|
205
|
+
* rejects is `ClaudeLoginRejectedError`, an account the service put on hold is `ClaudeAccountOnHoldError`, and a rate
|
|
206
|
+
* limit is `ClaudeRateLimitError`.
|
|
207
|
+
*/
|
|
208
|
+
public async refresh(oauthArg: Record<string, unknown>): Promise<IClaudeTokens> {
|
|
209
|
+
const refreshToken = credentialText(oauthArg.refreshToken);
|
|
210
|
+
const grant = claudeGrant(oauthArg);
|
|
211
|
+
if (!refreshToken || !grant) {
|
|
212
|
+
throw new ClaudeRequestError('This saved login has no refresh token, and no subscriber scope or plan to refresh with. Log in again with Claude Code and save it.');
|
|
213
|
+
}
|
|
214
|
+
let { status, body } = await this.attempt(refreshToken, grant, grant.scopes);
|
|
215
|
+
// The service refusing Claude Code's current scope set is the one failure it sends a second request for.
|
|
216
|
+
if (status === 400 && oauthErrorCode(body) === 'invalid_scope' && grant.fallbackScopes !== null) {
|
|
217
|
+
({ status, body } = await this.attempt(refreshToken, grant, grant.fallbackScopes));
|
|
218
|
+
}
|
|
219
|
+
if (accountOnHold(status, body)) throw new ClaudeAccountOnHoldError();
|
|
220
|
+
if ((status === 400 || status === 401) && oauthErrorCode(body) === 'invalid_grant') throw new ClaudeLoginRejectedError();
|
|
221
|
+
if (status < 200 || status > 299) throw new ClaudeRequestError(`The Claude sign-in service returned HTTP ${status}.`);
|
|
222
|
+
return this.tokensFromResponse(body, refreshToken);
|
|
223
|
+
}
|
|
161
224
|
}
|
|
@@ -69,6 +69,7 @@ export class CodexHarness implements IAuthHarness {
|
|
|
69
69
|
const isActive = this.recordOf(entryArg, active.identity);
|
|
70
70
|
return {
|
|
71
71
|
id: entryArg.email,
|
|
72
|
+
providerAccountId: entryArg.accountId,
|
|
72
73
|
label: entryArg.email,
|
|
73
74
|
isActive,
|
|
74
75
|
isStashed,
|
|
@@ -77,7 +78,8 @@ export class CodexHarness implements IAuthHarness {
|
|
|
77
78
|
};
|
|
78
79
|
});
|
|
79
80
|
if (active.identity && !accounts.some((accountArg) => accountArg.isActive)) {
|
|
80
|
-
accounts.unshift({ id: this.activeAccountId(active.identity.email, active.identity.accountId),
|
|
81
|
+
accounts.unshift({ id: this.activeAccountId(active.identity.email, active.identity.accountId),
|
|
82
|
+
providerAccountId: active.identity.accountId, label: active.identity.email, isActive: true,
|
|
81
83
|
isStashed: false, savedAt: null, details: [] });
|
|
82
84
|
}
|
|
83
85
|
return {
|