@aexol/spectral 0.9.249 → 0.9.250
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/dist/generated/zeus/const.d.ts.map +1 -1
- package/dist/generated/zeus/const.js +1 -10
- package/dist/generated/zeus/index.d.ts +6 -49
- package/dist/generated/zeus/index.d.ts.map +1 -1
- package/dist/sdk/ai/utils/image-source.d.ts +16 -6
- package/dist/sdk/ai/utils/image-source.d.ts.map +1 -1
- package/dist/sdk/ai/utils/image-source.js +39 -12
- package/package.json +1 -1
|
@@ -8,11 +8,18 @@
|
|
|
8
8
|
* something a provider can actually consume:
|
|
9
9
|
*
|
|
10
10
|
* - `data` present -> `data:<mimeType>;base64,<data>` (unchanged, legacy safe)
|
|
11
|
-
* - `url` public
|
|
12
|
-
* - `url` backend-hosted -> swapped for a presigned,
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
11
|
+
* - `url` public (3rd-party) -> passed through as-is (no base64 in the context!)
|
|
12
|
+
* - `url` backend-hosted -> swapped for a presigned S3 url, which is then
|
|
13
|
+
* ALWAYS downloaded anonymously here and inlined
|
|
14
|
+
* as a base64 data URI — OpenRouter's server-side
|
|
15
|
+
* media fetcher gets HTTP 400 from S3 on
|
|
16
|
+
* presigned urls, so the raw presigned url must
|
|
17
|
+
* never reach the provider. If the S3 download
|
|
18
|
+
* fails, the presigned url is sent as a fallback
|
|
19
|
+
* instead of dropping the image.
|
|
20
|
+
* (`/generated-images/<id>` is what the backend
|
|
21
|
+
* returns; it is AUTH-GATED, so handing it to a
|
|
22
|
+
* provider only yields a 401)
|
|
16
23
|
* - `url` relative -> resolved against the backend base url first
|
|
17
24
|
* - `url` local/private -> fetched and inlined **at send time only**
|
|
18
25
|
*
|
|
@@ -80,7 +87,10 @@ export interface ResolvedImageSource {
|
|
|
80
87
|
data?: string;
|
|
81
88
|
/**
|
|
82
89
|
* True when `url` is a presigned url returned by `resolveHostedUrl` (i.e.
|
|
83
|
-
* it replaced an auth-gated `/generated-images/<id>` reference).
|
|
90
|
+
* it replaced an auth-gated `/generated-images/<id>` reference). Only set
|
|
91
|
+
* when the presigned url itself is handed to the provider — which only
|
|
92
|
+
* happens as a fallback when inlining its bytes failed; a successful
|
|
93
|
+
* download is inlined (`inlined: true`) and the flag stays unset.
|
|
84
94
|
*/
|
|
85
95
|
hostedResolved?: boolean;
|
|
86
96
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image-source.d.ts","sourceRoot":"","sources":["../../../../src/sdk/ai/utils/image-source.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"image-source.d.ts","sourceRoot":"","sources":["../../../../src/sdk/ai/utils/image-source.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,11 +8,18 @@
|
|
|
8
8
|
* something a provider can actually consume:
|
|
9
9
|
*
|
|
10
10
|
* - `data` present -> `data:<mimeType>;base64,<data>` (unchanged, legacy safe)
|
|
11
|
-
* - `url` public
|
|
12
|
-
* - `url` backend-hosted -> swapped for a presigned,
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
11
|
+
* - `url` public (3rd-party) -> passed through as-is (no base64 in the context!)
|
|
12
|
+
* - `url` backend-hosted -> swapped for a presigned S3 url, which is then
|
|
13
|
+
* ALWAYS downloaded anonymously here and inlined
|
|
14
|
+
* as a base64 data URI — OpenRouter's server-side
|
|
15
|
+
* media fetcher gets HTTP 400 from S3 on
|
|
16
|
+
* presigned urls, so the raw presigned url must
|
|
17
|
+
* never reach the provider. If the S3 download
|
|
18
|
+
* fails, the presigned url is sent as a fallback
|
|
19
|
+
* instead of dropping the image.
|
|
20
|
+
* (`/generated-images/<id>` is what the backend
|
|
21
|
+
* returns; it is AUTH-GATED, so handing it to a
|
|
22
|
+
* provider only yields a 401)
|
|
16
23
|
* - `url` relative -> resolved against the backend base url first
|
|
17
24
|
* - `url` local/private -> fetched and inlined **at send time only**
|
|
18
25
|
*
|
|
@@ -287,13 +294,26 @@ export async function resolveImageForProvider(image, options = {}) {
|
|
|
287
294
|
// the provider would fetch it anonymously and get a 401. Swap it for a
|
|
288
295
|
// presigned url first (that one needs no headers at all).
|
|
289
296
|
const hosted = isHostedBackendImageUrl(url, backendUrl);
|
|
297
|
+
// Url the bytes are downloaded from: the presigned url when the hosted
|
|
298
|
+
// swap succeeded, the (possibly rewritten) backend url otherwise.
|
|
299
|
+
let downloadUrl = url;
|
|
300
|
+
let presignedResolved = false;
|
|
290
301
|
if (hosted && options.resolveHostedUrl) {
|
|
291
302
|
try {
|
|
292
303
|
const resolvedUrl = (await options.resolveHostedUrl(url, { signal: options.signal, timeoutMs: options.timeoutMs }))?.trim();
|
|
293
304
|
if (resolvedUrl && !isLocalOrPrivateImageUrl(resolvedUrl)) {
|
|
294
|
-
|
|
305
|
+
// OpenRouter's server-side media fetcher gets HTTP 400 from S3 on
|
|
306
|
+
// presigned urls (the in-repo vLLM fetcher had the same bug), so
|
|
307
|
+
// the presigned url must NEVER be handed over verbatim. Fall
|
|
308
|
+
// through to the inline path below, which downloads the bytes
|
|
309
|
+
// anonymously here and sends a base64 data URI instead; if that
|
|
310
|
+
// download fails, the presigned url is still sent (the fallback
|
|
311
|
+
// at the bottom keeps today's behavior instead of dropping the
|
|
312
|
+
// image).
|
|
313
|
+
downloadUrl = resolvedUrl;
|
|
314
|
+
presignedResolved = true;
|
|
295
315
|
}
|
|
296
|
-
if (resolvedUrl) {
|
|
316
|
+
if (resolvedUrl && !presignedResolved) {
|
|
297
317
|
// The backend minted the presigned url on a LOCAL/private endpoint
|
|
298
318
|
// (dev S3 on `http://localhost:9002`) — a remote provider can never
|
|
299
319
|
// fetch it. Do NOT hand over that dead url: fall through to the
|
|
@@ -316,14 +336,16 @@ export async function resolveImageForProvider(image, options = {}) {
|
|
|
316
336
|
}
|
|
317
337
|
// Only inline a hosted url when we can actually authenticate the download;
|
|
318
338
|
// without credentials the fetch is a guaranteed 401 anyway, so the plain
|
|
319
|
-
// pass-through (identical end result, one request less) is kept.
|
|
320
|
-
|
|
339
|
+
// pass-through (identical end result, one request less) is kept. A
|
|
340
|
+
// presigned url needs NO credentials — it is downloaded anonymously and
|
|
341
|
+
// always inlined.
|
|
342
|
+
const authHeaders = hosted && !presignedResolved ? await resolveAuthHeadersOption(options.authHeaders) : undefined;
|
|
321
343
|
// Belt and braces: re-check the origin here, because `url` was rewritten
|
|
322
344
|
// above (relative -> absolute) and only a url that is still ours may carry
|
|
323
345
|
// credentials. The resolver refuses foreign origins too, this is the last
|
|
324
346
|
// gate before the token goes on the wire.
|
|
325
347
|
const authenticated = authHeaders !== undefined && isHostedBackendImageUrl(url, backendUrl);
|
|
326
|
-
if (!isLocalOrPrivateImageUrl(url) && !authenticated) {
|
|
348
|
+
if (!isLocalOrPrivateImageUrl(url) && !authenticated && !presignedResolved) {
|
|
327
349
|
return { url, inlined: false, mimeType: image.mimeType };
|
|
328
350
|
}
|
|
329
351
|
const requestHeaders = authenticated ? authHeaders : undefined;
|
|
@@ -341,7 +363,7 @@ export async function resolveImageForProvider(image, options = {}) {
|
|
|
341
363
|
// `requestHeaders` is only set when the (possibly rewritten) url still
|
|
342
364
|
// resolves to the backend origin — a url on any other host is fetched
|
|
343
365
|
// anonymously, so the JWT cannot leak to a third party.
|
|
344
|
-
const response = await doFetch(
|
|
366
|
+
const response = await doFetch(downloadUrl, requestHeaders ? { signal: controller.signal, headers: requestHeaders } : { signal: controller.signal });
|
|
345
367
|
if (!response.ok)
|
|
346
368
|
throw new Error(`HTTP ${response.status}`);
|
|
347
369
|
// Reject oversized payloads from the declared length BEFORE reading
|
|
@@ -368,7 +390,12 @@ export async function resolveImageForProvider(image, options = {}) {
|
|
|
368
390
|
}
|
|
369
391
|
catch (error) {
|
|
370
392
|
const reason = error instanceof Error ? error.message : String(error);
|
|
371
|
-
options.onWarn?.(`Could not inline
|
|
393
|
+
options.onWarn?.(`Could not inline image ${presignedResolved ? downloadUrl : url} (${reason}); sending url as-is${hosted && !presignedResolved ? " — the provider may not be able to fetch it (auth required)" : ""}`);
|
|
394
|
+
if (presignedResolved) {
|
|
395
|
+
// The S3 download failed — degrade to the old verbatim behavior
|
|
396
|
+
// (send the presigned url) rather than dropping the image.
|
|
397
|
+
return { url: downloadUrl, inlined: false, mimeType: image.mimeType, hostedResolved: true };
|
|
398
|
+
}
|
|
372
399
|
return { url, inlined: false, mimeType: image.mimeType };
|
|
373
400
|
}
|
|
374
401
|
finally {
|