14
14
/** @typedef {import('./types.js').ComputeSourceLocationHook } ComputeSourceLocationHook */
15
15
/** @typedef {import('./types.js').LoadArchiveOptions } LoadArchiveOptions */
16
16
/** @typedef {import('./types.js').ExecuteOptions } ExecuteOptions */
17
+ /** @typedef {import('./types.js').ExitModuleImportHook } ExitModuleImportHook */
17
18
18
19
import { ZipReader } from '@endo/zip' ;
19
20
import { link } from './link.js' ;
@@ -78,6 +79,7 @@ const postponeErrorToExecute = errorMessage => {
78
79
* @param {string } archiveLocation
79
80
* @param {HashFn } [computeSha512]
80
81
* @param {ComputeSourceLocationHook } [computeSourceLocation]
82
+ * @param {ExitModuleImportHook } [exitModuleImportHook]
81
83
* @returns {ArchiveImportHookMaker }
82
84
*/
83
85
const makeArchiveImportHookMaker = (
@@ -86,6 +88,7 @@ const makeArchiveImportHookMaker = (
86
88
archiveLocation ,
87
89
computeSha512 = undefined ,
88
90
computeSourceLocation = undefined ,
91
+ exitModuleImportHook = undefined ,
89
92
) => {
90
93
// per-assembly:
91
94
/** @type {ArchiveImportHookMaker } */
@@ -97,6 +100,23 @@ const makeArchiveImportHookMaker = (
97
100
// per-module:
98
101
const module = modules [ moduleSpecifier ] ;
99
102
if ( module === undefined ) {
103
+ if ( exitModuleImportHook ) {
104
+ console . error ( '#################x' ) ;
105
+ const ns = await exitModuleImportHook ( moduleSpecifier ) ;
106
+ if ( ns ) {
107
+ return {
108
+ record : freeze ( {
109
+ imports : [ ] ,
110
+ exports : Object . keys ( ns ) ,
111
+ execute : moduleExports => {
112
+ moduleExports . default = ns ;
113
+ Object . assign ( moduleExports , ns ) ;
114
+ } ,
115
+ } ) ,
116
+ specifier : moduleSpecifier ,
117
+ } ;
118
+ }
119
+ }
100
120
throw new Error (
101
121
`Cannot find module ${ q ( moduleSpecifier ) } in package ${ q (
102
122
packageLocation ,
@@ -190,6 +210,7 @@ const makeFeauxModuleExportsNamespace = Compartment => {
190
210
* @param {string } [options.expectedSha512]
191
211
* @param {HashFn } [options.computeSha512]
192
212
* @param {Record<string, unknown> } [options.modules]
213
+ * @param {ExitModuleImportHook } [options.exitModuleImportHook]
193
214
* @param {Compartment } [options.Compartment]
194
215
* @param {ComputeSourceLocationHook } [options.computeSourceLocation]
195
216
* @returns {Promise<Application> }
@@ -205,6 +226,7 @@ export const parseArchive = async (
205
226
computeSourceLocation = undefined ,
206
227
Compartment = DefaultCompartment ,
207
228
modules = undefined ,
229
+ exitModuleImportHook = undefined ,
208
230
} = options ;
209
231
210
232
const archive = new ZipReader ( archiveBytes , { name : archiveLocation } ) ;
@@ -264,6 +286,7 @@ export const parseArchive = async (
264
286
archiveLocation ,
265
287
computeSha512 ,
266
288
computeSourceLocation ,
289
+ exitModuleImportHook ,
267
290
) ;
268
291
// A weakness of the current Compartment design is that the `modules` map
269
292
// must be given a module namespace object that passes a brand check.
@@ -291,14 +314,21 @@ export const parseArchive = async (
291
314
292
315
/** @type {ExecuteFn } */
293
316
const execute = async options => {
294
- const { globals, modules, transforms, __shimTransforms__, Compartment } =
295
- options || { } ;
317
+ const {
318
+ globals,
319
+ modules,
320
+ transforms,
321
+ __shimTransforms__,
322
+ Compartment,
323
+ exitModuleImportHook,
324
+ } = options || { } ;
296
325
const makeImportHook = makeArchiveImportHookMaker (
297
326
get ,
298
327
compartments ,
299
328
archiveLocation ,
300
329
computeSha512 ,
301
330
computeSourceLocation ,
331
+ exitModuleImportHook ,
302
332
) ;
303
333
const { compartment, pendingJobsPromise } = link ( compartmentMap , {
304
334
makeImportHook,
0 commit comments