@ai-sdk/quiverai 2.0.44 → 2.0.45

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/index.js CHANGED
@@ -11,12 +11,12 @@ import {
11
11
 
12
12
  // src/quiverai-image-model.ts
13
13
  import {
14
- InvalidArgumentError
14
+ InvalidArgumentError as InvalidArgumentError2
15
15
  } from "@ai-sdk/provider";
16
16
  import {
17
17
  combineHeaders,
18
- convertBase64ToUint8Array,
19
- convertUint8ArrayToBase64,
18
+ convertBase64ToUint8Array as convertBase64ToUint8Array2,
19
+ convertUint8ArrayToBase64 as convertUint8ArrayToBase642,
20
20
  createJsonErrorResponseHandler,
21
21
  createJsonResponseHandler,
22
22
  parseProviderOptions,
@@ -44,8 +44,10 @@ var quiveraiImageModelOptionsSchema = lazySchema(
44
44
  * single image in `prompt.images` / `files`.
45
45
  * - `animate`: Animate an input SVG. Requires a single SVG in
46
46
  * `prompt.images` / `files`; the text prompt is optional.
47
+ * - `edit`: Edit a single SVG from `prompt.images` using `prompt.text`
48
+ * as the required instruction.
47
49
  */
48
- operation: z.enum(["generate", "vectorize", "animate"]).optional(),
50
+ operation: z.enum(["generate", "vectorize", "animate", "edit"]).optional(),
49
51
  /**
50
52
  * Extra style guidance for prompt-based generation.
51
53
  */
@@ -54,6 +56,20 @@ var quiveraiImageModelOptionsSchema = lazySchema(
54
56
  * Reasoning effort applied to generation or vectorization.
55
57
  */
56
58
  reasoningEffort: z.enum(["low", "medium", "high", "xhigh"]).optional(),
59
+ /**
60
+ * Optional reference images for SVG editing. Use
61
+ * `prepareQuiverAIImageReference` to convert binary inputs.
62
+ */
63
+ referenceImages: z.array(
64
+ z.union([
65
+ z.object({ url: z.string().min(1) }).strict(),
66
+ z.object({ base64: z.string().min(1).max(16777216) }).strict()
67
+ ])
68
+ ).max(4).optional(),
69
+ /**
70
+ * Maximum number of edit review and redo steps (0-5).
71
+ */
72
+ maxReviewSteps: z.number().int().min(0).max(5).optional(),
57
73
  /**
58
74
  * SVG root attributes requested for generation or vectorization.
59
75
  */
@@ -82,6 +98,14 @@ var quiveraiImageModelOptionsSchema = lazySchema(
82
98
  * The legacy upper bound of 131072 is retained for other model IDs.
83
99
  */
84
100
  maxOutputTokens: z.number().int().min(1).max(131072).optional(),
101
+ /**
102
+ * Provider orchestrator token budget for SVG editing (1-65536).
103
+ */
104
+ orchestratorMaxOutputTokens: z.number().int().min(1).max(65536).optional(),
105
+ /**
106
+ * Provider shallow edit token budget for SVG editing (1-65536).
107
+ */
108
+ shallowMaxOutputTokens: z.number().int().min(1).max(65536).optional(),
85
109
  /**
86
110
  * Whether to auto-crop the input image before vectorization.
87
111
  * Only used when `operation` is `vectorize`.
@@ -96,6 +120,113 @@ var quiveraiImageModelOptionsSchema = lazySchema(
96
120
  )
97
121
  );
98
122
 
123
+ // src/prepare-quiverai-image-reference.ts
124
+ import { InvalidArgumentError } from "@ai-sdk/provider";
125
+ import {
126
+ convertBase64ToUint8Array,
127
+ convertUint8ArrayToBase64,
128
+ detectMediaType
129
+ } from "@ai-sdk/provider-utils";
130
+ var MAX_REFERENCE_BASE64_LENGTH = 16777216;
131
+ var MAX_REFERENCE_BYTES = 12582912;
132
+ var supportedReferenceMediaTypes = /* @__PURE__ */ new Set([
133
+ "image/gif",
134
+ "image/jpeg",
135
+ "image/png",
136
+ "image/svg+xml",
137
+ "image/webp"
138
+ ]);
139
+ function prepareQuiverAIImageReference(input) {
140
+ if (input instanceof URL) {
141
+ return { url: validateQuiverAIImageUrl(input.toString()) };
142
+ }
143
+ if (typeof input === "string") {
144
+ if (/^[a-z][a-z\d+.-]*:\/\//i.test(input)) {
145
+ return { url: validateQuiverAIImageUrl(input) };
146
+ }
147
+ if (input.startsWith("data:")) {
148
+ const match = /^data:([^;,]+);base64,(.+)$/s.exec(input);
149
+ if (match == null || !supportedReferenceMediaTypes.has(match[1])) {
150
+ throw new InvalidArgumentError({
151
+ argument: "input",
152
+ message: "QuiverAI reference image data URLs must use base64 encoding and a supported image media type."
153
+ });
154
+ }
155
+ validateQuiverAIReferenceBase64(match[2], "input");
156
+ return { base64: match[2] };
157
+ }
158
+ validateQuiverAIReferenceBase64(input, "input");
159
+ return { base64: input };
160
+ }
161
+ const data = input instanceof ArrayBuffer ? new Uint8Array(input) : new Uint8Array(input);
162
+ validateQuiverAIReferenceBytes(data, "input");
163
+ return { base64: convertUint8ArrayToBase64(data) };
164
+ }
165
+ function validateQuiverAIImageUrl(url) {
166
+ let parsed;
167
+ try {
168
+ parsed = new URL(url);
169
+ } catch (e) {
170
+ throw new InvalidArgumentError({
171
+ argument: "url",
172
+ message: "QuiverAI image URLs must be valid HTTP or HTTPS URLs."
173
+ });
174
+ }
175
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
176
+ throw new InvalidArgumentError({
177
+ argument: "url",
178
+ message: "QuiverAI image URLs must use HTTP or HTTPS."
179
+ });
180
+ }
181
+ return parsed.toString();
182
+ }
183
+ function validateQuiverAIReferenceBase64(base64, argument) {
184
+ if (base64.length === 0 || base64.length > MAX_REFERENCE_BASE64_LENGTH) {
185
+ throw new InvalidArgumentError({
186
+ argument,
187
+ message: `QuiverAI reference images must contain 1-${MAX_REFERENCE_BASE64_LENGTH} base64 characters.`
188
+ });
189
+ }
190
+ let data;
191
+ try {
192
+ data = convertBase64ToUint8Array(base64);
193
+ } catch (cause) {
194
+ throw new InvalidArgumentError({
195
+ argument,
196
+ message: "QuiverAI reference image data must be valid base64.",
197
+ cause
198
+ });
199
+ }
200
+ validateQuiverAIReferenceBytes(data, argument);
201
+ }
202
+ function validateQuiverAIReferenceBytes(data, argument) {
203
+ if (data.length === 0 || data.length > MAX_REFERENCE_BYTES) {
204
+ throw new InvalidArgumentError({
205
+ argument,
206
+ message: `QuiverAI reference images must decode to 1-${MAX_REFERENCE_BYTES} bytes.`
207
+ });
208
+ }
209
+ const mediaType = isSvg(data) ? "image/svg+xml" : detectMediaType({ data, topLevelType: "image" });
210
+ if (mediaType == null || !supportedReferenceMediaTypes.has(mediaType)) {
211
+ throw new InvalidArgumentError({
212
+ argument,
213
+ message: "QuiverAI reference images must be PNG, JPEG, WebP, GIF, or SVG data."
214
+ });
215
+ }
216
+ }
217
+ function isSvg(data) {
218
+ let text;
219
+ try {
220
+ text = new TextDecoder("utf-8", { fatal: true }).decode(data);
221
+ } catch (e) {
222
+ return false;
223
+ }
224
+ const normalized = text.replace(/^\uFEFF/, "").trim();
225
+ return /^(?:<\?xml[\s\S]*?\?>\s*)?(?:<!--[\s\S]*?-->\s*)?(?:<!DOCTYPE[\s\S]*?>\s*)?<svg[\s>]/i.test(
226
+ normalized
227
+ ) && (/<\/svg>\s*$/i.test(normalized) || /<svg(?:\s[^>]*)?\/>\s*$/is.test(normalized));
228
+ }
229
+
99
230
  // src/quiverai-image-model.ts
100
231
  var QuiverAIImageModel = class _QuiverAIImageModel {
101
232
  constructor(modelId, config) {
@@ -199,6 +330,8 @@ function getOperationPath(operation) {
199
330
  return "/svgs/generations";
200
331
  case "vectorize":
201
332
  return "/svgs/vectorizations";
333
+ case "edit":
334
+ return "/svgs/edits";
202
335
  case "animate":
203
336
  return "/svgs/animations";
204
337
  }
@@ -211,7 +344,7 @@ function toQuiverAIImageReference(image) {
211
344
  return { url: image.url };
212
345
  }
213
346
  return {
214
- base64: typeof image.data === "string" ? image.data : convertUint8ArrayToBase64(image.data)
347
+ base64: typeof image.data === "string" ? image.data : convertUint8ArrayToBase642(image.data)
215
348
  };
216
349
  }
217
350
  var maxAnimationSourceBase64Length = 1066668;
@@ -222,13 +355,13 @@ function toQuiverAIAnimationSource(image) {
222
355
  try {
223
356
  url = new URL(image.url);
224
357
  } catch (e) {
225
- throw new InvalidArgumentError({
358
+ throw new InvalidArgumentError2({
226
359
  argument: "files",
227
360
  message: "QuiverAI animate requires a valid HTTP or HTTPS SVG URL."
228
361
  });
229
362
  }
230
363
  if (url.protocol !== "http:" && url.protocol !== "https:") {
231
- throw new InvalidArgumentError({
364
+ throw new InvalidArgumentError2({
232
365
  argument: "files",
233
366
  message: "QuiverAI animate requires an HTTP or HTTPS SVG URL."
234
367
  });
@@ -241,33 +374,33 @@ function toQuiverAIAnimationSource(image) {
241
374
  const dataUrlMatch = /^data:image\/svg\+xml(?:;[^,]*)?;base64,([\s\S]+)$/i.exec(image.data);
242
375
  const encodedData = (_a = dataUrlMatch == null ? void 0 : dataUrlMatch[1]) != null ? _a : image.data;
243
376
  try {
244
- bytes = convertBase64ToUint8Array(encodedData);
377
+ bytes = convertBase64ToUint8Array2(encodedData);
245
378
  } catch (e) {
246
- throw new InvalidArgumentError({
379
+ throw new InvalidArgumentError2({
247
380
  argument: "files",
248
381
  message: "QuiverAI animate requires the source SVG string to be valid base64 or an SVG data URL."
249
382
  });
250
383
  }
251
- base64 = convertUint8ArrayToBase64(bytes);
384
+ base64 = convertUint8ArrayToBase642(bytes);
252
385
  } else {
253
386
  bytes = image.data;
254
- base64 = convertUint8ArrayToBase64(bytes);
387
+ base64 = convertUint8ArrayToBase642(bytes);
255
388
  }
256
- if (!isSvg(bytes)) {
257
- throw new InvalidArgumentError({
389
+ if (!isSvg2(bytes)) {
390
+ throw new InvalidArgumentError2({
258
391
  argument: "files",
259
392
  message: "QuiverAI animate requires the input file to contain SVG data."
260
393
  });
261
394
  }
262
395
  if (base64.length > maxAnimationSourceBase64Length) {
263
- throw new InvalidArgumentError({
396
+ throw new InvalidArgumentError2({
264
397
  argument: "files",
265
398
  message: `QuiverAI animate accepts at most ${maxAnimationSourceBase64Length} base64 characters for the source SVG.`
266
399
  });
267
400
  }
268
401
  return { base64 };
269
402
  }
270
- function isSvg(data) {
403
+ function isSvg2(data) {
271
404
  const head = new TextDecoder("utf-8", { fatal: false }).decode(data.subarray(0, 4096)).trimStart();
272
405
  return /^(?:(?:<\?xml[\s\S]*?\?>|<!--[\s\S]*?-->|<!DOCTYPE[\s\S]*?>)\s*)*<svg(?:\s|>)/i.test(
273
406
  head
@@ -283,7 +416,7 @@ function buildRequestBody({
283
416
  options
284
417
  }) {
285
418
  if ((modelId === "arrow-2" || modelId === "arrow-2-telos") && options.maxOutputTokens != null && options.maxOutputTokens > 65536) {
286
- throw new InvalidArgumentError({
419
+ throw new InvalidArgumentError2({
287
420
  argument: "maxOutputTokens",
288
421
  message: `QuiverAI model "${modelId}" supports at most 65536 output tokens.`
289
422
  });
@@ -297,9 +430,12 @@ function buildRequestBody({
297
430
  attributes: options.attributes,
298
431
  stream: false
299
432
  };
433
+ if (operation !== "edit") {
434
+ rejectEditOnlyOptions(operation, options);
435
+ }
300
436
  if (operation === "generate") {
301
437
  if (prompt == null || prompt.trim().length === 0) {
302
- throw new InvalidArgumentError({
438
+ throw new InvalidArgumentError2({
303
439
  argument: "prompt",
304
440
  message: "QuiverAI image generation requires a non-empty prompt for generateImage."
305
441
  });
@@ -307,7 +443,7 @@ function buildRequestBody({
307
443
  const references = files == null ? void 0 : files.map(toQuiverAIImageReference);
308
444
  const maxReferences = getGenerateReferenceLimit(modelId);
309
445
  if (references != null && references.length > maxReferences) {
310
- throw new InvalidArgumentError({
446
+ throw new InvalidArgumentError2({
311
447
  argument: "files",
312
448
  message: `QuiverAI generate supports up to ${maxReferences} reference images for model "${modelId}".`
313
449
  });
@@ -321,6 +457,16 @@ function buildRequestBody({
321
457
  references
322
458
  };
323
459
  }
460
+ if (operation === "edit") {
461
+ return buildEditRequestBody({
462
+ modelId,
463
+ n,
464
+ prompt,
465
+ files,
466
+ mask,
467
+ options
468
+ });
469
+ }
324
470
  if (operation === "animate") {
325
471
  return buildAnimationRequestBody({
326
472
  modelId,
@@ -332,19 +478,19 @@ function buildRequestBody({
332
478
  });
333
479
  }
334
480
  if (files == null || files.length === 0) {
335
- throw new InvalidArgumentError({
481
+ throw new InvalidArgumentError2({
336
482
  argument: "files",
337
483
  message: 'QuiverAI vectorize requires an input image. Pass an image in the generateImage prompt and set providerOptions.quiverai.operation to "vectorize".'
338
484
  });
339
485
  }
340
486
  if (files.length > 1) {
341
- throw new InvalidArgumentError({
487
+ throw new InvalidArgumentError2({
342
488
  argument: "files",
343
489
  message: "QuiverAI vectorize accepts a single input image."
344
490
  });
345
491
  }
346
492
  if (n !== 1) {
347
- throw new InvalidArgumentError({
493
+ throw new InvalidArgumentError2({
348
494
  argument: "n",
349
495
  message: "QuiverAI vectorize returns one SVG per request. Set maxImagesPerCall to 1 in generateImage to vectorize multiple times."
350
496
  });
@@ -366,37 +512,37 @@ function buildAnimationRequestBody({
366
512
  options
367
513
  }) {
368
514
  if (modelId !== "arrow-2" && modelId !== "arrow-2-telos") {
369
- throw new InvalidArgumentError({
515
+ throw new InvalidArgumentError2({
370
516
  argument: "modelId",
371
517
  message: 'QuiverAI animate is supported by the "arrow-2" and "arrow-2-telos" models.'
372
518
  });
373
519
  }
374
520
  if (files == null || files.length === 0) {
375
- throw new InvalidArgumentError({
521
+ throw new InvalidArgumentError2({
376
522
  argument: "files",
377
523
  message: "QuiverAI animate requires exactly one source SVG in prompt.images."
378
524
  });
379
525
  }
380
526
  if (files.length !== 1) {
381
- throw new InvalidArgumentError({
527
+ throw new InvalidArgumentError2({
382
528
  argument: "files",
383
529
  message: "QuiverAI animate accepts exactly one source SVG in prompt.images."
384
530
  });
385
531
  }
386
532
  if (n !== 1) {
387
- throw new InvalidArgumentError({
533
+ throw new InvalidArgumentError2({
388
534
  argument: "n",
389
535
  message: "QuiverAI animate returns one SVG per request. Set maxImagesPerCall to 1 in generateImage to animate multiple times."
390
536
  });
391
537
  }
392
538
  if (mask != null) {
393
- throw new InvalidArgumentError({
539
+ throw new InvalidArgumentError2({
394
540
  argument: "mask",
395
541
  message: "QuiverAI animate does not support masks."
396
542
  });
397
543
  }
398
544
  if (prompt != null && prompt.trim().length === 0) {
399
- throw new InvalidArgumentError({
545
+ throw new InvalidArgumentError2({
400
546
  argument: "prompt",
401
547
  message: "QuiverAI animate requires a non-empty prompt when an animation instruction is provided."
402
548
  });
@@ -412,7 +558,7 @@ function buildAnimationRequestBody({
412
558
  return option[1] !== void 0;
413
559
  });
414
560
  if (unsupportedOptions.length > 0) {
415
- throw new InvalidArgumentError({
561
+ throw new InvalidArgumentError2({
416
562
  argument: `providerOptions.quiverai.${unsupportedOptions[0][0]}`,
417
563
  message: `QuiverAI animate does not support providerOptions.quiverai.${unsupportedOptions[0][0]}.`
418
564
  });
@@ -427,6 +573,384 @@ function buildAnimationRequestBody({
427
573
  stream: false
428
574
  };
429
575
  }
576
+ var editModelIds = /* @__PURE__ */ new Set(["arrow-2", "arrow-2-telos"]);
577
+ var MAX_EDIT_SVG_BYTES = 2e5;
578
+ function buildEditRequestBody({
579
+ modelId,
580
+ n,
581
+ prompt,
582
+ files,
583
+ mask,
584
+ options
585
+ }) {
586
+ var _a;
587
+ if (!editModelIds.has(modelId)) {
588
+ throw new InvalidArgumentError2({
589
+ argument: "modelId",
590
+ message: 'QuiverAI SVG editing is supported by the "arrow-2" and "arrow-2-telos" models.'
591
+ });
592
+ }
593
+ if (prompt == null || prompt.trim().length === 0) {
594
+ throw new InvalidArgumentError2({
595
+ argument: "prompt",
596
+ message: "QuiverAI SVG editing requires a non-empty instruction in generateImage prompt.text."
597
+ });
598
+ }
599
+ if (prompt.length > 4e3) {
600
+ throw new InvalidArgumentError2({
601
+ argument: "prompt",
602
+ message: "QuiverAI SVG editing instructions must contain at most 4000 characters."
603
+ });
604
+ }
605
+ if (files == null || files.length === 0) {
606
+ throw new InvalidArgumentError2({
607
+ argument: "files",
608
+ message: "QuiverAI SVG editing requires one source SVG in generateImage prompt.images."
609
+ });
610
+ }
611
+ if (files.length !== 1) {
612
+ throw new InvalidArgumentError2({
613
+ argument: "files",
614
+ message: "QuiverAI SVG editing accepts exactly one source SVG."
615
+ });
616
+ }
617
+ if (n !== 1) {
618
+ throw new InvalidArgumentError2({
619
+ argument: "n",
620
+ message: "QuiverAI SVG editing returns exactly one SVG per request. Set maxImagesPerCall to 1 in generateImage to edit multiple times."
621
+ });
622
+ }
623
+ if (mask != null) {
624
+ throw new InvalidArgumentError2({
625
+ argument: "mask",
626
+ message: "QuiverAI SVG editing does not support masks."
627
+ });
628
+ }
629
+ const unsupportedOptions = [
630
+ ["instructions", options.instructions],
631
+ ["attributes", options.attributes],
632
+ ["topP", options.topP],
633
+ ["presencePenalty", options.presencePenalty],
634
+ ["autoCrop", options.autoCrop],
635
+ ["targetSize", options.targetSize]
636
+ ].flatMap(([name, value]) => value == null ? [] : [name]);
637
+ if (unsupportedOptions.length > 0) {
638
+ throw new InvalidArgumentError2({
639
+ argument: "providerOptions",
640
+ message: `QuiverAI SVG editing does not support these provider options: ${unsupportedOptions.join(
641
+ ", "
642
+ )}.`
643
+ });
644
+ }
645
+ const referenceImages = (_a = options.referenceImages) == null ? void 0 : _a.map((reference, index) => {
646
+ if ("url" in reference) {
647
+ return {
648
+ url: validateQuiverAIImageUrl(reference.url)
649
+ };
650
+ }
651
+ validateQuiverAIReferenceBase64(
652
+ reference.base64,
653
+ `providerOptions.quiverai.referenceImages[${index}]`
654
+ );
655
+ return { base64: reference.base64 };
656
+ });
657
+ const settings = {
658
+ max_output_tokens: options.maxOutputTokens,
659
+ orchestrator_max_output_tokens: options.orchestratorMaxOutputTokens,
660
+ shallow_max_output_tokens: options.shallowMaxOutputTokens,
661
+ temperature: options.temperature
662
+ };
663
+ const hasSettings = Object.values(settings).some((value) => value != null);
664
+ return {
665
+ model: modelId,
666
+ prompt,
667
+ ...toQuiverAIEditSource(files[0]),
668
+ reference_images: referenceImages,
669
+ max_review_steps: options.maxReviewSteps,
670
+ reasoning_effort: options.reasoningEffort,
671
+ ...hasSettings && { settings },
672
+ stream: false
673
+ };
674
+ }
675
+ function rejectEditOnlyOptions(operation, options) {
676
+ const editOnlyOptions = [
677
+ ["referenceImages", options.referenceImages],
678
+ ["maxReviewSteps", options.maxReviewSteps],
679
+ ["orchestratorMaxOutputTokens", options.orchestratorMaxOutputTokens],
680
+ ["shallowMaxOutputTokens", options.shallowMaxOutputTokens]
681
+ ].flatMap(([name, value]) => value == null ? [] : [name]);
682
+ if (editOnlyOptions.length > 0) {
683
+ throw new InvalidArgumentError2({
684
+ argument: "providerOptions",
685
+ message: `QuiverAI ${operation} does not support these edit-only provider options: ${editOnlyOptions.join(
686
+ ", "
687
+ )}.`
688
+ });
689
+ }
690
+ }
691
+ function toQuiverAIEditSource(file) {
692
+ if (file.type === "url") {
693
+ return {
694
+ svg_source: {
695
+ url: validateQuiverAIImageUrl(file.url)
696
+ }
697
+ };
698
+ }
699
+ let data;
700
+ try {
701
+ data = typeof file.data === "string" ? convertBase64ToUint8Array2(file.data) : file.data;
702
+ } catch (cause) {
703
+ throw new InvalidArgumentError2({
704
+ argument: "files",
705
+ message: "QuiverAI SVG source data must be valid base64 or binary data.",
706
+ cause
707
+ });
708
+ }
709
+ if (data.length === 0 || data.length > MAX_EDIT_SVG_BYTES) {
710
+ throw new InvalidArgumentError2({
711
+ argument: "files",
712
+ message: `QuiverAI SVG source data must contain 1-${MAX_EDIT_SVG_BYTES} bytes.`
713
+ });
714
+ }
715
+ let svg;
716
+ try {
717
+ svg = new TextDecoder("utf-8", { fatal: true }).decode(data);
718
+ } catch (cause) {
719
+ throw new InvalidArgumentError2({
720
+ argument: "files",
721
+ message: "QuiverAI SVG source data must be valid UTF-8.",
722
+ cause
723
+ });
724
+ }
725
+ if (svg.length > MAX_EDIT_SVG_BYTES || !isSvgMarkup(svg)) {
726
+ throw new InvalidArgumentError2({
727
+ argument: "files",
728
+ message: "QuiverAI SVG source data must contain a complete SVG document."
729
+ });
730
+ }
731
+ return {
732
+ svg_source: {
733
+ base64: convertUint8ArrayToBase642(data)
734
+ }
735
+ };
736
+ }
737
+ function isSvgMarkup(svg) {
738
+ var _a;
739
+ const document = svg.replace(/^\uFEFF/, "");
740
+ const elements = [];
741
+ let position = 0;
742
+ let rootSeen = false;
743
+ let rootClosed = false;
744
+ let doctypeSeen = false;
745
+ while (position < document.length) {
746
+ if (document[position] !== "<") {
747
+ const nextTag = document.indexOf("<", position);
748
+ const end = nextTag === -1 ? document.length : nextTag;
749
+ const text = document.slice(position, end);
750
+ if (elements.length === 0 && text.trim().length > 0 || text.includes("]]>") || !hasValidXmlReferences(text)) {
751
+ return false;
752
+ }
753
+ position = end;
754
+ continue;
755
+ }
756
+ if (document.startsWith("<!--", position)) {
757
+ const commentEnd = document.indexOf("-->", position + 4);
758
+ if (commentEnd === -1 || document.slice(position + 4, commentEnd).includes("--")) {
759
+ return false;
760
+ }
761
+ position = commentEnd + 3;
762
+ continue;
763
+ }
764
+ if (document.startsWith("<?", position)) {
765
+ const instructionEnd = document.indexOf("?>", position + 2);
766
+ if (instructionEnd === -1) {
767
+ return false;
768
+ }
769
+ position = instructionEnd + 2;
770
+ continue;
771
+ }
772
+ if (document.startsWith("<![CDATA[", position)) {
773
+ if (elements.length === 0) {
774
+ return false;
775
+ }
776
+ const cdataEnd = document.indexOf("]]>", position + 9);
777
+ if (cdataEnd === -1) {
778
+ return false;
779
+ }
780
+ position = cdataEnd + 3;
781
+ continue;
782
+ }
783
+ if (document.slice(position, position + 9).toUpperCase() === "<!DOCTYPE") {
784
+ if (rootSeen || doctypeSeen || elements.length > 0 || !/[\t\n\r ]/.test((_a = document[position + 9]) != null ? _a : "")) {
785
+ return false;
786
+ }
787
+ const doctypeName = readXmlName(
788
+ document,
789
+ skipXmlWhitespace(document, position + 9)
790
+ );
791
+ if ((doctypeName == null ? void 0 : doctypeName.name.toLowerCase()) !== "svg") {
792
+ return false;
793
+ }
794
+ const doctypeEnd = findDoctypeEnd(document, doctypeName.end);
795
+ if (doctypeEnd === -1) {
796
+ return false;
797
+ }
798
+ doctypeSeen = true;
799
+ position = doctypeEnd;
800
+ continue;
801
+ }
802
+ if (document.startsWith("<!", position)) {
803
+ return false;
804
+ }
805
+ if (document.startsWith("</", position)) {
806
+ const closingTag = readXmlName(document, position + 2);
807
+ if (closingTag == null) {
808
+ return false;
809
+ }
810
+ let tagEnd = skipXmlWhitespace(document, closingTag.end);
811
+ if (document[tagEnd] !== ">") {
812
+ return false;
813
+ }
814
+ const expectedTag = elements.pop();
815
+ if (expectedTag !== closingTag.name) {
816
+ return false;
817
+ }
818
+ tagEnd += 1;
819
+ if (elements.length === 0) {
820
+ rootClosed = true;
821
+ }
822
+ position = tagEnd;
823
+ continue;
824
+ }
825
+ if (rootClosed) {
826
+ return false;
827
+ }
828
+ const openingTag = readXmlName(document, position + 1);
829
+ if (openingTag == null) {
830
+ return false;
831
+ }
832
+ if (!rootSeen) {
833
+ if (openingTag.name.toLowerCase() !== "svg") {
834
+ return false;
835
+ }
836
+ rootSeen = true;
837
+ }
838
+ const attributes = /* @__PURE__ */ new Set();
839
+ let tagPosition = openingTag.end;
840
+ while (tagPosition < document.length) {
841
+ const beforeWhitespace = tagPosition;
842
+ tagPosition = skipXmlWhitespace(document, tagPosition);
843
+ if (document.startsWith("/>", tagPosition)) {
844
+ tagPosition += 2;
845
+ if (elements.length === 0) {
846
+ rootClosed = true;
847
+ }
848
+ position = tagPosition;
849
+ break;
850
+ }
851
+ if (document[tagPosition] === ">") {
852
+ elements.push(openingTag.name);
853
+ position = tagPosition + 1;
854
+ break;
855
+ }
856
+ if (tagPosition === beforeWhitespace) {
857
+ return false;
858
+ }
859
+ const attribute = readXmlName(document, tagPosition);
860
+ if (attribute == null || attributes.has(attribute.name)) {
861
+ return false;
862
+ }
863
+ attributes.add(attribute.name);
864
+ tagPosition = skipXmlWhitespace(document, attribute.end);
865
+ if (document[tagPosition] !== "=") {
866
+ return false;
867
+ }
868
+ tagPosition = skipXmlWhitespace(document, tagPosition + 1);
869
+ const quote = document[tagPosition];
870
+ if (quote !== '"' && quote !== "'") {
871
+ return false;
872
+ }
873
+ const valueEnd = document.indexOf(quote, tagPosition + 1);
874
+ if (valueEnd === -1 || document.slice(tagPosition + 1, valueEnd).includes("<") || !hasValidXmlReferences(document.slice(tagPosition + 1, valueEnd))) {
875
+ return false;
876
+ }
877
+ tagPosition = valueEnd + 1;
878
+ }
879
+ if (tagPosition >= document.length && position !== document.length) {
880
+ return false;
881
+ }
882
+ }
883
+ return rootSeen && rootClosed && elements.length === 0;
884
+ }
885
+ function isXmlNameStart(character) {
886
+ return character != null && /[A-Z_a-z:\u0080-\uFFFF]/.test(character);
887
+ }
888
+ function isXmlNameCharacter(character) {
889
+ return character != null && /[-.0-9A-Z_a-z:\u00B7\u0080-\uFFFF]/.test(character);
890
+ }
891
+ function readXmlName(value, position) {
892
+ if (!isXmlNameStart(value[position])) {
893
+ return void 0;
894
+ }
895
+ const start = position;
896
+ position += 1;
897
+ while (isXmlNameCharacter(value[position])) {
898
+ position += 1;
899
+ }
900
+ return {
901
+ name: value.slice(start, position),
902
+ end: position
903
+ };
904
+ }
905
+ function skipXmlWhitespace(value, position) {
906
+ var _a;
907
+ while (/[\t\n\r ]/.test((_a = value[position]) != null ? _a : "")) {
908
+ position += 1;
909
+ }
910
+ return position;
911
+ }
912
+ function hasValidXmlReferences(value) {
913
+ let position = value.indexOf("&");
914
+ while (position !== -1) {
915
+ const end = value.indexOf(";", position + 1);
916
+ if (end === -1) {
917
+ return false;
918
+ }
919
+ const reference = value.slice(position + 1, end);
920
+ if (!/^#\d+$/.test(reference) && !/^#x[\dA-Fa-f]+$/.test(reference) && !/^[A-Z_a-z:\u0080-\uFFFF][-.0-9A-Z_a-z:\u00B7\u0080-\uFFFF]*$/.test(
921
+ reference
922
+ )) {
923
+ return false;
924
+ }
925
+ position = value.indexOf("&", end + 1);
926
+ }
927
+ return true;
928
+ }
929
+ function findDoctypeEnd(value, position) {
930
+ let subsetDepth = 0;
931
+ let quote;
932
+ while (position < value.length) {
933
+ const character = value[position];
934
+ if (quote != null) {
935
+ if (character === quote) {
936
+ quote = void 0;
937
+ }
938
+ } else if (character === '"' || character === "'") {
939
+ quote = character;
940
+ } else if (character === "[") {
941
+ subsetDepth += 1;
942
+ } else if (character === "]") {
943
+ if (subsetDepth === 0) {
944
+ return -1;
945
+ }
946
+ subsetDepth -= 1;
947
+ } else if (character === ">" && subsetDepth === 0) {
948
+ return position + 1;
949
+ }
950
+ position += 1;
951
+ }
952
+ return -1;
953
+ }
430
954
  function collectWarnings({
431
955
  size,
432
956
  aspectRatio,
@@ -495,7 +1019,7 @@ var quiveraiFailedResponseHandler = createJsonErrorResponseHandler({
495
1019
  });
496
1020
 
497
1021
  // src/version.ts
498
- var VERSION = true ? "2.0.44" : "0.0.0-test";
1022
+ var VERSION = true ? "2.0.45" : "0.0.0-test";
499
1023
 
500
1024
  // src/quiverai-provider.ts
501
1025
  var defaultBaseURL = "https://api.quiver.ai/v1";
@@ -548,6 +1072,7 @@ var quiverai = createQuiverAI();
548
1072
  export {
549
1073
  VERSION,
550
1074
  createQuiverAI,
1075
+ prepareQuiverAIImageReference,
551
1076
  quiverai
552
1077
  };
553
1078
  //# sourceMappingURL=index.js.map