sandboxedjs 0.1.95 → 0.1.99
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/dist/index.cjs +62 -31
- package/dist/index.d.cts +36 -12
- package/dist/index.d.ts +36 -12
- package/dist/index.js +62 -31
- package/dist/python-worker.js +2 -1
- package/dist/service-worker.js +21 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -4273,7 +4273,8 @@ function md5Hex(input) {
|
|
|
4273
4273
|
var isNode, zlibPromise, cryptoPromise, SUBTLE_NAMES, UnsupportedAlgorithmError;
|
|
4274
4274
|
var init_binary = __esm({
|
|
4275
4275
|
"src/util/binary.ts"() {
|
|
4276
|
-
isNode = typeof process !== "undefined" && process.versions != null && process.versions.node != null
|
|
4276
|
+
isNode = typeof window === "undefined" && typeof document === "undefined" && typeof process !== "undefined" && process.versions != null && process.versions.node != null && /* A shim has no `release.name`, and Node's has said "node" since v3. */
|
|
4277
|
+
process.release?.name === "node";
|
|
4277
4278
|
zlibPromise = null;
|
|
4278
4279
|
cryptoPromise = null;
|
|
4279
4280
|
SUBTLE_NAMES = {
|
|
@@ -20958,7 +20959,7 @@ var wheels_default = {
|
|
|
20958
20959
|
|
|
20959
20960
|
// package.json
|
|
20960
20961
|
var package_default = {
|
|
20961
|
-
version: "0.1.
|
|
20962
|
+
version: "0.1.99"};
|
|
20962
20963
|
|
|
20963
20964
|
// src/python/extension-abi.ts
|
|
20964
20965
|
var EXTENSION_ABI = {
|
|
@@ -23933,9 +23934,7 @@ async function installRequirements(options) {
|
|
|
23933
23934
|
continue;
|
|
23934
23935
|
}
|
|
23935
23936
|
options.progress.downloading(distribution.name, distribution.version);
|
|
23936
|
-
const bytes2 = await options.client
|
|
23937
|
-
requireArchive(distribution, bytes2);
|
|
23938
|
-
verifyDigest(distribution, bytes2);
|
|
23937
|
+
const bytes2 = await download(options.client, distribution);
|
|
23939
23938
|
const files = stageWheel(readZip(bytes2));
|
|
23940
23939
|
staged.push(...distribution.kind === "substituted" ? substituteFiles(distribution.name, files, SITE_PACKAGES) : files);
|
|
23941
23940
|
installed3.push({ name: distribution.name, version: distribution.version });
|
|
@@ -23951,18 +23950,41 @@ function requireArchive(distribution, bytes2) {
|
|
|
23951
23950
|
`${distribution.filename} did not arrive as a wheel from ${distribution.url}: ` + (looksLikeMarkup ? "the server answered with an HTML page, which usually means the wheel is not published at that address and the server returned its index page instead" : `expected a zip archive, got ${bytes2.length} bytes beginning ${JSON.stringify(opening)}`)
|
|
23952
23951
|
);
|
|
23953
23952
|
}
|
|
23954
|
-
function
|
|
23953
|
+
async function download(client, distribution) {
|
|
23954
|
+
const bytes2 = await client.bytes(distribution.url, { timeoutMs: 12e4 });
|
|
23955
|
+
requireArchive(distribution, bytes2);
|
|
23956
|
+
const mismatch = digestMismatch(distribution, bytes2);
|
|
23957
|
+
if (!mismatch) return bytes2;
|
|
23958
|
+
const fresh = await refetch(client, distribution);
|
|
23959
|
+
if (fresh && !digestMismatch(distribution, fresh)) {
|
|
23960
|
+
requireArchive(distribution, fresh);
|
|
23961
|
+
return fresh;
|
|
23962
|
+
}
|
|
23963
|
+
throw new Error(
|
|
23964
|
+
`${mismatch} ${fresh ? "A retry past any cache returned the same bytes, so the index and the file it names disagree." : "A retry past any cache could not be made, so this may be a cached copy of an older build; clearing the cache, or asking the index's host to purge it, is worth trying before the index is blamed."}`
|
|
23965
|
+
);
|
|
23966
|
+
}
|
|
23967
|
+
async function refetch(client, distribution) {
|
|
23968
|
+
const separator = distribution.url.includes("?") ? "&" : "?";
|
|
23969
|
+
try {
|
|
23970
|
+
const bytes2 = await client.bytes(
|
|
23971
|
+
`${distribution.url}${separator}sha256=${distribution.sha256}`,
|
|
23972
|
+
{ timeoutMs: 6e4 }
|
|
23973
|
+
);
|
|
23974
|
+
return bytes2.length > 1 && bytes2[0] === 80 && bytes2[1] === 75 ? bytes2 : null;
|
|
23975
|
+
} catch {
|
|
23976
|
+
return null;
|
|
23977
|
+
}
|
|
23978
|
+
}
|
|
23979
|
+
function digestMismatch(distribution, bytes2) {
|
|
23955
23980
|
if (!distribution.sha256) {
|
|
23956
23981
|
throw new Error(
|
|
23957
23982
|
`${distribution.filename} was published without a sha256 digest, so it cannot be verified`
|
|
23958
23983
|
);
|
|
23959
23984
|
}
|
|
23960
23985
|
const actual = [...sha256.sha256(bytes2)].map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
23961
|
-
if (actual
|
|
23962
|
-
|
|
23963
|
-
`${distribution.filename} failed verification: the index published sha256 ${distribution.sha256} but the download hashes to ${actual}`
|
|
23964
|
-
);
|
|
23965
|
-
}
|
|
23986
|
+
if (actual === distribution.sha256) return null;
|
|
23987
|
+
return `${distribution.filename} failed verification: the index published sha256 ${distribution.sha256} but the download hashes to ${actual}.`;
|
|
23966
23988
|
}
|
|
23967
23989
|
function stageWheel(entries, resolved) {
|
|
23968
23990
|
const staged = [];
|
|
@@ -28043,12 +28065,19 @@ async function installRelease(ctx, index, release, seen, options) {
|
|
|
28043
28065
|
const base2 = registryBase(ctx).replace(/\/$/, "");
|
|
28044
28066
|
const url = `${base2}/${release.filename}`;
|
|
28045
28067
|
ctx.line(`Fetching ${release.name} ${release.version}`);
|
|
28046
|
-
|
|
28047
|
-
|
|
28068
|
+
let archive = await download2(url);
|
|
28069
|
+
let digest2 = await digestHex("sha256", archive);
|
|
28048
28070
|
if (digest2 !== release.sha256) {
|
|
28049
|
-
|
|
28050
|
-
|
|
28051
|
-
)
|
|
28071
|
+
const retried = await download2(`${url}${url.includes("?") ? "&" : "?"}sha256=${release.sha256}`).catch(() => null);
|
|
28072
|
+
const retriedDigest = retried && await digestHex("sha256", retried);
|
|
28073
|
+
if (retried && retriedDigest === release.sha256) {
|
|
28074
|
+
archive = retried;
|
|
28075
|
+
digest2 = retriedDigest;
|
|
28076
|
+
} else {
|
|
28077
|
+
throw new AppRegistryError(
|
|
28078
|
+
`${release.filename} failed verification: the registry publishes sha256 ${release.sha256} but the download hashes to ${digest2}. ` + (retried ? "A retry past any cache returned the same bytes, so the registry and the file it names disagree." : "A retry past any cache could not be made; a cached copy of an older build would look like this, so clearing the cache is worth trying before the registry is blamed.")
|
|
28079
|
+
);
|
|
28080
|
+
}
|
|
28052
28081
|
}
|
|
28053
28082
|
const verified = await verify(ctx, archive, release, options);
|
|
28054
28083
|
const root = `${APPS_ROOT}/${release.name}`;
|
|
@@ -28075,7 +28104,7 @@ async function installRelease(ctx, index, release, seen, options) {
|
|
|
28075
28104
|
}
|
|
28076
28105
|
if (manifest.docs) ctx.line(` docs: ${root}/${manifest.docs}`);
|
|
28077
28106
|
}
|
|
28078
|
-
async function
|
|
28107
|
+
async function download2(url) {
|
|
28079
28108
|
const response = await fetch(url);
|
|
28080
28109
|
if (!response.ok) {
|
|
28081
28110
|
throw new AppRegistryError(`${url} answered ${response.status} ${response.statusText}`);
|
|
@@ -38630,6 +38659,22 @@ var WS_DATA = "sandboxedjs:ws-data";
|
|
|
38630
38659
|
var WS_CLOSE = "sandboxedjs:ws-close";
|
|
38631
38660
|
var WS_ERROR = "sandboxedjs:ws-error";
|
|
38632
38661
|
|
|
38662
|
+
// src/preview/router.ts
|
|
38663
|
+
var LOOPBACK_HOST = /^(?:localhost|127(?:\.\d{1,3}){3}|0\.0\.0\.0|\[?::1\]?)$/i;
|
|
38664
|
+
function containerTarget(value) {
|
|
38665
|
+
let url;
|
|
38666
|
+
try {
|
|
38667
|
+
url = new URL(value.trim());
|
|
38668
|
+
} catch {
|
|
38669
|
+
return null;
|
|
38670
|
+
}
|
|
38671
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return null;
|
|
38672
|
+
if (!LOOPBACK_HOST.test(url.hostname)) return null;
|
|
38673
|
+
const port = Number(url.port || (url.protocol === "https:" ? 443 : 80));
|
|
38674
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) return null;
|
|
38675
|
+
return { port, path: `${url.pathname}${url.search}` };
|
|
38676
|
+
}
|
|
38677
|
+
|
|
38633
38678
|
// src/preview/register.ts
|
|
38634
38679
|
function serveContainerOn(port, box) {
|
|
38635
38680
|
port.onmessage = async (event) => {
|
|
@@ -38664,20 +38709,6 @@ function serveContainerOn(port, box) {
|
|
|
38664
38709
|
};
|
|
38665
38710
|
port.start?.();
|
|
38666
38711
|
}
|
|
38667
|
-
var LOOPBACK_HOST = /^(?:localhost|127(?:\.\d{1,3}){3}|0\.0\.0\.0|\[?::1\]?)$/i;
|
|
38668
|
-
function containerTarget(value) {
|
|
38669
|
-
let url;
|
|
38670
|
-
try {
|
|
38671
|
-
url = new URL(value.trim());
|
|
38672
|
-
} catch {
|
|
38673
|
-
return null;
|
|
38674
|
-
}
|
|
38675
|
-
if (url.protocol !== "http:" && url.protocol !== "https:") return null;
|
|
38676
|
-
if (!LOOPBACK_HOST.test(url.hostname)) return null;
|
|
38677
|
-
const port = Number(url.port || (url.protocol === "https:" ? 443 : 80));
|
|
38678
|
-
if (!Number.isInteger(port) || port < 1 || port > 65535) return null;
|
|
38679
|
-
return { port, path: `${url.pathname}${url.search}` };
|
|
38680
|
-
}
|
|
38681
38712
|
async function createPreview(box, options = {}) {
|
|
38682
38713
|
if (typeof navigator === "undefined" || !("serviceWorker" in navigator)) return null;
|
|
38683
38714
|
const scriptUrl = options.scriptUrl ?? new URL("./service-worker.js?no-inline", (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
package/dist/index.d.cts
CHANGED
|
@@ -1590,19 +1590,22 @@ declare function startRuntimeWorker(options?: {
|
|
|
1590
1590
|
declare function syncChannelSupported(): boolean;
|
|
1591
1591
|
|
|
1592
1592
|
/**
|
|
1593
|
-
*
|
|
1593
|
+
* The routing a preview service worker does, separated from the worker itself.
|
|
1594
1594
|
*
|
|
1595
|
-
*
|
|
1596
|
-
*
|
|
1595
|
+
* A service worker is awkward to test — it needs a browser, a registration and
|
|
1596
|
+
* a secure context — but almost none of what makes this correct is about being
|
|
1597
|
+
* a service worker. The interesting part is the bookkeeping: which client is
|
|
1598
|
+
* previewing which port, which requests belong to a preview at all, and how a
|
|
1599
|
+
* response is rebuilt on the way back. That lives here, where it can be
|
|
1600
|
+
* exercised directly.
|
|
1597
1601
|
*
|
|
1598
|
-
*
|
|
1599
|
-
*
|
|
1600
|
-
*
|
|
1601
|
-
*
|
|
1602
|
-
*
|
|
1603
|
-
*
|
|
1602
|
+
* The rule this implements, and the reason it exists: requests are routed by
|
|
1603
|
+
* **who is asking**, not by what the path looks like. An iframe navigates once
|
|
1604
|
+
* to `/__sbx__/<port>/`; every later request from that client — however
|
|
1605
|
+
* absolute its path — is recognised by its client id. Nothing has to rewrite
|
|
1606
|
+
* `/src/main.js` or `/@vite/client`, which is what makes a real dev server
|
|
1607
|
+
* work rather than only a single page.
|
|
1604
1608
|
*/
|
|
1605
|
-
|
|
1606
1609
|
/** A container-local server, named by port rather than by an address. */
|
|
1607
1610
|
interface ContainerTarget {
|
|
1608
1611
|
port: number;
|
|
@@ -1618,10 +1621,31 @@ interface ContainerTarget {
|
|
|
1618
1621
|
* is listening, so a frame pointed at it fails with "refused to connect"
|
|
1619
1622
|
* rather than failing visibly as a routing mistake.
|
|
1620
1623
|
*
|
|
1621
|
-
*
|
|
1622
|
-
*
|
|
1624
|
+
* The same translation serves two callers. A host reading an address out of a
|
|
1625
|
+
* build log needs it to point a frame somewhere (`Preview.resolve`), and the
|
|
1626
|
+
* service worker needs it for the other direction: a page *inside* a preview
|
|
1627
|
+
* asking its own backend for `http://localhost:8000/api` means the container's
|
|
1628
|
+
* port 8000, not the reader's machine.
|
|
1629
|
+
*
|
|
1630
|
+
* Kept pure, and kept here rather than beside the host half, because the
|
|
1631
|
+
* worker bundles this module and not that one.
|
|
1623
1632
|
*/
|
|
1624
1633
|
declare function containerTarget(value: string): ContainerTarget | null;
|
|
1634
|
+
|
|
1635
|
+
/**
|
|
1636
|
+
* Wiring a container's HTTP servers up to real URLs in the page.
|
|
1637
|
+
*
|
|
1638
|
+
* The service worker does the routing; this is the half that lives in the page
|
|
1639
|
+
* and actually knows about the container.
|
|
1640
|
+
*
|
|
1641
|
+
* **Read the origin note before using this.** A preview served this way runs on
|
|
1642
|
+
* *your* origin, so scripts inside it can reach `window.parent`, your cookies
|
|
1643
|
+
* and your `localStorage` — the sandbox contains the program's *filesystem and
|
|
1644
|
+
* process table*, not the page it serves. For code you did not write, either
|
|
1645
|
+
* host the preview on a separate origin, or use {@link renderInto}, which puts
|
|
1646
|
+
* the response in an iframe with no origin at all.
|
|
1647
|
+
*/
|
|
1648
|
+
|
|
1625
1649
|
interface PreviewOptions {
|
|
1626
1650
|
/** Where the worker script lives; defaults to the copy shipped beside the bundle. */
|
|
1627
1651
|
scriptUrl?: string | URL;
|
package/dist/index.d.ts
CHANGED
|
@@ -1590,19 +1590,22 @@ declare function startRuntimeWorker(options?: {
|
|
|
1590
1590
|
declare function syncChannelSupported(): boolean;
|
|
1591
1591
|
|
|
1592
1592
|
/**
|
|
1593
|
-
*
|
|
1593
|
+
* The routing a preview service worker does, separated from the worker itself.
|
|
1594
1594
|
*
|
|
1595
|
-
*
|
|
1596
|
-
*
|
|
1595
|
+
* A service worker is awkward to test — it needs a browser, a registration and
|
|
1596
|
+
* a secure context — but almost none of what makes this correct is about being
|
|
1597
|
+
* a service worker. The interesting part is the bookkeeping: which client is
|
|
1598
|
+
* previewing which port, which requests belong to a preview at all, and how a
|
|
1599
|
+
* response is rebuilt on the way back. That lives here, where it can be
|
|
1600
|
+
* exercised directly.
|
|
1597
1601
|
*
|
|
1598
|
-
*
|
|
1599
|
-
*
|
|
1600
|
-
*
|
|
1601
|
-
*
|
|
1602
|
-
*
|
|
1603
|
-
*
|
|
1602
|
+
* The rule this implements, and the reason it exists: requests are routed by
|
|
1603
|
+
* **who is asking**, not by what the path looks like. An iframe navigates once
|
|
1604
|
+
* to `/__sbx__/<port>/`; every later request from that client — however
|
|
1605
|
+
* absolute its path — is recognised by its client id. Nothing has to rewrite
|
|
1606
|
+
* `/src/main.js` or `/@vite/client`, which is what makes a real dev server
|
|
1607
|
+
* work rather than only a single page.
|
|
1604
1608
|
*/
|
|
1605
|
-
|
|
1606
1609
|
/** A container-local server, named by port rather than by an address. */
|
|
1607
1610
|
interface ContainerTarget {
|
|
1608
1611
|
port: number;
|
|
@@ -1618,10 +1621,31 @@ interface ContainerTarget {
|
|
|
1618
1621
|
* is listening, so a frame pointed at it fails with "refused to connect"
|
|
1619
1622
|
* rather than failing visibly as a routing mistake.
|
|
1620
1623
|
*
|
|
1621
|
-
*
|
|
1622
|
-
*
|
|
1624
|
+
* The same translation serves two callers. A host reading an address out of a
|
|
1625
|
+
* build log needs it to point a frame somewhere (`Preview.resolve`), and the
|
|
1626
|
+
* service worker needs it for the other direction: a page *inside* a preview
|
|
1627
|
+
* asking its own backend for `http://localhost:8000/api` means the container's
|
|
1628
|
+
* port 8000, not the reader's machine.
|
|
1629
|
+
*
|
|
1630
|
+
* Kept pure, and kept here rather than beside the host half, because the
|
|
1631
|
+
* worker bundles this module and not that one.
|
|
1623
1632
|
*/
|
|
1624
1633
|
declare function containerTarget(value: string): ContainerTarget | null;
|
|
1634
|
+
|
|
1635
|
+
/**
|
|
1636
|
+
* Wiring a container's HTTP servers up to real URLs in the page.
|
|
1637
|
+
*
|
|
1638
|
+
* The service worker does the routing; this is the half that lives in the page
|
|
1639
|
+
* and actually knows about the container.
|
|
1640
|
+
*
|
|
1641
|
+
* **Read the origin note before using this.** A preview served this way runs on
|
|
1642
|
+
* *your* origin, so scripts inside it can reach `window.parent`, your cookies
|
|
1643
|
+
* and your `localStorage` — the sandbox contains the program's *filesystem and
|
|
1644
|
+
* process table*, not the page it serves. For code you did not write, either
|
|
1645
|
+
* host the preview on a separate origin, or use {@link renderInto}, which puts
|
|
1646
|
+
* the response in an iframe with no origin at all.
|
|
1647
|
+
*/
|
|
1648
|
+
|
|
1625
1649
|
interface PreviewOptions {
|
|
1626
1650
|
/** Where the worker script lives; defaults to the copy shipped beside the bundle. */
|
|
1627
1651
|
scriptUrl?: string | URL;
|
package/dist/index.js
CHANGED
|
@@ -4256,7 +4256,8 @@ function md5Hex(input) {
|
|
|
4256
4256
|
var isNode, zlibPromise, cryptoPromise, SUBTLE_NAMES, UnsupportedAlgorithmError;
|
|
4257
4257
|
var init_binary = __esm({
|
|
4258
4258
|
"src/util/binary.ts"() {
|
|
4259
|
-
isNode = typeof process !== "undefined" && process.versions != null && process.versions.node != null
|
|
4259
|
+
isNode = typeof window === "undefined" && typeof document === "undefined" && typeof process !== "undefined" && process.versions != null && process.versions.node != null && /* A shim has no `release.name`, and Node's has said "node" since v3. */
|
|
4260
|
+
process.release?.name === "node";
|
|
4260
4261
|
zlibPromise = null;
|
|
4261
4262
|
cryptoPromise = null;
|
|
4262
4263
|
SUBTLE_NAMES = {
|
|
@@ -20941,7 +20942,7 @@ var wheels_default = {
|
|
|
20941
20942
|
|
|
20942
20943
|
// package.json
|
|
20943
20944
|
var package_default = {
|
|
20944
|
-
version: "0.1.
|
|
20945
|
+
version: "0.1.99"};
|
|
20945
20946
|
|
|
20946
20947
|
// src/python/extension-abi.ts
|
|
20947
20948
|
var EXTENSION_ABI = {
|
|
@@ -23916,9 +23917,7 @@ async function installRequirements(options) {
|
|
|
23916
23917
|
continue;
|
|
23917
23918
|
}
|
|
23918
23919
|
options.progress.downloading(distribution.name, distribution.version);
|
|
23919
|
-
const bytes2 = await options.client
|
|
23920
|
-
requireArchive(distribution, bytes2);
|
|
23921
|
-
verifyDigest(distribution, bytes2);
|
|
23920
|
+
const bytes2 = await download(options.client, distribution);
|
|
23922
23921
|
const files = stageWheel(readZip(bytes2));
|
|
23923
23922
|
staged.push(...distribution.kind === "substituted" ? substituteFiles(distribution.name, files, SITE_PACKAGES) : files);
|
|
23924
23923
|
installed3.push({ name: distribution.name, version: distribution.version });
|
|
@@ -23934,18 +23933,41 @@ function requireArchive(distribution, bytes2) {
|
|
|
23934
23933
|
`${distribution.filename} did not arrive as a wheel from ${distribution.url}: ` + (looksLikeMarkup ? "the server answered with an HTML page, which usually means the wheel is not published at that address and the server returned its index page instead" : `expected a zip archive, got ${bytes2.length} bytes beginning ${JSON.stringify(opening)}`)
|
|
23935
23934
|
);
|
|
23936
23935
|
}
|
|
23937
|
-
function
|
|
23936
|
+
async function download(client, distribution) {
|
|
23937
|
+
const bytes2 = await client.bytes(distribution.url, { timeoutMs: 12e4 });
|
|
23938
|
+
requireArchive(distribution, bytes2);
|
|
23939
|
+
const mismatch = digestMismatch(distribution, bytes2);
|
|
23940
|
+
if (!mismatch) return bytes2;
|
|
23941
|
+
const fresh = await refetch(client, distribution);
|
|
23942
|
+
if (fresh && !digestMismatch(distribution, fresh)) {
|
|
23943
|
+
requireArchive(distribution, fresh);
|
|
23944
|
+
return fresh;
|
|
23945
|
+
}
|
|
23946
|
+
throw new Error(
|
|
23947
|
+
`${mismatch} ${fresh ? "A retry past any cache returned the same bytes, so the index and the file it names disagree." : "A retry past any cache could not be made, so this may be a cached copy of an older build; clearing the cache, or asking the index's host to purge it, is worth trying before the index is blamed."}`
|
|
23948
|
+
);
|
|
23949
|
+
}
|
|
23950
|
+
async function refetch(client, distribution) {
|
|
23951
|
+
const separator = distribution.url.includes("?") ? "&" : "?";
|
|
23952
|
+
try {
|
|
23953
|
+
const bytes2 = await client.bytes(
|
|
23954
|
+
`${distribution.url}${separator}sha256=${distribution.sha256}`,
|
|
23955
|
+
{ timeoutMs: 6e4 }
|
|
23956
|
+
);
|
|
23957
|
+
return bytes2.length > 1 && bytes2[0] === 80 && bytes2[1] === 75 ? bytes2 : null;
|
|
23958
|
+
} catch {
|
|
23959
|
+
return null;
|
|
23960
|
+
}
|
|
23961
|
+
}
|
|
23962
|
+
function digestMismatch(distribution, bytes2) {
|
|
23938
23963
|
if (!distribution.sha256) {
|
|
23939
23964
|
throw new Error(
|
|
23940
23965
|
`${distribution.filename} was published without a sha256 digest, so it cannot be verified`
|
|
23941
23966
|
);
|
|
23942
23967
|
}
|
|
23943
23968
|
const actual = [...sha256(bytes2)].map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
23944
|
-
if (actual
|
|
23945
|
-
|
|
23946
|
-
`${distribution.filename} failed verification: the index published sha256 ${distribution.sha256} but the download hashes to ${actual}`
|
|
23947
|
-
);
|
|
23948
|
-
}
|
|
23969
|
+
if (actual === distribution.sha256) return null;
|
|
23970
|
+
return `${distribution.filename} failed verification: the index published sha256 ${distribution.sha256} but the download hashes to ${actual}.`;
|
|
23949
23971
|
}
|
|
23950
23972
|
function stageWheel(entries, resolved) {
|
|
23951
23973
|
const staged = [];
|
|
@@ -28026,12 +28048,19 @@ async function installRelease(ctx, index, release, seen, options) {
|
|
|
28026
28048
|
const base2 = registryBase(ctx).replace(/\/$/, "");
|
|
28027
28049
|
const url = `${base2}/${release.filename}`;
|
|
28028
28050
|
ctx.line(`Fetching ${release.name} ${release.version}`);
|
|
28029
|
-
|
|
28030
|
-
|
|
28051
|
+
let archive = await download2(url);
|
|
28052
|
+
let digest2 = await digestHex("sha256", archive);
|
|
28031
28053
|
if (digest2 !== release.sha256) {
|
|
28032
|
-
|
|
28033
|
-
|
|
28034
|
-
)
|
|
28054
|
+
const retried = await download2(`${url}${url.includes("?") ? "&" : "?"}sha256=${release.sha256}`).catch(() => null);
|
|
28055
|
+
const retriedDigest = retried && await digestHex("sha256", retried);
|
|
28056
|
+
if (retried && retriedDigest === release.sha256) {
|
|
28057
|
+
archive = retried;
|
|
28058
|
+
digest2 = retriedDigest;
|
|
28059
|
+
} else {
|
|
28060
|
+
throw new AppRegistryError(
|
|
28061
|
+
`${release.filename} failed verification: the registry publishes sha256 ${release.sha256} but the download hashes to ${digest2}. ` + (retried ? "A retry past any cache returned the same bytes, so the registry and the file it names disagree." : "A retry past any cache could not be made; a cached copy of an older build would look like this, so clearing the cache is worth trying before the registry is blamed.")
|
|
28062
|
+
);
|
|
28063
|
+
}
|
|
28035
28064
|
}
|
|
28036
28065
|
const verified = await verify(ctx, archive, release, options);
|
|
28037
28066
|
const root = `${APPS_ROOT}/${release.name}`;
|
|
@@ -28058,7 +28087,7 @@ async function installRelease(ctx, index, release, seen, options) {
|
|
|
28058
28087
|
}
|
|
28059
28088
|
if (manifest.docs) ctx.line(` docs: ${root}/${manifest.docs}`);
|
|
28060
28089
|
}
|
|
28061
|
-
async function
|
|
28090
|
+
async function download2(url) {
|
|
28062
28091
|
const response = await fetch(url);
|
|
28063
28092
|
if (!response.ok) {
|
|
28064
28093
|
throw new AppRegistryError(`${url} answered ${response.status} ${response.statusText}`);
|
|
@@ -38613,6 +38642,22 @@ var WS_DATA = "sandboxedjs:ws-data";
|
|
|
38613
38642
|
var WS_CLOSE = "sandboxedjs:ws-close";
|
|
38614
38643
|
var WS_ERROR = "sandboxedjs:ws-error";
|
|
38615
38644
|
|
|
38645
|
+
// src/preview/router.ts
|
|
38646
|
+
var LOOPBACK_HOST = /^(?:localhost|127(?:\.\d{1,3}){3}|0\.0\.0\.0|\[?::1\]?)$/i;
|
|
38647
|
+
function containerTarget(value) {
|
|
38648
|
+
let url;
|
|
38649
|
+
try {
|
|
38650
|
+
url = new URL(value.trim());
|
|
38651
|
+
} catch {
|
|
38652
|
+
return null;
|
|
38653
|
+
}
|
|
38654
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return null;
|
|
38655
|
+
if (!LOOPBACK_HOST.test(url.hostname)) return null;
|
|
38656
|
+
const port = Number(url.port || (url.protocol === "https:" ? 443 : 80));
|
|
38657
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) return null;
|
|
38658
|
+
return { port, path: `${url.pathname}${url.search}` };
|
|
38659
|
+
}
|
|
38660
|
+
|
|
38616
38661
|
// src/preview/register.ts
|
|
38617
38662
|
function serveContainerOn(port, box) {
|
|
38618
38663
|
port.onmessage = async (event) => {
|
|
@@ -38647,20 +38692,6 @@ function serveContainerOn(port, box) {
|
|
|
38647
38692
|
};
|
|
38648
38693
|
port.start?.();
|
|
38649
38694
|
}
|
|
38650
|
-
var LOOPBACK_HOST = /^(?:localhost|127(?:\.\d{1,3}){3}|0\.0\.0\.0|\[?::1\]?)$/i;
|
|
38651
|
-
function containerTarget(value) {
|
|
38652
|
-
let url;
|
|
38653
|
-
try {
|
|
38654
|
-
url = new URL(value.trim());
|
|
38655
|
-
} catch {
|
|
38656
|
-
return null;
|
|
38657
|
-
}
|
|
38658
|
-
if (url.protocol !== "http:" && url.protocol !== "https:") return null;
|
|
38659
|
-
if (!LOOPBACK_HOST.test(url.hostname)) return null;
|
|
38660
|
-
const port = Number(url.port || (url.protocol === "https:" ? 443 : 80));
|
|
38661
|
-
if (!Number.isInteger(port) || port < 1 || port > 65535) return null;
|
|
38662
|
-
return { port, path: `${url.pathname}${url.search}` };
|
|
38663
|
-
}
|
|
38664
38695
|
async function createPreview(box, options = {}) {
|
|
38665
38696
|
if (typeof navigator === "undefined" || !("serviceWorker" in navigator)) return null;
|
|
38666
38697
|
const scriptUrl = options.scriptUrl ?? new URL("./service-worker.js?no-inline", import.meta.url);
|
package/dist/python-worker.js
CHANGED
|
@@ -772,7 +772,8 @@ function createSbxFs(FS, client, errnoCodes) {
|
|
|
772
772
|
}
|
|
773
773
|
|
|
774
774
|
// src/util/binary.ts
|
|
775
|
-
typeof process !== "undefined" && process.versions != null && process.versions.node != null
|
|
775
|
+
typeof window === "undefined" && typeof document === "undefined" && typeof process !== "undefined" && process.versions != null && process.versions.node != null && /* A shim has no `release.name`, and Node's has said "node" since v3. */
|
|
776
|
+
process.release?.name === "node";
|
|
776
777
|
async function nodeBuiltin(name) {
|
|
777
778
|
const specifier = `node:${name}`;
|
|
778
779
|
return await import(
|
package/dist/service-worker.js
CHANGED
|
@@ -349,6 +349,20 @@ function previewSocketSource() {
|
|
|
349
349
|
|
|
350
350
|
// src/preview/router.ts
|
|
351
351
|
var CLAIM = /(?:^|\/)__sbx__\/(\d+)(?:\/|$)/;
|
|
352
|
+
var LOOPBACK_HOST = /^(?:localhost|127(?:\.\d{1,3}){3}|0\.0\.0\.0|\[?::1\]?)$/i;
|
|
353
|
+
function containerTarget(value) {
|
|
354
|
+
let url;
|
|
355
|
+
try {
|
|
356
|
+
url = new URL(value.trim());
|
|
357
|
+
} catch {
|
|
358
|
+
return null;
|
|
359
|
+
}
|
|
360
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return null;
|
|
361
|
+
if (!LOOPBACK_HOST.test(url.hostname)) return null;
|
|
362
|
+
const port = Number(url.port || (url.protocol === "https:" ? 443 : 80));
|
|
363
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) return null;
|
|
364
|
+
return { port, path: `${url.pathname}${url.search}` };
|
|
365
|
+
}
|
|
352
366
|
var OUTDATED = /outdated optimize dep/i;
|
|
353
367
|
var NOT_CONNECTED = 503;
|
|
354
368
|
var PreviewRouter = class {
|
|
@@ -549,7 +563,13 @@ worker.addEventListener("message", (event) => {
|
|
|
549
563
|
});
|
|
550
564
|
worker.addEventListener("fetch", (event) => {
|
|
551
565
|
const url = new URL(event.request.url);
|
|
552
|
-
if (url.origin !== worker.location.origin)
|
|
566
|
+
if (url.origin !== worker.location.origin) {
|
|
567
|
+
const port2 = router.portFor(event.clientId);
|
|
568
|
+
const target = port2 === void 0 ? null : containerTarget(url.href);
|
|
569
|
+
if (!target) return;
|
|
570
|
+
event.respondWith(router.fetch(target.port, target.path, event.request, event.clientId));
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
553
573
|
const claimed = router.claimedPort(url.pathname);
|
|
554
574
|
if (claimed !== null && event.request.mode === "navigate") {
|
|
555
575
|
router.bind(event.resultingClientId || event.clientId, claimed);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sandboxedjs",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.99",
|
|
4
4
|
"description": "A Linux-like container that runs entirely inside Node.js — POSIX shell, ~140 coreutils, Node.js and Python runtimes, virtual filesystem and networking. No Docker, no VM, no native modules.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|