@assistant-ui/core 0.3.3 → 0.3.4
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/internal.d.ts +4 -2
- package/dist/internal.js +4 -2
- package/dist/react/primitive-hooks/useSuggestionTrigger.js +29 -25
- package/dist/react/primitive-hooks/useSuggestionTrigger.js.map +1 -1
- package/dist/react/primitives/message/MessageParts.d.ts +6 -1
- package/dist/react/primitives/message/MessageParts.d.ts.map +1 -1
- package/dist/react/primitives/message/MessageParts.js.map +1 -1
- package/dist/react/providers/ReadonlyThreadProvider.d.ts.map +1 -1
- package/dist/react/providers/ReadonlyThreadProvider.js +1 -0
- package/dist/react/providers/ReadonlyThreadProvider.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts +67 -0
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js +76 -15
- package/dist/react/runtimes/RemoteThreadListHookInstanceManager.js.map +1 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts +4 -0
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js +21 -0
- package/dist/react/runtimes/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
- package/dist/react/runtimes/cloud/auiV0.d.ts +2 -0
- package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/auiV0.js +6 -4
- package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
- package/dist/react/types/MessagePartComponentTypes.d.ts +8 -0
- package/dist/react/types/MessagePartComponentTypes.d.ts.map +1 -1
- package/dist/runtime/api/bindings.d.ts +5 -0
- package/dist/runtime/api/bindings.d.ts.map +1 -1
- package/dist/runtime/api/thread-list-runtime.d.ts +14 -1
- package/dist/runtime/api/thread-list-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-list-runtime.js +6 -1
- package/dist/runtime/api/thread-list-runtime.js.map +1 -1
- package/dist/runtime/api/thread-runtime.d.ts +7 -1
- package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-runtime.js +11 -3
- package/dist/runtime/api/thread-runtime.js.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.d.ts +3 -0
- package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.js +54 -12
- package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
- package/dist/runtime/interfaces/thread-list-runtime-core.d.ts +10 -0
- package/dist/runtime/interfaces/thread-list-runtime-core.d.ts.map +1 -1
- package/dist/runtime/interfaces/thread-runtime-core.d.ts +14 -0
- package/dist/runtime/interfaces/thread-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-adapter.d.ts +9 -0
- package/dist/runtimes/external-store/external-store-adapter.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts +1 -0
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js +4 -0
- package/dist/runtimes/external-store/external-store-thread-list-runtime-core.js.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts +1 -0
- package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-runtime-core.js +6 -0
- package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
- package/dist/runtimes/local/local-thread-runtime-core.d.ts +1 -0
- package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/local/local-thread-runtime-core.js +1 -0
- package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
- package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts +1 -0
- package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.d.ts.map +1 -1
- package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js +1 -0
- package/dist/runtimes/readonly/ReadonlyThreadRuntimeCore.js.map +1 -1
- package/dist/runtimes/remote-thread-list/empty-thread-core.js +1 -0
- package/dist/runtimes/remote-thread-list/empty-thread-core.js.map +1 -1
- package/dist/store/runtime-clients/thread-list-item-runtime-client.d.ts +1 -0
- package/dist/store/runtime-clients/thread-list-item-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/thread-list-item-runtime-client.js +66 -45
- package/dist/store/runtime-clients/thread-list-item-runtime-client.js.map +1 -1
- package/dist/store/runtime-clients/thread-list-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/thread-list-runtime-client.js +91 -75
- package/dist/store/runtime-clients/thread-list-runtime-client.js.map +1 -1
- package/dist/store/scopes/thread-list-item.d.ts +7 -0
- package/dist/store/scopes/thread-list-item.d.ts.map +1 -1
- package/dist/store/scopes/threads.d.ts +1 -0
- package/dist/store/scopes/threads.d.ts.map +1 -1
- package/dist/types/message.d.ts +11 -0
- package/dist/types/message.d.ts.map +1 -1
- package/dist/types/message.js.map +1 -1
- package/dist/utils/data-url.d.ts +14 -1
- package/dist/utils/data-url.d.ts.map +1 -1
- package/dist/utils/data-url.js +23 -1
- package/dist/utils/data-url.js.map +1 -1
- package/dist/utils/image-media-type.d.ts +13 -0
- package/dist/utils/image-media-type.d.ts.map +1 -0
- package/dist/utils/image-media-type.js +141 -0
- package/dist/utils/image-media-type.js.map +1 -0
- package/dist/utils/wire-media.d.ts +35 -0
- package/dist/utils/wire-media.d.ts.map +1 -0
- package/dist/utils/wire-media.js +55 -0
- package/dist/utils/wire-media.js.map +1 -0
- package/package.json +3 -3
- package/src/internal.ts +12 -1
- package/src/react/primitive-hooks/useSuggestionTrigger.test.ts +148 -0
- package/src/react/primitive-hooks/useSuggestionTrigger.ts +10 -4
- package/src/react/primitives/message/MessageParts.tsx +6 -1
- package/src/react/providers/ReadonlyThreadProvider.tsx +1 -0
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.running.test.tsx +157 -0
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.test.tsx +160 -0
- package/src/react/runtimes/RemoteThreadListHookInstanceManager.tsx +135 -32
- package/src/react/runtimes/RemoteThreadListThreadListRuntimeCore.tsx +37 -0
- package/src/react/runtimes/cloud/auiV0.ts +8 -2
- package/src/react/types/MessagePartComponentTypes.ts +8 -0
- package/src/runtime/api/bindings.ts +5 -0
- package/src/runtime/api/thread-list-runtime.ts +22 -1
- package/src/runtime/api/thread-runtime.ts +15 -6
- package/src/runtime/base/base-composer-runtime-core.ts +72 -19
- package/src/runtime/interfaces/thread-list-runtime-core.ts +11 -0
- package/src/runtime/interfaces/thread-runtime-core.ts +15 -0
- package/src/runtimes/external-store/external-store-adapter.ts +9 -0
- package/src/runtimes/external-store/external-store-thread-list-runtime-core.ts +9 -0
- package/src/runtimes/external-store/external-store-thread-runtime-core.ts +8 -0
- package/src/runtimes/local/local-thread-runtime-core.ts +1 -0
- package/src/runtimes/readonly/ReadonlyThreadRuntimeCore.ts +1 -0
- package/src/runtimes/remote-thread-list/empty-thread-core.ts +1 -0
- package/src/store/runtime-clients/thread-list-item-runtime-client.ts +13 -2
- package/src/store/runtime-clients/thread-list-runtime-client.ts +13 -1
- package/src/store/scopes/thread-list-item.ts +7 -0
- package/src/store/scopes/threads.ts +1 -0
- package/src/tests/RemoteThreadListThreadListRuntimeCore-reloadMainThread.test.ts +257 -0
- package/src/tests/auiV0Encode.test.ts +125 -1
- package/src/tests/base-composer-runtime-core-addAttachment.test.ts +296 -0
- package/src/tests/event-subscription-listener-errors.test.ts +1 -0
- package/src/tests/external-store-thread-list-runtime-core.test.ts +39 -1
- package/src/types/message.ts +11 -0
- package/src/utils/data-url.ts +24 -0
- package/src/utils/image-media-type.test.ts +96 -0
- package/src/utils/image-media-type.ts +118 -0
- package/src/utils/wire-media.test.ts +96 -0
- package/src/utils/wire-media.ts +70 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Leading-byte signatures for the image formats a browser or attachment
|
|
3
|
+
* adapter realistically produces. `null` matches any byte, which WebP needs
|
|
4
|
+
* because its four size bytes sit between the two markers, and AVIF and HEIC
|
|
5
|
+
* need because their leading `ftyp` box size varies by encoder.
|
|
6
|
+
*
|
|
7
|
+
* These are file format constants rather than an evolving API, so the table
|
|
8
|
+
* mirrors the one the AI SDK applies on the far side of several adapters
|
|
9
|
+
* without taking a dependency to reach it.
|
|
10
|
+
*/
|
|
11
|
+
const IMAGE_SIGNATURES: readonly {
|
|
12
|
+
readonly mediaType: string;
|
|
13
|
+
readonly prefix: readonly (number | null)[];
|
|
14
|
+
}[] = [
|
|
15
|
+
{ mediaType: "image/gif", prefix: [0x47, 0x49, 0x46] },
|
|
16
|
+
{ mediaType: "image/png", prefix: [0x89, 0x50, 0x4e, 0x47] },
|
|
17
|
+
{ mediaType: "image/jpeg", prefix: [0xff, 0xd8] },
|
|
18
|
+
{
|
|
19
|
+
mediaType: "image/webp",
|
|
20
|
+
prefix: [
|
|
21
|
+
0x52,
|
|
22
|
+
0x49,
|
|
23
|
+
0x46,
|
|
24
|
+
0x46,
|
|
25
|
+
null,
|
|
26
|
+
null,
|
|
27
|
+
null,
|
|
28
|
+
null,
|
|
29
|
+
0x57,
|
|
30
|
+
0x45,
|
|
31
|
+
0x42,
|
|
32
|
+
0x50,
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
{ mediaType: "image/bmp", prefix: [0x42, 0x4d] },
|
|
36
|
+
{ mediaType: "image/tiff", prefix: [0x49, 0x49, 0x2a, 0x00] },
|
|
37
|
+
{ mediaType: "image/tiff", prefix: [0x4d, 0x4d, 0x00, 0x2a] },
|
|
38
|
+
{
|
|
39
|
+
mediaType: "image/avif",
|
|
40
|
+
prefix: [
|
|
41
|
+
null,
|
|
42
|
+
null,
|
|
43
|
+
null,
|
|
44
|
+
null,
|
|
45
|
+
0x66,
|
|
46
|
+
0x74,
|
|
47
|
+
0x79,
|
|
48
|
+
0x70,
|
|
49
|
+
0x61,
|
|
50
|
+
0x76,
|
|
51
|
+
0x69,
|
|
52
|
+
0x66,
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
mediaType: "image/heic",
|
|
57
|
+
prefix: [
|
|
58
|
+
null,
|
|
59
|
+
null,
|
|
60
|
+
null,
|
|
61
|
+
null,
|
|
62
|
+
0x66,
|
|
63
|
+
0x74,
|
|
64
|
+
0x79,
|
|
65
|
+
0x70,
|
|
66
|
+
0x68,
|
|
67
|
+
0x65,
|
|
68
|
+
0x69,
|
|
69
|
+
0x63,
|
|
70
|
+
],
|
|
71
|
+
},
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
/** 16 base64 characters decode to the 12 bytes the longest signature needs. */
|
|
75
|
+
const PREFIX_CHARS = 16;
|
|
76
|
+
|
|
77
|
+
const decodePrefix = (base64: string): Uint8Array | undefined => {
|
|
78
|
+
const prefix = base64.slice(0, PREFIX_CHARS);
|
|
79
|
+
const aligned = prefix.slice(0, prefix.length - (prefix.length % 4));
|
|
80
|
+
if (aligned.length === 0) return undefined;
|
|
81
|
+
|
|
82
|
+
const nodeBuffer = (
|
|
83
|
+
globalThis as {
|
|
84
|
+
Buffer?: {
|
|
85
|
+
from(data: string, encoding: string): Uint8Array;
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
).Buffer;
|
|
89
|
+
if (nodeBuffer) return new Uint8Array(nodeBuffer.from(aligned, "base64"));
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
const binary = atob(aligned);
|
|
93
|
+
const bytes = new Uint8Array(binary.length);
|
|
94
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
95
|
+
return bytes;
|
|
96
|
+
} catch {
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* The image media type a base64 payload's leading bytes identify, or
|
|
103
|
+
* `undefined` when they match no known signature or the input is not base64.
|
|
104
|
+
*
|
|
105
|
+
* An `ImageMessagePart` carries no media type, so an adapter that must declare
|
|
106
|
+
* one on the wire reads it from the bytes rather than assuming a format. Never
|
|
107
|
+
* throws: the input is whatever a caller put on the part.
|
|
108
|
+
*/
|
|
109
|
+
export function detectImageMediaType(base64: string): string | undefined {
|
|
110
|
+
const bytes = decodePrefix(base64);
|
|
111
|
+
if (!bytes) return undefined;
|
|
112
|
+
|
|
113
|
+
return IMAGE_SIGNATURES.find(
|
|
114
|
+
({ prefix }) =>
|
|
115
|
+
bytes.length >= prefix.length &&
|
|
116
|
+
prefix.every((byte, index) => byte === null || bytes[index] === byte),
|
|
117
|
+
)?.mediaType;
|
|
118
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
resolveFileMediaType,
|
|
4
|
+
resolveImageMediaType,
|
|
5
|
+
toMediaWireUrl,
|
|
6
|
+
} from "./wire-media";
|
|
7
|
+
|
|
8
|
+
const JPEG = "/9j/4AAQSkZJRg==";
|
|
9
|
+
|
|
10
|
+
describe("resolveImageMediaType", () => {
|
|
11
|
+
it("prefers an image content type over everything else", () => {
|
|
12
|
+
expect(
|
|
13
|
+
resolveImageMediaType(`data:image/png;base64,${JPEG}`, "image/webp"),
|
|
14
|
+
).toBe("image/webp");
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it("ignores a content type that is not an image", () => {
|
|
18
|
+
expect(resolveImageMediaType(JPEG, "application/octet-stream")).toBe(
|
|
19
|
+
"image/jpeg",
|
|
20
|
+
);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("takes the data url declaration when it is an image type", () => {
|
|
24
|
+
expect(
|
|
25
|
+
resolveImageMediaType("data:image/svg+xml,%3Csvg%3E%3C/svg%3E"),
|
|
26
|
+
).toBe("image/svg+xml");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("sniffs through a declaration that is not an image type", () => {
|
|
30
|
+
expect(
|
|
31
|
+
resolveImageMediaType(`data:application/octet-stream;base64,${JPEG}`),
|
|
32
|
+
).toBe("image/jpeg");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("sniffs a bare base64 payload", () => {
|
|
36
|
+
expect(resolveImageMediaType(JPEG)).toBe("image/jpeg");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("floors to image/png when there are no bytes to read", () => {
|
|
40
|
+
expect(resolveImageMediaType("https://cdn.example.com/photo")).toBe(
|
|
41
|
+
"image/png",
|
|
42
|
+
);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("floors to image/png when the bytes match no signature", () => {
|
|
46
|
+
expect(resolveImageMediaType("QUJD")).toBe("image/png");
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
describe("resolveFileMediaType", () => {
|
|
51
|
+
it("prefers the declared type", () => {
|
|
52
|
+
expect(
|
|
53
|
+
resolveFileMediaType(
|
|
54
|
+
"data:application/octet-stream;base64,QUJD",
|
|
55
|
+
"application/pdf",
|
|
56
|
+
),
|
|
57
|
+
).toBe("application/pdf");
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("falls back to the data url declaration when none is declared", () => {
|
|
61
|
+
expect(resolveFileMediaType("data:text/plain,hello", "")).toBe(
|
|
62
|
+
"text/plain",
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("floors to application/octet-stream", () => {
|
|
67
|
+
expect(resolveFileMediaType("QUJD", "")).toBe("application/octet-stream");
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
describe("toMediaWireUrl", () => {
|
|
72
|
+
it("forwards an envelope that agrees byte for byte", () => {
|
|
73
|
+
const payload = "data:image/jpeg;base64,QUJD";
|
|
74
|
+
expect(toMediaWireUrl(payload, "image/jpeg")).toBe(payload);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("rebuilds an envelope that disagrees", () => {
|
|
78
|
+
expect(
|
|
79
|
+
toMediaWireUrl("data:application/octet-stream;base64,QUJD", "image/jpeg"),
|
|
80
|
+
).toBe("data:image/jpeg;base64,QUJD");
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("wraps a bare base64 payload", () => {
|
|
84
|
+
expect(toMediaWireUrl("QUJD", "application/pdf")).toBe(
|
|
85
|
+
"data:application/pdf;base64,QUJD",
|
|
86
|
+
);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it.each([
|
|
90
|
+
"https://cdn.example.com/a.pdf",
|
|
91
|
+
"blob:https://app.example/1-2-3",
|
|
92
|
+
"data:text/plain,hello",
|
|
93
|
+
])("forwards %s untouched", (payload) => {
|
|
94
|
+
expect(toMediaWireUrl(payload, "application/pdf")).toBe(payload);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { dataUrlMediaType, isParsableUrl, parseDataUrl } from "./data-url";
|
|
2
|
+
import { detectImageMediaType } from "./image-media-type";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The media type to declare for an `ImageMessagePart`, which carries none of
|
|
6
|
+
* its own: an attachment's content type, then the payload's data URL
|
|
7
|
+
* declaration, then its leading bytes, then `image/png`.
|
|
8
|
+
*
|
|
9
|
+
* The floor cannot be a wildcard. `image/*` is rejected outright by the AI SDK
|
|
10
|
+
* for a url source and whenever inline bytes fail to sniff, so it fails exactly
|
|
11
|
+
* where a fallback is needed.
|
|
12
|
+
*/
|
|
13
|
+
export function resolveImageMediaType(
|
|
14
|
+
image: string,
|
|
15
|
+
contentType?: string | undefined,
|
|
16
|
+
): string {
|
|
17
|
+
if (contentType?.startsWith("image/")) return contentType;
|
|
18
|
+
|
|
19
|
+
const declared = dataUrlMediaType(image);
|
|
20
|
+
if (declared?.startsWith("image/")) return declared;
|
|
21
|
+
|
|
22
|
+
// Read through a data URL envelope too, so a generic one such as
|
|
23
|
+
// `application/octet-stream` does not mask the format. A url of any other
|
|
24
|
+
// scheme has no local bytes to read.
|
|
25
|
+
const parsed = parseDataUrl(image);
|
|
26
|
+
const payload = parsed?.data ?? (isParsableUrl(image) ? undefined : image);
|
|
27
|
+
if (payload !== undefined) {
|
|
28
|
+
const sniffed = detectImageMediaType(payload);
|
|
29
|
+
if (sniffed) return sniffed;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return "image/png";
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The media type to declare for a `FileMessagePart`: its own `mimeType`, then
|
|
37
|
+
* the payload's data URL declaration, then `application/octet-stream`.
|
|
38
|
+
*
|
|
39
|
+
* `mimeType` is a plain string, and an adapter reading `file.type` on a file
|
|
40
|
+
* the OS cannot type yields `""`, so the declared value is not always present.
|
|
41
|
+
*/
|
|
42
|
+
export function resolveFileMediaType(
|
|
43
|
+
data: string,
|
|
44
|
+
mimeType?: string | undefined,
|
|
45
|
+
): string {
|
|
46
|
+
return mimeType || dataUrlMediaType(data) || "application/octet-stream";
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* A payload placed into a wire field that is contractually a url.
|
|
51
|
+
*
|
|
52
|
+
* Two hazards drive this. A consumer may hand the value to an unguarded
|
|
53
|
+
* `new URL()`, so a payload that is not a url has to be wrapped; and a data
|
|
54
|
+
* URL's own media type wins over a separately declared one downstream, so a
|
|
55
|
+
* base64 envelope that disagrees with `mediaType` is rebuilt around the same
|
|
56
|
+
* bytes. Everything else passes through byte for byte: an envelope that agrees,
|
|
57
|
+
* a url of any other scheme, and a percent-encoded data URL, whose declaration
|
|
58
|
+
* cannot be corrected without transcoding the payload and is authoritative for
|
|
59
|
+
* the bytes it carries anyway.
|
|
60
|
+
*/
|
|
61
|
+
export function toMediaWireUrl(payload: string, mediaType: string): string {
|
|
62
|
+
const parsed = parseDataUrl(payload);
|
|
63
|
+
if (parsed) {
|
|
64
|
+
return parsed.mimeType === mediaType
|
|
65
|
+
? payload
|
|
66
|
+
: `data:${mediaType};base64,${parsed.data}`;
|
|
67
|
+
}
|
|
68
|
+
if (isParsableUrl(payload)) return payload;
|
|
69
|
+
return `data:${mediaType};base64,${payload}`;
|
|
70
|
+
}
|