@macpaw/ai-sdk 0.1.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/CHANGELOG.md +39 -0
- package/LICENSE +21 -0
- package/MIGRATION.md +52 -0
- package/README.md +272 -0
- package/dist/chunk-KGOVQRMH.js +287 -0
- package/dist/chunk-KGOVQRMH.js.map +1 -0
- package/dist/chunk-N26BDEG5.cjs +302 -0
- package/dist/chunk-N26BDEG5.cjs.map +1 -0
- package/dist/gateway-errors-DdgDIyQw.d.cts +181 -0
- package/dist/gateway-errors-DdgDIyQw.d.ts +181 -0
- package/dist/index.cjs +483 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +109 -0
- package/dist/index.d.ts +109 -0
- package/dist/index.js +438 -0
- package/dist/index.js.map +1 -0
- package/dist/nestjs/index.cjs +149 -0
- package/dist/nestjs/index.cjs.map +1 -0
- package/dist/nestjs/index.d.cts +117 -0
- package/dist/nestjs/index.d.ts +117 -0
- package/dist/nestjs/index.js +145 -0
- package/dist/nestjs/index.js.map +1 -0
- package/package.json +128 -0
- package/scripts/setup.mjs +90 -0
- package/templates/AGENTS.md +51 -0
- package/templates/CLAUDE.md +55 -0
- package/templates/cursor/skills/integrate-ai-gateway/SKILL.md +90 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
import { AuthError, parseErrorResponseFromResponse } from './chunk-KGOVQRMH.js';
|
|
2
|
+
export { AIGatewayError, AuthError, CreditsError, ErrorCode, GatewayApiCode, GatewayValidationError, ModelNotAllowedError, RateLimitError, isAIGatewayError, parseErrorResponse } from './chunk-KGOVQRMH.js';
|
|
3
|
+
import { createOpenAI } from '@ai-sdk/openai';
|
|
4
|
+
|
|
5
|
+
// src/gateway-config.ts
|
|
6
|
+
var DEFAULT_RETRY = {
|
|
7
|
+
maxAttempts: 3,
|
|
8
|
+
initialDelayMs: 1e3,
|
|
9
|
+
maxDelayMs: 3e4,
|
|
10
|
+
retryableStatuses: [429, 500, 502, 503, 504]
|
|
11
|
+
};
|
|
12
|
+
function normalizeRetryConfig(merged) {
|
|
13
|
+
const n = Math.floor(Number(merged.maxAttempts));
|
|
14
|
+
const maxAttempts = Number.isFinite(n) && n >= 1 ? n : DEFAULT_RETRY.maxAttempts;
|
|
15
|
+
return { ...merged, maxAttempts };
|
|
16
|
+
}
|
|
17
|
+
function resolveConfig(config) {
|
|
18
|
+
return {
|
|
19
|
+
baseURL: config.baseURL,
|
|
20
|
+
getAuthToken: config.getAuthToken,
|
|
21
|
+
retry: config.retry === false ? false : normalizeRetryConfig({ ...DEFAULT_RETRY, ...config.retry }),
|
|
22
|
+
middleware: [...config.middleware ?? []],
|
|
23
|
+
headers: config.headers,
|
|
24
|
+
timeout: config.timeout ?? 6e4,
|
|
25
|
+
fetchImpl: config.fetch
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
var DEFAULT_BASE_URLS = {
|
|
29
|
+
production: "https://api.macpaw.com/ai"
|
|
30
|
+
};
|
|
31
|
+
function resolveGatewayBaseURL(baseURL, env, consumerName) {
|
|
32
|
+
const resolved = baseURL ?? (env ? DEFAULT_BASE_URLS[env] : void 0);
|
|
33
|
+
if (!resolved) {
|
|
34
|
+
throw new Error(
|
|
35
|
+
`${consumerName} requires baseURL or env (production). For non-production environments, pass baseURL directly.`
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
return resolved;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// src/gateway-retry.ts
|
|
42
|
+
function delay(ms, signal) {
|
|
43
|
+
return new Promise((resolve, reject) => {
|
|
44
|
+
if (signal?.aborted) {
|
|
45
|
+
reject(signal.reason);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const timer = setTimeout(resolve, ms);
|
|
49
|
+
signal?.addEventListener(
|
|
50
|
+
"abort",
|
|
51
|
+
() => {
|
|
52
|
+
clearTimeout(timer);
|
|
53
|
+
reject(signal.reason);
|
|
54
|
+
},
|
|
55
|
+
{ once: true }
|
|
56
|
+
);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
function isRetryableStatus(status, retryableStatuses) {
|
|
60
|
+
return retryableStatuses.includes(status);
|
|
61
|
+
}
|
|
62
|
+
function addJitter(delayMs) {
|
|
63
|
+
const jitter = delayMs * 0.25 * Math.random();
|
|
64
|
+
return delayMs + jitter;
|
|
65
|
+
}
|
|
66
|
+
async function withRetry(fn, options) {
|
|
67
|
+
const { maxAttempts, initialDelayMs, maxDelayMs, retryableStatuses } = options.retryConfig;
|
|
68
|
+
let lastError;
|
|
69
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
70
|
+
try {
|
|
71
|
+
return await fn();
|
|
72
|
+
} catch (err) {
|
|
73
|
+
lastError = err;
|
|
74
|
+
if (attempt === maxAttempts) break;
|
|
75
|
+
const status = err?.statusCode;
|
|
76
|
+
const isRetryable = status != null ? isRetryableStatus(status, retryableStatuses) : options.isNetworkError?.(err) ?? false;
|
|
77
|
+
if (!isRetryable) throw err;
|
|
78
|
+
const retryAfterSeconds = err?.retryAfter;
|
|
79
|
+
let backoff;
|
|
80
|
+
if (retryAfterSeconds != null && retryAfterSeconds > 0) {
|
|
81
|
+
backoff = retryAfterSeconds * 1e3;
|
|
82
|
+
} else {
|
|
83
|
+
backoff = addJitter(Math.min(initialDelayMs * Math.pow(2, attempt - 1), maxDelayMs));
|
|
84
|
+
}
|
|
85
|
+
await delay(backoff, options.signal);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
throw lastError;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// src/gateway-request.ts
|
|
92
|
+
function anySignal(signals) {
|
|
93
|
+
const any = AbortSignal.any;
|
|
94
|
+
if (typeof any === "function") {
|
|
95
|
+
return any(signals);
|
|
96
|
+
}
|
|
97
|
+
const controller = new AbortController();
|
|
98
|
+
const handlers = [];
|
|
99
|
+
function cleanup() {
|
|
100
|
+
for (const [sig, handler] of handlers) sig.removeEventListener("abort", handler);
|
|
101
|
+
handlers.length = 0;
|
|
102
|
+
}
|
|
103
|
+
for (const signal of signals) {
|
|
104
|
+
if (signal.aborted) {
|
|
105
|
+
controller.abort(signal.reason);
|
|
106
|
+
return controller.signal;
|
|
107
|
+
}
|
|
108
|
+
const handler = () => {
|
|
109
|
+
cleanup();
|
|
110
|
+
controller.abort(signal.reason);
|
|
111
|
+
};
|
|
112
|
+
handlers.push([signal, handler]);
|
|
113
|
+
signal.addEventListener("abort", handler, { once: true });
|
|
114
|
+
}
|
|
115
|
+
controller.signal.addEventListener("abort", cleanup, { once: true });
|
|
116
|
+
return controller.signal;
|
|
117
|
+
}
|
|
118
|
+
var _counter = 0;
|
|
119
|
+
function generateRequestId(prefix = "sdk") {
|
|
120
|
+
if (typeof globalThis.crypto?.randomUUID === "function") {
|
|
121
|
+
return `${prefix}-${globalThis.crypto.randomUUID()}`;
|
|
122
|
+
}
|
|
123
|
+
const timestamp = Date.now().toString(36);
|
|
124
|
+
const count = (_counter++).toString(36);
|
|
125
|
+
const random = Math.random().toString(36).slice(2, 8);
|
|
126
|
+
return `${prefix}-${timestamp}-${count}-${random}`;
|
|
127
|
+
}
|
|
128
|
+
function hasHeaderCaseInsensitive(headers, name) {
|
|
129
|
+
const lower = name.toLowerCase();
|
|
130
|
+
return Object.keys(headers).some((k) => k.toLowerCase() === lower);
|
|
131
|
+
}
|
|
132
|
+
function shouldAutoSetJsonContentType(body, headers) {
|
|
133
|
+
if (body == null || hasHeaderCaseInsensitive(headers, "content-type")) return false;
|
|
134
|
+
const isFormData = typeof FormData !== "undefined" && body instanceof FormData;
|
|
135
|
+
const isBlob = typeof Blob !== "undefined" && body instanceof Blob;
|
|
136
|
+
return !isFormData && !isBlob;
|
|
137
|
+
}
|
|
138
|
+
var NODE_NETWORK_CODES = /* @__PURE__ */ new Set([
|
|
139
|
+
"ECONNREFUSED",
|
|
140
|
+
"ECONNRESET",
|
|
141
|
+
"ENOTFOUND",
|
|
142
|
+
"EPIPE",
|
|
143
|
+
"ETIMEDOUT",
|
|
144
|
+
"ENETUNREACH",
|
|
145
|
+
"EAI_AGAIN",
|
|
146
|
+
"UND_ERR_CONNECT_TIMEOUT"
|
|
147
|
+
]);
|
|
148
|
+
var FETCH_NETWORK_TYPEERROR_HINTS = [
|
|
149
|
+
"failed to fetch",
|
|
150
|
+
"fetch failed",
|
|
151
|
+
"load failed",
|
|
152
|
+
"networkerror",
|
|
153
|
+
"network error when attempting to fetch"
|
|
154
|
+
];
|
|
155
|
+
function hasRetryableNodeErrorCode(err) {
|
|
156
|
+
let cur = err;
|
|
157
|
+
for (let depth = 0; depth < 5 && cur != null; depth++) {
|
|
158
|
+
const code = cur?.code;
|
|
159
|
+
if (typeof code === "string" && NODE_NETWORK_CODES.has(code)) return true;
|
|
160
|
+
cur = cur instanceof Error && cur.cause !== void 0 ? cur.cause : void 0;
|
|
161
|
+
}
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
function isFetchFailureTypeError(err) {
|
|
165
|
+
if (!(err instanceof TypeError)) return false;
|
|
166
|
+
const msg = String(err.message).toLowerCase();
|
|
167
|
+
return FETCH_NETWORK_TYPEERROR_HINTS.some((hint) => msg.includes(hint));
|
|
168
|
+
}
|
|
169
|
+
function isNetworkError(err) {
|
|
170
|
+
return hasRetryableNodeErrorCode(err) || isFetchFailureTypeError(err);
|
|
171
|
+
}
|
|
172
|
+
async function executeFetch(fetchImpl, requestConfig) {
|
|
173
|
+
const impl = fetchImpl ?? globalThis.fetch;
|
|
174
|
+
if (typeof impl === "undefined") {
|
|
175
|
+
throw new Error(
|
|
176
|
+
"@macpaw/ai-sdk requires a global `fetch` implementation. Use Node.js 18+ or install a polyfill like `undici`."
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
return impl(requestConfig.url, {
|
|
180
|
+
method: requestConfig.method,
|
|
181
|
+
headers: requestConfig.headers,
|
|
182
|
+
body: requestConfig.body,
|
|
183
|
+
signal: requestConfig.signal
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
async function executeRequestPipeline(config, request, behavior) {
|
|
187
|
+
const b = {
|
|
188
|
+
includeConfigHeaders: behavior?.includeConfigHeaders ?? true,
|
|
189
|
+
includeAuth: behavior?.includeAuth ?? true,
|
|
190
|
+
includeRequestId: behavior?.includeRequestId ?? true,
|
|
191
|
+
normalizeErrors: behavior?.normalizeErrors ?? true,
|
|
192
|
+
allowAuthRetry: behavior?.allowAuthRetry ?? true,
|
|
193
|
+
requestIdPrefix: behavior?.requestIdPrefix
|
|
194
|
+
};
|
|
195
|
+
return executeWithAuth(config, request, b, false);
|
|
196
|
+
}
|
|
197
|
+
async function executeWithAuth(config, request, behavior, isTokenRetry) {
|
|
198
|
+
try {
|
|
199
|
+
return await executeRequest(config, request, behavior, isTokenRetry);
|
|
200
|
+
} catch (err) {
|
|
201
|
+
if (behavior.allowAuthRetry && !isTokenRetry && err instanceof AuthError) {
|
|
202
|
+
if (typeof ReadableStream !== "undefined" && request.body instanceof ReadableStream) {
|
|
203
|
+
throw err;
|
|
204
|
+
}
|
|
205
|
+
return executeWithAuth(config, request, behavior, true);
|
|
206
|
+
}
|
|
207
|
+
throw err;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
async function executeRequest(config, request, behavior, forceRefreshToken) {
|
|
211
|
+
const headers = {
|
|
212
|
+
...behavior.includeConfigHeaders ? config.headers : void 0,
|
|
213
|
+
...request.headers
|
|
214
|
+
};
|
|
215
|
+
if (shouldAutoSetJsonContentType(request.body, headers)) {
|
|
216
|
+
headers["Content-Type"] = "application/json";
|
|
217
|
+
}
|
|
218
|
+
if (behavior.includeRequestId && !hasHeaderCaseInsensitive(headers, "x-request-id")) {
|
|
219
|
+
headers["X-Request-ID"] = generateRequestId(behavior.requestIdPrefix);
|
|
220
|
+
}
|
|
221
|
+
const timeoutMs = config.timeout;
|
|
222
|
+
const userSignal = request.signal;
|
|
223
|
+
async function doRequest() {
|
|
224
|
+
const timeoutController = new AbortController();
|
|
225
|
+
const timeoutId = setTimeout(
|
|
226
|
+
() => timeoutController.abort(new Error(`Request timed out after ${timeoutMs}ms`)),
|
|
227
|
+
timeoutMs
|
|
228
|
+
);
|
|
229
|
+
const signal = userSignal ? anySignal([userSignal, timeoutController.signal]) : timeoutController.signal;
|
|
230
|
+
const requestConfig = {
|
|
231
|
+
url: request.url,
|
|
232
|
+
method: request.method,
|
|
233
|
+
headers: { ...headers },
|
|
234
|
+
body: request.body,
|
|
235
|
+
signal
|
|
236
|
+
};
|
|
237
|
+
const { middleware } = config;
|
|
238
|
+
let index = 0;
|
|
239
|
+
const next = async (currentRequest) => {
|
|
240
|
+
if (index < middleware.length) {
|
|
241
|
+
const middlewareItem = middleware[index++];
|
|
242
|
+
return middlewareItem(currentRequest, next);
|
|
243
|
+
}
|
|
244
|
+
const finalHeaders = { ...currentRequest.headers };
|
|
245
|
+
if (behavior.includeAuth) {
|
|
246
|
+
const token = await config.getAuthToken(forceRefreshToken);
|
|
247
|
+
if (token) {
|
|
248
|
+
finalHeaders.Authorization = `Bearer ${token}`;
|
|
249
|
+
} else {
|
|
250
|
+
for (const key of Object.keys(finalHeaders)) {
|
|
251
|
+
if (key.toLowerCase() === "authorization") delete finalHeaders[key];
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return executeFetch(config.fetchImpl, { ...currentRequest, headers: finalHeaders });
|
|
256
|
+
};
|
|
257
|
+
try {
|
|
258
|
+
const response = await next(requestConfig);
|
|
259
|
+
if (!response.ok) {
|
|
260
|
+
const retryableStatuses = config.retry !== false ? config.retry.retryableStatuses : [];
|
|
261
|
+
const isTransportCritical = behavior.allowAuthRetry && response.status === 401 || config.retry !== false && retryableStatuses.includes(response.status);
|
|
262
|
+
if (behavior.normalizeErrors || isTransportCritical) {
|
|
263
|
+
await parseErrorResponseFromResponse(response);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return response;
|
|
267
|
+
} finally {
|
|
268
|
+
clearTimeout(timeoutId);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
if (config.retry) {
|
|
272
|
+
return withRetry(doRequest, {
|
|
273
|
+
retryConfig: config.retry,
|
|
274
|
+
signal: userSignal,
|
|
275
|
+
isNetworkError
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
return doRequest();
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// src/gateway-fetch.ts
|
|
282
|
+
function resolveRequestUrl(input) {
|
|
283
|
+
if (typeof input === "string") return input;
|
|
284
|
+
if (input instanceof URL) return input.href;
|
|
285
|
+
return input.url;
|
|
286
|
+
}
|
|
287
|
+
function stripPlaceholderAuthorization(headers, placeholder) {
|
|
288
|
+
const auth = headers.get("authorization");
|
|
289
|
+
if (auth === `Bearer ${placeholder}`) {
|
|
290
|
+
headers.delete("authorization");
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
function headersToRecord(headers) {
|
|
294
|
+
const record = {};
|
|
295
|
+
for (const [key, value] of headers.entries()) {
|
|
296
|
+
record[key] = value;
|
|
297
|
+
}
|
|
298
|
+
return record;
|
|
299
|
+
}
|
|
300
|
+
function joinBaseUrl(baseURL, path) {
|
|
301
|
+
return `${baseURL}${path.startsWith("/") ? "" : "/"}${path}`;
|
|
302
|
+
}
|
|
303
|
+
function isGatewayUrl(url, gatewayBaseUrl) {
|
|
304
|
+
const gatewayPath = gatewayBaseUrl.pathname.replace(/\/$/, "");
|
|
305
|
+
const requestPath = url.pathname.replace(/\/$/, "");
|
|
306
|
+
return url.origin === gatewayBaseUrl.origin && (requestPath === gatewayPath || requestPath.startsWith(`${gatewayPath}/`));
|
|
307
|
+
}
|
|
308
|
+
var GATEWAY_PLACEHOLDER_API_KEY = "ai-gateway-auth-via-fetch";
|
|
309
|
+
function createGatewayFetch(options) {
|
|
310
|
+
const { baseURL, normalizeErrors = true } = options;
|
|
311
|
+
const base = baseURL.replace(/\/$/, "");
|
|
312
|
+
const gatewayBaseUrl = new URL(base);
|
|
313
|
+
const resolvedConfig = resolveConfig({ ...options, baseURL: base });
|
|
314
|
+
return async function gatewayFetch(input, init) {
|
|
315
|
+
const rawUrl = resolveRequestUrl(input);
|
|
316
|
+
const isAbsolute = rawUrl.startsWith("http://") || rawUrl.startsWith("https://");
|
|
317
|
+
const resolvedUrl = new URL(isAbsolute ? rawUrl : joinBaseUrl(base, rawUrl));
|
|
318
|
+
const isGatewayRequest = isGatewayUrl(resolvedUrl, gatewayBaseUrl);
|
|
319
|
+
const request = typeof Request !== "undefined" && input instanceof Request ? input : void 0;
|
|
320
|
+
const requestClone = request?.clone();
|
|
321
|
+
const headers = new Headers(requestClone?.headers);
|
|
322
|
+
if (init?.headers) {
|
|
323
|
+
for (const [key, value] of new Headers(init.headers).entries()) {
|
|
324
|
+
headers.set(key, value);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
if (!isGatewayRequest) {
|
|
328
|
+
stripPlaceholderAuthorization(headers, GATEWAY_PLACEHOLDER_API_KEY);
|
|
329
|
+
}
|
|
330
|
+
return executeRequestPipeline(
|
|
331
|
+
resolvedConfig,
|
|
332
|
+
{
|
|
333
|
+
url: resolvedUrl.toString(),
|
|
334
|
+
method: init?.method ?? requestClone?.method ?? "GET",
|
|
335
|
+
headers: headersToRecord(headers),
|
|
336
|
+
body: init?.body ?? requestClone?.body,
|
|
337
|
+
signal: init?.signal ?? requestClone?.signal
|
|
338
|
+
},
|
|
339
|
+
{
|
|
340
|
+
includeConfigHeaders: isGatewayRequest,
|
|
341
|
+
includeAuth: isGatewayRequest,
|
|
342
|
+
includeRequestId: isGatewayRequest,
|
|
343
|
+
normalizeErrors: isGatewayRequest && normalizeErrors,
|
|
344
|
+
allowAuthRetry: isGatewayRequest,
|
|
345
|
+
requestIdPrefix: "provider"
|
|
346
|
+
}
|
|
347
|
+
);
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// src/gateway-provider.ts
|
|
352
|
+
var DEFAULT_API_VERSION = "v1";
|
|
353
|
+
function createAIGatewayProvider(options) {
|
|
354
|
+
const baseURL = resolveGatewayBaseURL(options.baseURL, options.env, "AIGatewayProvider");
|
|
355
|
+
const customFetch = createGatewayFetch({ ...options, baseURL, normalizeErrors: options.normalizeErrors });
|
|
356
|
+
const openAI = options.createOpenAI ?? createOpenAI;
|
|
357
|
+
return openAI({
|
|
358
|
+
name: options.name,
|
|
359
|
+
organization: options.organization,
|
|
360
|
+
project: options.project,
|
|
361
|
+
baseURL: `${baseURL.replace(/\/$/, "")}/api/${DEFAULT_API_VERSION}`,
|
|
362
|
+
fetch: customFetch,
|
|
363
|
+
apiKey: GATEWAY_PLACEHOLDER_API_KEY
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
var GATEWAY_PROVIDERS = {
|
|
367
|
+
ANTHROPIC: "anthropic",
|
|
368
|
+
GOOGLE: "google",
|
|
369
|
+
XAI: "xai",
|
|
370
|
+
GROQ: "groq",
|
|
371
|
+
MISTRAL: "mistral",
|
|
372
|
+
AMAZON_BEDROCK: "amazon-bedrock",
|
|
373
|
+
AZURE: "azure",
|
|
374
|
+
COHERE: "cohere",
|
|
375
|
+
PERPLEXITY: "perplexity",
|
|
376
|
+
DEEPSEEK: "deepseek",
|
|
377
|
+
TOGETHERAI: "togetherai",
|
|
378
|
+
OPENAI_COMPATIBLE: "openai-compatible"
|
|
379
|
+
};
|
|
380
|
+
var GATEWAY_PROVIDER_DEFAULT_PREFIXES = {
|
|
381
|
+
[GATEWAY_PROVIDERS.ANTHROPIC]: "anthropic",
|
|
382
|
+
[GATEWAY_PROVIDERS.GOOGLE]: "google",
|
|
383
|
+
[GATEWAY_PROVIDERS.XAI]: "xai",
|
|
384
|
+
[GATEWAY_PROVIDERS.GROQ]: "groq",
|
|
385
|
+
[GATEWAY_PROVIDERS.MISTRAL]: "mistral",
|
|
386
|
+
[GATEWAY_PROVIDERS.AMAZON_BEDROCK]: "bedrock",
|
|
387
|
+
[GATEWAY_PROVIDERS.AZURE]: "azure",
|
|
388
|
+
[GATEWAY_PROVIDERS.COHERE]: "cohere",
|
|
389
|
+
[GATEWAY_PROVIDERS.PERPLEXITY]: "perplexity",
|
|
390
|
+
[GATEWAY_PROVIDERS.DEEPSEEK]: "deepseek",
|
|
391
|
+
[GATEWAY_PROVIDERS.TOGETHERAI]: "togetherai"
|
|
392
|
+
};
|
|
393
|
+
function prefixModelId(prefix, modelId) {
|
|
394
|
+
return modelId.includes("/") ? modelId : `${prefix}/${modelId}`;
|
|
395
|
+
}
|
|
396
|
+
function createPrefixedGatewayProvider(defaultPrefix, options) {
|
|
397
|
+
const { modelPrefix, ...providerOptions } = options;
|
|
398
|
+
const prefix = modelPrefix ?? defaultPrefix;
|
|
399
|
+
const provider = createAIGatewayProvider(providerOptions);
|
|
400
|
+
const wrapped = ((modelId) => provider(prefixModelId(prefix, modelId)));
|
|
401
|
+
return new Proxy(wrapped, {
|
|
402
|
+
apply(_target, _thisArg, args) {
|
|
403
|
+
const [modelId, ...rest] = args;
|
|
404
|
+
return provider(prefixModelId(prefix, modelId), ...rest);
|
|
405
|
+
},
|
|
406
|
+
get(_target, prop) {
|
|
407
|
+
const value = Reflect.get(provider, prop, provider);
|
|
408
|
+
if (typeof value === "function") {
|
|
409
|
+
return (...args) => {
|
|
410
|
+
if (typeof args[0] === "string") {
|
|
411
|
+
args[0] = prefixModelId(prefix, args[0]);
|
|
412
|
+
}
|
|
413
|
+
return value.apply(provider, args);
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
return value;
|
|
417
|
+
},
|
|
418
|
+
has(_target, prop) {
|
|
419
|
+
return prop in provider;
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
function createGatewayProvider(provider, options) {
|
|
424
|
+
if (provider === GATEWAY_PROVIDERS.OPENAI_COMPATIBLE) {
|
|
425
|
+
return createPrefixedGatewayProvider(
|
|
426
|
+
options.modelPrefix,
|
|
427
|
+
options
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
return createPrefixedGatewayProvider(
|
|
431
|
+
GATEWAY_PROVIDER_DEFAULT_PREFIXES[provider],
|
|
432
|
+
options
|
|
433
|
+
);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
export { GATEWAY_PLACEHOLDER_API_KEY, GATEWAY_PROVIDERS, createAIGatewayProvider, createGatewayFetch, createGatewayProvider };
|
|
437
|
+
//# sourceMappingURL=index.js.map
|
|
438
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/gateway-config.ts","../src/gateway-retry.ts","../src/gateway-request.ts","../src/gateway-fetch.ts","../src/gateway-provider.ts"],"names":["builtinCreateOpenAI"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Configuration types and resolver for the AI Gateway SDK.\n *\n * GatewayProviderSettings is the public API — 8 fields.\n * ResolvedConfig is the internal resolved form used by the request pipeline.\n */\n\n/**\n * Supported gateway environments.\n * Only 'production' is exposed — non-production setups use a direct `baseURL`\n * instead, keeping env-specific URL management out of this library.\n */\nexport type Environment = 'production';\n\nexport interface RetryConfig {\n /** Max number of attempts (including first). Default 3. */\n maxAttempts?: number;\n /** Initial delay in ms. Default 1000. */\n initialDelayMs?: number;\n /** Max delay in ms. Default 30000. */\n maxDelayMs?: number;\n /** Retry only on these status codes (and network errors). Default: 429, 5xx. */\n retryableStatuses?: number[];\n}\n\nexport const DEFAULT_RETRY: Required<RetryConfig> = {\n maxAttempts: 3,\n initialDelayMs: 1000,\n maxDelayMs: 30000,\n retryableStatuses: [429, 500, 502, 503, 504],\n};\n\n/** Coerces invalid `maxAttempts` (0, negative, NaN) to the default. */\nexport function normalizeRetryConfig(merged: Required<RetryConfig>): Required<RetryConfig> {\n const n = Math.floor(Number(merged.maxAttempts));\n const maxAttempts = Number.isFinite(n) && n >= 1 ? n : DEFAULT_RETRY.maxAttempts;\n return { ...merged, maxAttempts };\n}\n\nexport interface RequestConfig {\n url: string;\n method: string;\n headers: Record<string, string>;\n body?: RequestInit['body'];\n signal?: AbortSignal | undefined;\n}\n\nexport type Middleware = (\n config: RequestConfig,\n next: (config: RequestConfig) => Promise<Response>,\n) => Promise<Response>;\n\n/**\n * Configuration for AI Gateway providers and NestJS module.\n *\n * Exactly 8 fields — covers auth, routing, request behaviour and middleware.\n */\nexport interface GatewayProviderSettings {\n /** Gateway base URL. Required if env is not set. */\n baseURL?: string;\n /** 'production' uses the default MacPaw Gateway URL. */\n env?: Environment;\n /**\n * Returns Bearer token for auth.\n * Called with `forceRefresh=true` after 401 — provide a fresh token.\n */\n getAuthToken: (forceRefresh?: boolean) => Promise<string | null>;\n /** Extra headers sent with every request. Do not set Authorization here. */\n headers?: Record<string, string>;\n /** Retry policy. Set to false to disable. */\n retry?: RetryConfig | false;\n /** Request timeout in ms. Default: 60000. */\n timeout?: number;\n /** Request interceptors. Run in order before each request. */\n middleware?: Middleware[];\n /**\n * Custom fetch implementation.\n * Use for testing or low-level request customization.\n */\n fetch?: typeof fetch;\n}\n\n/** Internal resolved form — used only by the request pipeline. */\nexport interface ResolvedConfig {\n baseURL: string;\n getAuthToken: (forceRefresh?: boolean) => Promise<string | null>;\n /** Already normalized — all fields present, maxAttempts ≥ 1. */\n retry: Required<RetryConfig> | false;\n middleware: Middleware[];\n headers?: Record<string, string>;\n timeout: number;\n fetchImpl?: typeof fetch;\n}\n\nexport function resolveConfig(config: GatewayProviderSettings & { baseURL: string }): ResolvedConfig {\n return {\n baseURL: config.baseURL,\n getAuthToken: config.getAuthToken,\n retry: config.retry === false ? false : normalizeRetryConfig({ ...DEFAULT_RETRY, ...config.retry }),\n middleware: [...(config.middleware ?? [])],\n headers: config.headers,\n timeout: config.timeout ?? 60_000,\n fetchImpl: config.fetch,\n };\n}\n\n/** Default base URL for the production environment. */\nexport const DEFAULT_BASE_URLS: Record<Environment, string> = {\n production: 'https://api.macpaw.com/ai',\n};\n\nexport function resolveGatewayBaseURL(\n baseURL: string | undefined,\n env: Environment | undefined,\n consumerName: string,\n): string {\n const resolved = baseURL ?? (env ? DEFAULT_BASE_URLS[env] : undefined);\n if (!resolved) {\n throw new Error(\n `${consumerName} requires baseURL or env (production). For non-production environments, pass baseURL directly.`,\n );\n }\n return resolved;\n}\n","/**\n * Retry with exponential backoff + jitter.\n * Only retries on 429, 5xx and network errors; never on 4xx (401, 402, etc.).\n *\n * Jitter prevents thundering herd when many clients retry simultaneously.\n * Respects Retry-After metadata from 429 responses.\n */\n\nimport type { RetryConfig } from './gateway-config';\nimport type { AIGatewayError } from './gateway-errors';\n\nfunction delay(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(signal.reason);\n return;\n }\n const timer = setTimeout(resolve, ms);\n signal?.addEventListener(\n 'abort',\n () => {\n clearTimeout(timer);\n reject(signal.reason);\n },\n { once: true },\n );\n });\n}\n\nfunction isRetryableStatus(status: number, retryableStatuses: number[]): boolean {\n return retryableStatuses.includes(status);\n}\n\n/** Add random jitter: 0-25% of the base delay to avoid thundering herd */\nfunction addJitter(delayMs: number): number {\n const jitter = delayMs * 0.25 * Math.random();\n return delayMs + jitter;\n}\n\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n options: {\n /** Already-normalized config — all fields must be present. */\n retryConfig: Required<RetryConfig>;\n signal?: AbortSignal;\n isNetworkError?: (err: unknown) => boolean;\n },\n): Promise<T> {\n const { maxAttempts, initialDelayMs, maxDelayMs, retryableStatuses } = options.retryConfig;\n let lastError: unknown;\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n return await fn();\n } catch (err) {\n lastError = err;\n if (attempt === maxAttempts) break;\n const status = (err as { statusCode?: number })?.statusCode;\n const isRetryable =\n status != null ? isRetryableStatus(status, retryableStatuses) : (options.isNetworkError?.(err) ?? false);\n if (!isRetryable) throw err;\n\n const retryAfterSeconds = (err as AIGatewayError)?.retryAfter;\n let backoff: number;\n if (retryAfterSeconds != null && retryAfterSeconds > 0) {\n // Server-specified delay — use exactly, no jitter (contract compliance).\n backoff = retryAfterSeconds * 1000;\n } else {\n backoff = addJitter(Math.min(initialDelayMs * Math.pow(2, attempt - 1), maxDelayMs));\n }\n\n await delay(backoff, options.signal);\n }\n }\n throw lastError;\n}\n","/**\n * Shared request execution pipeline for the AI Gateway SDK.\n *\n * Handles: auth injection, Bearer token refresh on 401, middleware chain,\n * timeout, retry, and error normalization. Inlines abort, request-id,\n * and fetch transport as private helpers.\n */\n\nimport type { RequestConfig, ResolvedConfig } from './gateway-config';\nimport { AuthError, parseErrorResponseFromResponse } from './gateway-errors';\nimport { withRetry } from './gateway-retry';\n\n// ─── Private helpers ──────────────────────────────────────────────────────────\n\n/** Combine multiple AbortSignals — aborts when ANY fires. Uses native AbortSignal.any when available. */\nfunction anySignal(signals: AbortSignal[]): AbortSignal {\n const any = (AbortSignal as unknown as { any?: (signals: AbortSignal[]) => AbortSignal }).any;\n if (typeof any === 'function') {\n return any(signals);\n }\n const controller = new AbortController();\n const handlers: Array<[AbortSignal, () => void]> = [];\n function cleanup() {\n for (const [sig, handler] of handlers) sig.removeEventListener('abort', handler);\n handlers.length = 0;\n }\n for (const signal of signals) {\n if (signal.aborted) {\n controller.abort(signal.reason);\n return controller.signal;\n }\n const handler = () => {\n cleanup();\n controller.abort(signal.reason);\n };\n handlers.push([signal, handler]);\n signal.addEventListener('abort', handler, { once: true });\n }\n controller.signal.addEventListener('abort', cleanup, { once: true });\n return controller.signal;\n}\n\nlet _counter = 0;\n/** Generate a unique request ID for correlation. */\nfunction generateRequestId(prefix: string = 'sdk'): string {\n if (typeof globalThis.crypto?.randomUUID === 'function') {\n return `${prefix}-${globalThis.crypto.randomUUID()}`;\n }\n const timestamp = Date.now().toString(36);\n const count = (_counter++).toString(36);\n const random = Math.random().toString(36).slice(2, 8);\n return `${prefix}-${timestamp}-${count}-${random}`;\n}\n\n/** Case-insensitive header key lookup. */\nfunction hasHeaderCaseInsensitive(headers: Record<string, string>, name: string): boolean {\n const lower = name.toLowerCase();\n return Object.keys(headers).some((k) => k.toLowerCase() === lower);\n}\n\nfunction shouldAutoSetJsonContentType(body: RequestInit['body'], headers: Record<string, string>): boolean {\n if (body == null || hasHeaderCaseInsensitive(headers, 'content-type')) return false;\n const isFormData = typeof FormData !== 'undefined' && body instanceof FormData;\n const isBlob = typeof Blob !== 'undefined' && body instanceof Blob;\n return !isFormData && !isBlob;\n}\n\nfunction redactSensitiveHeaders(headers: Record<string, string>): Record<string, string> {\n const redacted: Record<string, string> = {};\n for (const [key, value] of Object.entries(headers)) {\n redacted[key] = key.toLowerCase() === 'authorization' ? '[REDACTED]' : value;\n }\n return redacted;\n}\n\nconst NODE_NETWORK_CODES = new Set([\n 'ECONNREFUSED',\n 'ECONNRESET',\n 'ENOTFOUND',\n 'EPIPE',\n 'ETIMEDOUT',\n 'ENETUNREACH',\n 'EAI_AGAIN',\n 'UND_ERR_CONNECT_TIMEOUT',\n]);\n\nconst FETCH_NETWORK_TYPEERROR_HINTS = [\n 'failed to fetch',\n 'fetch failed',\n 'load failed',\n 'networkerror',\n 'network error when attempting to fetch',\n];\n\nfunction hasRetryableNodeErrorCode(err: unknown): boolean {\n let cur: unknown = err;\n for (let depth = 0; depth < 5 && cur != null; depth++) {\n const code = (cur as { code?: string })?.code;\n if (typeof code === 'string' && NODE_NETWORK_CODES.has(code)) return true;\n cur = cur instanceof Error && cur.cause !== undefined ? cur.cause : undefined;\n }\n return false;\n}\n\nfunction isFetchFailureTypeError(err: unknown): boolean {\n if (!(err instanceof TypeError)) return false;\n const msg = String(err.message).toLowerCase();\n return FETCH_NETWORK_TYPEERROR_HINTS.some((hint) => msg.includes(hint));\n}\n\nfunction isNetworkError(err: unknown): boolean {\n return hasRetryableNodeErrorCode(err) || isFetchFailureTypeError(err);\n}\n\n/** Execute a single HTTP request using the configured fetch implementation. */\nasync function executeFetch(fetchImpl: typeof fetch | undefined, requestConfig: RequestConfig): Promise<Response> {\n const impl = fetchImpl ?? globalThis.fetch;\n if (typeof impl === 'undefined') {\n throw new Error(\n '@macpaw/ai-sdk requires a global `fetch` implementation. ' +\n 'Use Node.js 18+ or install a polyfill like `undici`.',\n );\n }\n return impl(requestConfig.url, {\n method: requestConfig.method,\n headers: requestConfig.headers,\n body: requestConfig.body,\n signal: requestConfig.signal,\n });\n}\n\n// ─── Public types ─────────────────────────────────────────────────────────────\n\nexport interface ExecuteRequestInput {\n url: string;\n method: string;\n body?: RequestInit['body'];\n headers?: Record<string, string>;\n signal?: AbortSignal;\n}\n\nexport interface ExecuteRequestBehavior {\n /** Merge config-level default headers before per-request headers. */\n includeConfigHeaders?: boolean;\n /** Resolve and inject Bearer auth via `getAuthToken()`. */\n includeAuth?: boolean;\n /** Auto-add `X-Request-ID` when missing. */\n includeRequestId?: boolean;\n /** Convert non-OK responses into normalized gateway errors. */\n normalizeErrors?: boolean;\n /** Retry once on auth failure by forcing a fresh token. */\n allowAuthRetry?: boolean;\n /** Request ID prefix for correlation, e.g. `sdk` or `provider`. */\n requestIdPrefix?: string;\n}\n\n// ─── Pipeline ─────────────────────────────────────────────────────────────────\n\nexport async function executeRequestPipeline(\n config: ResolvedConfig,\n request: ExecuteRequestInput,\n behavior?: ExecuteRequestBehavior,\n): Promise<Response> {\n const b: Required<ExecuteRequestBehavior> = {\n includeConfigHeaders: behavior?.includeConfigHeaders ?? true,\n includeAuth: behavior?.includeAuth ?? true,\n includeRequestId: behavior?.includeRequestId ?? true,\n normalizeErrors: behavior?.normalizeErrors ?? true,\n allowAuthRetry: behavior?.allowAuthRetry ?? true,\n requestIdPrefix: behavior?.requestIdPrefix ?? 'sdk',\n };\n return executeWithAuth(config, request, b, false);\n}\n\nasync function executeWithAuth(\n config: ResolvedConfig,\n request: ExecuteRequestInput,\n behavior: Required<ExecuteRequestBehavior>,\n isTokenRetry: boolean,\n): Promise<Response> {\n try {\n return await executeRequest(config, request, behavior, isTokenRetry);\n } catch (err) {\n if (behavior.allowAuthRetry && !isTokenRetry && err instanceof AuthError) {\n // ReadableStream bodies are single-consumer: once the first request reads\n // the stream it is consumed and cannot be replayed on the retry attempt.\n if (typeof ReadableStream !== 'undefined' && request.body instanceof ReadableStream) {\n throw err;\n }\n return executeWithAuth(config, request, behavior, true);\n }\n throw err;\n }\n}\n\nasync function executeRequest(\n config: ResolvedConfig,\n request: ExecuteRequestInput,\n behavior: Required<ExecuteRequestBehavior>,\n forceRefreshToken: boolean,\n): Promise<Response> {\n const headers: Record<string, string> = {\n ...(behavior.includeConfigHeaders ? config.headers : undefined),\n ...request.headers,\n };\n\n if (shouldAutoSetJsonContentType(request.body, headers)) {\n headers['Content-Type'] = 'application/json';\n }\n\n if (behavior.includeRequestId && !hasHeaderCaseInsensitive(headers, 'x-request-id')) {\n headers['X-Request-ID'] = generateRequestId(behavior.requestIdPrefix);\n }\n\n const timeoutMs = config.timeout;\n const userSignal = request.signal;\n\n async function doRequest(): Promise<Response> {\n const timeoutController = new AbortController();\n const timeoutId = setTimeout(\n () => timeoutController.abort(new Error(`Request timed out after ${timeoutMs}ms`)),\n timeoutMs,\n );\n\n const signal = userSignal ? anySignal([userSignal, timeoutController.signal]) : timeoutController.signal;\n\n const requestConfig: RequestConfig = {\n url: request.url,\n method: request.method,\n headers: { ...headers },\n body: request.body,\n signal,\n };\n\n const { middleware } = config;\n let index = 0;\n\n const next = async (currentRequest: RequestConfig): Promise<Response> => {\n if (index < middleware.length) {\n const middlewareItem = middleware[index++];\n return middlewareItem(currentRequest, next);\n }\n const finalHeaders = { ...currentRequest.headers };\n if (behavior.includeAuth) {\n const token = await config.getAuthToken(forceRefreshToken);\n if (token) {\n finalHeaders.Authorization = `Bearer ${token}`;\n } else {\n for (const key of Object.keys(finalHeaders)) {\n if (key.toLowerCase() === 'authorization') delete finalHeaders[key];\n }\n }\n }\n return executeFetch(config.fetchImpl, { ...currentRequest, headers: finalHeaders });\n };\n\n try {\n const response = await next(requestConfig);\n\n if (!response.ok) {\n const retryableStatuses = config.retry !== false ? config.retry.retryableStatuses : [];\n // Transport logic must fire regardless of normalizeErrors:\n // - 401 must throw AuthError so executeWithAuth can refresh the token\n // - retryable statuses must throw so withRetry can schedule retry attempts\n const isTransportCritical =\n (behavior.allowAuthRetry && response.status === 401) ||\n (config.retry !== false && retryableStatuses.includes(response.status));\n\n if (behavior.normalizeErrors || isTransportCritical) {\n await parseErrorResponseFromResponse(response);\n }\n }\n\n return response;\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n if (config.retry) {\n // doRequest() re-runs the full middleware chain on each retry attempt.\n // Middleware with side effects (metrics, audit logs) will fire per attempt.\n return withRetry(doRequest, {\n retryConfig: config.retry,\n signal: userSignal,\n isNetworkError,\n });\n }\n\n return doRequest();\n}\n\n/** Redact Authorization for safe logging/debugging. */\nexport { redactSensitiveHeaders };\n","/**\n * Custom fetch factory for use with Vercel AI SDK and other OpenAI-compatible clients.\n * Use this with createOpenAI({ baseURL, fetch: createGatewayFetch(...) }) or similar.\n *\n * AI Gateway HTTP paths are under /api/v1 (e.g. /api/v1/chat/completions).\n * So baseURL should be the gateway root, e.g. https://api.macpaw.com/ai\n *\n * Internally delegates to the shared request pipeline while guarding against\n * leaking gateway auth/headers to non-gateway hosts.\n */\n\nimport type { GatewayProviderSettings } from './gateway-config';\nimport { resolveConfig } from './gateway-config';\nimport { executeRequestPipeline } from './gateway-request';\n\n/**\n * Config for `createGatewayFetch`.\n * Extends GatewayProviderSettings with baseURL required (already resolved)\n * and normalizeErrors (provider-specific behavior).\n */\nexport interface GatewayFetchConfig extends GatewayProviderSettings {\n /** Resolved Gateway base URL (required — use resolveGatewayBaseURL first). */\n baseURL: string;\n /**\n * Normalize gateway error responses into `AIGatewayError`. Default: true.\n * When enabled, non-OK gateway responses throw instead of returning a failed Response.\n */\n normalizeErrors?: boolean;\n}\n\ntype FetchInput = string | URL | Request | { url: string };\n\nfunction resolveRequestUrl(input: FetchInput): string {\n if (typeof input === 'string') return input;\n if (input instanceof URL) return input.href;\n return input.url;\n}\n\nfunction stripPlaceholderAuthorization(headers: Headers, placeholder: string): void {\n const auth = headers.get('authorization');\n if (auth === `Bearer ${placeholder}`) {\n headers.delete('authorization');\n }\n}\n\nfunction headersToRecord(headers: Headers): Record<string, string> {\n const record: Record<string, string> = {};\n for (const [key, value] of headers.entries()) {\n record[key] = value;\n }\n return record;\n}\n\nfunction joinBaseUrl(baseURL: string, path: string): string {\n return `${baseURL}${path.startsWith('/') ? '' : '/'}${path}`;\n}\n\nfunction isGatewayUrl(url: URL, gatewayBaseUrl: URL): boolean {\n const gatewayPath = gatewayBaseUrl.pathname.replace(/\\/$/, '');\n const requestPath = url.pathname.replace(/\\/$/, '');\n return (\n url.origin === gatewayBaseUrl.origin && (requestPath === gatewayPath || requestPath.startsWith(`${gatewayPath}/`))\n );\n}\n\nexport const GATEWAY_PLACEHOLDER_API_KEY = 'ai-gateway-auth-via-fetch';\n\nexport function createGatewayFetch(\n options: GatewayFetchConfig,\n): (input: FetchInput, init?: RequestInit) => Promise<Response> {\n const { baseURL, normalizeErrors = true } = options;\n const base = baseURL.replace(/\\/$/, '');\n const gatewayBaseUrl = new URL(base);\n const resolvedConfig = resolveConfig({ ...options, baseURL: base });\n\n return async function gatewayFetch(input: FetchInput, init?: RequestInit): Promise<Response> {\n const rawUrl = resolveRequestUrl(input);\n const isAbsolute = rawUrl.startsWith('http://') || rawUrl.startsWith('https://');\n const resolvedUrl = new URL(isAbsolute ? rawUrl : joinBaseUrl(base, rawUrl));\n const isGatewayRequest = isGatewayUrl(resolvedUrl, gatewayBaseUrl);\n\n const request = typeof Request !== 'undefined' && input instanceof Request ? input : undefined;\n const requestClone = request?.clone();\n const headers = new Headers(requestClone?.headers);\n\n if (init?.headers) {\n for (const [key, value] of new Headers(init.headers).entries()) {\n headers.set(key, value);\n }\n }\n\n if (!isGatewayRequest) {\n stripPlaceholderAuthorization(headers, GATEWAY_PLACEHOLDER_API_KEY);\n }\n\n return executeRequestPipeline(\n resolvedConfig,\n {\n url: resolvedUrl.toString(),\n method: init?.method ?? requestClone?.method ?? 'GET',\n headers: headersToRecord(headers),\n body: init?.body ?? requestClone?.body,\n signal: init?.signal ?? requestClone?.signal,\n },\n {\n includeConfigHeaders: isGatewayRequest,\n includeAuth: isGatewayRequest,\n includeRequestId: isGatewayRequest,\n normalizeErrors: isGatewayRequest && normalizeErrors,\n allowAuthRetry: isGatewayRequest,\n requestIdPrefix: 'provider',\n },\n );\n };\n}\n","/**\n * AI Gateway provider factory.\n *\n * `createGatewayProvider()` routes bare model IDs through the gateway's\n * OpenAI-compatible endpoint with provider-specific prefixes.\n * `createAIGatewayProvider()` is the low-level escape hatch for direct\n * OpenAI-compatible provider construction.\n */\n\nimport { createOpenAI as builtinCreateOpenAI } from '@ai-sdk/openai';\nimport type { OpenAIProvider, OpenAIProviderSettings } from '@ai-sdk/openai';\nimport { createGatewayFetch, GATEWAY_PLACEHOLDER_API_KEY } from './gateway-fetch';\nimport type { Environment, GatewayProviderSettings } from './gateway-config';\nimport { resolveGatewayBaseURL } from './gateway-config';\n\n// ─── AIGatewayProvider (low-level) ────────────────────────────────────────────\n\nconst DEFAULT_API_VERSION = 'v1';\n\nexport interface AIGatewayProviderOptions\n extends Omit<OpenAIProviderSettings, 'apiKey' | 'baseURL' | 'fetch'>, GatewayProviderSettings {\n /**\n * Optional override for the OpenAI provider factory.\n * Uses `createOpenAI` from `@ai-sdk/openai` by default.\n */\n createOpenAI?: typeof builtinCreateOpenAI;\n /**\n * Normalize gateway error responses into `AIGatewayError`. Default: true.\n * When enabled, non-OK gateway responses throw instead of returning a failed Response.\n */\n normalizeErrors?: boolean;\n}\n\n/**\n * Creates a Vercel AI SDK-compatible provider backed by AI Gateway.\n *\n * The returned value is a fully typed `OpenAIProvider`, so existing apps can\n * keep using their `ai-sdk` helpers and model-selection patterns.\n */\nexport function createAIGatewayProvider(options: AIGatewayProviderOptions): OpenAIProvider {\n const baseURL = resolveGatewayBaseURL(options.baseURL, options.env as Environment, 'AIGatewayProvider');\n const customFetch = createGatewayFetch({ ...options, baseURL, normalizeErrors: options.normalizeErrors });\n\n const openAI = options.createOpenAI ?? builtinCreateOpenAI;\n\n return openAI({\n name: options.name,\n organization: options.organization,\n project: options.project,\n baseURL: `${baseURL.replace(/\\/$/, '')}/api/${DEFAULT_API_VERSION}`,\n fetch: customFetch,\n apiKey: GATEWAY_PLACEHOLDER_API_KEY,\n });\n}\n\n// ─── GatewayProvider (prefixed routing) ───────────────────────────────────────\n\nexport interface GatewayProviderBaseOptions extends AIGatewayProviderOptions {\n /**\n * Override the model ID prefix used for Gateway routing.\n * Default: the provider's canonical prefix (e.g. `'anthropic'`).\n *\n * Model IDs that already contain `/` are sent as-is.\n */\n modelPrefix?: string;\n}\n\nexport interface GatewayOpenAICompatibleOptions extends Omit<GatewayProviderBaseOptions, 'modelPrefix'> {\n /**\n * Required for openai-compatible backends because there is no single canonical\n * default prefix. Examples: `openai`, `fireworks_ai`, `openrouter`.\n */\n modelPrefix: string;\n}\n\nexport const GATEWAY_PROVIDERS = {\n ANTHROPIC: 'anthropic',\n GOOGLE: 'google',\n XAI: 'xai',\n GROQ: 'groq',\n MISTRAL: 'mistral',\n AMAZON_BEDROCK: 'amazon-bedrock',\n AZURE: 'azure',\n COHERE: 'cohere',\n PERPLEXITY: 'perplexity',\n DEEPSEEK: 'deepseek',\n TOGETHERAI: 'togetherai',\n OPENAI_COMPATIBLE: 'openai-compatible',\n} as const;\n\nexport type GatewayProvider = (typeof GATEWAY_PROVIDERS)[keyof typeof GATEWAY_PROVIDERS];\n\nexport type GatewayProviderWithDefaultPrefix = Exclude<GatewayProvider, typeof GATEWAY_PROVIDERS.OPENAI_COMPATIBLE>;\n\nexport interface GatewayProviderOptionsMap {\n [GATEWAY_PROVIDERS.OPENAI_COMPATIBLE]: GatewayOpenAICompatibleOptions;\n}\n\nexport type GatewayProviderOptions<P extends GatewayProvider> = P extends keyof GatewayProviderOptionsMap\n ? GatewayProviderOptionsMap[P]\n : GatewayProviderBaseOptions;\n\nconst GATEWAY_PROVIDER_DEFAULT_PREFIXES: Record<GatewayProviderWithDefaultPrefix, string> = {\n [GATEWAY_PROVIDERS.ANTHROPIC]: 'anthropic',\n [GATEWAY_PROVIDERS.GOOGLE]: 'google',\n [GATEWAY_PROVIDERS.XAI]: 'xai',\n [GATEWAY_PROVIDERS.GROQ]: 'groq',\n [GATEWAY_PROVIDERS.MISTRAL]: 'mistral',\n [GATEWAY_PROVIDERS.AMAZON_BEDROCK]: 'bedrock',\n [GATEWAY_PROVIDERS.AZURE]: 'azure',\n [GATEWAY_PROVIDERS.COHERE]: 'cohere',\n [GATEWAY_PROVIDERS.PERPLEXITY]: 'perplexity',\n [GATEWAY_PROVIDERS.DEEPSEEK]: 'deepseek',\n [GATEWAY_PROVIDERS.TOGETHERAI]: 'togetherai',\n};\n\nfunction prefixModelId(prefix: string, modelId: string): string {\n return modelId.includes('/') ? modelId : `${prefix}/${modelId}`;\n}\n\nfunction createPrefixedGatewayProvider(defaultPrefix: string, options: GatewayProviderBaseOptions): OpenAIProvider {\n const { modelPrefix, ...providerOptions } = options;\n const prefix = modelPrefix ?? defaultPrefix;\n const provider = createAIGatewayProvider(providerOptions);\n\n const wrapped = ((modelId: string) => provider(prefixModelId(prefix, modelId))) as OpenAIProvider;\n\n return new Proxy(wrapped, {\n apply(_target, _thisArg, args: [string, ...unknown[]]) {\n const [modelId, ...rest] = args;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (provider as (...a: unknown[]) => any)(prefixModelId(prefix, modelId), ...rest);\n },\n get(_target, prop) {\n const value = Reflect.get(provider, prop, provider);\n if (typeof value === 'function') {\n return (...args: unknown[]) => {\n if (typeof args[0] === 'string') {\n args[0] = prefixModelId(prefix, args[0] as string);\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (value as (...a: unknown[]) => any).apply(provider, args);\n };\n }\n return value;\n },\n has(_target, prop) {\n return prop in (provider as object);\n },\n });\n}\n\n/**\n * Creates an `OpenAIProvider` backed by AI Gateway for a supported provider.\n *\n * Bare model IDs are automatically prefixed with the provider's canonical\n * Gateway routing prefix. Model IDs that already contain `/` are passed as-is.\n */\nexport function createGatewayProvider(\n provider: GatewayProviderWithDefaultPrefix,\n options: GatewayProviderBaseOptions,\n): OpenAIProvider;\nexport function createGatewayProvider(\n provider: typeof GATEWAY_PROVIDERS.OPENAI_COMPATIBLE,\n options: GatewayOpenAICompatibleOptions,\n): OpenAIProvider;\nexport function createGatewayProvider(\n provider: GatewayProvider,\n options: GatewayProviderBaseOptions | GatewayOpenAICompatibleOptions,\n): OpenAIProvider {\n if (provider === GATEWAY_PROVIDERS.OPENAI_COMPATIBLE) {\n return createPrefixedGatewayProvider(\n (options as GatewayOpenAICompatibleOptions).modelPrefix,\n options as GatewayOpenAICompatibleOptions,\n );\n }\n\n return createPrefixedGatewayProvider(\n GATEWAY_PROVIDER_DEFAULT_PREFIXES[provider as GatewayProviderWithDefaultPrefix],\n options as GatewayProviderBaseOptions,\n );\n}\n"]}
|