From bd9efcca92c6d468bc58fb68775a22a4221d1cdc Mon Sep 17 00:00:00 2001 From: mazuh Date: Tue, 21 Nov 2023 16:04:30 -0300 Subject: [PATCH] opfs polyfill --- package-lock.json | 73 +++++++++++++++++++ package.json | 1 + .../origin-private-file-system.test.ts | 40 ++++++---- src/services/origin-private-file-system.ts | 4 +- .../native-file-system-adapter.d.ts | 5 ++ 5 files changed, 107 insertions(+), 16 deletions(-) create mode 100644 src/vendor-types/native-file-system-adapter.d.ts diff --git a/package-lock.json b/package-lock.json index e39dfe2..e7466d8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "postmaiden", "version": "0.0.0", "dependencies": { + "native-file-system-adapter": "^3.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", "uuid": "^9.0.1" @@ -5662,6 +5663,29 @@ "bser": "2.1.1" } }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "optional": true, + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -8788,12 +8812,52 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/native-file-system-adapter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/native-file-system-adapter/-/native-file-system-adapter-3.0.0.tgz", + "integrity": "sha512-IXwQiLiS7UlrlUetr9rHp+6uAAHT3291w2FGse5rdrQ7YXKtZHaqC4+tEXHMXVcevwsJNB3c7q9KO1Iu3IxgLw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=14.8.0" + }, + "optionalDependencies": { + "fetch-blob": "^3.2.0" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "optional": true, + "engines": { + "node": ">=10.5.0" + } + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -10219,6 +10283,15 @@ "makeerror": "1.0.12" } }, + "node_modules/web-streams-polyfill": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "optional": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", diff --git a/package.json b/package.json index fbc4a97..a3e1319 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "preview": "vite preview" }, "dependencies": { + "native-file-system-adapter": "^3.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", "uuid": "^9.0.1" diff --git a/src/services/origin-private-file-system.test.ts b/src/services/origin-private-file-system.test.ts index 7bec097..d3f4f12 100644 --- a/src/services/origin-private-file-system.test.ts +++ b/src/services/origin-private-file-system.test.ts @@ -1,27 +1,37 @@ +import { getOriginPrivateDirectory } from "native-file-system-adapter"; import { makeOpfsAdapter } from "./origin-private-file-system"; +jest.mock("native-file-system-adapter", () => ({ + getOriginPrivateDirectory: jest.fn(), +})); + describe("Origin private file system (OPFS) adapter", () => { beforeAll(() => { + const getDirectoryMock = jest.fn().mockImplementation(() => ({ + getFileHandle: jest.fn().mockImplementation(() => ({ + getFile: jest.fn().mockResolvedValue({ + text: jest + .fn() + .mockResolvedValue('{ "taste": "pepsicola", "surprise": false }'), + }), + createWritable: jest.fn().mockResolvedValue({ + write: jest.fn(), + close: jest.fn(), + }), + })), + })); + Object.defineProperty(global.navigator, "storage", { value: { - getDirectory: jest.fn().mockImplementation(() => ({ - getFileHandle: jest.fn().mockImplementation(() => ({ - getFile: jest.fn().mockResolvedValue({ - text: jest - .fn() - .mockResolvedValue( - '{ "taste": "pepsicola", "surprise": false }' - ), - }), - createWritable: jest.fn().mockResolvedValue({ - write: jest.fn(), - close: jest.fn(), - }), - })), - })), + getDirectory: getDirectoryMock, }, writable: true, }); + + // if the polyfill gets removed, this line below must be removed too and that's it. + (getOriginPrivateDirectory as jest.Mock).mockImplementation(() => + global.navigator.storage.getDirectory() + ); }); it("Integrates with real OPFS to retrieve parsed JSON content", async () => { diff --git a/src/services/origin-private-file-system.ts b/src/services/origin-private-file-system.ts index a39a575..69c3683 100644 --- a/src/services/origin-private-file-system.ts +++ b/src/services/origin-private-file-system.ts @@ -1,3 +1,5 @@ +import { getOriginPrivateDirectory } from "native-file-system-adapter"; + export interface OriginPrivateFileSystemAdapter { retrieve: () => Promise; persist: (data: T) => Promise; @@ -6,7 +8,7 @@ export interface OriginPrivateFileSystemAdapter { export async function makeOpfsAdapter( filename: string ): Promise> { - const opfsRoot = await navigator.storage.getDirectory(); + const opfsRoot = await getOriginPrivateDirectory(); const fileHandle = await opfsRoot.getFileHandle(filename, { create: true, }); diff --git a/src/vendor-types/native-file-system-adapter.d.ts b/src/vendor-types/native-file-system-adapter.d.ts new file mode 100644 index 0000000..33055b2 --- /dev/null +++ b/src/vendor-types/native-file-system-adapter.d.ts @@ -0,0 +1,5 @@ +// See: https://github.com/jimmywarting/native-file-system-adapter/issues/50 + +declare module "native-file-system-adapter" { + export * from "native-file-system-adapter/types/mod"; +}