diff --git a/packages/ses/NEWS.md b/packages/ses/NEWS.md index 75df0419a9..1716517358 100644 --- a/packages/ses/NEWS.md +++ b/packages/ses/NEWS.md @@ -13,6 +13,8 @@ User-visible changes in `ses`: - Node 18, Node 20, and all browsers have `structuredClone` - Node <= 16 have neither, but are also no longer supported by Endo. - Now exports separate layer for console shim: `ses/console-shim.js`. +- Adds permits for `ModuleSource` if present, either the native implementation + or from `@endo/module-source/shim.js`. # v1.8.0 (2024-08-27) diff --git a/packages/ses/src/get-anonymous-intrinsics.js b/packages/ses/src/get-anonymous-intrinsics.js index f7fcd37118..1dc66f9825 100644 --- a/packages/ses/src/get-anonymous-intrinsics.js +++ b/packages/ses/src/get-anonymous-intrinsics.js @@ -161,5 +161,19 @@ export const getAnonymousIntrinsics = () => { ); } + if (globalThis.ModuleSource) { + const AbstractModuleSourcePrototype = getPrototypeOf( + globalThis.ModuleSource.prototype, + ); + intrinsics['%AbstractModuleSourcePrototype%'] = + AbstractModuleSourcePrototype; + intrinsics['%AbstractModuleSource%'] = + AbstractModuleSourcePrototype.constructor; + } + + if (globalThis.ModuleSource) { + intrinsics['%ModuleSourcePrototype%'] = globalThis.ModuleSource.prototype; + } + return intrinsics; }; diff --git a/packages/ses/src/permits.js b/packages/ses/src/permits.js index 585d3c0c3f..9a06472cd1 100644 --- a/packages/ses/src/permits.js +++ b/packages/ses/src/permits.js @@ -101,8 +101,12 @@ export const universalPropertyNames = { // ESNext + // https://github.com/tc39/proposal-source-phase-imports?tab=readme-ov-file#js-module-source + ModuleSource: 'ModuleSource', + lockdown: 'lockdown', harden: 'harden', + HandledPromise: 'HandledPromise', // TODO: Until Promise.delegate (see below). }; @@ -1505,6 +1509,25 @@ export const permitted = { resolve: fn, }, + // https://github.com/tc39/proposal-source-phase-imports?tab=readme-ov-file#js-module-source + '%AbstractModuleSourcePrototype%': { + constructor: '%AbstractModuleSource%', + '@@toStringTag': getter, + }, + '%AbstractModuleSource%': { + '[[Proto]]': '%FunctionPrototype%', + prototype: '%AbstractModuleSourcePrototype%', + }, + '%ModuleSourcePrototype%': { + '[[Proto]]': '%AbstractModuleSourcePrototype%', + constructor: 'ModuleSource', + '@@toStringTag': getter, + }, + ModuleSource: { + '[[Proto]]': '%AbstractModuleSource%', + prototype: '%ModuleSourcePrototype%', + }, + Promise: { // Properties of the Promise Constructor '[[Proto]]': '%FunctionPrototype%', diff --git a/packages/ses/test/module-source.test.js b/packages/ses/test/module-source.test.js index dfdd0c2772..f2385ae9e6 100644 --- a/packages/ses/test/module-source.test.js +++ b/packages/ses/test/module-source.test.js @@ -6,6 +6,19 @@ import '@endo/module-source/shim.js'; lockdown(); +test('module source property/prototype graph and hardening', t => { + const AbstractModuleSource = Object.getPrototypeOf(ModuleSource); + t.is( + Object.getPrototypeOf(ModuleSource.prototype), + AbstractModuleSource.prototype, + ); + + t.truthy(Object.isFrozen(ModuleSource)); + t.truthy(Object.isFrozen(AbstractModuleSource)); + t.truthy(Object.isFrozen(ModuleSource.prototype)); + t.truthy(Object.isFrozen(AbstractModuleSource.prototype)); +}); + test('module source constructor', t => { const msr = new ModuleSource(` import foo from 'import-default-export-from-me.js';