@endo/compartment-mapper 1.5.0 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +278 -111
  3. package/SECURITY.md +2 -2
  4. package/bundle.d.ts +1 -1
  5. package/bundle.js +4 -1
  6. package/functor-lite.d.ts +3 -0
  7. package/functor-lite.d.ts.map +1 -0
  8. package/functor-lite.js +4 -0
  9. package/functor.d.ts +3 -0
  10. package/functor.d.ts.map +1 -0
  11. package/functor.js +4 -0
  12. package/index.d.ts +1 -1
  13. package/index.js +4 -1
  14. package/package.json +15 -11
  15. package/script-lite.d.ts +3 -0
  16. package/script-lite.d.ts.map +1 -0
  17. package/script-lite.js +4 -0
  18. package/script.d.ts +3 -0
  19. package/script.d.ts.map +1 -0
  20. package/script.js +4 -0
  21. package/src/archive-lite.d.ts +5 -5
  22. package/src/archive-lite.d.ts.map +1 -1
  23. package/src/archive-lite.js +1 -1
  24. package/src/archive.d.ts +5 -5
  25. package/src/archive.d.ts.map +1 -1
  26. package/src/archive.js +3 -1
  27. package/src/bundle-cjs.d.ts +12 -2
  28. package/src/bundle-cjs.d.ts.map +1 -1
  29. package/src/bundle-cjs.js +57 -28
  30. package/src/bundle-json.d.ts.map +1 -1
  31. package/src/bundle-json.js +2 -3
  32. package/src/bundle-lite.d.ts +91 -0
  33. package/src/bundle-lite.d.ts.map +1 -0
  34. package/src/bundle-lite.js +667 -0
  35. package/src/bundle-mjs.d.ts +13 -3
  36. package/src/bundle-mjs.d.ts.map +1 -1
  37. package/src/bundle-mjs.js +36 -19
  38. package/src/bundle.d.ts +48 -10
  39. package/src/bundle.d.ts.map +1 -1
  40. package/src/bundle.js +392 -126
  41. package/src/capture-lite.d.ts +1 -1
  42. package/src/capture-lite.d.ts.map +1 -1
  43. package/src/capture-lite.js +4 -2
  44. package/src/compartment-map.d.ts +1 -1
  45. package/src/compartment-map.d.ts.map +1 -1
  46. package/src/import-archive-lite.d.ts +2 -2
  47. package/src/import-archive-lite.d.ts.map +1 -1
  48. package/src/import-archive-lite.js +3 -1
  49. package/src/import-archive.d.ts +3 -3
  50. package/src/import-archive.d.ts.map +1 -1
  51. package/src/import-archive.js +3 -1
  52. package/src/import-hook.d.ts +3 -16
  53. package/src/import-hook.d.ts.map +1 -1
  54. package/src/import-hook.js +214 -116
  55. package/src/import-lite.d.ts +1 -1
  56. package/src/import-lite.d.ts.map +1 -1
  57. package/src/import-lite.js +7 -3
  58. package/src/import.d.ts.map +1 -1
  59. package/src/import.js +3 -1
  60. package/src/infer-exports.d.ts +5 -7
  61. package/src/infer-exports.d.ts.map +1 -1
  62. package/src/infer-exports.js +23 -8
  63. package/src/link.d.ts.map +1 -1
  64. package/src/link.js +4 -1
  65. package/src/map-parser.d.ts.map +1 -1
  66. package/src/map-parser.js +51 -5
  67. package/src/node-module-specifier.d.ts.map +1 -1
  68. package/src/node-module-specifier.js +3 -1
  69. package/src/node-modules.d.ts +4 -47
  70. package/src/node-modules.d.ts.map +1 -1
  71. package/src/node-modules.js +267 -148
  72. package/src/node-powers.d.ts +1 -1
  73. package/src/node-powers.d.ts.map +1 -1
  74. package/src/node-powers.js +3 -1
  75. package/src/parse-archive-cjs.d.ts +5 -1
  76. package/src/parse-archive-cjs.d.ts.map +1 -1
  77. package/src/parse-archive-cjs.js +11 -4
  78. package/src/parse-archive-mjs.d.ts +5 -1
  79. package/src/parse-archive-mjs.d.ts.map +1 -1
  80. package/src/parse-archive-mjs.js +3 -1
  81. package/src/parse-bytes.d.ts +5 -1
  82. package/src/parse-bytes.d.ts.map +1 -1
  83. package/src/parse-bytes.js +3 -1
  84. package/src/parse-cjs-shared-export-wrapper.d.ts.map +1 -1
  85. package/src/parse-cjs-shared-export-wrapper.js +5 -11
  86. package/src/parse-cjs.d.ts +5 -1
  87. package/src/parse-cjs.d.ts.map +1 -1
  88. package/src/parse-cjs.js +4 -2
  89. package/src/parse-json.d.ts +5 -2
  90. package/src/parse-json.d.ts.map +1 -1
  91. package/src/parse-mjs.d.ts +5 -1
  92. package/src/parse-mjs.d.ts.map +1 -1
  93. package/src/parse-mjs.js +2 -2
  94. package/src/parse-pre-cjs.d.ts +5 -1
  95. package/src/parse-pre-cjs.d.ts.map +1 -1
  96. package/src/parse-pre-cjs.js +3 -1
  97. package/src/parse-pre-mjs.d.ts +5 -1
  98. package/src/parse-pre-mjs.d.ts.map +1 -1
  99. package/src/parse-pre-mjs.js +3 -1
  100. package/src/parse-text.d.ts +5 -1
  101. package/src/parse-text.d.ts.map +1 -1
  102. package/src/parse-text.js +3 -1
  103. package/src/policy-format.d.ts +2 -1
  104. package/src/policy-format.d.ts.map +1 -1
  105. package/src/policy-format.js +5 -2
  106. package/src/policy.d.ts +2 -2
  107. package/src/policy.d.ts.map +1 -1
  108. package/src/policy.js +10 -11
  109. package/src/powers.d.ts +1 -1
  110. package/src/powers.d.ts.map +1 -1
  111. package/src/powers.js +3 -1
  112. package/src/search.d.ts +7 -12
  113. package/src/search.d.ts.map +1 -1
  114. package/src/search.js +32 -13
  115. package/src/types/compartment-map-schema.d.ts +8 -1
  116. package/src/types/compartment-map-schema.d.ts.map +1 -1
  117. package/src/types/compartment-map-schema.ts +8 -1
  118. package/src/types/external.d.ts +127 -17
  119. package/src/types/external.d.ts.map +1 -1
  120. package/src/types/external.ts +142 -17
  121. package/src/types/internal.d.ts +116 -29
  122. package/src/types/internal.d.ts.map +1 -1
  123. package/src/types/internal.ts +144 -31
  124. package/src/types/node-modules.d.ts +79 -0
  125. package/src/types/node-modules.d.ts.map +1 -0
  126. package/src/types/node-modules.ts +89 -0
  127. package/src/types/node-powers.d.ts +7 -5
  128. package/src/types/node-powers.d.ts.map +1 -1
  129. package/src/types/node-powers.ts +7 -5
  130. package/src/types/policy-schema.d.ts +3 -1
  131. package/src/types/policy-schema.d.ts.map +1 -1
  132. package/src/types/policy-schema.ts +3 -1
  133. package/src/types/policy.d.ts +3 -1
  134. package/src/types/policy.d.ts.map +1 -1
  135. package/src/types/policy.ts +3 -1
  136. package/src/types/powers.d.ts +5 -3
  137. package/src/types/powers.d.ts.map +1 -1
  138. package/src/types/powers.ts +5 -3
  139. package/src/types/typescript.d.ts +3 -1
  140. package/src/types/typescript.d.ts.map +1 -1
  141. package/src/types/typescript.ts +3 -1
  142. package/src/url.d.ts.map +1 -1
  143. package/src/url.js +3 -1
package/LICENSE CHANGED
@@ -186,7 +186,7 @@
186
186
  same "printed page" as the copyright notice for easier
187
187
  identification within third-party archives.
188
188
 
189
- Copyright [yyyy] [name of copyright owner]
189
+ Copyright 2020 Endo Contributors
190
190
 
191
191
  Licensed under the Apache License, Version 2.0 (the "License");
192
192
  you may not use this file except in compliance with the License.
package/README.md CHANGED
@@ -11,8 +11,10 @@ attacks and some supply chain attacks.
11
11
  Since most Node.js packages do not modify objects in global scope,
12
12
  many libraries and applications work in Compartments without modification.
13
13
 
14
- The `importLocation` function runs a compartmentalized application off the file
15
- system.
14
+ ## Evaluating an application from a file system
15
+
16
+ The `importLocation` function evaluates a compartmentalized application off the
17
+ file system.
16
18
  The `globals` are properties to add to the `globalThis` in the global scope
17
19
  of the application's main package compartment.
18
20
  The `modules` are built-in modules to grant the application's main package
@@ -20,23 +22,20 @@ compartment.
20
22
 
21
23
  ```js
22
24
  import fs from "fs";
25
+ import { fileURLToPath } from "url";
23
26
  import { importLocation } from "@endo/compartment-mapper";
24
27
 
25
28
  // ...
26
29
 
27
- const modules = { fs };
28
- const globals = { console };
29
-
30
- const read = async location =>
31
- fs.promises.readFile(new URL(location).pathname);
30
+ const read = async location => fs.promises.readFile(fileURLToPath(location));
32
31
 
33
- const { namespace } = await importLocation(
32
+ const { namespace: moduleExports } = await importLocation(
34
33
  read,
35
- moduleLocation,
34
+ moduleSpecifier,
36
35
  {
37
- globals,
38
- modules
39
- }
36
+ globals: { console },
37
+ modules: { fs },
38
+ },
40
39
  );
41
40
  ```
42
41
 
@@ -46,93 +45,264 @@ The application using the compartment mapper is responsible for applying the
46
45
  necessary).
47
46
  The compartment mapper is also not coupled specifically to Node.js IO and does
48
47
  not import any powerful modules like `fs`.
49
- The user must provide `read` and `write` functions from whatever IO powers they
50
- have. These powers can be provided as individual functions or as objects
51
- carrying functions. `ReadPowers` has optional functions which can be used to
52
- unlock compatibility features. When `fileURLToPath` is available, `__dirname`
53
- and `__filename` will be provided to CJS modules. If `requireResolve` is
54
- available, it will be called whenever a CJS module calls `require.resolve()`.
48
+ The caller must provide read powers in the first argument as either a ReadPowers
49
+ object or as a standalone `read` function. ReadPowers has optional functions
50
+ which can be used to unlock compatibility features. When `fileURLToPath` is
51
+ available, `__dirname` and `__filename` will be provided to CJS modules. When
52
+ `requireResolve` is available, it will be called whenever a CJS module calls
53
+ [`require.resolve()`].
55
54
 
56
- ```js
55
+ ```ts
57
56
  type ReadPowers = {
58
57
  read: (location: string) => Promise<Uint8Array>,
59
58
  canonical: (location: string) => Promise<string>,
60
- computeSha512: { (bytes: Uint8Array) => string }?,
61
- fileURLToPath: { (url: string | URL) => string }?,
62
- pathToFileURL: { (path: string) => URL }?,
63
- requireResolve: { (from: string, request: string, options?: {}) => string }?
59
+ computeSha512?: (bytes: Uint8Array) => string,
60
+ fileURLToPath?: (location: string | URL) => string,
61
+ pathToFileURL?: (path: string) => URL,
62
+ requireResolve?: (
63
+ fromLocation: string,
64
+ specifier: string,
65
+ options?: { paths?: string[] },
66
+ ) => string
64
67
  }
65
68
  ```
66
69
 
67
- > TODO
68
- >
69
- > A future version will allow application authors to distribute their choices
70
- > of globals and built-in modules to third-party packages within the
70
+ > [!NOTE]
71
+ > TODO: A future version will allow application authors to distribute their
72
+ > choices of globals and built-in modules to third-party packages within the
71
73
  > application, as with [LavaMoat].
72
74
 
73
- The `importLocation` function uses `loadLocation`.
74
- Using `loadLocation` directly allows for deferred execution or multiple runs
75
- with different globals or modules in the same process.
76
- Calling `loadLocation` returns an `Application` object with an
75
+ The `importLocation` function internally uses `loadLocation`.
76
+ Use `loadLocation` to defer execution or evaluate multiple times with varying
77
+ globals or modules in the same process.
78
+ `loadLocation` returns an Application object with an
77
79
  `import({ globals?, modules? })` method.
78
80
 
81
+ ## Writing an application archive
82
+
79
83
  Use `writeArchive` to capture an application in an archival format.
80
84
  Archives are `zip` files with a `compartment-map.json` manifest file.
81
85
 
82
86
  ```js
83
87
  import fs from "fs";
88
+ import { fileURLToPath } from "url";
84
89
  import { writeArchive } from "@endo/compartment-mapper";
85
90
 
86
- const read = async location =>
87
- fs.promises.readFile(new URL(location).pathname);
91
+ const read = async location => fs.promises.readFile(fileURLToPath(location));
88
92
  const write = async (location, content) =>
89
- fs.promises.writeFile(new URL(location).pathname, content);
93
+ fs.promises.writeFile(fileURLToPath(location), content);
90
94
 
91
- await writeArchive(
92
- write,
93
- read,
94
- new URL('app.zip', import.meta.url).toString(), // the archive to write
95
- new URL('app.js', import.meta.url).toString() // the application to capture
96
- );
95
+ const moduleSpecifier = new URL('app.js', import.meta.url).toString();
96
+ const archiveLocation = new URL('app.zip', import.meta.url).toString();
97
+
98
+ // Write to `archiveLocation`.
99
+ await writeArchive(write, read, archiveLocation, moduleSpecifier);
97
100
  ```
98
101
 
99
- The `writeArchive` function uses `makeArchive`.
102
+ The `writeArchive` function internally uses `makeArchive`.
100
103
  Using `makeArchive` directly gives you the archive bytes.
101
104
 
105
+ ## Evaluating an application from an archive
106
+
102
107
  Use `importArchive` to run an application from an archive.
103
108
  Note the similarity to `importLocation`.
104
109
 
105
110
  ```js
106
111
  import fs from "fs";
112
+ import { fileURLToPath } from "url";
107
113
  import { importArchive } from "@endo/compartment-mapper";
108
114
 
109
115
  // ...
110
116
 
111
- const modules = { fs };
112
- const globals = { console };
117
+ const read = async location => fs.promises.readFile(fileURLToPath(location));
113
118
 
114
- const read = async location =>
115
- fs.promises.readFile(new URL(location).pathname);
116
-
117
- const { namespace } = await importArchive(
119
+ const { namespace: moduleExports } = await importArchive(
118
120
  read,
119
121
  archiveLocation,
120
122
  {
121
- globals,
122
- modules
123
- }
123
+ globals: { console },
124
+ modules: { fs },
125
+ },
124
126
  );
125
127
  ```
126
128
 
127
- The `importArchive` function composes `loadArchive` and `parseArchive`.
129
+ The `importArchive` function internally composes `loadArchive` and
130
+ `parseArchive`.
128
131
  Use `loadArchive` to defer execution or run multiple times with varying
129
- globals.
132
+ globals or modules in the same process.
130
133
  Use `parseArchive` to construct a runner from the bytes of an archive.
131
- The `loadArchive` and `parseArchive` functions return an `Application`
132
- object with an `import({ globals?, modules? })` method.
134
+ `loadArchive` and `parseArchive` return an Application object with an
135
+ `import({ globals?, modules? })` method.
136
+
137
+ `loadArchive` and `parseArchive` do not run the archived application,
138
+ so they can be used to safely check its hash.
139
+
140
+ # Script bundles
141
+
142
+ From `@endo/compartment-mapper/script.js`, the `makeScript` function is similar
143
+ to `makeArchive` but generates a string of JavaScript suitable for `eval` or
144
+ embedding in a web page with a `<script>`.
145
+ Endo uses this "bundle" format to bootstrap an environment up to the point it
146
+ can call `importArchive`, so bundles are at least suitable for creating a
147
+ script that subsumes `ses`, `@endo/compartment-mapper/import-archive.js`, and
148
+ other parts of Endo, but is not as feature-complete as `importArchive`.
133
149
 
134
- `loadArchive` and `parseArchive` do not run the archived program,
135
- so they can be used to check the hash of a program without running it.
150
+ ```js
151
+ import url from "url";
152
+ import fs from "fs";
153
+ import { makeScript } from "@endo/compartment-mapper/script.js";
154
+ import { makeReadPowers } from "@endo/compartment-mapper/node-powers.js";
155
+ const readPowers = makeReadPowers({ fs, url });
156
+ const options = {}; // if any
157
+ const script = await makeScript(readPowers, moduleSpecifier, options);
158
+ ```
159
+
160
+ The script is suitable for evaluating as a script in a web environment.
161
+ The script is in UTF-8 format and uses non-ASCII characters, so may require
162
+ headers or tags to specify the encoding.
163
+
164
+ ```html
165
+ <meta charset="utf-8">
166
+ <script src="script.js"></script>
167
+ ```
168
+
169
+ Evaluation of `script` returns the emulated exports namespace of the entry
170
+ module.
171
+
172
+ ```js
173
+ const script = await makeScript(readPowers, moduleSpecifier, options);
174
+
175
+ // This one weird trick evaluates your script in global scope instead of
176
+ // lexical scope.
177
+ const globalEval = eval;
178
+ const moduleExports = globalEval(script);
179
+ ```
180
+
181
+ Scripts can include ESM, CJS, and JSON modules, but no other module languages
182
+ like bytes or text.
183
+
184
+ > [!WARNING]
185
+ > Scripts do not support [live
186
+ > bindings](https://developer.mozilla.org/en-US/docs/Glossary/Binding), dynamic
187
+ > `import`, or `import.meta`.
188
+ > Scripts do not isolate modules to a compartment.
189
+
190
+ `makeScript` accepts all the options of `makeArchive` and:
191
+
192
+ - `sourceUrlPrefix` (string, default `""`):
193
+ Specifies a prefix to occur on each module's `sourceURL` comment, as injected
194
+ at runtime.
195
+ Should generally end with `/` if non-empty.
196
+ This can improve stack traces.
197
+ - `format` (`"cjs"` or `undefined`, default `undefined`):
198
+ By default, `makeBundle` generates a bundle that can be evaluated in any
199
+ context.
200
+ By specifying `"cjs"`, the bundle can assume there is a host CommonJS
201
+ `require` function available for resolving modules that exit the bundle.
202
+ The default is `require` on `globalThis`.
203
+ The `require` function can be overridden with a curried runtime option.
204
+ - `useEvaluate` (boolean, default `false`):
205
+ Disabled by default, for bundles that may be embedded on a web page with a
206
+ `no-unsafe-eval` Content Security Policy.
207
+ Enable for any environment that can use `eval` or other suitable evaluator
208
+ (like a Hardened JavaScript `Compartment`).
209
+
210
+ By default and when `useEvaluate` is explicitly `false`, the text of a module
211
+ includes an array of module evaluator functions.
212
+
213
+ > [!WARNING]
214
+ > Example is illustrative and neither a compatibility guarantee nor even
215
+ > precise.
216
+
217
+ ```js
218
+ (modules => options => {
219
+ /* ...linker runtime... */
220
+ for (const module of modules) {
221
+ module(/* linking convention */);
222
+ }
223
+ )([
224
+ // 1. bundle ./dependency.js
225
+ function () { /* ... */ },
226
+ // 2. bundle ./dependent.js
227
+ function () { /* ... */ },
228
+ ])(/* runtime options */)
229
+ ```
230
+
231
+ Each of these functions is generated by [Endo's emulation of a JavaScript
232
+ `ModuleSource`
233
+ constructor](https://github.com/endojs/endo/blob/master/packages/module-source/DESIGN.md),
234
+ which we use elsewhere in the Compartment Mapper to emulate Compartment
235
+ module systems at runtime, as in the Compartment Mapper's own `importArchive`.
236
+
237
+ With `useEvaluate`, the script instead embeds the text for each module as a
238
+ string, along with a package-relative source URL, and uses an `eval` function
239
+ to produce the corresponding `function`.
240
+
241
+ ```js
242
+ (modules => options => {
243
+ /* ...linker runtime... */
244
+ for (const [module, sourceURL] of modules) {
245
+ evalWithSourceURL(module, sourceURL)(/* linking convention */);
246
+ }
247
+ )([
248
+ // 1. bundle ./dependency.js
249
+ ["(function () { /* ... */ })", "bundle/dependency.js"],
250
+ // 2. bundle ./dependent.js
251
+ ["(function () { /* ... */ })", "bundle/dependent.js"],
252
+ ])(/* runtime options */)
253
+ ```
254
+
255
+ With `useEvaluate`, the bundle will instead capture a string for
256
+ each module function and use an indirect `eval` to revive them.
257
+ This can make the file locations and line numbers in stack traces more
258
+ useful.
259
+
260
+ From `@endo/compartment-mapper/script-lite.js`, the `makeScriptFromMap` takes
261
+ a compartment map, like that generated by `mapNodeModules` in
262
+ `@endo/compartment-mapper/node-modules.js` instead of the entry module's
263
+ location.
264
+ The `-lite.js` modules, in general, do not entrain a specific compartment
265
+ mapper.
266
+
267
+ # Functor bundles
268
+
269
+ From `@endo/compartment-mapper/functor.js`, the `makeFunctor` function is similar
270
+ to `makeScript` but generates a string of JavaScript suitable for `eval` but *not*
271
+ suitable for embedding as a script. But, the completion value of the script
272
+ is a function that accepts runtime options and returns the entry module's emulated
273
+ module exports namespace, adding a level of indirection.
274
+
275
+ In this example, we use a Hardened JavaScript `Compartment` to confine the
276
+ execution of the functor and its modules.
277
+
278
+ ```js
279
+ const functorScript = await makeFunctor(readPowers, moduleSpecifier, options);
280
+ const compartment = new Compartment();
281
+ const moduleExports = compartment.evaluate(functorScript)({
282
+ require,
283
+ evaluate: compartment.evaluate,
284
+ sourceUrlPrefix: 'file:///Users/you/project/',
285
+ });
286
+ ```
287
+
288
+ The functor runtime options include:
289
+
290
+ - `evaluate`: for functors made with `useEvaluate`,
291
+ specifies a function to use to evaluate each module.
292
+ The default evaluator is indirect `eval`.
293
+ - `require`: for functors made with `format` of `"cjs"`, provides the behavior
294
+ for `require` calls that exit the bundle to the host environment.
295
+ Defaults to the `require` in lexical scope.
296
+ - `sourceUrlPrefix`: specifies a prefix to occur on each module's `sourceURL` comment,
297
+ as injected at runtime.
298
+ Overrides the `sourceUrlPrefix` provided to `makeFunctor`, if any.
299
+
300
+ From `@endo/compartment-mapper/functor-lite.js`, the `makeFunctorFromMap` takes
301
+ a compartment map, like that generated by `mapNodeModules` in
302
+ `@endo/compartment-mapper/node-modules.js` instead of the entry module's
303
+ location.
304
+ The `-lite.js` modules, in general, do not entrain a specific compartment
305
+ mapper.
136
306
 
137
307
  # Package Descriptors
138
308
 
@@ -164,7 +334,7 @@ in a parent directory, under `node_modules`.
164
334
  The `main`, `browser`, and `exports` properties determine the modules each
165
335
  package exports to other compartments.
166
336
 
167
- The `exports` property describes [package entry points][] and can be influenced
337
+ The `exports` property describes [package entry points] and can be influenced
168
338
  by build _conditions_.
169
339
  Currently, the only conditions supported by the compartment mapper are
170
340
  `import`, `browser`, and `endo`.
@@ -177,13 +347,11 @@ The `endo` condition only indicates that this tool is in use.
177
347
  If no `exports` apply to the root of the compartment namespace (`"."`),
178
348
  the `main` property serves as a default.
179
349
 
180
- > TODO
181
- >
182
- > A future version may also respect the `imports` property.
350
+ > [!NOTE]
351
+ > TODO: A future version may also respect the `imports` property.
183
352
 
184
- > TODO
185
- >
186
- > A future version may also respect wildcard patterns in `exports` and
353
+ > [!NOTE]
354
+ > TODO: A future version may also respect wildcard patterns in `exports` and
187
355
  > `imports`.
188
356
 
189
357
  The `files` property indicates all of the files in the package that
@@ -195,10 +363,9 @@ With the compartment mapper, just as in Node.js, a module specifier that has no
195
363
  extension may refer either to the file with the `js` extension, or if that file
196
364
  does not exist, to the `index.js` file in the directory with the same name.
197
365
 
198
- > TODO
199
- >
200
- > The compartment mapper does not yet do anything with the `files` globs but a
201
- > future version of the compartment mapper will collect these in archives.
366
+ > [!NOTE]
367
+ > TODO: The compartment mapper does not yet do anything with the `files` globs
368
+ > but a future version of the compartment mapper will collect these in archives.
202
369
  > The compartment mapper should eventually provide the means for any
203
370
  > compartment to access its own files using an attenuated `fs` module or
204
371
  > `fetch` global, in conjunction with usable values for `import.meta.url` in
@@ -206,29 +373,28 @@ does not exist, to the `index.js` file in the directory with the same name.
206
373
 
207
374
  ## Language Extensions
208
375
 
209
- Officially beginning with Node.js 14, Node.js treats `.mjs` files as ECMAScript
210
- modules and `.cjs` files as CommonJS modules.
376
+ Node.js version 14 or greater treats `.mjs` files as ECMAScript modules and
377
+ `.cjs` files as CommonJS modules.
211
378
  The `.js` extension indicates a CommonJS module by default, to maintain
212
379
  backward compatibility.
213
- However, packages that have a `type` property that explicitly says `module`
214
- will treat a `.js` file as an ECMAScript module.
380
+ However, packages with `type` "module" will treat a `.js` file as an ECMAScript
381
+ module.
215
382
 
216
383
  Many Node.js applications using CommonJS modules expect to be able to `require`
217
384
  a JSON file like `package.json`.
218
- The compartment mapper supports loading JSON modules from any type of module.
219
- As of Node.js 14, Node does not support importing JSON using ECMAScript
220
- `import` directives, so using this feature may limit compatibility with the
221
- Node.js platform.
385
+ The compartment mapper therefore supports loading JSON modules from any type of
386
+ module, but using this feature may limit compatibility with the Node.js platform
387
+ (in which importing a JSON module requires [import attributes] including
388
+ `type: "json"`).
222
389
 
223
390
  The compartment mapper supports loading CommonJS modules from ECMAScript
224
- modules as well as ECMAScript modules importing CommonJS modules.
391
+ modules as well as loading ECMAScript modules from CommonJS modules.
225
392
  This presumes that the CommonJS modules exclusively use `require` calls with a
226
393
  single string argument, where `require` is not lexically bound, to declare
227
394
  their shallow dependencies, so that these modules and their transitive
228
395
  dependencies can be loaded before any module executes.
229
- As of Node.js 14, Node does not support loading ECMAScript modules from
230
- CommonJS modules, so using this feature may limit compatibility with the
231
- Node.js platform.
396
+ Use of this feature may limit compatibility with the Node.js platform, which did
397
+ not support loading ECMAScript modules from CommonJS modules until version 22.
232
398
 
233
399
  The compartment mapper supports language plugins.
234
400
  The languages supported by default are:
@@ -245,8 +411,8 @@ The languages supported by default are:
245
411
 
246
412
  The compartment mapper accepts extensions to this set of languages with
247
413
  the `parserForLanguage` option supported by many functions.
248
- See `src/types/external.ts` for the type and expected behavior for
249
- parsers.
414
+ See [src/types/external.ts](./src/types/external.ts) for the type and expected
415
+ behavior of parsers.
250
416
 
251
417
  These language identifiers are keys for the `moduleTransforms` and
252
418
  `syncModuleTransforms` options, which may map each language to a transform
@@ -256,9 +422,9 @@ The language identifiers are also the values for a `languageForExtension`,
256
422
  configure additional extension-to-language mappings for a module and its
257
423
  transitive dependencies.
258
424
 
259
- For any package that has `type` set to `"module"` in its `package.json`,
425
+ For any package that has `type` set to "module" in its `package.json`,
260
426
  `moduleLangaugeForExtension` will precede `languageForExtension`.
261
- Packages with `type` set to `"commonjs"` or simply not set,
427
+ For any packages with `type` set to "commonjs" or simply not set,
262
428
  `commonjsLanguageForExtension` will precede `languageForExtension`.
263
429
  This provides an hook for mapping TypeScript's `.ts` to either `.cts` or
264
430
  `.mts`.
@@ -279,14 +445,12 @@ override the extension-to-language mapping.
279
445
  }
280
446
  ```
281
447
 
282
- > TODO
283
- >
284
- > The compartment mapper may elect to respect some properties specified for
285
- > import maps.
448
+ > [!NOTE]
449
+ > TODO: The compartment mapper may elect to respect some properties specified
450
+ > for import maps.
286
451
 
287
- > TODO
288
- >
289
- > A future version of the compartment mapper may add support for
452
+ > [!NOTE]
453
+ > TODO: A future version of the compartment mapper may add support for
290
454
  > source-to-source translation in the scope of a package or compartment.
291
455
  > This would be expressed in `package.json` using a property like
292
456
  > `translate` that would contain a map from file extension
@@ -300,10 +464,10 @@ override the extension-to-language mapping.
300
464
  > non-browser compartment during bundling, so the translator can be excluded
301
465
  > from the production application and archived applications.
302
466
 
303
- > TODO
304
- >
305
- > The compartment mapper may also add support for compartment map plugins that
306
- > would recognize packages in `devDependencies` that need to introduce globals.
467
+ > [!NOTE]
468
+ > TODO: The compartment mapper may also add support for compartment map plugins
469
+ > that would recognize packages in `devDependencies` that need to introduce
470
+ > globals.
307
471
  > For example, _packages_ that use JSX and a virtual DOM would be able to add a
308
472
  > module-to-module translator and endow the compartment with the `h` the
309
473
  > translated modules need.
@@ -344,25 +508,27 @@ certain conditions:
344
508
 
345
509
  # Design
346
510
 
347
- Each of the workflows the compartment mapper executes a portion of one sequence
511
+ Each workflow of the compartment mapper executes a portion of a sequence
348
512
  of underlying internals.
349
513
 
350
- * search (`search.js`): Scan the parent directories of a given `moduleLocation`
351
- until successfully finding and reading a `package.json` for the containing
352
- application.
353
- * map compartments from Node.js packages (`node-modules.js`): Find and gather
354
- all the `package.json` files for the application's transitive dependencies.
514
+ * search ([search.js](./src/search.js)): Scan the parent directories of a given
515
+ `moduleSpecifier` until successfully finding and reading a `package.json` for
516
+ the containing application.
517
+ * map compartments from Node.js packages
518
+ ([node-modules.js](./src/node-modules.js)): Find and gather all the
519
+ `package.json` files for the application's transitive dependencies.
355
520
  Use these to construct a compartment map describing how to construct a
356
521
  `Compartment` for each application package and how to link the modules each
357
522
  exports in the compartments that import them.
358
- * load compartments (`archive.js`): Using `compartment.load`, or
359
- implicitly through `compartment.import`, create a module graph for the
523
+ * load compartments ([archive.js](./src/archive.js)): Using `compartment.load`,
524
+ or implicitly through `compartment.import`, create a module graph for the
360
525
  application's entire working set.
361
526
  When creating an archive, this does not execute any of the modules.
362
527
  The compartment mapper uses the compartments and a special `importHook` that
363
528
  records the text of every module the main module needed.
364
- * import modules (`import.js`, `import-archive.js`): Actually execute the
365
- working set.
529
+ * import modules ([import.js](./src/import.js),
530
+ [import-archive.js](./src/import-archive.js)): Actually execute the working
531
+ set.
366
532
 
367
533
  Around this sequence, we can enter late or depart early to store or retrieve an
368
534
  archive.
@@ -449,7 +615,7 @@ type Compartment = {
449
615
  scopes: ScopeMap,
450
616
  // The name of the realm to run the compartment within.
451
617
  // The default is a single frozen realm that has no name.
452
- realm: RealmName? // TODO
618
+ realm?: RealmName // TODO
453
619
  };
454
620
 
455
621
  // Location is the URL relative to the compartment-map.json's
@@ -471,10 +637,10 @@ type CompartmentModule = {
471
637
  // TODO an absent compartment name may imply either
472
638
  // that the module is an internal alias of the
473
639
  // same compartment, or given by the user.
474
- compartment: CompartmentName?,
640
+ compartment?: CompartmentName,
475
641
  // The name of the module in the foreign compartment's
476
642
  // module namespace:
477
- module: ExternalModuleSpecifier?,
643
+ module?: ExternalModuleSpecifier,
478
644
  };
479
645
 
480
646
  // FileLocation is a URL for a module's file relative to the location of the
@@ -594,13 +760,14 @@ The rules defined by policy get preserved in the compartment map and enforced in
594
760
 
595
761
  The shape of the `policy` object is based on `policy.json` from LavaMoat. MetaMask's [LavaMoat] generates a `policy.json` file that serves the same purposes, using a tool called TOFU: _trust on first use_.
596
762
 
597
- > TODO
598
- >
599
- > Endo policy support is intended to reach parity with LavaMoat's policy.json.
763
+ > [!NOTE]
764
+ > TODO: Endo policy support is intended to reach parity with LavaMoat's
765
+ > policy.json.
600
766
  > Policy generation may be ported to Endo.
601
767
 
602
-
603
768
  [LavaMoat]: https://github.com/LavaMoat/lavamoat
604
769
  [Compartments]: ../ses/README.md#compartment
605
770
  [Policy Demo]: ./demo/policy/README.md
771
+ [import attributes]: https://nodejs.org/docs/latest/api/esm.html#import-attributes
606
772
  [package entry points]: https://nodejs.org/api/esm.html#esm_package_entry_points
773
+ [`require.resolve()`]: https://nodejs.org/docs/latest/api/modules.html#requireresolverequest-options
package/SECURITY.md CHANGED
@@ -8,9 +8,9 @@ be made for the most recent branch only.
8
8
 
9
9
  ## Coordinated Vulnerability Disclosure of Security Bugs
10
10
 
11
- SES stands for fearless cooperation, and strong security requires strong collaboration with security researchers. If you believe that you have found a security sensitive bug that should not be disclosed until a fix has been made available, we encourage you to report it. To report a bug in HardenedJS, you have several options that include:
11
+ SES stands for fearless cooperation, and strong security requires strong collaboration with security researchers. If you believe that you have found a security sensitive bug that should not be disclosed until a fix has been made available, we encourage you to report it. To report a bug in HardenedJS, you have several options that include:
12
12
 
13
- * Reporting the issue to the [Agoric HackerOne vulnerability rewards program](https://hackerone.com/agoric).
13
+ * Reporting the issue to the [Agoric HackerOne vulnerability rewards program](https://hackerone.com/agoric).
14
14
 
15
15
  * Sending an email to security at (@) agoric.com., encrypted or unencrypted. To encrypt, please use @Warner’s personal GPG key [A476E2E6 11880C98 5B3C3A39 0386E81B 11CAA07A](http://www.lothar.com/warner-gpg.html) .
16
16
 
package/bundle.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export * from "./src/types-external.js";
2
- export { makeBundle, writeBundle } from "./src/bundle.js";
2
+ export { makeScript as makeBundle, writeScript as writeBundle } from "./src/bundle.js";
3
3
  //# sourceMappingURL=bundle.d.ts.map
package/bundle.js CHANGED
@@ -1,4 +1,7 @@
1
1
  // eslint-disable-next-line import/export -- just types
2
2
  export * from './src/types-external.js';
3
3
 
4
- export { makeBundle, writeBundle } from './src/bundle.js';
4
+ export {
5
+ makeScript as makeBundle,
6
+ writeScript as writeBundle,
7
+ } from './src/bundle.js';
@@ -0,0 +1,3 @@
1
+ export * from "./src/types-external.js";
2
+ export { makeFunctorFromMap } from "./src/bundle-lite.js";
3
+ //# sourceMappingURL=functor-lite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"functor-lite.d.ts","sourceRoot":"","sources":["functor-lite.js"],"names":[],"mappings":""}
@@ -0,0 +1,4 @@
1
+ // eslint-disable-next-line import/export -- just types
2
+ export * from './src/types-external.js';
3
+
4
+ export { makeFunctorFromMap } from './src/bundle-lite.js';
package/functor.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from "./src/types-external.js";
2
+ export { makeFunctor } from "./src/bundle.js";
3
+ //# sourceMappingURL=functor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"functor.d.ts","sourceRoot":"","sources":["functor.js"],"names":[],"mappings":""}
package/functor.js ADDED
@@ -0,0 +1,4 @@
1
+ // eslint-disable-next-line import/export -- just types
2
+ export * from './src/types-external.js';
3
+
4
+ export { makeFunctor } from './src/bundle.js';
package/index.d.ts CHANGED
@@ -4,5 +4,5 @@ export { compartmentMapForNodeModules } from "./src/node-modules.js";
4
4
  export { loadLocation, importLocation } from "./src/import.js";
5
5
  export { makeArchive, makeAndHashArchive, writeArchive, mapLocation, hashLocation } from "./src/archive.js";
6
6
  export { parseArchive, loadArchive, importArchive } from "./src/import-archive.js";
7
- export { makeBundle, writeBundle } from "./src/bundle.js";
7
+ export { makeScript as makeBundle, writeScript as writeBundle } from "./src/bundle.js";
8
8
  //# sourceMappingURL=index.d.ts.map
package/index.js CHANGED
@@ -16,4 +16,7 @@ export {
16
16
  } from './src/import-archive.js';
17
17
  export { search } from './src/search.js';
18
18
  export { compartmentMapForNodeModules } from './src/node-modules.js';
19
- export { makeBundle, writeBundle } from './src/bundle.js';
19
+ export {
20
+ makeScript as makeBundle,
21
+ writeScript as writeBundle,
22
+ } from './src/bundle.js';