lynkr 9.5.0 → 9.7.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.
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Auth-mode classifier — JS port of Headroom's `headroom/proxy/auth_mode.py`.
3
+ *
4
+ * Three modes:
5
+ *
6
+ * - 'payg' — Pay-as-you-go API key. Aggressive lossy compression OK.
7
+ * - 'oauth' — Bearer OAuth (Bedrock SigV4, Codex/Cursor JWT, Vertex
8
+ * ADC, etc.). Same mutation policy as PAYG — those
9
+ * providers don't fingerprint the request body for
10
+ * anti-abuse. NOT to be confused with subscription
11
+ * OAuth: see below.
12
+ * - 'subscription' — A UX-bound CLI/IDE session backed by a flat-fee
13
+ * subscription (Claude Pro/Max via Claude Code, Cursor
14
+ * logged in via Cursor's auth, GitHub Copilot CLI, etc.).
15
+ * Stealth mode: passthrough byte-for-byte, never mutate
16
+ * the system prompt or frozen-prefix messages.
17
+ *
18
+ * Decision precedence (most specific signal wins):
19
+ *
20
+ * 1. Subscription User-Agent prefix → 'subscription'.
21
+ * A `claude-code/2.1.195` UA tells us this is a subscription-bound
22
+ * client even if the token shape would otherwise look like PAYG.
23
+ * Anthropic anti-abuse fingerprints the *client*, not just the token.
24
+ *
25
+ * 2. `Authorization: Bearer sk-ant-oat-…` → 'oauth'.
26
+ * Claude Pro/Max OAuth Access Token, but not detected as a subscription
27
+ * CLI in step 1 (e.g., a custom script using the token). Still
28
+ * passthrough-prefer to be safe.
29
+ *
30
+ * 3. `Authorization: Bearer sk-ant-api…` or `Bearer sk-…` → 'payg'.
31
+ * Anthropic / OpenAI / generic API key.
32
+ *
33
+ * 4. `Authorization: Bearer <jwt>` (3 dot-separated segments) → 'oauth'.
34
+ * Codex / Cursor / Copilot OAuth JWT.
35
+ *
36
+ * 5. `Authorization` present but not `Bearer …` → 'oauth'.
37
+ * AWS SigV4 (`AWS4-HMAC-SHA256 …`) for Bedrock, etc.
38
+ *
39
+ * 6. `x-api-key` or `x-goog-api-key` header → 'payg'.
40
+ *
41
+ * 7. Default → 'payg' (the safe default: aggressive compression on a
42
+ * misclassified request just costs a re-run, not a revoked
43
+ * subscription).
44
+ *
45
+ * Pure function. No I/O. No side effects. Safe to call from the hot path.
46
+ *
47
+ * @module auth-mode
48
+ */
49
+
50
+ const SUBSCRIPTION_UA_PREFIXES = [
51
+ 'claude-cli/',
52
+ 'claude-code/',
53
+ 'codex-cli/',
54
+ 'cursor/',
55
+ 'claude-vscode/',
56
+ 'github-copilot/',
57
+ 'anthropic-cli/',
58
+ 'antigravity/',
59
+ ];
60
+
61
+ /**
62
+ * Case-insensitive header read, returning '' on miss.
63
+ */
64
+ function getHeader(headers, name) {
65
+ if (!headers) return '';
66
+ const lower = name.toLowerCase();
67
+ // Express lowercases header keys; check both forms defensively.
68
+ const v = headers[lower] ?? headers[name];
69
+ if (v == null) return '';
70
+ if (Array.isArray(v)) return String(v[0] || '');
71
+ return String(v);
72
+ }
73
+
74
+ /**
75
+ * Classify the auth mode of an inbound request from its headers.
76
+ *
77
+ * @param {object} headers - Request headers map (express req.headers, dict, etc.)
78
+ * @returns {'payg' | 'oauth' | 'subscription'}
79
+ */
80
+ function classifyAuthMode(headers) {
81
+ // 1. Subscription UA wins over token shape.
82
+ const ua = getHeader(headers, 'user-agent').toLowerCase();
83
+ if (ua) {
84
+ for (const prefix of SUBSCRIPTION_UA_PREFIXES) {
85
+ if (ua.includes(prefix)) return 'subscription';
86
+ }
87
+ }
88
+
89
+ // 2-5. Authorization header.
90
+ const auth = getHeader(headers, 'authorization');
91
+ if (auth.startsWith('Bearer ')) {
92
+ const token = auth.slice('Bearer '.length);
93
+ // Order matters: check OAuth Access Token prefix before generic sk-.
94
+ if (token.startsWith('sk-ant-oat')) return 'oauth';
95
+ if (token.startsWith('sk-ant-api') || token.startsWith('sk-')) return 'payg';
96
+ // JWT: header.payload.signature
97
+ if (token.split('.').length >= 3) return 'oauth';
98
+ // Unknown bearer shape — fall through to default.
99
+ } else if (auth) {
100
+ // Authorization present but not Bearer — most commonly AWS SigV4 for
101
+ // Bedrock, or Basic for a custom proxy chain. Treat as OAuth.
102
+ return 'oauth';
103
+ }
104
+
105
+ // 6. Vendor API-key headers.
106
+ if (getHeader(headers, 'x-api-key')) return 'payg';
107
+ if (getHeader(headers, 'x-goog-api-key')) return 'payg';
108
+
109
+ // 7. Default.
110
+ return 'payg';
111
+ }
112
+
113
+ module.exports = {
114
+ classifyAuthMode,
115
+ SUBSCRIPTION_UA_PREFIXES,
116
+ };