@seanhogg/builderforce-webcontainers-core 2026.10.5 → 2026.10.7
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 +1 -1
- package/dist/archive.d.ts +11 -0
- package/dist/archive.d.ts.map +1 -0
- package/dist/archive.js +51 -0
- package/dist/archive.js.map +1 -0
- package/dist/build.d.ts +3 -3
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +1 -1
- package/dist/build.js.map +1 -1
- package/dist/check/typecheck.d.ts +2 -2
- package/dist/check/typecheck.d.ts.map +1 -1
- package/dist/check/typecheck.js +1 -1
- package/dist/check/typecheck.js.map +1 -1
- package/dist/devServer.d.ts +5 -0
- package/dist/devServer.d.ts.map +1 -1
- package/dist/devServer.js +11 -2
- package/dist/devServer.js.map +1 -1
- package/dist/html.d.ts +10 -3
- package/dist/html.d.ts.map +1 -1
- package/dist/html.js +29 -5
- package/dist/html.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/installer/index.d.ts +2 -0
- package/dist/installer/index.d.ts.map +1 -1
- package/dist/installer/index.js +1 -0
- package/dist/installer/index.js.map +1 -1
- package/dist/installer/install.d.ts +3 -0
- package/dist/installer/install.d.ts.map +1 -1
- package/dist/installer/install.js +1 -1
- package/dist/installer/install.js.map +1 -1
- package/dist/installer/npmrc.d.ts +26 -0
- package/dist/installer/npmrc.d.ts.map +1 -0
- package/dist/installer/npmrc.js +55 -0
- package/dist/installer/npmrc.js.map +1 -0
- package/dist/installer/registry.d.ts +3 -0
- package/dist/installer/registry.d.ts.map +1 -1
- package/dist/installer/registry.js +10 -5
- package/dist/installer/registry.js.map +1 -1
- package/dist/node/childProcess.js +1 -1
- package/dist/node/childProcess.js.map +1 -1
- package/dist/node/misc.js +1 -1
- package/dist/node/misc.js.map +1 -1
- package/dist/shell/builtins.d.ts.map +1 -1
- package/dist/shell/builtins.js +2 -2
- package/dist/shell/builtins.js.map +1 -1
- package/dist/shell/devHandoff.d.ts +1 -1
- package/dist/shell/exec.js +4 -4
- package/dist/shell/exec.js.map +1 -1
- package/dist/shell/expand.js +1 -1
- package/dist/shell/expand.js.map +1 -1
- package/dist/shell/npm.d.ts.map +1 -1
- package/dist/shell/npm.js +5 -1
- package/dist/shell/npm.js.map +1 -1
- package/dist/shell/program.d.ts +1 -1
- package/dist/shell/program.js +3 -3
- package/dist/shell/program.js.map +1 -1
- package/dist/system/commands.d.ts +4 -4
- package/dist/system/commands.d.ts.map +1 -1
- package/dist/system/commands.js +3 -3
- package/dist/system/commands.js.map +1 -1
- package/dist/system/index.d.ts +6 -4
- package/dist/system/index.d.ts.map +1 -1
- package/dist/system/index.js +2 -1
- package/dist/system/index.js.map +1 -1
- package/dist/system/kernel.d.ts +9 -16
- package/dist/system/kernel.d.ts.map +1 -1
- package/dist/system/kernel.js +10 -23
- package/dist/system/kernel.js.map +1 -1
- package/dist/system/process.d.ts +18 -14
- package/dist/system/process.d.ts.map +1 -1
- package/dist/system/process.js +12 -10
- package/dist/system/process.js.map +1 -1
- package/dist/system/programs.js +1 -1
- package/dist/system/programs.js.map +1 -1
- package/dist/system/serverEvents.d.ts +27 -0
- package/dist/system/serverEvents.d.ts.map +1 -0
- package/dist/system/serverEvents.js +33 -0
- package/dist/system/serverEvents.js.map +1 -0
- package/dist/system/types.d.ts +4 -4
- package/dist/system/types.d.ts.map +1 -1
- package/dist/vfs.d.ts +27 -17
- package/dist/vfs.d.ts.map +1 -1
- package/dist/vfs.js +48 -11
- package/dist/vfs.js.map +1 -1
- package/package.json +1 -1
- package/src/archive.ts +59 -0
- package/src/build.ts +4 -4
- package/src/check/typecheck.ts +4 -4
- package/src/devServer.ts +12 -2
- package/src/html.ts +32 -5
- package/src/index.ts +5 -2
- package/src/installer/index.ts +2 -0
- package/src/installer/install.ts +4 -1
- package/src/installer/npmrc.ts +69 -0
- package/src/installer/registry.ts +12 -5
- package/src/node/childProcess.ts +1 -1
- package/src/node/misc.ts +1 -1
- package/src/shell/builtins.ts +2 -2
- package/src/shell/devHandoff.ts +1 -1
- package/src/shell/exec.ts +4 -4
- package/src/shell/expand.ts +1 -1
- package/src/shell/npm.ts +5 -1
- package/src/shell/program.ts +4 -4
- package/src/system/commands.ts +6 -6
- package/src/system/index.ts +6 -4
- package/src/system/kernel.ts +15 -32
- package/src/system/process.ts +28 -20
- package/src/system/programs.ts +1 -1
- package/src/system/serverEvents.ts +44 -0
- package/src/system/types.ts +4 -4
- package/src/vfs.ts +58 -15
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Who hears about servers in a runtime: a port opening or closing, and a
|
|
3
|
+
* server becoming reachable (which a dev-server handoff announces without
|
|
4
|
+
* opening a port). One instance per runtime — the core `Kernel` and the
|
|
5
|
+
* browser's process host both own one, so the listener contract is the same.
|
|
6
|
+
*/
|
|
7
|
+
export interface ServerAddress {
|
|
8
|
+
port: number;
|
|
9
|
+
/** Where a browser reaches it (the preview URL for that port). */
|
|
10
|
+
url: string;
|
|
11
|
+
}
|
|
12
|
+
export interface PortChange extends ServerAddress {
|
|
13
|
+
type: 'open' | 'close';
|
|
14
|
+
}
|
|
15
|
+
export declare class ServerEvents {
|
|
16
|
+
private readonly listening;
|
|
17
|
+
private readonly changes;
|
|
18
|
+
/** A server started listening (or a dev script handed off to the preview); `url` loads it in an iframe. */
|
|
19
|
+
onListening(listener: (server: ServerAddress) => void): () => void;
|
|
20
|
+
/** A virtual server opened or closed its port. */
|
|
21
|
+
onPortChange(listener: (change: PortChange) => void): () => void;
|
|
22
|
+
/** Report a port table change; an opened port is also a server listening. */
|
|
23
|
+
portChanged(change: PortChange): void;
|
|
24
|
+
/** Report a reachable server that did not open a port of its own. */
|
|
25
|
+
announce(server: ServerAddress): void;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=serverEvents.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serverEvents.d.ts","sourceRoot":"","sources":["../../src/system/serverEvents.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,UAAW,SAAQ,aAAa;IAC/C,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA8C;IACxE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2C;IAEnE,2GAA2G;IAC3G,WAAW,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,GAAG,MAAM,IAAI;IAKlE,kDAAkD;IAClD,YAAY,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,GAAG,MAAM,IAAI;IAKhE,6EAA6E;IAC7E,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAKrC,qEAAqE;IACrE,QAAQ,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI;CAGtC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Who hears about servers in a runtime: a port opening or closing, and a
|
|
3
|
+
* server becoming reachable (which a dev-server handoff announces without
|
|
4
|
+
* opening a port). One instance per runtime — the core `Kernel` and the
|
|
5
|
+
* browser's process host both own one, so the listener contract is the same.
|
|
6
|
+
*/
|
|
7
|
+
export class ServerEvents {
|
|
8
|
+
listening = new Set();
|
|
9
|
+
changes = new Set();
|
|
10
|
+
/** A server started listening (or a dev script handed off to the preview); `url` loads it in an iframe. */
|
|
11
|
+
onListening(listener) {
|
|
12
|
+
this.listening.add(listener);
|
|
13
|
+
return () => this.listening.delete(listener);
|
|
14
|
+
}
|
|
15
|
+
/** A virtual server opened or closed its port. */
|
|
16
|
+
onPortChange(listener) {
|
|
17
|
+
this.changes.add(listener);
|
|
18
|
+
return () => this.changes.delete(listener);
|
|
19
|
+
}
|
|
20
|
+
/** Report a port table change; an opened port is also a server listening. */
|
|
21
|
+
portChanged(change) {
|
|
22
|
+
for (const listener of this.changes)
|
|
23
|
+
listener(change);
|
|
24
|
+
if (change.type === 'open')
|
|
25
|
+
this.announce({ port: change.port, url: change.url });
|
|
26
|
+
}
|
|
27
|
+
/** Report a reachable server that did not open a port of its own. */
|
|
28
|
+
announce(server) {
|
|
29
|
+
for (const listener of this.listening)
|
|
30
|
+
listener(server);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=serverEvents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serverEvents.js","sourceRoot":"","sources":["../../src/system/serverEvents.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAYH,MAAM,OAAO,YAAY;IACN,SAAS,GAAG,IAAI,GAAG,EAAmC,CAAC;IACvD,OAAO,GAAG,IAAI,GAAG,EAAgC,CAAC;IAEnE,2GAA2G;IAC3G,WAAW,CAAC,QAAyC;QACnD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC/C,CAAC;IAED,kDAAkD;IAClD,YAAY,CAAC,QAAsC;QACjD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC3B,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC7C,CAAC;IAED,6EAA6E;IAC7E,WAAW,CAAC,MAAkB;QAC5B,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,OAAO;YAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;QACtD,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM;YAAE,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;IACpF,CAAC;IAED,qEAAqE;IACrE,QAAQ,CAAC,MAAqB;QAC5B,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS;YAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC1D,CAAC;CACF"}
|
package/dist/system/types.d.ts
CHANGED
|
@@ -21,7 +21,7 @@ export interface ProgramIO {
|
|
|
21
21
|
/** Present when attached to a terminal (xterm.js). */
|
|
22
22
|
terminal?: TerminalPort;
|
|
23
23
|
}
|
|
24
|
-
export interface
|
|
24
|
+
export interface ProcessOptions {
|
|
25
25
|
cwd?: string;
|
|
26
26
|
env?: Record<string, string>;
|
|
27
27
|
/** Attach to a terminal of this size (`isTTY`, line discipline, `\r\n` output). */
|
|
@@ -30,7 +30,7 @@ export interface SpawnOptions {
|
|
|
30
30
|
rows: number;
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
|
-
/** A child as its parent sees it (separate stdout/stderr, unlike the public
|
|
33
|
+
/** A child as its parent sees it (separate stdout/stderr listeners, unlike the streams of the public `RuntimeProcess`). */
|
|
34
34
|
export interface ChildHandle {
|
|
35
35
|
readonly pid: number;
|
|
36
36
|
onStdout(listener: (chunk: string) => void): () => void;
|
|
@@ -59,7 +59,7 @@ export interface System {
|
|
|
59
59
|
fs: VirtualFileSystem;
|
|
60
60
|
/** Outbound network (registry, `http.request`, `fetch`). */
|
|
61
61
|
fetch(input: string, init?: RequestInit): Promise<Response>;
|
|
62
|
-
spawn(command: string, args: string[], options?:
|
|
62
|
+
spawn(command: string, args: string[], options?: ProcessOptions): ChildHandle;
|
|
63
63
|
/** Register a virtual server; throws `EADDRINUSE`. Port 0 picks a free one. Returns the port and an unlisten. */
|
|
64
64
|
listen(port: number, handler: HttpHandler): {
|
|
65
65
|
port: number;
|
|
@@ -69,7 +69,7 @@ export interface System {
|
|
|
69
69
|
loopback(port: number, request: HttpRequestData): Promise<HttpResponseData | undefined>;
|
|
70
70
|
/** Where a browser reaches a server on `port` (the preview URL), if known. */
|
|
71
71
|
serverUrl(port: number): string | undefined;
|
|
72
|
-
/** Tell the host a server is
|
|
72
|
+
/** Tell the host a server is reachable without opening a port; used by the dev-server handoff. */
|
|
73
73
|
announceServer(port: number, url: string): void;
|
|
74
74
|
/** The in-browser dev server's preview URL, for `vite`/`react-scripts start` handoff. */
|
|
75
75
|
previewUrl?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/system/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAE7D,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IACrE,kFAAkF;IAClF,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAAC;IACzC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAAC;IACzC,+FAA+F;IAC/F,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAC9D,sDAAsD;IACtD,QAAQ,CAAC,EAAE,YAAY,CAAC;CACzB;AAED,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/system/types.ts"],"names":[],"mappings":"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"}
|
package/dist/vfs.d.ts
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
export type FileContent = string | Uint8Array;
|
|
2
|
-
/**
|
|
3
|
-
export interface FileSystemTree {
|
|
4
|
-
[name: string]: {
|
|
5
|
-
file: {
|
|
6
|
-
contents: FileContent;
|
|
7
|
-
};
|
|
8
|
-
} | {
|
|
9
|
-
directory: FileSystemTree;
|
|
10
|
-
};
|
|
11
|
-
}
|
|
12
|
-
/** A flat `{ 'src/main.tsx': '...' }` map, the other shape callers commonly hold. */
|
|
2
|
+
/** A flat `{ 'src/main.tsx': '...' }` map: path → contents. */
|
|
13
3
|
export type FlatFiles = Record<string, FileContent>;
|
|
4
|
+
/**
|
|
5
|
+
* Files to write: a name maps to contents (a file) or to another tree (a
|
|
6
|
+
* directory). Names may hold slashes, so a {@link FlatFiles} map is a tree too,
|
|
7
|
+
* and the two styles mix freely: `{ src: { 'main.tsx': '…' }, 'public/a.svg': '…' }`.
|
|
8
|
+
*/
|
|
9
|
+
export interface FileTree {
|
|
10
|
+
[name: string]: FileContent | FileTree;
|
|
11
|
+
}
|
|
12
|
+
export interface DirectoryEntry {
|
|
13
|
+
name: string;
|
|
14
|
+
kind: 'file' | 'directory';
|
|
15
|
+
}
|
|
14
16
|
export interface FsChange {
|
|
15
17
|
/** `mkdir` is an explicitly created (possibly empty) directory. */
|
|
16
18
|
type: 'write' | 'remove' | 'mkdir';
|
|
@@ -51,6 +53,14 @@ export declare class VirtualFileSystem {
|
|
|
51
53
|
mkdir(path: string): void;
|
|
52
54
|
/** Direct children of a directory (files and sub-directories), sorted. */
|
|
53
55
|
readdir(path: string): string[];
|
|
56
|
+
/** Direct children with their kind, sorted by name — `readdir` for callers that render a tree. */
|
|
57
|
+
entries(path: string): DirectoryEntry[];
|
|
58
|
+
/**
|
|
59
|
+
* Move a file or a directory (with everything under it). Throws when `from` is
|
|
60
|
+
* missing or `to` already exists. Watchers see the old paths removed and the
|
|
61
|
+
* new ones written, which is what every consumer (dev server, process sync) needs.
|
|
62
|
+
*/
|
|
63
|
+
rename(from: string, to: string): void;
|
|
54
64
|
/** Every file path, sorted. */
|
|
55
65
|
list(): string[];
|
|
56
66
|
/** Directories created explicitly with `mkdir` — what `list()` cannot reproduce. */
|
|
@@ -61,14 +71,14 @@ export declare class VirtualFileSystem {
|
|
|
61
71
|
version(path: string): number | undefined;
|
|
62
72
|
/** When the file was last written (epoch ms), or undefined when absent. */
|
|
63
73
|
mtime(path: string): number | undefined;
|
|
64
|
-
/**
|
|
65
|
-
|
|
66
|
-
* path→contents map — or a mix, since each entry is judged on its own.
|
|
67
|
-
*/
|
|
68
|
-
mount(files: FileSystemTree | FlatFiles, at?: string): void;
|
|
74
|
+
/** Write many files at once, under `at` (default `/`). A nested object is a directory, created even when empty. */
|
|
75
|
+
writeTree(files: FileTree, at?: string): void;
|
|
69
76
|
/** Flat snapshot keyed without the leading slash (`src/main.tsx`). */
|
|
70
77
|
toFlat(): FlatFiles;
|
|
71
|
-
|
|
78
|
+
/** Every change, or with `under` only changes at or below that path. */
|
|
79
|
+
watch(listener: (change: FsChange) => void, options?: {
|
|
80
|
+
under?: string;
|
|
81
|
+
}): () => void;
|
|
72
82
|
private removeFile;
|
|
73
83
|
/** Register `key` under its parent, creating implicit ancestors as needed. */
|
|
74
84
|
private link;
|
package/dist/vfs.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vfs.d.ts","sourceRoot":"","sources":["../src/vfs.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,UAAU,CAAC;AAE9C
|
|
1
|
+
{"version":3,"file":"vfs.d.ts","sourceRoot":"","sources":["../src/vfs.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,UAAU,CAAC;AAE9C,+DAA+D;AAC/D,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AAEpD;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAC;CACxC;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;CAC5B;AAED,MAAM,WAAW,QAAQ;IACvB,mEAAmE;IACnE,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,6FAA6F;IAC7F,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAID;;;;;;;;;;;;GAYG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkC;IACxD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA6B;IACtD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6B;IACpD,kEAAkE;IAClE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoD;IAC7E,sEAAsE;IACtE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAC9C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAyC;IACnE,OAAO,CAAC,KAAK,CAAK;IAElB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,GAAG,IAAI;IAWpD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAI/C,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAM1C,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI7B,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIlC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI7B,4EAA4E;IAC5E,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAWzB,0EAA0E;IAC1E,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE;IAI/B,kGAAkG;IAClG,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,EAAE;IAKvC;;;;OAIG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAsBtC,+BAA+B;IAC/B,IAAI,IAAI,MAAM,EAAE;IAIhB,oFAAoF;IACpF,mBAAmB,IAAI,MAAM,EAAE;IAI/B,6DAA6D;IAC7D,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IActB,4EAA4E;IAC5E,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIzC,2EAA2E;IAC3E,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIvC,mHAAmH;IACnH,SAAS,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,SAAM,GAAG,IAAI;IAW1C,sEAAsE;IACtE,MAAM,IAAI,SAAS;IAMnB,wEAAwE;IACxE,KAAK,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,QAAQ,KAAK,IAAI,EAAE,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,MAAM,IAAI;IASzF,OAAO,CAAC,UAAU;IAQlB,8EAA8E;IAC9E,OAAO,CAAC,IAAI;IAMZ,OAAO,CAAC,SAAS;IAOjB,2EAA2E;IAC3E,OAAO,CAAC,MAAM;IAQd,OAAO,CAAC,SAAS;IAKjB,OAAO,CAAC,IAAI;CAGb"}
|
package/dist/vfs.js
CHANGED
|
@@ -71,6 +71,43 @@ export class VirtualFileSystem {
|
|
|
71
71
|
readdir(path) {
|
|
72
72
|
return [...(this.children.get(normalizePath(path)) ?? [])].sort();
|
|
73
73
|
}
|
|
74
|
+
/** Direct children with their kind, sorted by name — `readdir` for callers that render a tree. */
|
|
75
|
+
entries(path) {
|
|
76
|
+
const dir = normalizePath(path);
|
|
77
|
+
return this.readdir(dir).map((name) => ({ name, kind: this.children.has(join(dir, name)) ? 'directory' : 'file' }));
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Move a file or a directory (with everything under it). Throws when `from` is
|
|
81
|
+
* missing or `to` already exists. Watchers see the old paths removed and the
|
|
82
|
+
* new ones written, which is what every consumer (dev server, process sync) needs.
|
|
83
|
+
*/
|
|
84
|
+
rename(from, to) {
|
|
85
|
+
const source = normalizePath(from);
|
|
86
|
+
const target = normalizePath(to);
|
|
87
|
+
if (source === target)
|
|
88
|
+
return;
|
|
89
|
+
if (!this.exists(source))
|
|
90
|
+
throw new Error(`ENOENT: no such file or directory, rename '${source}' -> '${target}'`);
|
|
91
|
+
if (this.exists(target))
|
|
92
|
+
throw new Error(`EEXIST: file already exists, rename '${source}' -> '${target}'`);
|
|
93
|
+
if (target.startsWith(source + '/'))
|
|
94
|
+
throw new Error(`EINVAL: cannot move '${source}' into itself`);
|
|
95
|
+
if (this.files.has(source)) {
|
|
96
|
+
const contents = this.files.get(source);
|
|
97
|
+
this.removeFile(source);
|
|
98
|
+
this.writeFile(target, contents);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const prefix = source + '/';
|
|
102
|
+
const moved = [...this.files].filter(([path]) => path.startsWith(prefix));
|
|
103
|
+
const dirs = [...this.explicit].filter((dir) => dir === source || dir.startsWith(prefix));
|
|
104
|
+
this.rm(source);
|
|
105
|
+
this.mkdir(target);
|
|
106
|
+
for (const dir of dirs)
|
|
107
|
+
this.mkdir(target + dir.slice(source.length));
|
|
108
|
+
for (const [path, contents] of moved)
|
|
109
|
+
this.writeFile(target + path.slice(source.length), contents);
|
|
110
|
+
}
|
|
74
111
|
/** Every file path, sorted. */
|
|
75
112
|
list() {
|
|
76
113
|
return [...this.files.keys()].sort();
|
|
@@ -106,20 +143,15 @@ export class VirtualFileSystem {
|
|
|
106
143
|
mtime(path) {
|
|
107
144
|
return this.mtimes.get(normalizePath(path));
|
|
108
145
|
}
|
|
109
|
-
/**
|
|
110
|
-
|
|
111
|
-
* path→contents map — or a mix, since each entry is judged on its own.
|
|
112
|
-
*/
|
|
113
|
-
mount(files, at = '/') {
|
|
146
|
+
/** Write many files at once, under `at` (default `/`). A nested object is a directory, created even when empty. */
|
|
147
|
+
writeTree(files, at = '/') {
|
|
114
148
|
for (const [name, entry] of Object.entries(files)) {
|
|
115
149
|
const path = join(at, name);
|
|
116
150
|
if (typeof entry === 'string' || entry instanceof Uint8Array)
|
|
117
151
|
this.writeFile(path, entry);
|
|
118
|
-
else if ('file' in entry)
|
|
119
|
-
this.writeFile(path, entry.file.contents);
|
|
120
152
|
else {
|
|
121
153
|
this.mkdir(path);
|
|
122
|
-
this.
|
|
154
|
+
this.writeTree(entry, path);
|
|
123
155
|
}
|
|
124
156
|
}
|
|
125
157
|
}
|
|
@@ -130,9 +162,14 @@ export class VirtualFileSystem {
|
|
|
130
162
|
out[path.slice(1)] = contents;
|
|
131
163
|
return out;
|
|
132
164
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
165
|
+
/** Every change, or with `under` only changes at or below that path. */
|
|
166
|
+
watch(listener, options = {}) {
|
|
167
|
+
const root = options.under === undefined ? undefined : normalizePath(options.under);
|
|
168
|
+
const filtered = root === undefined || root === '/'
|
|
169
|
+
? listener
|
|
170
|
+
: (change) => (change.path === root || change.path.startsWith(root + '/')) && listener(change);
|
|
171
|
+
this.listeners.add(filtered);
|
|
172
|
+
return () => this.listeners.delete(filtered);
|
|
136
173
|
}
|
|
137
174
|
removeFile(key) {
|
|
138
175
|
this.files.delete(key);
|
package/dist/vfs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vfs.js","sourceRoot":"","sources":["../src/vfs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"vfs.js","sourceRoot":"","sources":["../src/vfs.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seanhogg/builderforce-webcontainers-core",
|
|
3
|
-
"version": "2026.10.
|
|
3
|
+
"version": "2026.10.7",
|
|
4
4
|
"description": "BuilderForce WebContainers — core. A runtime-agnostic in-browser dev server: virtual file system, module resolution, import rewriting to a package CDN, CSS/JSON/asset modules and project detection. No COOP/COEP required.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.js",
|
package/src/archive.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The file system as a zip: one format for "Download project" and for a
|
|
3
|
+
* snapshot a host stores and restores later (with `node_modules`, so a
|
|
4
|
+
* restored project needs no reinstall). Empty directories created with `mkdir`
|
|
5
|
+
* travel as `name/` entries; text comes back as strings, everything else as bytes.
|
|
6
|
+
*/
|
|
7
|
+
import { unzipSync, zipSync, type Zippable } from 'fflate';
|
|
8
|
+
import { VirtualFileSystem } from './vfs.js';
|
|
9
|
+
import { join } from './paths.js';
|
|
10
|
+
|
|
11
|
+
export interface ZipExportOptions {
|
|
12
|
+
/** Path prefixes left out (`node_modules`, `dist`), relative to the root, no leading slash. */
|
|
13
|
+
exclude?: string[];
|
|
14
|
+
/** 0 (store, fastest) to 9. Default 6. */
|
|
15
|
+
level?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const encoder = new TextEncoder();
|
|
19
|
+
const strictUtf8 = new TextDecoder('utf-8', { fatal: true });
|
|
20
|
+
|
|
21
|
+
function excluded(relative: string, exclude: string[]): boolean {
|
|
22
|
+
return exclude.some((prefix) => {
|
|
23
|
+
const clean = prefix.replace(/^\/+|\/+$/g, '');
|
|
24
|
+
return relative === clean || relative.startsWith(clean + '/');
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function exportZip(fs: VirtualFileSystem, options: ZipExportOptions = {}): Uint8Array {
|
|
29
|
+
const exclude = options.exclude ?? [];
|
|
30
|
+
const entries: Zippable = {};
|
|
31
|
+
for (const dir of fs.explicitDirectories()) {
|
|
32
|
+
const relative = dir.slice(1);
|
|
33
|
+
if (!excluded(relative, exclude) && fs.readdir(dir).length === 0) entries[relative + '/'] = new Uint8Array(0);
|
|
34
|
+
}
|
|
35
|
+
for (const path of fs.list()) {
|
|
36
|
+
const relative = path.slice(1);
|
|
37
|
+
if (excluded(relative, exclude)) continue;
|
|
38
|
+
const contents = fs.readFile(path)!;
|
|
39
|
+
entries[relative] = typeof contents === 'string' ? encoder.encode(contents) : contents;
|
|
40
|
+
}
|
|
41
|
+
return zipSync(entries, { level: options.level ?? 6 });
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Write a zip's contents into `fs` under `at` (default `/`), over whatever is there. */
|
|
45
|
+
export function importZip(fs: VirtualFileSystem, zip: Uint8Array, at = '/'): void {
|
|
46
|
+
for (const [name, bytes] of Object.entries(unzipSync(zip))) {
|
|
47
|
+
if (name.endsWith('/')) {
|
|
48
|
+
fs.mkdir(join(at, name.slice(0, -1)));
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
let contents: string | Uint8Array = bytes;
|
|
52
|
+
try {
|
|
53
|
+
contents = strictUtf8.decode(bytes);
|
|
54
|
+
} catch {
|
|
55
|
+
// binary: keep the bytes
|
|
56
|
+
}
|
|
57
|
+
fs.writeFile(join(at, name), contents);
|
|
58
|
+
}
|
|
59
|
+
}
|
package/src/build.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { VirtualFileSystem, type
|
|
1
|
+
import { VirtualFileSystem, type FileTree } from './vfs.js';
|
|
2
2
|
import type { Bundler, BundleOutput } from './bundler.js';
|
|
3
3
|
import type { PackageCdnFactory } from './packageCdn.js';
|
|
4
4
|
import { esmShCdnFactory } from './packageCdn.js';
|
|
@@ -18,8 +18,8 @@ import { findHtmlEntries, rewriteBuiltHtml } from './buildHtml.js';
|
|
|
18
18
|
* content hash in its name and can be cached forever.
|
|
19
19
|
*/
|
|
20
20
|
export interface BuildOptions {
|
|
21
|
-
/** The project: a file system, or files as `
|
|
22
|
-
files: VirtualFileSystem |
|
|
21
|
+
/** The project: a file system, or files as `writeTree()` takes them. */
|
|
22
|
+
files: VirtualFileSystem | FileTree;
|
|
23
23
|
bundler: Bundler;
|
|
24
24
|
/** Package CDN factory (called with `dev: false`). Default: esm.sh. */
|
|
25
25
|
cdn?: PackageCdnFactory;
|
|
@@ -50,7 +50,7 @@ const encoder = new TextEncoder();
|
|
|
50
50
|
function toFileSystem(files: BuildOptions['files']): VirtualFileSystem {
|
|
51
51
|
if (files instanceof VirtualFileSystem) return files;
|
|
52
52
|
const fs = new VirtualFileSystem();
|
|
53
|
-
fs.
|
|
53
|
+
fs.writeTree(files);
|
|
54
54
|
return fs;
|
|
55
55
|
}
|
|
56
56
|
|
package/src/check/typecheck.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type * as TS from 'typescript';
|
|
2
|
-
import { VirtualFileSystem, type
|
|
2
|
+
import { VirtualFileSystem, type FileTree } from '../vfs.js';
|
|
3
3
|
import { readProjectConfig } from '../projectConfig.js';
|
|
4
4
|
import { isBareSpecifier, resolveAlias, splitPackageSpecifier } from '../resolve.js';
|
|
5
5
|
import { acquireExtendedConfigs, acquireTypes, type FetchLike } from './acquire.js';
|
|
@@ -46,10 +46,10 @@ interface Reach {
|
|
|
46
46
|
libFiles: Set<string>;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
function toFileSystem(files: VirtualFileSystem |
|
|
49
|
+
function toFileSystem(files: VirtualFileSystem | FileTree): VirtualFileSystem {
|
|
50
50
|
if (files instanceof VirtualFileSystem) return files;
|
|
51
51
|
const fs = new VirtualFileSystem();
|
|
52
|
-
fs.
|
|
52
|
+
fs.writeTree(files);
|
|
53
53
|
return fs;
|
|
54
54
|
}
|
|
55
55
|
|
|
@@ -78,7 +78,7 @@ function collectReach(ts: typeof TS, fs: VirtualFileSystem, projects: CheckProje
|
|
|
78
78
|
|
|
79
79
|
export async function typecheckProject(
|
|
80
80
|
ts: typeof TS,
|
|
81
|
-
files: VirtualFileSystem |
|
|
81
|
+
files: VirtualFileSystem | FileTree,
|
|
82
82
|
options: TypecheckOptions,
|
|
83
83
|
): Promise<TypecheckResult> {
|
|
84
84
|
const fs = toFileSystem(files);
|
package/src/devServer.ts
CHANGED
|
@@ -30,6 +30,8 @@ export interface DevServerOptions {
|
|
|
30
30
|
components?: ComponentCompilers;
|
|
31
31
|
/** The "Built with Builderforce.ai" badge in served pages. Default true. */
|
|
32
32
|
attribution?: boolean;
|
|
33
|
+
/** Host scripts (JavaScript source) run in every preview page before the app. */
|
|
34
|
+
previewScripts?: readonly string[];
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
const NO_STORE = { 'cache-control': 'no-store' };
|
|
@@ -81,9 +83,11 @@ export class DevServer {
|
|
|
81
83
|
private profileCache?: ProjectProfile;
|
|
82
84
|
private readonly cache = new Map<string, { version: number; file: ServedFile }>();
|
|
83
85
|
private readonly unwatch: () => void;
|
|
86
|
+
private previewScripts: readonly string[];
|
|
84
87
|
|
|
85
88
|
constructor(private readonly options: DevServerOptions) {
|
|
86
89
|
if (!options.base.endsWith('/')) throw new Error('DevServer base must end with "/"');
|
|
90
|
+
this.previewScripts = options.previewScripts ?? [];
|
|
87
91
|
this.unwatch = options.fs.watch((change) => this.onChange(change));
|
|
88
92
|
}
|
|
89
93
|
|
|
@@ -92,6 +96,12 @@ export class DevServer {
|
|
|
92
96
|
this.cache.clear();
|
|
93
97
|
}
|
|
94
98
|
|
|
99
|
+
/** Replace the host scripts injected into preview pages; takes effect on the next page load. */
|
|
100
|
+
setPreviewScripts(scripts: readonly string[]): void {
|
|
101
|
+
this.previewScripts = [...scripts];
|
|
102
|
+
for (const key of [...this.cache.keys()]) if (/\.html?\?/.test(key)) this.cache.delete(key);
|
|
103
|
+
}
|
|
104
|
+
|
|
95
105
|
profile(): ProjectProfile {
|
|
96
106
|
return (this.profileCache ??= detectProject(this.options.fs));
|
|
97
107
|
}
|
|
@@ -136,7 +146,7 @@ export class DevServer {
|
|
|
136
146
|
if (loaderFor(ext)) return reply(200, JS_MIME, await compileScript(await this.context(), file));
|
|
137
147
|
if (isScriptPath(file)) return reply(200, JS_MIME, await compileComponent(await this.context(), file));
|
|
138
148
|
if (ext === '.html' || ext === '.htm') {
|
|
139
|
-
return reply(200, mimeFor(ext), transformHtml(fs.readText(file) ?? '', { base, attribution: this.options.attribution }));
|
|
149
|
+
return reply(200, mimeFor(ext), transformHtml(fs.readText(file) ?? '', { base, attribution: this.options.attribution, scripts: this.previewScripts }));
|
|
140
150
|
}
|
|
141
151
|
return reply(200, mimeFor(ext), fs.readFile(file) ?? '');
|
|
142
152
|
} catch (error) {
|
|
@@ -151,7 +161,7 @@ export class DevServer {
|
|
|
151
161
|
}
|
|
152
162
|
const html = this.options.fs.readText(profile.htmlPath) ?? '';
|
|
153
163
|
const { base, attribution } = this.options;
|
|
154
|
-
return reply(200, 'text/html; charset=utf-8', transformHtml(html, { base, entry: profile.entry, attribution }));
|
|
164
|
+
return reply(200, 'text/html; charset=utf-8', transformHtml(html, { base, entry: profile.entry, attribution, scripts: this.previewScripts }));
|
|
155
165
|
}
|
|
156
166
|
|
|
157
167
|
private async context(): Promise<CompileContext> {
|
package/src/html.ts
CHANGED
|
@@ -4,18 +4,24 @@
|
|
|
4
4
|
* base, since the preview is served from a sub-path, not the origin root;
|
|
5
5
|
* • CRA's `%PUBLIC_URL%` placeholder is filled;
|
|
6
6
|
* • a page with no module script (CRA) gets its entry injected;
|
|
7
|
-
* • the error bridge is prepended, so runtime errors reach the host;
|
|
7
|
+
* • the error bridge is prepended, so runtime errors and console output reach the host;
|
|
8
|
+
* • the host's preview scripts run next, before the app;
|
|
8
9
|
* • the live-reload listener is prepended, so an edit re-renders the preview;
|
|
9
10
|
* • the attribution badge is appended unless the host turned it off.
|
|
10
11
|
*/
|
|
11
12
|
import { injectAttribution } from './attribution.js';
|
|
12
13
|
|
|
13
14
|
export const ERROR_MESSAGE_TYPE = 'bfwc:error';
|
|
15
|
+
export const CONSOLE_MESSAGE_TYPE = 'bfwc:console';
|
|
16
|
+
/** Console messages forwarded per page load; past this the bridge goes quiet (a log loop must not flood the host). */
|
|
17
|
+
export const CONSOLE_MESSAGE_LIMIT = 1000;
|
|
14
18
|
|
|
15
19
|
/**
|
|
16
|
-
* Runs first in the preview. Forwards uncaught errors and rejections
|
|
17
|
-
* page (`window.parent`)
|
|
18
|
-
*
|
|
20
|
+
* Runs first in the preview. Forwards uncaught errors and rejections, and the
|
|
21
|
+
* app's console output, to the host page (`window.parent`): how an editor — or
|
|
22
|
+
* an agent — learns what the app did without scraping the iframe. Console
|
|
23
|
+
* arguments are flattened to text (errors with their stack, objects as JSON),
|
|
24
|
+
* each message capped at 4,000 characters.
|
|
19
25
|
*/
|
|
20
26
|
export function errorBridgeScript(): string {
|
|
21
27
|
return `<script>(function(){
|
|
@@ -24,6 +30,22 @@ export function errorBridgeScript(): string {
|
|
|
24
30
|
};
|
|
25
31
|
addEventListener('error', function (e) { send(e.message, e.error && e.error.stack); });
|
|
26
32
|
addEventListener('unhandledrejection', function (e) { var r = e.reason; send(r && r.message ? r.message : r, r && r.stack); });
|
|
33
|
+
var sent = 0;
|
|
34
|
+
var text = function (value) {
|
|
35
|
+
if (typeof value === 'string') return value;
|
|
36
|
+
if (value instanceof Error) return value.stack || String(value);
|
|
37
|
+
try { var json = JSON.stringify(value); return json === undefined ? String(value) : json; } catch (_) { return String(value); }
|
|
38
|
+
};
|
|
39
|
+
['log', 'info', 'warn', 'error', 'debug'].forEach(function (level) {
|
|
40
|
+
var original = console[level];
|
|
41
|
+
console[level] = function () {
|
|
42
|
+
if (sent < ${CONSOLE_MESSAGE_LIMIT}) {
|
|
43
|
+
sent++;
|
|
44
|
+
try { parent.postMessage({ type: ${JSON.stringify(CONSOLE_MESSAGE_TYPE)}, level: level, text: Array.prototype.map.call(arguments, text).join(' ').slice(0, 4000), href: location.href }, '*'); } catch (_) {}
|
|
45
|
+
}
|
|
46
|
+
return original.apply(console, arguments);
|
|
47
|
+
};
|
|
48
|
+
});
|
|
27
49
|
window.process = window.process || { env: { NODE_ENV: 'development' } };
|
|
28
50
|
})();</script>`;
|
|
29
51
|
}
|
|
@@ -55,8 +77,13 @@ export interface HtmlOptions {
|
|
|
55
77
|
entry?: string;
|
|
56
78
|
/** The "Built with Builderforce.ai" badge. On unless explicitly `false`. */
|
|
57
79
|
attribution?: boolean;
|
|
80
|
+
/** Host scripts (JavaScript source) run in every preview page before the app. */
|
|
81
|
+
scripts?: readonly string[];
|
|
58
82
|
}
|
|
59
83
|
|
|
84
|
+
/** `</script>` inside a script body would end the tag early. */
|
|
85
|
+
const scriptTag = (source: string) => `<script>${source.replace(/<\/script/gi, '<\\/script')}</script>`;
|
|
86
|
+
|
|
60
87
|
export function transformHtml(html: string, options: HtmlOptions): string {
|
|
61
88
|
const { base } = options;
|
|
62
89
|
// `%PUBLIC_URL%/logo.png` becomes root-absolute here and is re-rooted once below;
|
|
@@ -70,7 +97,7 @@ export function transformHtml(html: string, options: HtmlOptions): string {
|
|
|
70
97
|
}
|
|
71
98
|
if (options.attribution !== false) out = injectAttribution(out);
|
|
72
99
|
|
|
73
|
-
const bridge =
|
|
100
|
+
const bridge = [errorBridgeScript(), liveReloadScript(base), ...(options.scripts ?? []).map(scriptTag)].join('\n');
|
|
74
101
|
if (/<head[^>]*>/i.test(out)) return out.replace(/<head[^>]*>/i, (head) => `${head}\n${bridge}`);
|
|
75
102
|
return bridge + out;
|
|
76
103
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
export { VirtualFileSystem } from './vfs.js';
|
|
2
|
-
export type { FileContent,
|
|
2
|
+
export type { FileContent, FileTree, FlatFiles, FsChange } from './vfs.js';
|
|
3
|
+
export type { DirectoryEntry } from './vfs.js';
|
|
4
|
+
export { exportZip, importZip } from './archive.js';
|
|
5
|
+
export type { ZipExportOptions } from './archive.js';
|
|
3
6
|
export { normalizePath, dirname, basename, join, extname } from './paths.js';
|
|
4
7
|
export { DevServer } from './devServer.js';
|
|
5
8
|
export type { DevServerOptions, ServedFile } from './devServer.js';
|
|
@@ -41,7 +44,7 @@ export { rewriteImports } from './rewriteImports.js';
|
|
|
41
44
|
export { resolveLocal, resolveAlias, isBareSpecifier, splitPackageSpecifier, resolvePackage, RESOLVE_EXTENSIONS } from './resolve.js';
|
|
42
45
|
export { compileScript, compileModule, isScriptPath, mapSpecifier, moduleUrl, buildDefine } from './compileScript.js';
|
|
43
46
|
export { compileComponent } from './compileComponent.js';
|
|
44
|
-
export { transformHtml, errorBridgeScript, liveReloadScript, reloadChannelName, ERROR_MESSAGE_TYPE } from './html.js';
|
|
47
|
+
export { transformHtml, errorBridgeScript, liveReloadScript, reloadChannelName, ERROR_MESSAGE_TYPE, CONSOLE_MESSAGE_TYPE, CONSOLE_MESSAGE_LIMIT } from './html.js';
|
|
45
48
|
export { mimeFor } from './mime.js';
|
|
46
49
|
export { attributionScript, injectAttribution, ATTRIBUTION_URL, ATTRIBUTION_LABEL } from './attribution.js';
|
|
47
50
|
export type { AttributionOptions } from './attribution.js';
|
package/src/installer/index.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { installPackages, chooseVersion } from './install.js';
|
|
2
2
|
export type { InstallOptions, InstallResult, InstallProgress } from './install.js';
|
|
3
|
+
export { parseNpmrc, readNpmConfig, registryFor, authHeaders, emptyNpmConfig } from './npmrc.js';
|
|
4
|
+
export type { NpmConfig } from './npmrc.js';
|
|
3
5
|
export { RegistryClient, createMemoryCache, verifyIntegrity, DEFAULT_REGISTRY } from './registry.js';
|
|
4
6
|
export type { FetchLike, PackageCache, PackageManifest, Packument, RegistryOptions, BinField } from './registry.js';
|
|
5
7
|
export { resolveTree, childLocation, parentLocation, PLATFORM } from './tree.js';
|
package/src/installer/install.ts
CHANGED
|
@@ -13,6 +13,7 @@ import { gunzipSync } from 'fflate';
|
|
|
13
13
|
import type { VirtualFileSystem } from '../vfs.js';
|
|
14
14
|
import { join } from '../paths.js';
|
|
15
15
|
import { RegistryClient, type FetchLike, type PackageCache, type PackageManifest, type Packument } from './registry.js';
|
|
16
|
+
import type { NpmConfig } from './npmrc.js';
|
|
16
17
|
import { parseInstallSpec, sortObject, type PackageJson, type ParsedSpec } from './spec.js';
|
|
17
18
|
import { childLocation, parentLocation, resolveTree, type ResolvedPackage } from './tree.js';
|
|
18
19
|
import { buildLockfile, lockMatchesPackage, lockedManifests, parseLockfile, pickLocked, type Lockfile } from './lockfile.js';
|
|
@@ -32,6 +33,8 @@ export interface InstallOptions {
|
|
|
32
33
|
fs: VirtualFileSystem;
|
|
33
34
|
fetch: FetchLike;
|
|
34
35
|
registry?: string;
|
|
36
|
+
/** `.npmrc` settings: scoped registries and auth tokens. */
|
|
37
|
+
npmrc?: NpmConfig;
|
|
35
38
|
cache?: PackageCache;
|
|
36
39
|
/** The project directory holding package.json. Default `/`. */
|
|
37
40
|
cwd?: string;
|
|
@@ -158,7 +161,7 @@ export async function installPackages(options: InstallOptions): Promise<InstallR
|
|
|
158
161
|
const pkgPath = join(base, 'package.json');
|
|
159
162
|
const lockPath = join(base, 'package-lock.json');
|
|
160
163
|
const warnings: string[] = [];
|
|
161
|
-
const client = new RegistryClient({ fetch: options.fetch, registry: options.registry, cache: options.cache, signal });
|
|
164
|
+
const client = new RegistryClient({ fetch: options.fetch, registry: options.registry ?? options.npmrc?.registry, npmrc: options.npmrc, cache: options.cache, signal });
|
|
162
165
|
const progress = (p: InstallProgress) => options.onProgress?.(p);
|
|
163
166
|
|
|
164
167
|
let pkg = readJson<PackageJson>(fs, pkgPath);
|