@marimo-team/islands 0.19.8-dev23 → 0.19.8-dev24

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/main.js CHANGED
@@ -13114,11 +13114,11 @@ ${d.join("\n")}`;
13114
13114
  var r = e.toUpperCase();
13115
13115
  return methods.indexOf(r) > -1 ? r : e;
13116
13116
  }
13117
- function Request(e, r) {
13118
- if (!(this instanceof Request)) throw TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');
13117
+ function Request$1(e, r) {
13118
+ if (!(this instanceof Request$1)) throw TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');
13119
13119
  r || (r = {});
13120
13120
  var c = r.body;
13121
- if (e instanceof Request) {
13121
+ if (e instanceof Request$1) {
13122
13122
  if (e.bodyUsed) throw TypeError("Already read");
13123
13123
  this.url = e.url, this.credentials = e.credentials, r.headers || (this.headers = new Headers$2(e.headers)), this.method = e.method, this.mode = e.mode, this.signal = e.signal, !c && e._bodyInit != null && (c = e._bodyInit, e.bodyUsed = true);
13124
13124
  } else this.url = String(e);
@@ -13162,7 +13162,7 @@ ${d.join("\n")}`;
13162
13162
  }
13163
13163
  function fetch$1(e, r) {
13164
13164
  return new Promise(function(c, d) {
13165
- var f = new Request(e, r);
13165
+ var f = new Request$1(e, r);
13166
13166
  if (f.signal && f.signal.aborted) return d(new DOMException$1("Aborted", "AbortError"));
13167
13167
  var _ = new XMLHttpRequest();
13168
13168
  function v() {
@@ -13280,11 +13280,11 @@ ${d.join("\n")}`;
13280
13280
  "POST",
13281
13281
  "PUT",
13282
13282
  "TRACE"
13283
- ], Request.prototype.clone = function() {
13284
- return new Request(this, {
13283
+ ], Request$1.prototype.clone = function() {
13284
+ return new Request$1(this, {
13285
13285
  body: this._bodyInit
13286
13286
  });
13287
- }, Body.call(Request.prototype), Body.call(Response$1.prototype), Response$1.prototype.clone = function() {
13287
+ }, Body.call(Request$1.prototype), Body.call(Response$1.prototype), Response$1.prototype.clone = function() {
13288
13288
  return new Response$1(this._bodyInit, {
13289
13289
  status: this.status,
13290
13290
  statusText: this.statusText,
@@ -13319,7 +13319,7 @@ ${d.join("\n")}`;
13319
13319
  this.message = e, this.name = r, this.stack = Error(e).stack;
13320
13320
  }, DOMException$1.prototype = Object.create(Error.prototype), DOMException$1.prototype.constructor = DOMException$1;
13321
13321
  }
13322
- fetch$1.polyfill = true, g$3.fetch || (g$3.fetch = fetch$1, g$3.Headers = Headers$2, g$3.Request = Request, g$3.Response = Response$1);
13322
+ fetch$1.polyfill = true, g$3.fetch || (g$3.fetch = fetch$1, g$3.Headers = Headers$2, g$3.Request = Request$1, g$3.Response = Response$1);
13323
13323
  })), require_fetch_npm_browserify = __commonJSMin(((e, r) => {
13324
13324
  init_fetch(), r.exports = self.fetch.bind(self);
13325
13325
  })), require_HTTPTransport = __commonJSMin(((e) => {
@@ -44047,6 +44047,9 @@ ${c.sqlString}
44047
44047
  function isStaticNotebook() {
44048
44048
  return (window == null ? void 0 : window.__MARIMO_STATIC__) !== void 0;
44049
44049
  }
44050
+ function getStaticVirtualFiles() {
44051
+ return invariant(window.__MARIMO_STATIC__ !== void 0, "Not a static notebook"), window.__MARIMO_STATIC__.files;
44052
+ }
44050
44053
  function shallowCompare(e, r) {
44051
44054
  return e === r ? true : e == null || r == null ? false : Array.isArray(e) && Array.isArray(r) ? arrayShallowEquals(e, r) : typeof e == "object" && typeof r == "object" ? shallowCompareObjects(e, r) : false;
44052
44055
  }
@@ -64073,6 +64076,35 @@ ${O}`,
64073
64076
  }
64074
64077
  });
64075
64078
  }
64079
+ function deserializeBlob(e) {
64080
+ var _a2;
64081
+ let [r, c] = e.split(",", 2), d = (_a2 = /^data:(.+);base64$/.exec(r)) == null ? void 0 : _a2[1], f = atob(c), _ = f.length, v = new Uint8Array(_);
64082
+ for (let e2 = 0; e2 < _; e2++) v[e2] = f.charCodeAt(e2);
64083
+ return new Blob([
64084
+ v
64085
+ ], {
64086
+ type: d
64087
+ });
64088
+ }
64089
+ function withoutLeadingDot(e) {
64090
+ return e.startsWith(".") ? e.slice(1) : e;
64091
+ }
64092
+ function resolveVirtualFileURL(e, r = getStaticVirtualFiles()) {
64093
+ let c = maybeGetVirtualFile(e, r);
64094
+ if (!c) return e;
64095
+ let d = deserializeBlob(c);
64096
+ return URL.createObjectURL(d);
64097
+ }
64098
+ function maybeGetVirtualFile(e, r) {
64099
+ let c = document.baseURI;
64100
+ c.startsWith("blob:") && (c = c.replace("blob:", ""));
64101
+ let d = new URL(e, c).pathname, f = extractFilePath(e), _ = extractFilePath(d);
64102
+ return r[e] || r[withoutLeadingDot(e)] || r[d] || r[withoutLeadingDot(d)] || f && r[f] || _ && r[_];
64103
+ }
64104
+ function extractFilePath(e) {
64105
+ let r = e.indexOf("/@file/");
64106
+ return r === -1 ? null : e.slice(r);
64107
+ }
64076
64108
  function createPlugin(e, r = {}) {
64077
64109
  return {
64078
64110
  withData(c) {
@@ -64340,10 +64372,13 @@ ${O}`,
64340
64372
  return Logger.warn("AnyWidget value is not wire format:", e.value), e.value;
64341
64373
  }, [
64342
64374
  e.value
64343
- ]), { data: _, error: v, refetch: y } = useAsyncData(async () => await import(asRemoteURL(c).toString()).then(async (m2) => {
64344
- await m2.__tla;
64345
- return m2;
64346
- }), [
64375
+ ]), { data: _, error: v, refetch: y } = useAsyncData(async () => {
64376
+ let e2 = asRemoteURL(c).toString();
64377
+ return isStaticNotebook() && (e2 = resolveVirtualFileURL(e2)), await import(e2).then(async (m2) => {
64378
+ await m2.__tla;
64379
+ return m2;
64380
+ });
64381
+ }, [
64347
64382
  d
64348
64383
  ]), S = !!v;
64349
64384
  (0, import_react.useEffect)(() => {
@@ -71094,25 +71129,6 @@ Image URL: ${r.imageUrl}`)), contextToXml({
71094
71129
  }
71095
71130
  };
71096
71131
  const contextCallbacks = singleFacet();
71097
- function deserializeBlob(e) {
71098
- return new Promise((r, c) => {
71099
- var _a2;
71100
- try {
71101
- let [c2, d] = e.split(",", 2), f = (_a2 = /^data:(.+);base64$/.exec(c2)) == null ? void 0 : _a2[1], _ = atob(d), v = _.length, y = new Uint8Array(v);
71102
- for (let e2 = 0; e2 < v; e2++) y[e2] = _.charCodeAt(e2);
71103
- r(new Blob([
71104
- y
71105
- ], {
71106
- type: f
71107
- }));
71108
- } catch (e2) {
71109
- c(ensureError(e2));
71110
- }
71111
- });
71112
- }
71113
- function ensureError(e) {
71114
- return e instanceof Error ? e : Error(`${e}`);
71115
- }
71116
71132
  var DEFAULT_FILE_SEARCH_CONFIG = {
71117
71133
  maxDepth: 3,
71118
71134
  maxResults: 20,
@@ -71244,7 +71260,7 @@ Image URL: ${r.imageUrl}`)), contextToXml({
71244
71260
  type: S
71245
71261
  });
71246
71262
  else if (y.contents) try {
71247
- E = await deserializeBlob(base64ToDataURL(y.contents, S));
71263
+ E = deserializeBlob(base64ToDataURL(y.contents, S));
71248
71264
  } catch {
71249
71265
  E = new Blob([
71250
71266
  y.contents
@@ -73176,7 +73192,7 @@ Image URL: ${r.imageUrl}`)), contextToXml({
73176
73192
  return Logger.warn("Failed to get version from mount config"), null;
73177
73193
  }
73178
73194
  }
73179
- const marimoVersionAtom = atom(getVersionFromMountConfig() || "0.19.8-dev23"), showCodeInRunModeAtom = atom(true);
73195
+ const marimoVersionAtom = atom(getVersionFromMountConfig() || "0.19.8-dev24"), showCodeInRunModeAtom = atom(true);
73180
73196
  atom(null);
73181
73197
  var import_compiler_runtime$88 = require_compiler_runtime();
73182
73198
  function useKeydownOnElement(e, r) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marimo-team/islands",
3
- "version": "0.19.8-dev23",
3
+ "version": "0.19.8-dev24",
4
4
  "main": "dist/main.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -237,7 +237,7 @@ export class FileContextProvider extends AIContextProvider<FileContextItem> {
237
237
  fileDetails.contents as Base64String,
238
238
  mimeType,
239
239
  );
240
- blob = await deserializeBlob(dataURL);
240
+ blob = deserializeBlob(dataURL);
241
241
  } catch {
242
242
  // Fallback to treating as text
243
243
  blob = new Blob([fileDetails.contents], { type: mimeType });
@@ -6,7 +6,7 @@ import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
6
6
  import { createLoader } from "@/plugins/impl/vega/vega-loader";
7
7
  import { Functions } from "@/utils/functions";
8
8
  import type { DataURLString } from "@/utils/json/base64";
9
- import { patchFetch, patchVegaLoader } from "../files";
9
+ import { patchFetch, patchVegaLoader, resolveVirtualFileURL } from "../files";
10
10
 
11
11
  // Start a tiny server to serve virtual files
12
12
  const server = http.createServer((request, response) => {
@@ -350,6 +350,181 @@ describe("patchVegaLoader - loader.load", () => {
350
350
  });
351
351
  });
352
352
 
353
+ describe("resolveVirtualFileURL", () => {
354
+ // Mock URL.createObjectURL for jsdom environment
355
+ const mockBlobURLs = new Map<string, Blob>();
356
+ let blobCounter = 0;
357
+
358
+ beforeAll(() => {
359
+ URL.createObjectURL = vi.fn((blob: Blob) => {
360
+ const url = `blob:test-${blobCounter++}`;
361
+ mockBlobURLs.set(url, blob);
362
+ return url;
363
+ });
364
+ URL.revokeObjectURL = vi.fn((url: string) => {
365
+ mockBlobURLs.delete(url);
366
+ });
367
+ });
368
+
369
+ afterAll(() => {
370
+ mockBlobURLs.clear();
371
+ });
372
+
373
+ it("should return a blob URL for virtual files", () => {
374
+ const virtualFiles = {
375
+ "/@file/widget.js":
376
+ "data:text/javascript;base64,ZXhwb3J0IGRlZmF1bHQgeyByZW5kZXI6ICgpID0+IHt9IH0=" as DataURLString,
377
+ };
378
+
379
+ const result = resolveVirtualFileURL("/@file/widget.js", virtualFiles);
380
+
381
+ expect(result).toMatch(/^blob:/);
382
+ });
383
+
384
+ it("should return the original URL for non-virtual files", () => {
385
+ const virtualFiles = {};
386
+
387
+ const result = resolveVirtualFileURL(
388
+ "http://example.com/widget.js",
389
+ virtualFiles,
390
+ );
391
+
392
+ expect(result).toBe("http://example.com/widget.js");
393
+ });
394
+
395
+ it("should handle various URL formats", () => {
396
+ const virtualFiles = {
397
+ "/@file/module.js":
398
+ "data:text/javascript;base64,Y29uc29sZS5sb2coJ3Rlc3QnKQ==" as DataURLString,
399
+ };
400
+
401
+ const testUrls = [
402
+ "/@file/module.js",
403
+ "./@file/module.js",
404
+ "http://example.com/@file/module.js",
405
+ ];
406
+
407
+ for (const url of testUrls) {
408
+ const result = resolveVirtualFileURL(url, virtualFiles);
409
+ expect(result).toMatch(/^blob:/);
410
+ }
411
+ });
412
+
413
+ it("should create blob URL with correct content", async () => {
414
+ const jsCode = "export default { render: () => {} }";
415
+ const base64Code = btoa(jsCode);
416
+ const virtualFiles = {
417
+ "/@file/test-module.js":
418
+ `data:text/javascript;base64,${base64Code}` as DataURLString,
419
+ };
420
+
421
+ const blobUrl = resolveVirtualFileURL(
422
+ "/@file/test-module.js",
423
+ virtualFiles,
424
+ );
425
+
426
+ expect(blobUrl).toMatch(/^blob:/);
427
+ expect(URL.createObjectURL).toHaveBeenCalled();
428
+
429
+ // Verify blob content through the mock
430
+ const blob = mockBlobURLs.get(blobUrl);
431
+ expect(blob).toBeDefined();
432
+ const text = await blob!.text();
433
+ expect(text).toBe(jsCode);
434
+ });
435
+
436
+ it("should handle file:// URLs with @file/ paths", () => {
437
+ const virtualFiles = {
438
+ "/@file/local-module.js":
439
+ "data:text/javascript;base64,ZXhwb3J0IGRlZmF1bHQge30=" as DataURLString,
440
+ };
441
+
442
+ const result = resolveVirtualFileURL(
443
+ "file:///Users/test/@file/local-module.js",
444
+ virtualFiles,
445
+ );
446
+
447
+ expect(result).toMatch(/^blob:/);
448
+ });
449
+
450
+ it("should handle different MIME types", async () => {
451
+ const virtualFiles = {
452
+ "/@file/script.js":
453
+ "data:application/javascript;base64,Y29uc3QgeCA9IDE=" as DataURLString,
454
+ };
455
+
456
+ const blobUrl = resolveVirtualFileURL("/@file/script.js", virtualFiles);
457
+
458
+ // Should still be a valid blob URL
459
+ expect(blobUrl).toMatch(/^blob:/);
460
+
461
+ // Verify blob content through the mock
462
+ const blob = mockBlobURLs.get(blobUrl);
463
+ expect(blob).toBeDefined();
464
+ const text = await blob!.text();
465
+ expect(text).toBe("const x = 1");
466
+ });
467
+
468
+ it("should handle blob: base URIs correctly", () => {
469
+ // Mock document.baseURI to simulate blob: protocol
470
+ const originalBaseURI = document.baseURI;
471
+ Object.defineProperty(document, "baseURI", {
472
+ value: "blob:https://example.com/uuid",
473
+ configurable: true,
474
+ });
475
+
476
+ const virtualFiles = {
477
+ "/@file/blob-module.js":
478
+ "data:text/javascript;base64,ZXhwb3J0IGRlZmF1bHQge30=" as DataURLString,
479
+ };
480
+
481
+ const result = resolveVirtualFileURL("/@file/blob-module.js", virtualFiles);
482
+
483
+ expect(result).toMatch(/^blob:/);
484
+
485
+ // Restore original baseURI
486
+ Object.defineProperty(document, "baseURI", {
487
+ value: originalBaseURI,
488
+ configurable: true,
489
+ });
490
+ });
491
+
492
+ it("should handle data URLs with no explicit MIME type", async () => {
493
+ const virtualFiles = {
494
+ "/@file/generic.bin": "data:;base64,SGVsbG8gV29ybGQ=" as DataURLString,
495
+ };
496
+
497
+ const blobUrl = resolveVirtualFileURL("/@file/generic.bin", virtualFiles);
498
+ expect(blobUrl).toMatch(/^blob:/);
499
+
500
+ // Verify blob content through the mock
501
+ const blob = mockBlobURLs.get(blobUrl);
502
+ expect(blob).toBeDefined();
503
+ const text = await blob!.text();
504
+ expect(text).toBe("Hello World");
505
+ });
506
+
507
+ it("should match URLs with prefix paths before /@file/", async () => {
508
+ const virtualFiles = {
509
+ "/@file/4263-66-yUGhgQXp.js":
510
+ "data:application/javascript;base64,ZnVuY3Rpb24gcmVuZGVyKCkge30=" as DataURLString,
511
+ };
512
+
513
+ const blobUrl = resolveVirtualFileURL(
514
+ "https://molab.marimo.app/preview/@file/4263-66-yUGhgQXp.js",
515
+ virtualFiles,
516
+ );
517
+
518
+ expect(blobUrl).toMatch(/^blob:/);
519
+
520
+ // Verify blob content through the mock
521
+ const blob = mockBlobURLs.get(blobUrl);
522
+ expect(blob).toBeDefined();
523
+ const text = await blob!.text();
524
+ expect(text).toBe("function render() {}");
525
+ });
526
+ });
527
+
353
528
  describe("maybeGetVirtualFile utility function", () => {
354
529
  it("should handle URLs without leading dots correctly", async () => {
355
530
  const virtualFiles = {
@@ -370,6 +545,25 @@ describe("maybeGetVirtualFile utility function", () => {
370
545
  expect(text2).toBe("test");
371
546
  });
372
547
 
548
+ it("should match URLs with prefix paths before /@file/", async () => {
549
+ const virtualFiles = {
550
+ "/@file/4263-66-yUGhgQXp.js":
551
+ "data:application/javascript;base64,ZnVuY3Rpb24gcmVuZGVyKCkge30=" as DataURLString,
552
+ };
553
+
554
+ const unpatch = patchFetch(virtualFiles);
555
+
556
+ // Test URL with a prefix path before /@file/
557
+ const response = await window.fetch(
558
+ "https://molab.marimo.app/preview/@file/4263-66-yUGhgQXp.js",
559
+ );
560
+ const text = await response.text();
561
+
562
+ expect(text).toBe("function render() {}");
563
+
564
+ unpatch();
565
+ });
566
+
373
567
  it("should handle complex file:// URLs with nested paths", async () => {
374
568
  const virtualFiles = {
375
569
  "/@file/nested/data.json":
@@ -1,6 +1,8 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
3
  import type { Loader } from "@/plugins/impl/vega/vega-loader";
4
+ import { deserializeBlob } from "@/utils/blob";
5
+ import type { DataURLString } from "@/utils/json/base64";
4
6
  import { Logger } from "@/utils/Logger";
5
7
  import { getStaticVirtualFiles } from "./static-state";
6
8
  import type { StaticVirtualFiles } from "./types";
@@ -120,6 +122,24 @@ function withoutLeadingDot(path: string): string {
120
122
  return path.startsWith(".") ? path.slice(1) : path;
121
123
  }
122
124
 
125
+ /**
126
+ * Resolve a URL to a blob URL if it's a virtual file, for use with dynamic import().
127
+ * Unlike fetch, import() can't be patched, so we need to convert data URLs to blob URLs.
128
+ *
129
+ * @returns The original URL if not a virtual file, or a blob URL if it is
130
+ */
131
+ export function resolveVirtualFileURL(
132
+ url: string,
133
+ files: StaticVirtualFiles = getStaticVirtualFiles(),
134
+ ): string {
135
+ const vfile = maybeGetVirtualFile(url, files);
136
+ if (!vfile) {
137
+ return url;
138
+ }
139
+ const blob = deserializeBlob(vfile as DataURLString);
140
+ return URL.createObjectURL(blob);
141
+ }
142
+
123
143
  function maybeGetVirtualFile(
124
144
  url: string,
125
145
  files: StaticVirtualFiles,
@@ -130,14 +150,11 @@ function maybeGetVirtualFile(
130
150
  }
131
151
  const pathname = new URL(url, base).pathname;
132
152
 
133
- // If if the URL starts with file://, then using the document.baseURI
134
- // will not work. In this case, should just chop off from /@file/...
135
- if (url.startsWith("file://")) {
136
- const indexOfFile = url.indexOf("/@file/");
137
- if (indexOfFile !== -1) {
138
- url = url.slice(indexOfFile);
139
- }
140
- }
153
+ // Extract the /@file/... suffix from the URL or pathname
154
+ // This handles URLs like https://example.com/prefix/@file/foo.js
155
+ // or file:///path/to/@file/foo.js
156
+ const filePathFromUrl = extractFilePath(url);
157
+ const filePathFromPathname = extractFilePath(pathname);
141
158
 
142
159
  // Few variations to grab the URL.
143
160
  // This can happen if a static file was open at file:// or https://
@@ -145,6 +162,19 @@ function maybeGetVirtualFile(
145
162
  files[url] ||
146
163
  files[withoutLeadingDot(url)] ||
147
164
  files[pathname] ||
148
- files[withoutLeadingDot(pathname)]
165
+ files[withoutLeadingDot(pathname)] ||
166
+ (filePathFromUrl && files[filePathFromUrl]) ||
167
+ (filePathFromPathname && files[filePathFromPathname])
149
168
  );
150
169
  }
170
+
171
+ /**
172
+ * Extract the /@file/... path from a URL string
173
+ */
174
+ function extractFilePath(url: string): string | null {
175
+ const indexOfFile = url.indexOf("/@file/");
176
+ if (indexOfFile !== -1) {
177
+ return url.slice(indexOfFile);
178
+ }
179
+ return null;
180
+ }
@@ -8,6 +8,8 @@ import useEvent from "react-use-event-hook";
8
8
  import { z } from "zod";
9
9
  import { MarimoIncomingMessageEvent } from "@/core/dom/events";
10
10
  import { asRemoteURL } from "@/core/runtime/config";
11
+ import { resolveVirtualFileURL } from "@/core/static/files";
12
+ import { isStaticNotebook } from "@/core/static/static-state";
11
13
  import { useAsyncData } from "@/hooks/useAsyncData";
12
14
  import { useDeepCompareMemoize } from "@/hooks/useDeepCompareMemoize";
13
15
  import {
@@ -93,7 +95,11 @@ const AnyWidgetSlot = (
93
95
  error,
94
96
  refetch,
95
97
  } = useAsyncData(async () => {
96
- const url = asRemoteURL(jsUrl).toString();
98
+ let url = asRemoteURL(jsUrl).toString();
99
+ // In static notebooks, resolve virtual files to blob URLs for import()
100
+ if (isStaticNotebook()) {
101
+ url = resolveVirtualFileURL(url);
102
+ }
97
103
  return await import(/* @vite-ignore */ url);
98
104
  // Re-render on jsHash change (which is a hash of the contents of the file)
99
105
  // instead of a jsUrl change because URLs may change without the contents
@@ -20,7 +20,7 @@ describe("Blob serialization and deserialization", () => {
20
20
 
21
21
  test("deserializeBlob should deserialize a base64 string to a Blob", async () => {
22
22
  const serialized = await serializeBlob(testBlob);
23
- const deserialized = await deserializeBlob(serialized);
23
+ const deserialized = deserializeBlob(serialized);
24
24
  expect(deserialized).toBeDefined();
25
25
  expect(deserialized.size).toBe(testBlob.size);
26
26
  expect(deserialized.type).toBe(testBlob.type);
@@ -28,7 +28,7 @@ describe("Blob serialization and deserialization", () => {
28
28
 
29
29
  test("deserialized Blob should contain the original content", async () => {
30
30
  const serialized = await serializeBlob(testBlob);
31
- const deserialized = await deserializeBlob(serialized);
31
+ const deserialized = deserializeBlob(serialized);
32
32
  const reader = new FileReader();
33
33
  // eslint-disable-next-line unicorn/prefer-blob-reading-methods
34
34
  reader.readAsText(deserialized);
@@ -45,7 +45,7 @@ describe("Blob serialization and deserialization", () => {
45
45
  type: "image/png",
46
46
  });
47
47
  const serialized = await serializeBlob(imageBlob);
48
- const deserialized = await deserializeBlob(serialized);
48
+ const deserialized = deserializeBlob(serialized);
49
49
  expect(deserialized).toBeDefined();
50
50
  expect(deserialized.size).toBe(imageBlob.size);
51
51
  expect(deserialized.type).toBe(imageBlob.type);
package/src/utils/blob.ts CHANGED
@@ -14,32 +14,19 @@ export function serializeBlob<T>(blob: Blob): Promise<DataURLString> {
14
14
  });
15
15
  }
16
16
 
17
- export function deserializeBlob(serializedBlob: DataURLString): Promise<Blob> {
18
- return new Promise((resolve, reject) => {
19
- try {
20
- // Extract the base64 data from the data URL
21
- const [prefix, base64Data] = serializedBlob.split(",", 2);
22
- const mimeType = /^data:(.+);base64$/.exec(prefix)?.[1];
23
- // Decode the base64 string
24
- const binaryString = atob(base64Data);
25
- // Convert the binary string to an array buffer
26
- const len = binaryString.length;
27
- const bytes = new Uint8Array(len);
28
- for (let i = 0; i < len; i++) {
29
- bytes[i] = binaryString.charCodeAt(i);
30
- }
31
- // Create a new Blob from the array buffer
32
- const blob = new Blob([bytes], { type: mimeType });
33
- resolve(blob);
34
- } catch (error) {
35
- reject(ensureError(error));
36
- }
37
- });
38
- }
39
-
40
- function ensureError(error: unknown): Error {
41
- if (error instanceof Error) {
42
- return error;
17
+ export function deserializeBlob(serializedBlob: DataURLString): Blob {
18
+ // Extract the base64 data from the data URL
19
+ const [prefix, base64Data] = serializedBlob.split(",", 2);
20
+ const mimeType = /^data:(.+);base64$/.exec(prefix)?.[1];
21
+ // Decode the base64 string
22
+ const binaryString = atob(base64Data);
23
+ // Convert the binary string to an array buffer
24
+ const len = binaryString.length;
25
+ const bytes = new Uint8Array(len);
26
+ for (let i = 0; i < len; i++) {
27
+ bytes[i] = binaryString.charCodeAt(i);
43
28
  }
44
- return new Error(`${error}`);
29
+ // Create a new Blob from the array buffer
30
+ const blob = new Blob([bytes], { type: mimeType });
31
+ return blob;
45
32
  }