anurag008w commited on
Commit
b8014f2
·
unverified ·
1 Parent(s): db7749f

Add files via upload

Browse files
Files changed (1) hide show
  1. nvidia-key-rotator.cjs +185 -0
nvidia-key-rotator.cjs ADDED
@@ -0,0 +1,185 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use strict';
2
+
3
+ /**
4
+ * NVIDIA API key rotator for OpenClaw/HuggingClaw
5
+ * ------------------------------------------------
6
+ * - Supports comma-separated keys in NVIDIA_API_KEYS
7
+ * - Falls back to NVIDIA_API_KEY, then LLM_API_KEY
8
+ * - Rotates keys on every NVIDIA request
9
+ * - Patches fetch + http/https request so most callers are covered
10
+ */
11
+
12
+ const http = require('node:http');
13
+ const https = require('node:https');
14
+
15
+ const NVIDIA_HOST_RE = /(^|\.)((integrate\.api\.nvidia\.com)|(api\.nvidia\.com))$/i;
16
+
17
+ function normalizeKeys(input) {
18
+ return String(input || '')
19
+ .split(',')
20
+ .map((s) => s.trim())
21
+ .filter(Boolean);
22
+ }
23
+
24
+ const keys = Array.from(
25
+ new Set(
26
+ normalizeKeys(process.env.NVIDIA_API_KEYS)
27
+ .concat(normalizeKeys(process.env.NVIDIA_API_KEY))
28
+ .concat(normalizeKeys(process.env.LLM_API_KEY))
29
+ )
30
+ );
31
+
32
+ if (!keys.length) {
33
+ console.warn('[nvidia-key-rotator] No NVIDIA keys found');
34
+ }
35
+
36
+ let idx = 0;
37
+
38
+ function nextKey() {
39
+ if (!keys.length) return null;
40
+ const key = keys[idx % keys.length];
41
+ idx = (idx + 1) % keys.length;
42
+ return key;
43
+ }
44
+
45
+ function isNvidiaUrl(urlLike) {
46
+ try {
47
+ const u = typeof urlLike === 'string'
48
+ ? new URL(urlLike)
49
+ : urlLike instanceof URL
50
+ ? urlLike
51
+ : urlLike && typeof urlLike.url === 'string'
52
+ ? new URL(urlLike.url)
53
+ : null;
54
+
55
+ if (!u) return false;
56
+ return NVIDIA_HOST_RE.test(u.hostname);
57
+ } catch {
58
+ return false;
59
+ }
60
+ }
61
+
62
+ function setAuthHeader(headers, key) {
63
+ if (!key) return headers;
64
+
65
+ const authValue = `Bearer ${key}`;
66
+
67
+ // Headers instance
68
+ if (typeof Headers !== 'undefined' && headers instanceof Headers) {
69
+ headers.set('authorization', authValue);
70
+ return headers;
71
+ }
72
+
73
+ // Array of tuples
74
+ if (Array.isArray(headers)) {
75
+ const out = headers.filter(([k]) => String(k).toLowerCase() !== 'authorization');
76
+ out.push(['authorization', authValue]);
77
+ return out;
78
+ }
79
+
80
+ // Plain object
81
+ if (headers && typeof headers === 'object') {
82
+ return {
83
+ ...headers,
84
+ authorization: authValue,
85
+ };
86
+ }
87
+
88
+ return { authorization: authValue };
89
+ }
90
+
91
+ function patchFetch() {
92
+ if (typeof globalThis.fetch !== 'function') return;
93
+
94
+ const originalFetch = globalThis.fetch.bind(globalThis);
95
+
96
+ globalThis.fetch = async function patchedFetch(input, init = {}) {
97
+ try {
98
+ const urlLike =
99
+ typeof input === 'string' || input instanceof URL
100
+ ? input
101
+ : input && typeof input.url === 'string'
102
+ ? input.url
103
+ : null;
104
+
105
+ if (urlLike && isNvidiaUrl(urlLike)) {
106
+ const key = nextKey();
107
+ if (key) {
108
+ const headers = init.headers || (input && input.headers) || undefined;
109
+ const patchedHeaders = setAuthHeader(headers, key);
110
+
111
+ if (init && typeof init === 'object') {
112
+ init = { ...init, headers: patchedHeaders };
113
+ } else {
114
+ init = { headers: patchedHeaders };
115
+ }
116
+
117
+ if (input && typeof input === 'object' && !(input instanceof URL) && input.headers) {
118
+ try {
119
+ input = new Request(input, { headers: patchedHeaders });
120
+ } catch {
121
+ // ignore and let fetch handle original input
122
+ }
123
+ }
124
+ }
125
+ }
126
+ } catch (err) {
127
+ console.warn('[nvidia-key-rotator] fetch patch error:', err?.message || err);
128
+ }
129
+
130
+ return originalFetch(input, init);
131
+ };
132
+ }
133
+
134
+ function patchHttpModule(mod) {
135
+ const originalRequest = mod.request;
136
+
137
+ mod.request = function patchedRequest(...args) {
138
+ try {
139
+ let options = args[0];
140
+
141
+ const urlLike =
142
+ typeof options === 'string' || options instanceof URL
143
+ ? options
144
+ : options && typeof options === 'object' && typeof options.href === 'string'
145
+ ? options.href
146
+ : null;
147
+
148
+ if (urlLike && isNvidiaUrl(urlLike)) {
149
+ const key = nextKey();
150
+ if (key) {
151
+ if (typeof options === 'string' || options instanceof URL) {
152
+ const u = new URL(String(options));
153
+ u.username = '';
154
+ u.password = '';
155
+ args[0] = {
156
+ protocol: u.protocol,
157
+ hostname: u.hostname,
158
+ port: u.port,
159
+ path: `${u.pathname}${u.search}`,
160
+ headers: { authorization: `Bearer ${key}` },
161
+ };
162
+ } else if (options && typeof options === 'object') {
163
+ const headers = setAuthHeader(options.headers, key);
164
+ args[0] = {
165
+ ...options,
166
+ headers,
167
+ };
168
+ }
169
+ }
170
+ }
171
+ } catch (err) {
172
+ console.warn('[nvidia-key-rotator] http patch error:', err?.message || err);
173
+ }
174
+
175
+ return originalRequest.apply(mod, args);
176
+ };
177
+ }
178
+
179
+ patchFetch();
180
+ patchHttpModule(http);
181
+ patchHttpModule(https);
182
+
183
+ console.log(
184
+ `[nvidia-key-rotator] loaded (${keys.length} key${keys.length === 1 ? '' : 's'})`
185
+ );