@poe-platform/safe-js 0.1.39 → 0.1.41
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.
- package/README.md +26 -1
- package/dist/safe-js/chunks/{chunk-BW4SYRDC.js → chunk-CZNLD2Z3.js} +21 -3
- package/dist/safe-js/chunks/{chunk-BW4SYRDC.js.map → chunk-CZNLD2Z3.js.map} +2 -2
- package/dist/safe-js/chunks/{chunk-S64MC6ZD.js → chunk-VD4EWODR.js} +2 -2
- package/dist/safe-js/cli.js +2 -2
- package/dist/safe-js/core.js +1 -1
- package/dist/safe-js/index.js +2 -2
- package/dist/safe-js/realm.d.ts +3 -0
- package/dist/safe-js/run.d.ts +1 -0
- package/package.json +2 -2
- /package/dist/safe-js/chunks/{chunk-S64MC6ZD.js.map → chunk-VD4EWODR.js.map} +0 -0
package/README.md
CHANGED
|
@@ -168,6 +168,7 @@ This prints `2`. Evaluations share declarations, closures and object identity wi
|
|
|
168
168
|
| --- | --- |
|
|
169
169
|
| `extensions` | Explicit `defineExtension(...)` registrations; `[]`. Setup runs once, on first evaluation, not on construction or unused close. |
|
|
170
170
|
| `grants` | Granted capability names; `[]`. Every requested capability must be granted before any extension setup runs. |
|
|
171
|
+
| `builtinOverrides` | Optional `{ console: "extension-name" }` authorizes that registered extension to replace only the builtin console. It must declare `console` and export a host object created in the realm. No overrides by default. |
|
|
171
172
|
| `limits` | Positive integer caps: `extensions: 32`, `hostObjects: 1024`, `callbacks: 1024`, `guestReferences: 1024`, `cleanups: 1024`, `nestedEvaluations: 16`. Collection budgets also apply. |
|
|
172
173
|
|
|
173
174
|
Ordinary host arguments/results are still copied. To preserve live native identity, explicitly create a host object. A guest function crossing to the host becomes an opaque callback: invoke it with `realm.invokeCallback(callback, { thisValue?, args? })`, then `realm.releaseCallback(callback)` when no longer needed. Callbacks and live objects cannot cross realms or survive close. For deferred arguments that must preserve guest identity, opt into retained references as described below.
|
|
@@ -209,6 +210,30 @@ try {
|
|
|
209
210
|
|
|
210
211
|
The manifest requires `version: 1` and a nonempty `name`. Optional `capabilities` and `globals` are name arrays; `modules` maps module names to export-name arrays. Synchronous `setup(context)` returns `{ globals?, modules? }` matching those declarations exactly. Module exports use the existing record/Map registry. Duplicate names, incompatible versions, missing grants and conflicts with intrinsics or caller values are rejected before setup. Accessor-based declarations and asynchronous factories are unsupported.
|
|
211
212
|
|
|
213
|
+
**Sharing an owned console.** An extension can expose the same host object as `console`, `window.console` and `self.console`:
|
|
214
|
+
|
|
215
|
+
```js
|
|
216
|
+
const browser = defineExtension({
|
|
217
|
+
manifest: { version: 1, name: "browser", globals: ["console", "window", "self"] },
|
|
218
|
+
setup(context) {
|
|
219
|
+
const console = context.createHostObject({ methods: {
|
|
220
|
+
log: (...args) => journal.log(...args),
|
|
221
|
+
warn: (...args) => journal.warn(...args)
|
|
222
|
+
} });
|
|
223
|
+
const window = context.createHostObject({ properties: {
|
|
224
|
+
console: { get: () => console }
|
|
225
|
+
} });
|
|
226
|
+
return { globals: { console, window, self: window } };
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
const realm = createRealm({
|
|
230
|
+
extensions: [browser],
|
|
231
|
+
builtinOverrides: { console: "browser" }
|
|
232
|
+
});
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Supply your own bounded `journal`; this does not add browser console behavior. Without authorization, registration still fails before setup. Caller-provided console bindings, another extension claiming console, unknown override names and missing capability grants still reject. JSON and other intrinsics cannot be overridden this way. The replacement uses normal capability accounting and revocation; its calls do not also go to the builtin `sink`. Close the realm when finished, as in the example above.
|
|
236
|
+
|
|
212
237
|
| Context member | Contract |
|
|
213
238
|
| --- | --- |
|
|
214
239
|
| `signal` | Realm cancellation signal; aborted on close or failure. |
|
|
@@ -303,7 +328,7 @@ For one-shot use, `run(source, { extensions, grants, ... })` accepts the same re
|
|
|
303
328
|
| --- | --- |
|
|
304
329
|
| `bindings` | Global input values and host functions; none by default. |
|
|
305
330
|
| `modules` | Module names mapped to export records or Maps; none by default. |
|
|
306
|
-
| `extensions`, `grants`, `limits` | Opt into a one-shot extension realm; see the supported options and lifetime rules above. |
|
|
331
|
+
| `extensions`, `grants`, `builtinOverrides`, `limits` | Opt into a one-shot extension realm; see the supported options and lifetime rules above. |
|
|
307
332
|
| `budget` | A `Budget` instance. Without one, only the default call-depth limit of 1,000 is configured. |
|
|
308
333
|
| `signal` | Host `AbortSignal` for cancellation. |
|
|
309
334
|
| `filename` | Diagnostic filename; defaults to `<input>`. |
|
|
@@ -30844,6 +30844,14 @@ var RealmState = class {
|
|
|
30844
30844
|
this.modules = readModules(options.modules);
|
|
30845
30845
|
const grants = new Set(readStringList(options.grants ?? [], "Realm grants"));
|
|
30846
30846
|
for (const extension of this.extensions) getExtensionSetup(extension);
|
|
30847
|
+
const overrides = readDataRecord(options.builtinOverrides === void 0 ? {} : options.builtinOverrides, "Builtin overrides");
|
|
30848
|
+
for (const [name, extensionName] of Object.entries(overrides)) {
|
|
30849
|
+
if (name !== "console" || typeof extensionName !== "string" || extensionName.length === 0 || extensionName.length > 256)
|
|
30850
|
+
throw new TypeError("Builtin overrides only supports console with a nonempty extension name.");
|
|
30851
|
+
if (!this.extensions.some((extension) => extension.manifest.name === extensionName && extension.manifest.globals?.includes(name)))
|
|
30852
|
+
throw new TypeError("Console override requires a registered extension declaring console.");
|
|
30853
|
+
this.consoleExtension = extensionName;
|
|
30854
|
+
}
|
|
30847
30855
|
this.budget = options.budget ?? new Budget({ maxCallDepth: 1e3 });
|
|
30848
30856
|
this.lease = this.budget.acquireCompileOwner(true);
|
|
30849
30857
|
this.compilation = new CompileScope(this.lease.owner);
|
|
@@ -30864,7 +30872,10 @@ var RealmState = class {
|
|
|
30864
30872
|
random: createReplayableRandom({ seed: options.randomSeed }).next
|
|
30865
30873
|
});
|
|
30866
30874
|
const names = /* @__PURE__ */ new Set();
|
|
30867
|
-
const globals = /* @__PURE__ */ new Set([
|
|
30875
|
+
const globals = /* @__PURE__ */ new Set([
|
|
30876
|
+
...Object.keys(this.builtinBindings).filter((name) => name !== "console" || this.consoleExtension === void 0),
|
|
30877
|
+
...Object.keys(this.globals)
|
|
30878
|
+
]);
|
|
30868
30879
|
const modules = new Map(
|
|
30869
30880
|
Object.entries(this.modules).map(([name, exports]) => [name, new Set(Object.keys(exports))])
|
|
30870
30881
|
);
|
|
@@ -30878,6 +30889,8 @@ var RealmState = class {
|
|
|
30878
30889
|
throw new TypeError(`Missing grant '${capability}' for extension '${manifest.name}'.`);
|
|
30879
30890
|
}
|
|
30880
30891
|
for (const name of manifest.globals ?? []) {
|
|
30892
|
+
if (name === "console" && this.consoleExtension !== void 0 && manifest.name !== this.consoleExtension)
|
|
30893
|
+
throw new TypeError(`Conflicting global 'console': replacement is authorized only for '${this.consoleExtension}'.`);
|
|
30881
30894
|
if (globals.has(name)) throw new TypeError(`Conflicting global '${name}'.`);
|
|
30882
30895
|
globals.add(name);
|
|
30883
30896
|
}
|
|
@@ -30912,6 +30925,7 @@ var RealmState = class {
|
|
|
30912
30925
|
bridge;
|
|
30913
30926
|
limits;
|
|
30914
30927
|
extensions;
|
|
30928
|
+
consoleExtension;
|
|
30915
30929
|
cleanups = [];
|
|
30916
30930
|
callbacks = /* @__PURE__ */ new Map();
|
|
30917
30931
|
pendingCallbacks = /* @__PURE__ */ new Set();
|
|
@@ -31342,6 +31356,8 @@ var RealmState = class {
|
|
|
31342
31356
|
);
|
|
31343
31357
|
const modules = readModules(exports.modules);
|
|
31344
31358
|
assertNames(Object.keys(globals), extension.manifest.globals ?? [], "global");
|
|
31359
|
+
if (extension.manifest.name === this.consoleExtension && !this.hostObjects.has(globals.console))
|
|
31360
|
+
throw new TypeError("Console replacement must be a host object created in this realm.");
|
|
31345
31361
|
assertNames(Object.keys(modules), Object.keys(extension.manifest.modules ?? {}), "module");
|
|
31346
31362
|
for (const [name, values] of Object.entries(modules)) {
|
|
31347
31363
|
assertNames(Object.keys(values), extension.manifest.modules?.[name] ?? [], "module export");
|
|
@@ -31587,6 +31603,7 @@ function readRealmOptions(value, oneShot = false) {
|
|
|
31587
31603
|
"bindings",
|
|
31588
31604
|
"modules",
|
|
31589
31605
|
"extensions",
|
|
31606
|
+
"builtinOverrides",
|
|
31590
31607
|
"grants",
|
|
31591
31608
|
"budget",
|
|
31592
31609
|
"signal",
|
|
@@ -32170,7 +32187,8 @@ var UnhandledRejectionError = class extends Error {
|
|
|
32170
32187
|
};
|
|
32171
32188
|
var DEFAULT_MAX_CALL_DEPTH = 1e3;
|
|
32172
32189
|
function run(source, options = {}) {
|
|
32173
|
-
if (options.extensions !== void 0
|
|
32190
|
+
if (options.extensions !== void 0 || options.builtinOverrides !== void 0)
|
|
32191
|
+
return runWithExtensions(source, options);
|
|
32174
32192
|
const lifecycle = {
|
|
32175
32193
|
hostCallbackDepth: 0,
|
|
32176
32194
|
hostCallbackContext: new AsyncLocalStorage7()
|
|
@@ -32743,4 +32761,4 @@ export {
|
|
|
32743
32761
|
FileSnapshotBackend,
|
|
32744
32762
|
run
|
|
32745
32763
|
};
|
|
32746
|
-
//# sourceMappingURL=chunk-
|
|
32764
|
+
//# sourceMappingURL=chunk-CZNLD2Z3.js.map
|