From 4b94f1e7682190336ed2e7b387165795c154b3e9 Mon Sep 17 00:00:00 2001 From: make-github-pseudonymous-again <5165674+make-github-pseudonymous-again@users.noreply.github.com> Date: Mon, 13 May 2024 06:35:20 +0200 Subject: [PATCH 01/19] :rewind: revert: Bump pdfjs-dist to v3.11.174 explicitly. This reverts commit 182340d4cd21b4f570b4e3c230e34a23b7b6f2a3. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6a97ef2d0..490d077ed 100644 --- a/package.json +++ b/package.json @@ -115,7 +115,7 @@ "meteor-node-stubs": "^1.2.5", "notistack": "^3.0.1", "papaparse": "^5.4.1", - "pdfjs-dist": "~3.11.174", + "pdfjs-dist": "~3.11.0", "qrcode.react": "^3.1.0", "rate-limiter-flexible": "^3.0.0", "react": "^18.2.0", From 48d067aac6c12ca1bccb5938f21612ecc726326f Mon Sep 17 00:00:00 2001 From: make-github-pseudonymous-again <5165674+make-github-pseudonymous-again@users.noreply.github.com> Date: Mon, 13 May 2024 06:36:28 +0200 Subject: [PATCH 02/19] :rewind: revert: Upgrade dependency pdfjs-dist to ~3.11.0. This reverts commit de603a93903b65caf66b77036c4f2e76cd21358a. --- package-lock.json | 21 ++++++++++----------- package.json | 2 +- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index 02b936593..6f12df552 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13617,12 +13617,6 @@ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" }, - "path2d-polyfill": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path2d-polyfill/-/path2d-polyfill-2.0.1.tgz", - "integrity": "sha512-ad/3bsalbbWhmBo0D6FZ4RNMwsLsPpL6gnvhuSaU5Vm7b06Kr5ubSltQQ0T7YKsiJQO+g22zJ4dJKNTXIyOXtA==", - "optional": true - }, "pathval": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", @@ -13630,12 +13624,12 @@ "dev": true }, "pdfjs-dist": { - "version": "3.11.174", - "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-3.11.174.tgz", - "integrity": "sha512-TdTZPf1trZ8/UFu5Cx/GXB7GZM30LT+wWUNfsi6Bq8ePLnb+woNKtDymI2mxZYBpMbonNFqKmiz684DIfnd8dA==", + "version": "3.1.81", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-3.1.81.tgz", + "integrity": "sha512-hZHVVbjU2Ac1VYyPFrg9fBcyS7EEdB8YFy5upk6LmnsXl10WxAavdiViGWi2C/xK0GZObEpSSJU1VnoF9t8n9w==", "requires": { - "canvas": "^2.11.2", - "path2d-polyfill": "^2.0.1" + "canvas": "^2.10.2", + "web-streams-polyfill": "^3.2.1" } }, "pend": { @@ -16444,6 +16438,11 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" }, + "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==" + }, "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", diff --git a/package.json b/package.json index 490d077ed..1ddbe1630 100644 --- a/package.json +++ b/package.json @@ -115,7 +115,7 @@ "meteor-node-stubs": "^1.2.5", "notistack": "^3.0.1", "papaparse": "^5.4.1", - "pdfjs-dist": "~3.11.0", + "pdfjs-dist": "~3.1.81", "qrcode.react": "^3.1.0", "rate-limiter-flexible": "^3.0.0", "react": "^18.2.0", From 7ab87e5c34973e2b65545149cce51d6d932058f5 Mon Sep 17 00:00:00 2001 From: make-github-pseudonymous-again <5165674+make-github-pseudonymous-again@users.noreply.github.com> Date: Sun, 12 May 2024 10:10:10 +0200 Subject: [PATCH 03/19] :gear: config(ci): Always run NPM postinstall hook in workflows. --- .github/actions/install/action.yml | 18 ++++++++++++++++++ .github/workflows/ci:build.yml | 2 +- .github/workflows/ci:commit-msg.yml | 2 +- .github/workflows/ci:lint-config.yml | 2 +- .github/workflows/ci:lint.yml | 2 +- .github/workflows/ci:test.yml | 4 ++-- .github/workflows/ci:type-check.yml | 2 +- 7 files changed, 25 insertions(+), 7 deletions(-) create mode 100644 .github/actions/install/action.yml diff --git a/.github/actions/install/action.yml b/.github/actions/install/action.yml new file mode 100644 index 000000000..bf8bc447c --- /dev/null +++ b/.github/actions/install/action.yml @@ -0,0 +1,18 @@ +name: install +description: > + Installs Meteor and NPM dependencies. + +runs: + + using: composite + + steps: + + - name: Install 💾 + id: install + uses: meteor-actions/install@v6 + + - name: Postinstall 🪝 + if: steps.install.outputs.ran-npm-install-hooks != 'true' + shell: bash + run: meteor npm run postinstall diff --git a/.github/workflows/ci:build.yml b/.github/workflows/ci:build.yml index c818ababc..09b984da2 100644 --- a/.github/workflows/ci:build.yml +++ b/.github/workflows/ci:build.yml @@ -34,7 +34,7 @@ jobs: uses: actions/checkout@v4 - name: Install 💾 - uses: meteor-actions/install@v6 + uses: ./.github/actions/install - name: Get Meteor's Node version id: meteor-node diff --git a/.github/workflows/ci:commit-msg.yml b/.github/workflows/ci:commit-msg.yml index a715a858e..9b103a2d3 100644 --- a/.github/workflows/ci:commit-msg.yml +++ b/.github/workflows/ci:commit-msg.yml @@ -24,7 +24,7 @@ jobs: fetch-depth: 0 - name: Install 💾 - uses: meteor-actions/install@v6 + uses: ./.github/actions/install - name: Lint last pushed commit 👕 if: github.event_name == 'push' diff --git a/.github/workflows/ci:lint-config.yml b/.github/workflows/ci:lint-config.yml index bbb329847..eed556ed6 100644 --- a/.github/workflows/ci:lint-config.yml +++ b/.github/workflows/ci:lint-config.yml @@ -22,7 +22,7 @@ jobs: uses: actions/checkout@v4 - name: Install 💾 - uses: meteor-actions/install@v6 + uses: ./.github/actions/install - name: Lint config 👕 run: meteor npm run lint-config diff --git a/.github/workflows/ci:lint.yml b/.github/workflows/ci:lint.yml index a528689b8..dd3542490 100644 --- a/.github/workflows/ci:lint.yml +++ b/.github/workflows/ci:lint.yml @@ -22,7 +22,7 @@ jobs: uses: actions/checkout@v4 - name: Install 💾 - uses: meteor-actions/install@v6 + uses: ./.github/actions/install - name: Lint 👕 run: meteor npm run lint diff --git a/.github/workflows/ci:test.yml b/.github/workflows/ci:test.yml index 1e106c326..c00d7103c 100644 --- a/.github/workflows/ci:test.yml +++ b/.github/workflows/ci:test.yml @@ -31,7 +31,7 @@ jobs: key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - name: Install 💾 - uses: meteor-actions/install@v6 + uses: ./.github/actions/install - name: Cache build 💽 uses: meteor-actions/cache-build@v4 @@ -92,7 +92,7 @@ jobs: key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - name: Install 💾 - uses: meteor-actions/install@v6 + uses: ./.github/actions/install - name: Cache build 💽 uses: meteor-actions/cache-build@v4 diff --git a/.github/workflows/ci:type-check.yml b/.github/workflows/ci:type-check.yml index f3d5394a8..1cb9d96cb 100644 --- a/.github/workflows/ci:type-check.yml +++ b/.github/workflows/ci:type-check.yml @@ -22,7 +22,7 @@ jobs: uses: actions/checkout@v4 - name: Install 💾 - uses: meteor-actions/install@v6 + uses: ./.github/actions/install - name: TypeScript check ☑️ run: meteor npm run tsc From 861cf9470ca2bb190008f3471b22468b4b6b97fd Mon Sep 17 00:00:00 2001 From: make-github-pseudonymous-again <5165674+make-github-pseudonymous-again@users.noreply.github.com> Date: Sat, 11 May 2024 23:31:24 +0200 Subject: [PATCH 04/19] :umbrella: test(pdf): Prevent regression when upgrading pdfjs-dist. --- imports/lib/pdf/pdf.tests.ts | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 imports/lib/pdf/pdf.tests.ts diff --git a/imports/lib/pdf/pdf.tests.ts b/imports/lib/pdf/pdf.tests.ts new file mode 100644 index 000000000..502f51cee --- /dev/null +++ b/imports/lib/pdf/pdf.tests.ts @@ -0,0 +1,27 @@ +// eslint-disable-next-line import/no-unassigned-import +import 'regenerator-runtime/runtime.js'; + +import {client, server} from '../../_test/fixtures'; + +import {fetchPDF} from './pdf'; + +const document = `%PDF-1. +1 0 obj<>endobj +2 0 obj<>endobj +3 0 obj<>endobj +trailer <> +`; + +client(__filename, () => { + it('should work on the client', async () => { + const data = new TextEncoder().encode(document); + await fetchPDF({data}); + }); +}); + +server(__filename, () => { + it('should work on the server', async () => { + const data = new TextEncoder().encode(document); + await fetchPDF({data}); + }); +}); From 99f4c4b1a07bb270b3b1287ffd2431b2af8bec6b Mon Sep 17 00:00:00 2001 From: make-github-pseudonymous-again <5165674+make-github-pseudonymous-again@users.noreply.github.com> Date: Mon, 13 May 2024 14:00:46 +0200 Subject: [PATCH 05/19] :woman_technologist: dx: Fix warnings caused by example PDF used in tests. --- imports/lib/pdf/pdf.tests.ts | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/imports/lib/pdf/pdf.tests.ts b/imports/lib/pdf/pdf.tests.ts index 502f51cee..621fc8a9b 100644 --- a/imports/lib/pdf/pdf.tests.ts +++ b/imports/lib/pdf/pdf.tests.ts @@ -5,11 +5,20 @@ import {client, server} from '../../_test/fixtures'; import {fetchPDF} from './pdf'; -const document = `%PDF-1. -1 0 obj<>endobj -2 0 obj<>endobj -3 0 obj<>endobj -trailer <> +const document = `%PDF-1.0 +1 0 obj<>endobj +2 0 obj<>endobj +3 0 obj<>endobj +xref +0 4 +0000000000 65535 f +0000000009 00000 n +0000000052 00000 n +0000000101 00000 n +trailer<> +startxref +147 +%EOF `; client(__filename, () => { From d4f5cc25f8fdc84edb275d24e22c5da2321948dd Mon Sep 17 00:00:00 2001 From: make-github-pseudonymous-again <5165674+make-github-pseudonymous-again@users.noreply.github.com> Date: Mon, 13 May 2024 15:34:55 +0200 Subject: [PATCH 06/19] :woman_technologist: dx(pdf): Disable functions that are not isomorphic yet. --- imports/lib/pdf/pdfthumbnails.ts | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/imports/lib/pdf/pdfthumbnails.ts b/imports/lib/pdf/pdfthumbnails.ts index 826213eea..2cb905bc9 100644 --- a/imports/lib/pdf/pdfthumbnails.ts +++ b/imports/lib/pdf/pdfthumbnails.ts @@ -161,8 +161,12 @@ export const thumbnailDataURL = async ( const toBlob = async ( canvas: HTMLCanvasElement, {type, quality}: RenderOptions, -) => - new Promise((resolve, reject) => { +) => { + if (Meteor.isServer) { + throw new Error('not implemented'); + } + + return new Promise((resolve, reject) => { canvas.toBlob( (blob: Blob | null) => { if (blob === null) { @@ -175,6 +179,7 @@ const toBlob = async ( quality, ); }); +}; export const thumbnailBlob = async ( document: DocumentInitParameters, @@ -232,6 +237,10 @@ export const thumbnailBuffer = async ( pageOptions: PageOptions, canvasRenderOptions: CanvasRenderOptions, ) => { + if (Meteor.isClient) { + throw new Error('not implemented'); + } + const renderContext = await thumbnailRender(document, pageOptions); const canvas = renderContext.canvasContext.canvas as unknown as Canvas; const buffer = await toBuffer(canvas, canvasRenderOptions); @@ -244,6 +253,10 @@ export const thumbnailStream = async ( pageOptions: PageOptions, {type = 'image/png', config}: CanvasRenderOptions, ): Promise => { + if (Meteor.isClient) { + throw new Error('not implemented'); + } + const renderContext = await thumbnailRender(document, pageOptions); const canvas = renderContext.canvasContext.canvas as unknown as Canvas; let stream: Readable; From 4eff7d482c3e4476d70a5d66aeb228d026a60b29 Mon Sep 17 00:00:00 2001 From: make-github-pseudonymous-again <5165674+make-github-pseudonymous-again@users.noreply.github.com> Date: Mon, 13 May 2024 17:37:25 +0200 Subject: [PATCH 07/19] :woman_technologist: dx: Facilitate writing isomorphic tests. --- imports/_test/fixtures.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/imports/_test/fixtures.ts b/imports/_test/fixtures.ts index a83510e82..8f60c8635 100644 --- a/imports/_test/fixtures.ts +++ b/imports/_test/fixtures.ts @@ -132,6 +132,11 @@ export const server = (title, fn) => { } }; +export const isomorphic = (title, fn) => { + client(title, fn); + server(title, fn); +}; + export const throws = async ( fn: () => Promise, expected: string | RegExp, From f12cdaa6517593aa600555f1f8f8aeb2125d6b8a Mon Sep 17 00:00:00 2001 From: make-github-pseudonymous-again <5165674+make-github-pseudonymous-again@users.noreply.github.com> Date: Mon, 13 May 2024 17:48:35 +0200 Subject: [PATCH 08/19] :recycle: refactor: Factor out data URL constructor. --- imports/_test/png.ts | 5 +++-- imports/lib/dataURL.ts | 3 +++ imports/lib/png/dataURL.ts | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 imports/lib/dataURL.ts diff --git a/imports/_test/png.ts b/imports/_test/png.ts index 3d1bca70e..4501c40d2 100644 --- a/imports/_test/png.ts +++ b/imports/_test/png.ts @@ -1,3 +1,5 @@ +import pngDataURL from '../lib/png/dataURL'; + const base64Encoded = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='; @@ -6,8 +8,7 @@ export const randomPNGBuffer = async () => { return Buffer.from(base64Encoded, 'base64'); }; -export const randomPNGDataURI = (): string => - `data:image/png;base64,${base64Encoded}`; +export const randomPNGDataURI = (): string => pngDataURL(base64Encoded); export const randomPNGResponse = async (): Promise => fetch(randomPNGDataURI()); diff --git a/imports/lib/dataURL.ts b/imports/lib/dataURL.ts new file mode 100644 index 000000000..0da73dd30 --- /dev/null +++ b/imports/lib/dataURL.ts @@ -0,0 +1,3 @@ +const dataURL = (mimeType: string, base64: string) => + `data:${mimeType};base64,${base64}`; +export default dataURL; diff --git a/imports/lib/png/dataURL.ts b/imports/lib/png/dataURL.ts index 0ff937c9c..b8a265a53 100644 --- a/imports/lib/png/dataURL.ts +++ b/imports/lib/png/dataURL.ts @@ -1,2 +1,4 @@ -const dataURL = (base64: string) => `data:image/png;base64,${base64}`; +import _dataURL from '../dataURL'; + +const dataURL = (base64: string) => _dataURL('image/png', base64); export default dataURL; From cf40e0701be062860ec3ce883e45e52648839c90 Mon Sep 17 00:00:00 2001 From: make-github-pseudonymous-again <5165674+make-github-pseudonymous-again@users.noreply.github.com> Date: Mon, 13 May 2024 18:04:40 +0200 Subject: [PATCH 09/19] :woman_technologist: dx(server): Add modern `fetch` polyfill. --- package-lock.json | 58 +++++++++++++++++++++++++++++++++++++--- package.json | 1 + server/polyfill.ts | 3 +++ server/polyfill/fetch.ts | 25 +++++++++++++++++ 4 files changed, 83 insertions(+), 4 deletions(-) create mode 100644 server/polyfill/fetch.ts diff --git a/package-lock.json b/package-lock.json index 6f12df552..226876a5c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2448,6 +2448,16 @@ "rimraf": "^3.0.2", "semver": "^7.3.5", "tar": "^6.1.11" + }, + "dependencies": { + "node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "requires": { + "whatwg-url": "^5.0.0" + } + } } }, "@mongodb-js/saslprep": { @@ -6766,6 +6776,11 @@ "integrity": "sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==", "dev": true }, + "data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==" + }, "data-view-buffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", @@ -7376,6 +7391,17 @@ "enquirer": "^2.3.6", "meow": "^6.1.1", "node-fetch": "^2.6.1" + }, + "dependencies": { + "node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "requires": { + "whatwg-url": "^5.0.0" + } + } } }, "emoji-regex": { @@ -9002,6 +9028,15 @@ "pend": "~1.2.0" } }, + "fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "requires": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + } + }, "fflate": { "version": "0.4.8", "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz", @@ -9276,6 +9311,14 @@ "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", "dev": true }, + "formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "requires": { + "fetch-blob": "^3.1.2" + } + }, "formidable": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.1.tgz", @@ -12565,12 +12608,19 @@ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==" }, + "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==" + }, "node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", "requires": { - "whatwg-url": "^5.0.0" + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" } }, "node-gyp": { diff --git a/package.json b/package.json index 1ddbe1630..6b967cc07 100644 --- a/package.json +++ b/package.json @@ -113,6 +113,7 @@ "medidoc": "1.1.0", "mem": "^8.1.1", "meteor-node-stubs": "^1.2.5", + "node-fetch": "^3.3.2", "notistack": "^3.0.1", "papaparse": "^5.4.1", "pdfjs-dist": "~3.1.81", diff --git a/server/polyfill.ts b/server/polyfill.ts index 7678d9eca..0125dead4 100644 --- a/server/polyfill.ts +++ b/server/polyfill.ts @@ -3,3 +3,6 @@ import 'regenerator-runtime/runtime.js'; // eslint-disable-next-line import/no-unassigned-import import 'core-js/features/string/replace-all'; + +// eslint-disable-next-line import/no-unassigned-import +import './polyfill/fetch'; diff --git a/server/polyfill/fetch.ts b/server/polyfill/fetch.ts new file mode 100644 index 000000000..6dc26f591 --- /dev/null +++ b/server/polyfill/fetch.ts @@ -0,0 +1,25 @@ +// SEE +// https://github.com/node-fetch/node-fetch/blob/8b3320d2a7c07bce4afc6b2bf6c3bbddda85b01f/README.md#providing-global-access + +import process from 'process'; + +import fetch, {Blob, Headers, Request, Response} from 'node-fetch'; + +import semver from 'semver'; + +if (semver.gte(process.version, '18.0.0')) { + // eslint-disable-next-line unicorn/prefer-module + throw new Error(`Remove node-fetch polyfill located at '${__filename}'.`); +} + +if (Meteor.isServer && !globalThis.fetch) { + // @ts-expect-error fetch polyfill has incorrect type. + globalThis.fetch = fetch; + globalThis.Blob = Blob; + // @ts-expect-error Headers polyfill has incorrect type. + globalThis.Headers = Headers; + // @ts-expect-error Request polyfill has incorrect type. + globalThis.Request = Request; + // @ts-expect-error Response polyfill has incorrect type. + globalThis.Response = Response; +} From 5f1d7f5bdf86fc0ec7610857c5eb42f95ca561e4 Mon Sep 17 00:00:00 2001 From: make-github-pseudonymous-again <5165674+make-github-pseudonymous-again@users.noreply.github.com> Date: Mon, 13 May 2024 18:06:15 +0200 Subject: [PATCH 10/19] :woman_technologist: dx: Define Blob from/to DataURL conversion utilities. --- imports/lib/blob/blobFromDataURL.ts | 6 +++++ imports/lib/blob/blobToDataURL.ts | 39 +++++++++++++++++++++++++++++ imports/lib/blob/dataURL.tests.ts | 26 +++++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 imports/lib/blob/blobFromDataURL.ts create mode 100644 imports/lib/blob/blobToDataURL.ts create mode 100644 imports/lib/blob/dataURL.tests.ts diff --git a/imports/lib/blob/blobFromDataURL.ts b/imports/lib/blob/blobFromDataURL.ts new file mode 100644 index 000000000..1ab1e4a23 --- /dev/null +++ b/imports/lib/blob/blobFromDataURL.ts @@ -0,0 +1,6 @@ +const blobFromDataURL = async (url: string): Promise => { + const response = await fetch(url); + return response.blob(); +}; + +export default blobFromDataURL; diff --git a/imports/lib/blob/blobToDataURL.ts b/imports/lib/blob/blobToDataURL.ts new file mode 100644 index 000000000..b6cbcaecf --- /dev/null +++ b/imports/lib/blob/blobToDataURL.ts @@ -0,0 +1,39 @@ +const _blobToDataURLClient = async (blob: Blob): Promise => + new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.addEventListener('load', (_e) => { + resolve(reader.result as string); + }); + + reader.addEventListener('error', (_e) => { + reject(reader.error); + }); + + reader.addEventListener('abort', (_e) => { + reject(new Error('Read aborted')); + }); + reader.readAsDataURL(blob); + }); + +const _blobToDataURLServer = async (blob: Blob): Promise => { + const mimeType = blob.type; + if (mimeType === '') { + throw new Error('unknown mime-type'); + } + + const arrayBuffer = await blob.arrayBuffer(); + + const {Buffer} = await import('buffer'); + const buffer = Buffer.from(arrayBuffer); + + const base64 = buffer.toString('base64'); + + const {default: dataURL} = await import('../dataURL'); + return dataURL(mimeType, base64); +}; + +const blobToDataURL = Meteor.isServer + ? _blobToDataURLServer + : _blobToDataURLClient; + +export default blobToDataURL; diff --git a/imports/lib/blob/dataURL.tests.ts b/imports/lib/blob/dataURL.tests.ts new file mode 100644 index 000000000..4328d3bcd --- /dev/null +++ b/imports/lib/blob/dataURL.tests.ts @@ -0,0 +1,26 @@ +// eslint-disable-next-line import/no-unassigned-import +import 'regenerator-runtime/runtime.js'; + +import {assert} from 'chai'; + +import {isomorphic} from '../../_test/fixtures'; +import {randomPNGDataURI} from '../../_test/png'; + +import blobFromDataURL from './blobFromDataURL'; +import blobToDataURL from './blobToDataURL'; + +isomorphic(__filename, () => { + it('should allow to convert back and forth from a dataURL', async () => { + if (Meteor.isServer) { + await import('../../../server/polyfill/fetch'); + } + + const url = randomPNGDataURI(); + + const blob = await blobFromDataURL(url); + assert.instanceOf(blob, Blob); + + const result = await blobToDataURL(blob); + assert.equal(result, url); + }); +}); From 12d32d7f6aaa5dc8497513f4486a9a5c451f8efc Mon Sep 17 00:00:00 2001 From: make-github-pseudonymous-again <5165674+make-github-pseudonymous-again@users.noreply.github.com> Date: Mon, 13 May 2024 18:08:50 +0200 Subject: [PATCH 11/19] :test_tube: test(pdf): Test thumbnail-generating functions. --- imports/lib/pdf/pdfthumbmails.tests.ts | 141 +++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 imports/lib/pdf/pdfthumbmails.tests.ts diff --git a/imports/lib/pdf/pdfthumbmails.tests.ts b/imports/lib/pdf/pdfthumbmails.tests.ts new file mode 100644 index 000000000..c02e708b5 --- /dev/null +++ b/imports/lib/pdf/pdfthumbmails.tests.ts @@ -0,0 +1,141 @@ +import {Buffer} from 'buffer'; +import {Readable} from 'stream'; + +// eslint-disable-next-line import/no-unassigned-import +import 'regenerator-runtime/runtime.js'; + +import {assert} from 'chai'; + +import {client, server, throws} from '../../_test/fixtures'; + +import dataURL from '../dataURL'; +import blobToDataURL from '../blob/blobToDataURL'; + +import { + thumbnailDataURL, + thumbnailStream, + thumbnailBlob, + thumbnailBuffer, +} from './pdfthumbnails'; + +const document = `%PDF-1.0 +1 0 obj<>endobj +2 0 obj<>endobj +3 0 obj<>endobj +xref +0 4 +0000000000 65535 f +0000000009 00000 n +0000000052 00000 n +0000000101 00000 n +trailer<> +startxref +147 +%EOF +`; + +client(__filename, () => { + it('thumbnailDataURL should work', async () => { + const data = new TextEncoder().encode(document); + const blob = new Blob([data.buffer], {type: 'application/pdf'}); + const url = await blobToDataURL(blob); + const result = await thumbnailDataURL( + url, + {minWidth: 10, minHeight: 10}, + {type: 'image/png'}, + ); + const expected = dataURL( + 'image/png', + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARzQklUCAgICHwIZIgAAAAXSURBVBhXY/wPBAxEAMZRhfhCifrBAwDBjyfjq7VgpgAAAABJRU5ErkJggg==', + ); + assert.equal(result, expected); + }); + + it('thumbnailBlob should work', async () => { + const data = new TextEncoder().encode(document); + const result = await thumbnailBlob( + {data}, + {minWidth: 200, minHeight: 200}, + {type: 'image/png'}, + ); + assert.instanceOf(result, Blob); + }); + + it('thumbnailBuffer should NOT be implemented', async () => { + const data = new TextEncoder().encode(document); + await throws( + async () => + thumbnailBuffer( + {data}, + {minWidth: 200, minHeight: 200}, + {type: 'image/png'}, + ), + /not implemented/i, + ); + }); + + it('thumbnailStream should NOT be implemented', async () => { + const data = new TextEncoder().encode(document); + await throws( + async () => + thumbnailStream( + {data}, + {minWidth: 200, minHeight: 200}, + {type: 'image/png'}, + ), + /not implemented/i, + ); + }); +}); + +server(__filename, () => { + it('thumbnailDataURL should NOT be implemented', async () => { + const data = new TextEncoder().encode(document); + const buffer = Buffer.from(data).toString('base64'); + const url = dataURL('image/png', buffer); + + await throws( + async () => + thumbnailDataURL( + url, + {minWidth: 200, minHeight: 200}, + {type: 'image/png'}, + ), + /not implemented/i, + ); + }); + + it('thumbnailBlob should work', async () => { + const data = new TextEncoder().encode(document); + + await throws( + async () => + thumbnailBlob( + {data}, + {minWidth: 200, minHeight: 200}, + {type: 'image/png'}, + ), + /not implemented/i, + ); + }); + + it('thumbnailBuffer should work', async () => { + const data = new TextEncoder().encode(document); + const result = await thumbnailBuffer( + {data}, + {minWidth: 200, minHeight: 200}, + {type: 'image/png'}, + ); + assert.instanceOf(result, Buffer); + }); + + it('thumbnailStream should work', async () => { + const data = new TextEncoder().encode(document); + const result = await thumbnailStream( + {data}, + {minWidth: 200, minHeight: 200}, + {type: 'image/png'}, + ); + assert.instanceOf(result, Readable); + }); +}); From 4fb14f277ebae41cebdef52f048fd83d7f445898 Mon Sep 17 00:00:00 2001 From: make-github-pseudonymous-again <5165674+make-github-pseudonymous-again@users.noreply.github.com> Date: Mon, 13 May 2024 18:17:42 +0200 Subject: [PATCH 12/19] :woman_technologist: dx: Factor out PDF example from tests. --- imports/_test/pdf.ts | 19 +++++++++++++++ imports/lib/pdf/pdf.tests.ts | 21 +++------------- imports/lib/pdf/pdfthumbmails.tests.ts | 33 +++++++------------------- 3 files changed, 31 insertions(+), 42 deletions(-) create mode 100644 imports/_test/pdf.ts diff --git a/imports/_test/pdf.ts b/imports/_test/pdf.ts new file mode 100644 index 000000000..06a8c701c --- /dev/null +++ b/imports/_test/pdf.ts @@ -0,0 +1,19 @@ +const document = `%PDF-1.0 +1 0 obj<>endobj +2 0 obj<>endobj +3 0 obj<>endobj +xref +0 4 +0000000000 65535 f +0000000009 00000 n +0000000052 00000 n +0000000101 00000 n +trailer<> +startxref +147 +%EOF +`; + +export const randomPDFUint8Array = (): Uint8Array => { + return new TextEncoder().encode(document); +}; diff --git a/imports/lib/pdf/pdf.tests.ts b/imports/lib/pdf/pdf.tests.ts index 621fc8a9b..8b617d7a0 100644 --- a/imports/lib/pdf/pdf.tests.ts +++ b/imports/lib/pdf/pdf.tests.ts @@ -2,35 +2,20 @@ import 'regenerator-runtime/runtime.js'; import {client, server} from '../../_test/fixtures'; +import {randomPDFUint8Array} from '../../_test/pdf'; import {fetchPDF} from './pdf'; -const document = `%PDF-1.0 -1 0 obj<>endobj -2 0 obj<>endobj -3 0 obj<>endobj -xref -0 4 -0000000000 65535 f -0000000009 00000 n -0000000052 00000 n -0000000101 00000 n -trailer<> -startxref -147 -%EOF -`; - client(__filename, () => { it('should work on the client', async () => { - const data = new TextEncoder().encode(document); + const data = randomPDFUint8Array(); await fetchPDF({data}); }); }); server(__filename, () => { it('should work on the server', async () => { - const data = new TextEncoder().encode(document); + const data = randomPDFUint8Array(); await fetchPDF({data}); }); }); diff --git a/imports/lib/pdf/pdfthumbmails.tests.ts b/imports/lib/pdf/pdfthumbmails.tests.ts index c02e708b5..345ca6694 100644 --- a/imports/lib/pdf/pdfthumbmails.tests.ts +++ b/imports/lib/pdf/pdfthumbmails.tests.ts @@ -7,6 +7,7 @@ import 'regenerator-runtime/runtime.js'; import {assert} from 'chai'; import {client, server, throws} from '../../_test/fixtures'; +import {randomPDFUint8Array} from '../../_test/pdf'; import dataURL from '../dataURL'; import blobToDataURL from '../blob/blobToDataURL'; @@ -18,25 +19,9 @@ import { thumbnailBuffer, } from './pdfthumbnails'; -const document = `%PDF-1.0 -1 0 obj<>endobj -2 0 obj<>endobj -3 0 obj<>endobj -xref -0 4 -0000000000 65535 f -0000000009 00000 n -0000000052 00000 n -0000000101 00000 n -trailer<> -startxref -147 -%EOF -`; - client(__filename, () => { it('thumbnailDataURL should work', async () => { - const data = new TextEncoder().encode(document); + const data = randomPDFUint8Array(); const blob = new Blob([data.buffer], {type: 'application/pdf'}); const url = await blobToDataURL(blob); const result = await thumbnailDataURL( @@ -52,7 +37,7 @@ client(__filename, () => { }); it('thumbnailBlob should work', async () => { - const data = new TextEncoder().encode(document); + const data = randomPDFUint8Array(); const result = await thumbnailBlob( {data}, {minWidth: 200, minHeight: 200}, @@ -62,7 +47,7 @@ client(__filename, () => { }); it('thumbnailBuffer should NOT be implemented', async () => { - const data = new TextEncoder().encode(document); + const data = randomPDFUint8Array(); await throws( async () => thumbnailBuffer( @@ -75,7 +60,7 @@ client(__filename, () => { }); it('thumbnailStream should NOT be implemented', async () => { - const data = new TextEncoder().encode(document); + const data = randomPDFUint8Array(); await throws( async () => thumbnailStream( @@ -90,7 +75,7 @@ client(__filename, () => { server(__filename, () => { it('thumbnailDataURL should NOT be implemented', async () => { - const data = new TextEncoder().encode(document); + const data = randomPDFUint8Array(); const buffer = Buffer.from(data).toString('base64'); const url = dataURL('image/png', buffer); @@ -106,7 +91,7 @@ server(__filename, () => { }); it('thumbnailBlob should work', async () => { - const data = new TextEncoder().encode(document); + const data = randomPDFUint8Array(); await throws( async () => @@ -120,7 +105,7 @@ server(__filename, () => { }); it('thumbnailBuffer should work', async () => { - const data = new TextEncoder().encode(document); + const data = randomPDFUint8Array(); const result = await thumbnailBuffer( {data}, {minWidth: 200, minHeight: 200}, @@ -130,7 +115,7 @@ server(__filename, () => { }); it('thumbnailStream should work', async () => { - const data = new TextEncoder().encode(document); + const data = randomPDFUint8Array(); const result = await thumbnailStream( {data}, {minWidth: 200, minHeight: 200}, From 97ade6ee20c70af4c45e88070ffdb356ce03149a Mon Sep 17 00:00:00 2001 From: make-github-pseudonymous-again <5165674+make-github-pseudonymous-again@users.noreply.github.com> Date: Mon, 13 May 2024 18:27:53 +0200 Subject: [PATCH 13/19] :recycle: refactor(tests): Simplify creation of PDF sample data. --- imports/_test/pdf.ts | 12 ++++++++++++ imports/lib/pdf/pdfthumbmails.tests.ts | 11 +++-------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/imports/_test/pdf.ts b/imports/_test/pdf.ts index 06a8c701c..c7412f3a7 100644 --- a/imports/_test/pdf.ts +++ b/imports/_test/pdf.ts @@ -1,3 +1,5 @@ +import blobToDataURL from '../lib/blob/blobToDataURL'; + const document = `%PDF-1.0 1 0 obj<>endobj 2 0 obj<>endobj @@ -17,3 +19,13 @@ startxref export const randomPDFUint8Array = (): Uint8Array => { return new TextEncoder().encode(document); }; + +export const randomPDFBlob = (): Blob => { + const data = randomPDFUint8Array(); + return new Blob([data.buffer], {type: 'application/pdf'}); +}; + +export const randomPDFDataURI = async (): Promise => { + const blob = randomPDFBlob(); + return blobToDataURL(blob); +}; diff --git a/imports/lib/pdf/pdfthumbmails.tests.ts b/imports/lib/pdf/pdfthumbmails.tests.ts index 345ca6694..7dd5712cf 100644 --- a/imports/lib/pdf/pdfthumbmails.tests.ts +++ b/imports/lib/pdf/pdfthumbmails.tests.ts @@ -7,10 +7,9 @@ import 'regenerator-runtime/runtime.js'; import {assert} from 'chai'; import {client, server, throws} from '../../_test/fixtures'; -import {randomPDFUint8Array} from '../../_test/pdf'; +import {randomPDFUint8Array, randomPDFDataURI} from '../../_test/pdf'; import dataURL from '../dataURL'; -import blobToDataURL from '../blob/blobToDataURL'; import { thumbnailDataURL, @@ -21,9 +20,7 @@ import { client(__filename, () => { it('thumbnailDataURL should work', async () => { - const data = randomPDFUint8Array(); - const blob = new Blob([data.buffer], {type: 'application/pdf'}); - const url = await blobToDataURL(blob); + const url = await randomPDFDataURI(); const result = await thumbnailDataURL( url, {minWidth: 10, minHeight: 10}, @@ -75,9 +72,7 @@ client(__filename, () => { server(__filename, () => { it('thumbnailDataURL should NOT be implemented', async () => { - const data = randomPDFUint8Array(); - const buffer = Buffer.from(data).toString('base64'); - const url = dataURL('image/png', buffer); + const url = await randomPDFDataURI(); await throws( async () => From 17b96b6e6908b55e68f4579b1ffd7c120a9cde55 Mon Sep 17 00:00:00 2001 From: make-github-pseudonymous-again <5165674+make-github-pseudonymous-again@users.noreply.github.com> Date: Mon, 13 May 2024 18:37:00 +0200 Subject: [PATCH 14/19] :woman_technologist: dx(tests): Simplify server polyfill setup. --- imports/_test/fixtures.ts | 2 ++ imports/api/endpoint/documents/fetch.tests.ts | 3 +-- imports/api/endpoint/documents/insert.tests.ts | 3 +-- imports/lib/blob/dataURL.tests.ts | 4 ---- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/imports/_test/fixtures.ts b/imports/_test/fixtures.ts index 8f60c8635..8a238a785 100644 --- a/imports/_test/fixtures.ts +++ b/imports/_test/fixtures.ts @@ -113,6 +113,8 @@ export const server = (title, fn) => { }; const prepare = async () => { + await import('../../server/polyfill'); + if (isAppTest()) { await appIsReady(); } diff --git a/imports/api/endpoint/documents/fetch.tests.ts b/imports/api/endpoint/documents/fetch.tests.ts index 14e4d1496..b34e04092 100644 --- a/imports/api/endpoint/documents/fetch.tests.ts +++ b/imports/api/endpoint/documents/fetch.tests.ts @@ -1,7 +1,6 @@ // eslint-disable-next-line import/no-unassigned-import import 'regenerator-runtime/runtime.js'; -// eslint-disable-next-line import/no-unassigned-import -import 'core-js/features/string/replace-all'; + import {assert} from 'chai'; import {randomUserId, server, throws} from '../../../_test/fixtures'; diff --git a/imports/api/endpoint/documents/insert.tests.ts b/imports/api/endpoint/documents/insert.tests.ts index a054b1463..cff55bbe1 100644 --- a/imports/api/endpoint/documents/insert.tests.ts +++ b/imports/api/endpoint/documents/insert.tests.ts @@ -1,7 +1,6 @@ // eslint-disable-next-line import/no-unassigned-import import 'regenerator-runtime/runtime.js'; -// eslint-disable-next-line import/no-unassigned-import -import 'core-js/features/string/replace-all'; + import {assert} from 'chai'; import {randomUserId, server, throws} from '../../../_test/fixtures'; diff --git a/imports/lib/blob/dataURL.tests.ts b/imports/lib/blob/dataURL.tests.ts index 4328d3bcd..feb292cee 100644 --- a/imports/lib/blob/dataURL.tests.ts +++ b/imports/lib/blob/dataURL.tests.ts @@ -11,10 +11,6 @@ import blobToDataURL from './blobToDataURL'; isomorphic(__filename, () => { it('should allow to convert back and forth from a dataURL', async () => { - if (Meteor.isServer) { - await import('../../../server/polyfill/fetch'); - } - const url = randomPNGDataURI(); const blob = await blobFromDataURL(url); From 3f9bed105f335ae23275cb2c2c941b4d0a7fb607 Mon Sep 17 00:00:00 2001 From: make-github-pseudonymous-again <5165674+make-github-pseudonymous-again@users.noreply.github.com> Date: Mon, 13 May 2024 22:23:41 +0200 Subject: [PATCH 15/19] :recycle: refactor(client): Abstract away polyfills. --- client/main.tsx | 5 +++-- client/polyfill.ts | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 client/polyfill.ts diff --git a/client/main.tsx b/client/main.tsx index 0637fe632..1fc35d229 100644 --- a/client/main.tsx +++ b/client/main.tsx @@ -1,5 +1,6 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; +// eslint-disable-next-line import/order, import/no-unassigned-import +import './polyfill'; + import React, {StrictMode} from 'react'; import {Meteor} from 'meteor/meteor'; diff --git a/client/polyfill.ts b/client/polyfill.ts new file mode 100644 index 000000000..1a15fb5c6 --- /dev/null +++ b/client/polyfill.ts @@ -0,0 +1,2 @@ +// eslint-disable-next-line import/no-unassigned-import +import 'regenerator-runtime/runtime.js'; From a7920437df1d200b5ba9f54fab52435b101ab428 Mon Sep 17 00:00:00 2001 From: make-github-pseudonymous-again <5165674+make-github-pseudonymous-again@users.noreply.github.com> Date: Mon, 13 May 2024 22:34:52 +0200 Subject: [PATCH 16/19] :woman_technologist: dx(tests): Use DRY client polyfill. --- imports/_test/fixtures.ts | 2 ++ imports/api/endpoint/allergies/changeColor.tests.ts | 2 -- imports/api/endpoint/appointments/beginConsultation.tests.ts | 2 -- imports/api/endpoint/appointments/cancel.tests.ts | 2 -- imports/api/endpoint/appointments/remove.tests.ts | 2 -- imports/api/endpoint/appointments/reschedule.tests.ts | 2 -- imports/api/endpoint/appointments/schedule.tests.ts | 2 -- imports/api/endpoint/appointments/uncancel.tests.ts | 2 -- imports/api/endpoint/availability/next.tests.ts | 2 -- imports/api/endpoint/books/csv.tests.ts | 2 -- imports/api/endpoint/books/rename.tests.ts | 2 -- imports/api/endpoint/consultations/attach.tests.ts | 2 -- imports/api/endpoint/consultations/detach.tests.ts | 2 -- imports/api/endpoint/consultations/insert.tests.ts | 2 -- imports/api/endpoint/consultations/remove.tests.ts | 2 -- imports/api/endpoint/consultations/restoreAppointment.tests.ts | 2 -- imports/api/endpoint/consultations/transfer.tests.ts | 2 -- imports/api/endpoint/consultations/update.tests.ts | 2 -- imports/api/endpoint/documents/delete.tests.ts | 2 -- imports/api/endpoint/documents/fetch.tests.ts | 3 --- imports/api/endpoint/documents/insert.tests.ts | 3 --- imports/api/endpoint/documents/link.tests.ts | 2 -- imports/api/endpoint/documents/restore.tests.ts | 2 -- imports/api/endpoint/documents/superdelete.tests.ts | 2 -- imports/api/endpoint/documents/unlink.tests.ts | 2 -- imports/api/endpoint/patients/attach.tests.ts | 2 -- imports/api/endpoint/patients/detach.tests.ts | 2 -- imports/api/endpoint/patients/insert.tests.ts | 3 --- imports/api/endpoint/patients/merge.tests.ts | 2 -- imports/api/endpoint/patients/remove.tests.ts | 2 -- imports/api/endpoint/patients/update.tests.ts | 3 --- imports/api/endpoint/permissions/token/generate.tests.ts | 3 --- imports/api/endpoint/permissions/token/revoke.tests.ts | 3 --- imports/api/endpoint/settings/reset.tests.ts | 3 --- imports/api/endpoint/settings/update.tests.ts | 3 --- imports/api/endpoint/uploads/delete.tests.ts | 3 --- imports/api/endpoint/uploads/rename.tests.ts | 3 --- imports/api/endpoint/uploads/restore.tests.ts | 3 --- imports/api/transaction/TransactionDriver.tests.ts | 2 -- imports/app/isAppTest.app-tests.ts | 3 --- imports/app/isAppTest.tests.ts | 3 --- imports/app/isNonAppTest.app-tests.ts | 3 --- imports/app/isNonAppTest.tests.ts | 3 --- imports/app/isProduction.app-tests.ts | 3 --- imports/app/isProduction.tests.ts | 3 --- imports/app/isTest.app-tests.ts | 3 --- imports/app/isTest.tests.ts | 3 --- imports/lib/blob/dataURL.tests.ts | 3 --- imports/lib/pdf/pdf.tests.ts | 3 --- imports/lib/pdf/pdfthumbmails.tests.ts | 3 --- imports/ui/App.tests.tsx | 2 -- server/api/healthcheck/index.app-tests.ts | 2 -- server/api/ics/index.app-tests.ts | 2 -- 53 files changed, 2 insertions(+), 126 deletions(-) diff --git a/imports/_test/fixtures.ts b/imports/_test/fixtures.ts index 8a238a785..f65648c23 100644 --- a/imports/_test/fixtures.ts +++ b/imports/_test/fixtures.ts @@ -88,6 +88,8 @@ export const client = (title, fn) => { let original; const prepare = async () => { + await import('../../client/polyfill'); + original = await forgetHistory(); await cleanup(); }; diff --git a/imports/api/endpoint/allergies/changeColor.tests.ts b/imports/api/endpoint/allergies/changeColor.tests.ts index a523e03f8..d433f01a9 100644 --- a/imports/api/endpoint/allergies/changeColor.tests.ts +++ b/imports/api/endpoint/allergies/changeColor.tests.ts @@ -1,5 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; import {assert} from 'chai'; import {Allergies} from '../../collection/allergies'; diff --git a/imports/api/endpoint/appointments/beginConsultation.tests.ts b/imports/api/endpoint/appointments/beginConsultation.tests.ts index e466a7583..5a1f1401f 100644 --- a/imports/api/endpoint/appointments/beginConsultation.tests.ts +++ b/imports/api/endpoint/appointments/beginConsultation.tests.ts @@ -1,5 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; import {assert} from 'chai'; import { diff --git a/imports/api/endpoint/appointments/cancel.tests.ts b/imports/api/endpoint/appointments/cancel.tests.ts index 89cb0a656..75b3e648c 100644 --- a/imports/api/endpoint/appointments/cancel.tests.ts +++ b/imports/api/endpoint/appointments/cancel.tests.ts @@ -1,5 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; import {assert} from 'chai'; import { diff --git a/imports/api/endpoint/appointments/remove.tests.ts b/imports/api/endpoint/appointments/remove.tests.ts index faf6d3838..766dd61f4 100644 --- a/imports/api/endpoint/appointments/remove.tests.ts +++ b/imports/api/endpoint/appointments/remove.tests.ts @@ -1,5 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; import {assert} from 'chai'; import { diff --git a/imports/api/endpoint/appointments/reschedule.tests.ts b/imports/api/endpoint/appointments/reschedule.tests.ts index d514e1fc3..e573127a2 100644 --- a/imports/api/endpoint/appointments/reschedule.tests.ts +++ b/imports/api/endpoint/appointments/reschedule.tests.ts @@ -1,5 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; import {assert} from 'chai'; import {Appointments} from '../../collection/appointments'; diff --git a/imports/api/endpoint/appointments/schedule.tests.ts b/imports/api/endpoint/appointments/schedule.tests.ts index f6cd04a1e..48ae9c27f 100644 --- a/imports/api/endpoint/appointments/schedule.tests.ts +++ b/imports/api/endpoint/appointments/schedule.tests.ts @@ -1,5 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; import {assert} from 'chai'; import { diff --git a/imports/api/endpoint/appointments/uncancel.tests.ts b/imports/api/endpoint/appointments/uncancel.tests.ts index 0f0005644..20de2d87a 100644 --- a/imports/api/endpoint/appointments/uncancel.tests.ts +++ b/imports/api/endpoint/appointments/uncancel.tests.ts @@ -1,5 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; import {assert} from 'chai'; import { diff --git a/imports/api/endpoint/availability/next.tests.ts b/imports/api/endpoint/availability/next.tests.ts index 0d1bfa4d7..b6a93eb5e 100644 --- a/imports/api/endpoint/availability/next.tests.ts +++ b/imports/api/endpoint/availability/next.tests.ts @@ -1,5 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; import {assert} from 'chai'; import addMinutes from 'date-fns/addMinutes'; diff --git a/imports/api/endpoint/books/csv.tests.ts b/imports/api/endpoint/books/csv.tests.ts index 53965ae72..5aed8161f 100644 --- a/imports/api/endpoint/books/csv.tests.ts +++ b/imports/api/endpoint/books/csv.tests.ts @@ -1,5 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; import {assert} from 'chai'; import startOfYear from 'date-fns/startOfYear'; diff --git a/imports/api/endpoint/books/rename.tests.ts b/imports/api/endpoint/books/rename.tests.ts index 7ef652f7f..1f6039ca8 100644 --- a/imports/api/endpoint/books/rename.tests.ts +++ b/imports/api/endpoint/books/rename.tests.ts @@ -1,5 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; import {assert} from 'chai'; import invoke from '../invoke'; diff --git a/imports/api/endpoint/consultations/attach.tests.ts b/imports/api/endpoint/consultations/attach.tests.ts index d7977a3f3..f71caaf80 100644 --- a/imports/api/endpoint/consultations/attach.tests.ts +++ b/imports/api/endpoint/consultations/attach.tests.ts @@ -1,5 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; import {assert} from 'chai'; import {randomUserId, server, throws} from '../../../_test/fixtures'; diff --git a/imports/api/endpoint/consultations/detach.tests.ts b/imports/api/endpoint/consultations/detach.tests.ts index 967502ace..05cc4d5d0 100644 --- a/imports/api/endpoint/consultations/detach.tests.ts +++ b/imports/api/endpoint/consultations/detach.tests.ts @@ -1,5 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; import {assert} from 'chai'; import {randomUserId, server, throws} from '../../../_test/fixtures'; diff --git a/imports/api/endpoint/consultations/insert.tests.ts b/imports/api/endpoint/consultations/insert.tests.ts index 353d4f491..fedbba506 100644 --- a/imports/api/endpoint/consultations/insert.tests.ts +++ b/imports/api/endpoint/consultations/insert.tests.ts @@ -1,5 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; import {assert} from 'chai'; import {randomUserId, server, throws} from '../../../_test/fixtures'; diff --git a/imports/api/endpoint/consultations/remove.tests.ts b/imports/api/endpoint/consultations/remove.tests.ts index 249da1c78..a4dbcf2e5 100644 --- a/imports/api/endpoint/consultations/remove.tests.ts +++ b/imports/api/endpoint/consultations/remove.tests.ts @@ -1,5 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; import {assert} from 'chai'; import {Patients} from '../../collection/patients'; diff --git a/imports/api/endpoint/consultations/restoreAppointment.tests.ts b/imports/api/endpoint/consultations/restoreAppointment.tests.ts index d1609c53d..8dfca3e02 100644 --- a/imports/api/endpoint/consultations/restoreAppointment.tests.ts +++ b/imports/api/endpoint/consultations/restoreAppointment.tests.ts @@ -1,5 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; import {assert} from 'chai'; import {dropIds, randomUserId, server, throws} from '../../../_test/fixtures'; diff --git a/imports/api/endpoint/consultations/transfer.tests.ts b/imports/api/endpoint/consultations/transfer.tests.ts index d7eb113be..d3068b1c5 100644 --- a/imports/api/endpoint/consultations/transfer.tests.ts +++ b/imports/api/endpoint/consultations/transfer.tests.ts @@ -1,5 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; import {assert} from 'chai'; import {randomUserId, server, throws} from '../../../_test/fixtures'; diff --git a/imports/api/endpoint/consultations/update.tests.ts b/imports/api/endpoint/consultations/update.tests.ts index 04e8f41c4..512063474 100644 --- a/imports/api/endpoint/consultations/update.tests.ts +++ b/imports/api/endpoint/consultations/update.tests.ts @@ -1,5 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; import {assert} from 'chai'; import {randomUserId, server, throws} from '../../../_test/fixtures'; diff --git a/imports/api/endpoint/documents/delete.tests.ts b/imports/api/endpoint/documents/delete.tests.ts index 5b235199b..a9d3de388 100644 --- a/imports/api/endpoint/documents/delete.tests.ts +++ b/imports/api/endpoint/documents/delete.tests.ts @@ -1,5 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; import {assert} from 'chai'; import {randomUserId, server, throws} from '../../../_test/fixtures'; diff --git a/imports/api/endpoint/documents/fetch.tests.ts b/imports/api/endpoint/documents/fetch.tests.ts index b34e04092..b0ed12757 100644 --- a/imports/api/endpoint/documents/fetch.tests.ts +++ b/imports/api/endpoint/documents/fetch.tests.ts @@ -1,6 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; - import {assert} from 'chai'; import {randomUserId, server, throws} from '../../../_test/fixtures'; diff --git a/imports/api/endpoint/documents/insert.tests.ts b/imports/api/endpoint/documents/insert.tests.ts index cff55bbe1..3a08e14cd 100644 --- a/imports/api/endpoint/documents/insert.tests.ts +++ b/imports/api/endpoint/documents/insert.tests.ts @@ -1,6 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; - import {assert} from 'chai'; import {randomUserId, server, throws} from '../../../_test/fixtures'; diff --git a/imports/api/endpoint/documents/link.tests.ts b/imports/api/endpoint/documents/link.tests.ts index 6617544df..227a867df 100644 --- a/imports/api/endpoint/documents/link.tests.ts +++ b/imports/api/endpoint/documents/link.tests.ts @@ -1,5 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; import {assert} from 'chai'; import {randomUserId, server, throws} from '../../../_test/fixtures'; diff --git a/imports/api/endpoint/documents/restore.tests.ts b/imports/api/endpoint/documents/restore.tests.ts index 0893002ed..4f8ad1366 100644 --- a/imports/api/endpoint/documents/restore.tests.ts +++ b/imports/api/endpoint/documents/restore.tests.ts @@ -1,5 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; import {assert} from 'chai'; import {randomUserId, server, throws} from '../../../_test/fixtures'; diff --git a/imports/api/endpoint/documents/superdelete.tests.ts b/imports/api/endpoint/documents/superdelete.tests.ts index 48398ed67..233810dc8 100644 --- a/imports/api/endpoint/documents/superdelete.tests.ts +++ b/imports/api/endpoint/documents/superdelete.tests.ts @@ -1,5 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; import {assert} from 'chai'; import {randomUserId, server, throws} from '../../../_test/fixtures'; diff --git a/imports/api/endpoint/documents/unlink.tests.ts b/imports/api/endpoint/documents/unlink.tests.ts index b52b3383b..a0f4272bf 100644 --- a/imports/api/endpoint/documents/unlink.tests.ts +++ b/imports/api/endpoint/documents/unlink.tests.ts @@ -1,5 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; import {assert} from 'chai'; import {randomUserId, server, throws} from '../../../_test/fixtures'; diff --git a/imports/api/endpoint/patients/attach.tests.ts b/imports/api/endpoint/patients/attach.tests.ts index d83592a1b..1e8b02a67 100644 --- a/imports/api/endpoint/patients/attach.tests.ts +++ b/imports/api/endpoint/patients/attach.tests.ts @@ -1,5 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; import {assert} from 'chai'; import {randomUserId, server, throws} from '../../../_test/fixtures'; diff --git a/imports/api/endpoint/patients/detach.tests.ts b/imports/api/endpoint/patients/detach.tests.ts index 81dde15bc..15a622639 100644 --- a/imports/api/endpoint/patients/detach.tests.ts +++ b/imports/api/endpoint/patients/detach.tests.ts @@ -1,5 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; import {assert} from 'chai'; import {randomUserId, server, throws} from '../../../_test/fixtures'; diff --git a/imports/api/endpoint/patients/insert.tests.ts b/imports/api/endpoint/patients/insert.tests.ts index 0faf8d4f8..4ed3a2919 100644 --- a/imports/api/endpoint/patients/insert.tests.ts +++ b/imports/api/endpoint/patients/insert.tests.ts @@ -1,6 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; - import {assert} from 'chai'; import {randomUserId, server, throws} from '../../../_test/fixtures'; diff --git a/imports/api/endpoint/patients/merge.tests.ts b/imports/api/endpoint/patients/merge.tests.ts index 0d59a5d9d..3bee36570 100644 --- a/imports/api/endpoint/patients/merge.tests.ts +++ b/imports/api/endpoint/patients/merge.tests.ts @@ -1,5 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; import {assert} from 'chai'; import {randomUserId, server, setLike} from '../../../_test/fixtures'; diff --git a/imports/api/endpoint/patients/remove.tests.ts b/imports/api/endpoint/patients/remove.tests.ts index afd7a312f..19a66897e 100644 --- a/imports/api/endpoint/patients/remove.tests.ts +++ b/imports/api/endpoint/patients/remove.tests.ts @@ -1,5 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; import {assert} from 'chai'; import {randomUserId, server, throws} from '../../../_test/fixtures'; diff --git a/imports/api/endpoint/patients/update.tests.ts b/imports/api/endpoint/patients/update.tests.ts index 6f86474b6..cc7d12897 100644 --- a/imports/api/endpoint/patients/update.tests.ts +++ b/imports/api/endpoint/patients/update.tests.ts @@ -1,6 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; - import {assert} from 'chai'; import {randomUserId, server, throws} from '../../../_test/fixtures'; diff --git a/imports/api/endpoint/permissions/token/generate.tests.ts b/imports/api/endpoint/permissions/token/generate.tests.ts index 957deafe1..3a7e19457 100644 --- a/imports/api/endpoint/permissions/token/generate.tests.ts +++ b/imports/api/endpoint/permissions/token/generate.tests.ts @@ -1,6 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; - import {assert} from 'chai'; import {randomUserId, server, throws} from '../../../../_test/fixtures'; diff --git a/imports/api/endpoint/permissions/token/revoke.tests.ts b/imports/api/endpoint/permissions/token/revoke.tests.ts index 2d3794c23..524c98c81 100644 --- a/imports/api/endpoint/permissions/token/revoke.tests.ts +++ b/imports/api/endpoint/permissions/token/revoke.tests.ts @@ -1,6 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; - import {randomUserId, server, throws} from '../../../../_test/fixtures'; import {decode, getPermissionsForToken} from '../../../permissions/token'; diff --git a/imports/api/endpoint/settings/reset.tests.ts b/imports/api/endpoint/settings/reset.tests.ts index ff9ab6124..564fdbfe6 100644 --- a/imports/api/endpoint/settings/reset.tests.ts +++ b/imports/api/endpoint/settings/reset.tests.ts @@ -1,6 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; - import {assert} from 'chai'; import {randomUserId, server, throws} from '../../../_test/fixtures'; diff --git a/imports/api/endpoint/settings/update.tests.ts b/imports/api/endpoint/settings/update.tests.ts index 8d38cfd82..3d366d14c 100644 --- a/imports/api/endpoint/settings/update.tests.ts +++ b/imports/api/endpoint/settings/update.tests.ts @@ -1,6 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; - import {assert} from 'chai'; import {randomUserId, server, throws} from '../../../_test/fixtures'; diff --git a/imports/api/endpoint/uploads/delete.tests.ts b/imports/api/endpoint/uploads/delete.tests.ts index 9b307c290..031874f8b 100644 --- a/imports/api/endpoint/uploads/delete.tests.ts +++ b/imports/api/endpoint/uploads/delete.tests.ts @@ -1,6 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; - import {assert} from 'chai'; import {randomUserId, server, throws} from '../../../_test/fixtures'; diff --git a/imports/api/endpoint/uploads/rename.tests.ts b/imports/api/endpoint/uploads/rename.tests.ts index e0cb42c6f..a25b43fac 100644 --- a/imports/api/endpoint/uploads/rename.tests.ts +++ b/imports/api/endpoint/uploads/rename.tests.ts @@ -1,6 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; - import {assert} from 'chai'; import {randomUserId, server, throws} from '../../../_test/fixtures'; diff --git a/imports/api/endpoint/uploads/restore.tests.ts b/imports/api/endpoint/uploads/restore.tests.ts index 7f71e58a0..c273c42ee 100644 --- a/imports/api/endpoint/uploads/restore.tests.ts +++ b/imports/api/endpoint/uploads/restore.tests.ts @@ -1,6 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; - import {assert} from 'chai'; import {randomUserId, server, throws} from '../../../_test/fixtures'; diff --git a/imports/api/transaction/TransactionDriver.tests.ts b/imports/api/transaction/TransactionDriver.tests.ts index 040bd9ca8..0cc91a402 100644 --- a/imports/api/transaction/TransactionDriver.tests.ts +++ b/imports/api/transaction/TransactionDriver.tests.ts @@ -1,5 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; import {assert} from 'chai'; import {dropId, dropIds, randomId, server} from '../../_test/fixtures'; diff --git a/imports/app/isAppTest.app-tests.ts b/imports/app/isAppTest.app-tests.ts index 864c23c69..94e919a0c 100644 --- a/imports/app/isAppTest.app-tests.ts +++ b/imports/app/isAppTest.app-tests.ts @@ -1,6 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; - import {assert} from 'chai'; import {client, server} from '../_test/fixtures'; diff --git a/imports/app/isAppTest.tests.ts b/imports/app/isAppTest.tests.ts index 68d5f0a8e..14ae6f278 100644 --- a/imports/app/isAppTest.tests.ts +++ b/imports/app/isAppTest.tests.ts @@ -1,6 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; - import {assert} from 'chai'; import {client, server} from '../_test/fixtures'; diff --git a/imports/app/isNonAppTest.app-tests.ts b/imports/app/isNonAppTest.app-tests.ts index ac664f2a9..c1ef7a805 100644 --- a/imports/app/isNonAppTest.app-tests.ts +++ b/imports/app/isNonAppTest.app-tests.ts @@ -1,6 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; - import {assert} from 'chai'; import {client, server} from '../_test/fixtures'; diff --git a/imports/app/isNonAppTest.tests.ts b/imports/app/isNonAppTest.tests.ts index 1da236d33..09ccce351 100644 --- a/imports/app/isNonAppTest.tests.ts +++ b/imports/app/isNonAppTest.tests.ts @@ -1,6 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; - import {assert} from 'chai'; import {client, server} from '../_test/fixtures'; diff --git a/imports/app/isProduction.app-tests.ts b/imports/app/isProduction.app-tests.ts index e4bba1e4f..0fb8b19c1 100644 --- a/imports/app/isProduction.app-tests.ts +++ b/imports/app/isProduction.app-tests.ts @@ -1,6 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; - import {assert} from 'chai'; import {client, server} from '../_test/fixtures'; diff --git a/imports/app/isProduction.tests.ts b/imports/app/isProduction.tests.ts index e4bba1e4f..0fb8b19c1 100644 --- a/imports/app/isProduction.tests.ts +++ b/imports/app/isProduction.tests.ts @@ -1,6 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; - import {assert} from 'chai'; import {client, server} from '../_test/fixtures'; diff --git a/imports/app/isTest.app-tests.ts b/imports/app/isTest.app-tests.ts index c083323ba..f054b4532 100644 --- a/imports/app/isTest.app-tests.ts +++ b/imports/app/isTest.app-tests.ts @@ -1,6 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; - import {assert} from 'chai'; import {client, server} from '../_test/fixtures'; diff --git a/imports/app/isTest.tests.ts b/imports/app/isTest.tests.ts index c083323ba..f054b4532 100644 --- a/imports/app/isTest.tests.ts +++ b/imports/app/isTest.tests.ts @@ -1,6 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; - import {assert} from 'chai'; import {client, server} from '../_test/fixtures'; diff --git a/imports/lib/blob/dataURL.tests.ts b/imports/lib/blob/dataURL.tests.ts index feb292cee..700ce08d4 100644 --- a/imports/lib/blob/dataURL.tests.ts +++ b/imports/lib/blob/dataURL.tests.ts @@ -1,6 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; - import {assert} from 'chai'; import {isomorphic} from '../../_test/fixtures'; diff --git a/imports/lib/pdf/pdf.tests.ts b/imports/lib/pdf/pdf.tests.ts index 8b617d7a0..805d3c0c9 100644 --- a/imports/lib/pdf/pdf.tests.ts +++ b/imports/lib/pdf/pdf.tests.ts @@ -1,6 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; - import {client, server} from '../../_test/fixtures'; import {randomPDFUint8Array} from '../../_test/pdf'; diff --git a/imports/lib/pdf/pdfthumbmails.tests.ts b/imports/lib/pdf/pdfthumbmails.tests.ts index 7dd5712cf..9af9cd5eb 100644 --- a/imports/lib/pdf/pdfthumbmails.tests.ts +++ b/imports/lib/pdf/pdfthumbmails.tests.ts @@ -1,9 +1,6 @@ import {Buffer} from 'buffer'; import {Readable} from 'stream'; -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; - import {assert} from 'chai'; import {client, server, throws} from '../../_test/fixtures'; diff --git a/imports/ui/App.tests.tsx b/imports/ui/App.tests.tsx index e6cd1ec52..e6c85d437 100644 --- a/imports/ui/App.tests.tsx +++ b/imports/ui/App.tests.tsx @@ -1,5 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; import React from 'react'; import {render, waitForElementToBeRemoved} from '@testing-library/react'; diff --git a/server/api/healthcheck/index.app-tests.ts b/server/api/healthcheck/index.app-tests.ts index a665270ee..b904d96b6 100644 --- a/server/api/healthcheck/index.app-tests.ts +++ b/server/api/healthcheck/index.app-tests.ts @@ -1,5 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; import {assert} from 'chai'; import request from 'supertest'; diff --git a/server/api/ics/index.app-tests.ts b/server/api/ics/index.app-tests.ts index 7d0b04af1..7818df423 100644 --- a/server/api/ics/index.app-tests.ts +++ b/server/api/ics/index.app-tests.ts @@ -1,5 +1,3 @@ -// eslint-disable-next-line import/no-unassigned-import -import 'regenerator-runtime/runtime.js'; import {assert} from 'chai'; import request from 'supertest'; From cc387ddaa7e84c36a57c04fbed95ea7cbd2c8455 Mon Sep 17 00:00:00 2001 From: make-github-pseudonymous-again <5165674+make-github-pseudonymous-again@users.noreply.github.com> Date: Tue, 14 May 2024 01:54:01 +0200 Subject: [PATCH 17/19] :recycle: refactor(lib/pdf): Factor out isomorphic canvas helpers. --- imports/lib/canvas.ts | 50 +++++++++++++++++++++++++++++++ imports/lib/pdf/pdfthumbnails.ts | 51 +++++--------------------------- 2 files changed, 58 insertions(+), 43 deletions(-) create mode 100644 imports/lib/canvas.ts diff --git a/imports/lib/canvas.ts b/imports/lib/canvas.ts new file mode 100644 index 000000000..40e4fc06b --- /dev/null +++ b/imports/lib/canvas.ts @@ -0,0 +1,50 @@ +import {type Canvas} from 'canvas/types'; + +export { + type Canvas, + type JpegConfig, + type PdfConfig, + type PngConfig, +} from 'canvas/types'; + +type CreateCanvasOptions = { + width: number; + height: number; +}; + +const createCanvasIso = async ({ + width, + height, +}: CreateCanvasOptions): Promise => { + if (Meteor.isServer) { + const {createCanvas} = await import('canvas'); + return createCanvas(width, height); + } + + const browserCanvas = document.createElement('canvas'); + browserCanvas.width = width; + browserCanvas.height = height; + return browserCanvas; +}; + +export const destroyCanvasIso = (canvas: HTMLCanvasElement | Canvas) => { + canvas.width = 0; + canvas.height = 0; + if (Meteor.isClient) { + (canvas as HTMLCanvasElement).remove(); + } +}; + +type CreateContextOptions = {} & CreateCanvasOptions; + +export const createContextIso = async ( + options: CreateContextOptions, +): Promise => { + return createCanvasIso(options).then( + (canvas) => canvas.getContext('2d') as CanvasRenderingContext2D, + ); +}; + +export const destroyContextIso = (context: CanvasRenderingContext2D) => { + destroyCanvasIso(context.canvas); +}; diff --git a/imports/lib/pdf/pdfthumbnails.ts b/imports/lib/pdf/pdfthumbnails.ts index 2cb905bc9..62f8d063c 100644 --- a/imports/lib/pdf/pdfthumbnails.ts +++ b/imports/lib/pdf/pdfthumbnails.ts @@ -2,15 +2,18 @@ import {type Buffer} from 'buffer'; import {type Readable} from 'stream'; +import addDays from 'date-fns/addDays'; + +import {cache as lru, type IndexedDBPersistedLRUCache} from '../cache/lru'; + import { type Canvas, type JpegConfig, type PdfConfig, type PngConfig, -} from 'canvas/types'; -import addDays from 'date-fns/addDays'; - -import {cache as lru, type IndexedDBPersistedLRUCache} from '../cache/lru'; + createContextIso, + destroyContextIso, +} from '../canvas'; import {type DocumentInitParameters, type PageViewport, fetchPDF} from './pdf'; @@ -22,44 +25,6 @@ if (Meteor.isClient) { }); } -type CreateCanvasOptions = { - width: number; - height: number; -}; - -const createCanvasIso = async ({ - width, - height, -}: CreateCanvasOptions): Promise => { - if (Meteor.isServer) { - const {createCanvas} = await import('canvas'); - return createCanvas(width, height); - } - - const browserCanvas = document.createElement('canvas'); - browserCanvas.width = width; - browserCanvas.height = height; - return browserCanvas; -}; - -const destroyCanvasIso = (canvas: HTMLCanvasElement | Canvas) => { - canvas.width = 0; - canvas.height = 0; - if (Meteor.isClient) { - (canvas as HTMLCanvasElement).remove(); - } -}; - -type CreateContextOptions = {} & CreateCanvasOptions; - -const createContextIso = async ( - options: CreateContextOptions, -): Promise => { - return createCanvasIso(options).then( - (canvas) => canvas.getContext('2d') as CanvasRenderingContext2D, - ); -}; - type RenderContext = { canvasContext: CanvasRenderingContext2D; viewport: PageViewport; @@ -91,7 +56,7 @@ const createRenderContextIso = async ( }; const destroyRenderContextIso = (renderContext: RenderContext) => { - destroyCanvasIso(renderContext.canvasContext.canvas); + destroyContextIso(renderContext.canvasContext); // @ts-expect-error This is for garbage collection. renderContext.canvasContext = null; }; From fd19715e95bf07ea307f46ec778a7ee9c0b5eab6 Mon Sep 17 00:00:00 2001 From: make-github-pseudonymous-again <5165674+make-github-pseudonymous-again@users.noreply.github.com> Date: Tue, 14 May 2024 01:55:25 +0200 Subject: [PATCH 18/19] :test_tube: test(lib/pdf): Check thumbnail helper functions outputs. --- imports/_test/image.ts | 164 +++++++++++++++++++++++++ imports/lib/blob/blobToImage.ts | 22 ++++ imports/lib/pdf/pdfthumbmails.tests.ts | 72 +++++++---- 3 files changed, 235 insertions(+), 23 deletions(-) create mode 100644 imports/_test/image.ts create mode 100644 imports/lib/blob/blobToImage.ts diff --git a/imports/_test/image.ts b/imports/_test/image.ts new file mode 100644 index 000000000..3a8ce1518 --- /dev/null +++ b/imports/_test/image.ts @@ -0,0 +1,164 @@ +import {assert} from 'chai'; + +import {type Sharp} from 'sharp'; + +import {createContextIso, destroyContextIso} from '../lib/canvas'; +import blobToImage from '../lib/blob/blobToImage'; + +type TypedArray = + | Uint8Array + | Uint8ClampedArray + | Int8Array + | Uint16Array + | Int16Array + | Uint32Array + | Int32Array + | Float32Array + | Float64Array; +type SharpInput = ArrayBuffer | TypedArray; +type S = Sharp | SharpInput; + +type I = HTMLImageElement | ArrayBuffer; + +type Image = S | I; + +const _s = async (x: S): Promise => { + const {default: sharp} = await import('sharp'); + return x instanceof sharp ? (x as Sharp) : sharp(x as SharpInput); +}; + +const _i = async (x: I): Promise => { + if (x instanceof HTMLImageElement) return x; + const blob = new Blob([x], {type: 'image/png'}); + const image = await blobToImage(blob); + return image; +}; + +const _pixels = async (image: HTMLImageElement): Promise => { + const {width, height} = image; + const context = await createContextIso({width, height}); + context.drawImage(image, 0, 0); + const data = context.getImageData(0, 0, width, height).data; + destroyContextIso(context); + return data; +}; + +const _xorClient = ( + a: Uint8ClampedArray, + b: Uint8ClampedArray, +): Uint8ClampedArray => { + const n = a.length; + assert.equal(b.length, n); + const delta = new Uint8ClampedArray(n); + for (let i = 0; i < n; ++i) { + // eslint-disable-next-line no-bitwise + delta[i] = a[i]! ^ b[i]!; + } + + return delta; +}; + +const _diffClient = async (a: Image, b: Image) => { + const _a = await _i(a as I); + const _b = await _i(b as I); + const aPixels = await _pixels(_a); + const bPixels = await _pixels(_b); + return _xorClient(aPixels, bPixels); +}; + +const _diffServer = async (a: Image, b: Image) => { + const _a = await _s(a as S); + const _b = await _s(b as S); + const delta = await _xorServer(_a, _b); + return delta.raw().toBuffer(); +}; + +export const diff = Meteor.isServer ? _diffServer : _diffClient; + +export const assertEqual = async (a: Image, b: Image) => { + const delta = await diff(a, b); + assert( + !delta.some((value, index) => index % 4 !== 3 && value !== 0), + `Input images are not equal.`, + ); +}; + +const _assertSameDimensions = async (a: Sharp, b: Sharp): Promise => { + const { + width: aWidth, + height: aHeight, + channels: aChannels, + hasAlpha: aHasAlpha, + } = await a.metadata(); + const { + width: bWidth, + height: bHeight, + channels: bChannels, + hasAlpha: bHasAlpha, + } = await b.metadata(); + + assert.equal( + aWidth, + bWidth, + `Images have different widths: ${aWidth} !== ${bWidth}`, + ); + + assert.equal( + aHeight, + bHeight, + `Images have different heights: ${aHeight} !== ${bHeight}`, + ); + + assert.equal( + aChannels, + bChannels, + `Images have different number of channels: ${aChannels} !== ${bChannels}`, + ); + + assert.equal( + aHasAlpha, + bHasAlpha, + `Images have different alpha channel settings: ${aHasAlpha} !== ${bHasAlpha}`, + ); +}; + +const _xorServer = async (a: Sharp, b: Sharp): Promise => { + await _assertSameDimensions(a, b); + const _b = await b.toBuffer(); + return a.boolean(_b, 'eor'); +}; + +const _whiteRectanglePNGServer = async (options: { + width: number; + height: number; +}) => { + const {default: sharp} = await import('sharp'); + return sharp({ + create: { + ...options, + channels: 4, + background: {r: 255, g: 255, b: 255, alpha: 0}, + }, + }).png(); +}; + +const _whiteRectanglePNGClient = async ({ + width, + height, +}: { + width: number; + height: number; +}): Promise => { + const context = await createContextIso({width, height}); + context.fillStyle = '#FFFFFF'; + context.fillRect(0, 0, width, height); + const url = context.canvas.toDataURL('image/png'); + destroyContextIso(context); + const img = new Image(); + img.src = url; + return img; +}; + +export const whiteRectanglePNG = Meteor.isServer + ? _whiteRectanglePNGServer + : _whiteRectanglePNGClient; diff --git a/imports/lib/blob/blobToImage.ts b/imports/lib/blob/blobToImage.ts new file mode 100644 index 000000000..fec3c0e65 --- /dev/null +++ b/imports/lib/blob/blobToImage.ts @@ -0,0 +1,22 @@ +const blobToImage = async (blob: Blob): Promise => + new Promise((resolve, reject) => { + const url = URL.createObjectURL(blob); + const img = new Image(); + img.addEventListener('load', () => { + URL.revokeObjectURL(url); + resolve(img); + }); + + img.addEventListener('error', (error) => { + URL.revokeObjectURL(url); + reject(error); + }); + + img.addEventListener('abort', (_e) => { + reject(new Error(`Image load aborted for ${url}`)); + }); + + img.src = url; + }); + +export default blobToImage; diff --git a/imports/lib/pdf/pdfthumbmails.tests.ts b/imports/lib/pdf/pdfthumbmails.tests.ts index 9af9cd5eb..1532d5ebc 100644 --- a/imports/lib/pdf/pdfthumbmails.tests.ts +++ b/imports/lib/pdf/pdfthumbmails.tests.ts @@ -5,8 +5,14 @@ import {assert} from 'chai'; import {client, server, throws} from '../../_test/fixtures'; import {randomPDFUint8Array, randomPDFDataURI} from '../../_test/pdf'; +import { + assertEqual as assertEqualImages, + whiteRectanglePNG, +} from '../../_test/image'; -import dataURL from '../dataURL'; +import blobFromDataURL from '../blob/blobFromDataURL'; +import blobToBuffer from '../blob/blobToBuffer'; +import streamToBuffer from '../stream/streamToBuffer'; import { thumbnailDataURL, @@ -15,29 +21,39 @@ import { thumbnailBuffer, } from './pdfthumbnails'; +const width = 200; +const height = 200; + client(__filename, () => { it('thumbnailDataURL should work', async () => { - const url = await randomPDFDataURI(); - const result = await thumbnailDataURL( - url, - {minWidth: 10, minHeight: 10}, + const pdfDataURL = await randomPDFDataURI(); + const pngDataURL = await thumbnailDataURL( + pdfDataURL, + {minWidth: width, minHeight: height}, {type: 'image/png'}, ); - const expected = dataURL( - 'image/png', - 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARzQklUCAgICHwIZIgAAAAXSURBVBhXY/wPBAxEAMZRhfhCifrBAwDBjyfjq7VgpgAAAABJRU5ErkJggg==', - ); - assert.equal(result, expected); + + assert.typeOf(pngDataURL, 'string'); + + const buffer = await blobFromDataURL(pngDataURL).then(blobToBuffer); + const expected = await whiteRectanglePNG({width, height}); + + await assertEqualImages(buffer, expected); }); it('thumbnailBlob should work', async () => { const data = randomPDFUint8Array(); - const result = await thumbnailBlob( + const blob = await thumbnailBlob( {data}, - {minWidth: 200, minHeight: 200}, + {minWidth: width, minHeight: height}, {type: 'image/png'}, ); - assert.instanceOf(result, Blob); + assert.instanceOf(blob, Blob); + + const buffer = await blobToBuffer(blob); + const expected = await whiteRectanglePNG({width, height}); + + await assertEqualImages(buffer, expected); }); it('thumbnailBuffer should NOT be implemented', async () => { @@ -46,7 +62,7 @@ client(__filename, () => { async () => thumbnailBuffer( {data}, - {minWidth: 200, minHeight: 200}, + {minWidth: width, minHeight: height}, {type: 'image/png'}, ), /not implemented/i, @@ -59,7 +75,7 @@ client(__filename, () => { async () => thumbnailStream( {data}, - {minWidth: 200, minHeight: 200}, + {minWidth: width, minHeight: height}, {type: 'image/png'}, ), /not implemented/i, @@ -75,7 +91,7 @@ server(__filename, () => { async () => thumbnailDataURL( url, - {minWidth: 200, minHeight: 200}, + {minWidth: width, minHeight: height}, {type: 'image/png'}, ), /not implemented/i, @@ -89,7 +105,7 @@ server(__filename, () => { async () => thumbnailBlob( {data}, - {minWidth: 200, minHeight: 200}, + {minWidth: width, minHeight: height}, {type: 'image/png'}, ), /not implemented/i, @@ -98,21 +114,31 @@ server(__filename, () => { it('thumbnailBuffer should work', async () => { const data = randomPDFUint8Array(); - const result = await thumbnailBuffer( + const buffer = await thumbnailBuffer( {data}, - {minWidth: 200, minHeight: 200}, + {minWidth: width, minHeight: height}, {type: 'image/png'}, ); - assert.instanceOf(result, Buffer); + assert.instanceOf(buffer, Buffer); + + const expected = await whiteRectanglePNG({width, height}); + + await assertEqualImages(buffer, expected); }); it('thumbnailStream should work', async () => { const data = randomPDFUint8Array(); - const result = await thumbnailStream( + const stream = await thumbnailStream( {data}, - {minWidth: 200, minHeight: 200}, + {minWidth: width, minHeight: height}, {type: 'image/png'}, ); - assert.instanceOf(result, Readable); + assert.instanceOf(stream, Readable); + + const buffer = await streamToBuffer(stream); + + const expected = await whiteRectanglePNG({width, height}); + + await assertEqualImages(buffer, expected); }); }); From 02e9cba1ce195275a5e52cb6c5ec8f4ae3dee5c6 Mon Sep 17 00:00:00 2001 From: make-github-pseudonymous-again <5165674+make-github-pseudonymous-again@users.noreply.github.com> Date: Tue, 14 May 2024 02:32:49 +0200 Subject: [PATCH 19/19] :microscope: test: Increase coverage target to 67%. --- codecov.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codecov.yml b/codecov.yml index d07ddeb3d..0b10e1d15 100644 --- a/codecov.yml +++ b/codecov.yml @@ -2,7 +2,7 @@ coverage: status: project: default: - target: 66% + target: 67% threshold: 2% patch: default: