@cortexkit/anthropic-auth-core 1.19.1 → 1.20.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/accounts.d.ts +68 -2
- package/dist/accounts.js +382 -23
- package/dist/auth.d.ts +2 -0
- package/dist/auth.js +3 -2
- package/dist/cache1h.d.ts +1 -1
- package/dist/cache1h.js +1 -1
- package/dist/cachekeep.d.ts +20 -2
- package/dist/cachekeep.js +134 -28
- package/dist/cch.d.ts +1 -0
- package/dist/cch.js +6 -1
- package/dist/claude-code.d.ts +2 -1
- package/dist/claude-code.js +3 -3
- package/dist/commands/account.js +1 -1
- package/dist/constants.d.ts +3 -3
- package/dist/dump.d.ts +12 -1
- package/dist/dump.js +166 -22
- package/dist/index.d.ts +2 -0
- package/dist/index.js +26 -24
- package/dist/killswitch.js +1 -1
- package/dist/models.d.ts +22 -6
- package/dist/models.js +16 -0
- package/dist/oauth-profile.js +1 -1
- package/dist/prime.d.ts +219 -0
- package/dist/prime.js +823 -0
- package/dist/quota-manager.d.ts +7 -0
- package/dist/quota-manager.js +24 -15
- package/dist/quotas.d.ts +4 -4
- package/dist/quotas.js +2 -2
- package/dist/relay.d.ts +2 -0
- package/dist/relay.js +10 -4
- package/dist/routing.d.ts +1 -1
- package/dist/routing.js +1 -1
- package/dist/start.d.ts +13 -0
- package/dist/start.js +29 -0
- package/dist/sticky-routing.d.ts +1 -0
- package/dist/sticky-routing.js +14 -4
- package/package.json +1 -1
package/dist/quota-manager.d.ts
CHANGED
|
@@ -12,6 +12,11 @@ export type QuotaEntry = {
|
|
|
12
12
|
refreshAfter: number;
|
|
13
13
|
checkedAt: number;
|
|
14
14
|
};
|
|
15
|
+
export type QuotaRefreshResult = {
|
|
16
|
+
quota: OAuthQuotaSnapshot;
|
|
17
|
+
/** False when backoff or a cross-process lock served the existing cache. */
|
|
18
|
+
fetched: boolean;
|
|
19
|
+
};
|
|
15
20
|
export type QuotaManagerOptions = {
|
|
16
21
|
storage: AccountStorage | null;
|
|
17
22
|
fetchImpl?: typeof fetch;
|
|
@@ -58,7 +63,9 @@ export declare class QuotaManager {
|
|
|
58
63
|
pushMainFromHeaders(accessToken: string, incoming: OAuthQuotaSnapshot): QuotaEntry;
|
|
59
64
|
pushFallbackFromHeaders(accountId: string, accessToken: string, incoming: OAuthQuotaSnapshot): QuotaEntry;
|
|
60
65
|
refreshMain(accessToken: string): Promise<OAuthQuotaSnapshot>;
|
|
66
|
+
refreshMainWithMetadata(accessToken: string): Promise<QuotaRefreshResult>;
|
|
61
67
|
refreshFallback(accountId: string, accessToken: string): Promise<OAuthQuotaSnapshot>;
|
|
68
|
+
refreshFallbackWithMetadata(accountId: string, accessToken: string): Promise<QuotaRefreshResult>;
|
|
62
69
|
refreshAllFallbacks(accounts: OAuthAccount[]): Promise<void>;
|
|
63
70
|
/**
|
|
64
71
|
* Fire-and-forget refresh. Does not await, swallows errors.
|
package/dist/quota-manager.js
CHANGED
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
* share one QuotaManager instance so they see the same in-memory cache.
|
|
6
6
|
* Handles deduplication, rate-limiting (429 backoff), and staleness.
|
|
7
7
|
*/
|
|
8
|
-
import { acquireRefreshFileLock, buildQuotaOperationError, fetchOAuthQuotaSnapshot, getPersistedMainQuota, getQuotaCheckIntervalMs, getQuotaNextRefreshAt, getQuotaRefreshEveryNRequests, getScopedQuotaWindowForModel, isQuotaPolicyAuthError, quotaBackoffActive, } from
|
|
9
|
-
import { mergeHeaderQuotaSnapshot } from
|
|
10
|
-
export { tokenFingerprint } from
|
|
11
|
-
import { tokenFingerprint } from
|
|
8
|
+
import { acquireRefreshFileLock, buildQuotaOperationError, fetchOAuthQuotaSnapshot, getPersistedMainQuota, getQuotaCheckIntervalMs, getQuotaNextRefreshAt, getQuotaRefreshEveryNRequests, getScopedQuotaWindowForModel, isQuotaPolicyAuthError, quotaBackoffActive, quotaSnapshotCheckedAt, } from './accounts.js';
|
|
9
|
+
import { mergeHeaderQuotaSnapshot } from './quota-headers.js';
|
|
10
|
+
export { tokenFingerprint } from './token-fingerprint.js';
|
|
11
|
+
import { tokenFingerprint } from './token-fingerprint.js';
|
|
12
12
|
// Capture real setTimeout before tests can mock globalThis.setTimeout
|
|
13
13
|
const nativeSetTimeout = globalThis.setTimeout;
|
|
14
14
|
function mergePollCompletionWithNewerHeaders(current, polled) {
|
|
@@ -158,6 +158,9 @@ export class QuotaManager {
|
|
|
158
158
|
// Refresh (async, deduplicated, rate-limited)
|
|
159
159
|
// =========================================================================
|
|
160
160
|
async refreshMain(accessToken) {
|
|
161
|
+
return (await this.refreshMainWithMetadata(accessToken)).quota;
|
|
162
|
+
}
|
|
163
|
+
async refreshMainWithMetadata(accessToken) {
|
|
161
164
|
// If the main account/token changed, invalidate the cache (including a
|
|
162
165
|
// persisted seed) BEFORE the backoff short-circuit so a different account's
|
|
163
166
|
// stale quota is never returned while the quota API is backed off.
|
|
@@ -172,7 +175,7 @@ export class QuotaManager {
|
|
|
172
175
|
// Rate-limit — if API recently 429'd, return stale or throw
|
|
173
176
|
if (this.isBackedOff()) {
|
|
174
177
|
if (this.main)
|
|
175
|
-
return this.main.quota;
|
|
178
|
+
return { quota: this.main.quota, fetched: false };
|
|
176
179
|
throw new Error('Quota API rate-limited — try again later');
|
|
177
180
|
}
|
|
178
181
|
this.inflightMainFp = fp;
|
|
@@ -180,6 +183,10 @@ export class QuotaManager {
|
|
|
180
183
|
return this.inflightMain;
|
|
181
184
|
}
|
|
182
185
|
async refreshFallback(accountId, accessToken) {
|
|
186
|
+
return (await this.refreshFallbackWithMetadata(accountId, accessToken))
|
|
187
|
+
.quota;
|
|
188
|
+
}
|
|
189
|
+
async refreshFallbackWithMetadata(accountId, accessToken) {
|
|
183
190
|
// Deduplicate per account+token so a same-label re-login never joins a
|
|
184
191
|
// quota probe that was started with the previous credentials.
|
|
185
192
|
const inflightKey = QuotaManager.fallbackInflightKey(accountId, accessToken);
|
|
@@ -190,7 +197,7 @@ export class QuotaManager {
|
|
|
190
197
|
if (this.isFallbackBackedOff(accountId, accessToken)) {
|
|
191
198
|
const cached = this.getFallback(accountId, accessToken);
|
|
192
199
|
if (cached)
|
|
193
|
-
return cached.quota;
|
|
200
|
+
return { quota: cached.quota, fetched: false };
|
|
194
201
|
throw new Error('Quota API rate-limited — try again later');
|
|
195
202
|
}
|
|
196
203
|
const promise = this._fetchFallback(accountId, accessToken);
|
|
@@ -319,7 +326,7 @@ export class QuotaManager {
|
|
|
319
326
|
continue;
|
|
320
327
|
if (!account.quota)
|
|
321
328
|
continue;
|
|
322
|
-
const checkedAt =
|
|
329
|
+
const checkedAt = quotaSnapshotCheckedAt(account.quota);
|
|
323
330
|
if (checkedAt <= 0)
|
|
324
331
|
continue;
|
|
325
332
|
const existing = this.getFallback(account.id, account.access);
|
|
@@ -397,7 +404,7 @@ export class QuotaManager {
|
|
|
397
404
|
// a preceding queued call while we waited
|
|
398
405
|
if (this.isBackedOff()) {
|
|
399
406
|
if (this.main)
|
|
400
|
-
return this.main.quota;
|
|
407
|
+
return { quota: this.main.quota, fetched: false };
|
|
401
408
|
throw new Error('Quota API rate-limited — try again later');
|
|
402
409
|
}
|
|
403
410
|
const fileLock = await acquireRefreshFileLock({
|
|
@@ -406,8 +413,9 @@ export class QuotaManager {
|
|
|
406
413
|
});
|
|
407
414
|
if (!fileLock) {
|
|
408
415
|
const cached = this.main;
|
|
409
|
-
if (cached && this.now() < cached.refreshAfter)
|
|
410
|
-
return cached.quota;
|
|
416
|
+
if (cached && this.now() < cached.refreshAfter) {
|
|
417
|
+
return { quota: cached.quota, fetched: false };
|
|
418
|
+
}
|
|
411
419
|
throw new Error('Quota refresh is already in progress');
|
|
412
420
|
}
|
|
413
421
|
try {
|
|
@@ -427,7 +435,7 @@ export class QuotaManager {
|
|
|
427
435
|
};
|
|
428
436
|
this.mainLastApiError = undefined;
|
|
429
437
|
this.onMainQuotaFetched?.(completedQuota, now, this.mainTokenFp, fetchStartedAt);
|
|
430
|
-
return completedQuota;
|
|
438
|
+
return { quota: completedQuota, fetched: true };
|
|
431
439
|
}
|
|
432
440
|
catch (error) {
|
|
433
441
|
this._handleMainFetchError(error);
|
|
@@ -452,7 +460,7 @@ export class QuotaManager {
|
|
|
452
460
|
if (this.isFallbackBackedOff(accountId, accessToken)) {
|
|
453
461
|
const cached = this.getFallback(accountId, accessToken);
|
|
454
462
|
if (cached)
|
|
455
|
-
return cached.quota;
|
|
463
|
+
return { quota: cached.quota, fetched: false };
|
|
456
464
|
throw new Error('Quota API rate-limited — try again later');
|
|
457
465
|
}
|
|
458
466
|
const fileLock = await acquireRefreshFileLock({
|
|
@@ -461,8 +469,9 @@ export class QuotaManager {
|
|
|
461
469
|
});
|
|
462
470
|
if (!fileLock) {
|
|
463
471
|
const cached = this.getFallback(accountId, accessToken);
|
|
464
|
-
if (cached && this.now() < cached.refreshAfter)
|
|
465
|
-
return cached.quota;
|
|
472
|
+
if (cached && this.now() < cached.refreshAfter) {
|
|
473
|
+
return { quota: cached.quota, fetched: false };
|
|
474
|
+
}
|
|
466
475
|
throw new Error('Quota refresh is already in progress');
|
|
467
476
|
}
|
|
468
477
|
try {
|
|
@@ -480,7 +489,7 @@ export class QuotaManager {
|
|
|
480
489
|
}, accessToken);
|
|
481
490
|
this.fallbackApiErrors.delete(accountId);
|
|
482
491
|
this.fallbackErrorTokenFps.delete(accountId);
|
|
483
|
-
return completedQuota;
|
|
492
|
+
return { quota: completedQuota, fetched: true };
|
|
484
493
|
}
|
|
485
494
|
finally {
|
|
486
495
|
await fileLock.release();
|
package/dist/quotas.d.ts
CHANGED
|
@@ -11,13 +11,13 @@ export type QuotaAccountSummary = {
|
|
|
11
11
|
};
|
|
12
12
|
export declare function formatQuotaMoney(money: QuotaMoney): string;
|
|
13
13
|
export declare function buildFallbackQuotaSummaries(storage: AccountStorage | null, errors?: ReadonlyMap<string, string>): {
|
|
14
|
-
error?: string | undefined;
|
|
15
|
-
lastRefreshedAt: number | undefined;
|
|
16
|
-
tierLabel?: string | undefined;
|
|
17
14
|
name: string;
|
|
18
|
-
role:
|
|
15
|
+
role: 'fallback';
|
|
19
16
|
enabled: boolean;
|
|
20
17
|
quota: OAuthQuotaSnapshot | undefined;
|
|
18
|
+
tierLabel?: string | undefined;
|
|
19
|
+
lastRefreshedAt: number | undefined;
|
|
20
|
+
error?: string | undefined;
|
|
21
21
|
}[];
|
|
22
22
|
export declare function buildClaudeQuotaSummary(input: {
|
|
23
23
|
accounts: QuotaAccountSummary[];
|
package/dist/quotas.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { isOAuthAccount } from
|
|
2
|
-
import { formatOAuthAccountTier } from
|
|
1
|
+
import { isOAuthAccount } from './accounts.js';
|
|
2
|
+
import { formatOAuthAccountTier } from './oauth-profile.js';
|
|
3
3
|
export const CLAUDE_QUOTAS_COMMAND_NAME = 'claude-quota';
|
|
4
4
|
const WINDOW_LABELS = {
|
|
5
5
|
five_hour: '5h',
|
package/dist/relay.d.ts
CHANGED
|
@@ -31,6 +31,8 @@ export declare function sendViaRelay(options: {
|
|
|
31
31
|
* within an attempt are ignored.
|
|
32
32
|
*/
|
|
33
33
|
onResponseHeaders?: (headers: Headers) => void;
|
|
34
|
+
dumpTag?: import('./dump.ts').DumpTag;
|
|
35
|
+
onDumpCreated?: (handle: import('./dump.ts').DumpHandle) => void;
|
|
34
36
|
setTimeoutImpl?: typeof globalThis.setTimeout;
|
|
35
37
|
clearTimeoutImpl?: typeof globalThis.clearTimeout;
|
|
36
38
|
}): Promise<Response>;
|
package/dist/relay.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Buffer } from 'node:buffer';
|
|
2
2
|
import { createHash, randomBytes } from 'node:crypto';
|
|
3
|
-
import { dumpRelayRequest } from
|
|
4
|
-
import { relayLog } from
|
|
3
|
+
import { dumpRelayRequest } from './dump.js';
|
|
4
|
+
import { relayLog } from './logger.js';
|
|
5
5
|
class RelayStateMismatchError extends Error {
|
|
6
6
|
}
|
|
7
7
|
class RelayWebSocketConnectionResetError extends Error {
|
|
@@ -752,7 +752,7 @@ function getPersistentRelaySession(config, affinity, timers) {
|
|
|
752
752
|
return session;
|
|
753
753
|
}
|
|
754
754
|
export async function sendViaRelay(options) {
|
|
755
|
-
const { config, input, init, headers, body, fallback, affinity: explicitAffinity, optimisticResponse, onResponseHeaders, setTimeoutImpl = globalThis.setTimeout, clearTimeoutImpl = globalThis.clearTimeout, } = options;
|
|
755
|
+
const { config, input, init, headers, body, fallback, affinity: explicitAffinity, optimisticResponse, onResponseHeaders, dumpTag, onDumpCreated, setTimeoutImpl = globalThis.setTimeout, clearTimeoutImpl = globalThis.clearTimeout, } = options;
|
|
756
756
|
if (!config || !isRelayableAnthropicRequest(input, body))
|
|
757
757
|
return fallback();
|
|
758
758
|
const affinity = explicitAffinity ||
|
|
@@ -848,7 +848,7 @@ export async function sendViaRelay(options) {
|
|
|
848
848
|
});
|
|
849
849
|
relayLog(`used relay transport=${result.transport} protocol=${result.protocol} mode=${result.payload.mode} status=${result.response.status} session=${shortAffinity(affinity)} bodyBytes=${bodyText.length} relayBytes=${actualPayloadBytes}`);
|
|
850
850
|
const dumpStart = perfNowMs();
|
|
851
|
-
await dumpRelayRequest({
|
|
851
|
+
const dumpHandle = await dumpRelayRequest({
|
|
852
852
|
affinity,
|
|
853
853
|
transport: result.transport,
|
|
854
854
|
protocol: result.protocol,
|
|
@@ -858,7 +858,13 @@ export async function sendViaRelay(options) {
|
|
|
858
858
|
previousBodyText: previous?.body,
|
|
859
859
|
payload: result.payload,
|
|
860
860
|
relayBytes: actualPayloadBytes,
|
|
861
|
+
tag: dumpTag,
|
|
861
862
|
});
|
|
863
|
+
try {
|
|
864
|
+
if (dumpHandle)
|
|
865
|
+
onDumpCreated?.(dumpHandle);
|
|
866
|
+
}
|
|
867
|
+
catch { }
|
|
862
868
|
relayPerfLog('dump', {
|
|
863
869
|
session: shortAffinity(affinity),
|
|
864
870
|
ms: formatMs(perfNowMs() - dumpStart),
|
package/dist/routing.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type AccountStorage, type RoutingMode } from './accounts.ts';
|
|
2
2
|
export declare const CLAUDE_ROUTING_COMMAND_NAME = "claude-routing";
|
|
3
|
-
export declare const ROUTING_MODES: readonly [
|
|
3
|
+
export declare const ROUTING_MODES: readonly ['main-first', 'fallback-first', 'sticky-balanced'];
|
|
4
4
|
export declare const DEFAULT_ROUTING_MODE: RoutingMode;
|
|
5
5
|
type RoutingCommandAction = {
|
|
6
6
|
type: 'status';
|
package/dist/routing.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createEmptyStorage, getAccountStoragePath, loadAccounts, saveAccounts, } from
|
|
1
|
+
import { createEmptyStorage, getAccountStoragePath, loadAccounts, saveAccounts, } from './accounts.js';
|
|
2
2
|
export const CLAUDE_ROUTING_COMMAND_NAME = 'claude-routing';
|
|
3
3
|
export const ROUTING_MODES = [
|
|
4
4
|
'main-first',
|
package/dist/start.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare const CLAUDE_START_COMMAND_NAME = "claude-start";
|
|
2
|
+
export type LaneStartCommandAction = {
|
|
3
|
+
type: 'fire';
|
|
4
|
+
} | {
|
|
5
|
+
type: 'usage';
|
|
6
|
+
};
|
|
7
|
+
export declare function parseLaneStartCommandAction(input: string): LaneStartCommandAction;
|
|
8
|
+
export declare function executeLaneStartCommand(input: {
|
|
9
|
+
argumentsText: string;
|
|
10
|
+
}): {
|
|
11
|
+
action: LaneStartCommandAction;
|
|
12
|
+
text: string;
|
|
13
|
+
};
|
package/dist/start.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export const CLAUDE_START_COMMAND_NAME = 'claude-start';
|
|
2
|
+
const START_STATUS_TITLE = '## Claude Lane Start Status';
|
|
3
|
+
const START_QUEUED_TITLE = '## Claude Lane Start Queued';
|
|
4
|
+
const START_USAGE_TITLE = '## Claude Lane Start Usage';
|
|
5
|
+
const START_USAGE = 'Usage: `/claude-start`.';
|
|
6
|
+
export function parseLaneStartCommandAction(input) {
|
|
7
|
+
const normalized = input.trim().split(/\s+/).filter(Boolean);
|
|
8
|
+
if (normalized.length === 0)
|
|
9
|
+
return { type: 'fire' };
|
|
10
|
+
return { type: 'usage' };
|
|
11
|
+
}
|
|
12
|
+
export function executeLaneStartCommand(input) {
|
|
13
|
+
const action = parseLaneStartCommandAction(input.argumentsText);
|
|
14
|
+
if (action.type === 'fire') {
|
|
15
|
+
return {
|
|
16
|
+
action,
|
|
17
|
+
text: [
|
|
18
|
+
START_QUEUED_TITLE,
|
|
19
|
+
'',
|
|
20
|
+
'- Queued an explicit lane-start request.',
|
|
21
|
+
'- This is a billed request: the one-token limit does not remove prompt-cache read or write charges.',
|
|
22
|
+
].join('\n'),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
action,
|
|
27
|
+
text: [START_USAGE_TITLE, '', START_USAGE, '', START_STATUS_TITLE].join('\n'),
|
|
28
|
+
};
|
|
29
|
+
}
|
package/dist/sticky-routing.d.ts
CHANGED
|
@@ -40,6 +40,7 @@ export type StickyQuotaFailureDecision = {
|
|
|
40
40
|
*/
|
|
41
41
|
export declare function createStickyNoRouteResponse(input: {
|
|
42
42
|
mainRefreshError?: AccountOperationError;
|
|
43
|
+
fallbackReauthLabels?: readonly string[];
|
|
43
44
|
routeQuotas: readonly OAuthQuotaSnapshot[];
|
|
44
45
|
modelId?: string;
|
|
45
46
|
now?: number;
|
package/dist/sticky-routing.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createHash, randomUUID } from 'node:crypto';
|
|
2
2
|
import { mkdir, readFile, rename, rm, stat, writeFile } from 'node:fs/promises';
|
|
3
3
|
import { basename, dirname, join } from 'node:path';
|
|
4
|
-
import { acquireRefreshFileLock, getKillswitchThresholdsForAccount, getQuotaCheckIntervalMs, getQuotaMinimumRemainingThresholds, getScopedQuotaWindowForModel, isKillswitchEnabled, isPermanentRefreshError, killswitchRetryAfterSeconds, quotaSnapshotPassesModelScope, } from
|
|
5
|
-
import { isClaudeFableOrMythos5Model } from
|
|
4
|
+
import { acquireRefreshFileLock, getKillswitchThresholdsForAccount, getQuotaCheckIntervalMs, getQuotaMinimumRemainingThresholds, getScopedQuotaWindowForModel, isKillswitchEnabled, isPermanentRefreshError, killswitchRetryAfterSeconds, quotaSnapshotPassesModelScope, } from './accounts.js';
|
|
5
|
+
import { isClaudeFableOrMythos5Model } from './models.js';
|
|
6
6
|
export const STICKY_ROUTING_MAIN_ACCOUNT_ID = 'main';
|
|
7
7
|
export const STICKY_ROUTING_SHORT_RESET_GRACE_MS = 15 * 60_000;
|
|
8
8
|
export const STICKY_ROUTING_ASSIGNMENT_TTL_MS = 7 * 24 * 60 * 60_000;
|
|
@@ -24,13 +24,23 @@ export function createStickyNoRouteResponse(input) {
|
|
|
24
24
|
.map((quota) => getScopedQuotaWindowForModel(quota, modelId))
|
|
25
25
|
.find(Boolean)?.modelName
|
|
26
26
|
: undefined;
|
|
27
|
+
let authenticationMessage;
|
|
27
28
|
if (isPermanentRefreshError(input.mainRefreshError)) {
|
|
28
|
-
|
|
29
|
+
authenticationMessage = modelName
|
|
29
30
|
? `Main Claude OAuth account requires re-login, and no fallback OAuth account is currently routable for ${modelName}.`
|
|
30
31
|
: 'Main Claude OAuth account requires re-login, and no fallback OAuth account is currently routable.';
|
|
32
|
+
}
|
|
33
|
+
else if (input.fallbackReauthLabels?.length) {
|
|
34
|
+
const scope = modelName ? ` for ${modelName}` : '';
|
|
35
|
+
authenticationMessage = `No OAuth account is currently routable${scope}. Fallback Claude OAuth accounts require re-login: ${input.fallbackReauthLabels.join(', ')}.`;
|
|
36
|
+
}
|
|
37
|
+
if (authenticationMessage) {
|
|
31
38
|
return new Response(JSON.stringify({
|
|
32
39
|
type: 'error',
|
|
33
|
-
error: {
|
|
40
|
+
error: {
|
|
41
|
+
type: 'authentication_error',
|
|
42
|
+
message: authenticationMessage,
|
|
43
|
+
},
|
|
34
44
|
}), {
|
|
35
45
|
status: 401,
|
|
36
46
|
headers: { 'content-type': 'application/json' },
|