@gajae-code/ai 0.1.1
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 +2644 -0
- package/README.md +1181 -0
- package/dist/types/api-registry.d.ts +30 -0
- package/dist/types/auth-broker/client.d.ts +66 -0
- package/dist/types/auth-broker/index.d.ts +5 -0
- package/dist/types/auth-broker/refresher.d.ts +25 -0
- package/dist/types/auth-broker/remote-store.d.ts +96 -0
- package/dist/types/auth-broker/server.d.ts +32 -0
- package/dist/types/auth-broker/types.d.ts +105 -0
- package/dist/types/auth-broker/wire-schemas.d.ts +412 -0
- package/dist/types/auth-gateway/http.d.ts +39 -0
- package/dist/types/auth-gateway/index.d.ts +3 -0
- package/dist/types/auth-gateway/server.d.ts +17 -0
- package/dist/types/auth-gateway/types.d.ts +115 -0
- package/dist/types/auth-storage.d.ts +641 -0
- package/dist/types/cli.d.ts +2 -0
- package/dist/types/index.d.ts +49 -0
- package/dist/types/model-cache.d.ts +17 -0
- package/dist/types/model-manager.d.ts +62 -0
- package/dist/types/model-thinking.d.ts +71 -0
- package/dist/types/models.d.ts +12 -0
- package/dist/types/provider-details.d.ts +24 -0
- package/dist/types/provider-models/bundled-references.d.ts +4 -0
- package/dist/types/provider-models/descriptors.d.ts +48 -0
- package/dist/types/provider-models/google.d.ts +20 -0
- package/dist/types/provider-models/index.d.ts +5 -0
- package/dist/types/provider-models/ollama.d.ts +7 -0
- package/dist/types/provider-models/openai-compat.d.ts +237 -0
- package/dist/types/provider-models/special.d.ts +16 -0
- package/dist/types/providers/amazon-bedrock.d.ts +36 -0
- package/dist/types/providers/anthropic-messages-server-schema.d.ts +450 -0
- package/dist/types/providers/anthropic-messages-server.d.ts +17 -0
- package/dist/types/providers/anthropic.d.ts +188 -0
- package/dist/types/providers/aws-credentials.d.ts +43 -0
- package/dist/types/providers/aws-eventstream.d.ts +38 -0
- package/dist/types/providers/aws-sigv4.d.ts +55 -0
- package/dist/types/providers/azure-openai-responses.d.ts +15 -0
- package/dist/types/providers/cursor/gen/agent_pb.d.ts +13022 -0
- package/dist/types/providers/cursor.d.ts +42 -0
- package/dist/types/providers/error-message.d.ts +27 -0
- package/dist/types/providers/github-copilot-headers.d.ts +40 -0
- package/dist/types/providers/gitlab-duo.d.ts +27 -0
- package/dist/types/providers/google-auth.d.ts +24 -0
- package/dist/types/providers/google-gemini-cli.d.ts +72 -0
- package/dist/types/providers/google-gemini-headers.d.ts +18 -0
- package/dist/types/providers/google-shared.d.ts +163 -0
- package/dist/types/providers/google-types.d.ts +138 -0
- package/dist/types/providers/google-vertex.d.ts +7 -0
- package/dist/types/providers/google.d.ts +4 -0
- package/dist/types/providers/grammar.d.ts +1 -0
- package/dist/types/providers/kimi.d.ts +27 -0
- package/dist/types/providers/mock.d.ts +175 -0
- package/dist/types/providers/ollama.d.ts +6 -0
- package/dist/types/providers/openai-anthropic-shim.d.ts +31 -0
- package/dist/types/providers/openai-chat-server-schema.d.ts +814 -0
- package/dist/types/providers/openai-chat-server.d.ts +16 -0
- package/dist/types/providers/openai-codex/constants.d.ts +26 -0
- package/dist/types/providers/openai-codex/request-transformer.d.ts +49 -0
- package/dist/types/providers/openai-codex/response-handler.d.ts +17 -0
- package/dist/types/providers/openai-codex-responses.d.ts +67 -0
- package/dist/types/providers/openai-completions-compat.d.ts +25 -0
- package/dist/types/providers/openai-completions.d.ts +33 -0
- package/dist/types/providers/openai-responses-server-schema.d.ts +392 -0
- package/dist/types/providers/openai-responses-server.d.ts +17 -0
- package/dist/types/providers/openai-responses-shared.d.ts +89 -0
- package/dist/types/providers/openai-responses.d.ts +32 -0
- package/dist/types/providers/pi-native-client.d.ts +13 -0
- package/dist/types/providers/pi-native-server.d.ts +68 -0
- package/dist/types/providers/register-builtins.d.ts +31 -0
- package/dist/types/providers/synthetic.d.ts +26 -0
- package/dist/types/providers/transform-messages.d.ts +12 -0
- package/dist/types/providers/vision-guard.d.ts +8 -0
- package/dist/types/rate-limit-utils.d.ts +19 -0
- package/dist/types/stream.d.ts +24 -0
- package/dist/types/types.d.ts +746 -0
- package/dist/types/usage/claude.d.ts +3 -0
- package/dist/types/usage/gemini.d.ts +2 -0
- package/dist/types/usage/github-copilot.d.ts +7 -0
- package/dist/types/usage/google-antigravity.d.ts +2 -0
- package/dist/types/usage/kimi.d.ts +2 -0
- package/dist/types/usage/minimax-code.d.ts +2 -0
- package/dist/types/usage/openai-codex.d.ts +3 -0
- package/dist/types/usage/shared.d.ts +1 -0
- package/dist/types/usage/zai.d.ts +2 -0
- package/dist/types/usage.d.ts +258 -0
- package/dist/types/utils/abort.d.ts +19 -0
- package/dist/types/utils/anthropic-auth.d.ts +31 -0
- package/dist/types/utils/discovery/antigravity.d.ts +61 -0
- package/dist/types/utils/discovery/codex.d.ts +38 -0
- package/dist/types/utils/discovery/cursor.d.ts +23 -0
- package/dist/types/utils/discovery/gemini.d.ts +25 -0
- package/dist/types/utils/discovery/index.d.ts +4 -0
- package/dist/types/utils/discovery/openai-compatible.d.ts +72 -0
- package/dist/types/utils/event-stream.d.ts +28 -0
- package/dist/types/utils/fireworks-model-id.d.ts +10 -0
- package/dist/types/utils/foundry.d.ts +1 -0
- package/dist/types/utils/h2-fetch.d.ts +22 -0
- package/dist/types/utils/http-inspector.d.ts +31 -0
- package/dist/types/utils/idle-iterator.d.ts +67 -0
- package/dist/types/utils/json-parse.d.ts +10 -0
- package/dist/types/utils/oauth/alibaba-coding-plan.d.ts +18 -0
- package/dist/types/utils/oauth/anthropic.d.ts +22 -0
- package/dist/types/utils/oauth/api-key-login.d.ts +35 -0
- package/dist/types/utils/oauth/api-key-validation.d.ts +27 -0
- package/dist/types/utils/oauth/callback-server.d.ts +57 -0
- package/dist/types/utils/oauth/cerebras.d.ts +1 -0
- package/dist/types/utils/oauth/cloudflare-ai-gateway.d.ts +18 -0
- package/dist/types/utils/oauth/cursor.d.ts +15 -0
- package/dist/types/utils/oauth/deepseek.d.ts +10 -0
- package/dist/types/utils/oauth/firepass.d.ts +1 -0
- package/dist/types/utils/oauth/fireworks.d.ts +1 -0
- package/dist/types/utils/oauth/github-copilot.d.ts +38 -0
- package/dist/types/utils/oauth/gitlab-duo.d.ts +3 -0
- package/dist/types/utils/oauth/google-antigravity.d.ts +11 -0
- package/dist/types/utils/oauth/google-gemini-cli.d.ts +10 -0
- package/dist/types/utils/oauth/google-oauth-shared.d.ts +28 -0
- package/dist/types/utils/oauth/huggingface.d.ts +19 -0
- package/dist/types/utils/oauth/index.d.ts +38 -0
- package/dist/types/utils/oauth/kagi.d.ts +17 -0
- package/dist/types/utils/oauth/kilo.d.ts +5 -0
- package/dist/types/utils/oauth/kimi.d.ts +21 -0
- package/dist/types/utils/oauth/litellm.d.ts +18 -0
- package/dist/types/utils/oauth/lm-studio.d.ts +17 -0
- package/dist/types/utils/oauth/minimax-code.d.ts +28 -0
- package/dist/types/utils/oauth/moonshot.d.ts +1 -0
- package/dist/types/utils/oauth/nanogpt.d.ts +1 -0
- package/dist/types/utils/oauth/nvidia.d.ts +18 -0
- package/dist/types/utils/oauth/ollama-cloud.d.ts +2 -0
- package/dist/types/utils/oauth/ollama.d.ts +18 -0
- package/dist/types/utils/oauth/openai-codex.d.ts +21 -0
- package/dist/types/utils/oauth/opencode.d.ts +18 -0
- package/dist/types/utils/oauth/parallel.d.ts +17 -0
- package/dist/types/utils/oauth/perplexity.d.ts +9 -0
- package/dist/types/utils/oauth/pkce.d.ts +8 -0
- package/dist/types/utils/oauth/qianfan.d.ts +17 -0
- package/dist/types/utils/oauth/qwen-portal.d.ts +19 -0
- package/dist/types/utils/oauth/synthetic.d.ts +1 -0
- package/dist/types/utils/oauth/tavily.d.ts +17 -0
- package/dist/types/utils/oauth/together.d.ts +1 -0
- package/dist/types/utils/oauth/types.d.ts +44 -0
- package/dist/types/utils/oauth/venice.d.ts +18 -0
- package/dist/types/utils/oauth/vercel-ai-gateway.d.ts +18 -0
- package/dist/types/utils/oauth/vllm.d.ts +16 -0
- package/dist/types/utils/oauth/xiaomi.d.ts +19 -0
- package/dist/types/utils/oauth/zai.d.ts +18 -0
- package/dist/types/utils/oauth/zenmux.d.ts +1 -0
- package/dist/types/utils/overflow.d.ts +54 -0
- package/dist/types/utils/parse-bind.d.ts +23 -0
- package/dist/types/utils/provider-response.d.ts +3 -0
- package/dist/types/utils/retry-after.d.ts +3 -0
- package/dist/types/utils/retry.d.ts +26 -0
- package/dist/types/utils/schema/adapt.d.ts +24 -0
- package/dist/types/utils/schema/compatibility.d.ts +30 -0
- package/dist/types/utils/schema/dereference.d.ts +11 -0
- package/dist/types/utils/schema/draft.d.ts +10 -0
- package/dist/types/utils/schema/equality.d.ts +4 -0
- package/dist/types/utils/schema/fields.d.ts +49 -0
- package/dist/types/utils/schema/index.d.ts +13 -0
- package/dist/types/utils/schema/json-schema-validator.d.ts +12 -0
- package/dist/types/utils/schema/meta-validator.d.ts +2 -0
- package/dist/types/utils/schema/normalize.d.ts +93 -0
- package/dist/types/utils/schema/spill.d.ts +8 -0
- package/dist/types/utils/schema/stamps.d.ts +25 -0
- package/dist/types/utils/schema/types.d.ts +4 -0
- package/dist/types/utils/schema/wire.d.ts +54 -0
- package/dist/types/utils/schema/zod-decontaminate.d.ts +31 -0
- package/dist/types/utils/sse-debug.d.ts +10 -0
- package/dist/types/utils/tool-call-healing.d.ts +71 -0
- package/dist/types/utils/tool-choice.d.ts +50 -0
- package/dist/types/utils/validation.d.ts +17 -0
- package/dist/types/utils.d.ts +28 -0
- package/package.json +146 -0
- package/src/api-registry.ts +96 -0
- package/src/auth-broker/client.ts +358 -0
- package/src/auth-broker/index.ts +5 -0
- package/src/auth-broker/refresher.ts +127 -0
- package/src/auth-broker/remote-store.ts +623 -0
- package/src/auth-broker/server.ts +644 -0
- package/src/auth-broker/types.ts +127 -0
- package/src/auth-broker/wire-schemas.ts +200 -0
- package/src/auth-gateway/http.ts +194 -0
- package/src/auth-gateway/index.ts +3 -0
- package/src/auth-gateway/server.ts +717 -0
- package/src/auth-gateway/types.ts +134 -0
- package/src/auth-storage.ts +4104 -0
- package/src/cli.ts +262 -0
- package/src/index.ts +54 -0
- package/src/model-cache.ts +129 -0
- package/src/model-manager.ts +450 -0
- package/src/model-thinking.ts +691 -0
- package/src/models.json +73853 -0
- package/src/models.json.d.ts +9 -0
- package/src/models.ts +56 -0
- package/src/prompts/turn-aborted-guidance.md +4 -0
- package/src/provider-details.ts +90 -0
- package/src/provider-models/bundled-references.ts +38 -0
- package/src/provider-models/descriptors.ts +308 -0
- package/src/provider-models/google.ts +91 -0
- package/src/provider-models/index.ts +5 -0
- package/src/provider-models/ollama.ts +153 -0
- package/src/provider-models/openai-compat.ts +2275 -0
- package/src/provider-models/special.ts +67 -0
- package/src/providers/amazon-bedrock.ts +849 -0
- package/src/providers/anthropic-messages-server-schema.ts +229 -0
- package/src/providers/anthropic-messages-server.ts +677 -0
- package/src/providers/anthropic.ts +2696 -0
- package/src/providers/aws-credentials.ts +501 -0
- package/src/providers/aws-eventstream.ts +185 -0
- package/src/providers/aws-sigv4.ts +218 -0
- package/src/providers/azure-openai-responses.ts +337 -0
- package/src/providers/cursor/gen/agent_pb.ts +15274 -0
- package/src/providers/cursor/proto/agent.proto +3526 -0
- package/src/providers/cursor/proto/buf.gen.yaml +6 -0
- package/src/providers/cursor/proto/buf.yaml +17 -0
- package/src/providers/cursor.ts +2561 -0
- package/src/providers/error-message.ts +21 -0
- package/src/providers/github-copilot-headers.ts +140 -0
- package/src/providers/gitlab-duo.ts +372 -0
- package/src/providers/google-auth.ts +252 -0
- package/src/providers/google-gemini-cli.ts +795 -0
- package/src/providers/google-gemini-headers.ts +41 -0
- package/src/providers/google-shared.ts +902 -0
- package/src/providers/google-types.ts +167 -0
- package/src/providers/google-vertex.ts +88 -0
- package/src/providers/google.ts +41 -0
- package/src/providers/grammar.ts +70 -0
- package/src/providers/kimi.ts +52 -0
- package/src/providers/mock.ts +500 -0
- package/src/providers/ollama.ts +544 -0
- package/src/providers/openai-anthropic-shim.ts +138 -0
- package/src/providers/openai-chat-server-schema.ts +243 -0
- package/src/providers/openai-chat-server.ts +628 -0
- package/src/providers/openai-codex/constants.ts +43 -0
- package/src/providers/openai-codex/request-transformer.ts +161 -0
- package/src/providers/openai-codex/response-handler.ts +81 -0
- package/src/providers/openai-codex-responses.ts +2598 -0
- package/src/providers/openai-completions-compat.ts +279 -0
- package/src/providers/openai-completions.ts +1853 -0
- package/src/providers/openai-responses-server-schema.ts +290 -0
- package/src/providers/openai-responses-server.ts +1183 -0
- package/src/providers/openai-responses-shared.ts +800 -0
- package/src/providers/openai-responses.ts +621 -0
- package/src/providers/pi-native-client.ts +228 -0
- package/src/providers/pi-native-server.ts +210 -0
- package/src/providers/register-builtins.ts +412 -0
- package/src/providers/synthetic.ts +50 -0
- package/src/providers/transform-messages.ts +309 -0
- package/src/providers/vision-guard.ts +31 -0
- package/src/rate-limit-utils.ts +84 -0
- package/src/stream.ts +895 -0
- package/src/types.ts +884 -0
- package/src/usage/claude.ts +431 -0
- package/src/usage/gemini.ts +250 -0
- package/src/usage/github-copilot.ts +421 -0
- package/src/usage/google-antigravity.ts +201 -0
- package/src/usage/kimi.ts +271 -0
- package/src/usage/minimax-code.ts +31 -0
- package/src/usage/openai-codex.ts +503 -0
- package/src/usage/shared.ts +10 -0
- package/src/usage/zai.ts +247 -0
- package/src/usage.ts +183 -0
- package/src/utils/abort.ts +51 -0
- package/src/utils/anthropic-auth.ts +87 -0
- package/src/utils/discovery/antigravity.ts +261 -0
- package/src/utils/discovery/codex.ts +371 -0
- package/src/utils/discovery/cursor.ts +306 -0
- package/src/utils/discovery/gemini.ts +248 -0
- package/src/utils/discovery/index.ts +4 -0
- package/src/utils/discovery/openai-compatible.ts +224 -0
- package/src/utils/event-stream.ts +142 -0
- package/src/utils/fireworks-model-id.ts +30 -0
- package/src/utils/foundry.ts +8 -0
- package/src/utils/h2-fetch.ts +60 -0
- package/src/utils/http-inspector.ts +176 -0
- package/src/utils/idle-iterator.ts +250 -0
- package/src/utils/json-parse.ts +148 -0
- package/src/utils/oauth/alibaba-coding-plan.ts +59 -0
- package/src/utils/oauth/anthropic.ts +200 -0
- package/src/utils/oauth/api-key-login.ts +87 -0
- package/src/utils/oauth/api-key-validation.ts +92 -0
- package/src/utils/oauth/callback-server.ts +276 -0
- package/src/utils/oauth/cerebras.ts +16 -0
- package/src/utils/oauth/cloudflare-ai-gateway.ts +48 -0
- package/src/utils/oauth/cursor.ts +157 -0
- package/src/utils/oauth/deepseek.ts +53 -0
- package/src/utils/oauth/firepass.ts +24 -0
- package/src/utils/oauth/fireworks.ts +15 -0
- package/src/utils/oauth/github-copilot.ts +362 -0
- package/src/utils/oauth/gitlab-duo.ts +123 -0
- package/src/utils/oauth/google-antigravity.ts +200 -0
- package/src/utils/oauth/google-gemini-cli.ts +256 -0
- package/src/utils/oauth/google-oauth-shared.ts +110 -0
- package/src/utils/oauth/huggingface.ts +62 -0
- package/src/utils/oauth/index.ts +444 -0
- package/src/utils/oauth/kagi.ts +47 -0
- package/src/utils/oauth/kilo.ts +87 -0
- package/src/utils/oauth/kimi.ts +254 -0
- package/src/utils/oauth/litellm.ts +47 -0
- package/src/utils/oauth/lm-studio.ts +38 -0
- package/src/utils/oauth/minimax-code.ts +78 -0
- package/src/utils/oauth/moonshot.ts +16 -0
- package/src/utils/oauth/nanogpt.ts +15 -0
- package/src/utils/oauth/nvidia.ts +70 -0
- package/src/utils/oauth/oauth.html +199 -0
- package/src/utils/oauth/ollama-cloud.ts +28 -0
- package/src/utils/oauth/ollama.ts +47 -0
- package/src/utils/oauth/openai-codex.ts +299 -0
- package/src/utils/oauth/opencode.ts +49 -0
- package/src/utils/oauth/parallel.ts +46 -0
- package/src/utils/oauth/perplexity.ts +206 -0
- package/src/utils/oauth/pkce.ts +18 -0
- package/src/utils/oauth/qianfan.ts +58 -0
- package/src/utils/oauth/qwen-portal.ts +60 -0
- package/src/utils/oauth/synthetic.ts +16 -0
- package/src/utils/oauth/tavily.ts +46 -0
- package/src/utils/oauth/together.ts +16 -0
- package/src/utils/oauth/types.ts +94 -0
- package/src/utils/oauth/venice.ts +59 -0
- package/src/utils/oauth/vercel-ai-gateway.ts +47 -0
- package/src/utils/oauth/vllm.ts +40 -0
- package/src/utils/oauth/xiaomi.ts +137 -0
- package/src/utils/oauth/zai.ts +60 -0
- package/src/utils/oauth/zenmux.ts +15 -0
- package/src/utils/overflow.ts +137 -0
- package/src/utils/parse-bind.ts +54 -0
- package/src/utils/provider-response.ts +30 -0
- package/src/utils/retry-after.ts +110 -0
- package/src/utils/retry.ts +54 -0
- package/src/utils/schema/CONSTRAINTS.md +164 -0
- package/src/utils/schema/adapt.ts +36 -0
- package/src/utils/schema/compatibility.ts +435 -0
- package/src/utils/schema/dereference.ts +98 -0
- package/src/utils/schema/draft.ts +341 -0
- package/src/utils/schema/equality.ts +97 -0
- package/src/utils/schema/fields.ts +190 -0
- package/src/utils/schema/index.ts +13 -0
- package/src/utils/schema/json-schema-validator.ts +577 -0
- package/src/utils/schema/meta-validator.ts +167 -0
- package/src/utils/schema/normalize.ts +1588 -0
- package/src/utils/schema/spill.ts +43 -0
- package/src/utils/schema/stamps.ts +97 -0
- package/src/utils/schema/types.ts +11 -0
- package/src/utils/schema/wire.ts +213 -0
- package/src/utils/schema/zod-decontaminate.ts +331 -0
- package/src/utils/sse-debug.ts +289 -0
- package/src/utils/tool-call-healing.ts +271 -0
- package/src/utils/tool-choice.ts +99 -0
- package/src/utils/validation.ts +1019 -0
- package/src/utils.ts +166 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire types shared between the auth-broker server and clients.
|
|
3
|
+
*
|
|
4
|
+
* The broker holds OAuth refresh tokens and exposes a redacted snapshot;
|
|
5
|
+
* clients use `access` tokens directly and call back to the broker when a
|
|
6
|
+
* credential expires or a 401 surfaces on a supposedly-fresh credential.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { AuthCredential, AuthCredentialSnapshot, AuthCredentialSnapshotEntry } from "../auth-storage";
|
|
10
|
+
import type { UsageReport } from "../usage";
|
|
11
|
+
|
|
12
|
+
/** GET /v1/healthz response body. */
|
|
13
|
+
export interface HealthzResponse {
|
|
14
|
+
ok: boolean;
|
|
15
|
+
version?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface RefresherSchedule {
|
|
19
|
+
enabled: boolean;
|
|
20
|
+
intervalMs: number;
|
|
21
|
+
skewMs: number;
|
|
22
|
+
nextSweepInMs: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type SnapshotEntry = AuthCredentialSnapshotEntry & {
|
|
26
|
+
rotatesInMs: number | null;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/** GET /v1/snapshot response body. */
|
|
30
|
+
export interface SnapshotResponse extends Omit<AuthCredentialSnapshot, "credentials"> {
|
|
31
|
+
serverNowMs: number;
|
|
32
|
+
refresher: RefresherSchedule;
|
|
33
|
+
credentials: SnapshotEntry[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** GET /v1/usage response body — matches the local `AuthStorage.fetchUsageReports` shape. */
|
|
37
|
+
export interface UsageResponse {
|
|
38
|
+
generatedAt: number;
|
|
39
|
+
reports: UsageReport[];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** POST /v1/credential/:id/refresh response body. */
|
|
43
|
+
export interface CredentialRefreshResponse {
|
|
44
|
+
entry: AuthCredentialSnapshotEntry;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** POST /v1/credential/:id/disable request body. */
|
|
48
|
+
export interface CredentialDisableRequest {
|
|
49
|
+
cause: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** POST /v1/credential/:id/disable response body. */
|
|
53
|
+
export interface CredentialDisableResponse {
|
|
54
|
+
ok: boolean;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* POST /v1/credential request body. The OAuth `refresh` must be the *real*
|
|
59
|
+
* refresh token (not the sentinel) — the broker is the canonical writer.
|
|
60
|
+
*/
|
|
61
|
+
export interface CredentialUploadRequest {
|
|
62
|
+
provider: string;
|
|
63
|
+
credential: AuthCredential;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** POST /v1/credential response body — redacted snapshot of the provider's rows after upsert. */
|
|
67
|
+
export interface CredentialUploadResponse {
|
|
68
|
+
entries: AuthCredentialSnapshotEntry[];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* SSE event kinds emitted on `GET /v1/snapshot/stream`. The same value is set
|
|
73
|
+
* as the SSE `event:` name (load-bearing for clients) **and** embedded as a
|
|
74
|
+
* `kind` field inside the JSON body so a Zod discriminated union can validate
|
|
75
|
+
* the payload without consulting the line metadata.
|
|
76
|
+
*/
|
|
77
|
+
export type SnapshotStreamEventKind = "snapshot" | "entry" | "removed";
|
|
78
|
+
|
|
79
|
+
/** Initial frame emitted on connect — the full {@link SnapshotResponse}. */
|
|
80
|
+
export interface SnapshotStreamSnapshotEvent extends SnapshotResponse {
|
|
81
|
+
kind: "snapshot";
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Single credential added/changed (upsert or refresh). */
|
|
85
|
+
export interface SnapshotStreamEntryEvent {
|
|
86
|
+
kind: "entry";
|
|
87
|
+
generation: number;
|
|
88
|
+
serverNowMs: number;
|
|
89
|
+
refresher: RefresherSchedule;
|
|
90
|
+
entry: SnapshotEntry;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Single credential disabled/deleted. */
|
|
94
|
+
export interface SnapshotStreamRemovedEvent {
|
|
95
|
+
kind: "removed";
|
|
96
|
+
generation: number;
|
|
97
|
+
serverNowMs: number;
|
|
98
|
+
refresher: RefresherSchedule;
|
|
99
|
+
id: number;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Discriminated union of every event the snapshot stream emits. */
|
|
103
|
+
export type SnapshotStreamEvent = SnapshotStreamSnapshotEvent | SnapshotStreamEntryEvent | SnapshotStreamRemovedEvent;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Default bearer-protected route prefix. The broker exposes `/v1/healthz`
|
|
107
|
+
* unauthenticated for liveness probes; everything else requires a bearer.
|
|
108
|
+
*/
|
|
109
|
+
export const AUTH_BROKER_API_PREFIX = "/v1";
|
|
110
|
+
|
|
111
|
+
/** Default port when none is configured. Loopback-only, no external exposure. */
|
|
112
|
+
export const DEFAULT_AUTH_BROKER_BIND = "127.0.0.1:8765";
|
|
113
|
+
|
|
114
|
+
/** Default broker→provider refresh skew. Refresh credentials this close to expiry. */
|
|
115
|
+
export const DEFAULT_REFRESH_SKEW_MS = 5 * 60_000;
|
|
116
|
+
|
|
117
|
+
/** Default broker refresh-loop cadence. */
|
|
118
|
+
export const DEFAULT_REFRESH_INTERVAL_MS = 60_000;
|
|
119
|
+
|
|
120
|
+
/** Keepalive cadence for `GET /v1/snapshot/stream` SSE comments. */
|
|
121
|
+
export const DEFAULT_STREAM_KEEPALIVE_MS = 20_000;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Bun.serve `idleTimeout` (seconds) used by the broker. Default Bun idle
|
|
125
|
+
* timeout (10s) would close long-lived SSE connections between keepalives.
|
|
126
|
+
*/
|
|
127
|
+
export const DEFAULT_SERVER_IDLE_TIMEOUT_S = 255;
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod schemas for the auth-broker wire protocol.
|
|
3
|
+
*
|
|
4
|
+
* Shared between the server (validates inbound request bodies) and the client
|
|
5
|
+
* (validates responses from the broker). Schemas mirror the TypeScript types
|
|
6
|
+
* in `./types.ts` 1:1; the types remain the source of truth for static typing,
|
|
7
|
+
* and `z.infer<typeof Schema>` is asserted-compatible with them where possible.
|
|
8
|
+
*
|
|
9
|
+
* Schemas use `.strict()` on objects with a closed set of fields so unknown
|
|
10
|
+
* keys are rejected — the previous implementation used a hand-rolled
|
|
11
|
+
* `hasOnlyFields` allowlist for the same effect.
|
|
12
|
+
*/
|
|
13
|
+
import * as z from "zod/v4";
|
|
14
|
+
import { REMOTE_REFRESH_SENTINEL } from "../auth-storage";
|
|
15
|
+
import { usageReportSchema } from "../usage";
|
|
16
|
+
|
|
17
|
+
// ─── Credential payloads ───────────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
/** Real OAuth credential (broker-side) — refresh token is the actual upstream value. */
|
|
20
|
+
export const oauthCredentialSchema = z
|
|
21
|
+
.object({
|
|
22
|
+
type: z.literal("oauth"),
|
|
23
|
+
refresh: z
|
|
24
|
+
.string()
|
|
25
|
+
.min(1)
|
|
26
|
+
// Reject the sentinel literal on writes: if a client somehow round-trips
|
|
27
|
+
// a snapshot back into POST /v1/credential, accepting the sentinel as a
|
|
28
|
+
// real refresh token would silently break that credential's refresh
|
|
29
|
+
// forever (the broker would store `"__remote__"` and try to use it as
|
|
30
|
+
// the upstream refresh token).
|
|
31
|
+
.refine(value => value !== REMOTE_REFRESH_SENTINEL, {
|
|
32
|
+
message: `refresh token must not equal the remote sentinel (${REMOTE_REFRESH_SENTINEL})`,
|
|
33
|
+
}),
|
|
34
|
+
access: z.string().min(1),
|
|
35
|
+
expires: z.number(),
|
|
36
|
+
enterpriseUrl: z.string().optional(),
|
|
37
|
+
projectId: z.string().optional(),
|
|
38
|
+
email: z.string().optional(),
|
|
39
|
+
accountId: z.string().optional(),
|
|
40
|
+
})
|
|
41
|
+
.strict();
|
|
42
|
+
|
|
43
|
+
/** OAuth credential as it appears in broker snapshots — refresh replaced with sentinel. */
|
|
44
|
+
export const remoteOauthCredentialSchema = oauthCredentialSchema.extend({
|
|
45
|
+
refresh: z.literal(REMOTE_REFRESH_SENTINEL),
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
export const apiKeyCredentialSchema = z
|
|
49
|
+
.object({
|
|
50
|
+
type: z.literal("api_key"),
|
|
51
|
+
key: z.string().min(1),
|
|
52
|
+
})
|
|
53
|
+
.strict();
|
|
54
|
+
|
|
55
|
+
/** Discriminated union accepted on POST /v1/credential (writes). */
|
|
56
|
+
export const writableAuthCredentialSchema = z.discriminatedUnion("type", [
|
|
57
|
+
oauthCredentialSchema,
|
|
58
|
+
apiKeyCredentialSchema,
|
|
59
|
+
]);
|
|
60
|
+
|
|
61
|
+
/** Discriminated union returned in snapshots (refresh is sentinel for OAuth). */
|
|
62
|
+
export const snapshotCredentialSchema = z.discriminatedUnion("type", [
|
|
63
|
+
remoteOauthCredentialSchema,
|
|
64
|
+
apiKeyCredentialSchema,
|
|
65
|
+
]);
|
|
66
|
+
|
|
67
|
+
// ─── Snapshot ──────────────────────────────────────────────────────────────
|
|
68
|
+
|
|
69
|
+
export const credentialSnapshotEntrySchema = z
|
|
70
|
+
.object({
|
|
71
|
+
id: z.number().int(),
|
|
72
|
+
provider: z.string().min(1),
|
|
73
|
+
credential: snapshotCredentialSchema,
|
|
74
|
+
identityKey: z.string().nullable(),
|
|
75
|
+
})
|
|
76
|
+
.strict();
|
|
77
|
+
|
|
78
|
+
export const snapshotEntrySchema = credentialSnapshotEntrySchema
|
|
79
|
+
.extend({
|
|
80
|
+
rotatesInMs: z.number().nullable(),
|
|
81
|
+
})
|
|
82
|
+
.strict();
|
|
83
|
+
|
|
84
|
+
export const refresherScheduleSchema = z
|
|
85
|
+
.object({
|
|
86
|
+
enabled: z.boolean(),
|
|
87
|
+
intervalMs: z.number(),
|
|
88
|
+
skewMs: z.number(),
|
|
89
|
+
nextSweepInMs: z.number(),
|
|
90
|
+
})
|
|
91
|
+
.strict();
|
|
92
|
+
|
|
93
|
+
export const snapshotResponseSchema = z
|
|
94
|
+
.object({
|
|
95
|
+
generation: z.number().int(),
|
|
96
|
+
generatedAt: z.number(),
|
|
97
|
+
serverNowMs: z.number(),
|
|
98
|
+
refresher: refresherScheduleSchema,
|
|
99
|
+
credentials: z.array(snapshotEntrySchema),
|
|
100
|
+
})
|
|
101
|
+
.strict();
|
|
102
|
+
|
|
103
|
+
// ─── Snapshot stream (SSE) ────────────────────────────────────────────────
|
|
104
|
+
|
|
105
|
+
/** First frame on connect — full snapshot embedded inline with a `kind` tag. */
|
|
106
|
+
export const snapshotStreamSnapshotEventSchema = snapshotResponseSchema
|
|
107
|
+
.extend({
|
|
108
|
+
kind: z.literal("snapshot"),
|
|
109
|
+
})
|
|
110
|
+
.strict();
|
|
111
|
+
|
|
112
|
+
/** Per-credential upsert/refresh delta. */
|
|
113
|
+
export const snapshotStreamEntryEventSchema = z
|
|
114
|
+
.object({
|
|
115
|
+
kind: z.literal("entry"),
|
|
116
|
+
generation: z.number().int(),
|
|
117
|
+
serverNowMs: z.number(),
|
|
118
|
+
refresher: refresherScheduleSchema,
|
|
119
|
+
entry: snapshotEntrySchema,
|
|
120
|
+
})
|
|
121
|
+
.strict();
|
|
122
|
+
|
|
123
|
+
/** Per-credential delete delta. */
|
|
124
|
+
export const snapshotStreamRemovedEventSchema = z
|
|
125
|
+
.object({
|
|
126
|
+
kind: z.literal("removed"),
|
|
127
|
+
generation: z.number().int(),
|
|
128
|
+
serverNowMs: z.number(),
|
|
129
|
+
refresher: refresherScheduleSchema,
|
|
130
|
+
id: z.number().int(),
|
|
131
|
+
})
|
|
132
|
+
.strict();
|
|
133
|
+
|
|
134
|
+
/** Discriminated union over every event frame the snapshot stream emits. */
|
|
135
|
+
export const snapshotStreamEventSchema = z.discriminatedUnion("kind", [
|
|
136
|
+
snapshotStreamSnapshotEventSchema,
|
|
137
|
+
snapshotStreamEntryEventSchema,
|
|
138
|
+
snapshotStreamRemovedEventSchema,
|
|
139
|
+
]);
|
|
140
|
+
|
|
141
|
+
// ─── Healthz ────────────────────────────────────────────────────────────────
|
|
142
|
+
|
|
143
|
+
export const healthzResponseSchema = z
|
|
144
|
+
.object({
|
|
145
|
+
ok: z.boolean(),
|
|
146
|
+
version: z.string().optional(),
|
|
147
|
+
})
|
|
148
|
+
.strict();
|
|
149
|
+
|
|
150
|
+
// ─── Usage ─────────────────────────────────────────────────────────────────
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Broker `/v1/usage` response. Reports are full {@link UsageReport}s minus the
|
|
154
|
+
* heavy provider-specific `raw` field (the server strips it before send) — we
|
|
155
|
+
* keep `raw` optional in the underlying schema so a misconfigured broker that
|
|
156
|
+
* forgot to strip still validates.
|
|
157
|
+
*/
|
|
158
|
+
export const usageResponseSchema = z
|
|
159
|
+
.object({
|
|
160
|
+
generatedAt: z.number(),
|
|
161
|
+
reports: z.array(usageReportSchema),
|
|
162
|
+
})
|
|
163
|
+
.strict();
|
|
164
|
+
|
|
165
|
+
// ─── Refresh ───────────────────────────────────────────────────────────────
|
|
166
|
+
|
|
167
|
+
export const credentialRefreshResponseSchema = z
|
|
168
|
+
.object({
|
|
169
|
+
entry: credentialSnapshotEntrySchema,
|
|
170
|
+
})
|
|
171
|
+
.strict();
|
|
172
|
+
|
|
173
|
+
// ─── Disable ───────────────────────────────────────────────────────────────
|
|
174
|
+
|
|
175
|
+
export const credentialDisableRequestSchema = z
|
|
176
|
+
.object({
|
|
177
|
+
cause: z.string().optional(),
|
|
178
|
+
})
|
|
179
|
+
.strict();
|
|
180
|
+
|
|
181
|
+
export const credentialDisableResponseSchema = z
|
|
182
|
+
.object({
|
|
183
|
+
ok: z.boolean(),
|
|
184
|
+
})
|
|
185
|
+
.strict();
|
|
186
|
+
|
|
187
|
+
// ─── Upload ────────────────────────────────────────────────────────────────
|
|
188
|
+
|
|
189
|
+
export const credentialUploadRequestSchema = z
|
|
190
|
+
.object({
|
|
191
|
+
provider: z.string().min(1),
|
|
192
|
+
credential: writableAuthCredentialSchema,
|
|
193
|
+
})
|
|
194
|
+
.strict();
|
|
195
|
+
|
|
196
|
+
export const credentialUploadResponseSchema = z
|
|
197
|
+
.object({
|
|
198
|
+
entries: z.array(credentialSnapshotEntrySchema),
|
|
199
|
+
})
|
|
200
|
+
.strict();
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared HTTP helpers for the auth-gateway routes.
|
|
3
|
+
*
|
|
4
|
+
* Centralized so we share the same JSON shape, auth check,
|
|
5
|
+
* and peer-resolution logic.
|
|
6
|
+
*/
|
|
7
|
+
import { timingSafeEqual as nodeTimingSafeEqual } from "node:crypto";
|
|
8
|
+
|
|
9
|
+
const JSON_HEADERS = {
|
|
10
|
+
"Content-Type": "application/json",
|
|
11
|
+
"X-Content-Type-Options": "nosniff",
|
|
12
|
+
} as const;
|
|
13
|
+
|
|
14
|
+
export function json(status: number, body: unknown): Response {
|
|
15
|
+
return new Response(JSON.stringify(body) ?? "null", {
|
|
16
|
+
status,
|
|
17
|
+
headers: JSON_HEADERS,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function resolvePeer(req: Request): string {
|
|
22
|
+
const fwd = req.headers.get("x-forwarded-for");
|
|
23
|
+
if (fwd) return fwd.split(",")[0].trim();
|
|
24
|
+
return req.headers.get("x-real-ip") ?? "unknown";
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Constant-time byte comparison. Falls back to a manual XOR accumulator if
|
|
29
|
+
* `node:crypto.timingSafeEqual` isn't available. Always processes every byte
|
|
30
|
+
* of the longer input so length itself doesn't leak via timing.
|
|
31
|
+
*/
|
|
32
|
+
export function timingSafeEqual(a: Uint8Array, b: Uint8Array): boolean {
|
|
33
|
+
if (a.length === b.length && typeof nodeTimingSafeEqual === "function") {
|
|
34
|
+
return nodeTimingSafeEqual(a, b);
|
|
35
|
+
}
|
|
36
|
+
const len = Math.max(a.length, b.length);
|
|
37
|
+
let diff = a.length ^ b.length;
|
|
38
|
+
for (let i = 0; i < len; i++) {
|
|
39
|
+
// Out-of-range reads return undefined → coerce to 0 via `| 0`.
|
|
40
|
+
const av = (i < a.length ? a[i] : 0) | 0;
|
|
41
|
+
const bv = (i < b.length ? b[i] : 0) | 0;
|
|
42
|
+
diff |= av ^ bv;
|
|
43
|
+
}
|
|
44
|
+
return diff === 0;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const TOKEN_ENCODER = new TextEncoder();
|
|
48
|
+
|
|
49
|
+
export function isAuthorized(req: Request, tokens: ReadonlySet<string>): boolean {
|
|
50
|
+
if (tokens.size === 0) return true;
|
|
51
|
+
const header = req.headers.get("authorization");
|
|
52
|
+
if (!header) return false;
|
|
53
|
+
const match = header.match(/^Bearer\s+(.+)$/i);
|
|
54
|
+
if (!match) return false;
|
|
55
|
+
const presented = TOKEN_ENCODER.encode(match[1].trim());
|
|
56
|
+
// Iterate every allowed token regardless of early hits so the result
|
|
57
|
+
// timing reflects the full set, not the position of the match.
|
|
58
|
+
let ok = false;
|
|
59
|
+
for (const tok of tokens) {
|
|
60
|
+
const expected = TOKEN_ENCODER.encode(tok);
|
|
61
|
+
if (timingSafeEqual(presented, expected)) ok = true;
|
|
62
|
+
}
|
|
63
|
+
return ok;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Allow-list of inbound request headers that the gateway captures and forwards
|
|
68
|
+
* to the underlying parsers (which decide whether to surface them to the
|
|
69
|
+
* provider). Case-insensitive; `x-stainless-` is a prefix match.
|
|
70
|
+
*/
|
|
71
|
+
const PASSTHROUGH_HEADER_NAMES: Record<string, true> = {
|
|
72
|
+
"anthropic-beta": true,
|
|
73
|
+
"anthropic-version": true,
|
|
74
|
+
"openai-organization": true,
|
|
75
|
+
"openai-project": true,
|
|
76
|
+
"openai-beta": true,
|
|
77
|
+
// OpenAI code backend / ChatGPT-OAuth backend headers (see OpenAI code provider/constants.ts).
|
|
78
|
+
// `session_id` and `conversation_id` thread the upstream session so prompt
|
|
79
|
+
// caching and per-conversation rate limiting work; `chatgpt-account-id` and
|
|
80
|
+
// `originator` identify the calling account and client surface.
|
|
81
|
+
"chatgpt-account-id": true,
|
|
82
|
+
originator: true,
|
|
83
|
+
session_id: true,
|
|
84
|
+
conversation_id: true,
|
|
85
|
+
// Vendor-neutral cache-identity headers. The gateway also reads these to
|
|
86
|
+
// populate `options.promptCacheKey` (see `resolvePromptCacheKey` below)
|
|
87
|
+
// so explicit client hints win over the derived fallback.
|
|
88
|
+
"x-prompt-cache-key": true,
|
|
89
|
+
"x-session-id": true,
|
|
90
|
+
"x-conversation-id": true,
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Extract allow-listed passthrough headers from an inbound request. Keys are
|
|
95
|
+
* lowercased; empty values are dropped. Called once per request in
|
|
96
|
+
* `handleFormatEndpoint`; parsers then read `options.headers`.
|
|
97
|
+
*/
|
|
98
|
+
export function captureRequestHeaders(headers: Headers): Record<string, string> {
|
|
99
|
+
const out: Record<string, string> = {};
|
|
100
|
+
headers.forEach((value, key) => {
|
|
101
|
+
if (!value) return;
|
|
102
|
+
const lower = key.toLowerCase();
|
|
103
|
+
if (PASSTHROUGH_HEADER_NAMES[lower] || lower.startsWith("x-stainless-")) {
|
|
104
|
+
out[lower] = value;
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
return out;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Priority order for resolving a client-supplied prompt-cache identity. The
|
|
112
|
+
* first non-empty value wins. When none are present, the gateway derives a
|
|
113
|
+
* stable UUID from the request's stable parts.
|
|
114
|
+
*/
|
|
115
|
+
const CACHE_KEY_HEADERS: readonly string[] = [
|
|
116
|
+
"x-prompt-cache-key",
|
|
117
|
+
"session_id",
|
|
118
|
+
"conversation_id",
|
|
119
|
+
"x-session-id",
|
|
120
|
+
"x-conversation-id",
|
|
121
|
+
];
|
|
122
|
+
|
|
123
|
+
function readBodyCacheKey(body: unknown): string | undefined {
|
|
124
|
+
if (body === null || typeof body !== "object") return undefined;
|
|
125
|
+
const root = body as Record<string, unknown>;
|
|
126
|
+
// Explicit body fields (OpenAI Responses / Chat).
|
|
127
|
+
const direct = root.prompt_cache_key;
|
|
128
|
+
if (typeof direct === "string" && direct.length > 0) return direct;
|
|
129
|
+
// Nested `metadata` (OpenAI code backend CLI / Anthropic clients that route a session
|
|
130
|
+
// identifier through the metadata bag).
|
|
131
|
+
const metadata = root.metadata;
|
|
132
|
+
if (metadata === null || typeof metadata !== "object") return undefined;
|
|
133
|
+
const meta = metadata as Record<string, unknown>;
|
|
134
|
+
for (const field of ["prompt_cache_key", "session_id", "conversation_id"] as const) {
|
|
135
|
+
const v = meta[field];
|
|
136
|
+
if (typeof v === "string" && v.length > 0) return v;
|
|
137
|
+
}
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Resolve a prompt-cache identity from inbound request body + headers.
|
|
143
|
+
* Order of precedence (first wins):
|
|
144
|
+
* 1. Body `prompt_cache_key`
|
|
145
|
+
* 2. Body `metadata.{prompt_cache_key,session_id,conversation_id}`
|
|
146
|
+
* 3. Header `x-prompt-cache-key`
|
|
147
|
+
* 4. Header `session_id` / `conversation_id` (OpenAI code backend / ChatGPT-OAuth surface)
|
|
148
|
+
* 5. Header `x-session-id` / `x-conversation-id` (common informal)
|
|
149
|
+
* Returns undefined when none present; the gateway then derives a stable
|
|
150
|
+
* UUID from the request's stable parts.
|
|
151
|
+
*/
|
|
152
|
+
export function resolvePromptCacheKey(body: unknown, headers?: Headers): string | undefined {
|
|
153
|
+
const fromBody = readBodyCacheKey(body);
|
|
154
|
+
if (fromBody) return fromBody;
|
|
155
|
+
if (!headers) return undefined;
|
|
156
|
+
for (const name of CACHE_KEY_HEADERS) {
|
|
157
|
+
const v = headers.get(name);
|
|
158
|
+
if (v && v.length > 0) return v;
|
|
159
|
+
}
|
|
160
|
+
return undefined;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const CORS_HEADERS: Record<string, string> = {
|
|
164
|
+
"Access-Control-Allow-Origin": "*",
|
|
165
|
+
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
|
|
166
|
+
"Access-Control-Allow-Headers":
|
|
167
|
+
"authorization, content-type, anthropic-version, anthropic-beta, openai-organization, openai-project, x-stainless-*, x-api-key",
|
|
168
|
+
"Access-Control-Max-Age": "86400",
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* CORS headers for the auth-gateway. Currently echoes a wildcard origin; the
|
|
173
|
+
* request is accepted so future tightening can mirror `Origin` without
|
|
174
|
+
* threading the request through every caller.
|
|
175
|
+
*/
|
|
176
|
+
export function corsHeaders(_req: Request): Record<string, string> {
|
|
177
|
+
return { ...CORS_HEADERS };
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Re-emit `response` with CORS headers merged. The original response body is
|
|
182
|
+
* passed through unchanged. Used by the gateway wrapper so every outbound
|
|
183
|
+
* format-endpoint response carries the same CORS surface as the preflight.
|
|
184
|
+
*/
|
|
185
|
+
export function withCors(response: Response, req: Request): Response {
|
|
186
|
+
const headers = new Headers(response.headers);
|
|
187
|
+
const cors = corsHeaders(req);
|
|
188
|
+
for (const k in cors) headers.set(k, cors[k]);
|
|
189
|
+
return new Response(response.body, {
|
|
190
|
+
status: response.status,
|
|
191
|
+
statusText: response.statusText,
|
|
192
|
+
headers,
|
|
193
|
+
});
|
|
194
|
+
}
|