From 0262fc0e2b452e0f64fdeb8b4126fdc99db55aa7 Mon Sep 17 00:00:00 2001 From: grypez <143971198+grypez@users.noreply.github.com> Date: Wed, 21 Aug 2024 22:44:13 -0400 Subject: [PATCH 1/6] fix(shims): Add glob param to rimraf --- packages/shims/scripts/bundle.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shims/scripts/bundle.js b/packages/shims/scripts/bundle.js index 45157d98d..ad52c1d7d 100644 --- a/packages/shims/scripts/bundle.js +++ b/packages/shims/scripts/bundle.js @@ -19,7 +19,7 @@ const fileNames = { }; await mkdir(dist, { recursive: true }); -await rimraf(`${dist}/*`); +await rimraf(`${dist}/*`, { glob: true }); for (const fileName of [fileNames.endoify, fileNames.applyLockdown]) { await copyFile(path.resolve(src, fileName), path.resolve(dist, fileName)); From 6d06bc5e224e2669be0569d631d9911bc04a8982 Mon Sep 17 00:00:00 2001 From: grypez <143971198+grypez@users.noreply.github.com> Date: Wed, 21 Aug 2024 23:54:35 -0400 Subject: [PATCH 2/6] build(shims): Harmonize bundle.js with node 18 & 20 The CI build job requires that yarn build succeeds with node 20. The CI test job (essentially) requires that yarn test succeeds with node 18 and 20. The test job does not have access to the build artifacts from the build job, which allows the build and test jobs to run in parallel. In order to allow the shims package to test its built shims, we prefix the shims test command with `build && `, which, as a command called during the CI test job, runs with both node 18 and 20. Therefore, although our CI suggests the intended workflow for the ocap monorepo is "build with 20, run with 18 or 20", the tests tighten the constraint in the shims package specifically to "build and run with 18 or 20". As @SMotaal noted, this change in commit is sufficient to meet the tighter constraint. --- packages/shims/scripts/bundle.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shims/scripts/bundle.js b/packages/shims/scripts/bundle.js index ad52c1d7d..3f3135644 100644 --- a/packages/shims/scripts/bundle.js +++ b/packages/shims/scripts/bundle.js @@ -9,7 +9,7 @@ import { fileURLToPath } from 'url'; console.log('Bundling shims...'); -const rootDir = path.resolve(import.meta.dirname, '..'); +const rootDir = fileURLToPath(new URL('..', import.meta.url)); const src = path.resolve(rootDir, 'src'); const dist = path.resolve(rootDir, 'dist'); const fileNames = { From 7114e00383182c760c1335509fd6da130562bd90 Mon Sep 17 00:00:00 2001 From: grypez <143971198+grypez@users.noreply.github.com> Date: Thu, 22 Aug 2024 00:03:07 -0400 Subject: [PATCH 3/6] test(shims): Configure tests --- packages/shims/package.json | 1 + .../shims/src/vitest-environment-endoified.ts | 25 +++++++++++++++++++ packages/shims/vitest.config.ts | 16 +++++++++++- yarn.lock | 1 + 4 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 packages/shims/src/vitest-environment-endoified.ts diff --git a/packages/shims/package.json b/packages/shims/package.json index a257b5b88..0f44bb780 100644 --- a/packages/shims/package.json +++ b/packages/shims/package.json @@ -42,6 +42,7 @@ "@metamask/auto-changelog": "^3.4.4", "deepmerge": "^4.3.1", "rimraf": "^6.0.1", + "vite": "^5.3.5", "vitest": "^2.0.5" }, "engines": { diff --git a/packages/shims/src/vitest-environment-endoified.ts b/packages/shims/src/vitest-environment-endoified.ts new file mode 100644 index 000000000..63a817387 --- /dev/null +++ b/packages/shims/src/vitest-environment-endoified.ts @@ -0,0 +1,25 @@ +import type { Context } from 'node:vm'; +import type { Environment } from 'vitest/environments'; + +export default { + name: 'endoified', + transformMode: 'ssr', + async setupVM() { + const vm = await import('node:vm'); + return { + getVmContext(): Context { + return vm.createContext({ + setTimeout, + clearTimeout, + }); + }, + // eslint-disable-next-line no-empty-function + teardown(): void {}, + }; + }, + async setup() { + throw new Error( + 'endoified environment requires vitest option --pool=vmThreads or --pool=vmForks', + ); + }, +} as Environment; diff --git a/packages/shims/vitest.config.ts b/packages/shims/vitest.config.ts index 2709902e1..4d7480d27 100644 --- a/packages/shims/vitest.config.ts +++ b/packages/shims/vitest.config.ts @@ -1,9 +1,23 @@ // eslint-disable-next-line spaced-comment /// +import { defineConfig, mergeConfig } from 'vite'; + import { getDefaultConfig } from '../../vitest.config.packages.js'; -const config = getDefaultConfig(); +const defaultConfig = getDefaultConfig(); + +const config = mergeConfig( + defaultConfig, + defineConfig({ + test: { + pool: 'vmThreads', + environment: './vitest-environment-endoified.ts', + setupFiles: '../dist/endoify.mjs', + }, + }), +); + // @ts-expect-error We can and will delete this. delete config.test.coverage.thresholds; export default config; diff --git a/yarn.lock b/yarn.lock index d5df286f8..7dfab2953 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1324,6 +1324,7 @@ __metadata: deepmerge: "npm:^4.3.1" rimraf: "npm:^6.0.1" ses: "npm:^1.7.0" + vite: "npm:^5.3.5" vitest: "npm:^2.0.5" languageName: unknown linkType: soft From 576e29cbefdd283244a36e1834225bcb4fb7e833 Mon Sep 17 00:00:00 2001 From: grypez <143971198+grypez@users.noreply.github.com> Date: Thu, 22 Aug 2024 01:57:18 -0400 Subject: [PATCH 4/6] test(shims): Add minimal endoify shim test --- packages/shims/package.json | 2 +- packages/shims/src/endoify.test.ts | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 packages/shims/src/endoify.test.ts diff --git a/packages/shims/package.json b/packages/shims/package.json index 0f44bb780..120ae5f53 100644 --- a/packages/shims/package.json +++ b/packages/shims/package.json @@ -26,7 +26,7 @@ "changelog:validate": "../../scripts/validate-changelog.sh @ocap/shims", "clean": "rimraf --glob ./dist './*.tsbuildinfo'", "publish:preview": "yarn npm publish --tag preview", - "test": "vitest run --config vitest.config.ts --passWithNoTests", + "test": "yarn build && vitest run --config vitest.config.ts --passWithNoTests", "test:clean": "yarn test --no-cache --coverage.clean", "test:dev": "yarn test --coverage false", "test:verbose": "yarn test --reporter verbose", diff --git a/packages/shims/src/endoify.test.ts b/packages/shims/src/endoify.test.ts new file mode 100644 index 000000000..de8618c6c --- /dev/null +++ b/packages/shims/src/endoify.test.ts @@ -0,0 +1,12 @@ +import { HandledPromise } from '@endo/eventual-send'; +import { describe, expect, it } from 'vitest'; + +describe('endoified', () => { + it('calls lockdown', () => { + expect(Object.isFrozen(Array.prototype)).toBe(true); // Due to `lockdown()`, and therefore `ses` + }); + + it('loads eventual-send', () => { + expect(typeof HandledPromise).not.toBe('undefined'); // Due to eventual send + }); +}); From fdb97fa3cb0f9a853619c8f241460d83460abb4b Mon Sep 17 00:00:00 2001 From: grypez <143971198+grypez@users.noreply.github.com> Date: Thu, 22 Aug 2024 02:08:50 -0400 Subject: [PATCH 5/6] refactor(shims): Abstract endo bundling of endo sources --- packages/shims/scripts/bundle.js | 36 +++++++++++++++++++------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/packages/shims/scripts/bundle.js b/packages/shims/scripts/bundle.js index 3f3135644..74b65b79c 100644 --- a/packages/shims/scripts/bundle.js +++ b/packages/shims/scripts/bundle.js @@ -2,9 +2,11 @@ import 'ses'; import '@endo/lockdown/commit.js'; import bundleSource from '@endo/bundle-source'; -import { copyFile, mkdir, writeFile } from 'fs/promises'; +import { createWriteStream } from 'fs'; +import { copyFile, mkdir } from 'fs/promises'; import path from 'path'; import { rimraf } from 'rimraf'; +import { Readable } from 'stream'; import { fileURLToPath } from 'url'; console.log('Bundling shims...'); @@ -21,22 +23,26 @@ const fileNames = { await mkdir(dist, { recursive: true }); await rimraf(`${dist}/*`, { glob: true }); +/** + * Bundles the target file as endoScript and returns the content as a readable stream. + * + * @param {string} specifier - Import path to the file to bundle, e.g. `'@endo/eventual-send/shim.js'`. + * @returns {Promise} The bundled file contents as a Readable stream. + */ +const createEndoBundleReadStream = async (specifier) => { + const filePath = fileURLToPath(import.meta.resolve(specifier)); + const { source: bundle } = await bundleSource(filePath, { + format: 'endoScript', + }); + return Readable.from(bundle); +}; + for (const fileName of [fileNames.endoify, fileNames.applyLockdown]) { await copyFile(path.resolve(src, fileName), path.resolve(dist, fileName)); } -const eventualSendSourcePath = fileURLToPath( - import.meta.resolve('@endo/eventual-send/shim.js'), -); - -const { source: eventualSendBundleSource } = await bundleSource( - eventualSendSourcePath, - { format: 'endoScript' }, -); - -await writeFile( - path.resolve(dist, fileNames.eventualSend), - eventualSendBundleSource, -); +const source = await createEndoBundleReadStream('@endo/eventual-send/shim.js'); +const target = createWriteStream(path.resolve(dist, fileNames.eventualSend)); -console.log('Success!'); +source.pipe(target); +source.on('end', () => console.log('Success!')); From c8dea0e3930a1ea31c55e2ff6a8b933bfd0b6efa Mon Sep 17 00:00:00 2001 From: grypez <143971198+grypez@users.noreply.github.com> Date: Thu, 22 Aug 2024 02:22:09 -0400 Subject: [PATCH 6/6] feat(shims): Bundle endoify dependencies --- packages/shims/scripts/bundle.js | 28 ++++++++++++++-------------- packages/shims/src/endoify.mjs | 7 +++++-- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/packages/shims/scripts/bundle.js b/packages/shims/scripts/bundle.js index 74b65b79c..b27a9f6d7 100644 --- a/packages/shims/scripts/bundle.js +++ b/packages/shims/scripts/bundle.js @@ -2,8 +2,8 @@ import 'ses'; import '@endo/lockdown/commit.js'; import bundleSource from '@endo/bundle-source'; -import { createWriteStream } from 'fs'; -import { copyFile, mkdir } from 'fs/promises'; +import { createReadStream, createWriteStream } from 'fs'; +import { mkdir } from 'fs/promises'; import path from 'path'; import { rimraf } from 'rimraf'; import { Readable } from 'stream'; @@ -14,11 +14,6 @@ console.log('Bundling shims...'); const rootDir = fileURLToPath(new URL('..', import.meta.url)); const src = path.resolve(rootDir, 'src'); const dist = path.resolve(rootDir, 'dist'); -const fileNames = { - endoify: 'endoify.mjs', - eventualSend: 'eventual-send.mjs', - applyLockdown: 'apply-lockdown.mjs', -}; await mkdir(dist, { recursive: true }); await rimraf(`${dist}/*`, { glob: true }); @@ -37,12 +32,17 @@ const createEndoBundleReadStream = async (specifier) => { return Readable.from(bundle); }; -for (const fileName of [fileNames.endoify, fileNames.applyLockdown]) { - await copyFile(path.resolve(src, fileName), path.resolve(dist, fileName)); -} +const sources = { + ses: createReadStream( + path.resolve(rootDir, '../../node_modules/ses/dist/ses.mjs'), + ), + eventualSend: await createEndoBundleReadStream('@endo/eventual-send/shim.js'), + shim: createReadStream(path.resolve(src, 'endoify.mjs')), +}; -const source = await createEndoBundleReadStream('@endo/eventual-send/shim.js'); -const target = createWriteStream(path.resolve(dist, fileNames.eventualSend)); +const target = createWriteStream(path.resolve(dist, 'endoify.mjs')); -source.pipe(target); -source.on('end', () => console.log('Success!')); +sources.ses.pipe(target, { end: false }); +sources.ses.on('end', () => sources.eventualSend.pipe(target, { end: false })); +sources.eventualSend.on('end', () => sources.shim.pipe(target, { end: true })); +sources.shim.on('end', () => console.log('Success!')); diff --git a/packages/shims/src/endoify.mjs b/packages/shims/src/endoify.mjs index 824aa9c32..40124f6f0 100644 --- a/packages/shims/src/endoify.mjs +++ b/packages/shims/src/endoify.mjs @@ -1,5 +1,6 @@ -import './ses.mjs'; -import './eventual-send.mjs'; +/* eslint-disable import-x/unambiguous */ +// @inline './ses.mjs'; +// @inline './eventual-send.mjs'; lockdown({ consoleTaming: 'unsafe', @@ -9,3 +10,5 @@ lockdown({ domainTaming: 'unsafe', overrideTaming: 'severe', }); + +/* eslint-enable import-x/unambiguous */