@ai-sdk/provider-utils 4.0.8 → 4.0.9

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 (55) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/index.js +1 -1
  3. package/dist/index.mjs +1 -1
  4. package/package.json +6 -2
  5. package/src/__snapshots__/schema.test.ts.snap +0 -346
  6. package/src/add-additional-properties-to-json-schema.test.ts +0 -289
  7. package/src/convert-async-iterator-to-readable-stream.test.ts +0 -78
  8. package/src/convert-image-model-file-to-data-uri.test.ts +0 -85
  9. package/src/convert-to-form-data.test.ts +0 -167
  10. package/src/create-tool-name-mapping.test.ts +0 -163
  11. package/src/delay.test.ts +0 -212
  12. package/src/delayed-promise.test.ts +0 -132
  13. package/src/download-blob.test.ts +0 -145
  14. package/src/generate-id.test.ts +0 -31
  15. package/src/get-from-api.test.ts +0 -199
  16. package/src/get-runtime-environment-user-agent.test.ts +0 -47
  17. package/src/inject-json-instruction.test.ts +0 -404
  18. package/src/is-url-supported.test.ts +0 -282
  19. package/src/media-type-to-extension.test.ts +0 -26
  20. package/src/normalize-headers.test.ts +0 -64
  21. package/src/parse-json.test.ts +0 -191
  22. package/src/remove-undefined-entries.test.ts +0 -57
  23. package/src/resolve.test.ts +0 -125
  24. package/src/response-handler.test.ts +0 -89
  25. package/src/schema.test-d.ts +0 -11
  26. package/src/schema.test.ts +0 -502
  27. package/src/secure-json-parse.test.ts +0 -59
  28. package/src/to-json-schema/zod3-to-json-schema/parse-def.test.ts +0 -224
  29. package/src/to-json-schema/zod3-to-json-schema/parsers/array.test.ts +0 -98
  30. package/src/to-json-schema/zod3-to-json-schema/parsers/bigint.test.ts +0 -51
  31. package/src/to-json-schema/zod3-to-json-schema/parsers/branded.test.ts +0 -16
  32. package/src/to-json-schema/zod3-to-json-schema/parsers/catch.test.ts +0 -15
  33. package/src/to-json-schema/zod3-to-json-schema/parsers/date.test.ts +0 -97
  34. package/src/to-json-schema/zod3-to-json-schema/parsers/default.test.ts +0 -54
  35. package/src/to-json-schema/zod3-to-json-schema/parsers/effects.test.ts +0 -41
  36. package/src/to-json-schema/zod3-to-json-schema/parsers/intersection.test.ts +0 -92
  37. package/src/to-json-schema/zod3-to-json-schema/parsers/map.test.ts +0 -48
  38. package/src/to-json-schema/zod3-to-json-schema/parsers/native-enum.test.ts +0 -102
  39. package/src/to-json-schema/zod3-to-json-schema/parsers/nullable.test.ts +0 -67
  40. package/src/to-json-schema/zod3-to-json-schema/parsers/number.test.ts +0 -65
  41. package/src/to-json-schema/zod3-to-json-schema/parsers/object.test.ts +0 -149
  42. package/src/to-json-schema/zod3-to-json-schema/parsers/optional.test.ts +0 -147
  43. package/src/to-json-schema/zod3-to-json-schema/parsers/pipe.test.ts +0 -35
  44. package/src/to-json-schema/zod3-to-json-schema/parsers/promise.test.ts +0 -15
  45. package/src/to-json-schema/zod3-to-json-schema/parsers/readonly.test.ts +0 -20
  46. package/src/to-json-schema/zod3-to-json-schema/parsers/record.test.ts +0 -108
  47. package/src/to-json-schema/zod3-to-json-schema/parsers/set.test.ts +0 -20
  48. package/src/to-json-schema/zod3-to-json-schema/parsers/string.test.ts +0 -438
  49. package/src/to-json-schema/zod3-to-json-schema/parsers/tuple.test.ts +0 -33
  50. package/src/to-json-schema/zod3-to-json-schema/parsers/union.test.ts +0 -226
  51. package/src/to-json-schema/zod3-to-json-schema/refs.test.ts +0 -919
  52. package/src/to-json-schema/zod3-to-json-schema/zod3-to-json-schema.test.ts +0 -862
  53. package/src/types/tool.test-d.ts +0 -228
  54. package/src/validate-types.test.ts +0 -105
  55. 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
- });