@gajae-code/ai 0.15.4 → 0.15.6
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/CHANGELOG.md +27 -1
- package/dist/types/auth-broker/client.d.ts +6 -2
- package/dist/types/auth-broker/remote-store.d.ts +14 -2
- package/dist/types/auth-broker/types.d.ts +6 -0
- package/dist/types/auth-broker/wire-schemas.d.ts +19 -0
- package/dist/types/auth-gateway/server.d.ts +39 -5
- package/dist/types/auth-gateway/types.d.ts +16 -2
- package/dist/types/auth-storage.d.ts +116 -34
- package/dist/types/provider-models/openai-compat.d.ts +1 -0
- package/dist/types/provider-models/special.d.ts +2 -1
- package/dist/types/providers/kiro-api-key.d.ts +50 -0
- package/dist/types/providers/kiro-codewhisperer.d.ts +3 -0
- package/dist/types/providers/register-builtins.d.ts +12 -12
- package/dist/types/stream.d.ts +2 -1
- package/dist/types/types.d.ts +35 -24
- package/dist/types/utils/fallback-transport.d.ts +7 -0
- package/dist/types/utils/json-parse.d.ts +5 -3
- package/dist/types/utils/oauth/api-key-login.d.ts +4 -1
- package/dist/types/utils/oauth/api-key-validation.d.ts +12 -6
- package/dist/types/utils/oauth/commandcode.d.ts +1 -0
- package/dist/types/utils/oauth/types.d.ts +1 -1
- package/dist/types/utils/retry.d.ts +2 -0
- package/dist/types/utils/tool-call-healing.d.ts +4 -4
- package/package.json +3 -3
- package/src/auth-broker/client.ts +41 -13
- package/src/auth-broker/redact.ts +25 -1
- package/src/auth-broker/remote-store.ts +374 -115
- package/src/auth-broker/server.ts +131 -91
- package/src/auth-broker/types.ts +6 -0
- package/src/auth-broker/wire-schemas.ts +6 -0
- package/src/auth-gateway/server.ts +447 -79
- package/src/auth-gateway/types.ts +28 -2
- package/src/auth-storage.ts +742 -157
- package/src/cli.ts +1 -0
- package/src/model-thinking.ts +16 -0
- package/src/models.json +1054 -0
- package/src/models.ts +9 -1
- package/src/provider-models/descriptors.ts +3 -1
- package/src/provider-models/openai-compat.ts +41 -1
- package/src/provider-models/special.ts +15 -3
- package/src/providers/anthropic.ts +7 -1
- package/src/providers/azure-openai-responses.ts +4 -1
- package/src/providers/cursor.ts +256 -101
- package/src/providers/gitlab-duo.ts +18 -1
- package/src/providers/google-gemini-cli.ts +3 -0
- package/src/providers/google-shared.ts +3 -0
- package/src/providers/kiro-api-key.d.ts +50 -0
- package/src/providers/kiro-api-key.ts +786 -0
- package/src/providers/kiro-codewhisperer.d.ts +3 -0
- package/src/providers/kiro-codewhisperer.ts +34 -9
- package/src/providers/ollama.ts +3 -0
- package/src/providers/openai-codex-responses.ts +24 -6
- package/src/providers/openai-completions.ts +11 -1
- package/src/providers/openai-responses-shared.ts +23 -2
- package/src/providers/openai-responses.ts +10 -1
- package/src/providers/pi-native-client.ts +1 -0
- package/src/providers/pi-native-server.ts +24 -0
- package/src/providers/register-builtins.d.ts +12 -12
- package/src/providers/register-builtins.ts +16 -3
- package/src/stream.d.ts +2 -1
- package/src/stream.ts +180 -70
- package/src/types.d.ts +35 -24
- package/src/types.ts +40 -23
- package/src/utils/fallback-transport.d.ts +7 -0
- package/src/utils/fallback-transport.ts +21 -4
- package/src/utils/json-parse.d.ts +5 -3
- package/src/utils/json-parse.ts +6 -6
- package/src/utils/oauth/api-key-login.ts +13 -2
- package/src/utils/oauth/api-key-validation.ts +242 -41
- package/src/utils/oauth/commandcode.ts +17 -0
- package/src/utils/oauth/index.ts +20 -5
- package/src/utils/oauth/types.d.ts +1 -1
- package/src/utils/oauth/types.ts +1 -0
- package/src/utils/retry.d.ts +2 -0
- package/src/utils/retry.ts +15 -2
- package/src/utils/tool-call-healing.d.ts +4 -4
- package/src/utils/tool-call-healing.ts +4 -4
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared factory for API-key-paste "login" flows.
|
|
3
3
|
*
|
|
4
|
-
* Several providers (Cerebras, Synthetic, Moonshot, Together, NanoGPT, ZenMux
|
|
4
|
+
* Several providers (Cerebras, Synthetic, Moonshot, Together, NanoGPT, ZenMux,
|
|
5
|
+
* Command Code GOAT)
|
|
5
6
|
* don't actually implement OAuth — they just ask the user to paste an API key,
|
|
6
7
|
* optionally validate it, and return the trimmed key.
|
|
7
8
|
*/
|
|
@@ -11,6 +12,7 @@ type ChatCompletionsValidation = {
|
|
|
11
12
|
provider: string;
|
|
12
13
|
baseUrl: string;
|
|
13
14
|
model: string;
|
|
15
|
+
requireInferenceResponse?: boolean;
|
|
14
16
|
};
|
|
15
17
|
type ModelsEndpointValidation = {
|
|
16
18
|
kind: "models-endpoint";
|
|
@@ -30,6 +32,7 @@ export type ApiKeyLoginConfig = {
|
|
|
30
32
|
placeholder: string;
|
|
31
33
|
/** Validation strategy, or `null` to skip validation. */
|
|
32
34
|
validation: ChatCompletionsValidation | ModelsEndpointValidation | null;
|
|
35
|
+
validationProgressMessage?: string;
|
|
33
36
|
};
|
|
34
37
|
export declare function createApiKeyLogin(config: ApiKeyLoginConfig): (options: OAuthController) => Promise<string>;
|
|
35
38
|
export {};
|
|
@@ -4,12 +4,17 @@ type OpenAICompatibleValidationOptions = {
|
|
|
4
4
|
baseUrl: string;
|
|
5
5
|
model: string;
|
|
6
6
|
signal?: AbortSignal;
|
|
7
|
+
fetch?: typeof globalThis.fetch;
|
|
8
|
+
requireInferenceResponse?: boolean;
|
|
9
|
+
timeoutMs?: number;
|
|
7
10
|
};
|
|
8
11
|
type ModelListValidationOptions = {
|
|
9
12
|
provider: string;
|
|
10
13
|
apiKey: string;
|
|
11
14
|
modelsUrl: string;
|
|
12
15
|
signal?: AbortSignal;
|
|
16
|
+
fetch?: typeof globalThis.fetch;
|
|
17
|
+
timeoutMs?: number;
|
|
13
18
|
};
|
|
14
19
|
/**
|
|
15
20
|
* Validate an API key against an OpenAI-compatible chat completions endpoint.
|
|
@@ -18,16 +23,17 @@ type ModelListValidationOptions = {
|
|
|
18
23
|
*/
|
|
19
24
|
export declare function validateOpenAICompatibleApiKey(options: OpenAICompatibleValidationOptions): Promise<void>;
|
|
20
25
|
/**
|
|
21
|
-
* Validate
|
|
26
|
+
* Validate a provider models endpoint's reachability and response shape.
|
|
22
27
|
*
|
|
23
28
|
* Useful for providers where access to specific models may vary by plan and
|
|
24
|
-
* should not block
|
|
29
|
+
* should not block login; an available model list is not proof that an
|
|
30
|
+
* authenticated inference request will succeed for the supplied key.
|
|
25
31
|
*
|
|
26
32
|
* A 200 status alone is NOT accepted: a captive portal, misrouting proxy, or
|
|
27
|
-
* broken gateway can answer 200 with an HTML page or an empty JSON object
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
33
|
+
* broken gateway can answer 200 with an HTML page or an empty JSON object.
|
|
34
|
+
* The body must parse as JSON and carry a recognizable model list before the
|
|
35
|
+
* endpoint is considered reachable. This catalog check is not proof that
|
|
36
|
+
* authenticated inference is entitled to use the supplied key.
|
|
31
37
|
*/
|
|
32
38
|
export declare function validateApiKeyAgainstModelsEndpoint(options: ModelListValidationOptions): Promise<void>;
|
|
33
39
|
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const loginCommandCode: (options: import("./types").OAuthController) => Promise<string>;
|
|
@@ -7,7 +7,7 @@ export type OAuthCredentials = {
|
|
|
7
7
|
email?: string;
|
|
8
8
|
accountId?: string;
|
|
9
9
|
};
|
|
10
|
-
export type OAuthProvider = "kiro" | "alibaba-token-plan" | "anthropic" | "bizrouter" | "mara" | "cerebras" | "cloudflare-ai-gateway" | "cursor" | "deepseek" | "deepinfra" | "fireworks" | "firepass" | "fugu" | "github-copilot" | "google-gemini-cli" | "google-antigravity" | "gitlab-duo" | "huggingface" | "kimi-code" | "kilo" | "kagi" | "litellm" | "lm-studio" | "minimax-code" | "minimax-code-cn" | "moonshot" | "nvidia" | "nanogpt" | "ollama" | "ollama-cloud" | "openai-codex" | "openai-codex-device" | "opencode-go" | "opencode-zen" | "opengateway" | "openrouter" | "parallel" | "perplexity" | "qianfan" | "qwen-portal" | "sglang" | "synthetic" | "tavily" | "together" | "venice" | "vercel-ai-gateway" | "vllm" | "xai" | "glm-zcode" | "xiaomi" | "xiaomi-token-plan-sgp" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-cn" | "zenmux" | "opencodex" | "zai";
|
|
10
|
+
export type OAuthProvider = "kiro" | "alibaba-token-plan" | "anthropic" | "bizrouter" | "mara" | "cerebras" | "cloudflare-ai-gateway" | "cursor" | "deepseek" | "deepinfra" | "fireworks" | "firepass" | "fugu" | "github-copilot" | "google-gemini-cli" | "google-antigravity" | "gitlab-duo" | "huggingface" | "kimi-code" | "kilo" | "kagi" | "litellm" | "lm-studio" | "minimax-code" | "minimax-code-cn" | "moonshot" | "nvidia" | "nanogpt" | "ollama" | "ollama-cloud" | "openai-codex" | "openai-codex-device" | "opencode-go" | "opencode-zen" | "commandcode-goat" | "opengateway" | "openrouter" | "parallel" | "perplexity" | "qianfan" | "qwen-portal" | "sglang" | "synthetic" | "tavily" | "together" | "venice" | "vercel-ai-gateway" | "vllm" | "xai" | "glm-zcode" | "xiaomi" | "xiaomi-token-plan-sgp" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-cn" | "zenmux" | "opencodex" | "zai";
|
|
11
11
|
export type OAuthProviderId = OAuthProvider | (string & {});
|
|
12
12
|
export type OAuthPrompt = {
|
|
13
13
|
message: string;
|
|
@@ -22,10 +22,10 @@ export interface HealedToolCall {
|
|
|
22
22
|
readonly name: string;
|
|
23
23
|
readonly arguments: string;
|
|
24
24
|
/**
|
|
25
|
-
* Whether the raw leaked payload
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
25
|
+
* Whether the raw leaked payload carried unsafe Unicode argument data.
|
|
26
|
+
* Captured before the normalizing round-trip below, which would otherwise
|
|
27
|
+
* erase malformed escape evidence. Valid `\uXXXX` spellings decode
|
|
28
|
+
* canonically and leave this false.
|
|
29
29
|
*/
|
|
30
30
|
readonly escapedNonAsciiArguments: boolean;
|
|
31
31
|
readonly escapedUnicodeArgumentEvidence?: UnicodeEscapeEvidence;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@gajae-code/ai",
|
|
4
|
-
"version": "0.15.
|
|
4
|
+
"version": "0.15.6",
|
|
5
5
|
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
|
6
6
|
"homepage": "https://gajae-code.com",
|
|
7
7
|
"author": "Yeachan-Heo and Gajae Code Contributors",
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@anthropic-ai/sdk": "^0.94.0",
|
|
42
42
|
"@bufbuild/protobuf": "^2.12.0",
|
|
43
|
-
"@gajae-code/natives": "0.15.
|
|
44
|
-
"@gajae-code/utils": "0.15.
|
|
43
|
+
"@gajae-code/natives": "0.15.6",
|
|
44
|
+
"@gajae-code/utils": "0.15.6",
|
|
45
45
|
"openai": "^6.36.0",
|
|
46
46
|
"partial-json": "^0.1.7",
|
|
47
47
|
"zod": "4.4.3"
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { readSseEvents } from "@gajae-code/utils";
|
|
9
9
|
import type { ZodType, infer as zInfer } from "zod/v4";
|
|
10
10
|
import type { AuthCredential } from "../auth-storage";
|
|
11
|
+
import type { Provider } from "../types";
|
|
11
12
|
import type {
|
|
12
13
|
CredentialDisableRequest,
|
|
13
14
|
CredentialDisableResponse,
|
|
@@ -34,6 +35,8 @@ import {
|
|
|
34
35
|
usageResponseSchema,
|
|
35
36
|
} from "./wire-schemas";
|
|
36
37
|
|
|
38
|
+
export const AUTH_BROKER_EPOCH_HEADER = "X-GJC-Auth-Broker-Epoch";
|
|
39
|
+
|
|
37
40
|
export interface AuthBrokerClientOptions {
|
|
38
41
|
/** Base URL (e.g. `https://broker.tailnet:8765`). Trailing slashes are trimmed. */
|
|
39
42
|
url: string;
|
|
@@ -80,24 +83,27 @@ export class AuthBrokerCredentialMetadataUnsupportedError extends AuthBrokerErro
|
|
|
80
83
|
|
|
81
84
|
export interface FetchSnapshotOptions {
|
|
82
85
|
ifGenerationGt?: number;
|
|
86
|
+
ifEpoch?: string;
|
|
83
87
|
waitMs?: number;
|
|
84
88
|
signal?: AbortSignal;
|
|
85
89
|
}
|
|
86
90
|
|
|
87
91
|
export type FetchSnapshotResult =
|
|
88
92
|
| { status: 200; snapshot: SnapshotResponse; generation: number }
|
|
89
|
-
| { status: 304; generation: number };
|
|
93
|
+
| { status: 304; generation: number; epoch?: string };
|
|
90
94
|
|
|
91
|
-
function
|
|
95
|
+
function parseSnapshotTag(header: string | null): { epoch?: string; generation: number } | undefined {
|
|
92
96
|
if (!header) return undefined;
|
|
93
97
|
let value = header.trim();
|
|
94
98
|
if (value.startsWith("W/")) value = value.slice(2).trim();
|
|
95
99
|
if (value.startsWith('"') && value.endsWith('"') && value.length >= 2) {
|
|
96
100
|
value = value.slice(1, -1);
|
|
97
101
|
}
|
|
98
|
-
const
|
|
102
|
+
const separator = value.lastIndexOf(":");
|
|
103
|
+
const epoch = separator > 0 ? value.slice(0, separator) : undefined;
|
|
104
|
+
const generation = Number(separator > 0 ? value.slice(separator + 1) : value);
|
|
99
105
|
if (!Number.isInteger(generation) || generation < 0) return undefined;
|
|
100
|
-
return generation;
|
|
106
|
+
return { epoch, generation };
|
|
101
107
|
}
|
|
102
108
|
|
|
103
109
|
const DEFAULT_TIMEOUT_MS = 10_000;
|
|
@@ -136,6 +142,7 @@ export class AuthBrokerClient {
|
|
|
136
142
|
try {
|
|
137
143
|
return (await this.#request("GET", "/v1/credentials/metadata", {
|
|
138
144
|
schema: credentialMetadataResponseSchema,
|
|
145
|
+
headers: { [AUTH_BROKER_EPOCH_HEADER]: "1" },
|
|
139
146
|
signal,
|
|
140
147
|
})) as CredentialMetadataResponse;
|
|
141
148
|
} catch (error) {
|
|
@@ -150,7 +157,11 @@ export class AuthBrokerClient {
|
|
|
150
157
|
if (opts.waitMs !== undefined) query.set("wait", String(opts.waitMs));
|
|
151
158
|
const path = `/v1/snapshot${query.size > 0 ? `?${query.toString()}` : ""}`;
|
|
152
159
|
const headers: Record<string, string> = {};
|
|
153
|
-
|
|
160
|
+
headers[AUTH_BROKER_EPOCH_HEADER] = "1";
|
|
161
|
+
if (opts.ifGenerationGt !== undefined) {
|
|
162
|
+
const validator = opts.ifEpoch ? `${opts.ifEpoch}:${opts.ifGenerationGt}` : String(opts.ifGenerationGt);
|
|
163
|
+
headers["If-None-Match"] = `"${validator}"`;
|
|
164
|
+
}
|
|
154
165
|
const timeoutMs =
|
|
155
166
|
opts.waitMs !== undefined && opts.waitMs > 0 ? Math.max(this.#timeoutMs, opts.waitMs + 1000) : undefined;
|
|
156
167
|
const response = await this.#fetchRaw("GET", path, {
|
|
@@ -159,9 +170,13 @@ export class AuthBrokerClient {
|
|
|
159
170
|
signal: opts.signal,
|
|
160
171
|
timeoutMs,
|
|
161
172
|
});
|
|
162
|
-
const
|
|
173
|
+
const etag = parseSnapshotTag(response.headers.get("etag"));
|
|
163
174
|
if (response.status === 304) {
|
|
164
|
-
return {
|
|
175
|
+
return {
|
|
176
|
+
status: 304,
|
|
177
|
+
generation: etag?.generation ?? opts.ifGenerationGt ?? 0,
|
|
178
|
+
...(etag?.epoch ? { epoch: etag.epoch } : {}),
|
|
179
|
+
};
|
|
165
180
|
}
|
|
166
181
|
const text = await response.text();
|
|
167
182
|
const raw = this.#parseJson(text, response.status);
|
|
@@ -173,7 +188,7 @@ export class AuthBrokerClient {
|
|
|
173
188
|
});
|
|
174
189
|
}
|
|
175
190
|
const snapshot = validated.data as SnapshotResponse;
|
|
176
|
-
return { status: 200, snapshot, generation:
|
|
191
|
+
return { status: 200, snapshot, generation: etag?.generation ?? snapshot.generation };
|
|
177
192
|
}
|
|
178
193
|
|
|
179
194
|
/**
|
|
@@ -190,6 +205,7 @@ export class AuthBrokerClient {
|
|
|
190
205
|
const headers: Record<string, string> = {
|
|
191
206
|
Accept: "text/event-stream",
|
|
192
207
|
Authorization: `Bearer ${this.#token}`,
|
|
208
|
+
[AUTH_BROKER_EPOCH_HEADER]: "1",
|
|
193
209
|
};
|
|
194
210
|
if (opts.signal?.aborted) {
|
|
195
211
|
throw new AuthBrokerError("Auth broker request aborted", { cause: opts.signal.reason });
|
|
@@ -258,12 +274,13 @@ export class AuthBrokerClient {
|
|
|
258
274
|
}
|
|
259
275
|
}
|
|
260
276
|
|
|
261
|
-
fetchUsage(signal?: AbortSignal): Promise<UsageResponse> {
|
|
277
|
+
fetchUsage(signal?: AbortSignal, provider?: Provider): Promise<UsageResponse> {
|
|
262
278
|
// Validates the envelope (`generatedAt`, `reports[].provider`, `limits`,
|
|
263
279
|
// `metadata`) but leaves provider-specific extension fields permissive so
|
|
264
280
|
// the broker can ship new shapes ahead of the client. `raw` is accepted
|
|
265
281
|
// but normally stripped by the broker before send.
|
|
266
|
-
|
|
282
|
+
const path = provider ? `/v1/usage/scoped?provider=${encodeURIComponent(provider)}` : "/v1/usage";
|
|
283
|
+
return this.#request("GET", path, { schema: usageResponseSchema, signal }) as Promise<UsageResponse>;
|
|
267
284
|
}
|
|
268
285
|
|
|
269
286
|
async refreshCredential(id: number, signal?: AbortSignal): Promise<CredentialRefreshResponse> {
|
|
@@ -285,8 +302,13 @@ export class AuthBrokerClient {
|
|
|
285
302
|
}) as Promise<CredentialRefreshResponse>;
|
|
286
303
|
}
|
|
287
304
|
|
|
288
|
-
async disableCredential(
|
|
289
|
-
|
|
305
|
+
async disableCredential(
|
|
306
|
+
id: number,
|
|
307
|
+
cause: string,
|
|
308
|
+
signal?: AbortSignal,
|
|
309
|
+
expectedRevision?: number,
|
|
310
|
+
): Promise<CredentialDisableResponse> {
|
|
311
|
+
const body: CredentialDisableRequest = { cause, ...(expectedRevision === undefined ? {} : { expectedRevision }) };
|
|
290
312
|
return this.#request("POST", `/v1/credential/${id}/disable`, {
|
|
291
313
|
body,
|
|
292
314
|
schema: credentialDisableResponseSchema,
|
|
@@ -323,7 +345,13 @@ export class AuthBrokerClient {
|
|
|
323
345
|
async #request<TSchema extends ZodType>(
|
|
324
346
|
method: "GET" | "POST",
|
|
325
347
|
path: string,
|
|
326
|
-
opts: {
|
|
348
|
+
opts: {
|
|
349
|
+
schema: TSchema;
|
|
350
|
+
auth?: boolean;
|
|
351
|
+
body?: unknown;
|
|
352
|
+
signal?: AbortSignal;
|
|
353
|
+
headers?: Record<string, string>;
|
|
354
|
+
},
|
|
327
355
|
): Promise<zInfer<TSchema>> {
|
|
328
356
|
const response = await this.#fetchRaw(method, path, opts);
|
|
329
357
|
const text = await response.text();
|
|
@@ -7,8 +7,32 @@
|
|
|
7
7
|
export function cleanReason(value: unknown): string | undefined {
|
|
8
8
|
if (value === undefined || value === null) return undefined;
|
|
9
9
|
let reason = value instanceof Error ? value.message : String(value);
|
|
10
|
+
if (/[\u0000-\u001f\u007f-\u009f]/.test(reason)) return "Credential diagnostic unavailable.";
|
|
11
|
+
if (reason.includes("\\")) return "Credential diagnostic unavailable.";
|
|
12
|
+
if (/["']?authorization(?:[_-]header)?["']?\s*[:=]/i.test(reason)) return "Credential diagnostic unavailable.";
|
|
13
|
+
if (
|
|
14
|
+
/\b["']?(?:key|api[_-]?key|client[_-]?secret|clientSecret|token|secret|password|access|refresh|cookie|credential)(?:[_-](?:token|key|secret|header|headers))?["']?\s*[:=]/i.test(
|
|
15
|
+
reason,
|
|
16
|
+
)
|
|
17
|
+
) {
|
|
18
|
+
return "Credential diagnostic unavailable.";
|
|
19
|
+
}
|
|
20
|
+
if (/\b(?:bearer|basic)\s+["']/i.test(reason)) return "Credential diagnostic unavailable.";
|
|
21
|
+
if (/^No credential with id=\d+$/i.test(reason)) return reason;
|
|
22
|
+
if (/\b(?:api\s*[-_]?key|access\s*[-_]?token|refresh\s*[-_]?token|credential)\b/i.test(reason))
|
|
23
|
+
return "Credential diagnostic unavailable.";
|
|
10
24
|
reason = reason.replace(/bearer\s+[^\s,;]+/gi, "Bearer [redacted]");
|
|
11
|
-
reason = reason.replace(/
|
|
25
|
+
reason = reason.replace(/basic\s+[^\s,;]+/gi, "Basic [redacted]");
|
|
26
|
+
reason = reason.replace(/([a-z][a-z0-9+.-]*:\/\/)[^\s/@]+@/gi, "$1[redacted]@");
|
|
27
|
+
reason = reason.replace(/\b([a-z][a-z0-9+.-]*:\/\/[^\s<>"']*?)(?:[?#][^\s<>"']*)/gi, "$1");
|
|
28
|
+
reason = reason.replace(
|
|
29
|
+
/((?:\\?["']?(?:key|api[_-]?key|client[_-]?secret|clientSecret|token|secret|authorization|password|access|refresh|cookie|credential)(?:[_-](?:token|key|secret|header|headers))?\\?["']?)\s*:\s*)\\?(["'])(?:\\.|(?!\2)[^\\])*\2/gi,
|
|
30
|
+
"$1$2[redacted]$2",
|
|
31
|
+
);
|
|
32
|
+
reason = reason.replace(
|
|
33
|
+
/((?:key|api[_-]?key|client[_-]?secret|clientSecret|token|secret|authorization|password|access|refresh|cookie|credential)(?:[_-](?:token|key|secret|header|headers))?)\s*[:=]\s*[^\s,;]+/gi,
|
|
34
|
+
"$1=[redacted]",
|
|
35
|
+
);
|
|
12
36
|
reason = reason.replace(/[\r\n\t ]+/g, " ").trim();
|
|
13
37
|
if (reason.length > 256) reason = `${reason.slice(0, 253)}...`;
|
|
14
38
|
return reason || undefined;
|