@ai-sdk/provider-utils 4.0.8 → 4.0.10

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.
Files changed (58) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/index.js +29 -1
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.mjs +29 -1
  5. package/dist/index.mjs.map +1 -1
  6. package/package.json +6 -2
  7. package/src/handle-fetch-error.ts +33 -0
  8. package/src/__snapshots__/schema.test.ts.snap +0 -346
  9. package/src/add-additional-properties-to-json-schema.test.ts +0 -289
  10. package/src/convert-async-iterator-to-readable-stream.test.ts +0 -78
  11. package/src/convert-image-model-file-to-data-uri.test.ts +0 -85
  12. package/src/convert-to-form-data.test.ts +0 -167
  13. package/src/create-tool-name-mapping.test.ts +0 -163
  14. package/src/delay.test.ts +0 -212
  15. package/src/delayed-promise.test.ts +0 -132
  16. package/src/download-blob.test.ts +0 -145
  17. package/src/generate-id.test.ts +0 -31
  18. package/src/get-from-api.test.ts +0 -199
  19. package/src/get-runtime-environment-user-agent.test.ts +0 -47
  20. package/src/inject-json-instruction.test.ts +0 -404
  21. package/src/is-url-supported.test.ts +0 -282
  22. package/src/media-type-to-extension.test.ts +0 -26
  23. package/src/normalize-headers.test.ts +0 -64
  24. package/src/parse-json.test.ts +0 -191
  25. package/src/remove-undefined-entries.test.ts +0 -57
  26. package/src/resolve.test.ts +0 -125
  27. package/src/response-handler.test.ts +0 -89
  28. package/src/schema.test-d.ts +0 -11
  29. package/src/schema.test.ts +0 -502
  30. package/src/secure-json-parse.test.ts +0 -59
  31. package/src/to-json-schema/zod3-to-json-schema/parse-def.test.ts +0 -224
  32. package/src/to-json-schema/zod3-to-json-schema/parsers/array.test.ts +0 -98
  33. package/src/to-json-schema/zod3-to-json-schema/parsers/bigint.test.ts +0 -51
  34. package/src/to-json-schema/zod3-to-json-schema/parsers/branded.test.ts +0 -16
  35. package/src/to-json-schema/zod3-to-json-schema/parsers/catch.test.ts +0 -15
  36. package/src/to-json-schema/zod3-to-json-schema/parsers/date.test.ts +0 -97
  37. package/src/to-json-schema/zod3-to-json-schema/parsers/default.test.ts +0 -54
  38. package/src/to-json-schema/zod3-to-json-schema/parsers/effects.test.ts +0 -41
  39. package/src/to-json-schema/zod3-to-json-schema/parsers/intersection.test.ts +0 -92
  40. package/src/to-json-schema/zod3-to-json-schema/parsers/map.test.ts +0 -48
  41. package/src/to-json-schema/zod3-to-json-schema/parsers/native-enum.test.ts +0 -102
  42. package/src/to-json-schema/zod3-to-json-schema/parsers/nullable.test.ts +0 -67
  43. package/src/to-json-schema/zod3-to-json-schema/parsers/number.test.ts +0 -65
  44. package/src/to-json-schema/zod3-to-json-schema/parsers/object.test.ts +0 -149
  45. package/src/to-json-schema/zod3-to-json-schema/parsers/optional.test.ts +0 -147
  46. package/src/to-json-schema/zod3-to-json-schema/parsers/pipe.test.ts +0 -35
  47. package/src/to-json-schema/zod3-to-json-schema/parsers/promise.test.ts +0 -15
  48. package/src/to-json-schema/zod3-to-json-schema/parsers/readonly.test.ts +0 -20
  49. package/src/to-json-schema/zod3-to-json-schema/parsers/record.test.ts +0 -108
  50. package/src/to-json-schema/zod3-to-json-schema/parsers/set.test.ts +0 -20
  51. package/src/to-json-schema/zod3-to-json-schema/parsers/string.test.ts +0 -438
  52. package/src/to-json-schema/zod3-to-json-schema/parsers/tuple.test.ts +0 -33
  53. package/src/to-json-schema/zod3-to-json-schema/parsers/union.test.ts +0 -226
  54. package/src/to-json-schema/zod3-to-json-schema/refs.test.ts +0 -919
  55. package/src/to-json-schema/zod3-to-json-schema/zod3-to-json-schema.test.ts +0 -862
  56. package/src/types/tool.test-d.ts +0 -228
  57. package/src/validate-types.test.ts +0 -105
  58. package/src/with-user-agent-suffix.test.ts +0 -84
@@ -1,404 +0,0 @@
1
- import { JSONSchema7, LanguageModelV3Prompt } from '@ai-sdk/provider';
2
- import { expect, it, describe } from 'vitest';
3
- import {
4
- injectJsonInstruction,
5
- injectJsonInstructionIntoMessages,
6
- } from './inject-json-instruction';
7
-
8
- const basicSchema: JSONSchema7 = {
9
- type: 'object',
10
- properties: {
11
- name: { type: 'string' },
12
- age: { type: 'number' },
13
- },
14
- required: ['name', 'age'],
15
- };
16
-
17
- describe('injectJsonInstruction', () => {
18
- it('should handle basic case with prompt and schema', () => {
19
- const result = injectJsonInstruction({
20
- prompt: 'Generate a person',
21
- schema: basicSchema,
22
- });
23
- expect(result).toBe(
24
- 'Generate a person\n\n' +
25
- 'JSON schema:\n' +
26
- '{"type":"object","properties":{"name":{"type":"string"},"age":{"type":"number"}},"required":["name","age"]}\n' +
27
- 'You MUST answer with a JSON object that matches the JSON schema above.',
28
- );
29
- });
30
-
31
- it('should handle only prompt, no schema', () => {
32
- const result = injectJsonInstruction({
33
- prompt: 'Generate a person',
34
- });
35
- expect(result).toBe('Generate a person\n\nYou MUST answer with JSON.');
36
- });
37
-
38
- it('should handle only schema, no prompt', () => {
39
- const result = injectJsonInstruction({
40
- schema: basicSchema,
41
- });
42
- expect(result).toBe(
43
- 'JSON schema:\n' +
44
- '{"type":"object","properties":{"name":{"type":"string"},"age":{"type":"number"}},"required":["name","age"]}\n' +
45
- 'You MUST answer with a JSON object that matches the JSON schema above.',
46
- );
47
- });
48
-
49
- it('should handle no prompt, no schema', () => {
50
- const result = injectJsonInstruction({});
51
- expect(result).toBe('You MUST answer with JSON.');
52
- });
53
-
54
- it('should handle custom schemaPrefix and schemaSuffix', () => {
55
- const result = injectJsonInstruction({
56
- prompt: 'Generate a person',
57
- schema: basicSchema,
58
- schemaPrefix: 'Custom prefix:',
59
- schemaSuffix: 'Custom suffix',
60
- });
61
- expect(result).toBe(
62
- 'Generate a person\n\n' +
63
- 'Custom prefix:\n' +
64
- '{"type":"object","properties":{"name":{"type":"string"},"age":{"type":"number"}},"required":["name","age"]}\n' +
65
- 'Custom suffix',
66
- );
67
- });
68
-
69
- it('should handle empty string prompt', () => {
70
- const result = injectJsonInstruction({
71
- prompt: '',
72
- schema: basicSchema,
73
- });
74
- expect(result).toBe(
75
- 'JSON schema:\n' +
76
- '{"type":"object","properties":{"name":{"type":"string"},"age":{"type":"number"}},"required":["name","age"]}\n' +
77
- 'You MUST answer with a JSON object that matches the JSON schema above.',
78
- );
79
- });
80
-
81
- it('should handle empty object schema', () => {
82
- const result = injectJsonInstruction({
83
- prompt: 'Generate something',
84
- schema: {},
85
- });
86
- expect(result).toBe(
87
- 'Generate something\n\n' +
88
- 'JSON schema:\n' +
89
- '{}\n' +
90
- 'You MUST answer with a JSON object that matches the JSON schema above.',
91
- );
92
- });
93
-
94
- it('should handle complex nested schema', () => {
95
- const complexSchema: JSONSchema7 = {
96
- type: 'object',
97
- properties: {
98
- person: {
99
- type: 'object',
100
- properties: {
101
- name: { type: 'string' },
102
- age: { type: 'number' },
103
- address: {
104
- type: 'object',
105
- properties: {
106
- street: { type: 'string' },
107
- city: { type: 'string' },
108
- },
109
- },
110
- },
111
- },
112
- },
113
- };
114
- const result = injectJsonInstruction({
115
- prompt: 'Generate a complex person',
116
- schema: complexSchema,
117
- });
118
- expect(result).toBe(
119
- 'Generate a complex person\n\n' +
120
- 'JSON schema:\n' +
121
- '{"type":"object","properties":{"person":{"type":"object","properties":{"name":{"type":"string"},"age":{"type":"number"},"address":{"type":"object","properties":{"street":{"type":"string"},"city":{"type":"string"}}}}}}}\n' +
122
- 'You MUST answer with a JSON object that matches the JSON schema above.',
123
- );
124
- });
125
-
126
- it('should handle schema with special characters', () => {
127
- const specialSchema: JSONSchema7 = {
128
- type: 'object',
129
- properties: {
130
- 'special@property': { type: 'string' },
131
- 'emoji😊': { type: 'string' },
132
- },
133
- };
134
- const result = injectJsonInstruction({
135
- schema: specialSchema,
136
- });
137
- expect(result).toBe(
138
- 'JSON schema:\n' +
139
- '{"type":"object","properties":{"special@property":{"type":"string"},"emoji😊":{"type":"string"}}}\n' +
140
- 'You MUST answer with a JSON object that matches the JSON schema above.',
141
- );
142
- });
143
-
144
- it('should handle very long prompt and schema', () => {
145
- const longPrompt = 'A'.repeat(1000);
146
- const longSchema: JSONSchema7 = {
147
- type: 'object',
148
- properties: {},
149
- };
150
- for (let i = 0; i < 100; i++) {
151
- longSchema.properties![`prop${i}`] = { type: 'string' };
152
- }
153
- const result = injectJsonInstruction({
154
- prompt: longPrompt,
155
- schema: longSchema,
156
- });
157
- expect(result).toBe(
158
- longPrompt +
159
- '\n\n' +
160
- 'JSON schema:\n' +
161
- JSON.stringify(longSchema) +
162
- '\n' +
163
- 'You MUST answer with a JSON object that matches the JSON schema above.',
164
- );
165
- });
166
-
167
- it('should handle null values for optional parameters', () => {
168
- const result = injectJsonInstruction({
169
- prompt: null as any,
170
- schema: null as any,
171
- schemaPrefix: null as any,
172
- schemaSuffix: null as any,
173
- });
174
- expect(result).toBe('');
175
- });
176
-
177
- it('should handle undefined values for optional parameters', () => {
178
- const result = injectJsonInstruction({
179
- prompt: undefined,
180
- schema: undefined,
181
- schemaPrefix: undefined,
182
- schemaSuffix: undefined,
183
- });
184
- expect(result).toBe('You MUST answer with JSON.');
185
- });
186
- });
187
-
188
- describe('injectJsonInstructionIntoMessages', () => {
189
- it('should handle basic case with prompt and schema', () => {
190
- const result = injectJsonInstructionIntoMessages({
191
- messages: [{ role: 'system', content: 'Generate a person' }],
192
- schema: basicSchema,
193
- });
194
-
195
- expect(result).toMatchInlineSnapshot(`
196
- [
197
- {
198
- "content": "Generate a person
199
-
200
- JSON schema:
201
- {"type":"object","properties":{"name":{"type":"string"},"age":{"type":"number"}},"required":["name","age"]}
202
- You MUST answer with a JSON object that matches the JSON schema above.",
203
- "role": "system",
204
- },
205
- ]
206
- `);
207
- });
208
-
209
- it('should not mutate the input messages array', () => {
210
- const originalMessages: LanguageModelV3Prompt = [
211
- { role: 'system', content: 'Generate a person' },
212
- ];
213
-
214
- injectJsonInstructionIntoMessages({
215
- messages: originalMessages,
216
- schema: basicSchema,
217
- });
218
-
219
- expect(originalMessages).toEqual([
220
- { role: 'system', content: 'Generate a person' },
221
- ]);
222
- });
223
-
224
- it('should handle empty messages array', () => {
225
- const result = injectJsonInstructionIntoMessages({
226
- messages: [],
227
- schema: basicSchema,
228
- });
229
-
230
- expect(result).toMatchInlineSnapshot(`
231
- [
232
- {
233
- "content": "JSON schema:
234
- {"type":"object","properties":{"name":{"type":"string"},"age":{"type":"number"}},"required":["name","age"]}
235
- You MUST answer with a JSON object that matches the JSON schema above.",
236
- "role": "system",
237
- },
238
- ]
239
- `);
240
- });
241
-
242
- it('should handle messages without initial system message', () => {
243
- const result = injectJsonInstructionIntoMessages({
244
- messages: [
245
- { role: 'user', content: [{ type: 'text', text: 'Hello' }] },
246
- {
247
- role: 'assistant',
248
- content: [{ type: 'text', text: 'Hi there' }],
249
- },
250
- ],
251
- schema: basicSchema,
252
- });
253
-
254
- expect(result).toMatchInlineSnapshot(`
255
- [
256
- {
257
- "content": "JSON schema:
258
- {"type":"object","properties":{"name":{"type":"string"},"age":{"type":"number"}},"required":["name","age"]}
259
- You MUST answer with a JSON object that matches the JSON schema above.",
260
- "role": "system",
261
- },
262
- {
263
- "content": [
264
- {
265
- "text": "Hello",
266
- "type": "text",
267
- },
268
- ],
269
- "role": "user",
270
- },
271
- {
272
- "content": [
273
- {
274
- "text": "Hi there",
275
- "type": "text",
276
- },
277
- ],
278
- "role": "assistant",
279
- },
280
- ]
281
- `);
282
- });
283
-
284
- it('should handle system message with empty content', () => {
285
- const result = injectJsonInstructionIntoMessages({
286
- messages: [
287
- { role: 'system', content: '' },
288
- { role: 'user', content: [{ type: 'text', text: 'Generate data' }] },
289
- ],
290
- schema: basicSchema,
291
- });
292
-
293
- expect(result).toMatchInlineSnapshot(`
294
- [
295
- {
296
- "content": "JSON schema:
297
- {"type":"object","properties":{"name":{"type":"string"},"age":{"type":"number"}},"required":["name","age"]}
298
- You MUST answer with a JSON object that matches the JSON schema above.",
299
- "role": "system",
300
- },
301
- {
302
- "content": [
303
- {
304
- "text": "Generate data",
305
- "type": "text",
306
- },
307
- ],
308
- "role": "user",
309
- },
310
- ]
311
- `);
312
- });
313
-
314
- it('should preserve all non-system messages', () => {
315
- const result = injectJsonInstructionIntoMessages({
316
- messages: [
317
- { role: 'system', content: 'You are helpful' },
318
- { role: 'user', content: [{ type: 'text', text: 'Hello' }] },
319
- { role: 'assistant', content: [{ type: 'text', text: 'Hi' }] },
320
- { role: 'user', content: [{ type: 'text', text: 'Generate person' }] },
321
- ],
322
- schema: basicSchema,
323
- });
324
-
325
- expect(result).toMatchInlineSnapshot(`
326
- [
327
- {
328
- "content": "You are helpful
329
-
330
- JSON schema:
331
- {"type":"object","properties":{"name":{"type":"string"},"age":{"type":"number"}},"required":["name","age"]}
332
- You MUST answer with a JSON object that matches the JSON schema above.",
333
- "role": "system",
334
- },
335
- {
336
- "content": [
337
- {
338
- "text": "Hello",
339
- "type": "text",
340
- },
341
- ],
342
- "role": "user",
343
- },
344
- {
345
- "content": [
346
- {
347
- "text": "Hi",
348
- "type": "text",
349
- },
350
- ],
351
- "role": "assistant",
352
- },
353
- {
354
- "content": [
355
- {
356
- "text": "Generate person",
357
- "type": "text",
358
- },
359
- ],
360
- "role": "user",
361
- },
362
- ]
363
- `);
364
- });
365
-
366
- it('should handle case with no schema', () => {
367
- const result = injectJsonInstructionIntoMessages({
368
- messages: [{ role: 'system', content: 'Generate data' }],
369
- });
370
-
371
- expect(result).toMatchInlineSnapshot(`
372
- [
373
- {
374
- "content": "Generate data
375
-
376
- You MUST answer with JSON.",
377
- "role": "system",
378
- },
379
- ]
380
- `);
381
- });
382
-
383
- it('should handle custom schema prefix and suffix', () => {
384
- const result = injectJsonInstructionIntoMessages({
385
- messages: [{ role: 'system', content: 'Generate data' }],
386
- schema: basicSchema,
387
- schemaPrefix: 'Custom schema:',
388
- schemaSuffix: 'Follow this format exactly.',
389
- });
390
-
391
- expect(result).toMatchInlineSnapshot(`
392
- [
393
- {
394
- "content": "Generate data
395
-
396
- Custom schema:
397
- {"type":"object","properties":{"name":{"type":"string"},"age":{"type":"number"}},"required":["name","age"]}
398
- Follow this format exactly.",
399
- "role": "system",
400
- },
401
- ]
402
- `);
403
- });
404
- });
@@ -1,282 +0,0 @@
1
- import { isUrlSupported } from './is-url-supported';
2
- import { describe, expect, it } from 'vitest';
3
-
4
- describe('isUrlSupported', () => {
5
- describe('when the model does not support any URLs', () => {
6
- it('should return false', async () => {
7
- expect(
8
- isUrlSupported({
9
- mediaType: 'text/plain',
10
- url: 'https://example.com',
11
- supportedUrls: {},
12
- }),
13
- ).toBe(false);
14
- });
15
- });
16
-
17
- describe('when the model supports specific media types and URLs', () => {
18
- it('should return true for exact media type and exact URL match', async () => {
19
- expect(
20
- isUrlSupported({
21
- mediaType: 'text/plain',
22
- url: 'https://example.com',
23
- supportedUrls: { 'text/plain': [/https:\/\/example\.com/] },
24
- }),
25
- ).toBe(true);
26
- });
27
-
28
- it('should return true for exact media type and regex URL match', async () => {
29
- expect(
30
- isUrlSupported({
31
- mediaType: 'image/png',
32
- url: 'https://images.example.com/cat.png',
33
- supportedUrls: {
34
- 'image/png': [/https:\/\/images\.example\.com\/.+/],
35
- },
36
- }),
37
- ).toBe(true);
38
- });
39
-
40
- it('should return true for exact media type and one of multiple regex URLs match', async () => {
41
- expect(
42
- isUrlSupported({
43
- mediaType: 'image/png',
44
- url: 'https://another.com/img.png',
45
- supportedUrls: {
46
- 'image/png': [
47
- /https:\/\/images\.example\.com\/.+/,
48
- /https:\/\/another\.com\/img\.png/,
49
- ],
50
- },
51
- }),
52
- ).toBe(true);
53
- });
54
-
55
- it('should return false for exact media type but URL mismatch', async () => {
56
- expect(
57
- isUrlSupported({
58
- mediaType: 'text/plain',
59
- url: 'https://another.com',
60
- supportedUrls: { 'text/plain': [/https:\/\/example\.com/] },
61
- }),
62
- ).toBe(false);
63
- });
64
-
65
- it('should return false for URL match but media type mismatch', async () => {
66
- expect(
67
- isUrlSupported({
68
- mediaType: 'image/png', // Different media type
69
- url: 'https://example.com',
70
- supportedUrls: { 'text/plain': [/https:\/\/example\.com/] },
71
- }),
72
- ).toBe(false);
73
- });
74
- });
75
-
76
- describe('when the model supports URLs via wildcard media type (*)', () => {
77
- it('should return true for wildcard media type and exact URL match', async () => {
78
- expect(
79
- isUrlSupported({
80
- mediaType: 'text/plain',
81
- url: 'https://example.com',
82
- supportedUrls: { '*': [/https:\/\/example\.com/] },
83
- }),
84
- ).toBe(true);
85
- });
86
-
87
- it('should return true for wildcard media type and regex URL match', async () => {
88
- expect(
89
- isUrlSupported({
90
- mediaType: 'image/jpeg',
91
- url: 'https://images.example.com/dog.jpg',
92
- supportedUrls: { '*': [/https:\/\/images\.example\.com\/.+/] },
93
- }),
94
- ).toBe(true);
95
- });
96
-
97
- it('should return false for wildcard media type but URL mismatch', async () => {
98
- expect(
99
- isUrlSupported({
100
- mediaType: 'video/mp4',
101
- url: 'https://another.com',
102
- supportedUrls: { '*': [/https:\/\/example\.com/] },
103
- }),
104
- ).toBe(false);
105
- });
106
- });
107
-
108
- describe('when both specific and wildcard media types are defined', () => {
109
- const supportedUrls = {
110
- 'text/plain': [/https:\/\/text\.com/],
111
- '*': [/https:\/\/any\.com/],
112
- };
113
-
114
- it('should return true if URL matches under specific media type', async () => {
115
- expect(
116
- isUrlSupported({
117
- mediaType: 'text/plain',
118
- url: 'https://text.com',
119
- supportedUrls,
120
- }),
121
- ).toBe(true);
122
- });
123
-
124
- it('should return true if URL matches under wildcard media type even if specific exists', async () => {
125
- // Assumes the logic checks specific first, then falls back to wildcard
126
- expect(
127
- isUrlSupported({
128
- mediaType: 'text/plain', // Specific type exists
129
- url: 'https://any.com', // Matches wildcard
130
- supportedUrls,
131
- }),
132
- ).toBe(true);
133
- });
134
-
135
- it('should return true if URL matches under wildcard for a non-specified media type', async () => {
136
- expect(
137
- isUrlSupported({
138
- mediaType: 'image/png', // No specific entry for this type
139
- url: 'https://any.com', // Matches wildcard
140
- supportedUrls,
141
- }),
142
- ).toBe(true);
143
- });
144
-
145
- it('should return false if URL matches neither specific nor wildcard', async () => {
146
- expect(
147
- isUrlSupported({
148
- mediaType: 'text/plain',
149
- url: 'https://other.com',
150
- supportedUrls,
151
- }),
152
- ).toBe(false);
153
- });
154
-
155
- it('should return false if URL does not match wildcard for a non-specified media type', async () => {
156
- expect(
157
- isUrlSupported({
158
- mediaType: 'image/png',
159
- url: 'https://other.com',
160
- supportedUrls,
161
- }),
162
- ).toBe(false);
163
- });
164
- });
165
-
166
- describe('edge cases', () => {
167
- it('should return true if an empty URL matches a pattern', async () => {
168
- expect(
169
- isUrlSupported({
170
- mediaType: 'text/plain',
171
- url: '',
172
- supportedUrls: { 'text/plain': [/.*/] }, // Matches any string, including empty
173
- }),
174
- ).toBe(true);
175
- });
176
-
177
- it('should return false if an empty URL does not match a pattern', async () => {
178
- expect(
179
- isUrlSupported({
180
- mediaType: 'text/plain',
181
- url: '',
182
- supportedUrls: { 'text/plain': [/https:\/\/.+/] }, // Requires non-empty string
183
- }),
184
- ).toBe(false);
185
- });
186
- });
187
-
188
- describe('case sensitivity', () => {
189
- it('should be case-insensitive for media types', async () => {
190
- expect(
191
- isUrlSupported({
192
- mediaType: 'TEXT/PLAIN', // Uppercase
193
- url: 'https://example.com',
194
- supportedUrls: { 'text/plain': [/https:\/\/example\.com/] }, // Lowercase
195
- }),
196
- ).toBe(true);
197
- });
198
-
199
- it('should handle case-insensitive regex for URLs if specified', async () => {
200
- expect(
201
- isUrlSupported({
202
- mediaType: 'text/plain',
203
- url: 'https://EXAMPLE.com/path', // Uppercase domain
204
- supportedUrls: { 'text/plain': [/https:\/\/example\.com\/path/] },
205
- }),
206
- ).toBe(true);
207
- });
208
-
209
- it('should be case-insensitive for URL paths by default regex', async () => {
210
- expect(
211
- isUrlSupported({
212
- mediaType: 'text/plain',
213
- url: 'https://example.com/PATH', // Uppercase path
214
- supportedUrls: { 'text/plain': [/https:\/\/example\.com\/path/] }, // Lowercase path in regex
215
- }),
216
- ).toBe(true);
217
- });
218
- });
219
-
220
- describe('wildcard subtypes in media types', () => {
221
- it('should return true for wildcard subtype match', async () => {
222
- expect(
223
- isUrlSupported({
224
- mediaType: 'image/png',
225
- url: 'https://example.com',
226
- supportedUrls: { 'image/*': [/https:\/\/example\.com/] },
227
- }),
228
- ).toBe(true);
229
- });
230
-
231
- it('should use full wildcard "*" if subtype wildcard is not matched or supported', async () => {
232
- expect(
233
- isUrlSupported({
234
- mediaType: 'image/png',
235
- url: 'https://any.com',
236
- supportedUrls: {
237
- 'image/*': [/https:\/\/images\.com/], // Doesn't match URL
238
- '*': [/https:\/\/any\.com/], // Matches URL
239
- },
240
- }),
241
- ).toBe(true);
242
- });
243
- });
244
-
245
- describe('empty URL arrays for a media type', () => {
246
- it('should return false if the specific media type has an empty URL array', async () => {
247
- expect(
248
- isUrlSupported({
249
- mediaType: 'text/plain',
250
- url: 'https://example.com',
251
- supportedUrls: { 'text/plain': [] },
252
- }),
253
- ).toBe(false);
254
- });
255
-
256
- it('should fall back to wildcard "*" if specific media type has empty array but wildcard matches', async () => {
257
- expect(
258
- isUrlSupported({
259
- mediaType: 'text/plain',
260
- url: 'https://any.com',
261
- supportedUrls: {
262
- 'text/plain': [],
263
- '*': [/https:\/\/any\.com/],
264
- },
265
- }),
266
- ).toBe(true);
267
- });
268
-
269
- it('should return false if specific media type has empty array and wildcard does not match', async () => {
270
- expect(
271
- isUrlSupported({
272
- mediaType: 'text/plain',
273
- url: 'https://another.com',
274
- supportedUrls: {
275
- 'text/plain': [],
276
- '*': [/https:\/\/any\.com/],
277
- },
278
- }),
279
- ).toBe(false);
280
- });
281
- });
282
- });