@seams/voiceid 0.0.0-stage → 0.24.0

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 (65) hide show
  1. package/LICENSE.md +201 -0
  2. package/README.md +74 -2
  3. package/THIRD_PARTY_NOTICES.md +504 -0
  4. package/dist/compose-host.mjs +11 -0
  5. package/dist/esm/browser/ribbon.js +489 -0
  6. package/dist/esm/capture/prompt.js +515 -0
  7. package/dist/esm/capture/visual.js +87 -0
  8. package/dist/esm/descriptor.js +7 -0
  9. package/dist/esm/index.js +2 -0
  10. package/dist/esm/react/VoiceAssistantCard.css +313 -0
  11. package/dist/esm/react/VoiceAssistantCard.js +147 -0
  12. package/dist/esm/react.js +3 -0
  13. package/dist/hosting.d.mts +4 -0
  14. package/dist/hosting.mjs +91 -0
  15. package/dist/public/sdk/voiceid/AURORA_LICENSE.txt +202 -0
  16. package/dist/public/sdk/voiceid/NOTICE.txt +54 -0
  17. package/dist/public/sdk/voiceid/SILERO_LICENSE.txt +21 -0
  18. package/dist/public/sdk/voiceid/addVoiceId-CeBXVHqs.js +1 -0
  19. package/dist/public/sdk/voiceid/approval-CCbdLhTv.js +1 -0
  20. package/dist/public/sdk/voiceid/aurora-int8.onnx +0 -0
  21. package/dist/public/sdk/voiceid/deviceBridge-wRAbqdap.js +1 -0
  22. package/dist/public/sdk/voiceid/enrollment-DIRoCkx5.js +1 -0
  23. package/dist/public/sdk/voiceid/host.js +80 -0
  24. package/dist/public/sdk/voiceid/ort-wasm-simd-threaded.mjs +59 -0
  25. package/dist/public/sdk/voiceid/ort-wasm-simd-threaded.wasm +0 -0
  26. package/dist/public/sdk/voiceid/ort.wasm.bundle.min-7y-hlRN8.js +3 -0
  27. package/dist/public/sdk/voiceid/prompt-CCrXTRRx.js +606 -0
  28. package/dist/public/sdk/voiceid/redimnet-b1.onnx +0 -0
  29. package/dist/public/sdk/voiceid/silero-vad.onnx +0 -0
  30. package/dist/public/sdk/voiceid/unlock-E7YHqBGT.js +1 -0
  31. package/dist/public/sdk/voiceid/voice-activity-worklet.js +21 -0
  32. package/dist/types/activation/addVoiceId.d.ts +11 -0
  33. package/dist/types/activation/manageEnrollment.d.ts +4 -0
  34. package/dist/types/activation/ownerConfirmation.d.ts +17 -0
  35. package/dist/types/browser/deviceStore.d.ts +19 -0
  36. package/dist/types/browser/enrollment.d.ts +37 -0
  37. package/dist/types/browser/enrollmentStore.d.ts +91 -0
  38. package/dist/types/browser/inference.d.ts +39 -0
  39. package/dist/types/browser/microphone.d.ts +61 -0
  40. package/dist/types/browser/model.d.ts +8 -0
  41. package/dist/types/browser/phrase.d.ts +35 -0
  42. package/dist/types/browser/phraseVocabulary.d.ts +3 -0
  43. package/dist/types/browser/progress.d.ts +2 -0
  44. package/dist/types/browser/ribbon.d.ts +63 -0
  45. package/dist/types/browser/verificationError.d.ts +6 -0
  46. package/dist/types/browser/voiceActivity.d.ts +15 -0
  47. package/dist/types/capture/approval.d.ts +36 -0
  48. package/dist/types/capture/bridge.d.ts +12 -0
  49. package/dist/types/capture/deviceBridge.d.ts +29 -0
  50. package/dist/types/capture/prompt.d.ts +41 -0
  51. package/dist/types/capture/surface.d.ts +27 -0
  52. package/dist/types/capture/unlockFrame.d.ts +13 -0
  53. package/dist/types/capture/visual.d.ts +24 -0
  54. package/dist/types/descriptor.d.ts +4 -0
  55. package/dist/types/host.d.ts +4 -0
  56. package/dist/types/index.d.ts +2 -0
  57. package/dist/types/react/VoiceAssistantCard.d.ts +37 -0
  58. package/dist/types/react.d.ts +5 -0
  59. package/dist/types/session/activation.d.ts +61 -0
  60. package/dist/types/session/activationStore.d.ts +21 -0
  61. package/dist/types/session/httpClient.d.ts +39 -0
  62. package/dist/types/session/unlock.d.ts +4 -0
  63. package/dist/types/session/unlockFromDevice.d.ts +18 -0
  64. package/package.json +66 -4
  65. package/src/README.md +270 -0
@@ -0,0 +1,313 @@
1
+ .voice-assistant-card {
2
+ --voice-surface: #1d1d1d;
3
+ --voice-foreground: #f2f2f2;
4
+ --voice-muted: rgb(202 202 202 / 70%);
5
+ --voice-bubble: #303030;
6
+ --voice-divider: rgb(255 255 255 / 4%);
7
+ --voice-button: rgb(255 255 255 / 10%);
8
+ --voice-button-shadow:
9
+ 0 1px 1px rgb(0 0 0 / 24%), inset 0 0 0 1px rgb(255 255 255 / 4%),
10
+ inset 0 1px 0 rgb(255 255 255 / 6%);
11
+ display: grid;
12
+ inline-size: 360px;
13
+ max-inline-size: 100%;
14
+ min-inline-size: 0;
15
+ border-radius: 24px;
16
+ background: var(--voice-surface);
17
+ color: var(--voice-foreground);
18
+ font: 400 14px / 20px var(--seams-fonts-sans, Inter, system-ui, sans-serif);
19
+ -webkit-font-smoothing: antialiased;
20
+ color-scheme: dark;
21
+ }
22
+
23
+ .voice-assistant-card[data-theme='light'] {
24
+ --voice-surface: #fff;
25
+ --voice-foreground: #0d0d0d;
26
+ --voice-muted: #6c6c6c;
27
+ --voice-bubble: #f0f0f0;
28
+ --voice-divider: rgb(0 0 0 / 4%);
29
+ --voice-button: rgb(255 255 255 / 40%);
30
+ --voice-button-shadow:
31
+ 0 1px 3px rgb(0 0 0 / 4%), inset 0 0 0 1px rgb(0 0 0 / 8%), inset 0 -1px 0 rgb(0 0 0 / 8%);
32
+ box-shadow:
33
+ 0 0 0 1px rgb(0 0 0 / 4%),
34
+ 0 8px 32px -4px rgb(0 0 0 / 6%),
35
+ 0 1px 3px rgb(0 0 0 / 4%);
36
+ color-scheme: light;
37
+ }
38
+
39
+ .voice-assistant-card,
40
+ .voice-assistant-card * {
41
+ box-sizing: border-box;
42
+ }
43
+
44
+ .voice-assistant-beam {
45
+ margin: -1px;
46
+ border-radius: 25px;
47
+ min-inline-size: 0;
48
+ }
49
+
50
+ .voice-assistant-content {
51
+ position: relative;
52
+ z-index: 5;
53
+ display: flex;
54
+ flex-direction: column;
55
+ min-block-size: 342px;
56
+ border-radius: 25px;
57
+ }
58
+
59
+ .voice-assistant-header {
60
+ display: flex;
61
+ align-items: center;
62
+ gap: 12px;
63
+ padding: 16px;
64
+ }
65
+
66
+ .voice-assistant-avatar {
67
+ display: grid;
68
+ flex: none;
69
+ place-items: center;
70
+ inline-size: 32px;
71
+ block-size: 32px;
72
+ border-radius: 50%;
73
+ background: #27272e;
74
+ color: #e6dfec;
75
+ box-shadow: inset 0 0 0 1px rgb(255 255 255 / 4%);
76
+ font-size: 13px;
77
+ font-weight: 500;
78
+ line-height: 1;
79
+ }
80
+
81
+ .voice-assistant-card[data-theme='light'] .voice-assistant-avatar {
82
+ background: #eee9f2;
83
+ color: #37364f;
84
+ box-shadow: inset 0 0 0 1px rgb(0 0 0 / 2%);
85
+ }
86
+
87
+ .voice-assistant-identity {
88
+ min-inline-size: 0;
89
+ }
90
+
91
+ .voice-assistant-identity h2,
92
+ .voice-assistant-identity p {
93
+ margin: 0;
94
+ overflow-wrap: anywhere;
95
+ }
96
+
97
+ .voice-assistant-identity h2 {
98
+ font-size: 16px;
99
+ font-weight: 500;
100
+ line-height: 22px;
101
+ }
102
+
103
+ .voice-assistant-identity p {
104
+ color: var(--voice-muted);
105
+ font-size: 12px;
106
+ line-height: 16px;
107
+ }
108
+
109
+ .voice-assistant-divider {
110
+ flex: none;
111
+ block-size: 1px;
112
+ background: linear-gradient(90deg, transparent, var(--voice-divider) 20% 80%, transparent);
113
+ }
114
+
115
+ .voice-assistant-body {
116
+ display: flex;
117
+ flex-direction: column;
118
+ gap: 16px;
119
+ padding: 24px 24px 0;
120
+ overflow-wrap: anywhere;
121
+ }
122
+
123
+ .voice-assistant-bubble-row {
124
+ padding-inline-start: 8px;
125
+ animation: voice-assistant-float 4s ease-in-out infinite;
126
+ }
127
+
128
+ .voice-assistant-bubble {
129
+ position: relative;
130
+ display: inline-block;
131
+ max-inline-size: 240px;
132
+ margin: 0;
133
+ padding: 8px 12px;
134
+ border-radius: 18px;
135
+ background: var(--voice-bubble);
136
+ font-size: 14px;
137
+ line-height: 20px;
138
+ }
139
+
140
+ .voice-assistant-bubble span {
141
+ position: relative;
142
+ z-index: 1;
143
+ }
144
+
145
+ .voice-assistant-bubble::before {
146
+ content: '';
147
+ position: absolute;
148
+ inset-block-end: 0;
149
+ inset-inline-start: -7px;
150
+ inline-size: 20px;
151
+ block-size: 20px;
152
+ border-end-end-radius: 16px 14px;
153
+ background: var(--voice-bubble);
154
+ }
155
+
156
+ .voice-assistant-bubble::after {
157
+ content: '';
158
+ position: absolute;
159
+ inset-block-end: 0;
160
+ inset-inline-start: -26px;
161
+ inline-size: 26px;
162
+ block-size: 20px;
163
+ border-end-end-radius: 10px;
164
+ background: var(--voice-surface);
165
+ }
166
+
167
+ .voice-assistant-transcript {
168
+ padding-inline-start: 32px;
169
+ text-align: end;
170
+ text-wrap: pretty;
171
+ }
172
+
173
+ .voice-assistant-footer {
174
+ display: flex;
175
+ flex-direction: column;
176
+ align-items: center;
177
+ gap: 12px;
178
+ margin-block-start: auto;
179
+ padding: 24px;
180
+ }
181
+
182
+ .voice-assistant-caption {
183
+ display: grid;
184
+ color: var(--voice-muted);
185
+ font-size: 12px;
186
+ line-height: 16px;
187
+ }
188
+
189
+ .voice-assistant-caption > span {
190
+ grid-area: 1 / 1;
191
+ text-align: center;
192
+ opacity: 0;
193
+ transform: translateY(4px);
194
+ transition:
195
+ opacity var(--seams-voice-transition, 150ms ease-out),
196
+ transform var(--seams-voice-transition, 150ms ease-out);
197
+ }
198
+
199
+ .voice-assistant-caption > span[data-visible='true'] {
200
+ opacity: 1;
201
+ transform: translateY(0);
202
+ }
203
+
204
+ .voice-assistant-status {
205
+ position: absolute;
206
+ inline-size: 1px;
207
+ block-size: 1px;
208
+ overflow: hidden;
209
+ clip-path: inset(50%);
210
+ white-space: nowrap;
211
+ }
212
+
213
+ .voice-assistant-mic {
214
+ display: grid;
215
+ place-items: center;
216
+ inline-size: 48px;
217
+ block-size: 48px;
218
+ padding: 0;
219
+ border: 0;
220
+ border-radius: 50%;
221
+ background: var(--voice-button);
222
+ box-shadow: var(--voice-button-shadow);
223
+ color: inherit;
224
+ font: inherit;
225
+ cursor: pointer;
226
+ touch-action: manipulation;
227
+ -webkit-tap-highlight-color: transparent;
228
+ user-select: none;
229
+ transition: transform var(--seams-voice-transition, 150ms ease-out);
230
+ }
231
+
232
+ .voice-assistant-mic:active {
233
+ transform: scale(0.95);
234
+ }
235
+
236
+ .voice-assistant-mic:focus-visible {
237
+ outline: 2px solid var(--voice-foreground);
238
+ outline-offset: 3px;
239
+ }
240
+
241
+ @media (hover: hover) and (pointer: fine) {
242
+ .voice-assistant-mic:hover {
243
+ background-image: linear-gradient(rgb(128 128 128 / 4%) 0 100%);
244
+ }
245
+ }
246
+
247
+ .voice-assistant-wave {
248
+ display: flex;
249
+ align-items: center;
250
+ gap: 2px;
251
+ block-size: 20px;
252
+ }
253
+
254
+ .voice-assistant-wave i {
255
+ inline-size: 2px;
256
+ block-size: 6px;
257
+ border-radius: 1px;
258
+ background: currentColor;
259
+ }
260
+
261
+ .voice-assistant-wave i:nth-child(2),
262
+ .voice-assistant-wave i:nth-child(4) {
263
+ block-size: 12px;
264
+ }
265
+
266
+ .voice-assistant-wave i:nth-child(3) {
267
+ block-size: 18px;
268
+ }
269
+
270
+ .voice-assistant-card[data-state='listening'] .voice-assistant-wave i {
271
+ animation: voice-assistant-wave 900ms ease-in-out infinite;
272
+ }
273
+
274
+ .voice-assistant-wave i:nth-child(2) {
275
+ animation-delay: -270ms;
276
+ }
277
+
278
+ .voice-assistant-wave i:nth-child(3) {
279
+ animation-delay: -540ms;
280
+ }
281
+
282
+ .voice-assistant-wave i:nth-child(4) {
283
+ animation-delay: -135ms;
284
+ }
285
+
286
+ .voice-assistant-wave i:nth-child(5) {
287
+ animation-delay: -405ms;
288
+ }
289
+
290
+ @keyframes voice-assistant-wave {
291
+ 50% {
292
+ transform: scaleY(0.35);
293
+ }
294
+ }
295
+
296
+ @keyframes voice-assistant-float {
297
+ 50% {
298
+ transform: translateY(-3px);
299
+ }
300
+ }
301
+
302
+ @media (prefers-reduced-motion: reduce) {
303
+ .voice-assistant-bubble-row,
304
+ .voice-assistant-card[data-state='listening'] .voice-assistant-wave i {
305
+ animation: none;
306
+ }
307
+
308
+ .voice-assistant-caption > span,
309
+ .voice-assistant-mic {
310
+ transition: none;
311
+ transform: none;
312
+ }
313
+ }
@@ -0,0 +1,147 @@
1
+ import { VoiceBeam } from "voice-glow";
2
+ import React from "react";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ //#region src/react/VoiceAssistantCard.tsx
5
+ /** Controlled presentation. The caller owns audio, transcripts, and work. */
6
+ function VoiceAssistantCard(props) {
7
+ const titleId = React.useId();
8
+ const drive = beamDrive(props.state);
9
+ const listening = props.state.kind === "listening";
10
+ return /* @__PURE__ */ jsx("section", {
11
+ className: `voice-assistant-card ${props.className ?? ""}`,
12
+ style: props.style,
13
+ "data-theme": props.theme,
14
+ "data-state": props.state.kind,
15
+ "aria-labelledby": titleId,
16
+ children: /* @__PURE__ */ jsx(VoiceBeam, {
17
+ className: "voice-assistant-beam",
18
+ theme: props.theme,
19
+ level: drive.level,
20
+ stream: drive.stream,
21
+ processing: drive.processing,
22
+ children: /* @__PURE__ */ jsxs("div", {
23
+ className: "voice-assistant-content",
24
+ children: [
25
+ /* @__PURE__ */ jsxs("header", {
26
+ className: "voice-assistant-header",
27
+ children: [/* @__PURE__ */ jsx("span", {
28
+ className: "voice-assistant-avatar",
29
+ "aria-hidden": "true",
30
+ children: props.initials
31
+ }), /* @__PURE__ */ jsxs("div", {
32
+ className: "voice-assistant-identity",
33
+ children: [/* @__PURE__ */ jsx("h2", {
34
+ id: titleId,
35
+ children: props.name
36
+ }), /* @__PURE__ */ jsx("p", { children: props.description })]
37
+ })]
38
+ }),
39
+ /* @__PURE__ */ jsx("div", {
40
+ className: "voice-assistant-divider",
41
+ "aria-hidden": "true"
42
+ }),
43
+ /* @__PURE__ */ jsxs("div", {
44
+ className: "voice-assistant-body",
45
+ children: [/* @__PURE__ */ jsx("div", {
46
+ className: "voice-assistant-bubble-row",
47
+ children: /* @__PURE__ */ jsx("p", {
48
+ className: "voice-assistant-bubble",
49
+ children: /* @__PURE__ */ jsx("span", { children: props.message })
50
+ })
51
+ }), /* @__PURE__ */ jsx("div", {
52
+ className: "voice-assistant-transcript",
53
+ children: props.transcript
54
+ })]
55
+ }),
56
+ /* @__PURE__ */ jsxs("footer", {
57
+ className: "voice-assistant-footer",
58
+ children: [
59
+ /* @__PURE__ */ jsxs("div", {
60
+ className: "voice-assistant-caption",
61
+ "aria-hidden": "true",
62
+ children: [
63
+ /* @__PURE__ */ jsx("span", {
64
+ "data-visible": props.state.kind === "idle",
65
+ children: "Tap to speak"
66
+ }),
67
+ /* @__PURE__ */ jsx("span", {
68
+ "data-visible": listening,
69
+ children: "Listening…"
70
+ }),
71
+ /* @__PURE__ */ jsx("span", {
72
+ "data-visible": props.state.kind === "processing",
73
+ children: "One moment"
74
+ })
75
+ ]
76
+ }),
77
+ /* @__PURE__ */ jsx("span", {
78
+ className: "voice-assistant-status",
79
+ role: "status",
80
+ children: stateCaption(props.state)
81
+ }),
82
+ /* @__PURE__ */ jsx("button", {
83
+ type: "button",
84
+ className: "voice-assistant-mic",
85
+ "aria-label": listening ? "Stop speaking" : "Start speaking",
86
+ "aria-pressed": listening,
87
+ onClick: props.onToggle,
88
+ children: /* @__PURE__ */ jsxs("span", {
89
+ className: "voice-assistant-wave",
90
+ "aria-hidden": "true",
91
+ children: [
92
+ /* @__PURE__ */ jsx("i", {}),
93
+ /* @__PURE__ */ jsx("i", {}),
94
+ /* @__PURE__ */ jsx("i", {}),
95
+ /* @__PURE__ */ jsx("i", {}),
96
+ /* @__PURE__ */ jsx("i", {})
97
+ ]
98
+ })
99
+ })
100
+ ]
101
+ })
102
+ ]
103
+ })
104
+ })
105
+ });
106
+ }
107
+ function stateCaption(state) {
108
+ switch (state.kind) {
109
+ case "idle": return "Tap to speak";
110
+ case "listening": return "Listening…";
111
+ case "processing": return "One moment";
112
+ default: return assertNeverVoiceAssistantVariant(state);
113
+ }
114
+ }
115
+ function beamDrive(state) {
116
+ switch (state.kind) {
117
+ case "idle": return {
118
+ level: .06,
119
+ stream: null,
120
+ processing: false
121
+ };
122
+ case "processing": return {
123
+ level: .06,
124
+ stream: null,
125
+ processing: true
126
+ };
127
+ case "listening": switch (state.input.kind) {
128
+ case "level": return {
129
+ level: state.input.level,
130
+ stream: null,
131
+ processing: false
132
+ };
133
+ case "microphone": return {
134
+ level: 0,
135
+ stream: state.input.stream,
136
+ processing: false
137
+ };
138
+ default: return assertNeverVoiceAssistantVariant(state.input);
139
+ }
140
+ default: return assertNeverVoiceAssistantVariant(state);
141
+ }
142
+ }
143
+ function assertNeverVoiceAssistantVariant(value) {
144
+ throw new Error(`Unexpected voice assistant variant: ${String(value)}`);
145
+ }
146
+ //#endregion
147
+ export { VoiceAssistantCard };
@@ -0,0 +1,3 @@
1
+ import { VoiceAssistantCard } from "./react/VoiceAssistantCard.js";
2
+ import { VoiceBeam } from "voice-glow";
3
+ export { VoiceAssistantCard, VoiceBeam };
@@ -0,0 +1,4 @@
1
+ export function composeVoiceIdWalletAssets(input: {
2
+ walletPublicDirectory: string;
3
+ outputDirectory: string;
4
+ }): Promise<string>;
@@ -0,0 +1,91 @@
1
+ import { access, cp, mkdir, readFile, readdir, writeFile } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+
5
+ const voicePublic = fileURLToPath(new URL('./public/', import.meta.url));
6
+
7
+ /** Compose a new deployment directory without changing either source asset tree. */
8
+ export async function composeVoiceIdWalletAssets({ walletPublicDirectory, outputDirectory }) {
9
+ const walletPublic = path.resolve(walletPublicDirectory);
10
+ const output = path.resolve(outputDirectory);
11
+ if (
12
+ containsPath(walletPublic, output) ||
13
+ containsPath(voicePublic, output) ||
14
+ containsPath(output, walletPublic) ||
15
+ containsPath(output, voicePublic)
16
+ ) {
17
+ throw new Error('Compose VoiceID into a separate deployment directory.');
18
+ }
19
+ await access(path.join(walletPublic, 'sdk/voiceid-host.js'));
20
+ const manifest = JSON.parse(
21
+ await readFile(path.join(walletPublic, 'wallet-assets.manifest.json'), 'utf8'),
22
+ );
23
+ if (
24
+ manifest.schemaVersion !== 1 ||
25
+ manifest.packageName !== '@seams/wallet' ||
26
+ !Array.isArray(manifest.assets)
27
+ ) {
28
+ throw new Error('Expected the static asset manifest from a compatible @seams/wallet package.');
29
+ }
30
+ // An existing directory is never overwritten, including either package's dist tree.
31
+ await mkdir(output);
32
+ for (const entry of await readdir(walletPublic)) {
33
+ await cp(path.join(walletPublic, entry), path.join(output, entry), {
34
+ recursive: true,
35
+ force: false,
36
+ errorOnExist: true,
37
+ });
38
+ }
39
+ await cp(path.join(voicePublic, 'sdk/voiceid'), path.join(output, 'sdk/voiceid'), {
40
+ recursive: true,
41
+ force: false,
42
+ errorOnExist: true,
43
+ });
44
+ const voiceFiles = await readdir(path.join(voicePublic, 'sdk/voiceid'));
45
+ for (const filename of voiceFiles) manifest.assets.push(assetEntry(filename));
46
+ manifest.assets.sort(compareAssets);
47
+ await writeFile(
48
+ path.join(output, 'wallet-assets.manifest.json'),
49
+ JSON.stringify(manifest, null, 2) + '\n',
50
+ );
51
+ return output;
52
+ }
53
+
54
+ function containsPath(parent, child) {
55
+ const relative = path.relative(parent, child);
56
+ return relative === '' || (
57
+ relative !== '..' && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative)
58
+ );
59
+ }
60
+
61
+ function compareAssets(left, right) {
62
+ return left.sourceFile.localeCompare(right.sourceFile);
63
+ }
64
+
65
+ function assetEntry(filename) {
66
+ const sourceFile = `sdk/voiceid/${filename}`;
67
+ const extension = path.extname(filename);
68
+ let routeClass = 'binary';
69
+ let contentType = 'application/octet-stream';
70
+ if (extension === '.js' || extension === '.mjs') {
71
+ routeClass = 'javascript';
72
+ contentType = 'text/javascript; charset=utf-8';
73
+ } else if (extension === '.wasm') {
74
+ routeClass = 'wasm';
75
+ contentType = 'application/wasm';
76
+ }
77
+ const cachePolicy = 'public, max-age=300, must-revalidate';
78
+ return {
79
+ route: `/${sourceFile}`,
80
+ sourceFile,
81
+ owner: 'wallet_sdk_asset',
82
+ routeClass,
83
+ contentType,
84
+ cachePolicy,
85
+ requiredHeaders: [
86
+ { name: 'Content-Type', value: contentType },
87
+ { name: 'Cache-Control', value: cachePolicy },
88
+ { name: 'Access-Control-Allow-Origin', value: '*' },
89
+ ],
90
+ };
91
+ }