@bytecodealliance/preview2-shim 0.18.1 → 0.20.0
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 +15 -15
- package/dist/browser/cli.d.ts +16 -0
- package/dist/browser/cli.js +109 -0
- package/dist/browser/clocks.d.ts +3 -0
- package/dist/browser/clocks.js +36 -0
- package/dist/browser/config.d.ts +2 -0
- package/{lib → dist}/browser/config.js +2 -4
- package/dist/browser/environment.d.ts +5 -0
- package/dist/browser/environment.js +24 -0
- package/dist/browser/filesystem.d.ts +132 -0
- package/dist/browser/filesystem.js +488 -0
- package/dist/browser/http.d.ts +4 -0
- package/dist/browser/http.js +643 -0
- package/dist/browser/index.d.ts +7 -0
- package/dist/browser/index.js +7 -0
- package/dist/browser/io.d.ts +58 -0
- package/dist/browser/io.js +205 -0
- package/dist/browser/random.d.ts +4 -0
- package/dist/browser/random.js +49 -0
- package/dist/browser/sockets.d.ts +8 -0
- package/dist/browser/sockets.js +66 -0
- package/dist/common/instantiation.d.ts +97 -0
- package/dist/common/instantiation.js +228 -0
- package/dist/io/calls.d.ts +91 -0
- package/{lib → dist}/io/calls.js +4 -19
- package/dist/io/worker-http.d.ts +17 -0
- package/dist/io/worker-http.js +192 -0
- package/dist/io/worker-io.d.ts +84 -0
- package/dist/io/worker-io.js +381 -0
- package/dist/io/worker-socket-tcp.d.ts +34 -0
- package/dist/io/worker-socket-tcp.js +251 -0
- package/dist/io/worker-socket-udp.d.ts +54 -0
- package/dist/io/worker-socket-udp.js +493 -0
- package/dist/io/worker-sockets.d.ts +32 -0
- package/dist/io/worker-sockets.js +265 -0
- package/dist/io/worker-thread.d.ts +73 -0
- package/dist/io/worker-thread.js +794 -0
- package/dist/nodejs/cli.d.ts +30 -0
- package/dist/nodejs/cli.js +86 -0
- package/dist/nodejs/clocks.d.ts +3 -0
- package/dist/nodejs/clocks.js +61 -0
- package/dist/nodejs/filesystem.d.ts +113 -0
- package/dist/nodejs/filesystem.js +761 -0
- package/dist/nodejs/http.d.ts +82 -0
- package/dist/nodejs/http.js +674 -0
- package/dist/nodejs/index.d.ts +7 -0
- package/dist/nodejs/index.js +7 -0
- package/dist/nodejs/io.d.ts +1 -0
- package/dist/nodejs/io.js +1 -0
- package/dist/nodejs/random.d.ts +4 -0
- package/dist/nodejs/random.js +42 -0
- package/dist/nodejs/sockets.d.ts +21 -0
- package/dist/nodejs/sockets.js +482 -0
- package/dist/synckit/index.d.ts +2 -0
- package/dist/synckit/index.js +117 -0
- package/package.json +28 -15
- package/types/instantiation.d.ts +7 -7
- package/lib/browser/cli.js +0 -135
- package/lib/browser/clocks.js +0 -39
- package/lib/browser/environment.js +0 -29
- package/lib/browser/filesystem.js +0 -503
- package/lib/browser/http.js +0 -707
- package/lib/browser/index.js +0 -9
- package/lib/browser/io.js +0 -262
- package/lib/browser/random.js +0 -56
- package/lib/browser/sockets.js +0 -88
- package/lib/common/instantiation.js +0 -253
- package/lib/io/worker-http.js +0 -206
- package/lib/io/worker-io.js +0 -468
- package/lib/io/worker-socket-tcp.js +0 -331
- package/lib/io/worker-socket-udp.js +0 -587
- package/lib/io/worker-sockets.js +0 -364
- package/lib/io/worker-thread.js +0 -1051
- package/lib/nodejs/cli.js +0 -109
- package/lib/nodejs/clocks.js +0 -67
- package/lib/nodejs/filesystem.js +0 -829
- package/lib/nodejs/http.js +0 -764
- package/lib/nodejs/index.js +0 -9
- package/lib/nodejs/io.js +0 -1
- package/lib/nodejs/random.js +0 -49
- package/lib/nodejs/sockets.js +0 -565
- package/lib/synckit/index.js +0 -127
package/lib/browser/io.js
DELETED
|
@@ -1,262 +0,0 @@
|
|
|
1
|
-
let id = 0;
|
|
2
|
-
|
|
3
|
-
const symbolDispose = Symbol.dispose || Symbol.for("dispose");
|
|
4
|
-
|
|
5
|
-
const IoError = class Error {
|
|
6
|
-
constructor(msg) {
|
|
7
|
-
this.msg = msg;
|
|
8
|
-
}
|
|
9
|
-
toDebugString() {
|
|
10
|
-
return this.msg;
|
|
11
|
-
}
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* @typedef {{
|
|
16
|
-
* read?: (len: BigInt) => Uint8Array,
|
|
17
|
-
* blockingRead: (len: BigInt) => Uint8Array,
|
|
18
|
-
* skip?: (len: BigInt) => BigInt,
|
|
19
|
-
* blockingSkip?: (len: BigInt) => BigInt,
|
|
20
|
-
* subscribe: () => Pollable,
|
|
21
|
-
* drop?: () => void,
|
|
22
|
-
* }} InputStreamHandler
|
|
23
|
-
*
|
|
24
|
-
* @typedef {{
|
|
25
|
-
* checkWrite?: () -> BigInt,
|
|
26
|
-
* write: (buf: Uint8Array) => BigInt,
|
|
27
|
-
* blockingWriteAndFlush?: (buf: Uint8Array) => void,
|
|
28
|
-
* flush?: () => void,
|
|
29
|
-
* blockingFlush: () => void,
|
|
30
|
-
* writeZeroes?: (len: BigInt) => void,
|
|
31
|
-
* blockingWriteZeroes?: (len: BigInt) => void,
|
|
32
|
-
* blockingWriteZeroesAndFlush?: (len: BigInt) => void,
|
|
33
|
-
* splice?: (src: InputStream, len: BigInt) => BigInt,
|
|
34
|
-
* blockingSplice?: (src: InputStream, len: BigInt) => BigInt,
|
|
35
|
-
* forward?: (src: InputStream) => void,
|
|
36
|
-
* subscribe?: () => Pollable,
|
|
37
|
-
* drop?: () => void,
|
|
38
|
-
* }} OutputStreamHandler
|
|
39
|
-
*
|
|
40
|
-
**/
|
|
41
|
-
|
|
42
|
-
class InputStream {
|
|
43
|
-
/**
|
|
44
|
-
* @param {InputStreamHandler} handler
|
|
45
|
-
*/
|
|
46
|
-
constructor(handler) {
|
|
47
|
-
if (!handler) {
|
|
48
|
-
console.trace("no handler");
|
|
49
|
-
}
|
|
50
|
-
this.id = ++id;
|
|
51
|
-
this.handler = handler;
|
|
52
|
-
}
|
|
53
|
-
read(len) {
|
|
54
|
-
if (this.handler.read) {
|
|
55
|
-
return this.handler.read(len);
|
|
56
|
-
}
|
|
57
|
-
return this.handler.blockingRead.call(this, len);
|
|
58
|
-
}
|
|
59
|
-
blockingRead(len) {
|
|
60
|
-
return this.handler.blockingRead.call(this, len);
|
|
61
|
-
}
|
|
62
|
-
skip(len) {
|
|
63
|
-
if (this.handler.skip) {
|
|
64
|
-
return this.handler.skip.call(this, len);
|
|
65
|
-
}
|
|
66
|
-
if (this.handler.read) {
|
|
67
|
-
const bytes = this.handler.read.call(this, len);
|
|
68
|
-
return BigInt(bytes.byteLength);
|
|
69
|
-
}
|
|
70
|
-
return this.blockingSkip.call(this, len);
|
|
71
|
-
}
|
|
72
|
-
blockingSkip(len) {
|
|
73
|
-
if (this.handler.blockingSkip) {
|
|
74
|
-
return this.handler.blockingSkip.call(this, len);
|
|
75
|
-
}
|
|
76
|
-
const bytes = this.handler.blockingRead.call(this, len);
|
|
77
|
-
return BigInt(bytes.byteLength);
|
|
78
|
-
}
|
|
79
|
-
subscribe() {
|
|
80
|
-
if (this.handler.subscribe) {
|
|
81
|
-
return this.handler.subscribe();
|
|
82
|
-
}
|
|
83
|
-
return new Pollable();
|
|
84
|
-
}
|
|
85
|
-
[symbolDispose]() {
|
|
86
|
-
if (this.handler.drop) {
|
|
87
|
-
this.handler.drop.call(this);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
class OutputStream {
|
|
93
|
-
/**
|
|
94
|
-
* @param {OutputStreamHandler} handler
|
|
95
|
-
*/
|
|
96
|
-
constructor(handler) {
|
|
97
|
-
if (!handler) {
|
|
98
|
-
console.trace("no handler");
|
|
99
|
-
}
|
|
100
|
-
this.id = ++id;
|
|
101
|
-
this.open = true;
|
|
102
|
-
this.handler = handler;
|
|
103
|
-
}
|
|
104
|
-
checkWrite(len) {
|
|
105
|
-
if (!this.open) {
|
|
106
|
-
return 0n;
|
|
107
|
-
}
|
|
108
|
-
if (this.handler.checkWrite) {
|
|
109
|
-
return this.handler.checkWrite.call(this, len);
|
|
110
|
-
}
|
|
111
|
-
return 1_000_000n;
|
|
112
|
-
}
|
|
113
|
-
write(buf) {
|
|
114
|
-
this.handler.write.call(this, buf);
|
|
115
|
-
}
|
|
116
|
-
blockingWriteAndFlush(buf) {
|
|
117
|
-
/// Perform a write of up to 4096 bytes, and then flush the stream. Block
|
|
118
|
-
/// until all of these operations are complete, or an error occurs.
|
|
119
|
-
///
|
|
120
|
-
/// This is a convenience wrapper around the use of `check-write`,
|
|
121
|
-
/// `subscribe`, `write`, and `flush`, and is implemented with the
|
|
122
|
-
/// following pseudo-code:
|
|
123
|
-
///
|
|
124
|
-
/// ```text
|
|
125
|
-
/// let pollable = this.subscribe();
|
|
126
|
-
/// while !contents.is_empty() {
|
|
127
|
-
/// // Wait for the stream to become writable
|
|
128
|
-
/// poll-one(pollable);
|
|
129
|
-
/// let Ok(n) = this.check-write(); // eliding error handling
|
|
130
|
-
/// let len = min(n, contents.len());
|
|
131
|
-
/// let (chunk, rest) = contents.split_at(len);
|
|
132
|
-
/// this.write(chunk ); // eliding error handling
|
|
133
|
-
/// contents = rest;
|
|
134
|
-
/// }
|
|
135
|
-
/// this.flush();
|
|
136
|
-
/// // Wait for completion of `flush`
|
|
137
|
-
/// poll-one(pollable);
|
|
138
|
-
/// // Check for any errors that arose during `flush`
|
|
139
|
-
/// let _ = this.check-write(); // eliding error handling
|
|
140
|
-
/// ```
|
|
141
|
-
this.handler.write.call(this, buf);
|
|
142
|
-
}
|
|
143
|
-
flush() {
|
|
144
|
-
if (this.handler.flush) {
|
|
145
|
-
this.handler.flush.call(this);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
blockingFlush() {
|
|
149
|
-
this.open = true;
|
|
150
|
-
}
|
|
151
|
-
writeZeroes(len) {
|
|
152
|
-
this.write.call(this, new Uint8Array(Number(len)));
|
|
153
|
-
}
|
|
154
|
-
blockingWriteZeroes(len) {
|
|
155
|
-
this.blockingWrite.call(this, new Uint8Array(Number(len)));
|
|
156
|
-
}
|
|
157
|
-
blockingWriteZeroesAndFlush(len) {
|
|
158
|
-
this.blockingWriteAndFlush.call(this, new Uint8Array(Number(len)));
|
|
159
|
-
}
|
|
160
|
-
splice(src, len) {
|
|
161
|
-
const spliceLen = Math.min(len, this.checkWrite.call(this));
|
|
162
|
-
const bytes = src.read(spliceLen);
|
|
163
|
-
this.write.call(this, bytes);
|
|
164
|
-
return bytes.byteLength;
|
|
165
|
-
}
|
|
166
|
-
blockingSplice(_src, _len) {
|
|
167
|
-
console.log(`[streams] Blocking splice ${this.id}`);
|
|
168
|
-
}
|
|
169
|
-
forward(_src) {
|
|
170
|
-
console.log(`[streams] Forward ${this.id}`);
|
|
171
|
-
}
|
|
172
|
-
subscribe() {
|
|
173
|
-
if (this.handler.subscribe) {
|
|
174
|
-
return this.handler.subscribe();
|
|
175
|
-
}
|
|
176
|
-
return new Pollable();
|
|
177
|
-
}
|
|
178
|
-
[symbolDispose]() {}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
export const error = { Error: IoError };
|
|
182
|
-
|
|
183
|
-
export const streams = { InputStream, OutputStream };
|
|
184
|
-
|
|
185
|
-
class Pollable {
|
|
186
|
-
#ready = false;
|
|
187
|
-
#promise = null;
|
|
188
|
-
|
|
189
|
-
constructor(promise) {
|
|
190
|
-
if (!promise) {
|
|
191
|
-
this.#ready = true;
|
|
192
|
-
} else {
|
|
193
|
-
this.#promise = promise.then(
|
|
194
|
-
() => {
|
|
195
|
-
this.#ready = true;
|
|
196
|
-
},
|
|
197
|
-
() => {
|
|
198
|
-
this.#ready = true;
|
|
199
|
-
},
|
|
200
|
-
);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
ready() {
|
|
205
|
-
return this.#ready;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
block() {
|
|
209
|
-
if (this.#ready) {
|
|
210
|
-
return Promise.resolve();
|
|
211
|
-
}
|
|
212
|
-
return this.#promise;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
[symbolDispose]() {
|
|
216
|
-
this.#promise = null;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
function pollList(list) {
|
|
221
|
-
if (list.length === 0) {
|
|
222
|
-
throw new Error("poll list must not be empty");
|
|
223
|
-
}
|
|
224
|
-
if (list.length > 0xffffffff) {
|
|
225
|
-
throw new Error("poll list length exceeds u32 index range");
|
|
226
|
-
}
|
|
227
|
-
const ready = [];
|
|
228
|
-
for (let i = 0; i < list.length; i++) {
|
|
229
|
-
if (list[i].ready()) {
|
|
230
|
-
ready.push(i);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
if (ready.length > 0) {
|
|
234
|
-
return new Uint32Array(ready);
|
|
235
|
-
}
|
|
236
|
-
// None ready synchronously. Wait for the first to resolve via Promise.race,
|
|
237
|
-
// then sweep for any others that became ready concurrently.
|
|
238
|
-
return Promise.race(
|
|
239
|
-
list.map((p, i) =>
|
|
240
|
-
p.block().then(() => {
|
|
241
|
-
const result = [i];
|
|
242
|
-
for (let j = 0; j < list.length; j++) {
|
|
243
|
-
if (j !== i && list[j].ready()) {
|
|
244
|
-
result.push(j);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
return new Uint32Array(result);
|
|
248
|
-
}),
|
|
249
|
-
),
|
|
250
|
-
);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
function pollOne(poll) {
|
|
254
|
-
return poll.block();
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
export const poll = {
|
|
258
|
-
Pollable,
|
|
259
|
-
pollList,
|
|
260
|
-
pollOne,
|
|
261
|
-
poll: pollList,
|
|
262
|
-
};
|
package/lib/browser/random.js
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
const MAX_BYTES = 65536;
|
|
2
|
-
|
|
3
|
-
let insecureRandomValue1, insecureRandomValue2;
|
|
4
|
-
|
|
5
|
-
export const insecure = {
|
|
6
|
-
getInsecureRandomBytes(len) {
|
|
7
|
-
return random.getRandomBytes(len);
|
|
8
|
-
},
|
|
9
|
-
getInsecureRandomU64() {
|
|
10
|
-
return random.getRandomU64();
|
|
11
|
-
},
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
let insecureSeedValue1, insecureSeedValue2;
|
|
15
|
-
|
|
16
|
-
export const insecureSeed = {
|
|
17
|
-
insecureSeed() {
|
|
18
|
-
if (insecureSeedValue1 === undefined) {
|
|
19
|
-
insecureSeedValue1 = random.getRandomU64();
|
|
20
|
-
insecureSeedValue2 = random.getRandomU64();
|
|
21
|
-
}
|
|
22
|
-
return [insecureSeedValue1, insecureSeedValue2];
|
|
23
|
-
},
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
export const random = {
|
|
27
|
-
getRandomBytes(len) {
|
|
28
|
-
const bytes = new Uint8Array(Number(len));
|
|
29
|
-
|
|
30
|
-
if (len > MAX_BYTES) {
|
|
31
|
-
// this is the max bytes crypto.getRandomValues
|
|
32
|
-
// can do at once see https://developer.mozilla.org/en-US/docs/Web/API/window.crypto.getRandomValues
|
|
33
|
-
for (var generated = 0; generated < len; generated += MAX_BYTES) {
|
|
34
|
-
// buffer.slice automatically checks if the end is past the end of
|
|
35
|
-
// the buffer so we don't have to here
|
|
36
|
-
crypto.getRandomValues(bytes.subarray(generated, generated + MAX_BYTES));
|
|
37
|
-
}
|
|
38
|
-
} else {
|
|
39
|
-
crypto.getRandomValues(bytes);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return bytes;
|
|
43
|
-
},
|
|
44
|
-
|
|
45
|
-
getRandomU64() {
|
|
46
|
-
return crypto.getRandomValues(new BigUint64Array(1))[0];
|
|
47
|
-
},
|
|
48
|
-
|
|
49
|
-
insecureRandom() {
|
|
50
|
-
if (insecureRandomValue1 === undefined) {
|
|
51
|
-
insecureRandomValue1 = random.getRandomU64();
|
|
52
|
-
insecureRandomValue2 = random.getRandomU64();
|
|
53
|
-
}
|
|
54
|
-
return [insecureRandomValue1, insecureRandomValue2];
|
|
55
|
-
},
|
|
56
|
-
};
|
package/lib/browser/sockets.js
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
export const instanceNetwork = {
|
|
2
|
-
instanceNetwork() {
|
|
3
|
-
console.log(`[sockets] instance network`);
|
|
4
|
-
},
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
export const ipNameLookup = {
|
|
8
|
-
dropResolveAddressStream() {},
|
|
9
|
-
subscribe() {},
|
|
10
|
-
resolveAddresses() {},
|
|
11
|
-
resolveNextAddress() {},
|
|
12
|
-
nonBlocking() {},
|
|
13
|
-
setNonBlocking() {},
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export const network = {
|
|
17
|
-
dropNetwork() {},
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export const tcpCreateSocket = {
|
|
21
|
-
createTcpSocket() {},
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export const tcp = {
|
|
25
|
-
subscribe() {},
|
|
26
|
-
dropTcpSocket() {},
|
|
27
|
-
bind() {},
|
|
28
|
-
connect() {},
|
|
29
|
-
listen() {},
|
|
30
|
-
accept() {},
|
|
31
|
-
localAddress() {},
|
|
32
|
-
remoteAddress() {},
|
|
33
|
-
addressFamily() {},
|
|
34
|
-
setListenBacklogSize() {},
|
|
35
|
-
keepAlive() {},
|
|
36
|
-
setKeepAlive() {},
|
|
37
|
-
noDelay() {},
|
|
38
|
-
setNoDelay() {},
|
|
39
|
-
unicastHopLimit() {},
|
|
40
|
-
setUnicastHopLimit() {},
|
|
41
|
-
receiveBufferSize() {},
|
|
42
|
-
setReceiveBufferSize() {},
|
|
43
|
-
sendBufferSize() {},
|
|
44
|
-
setSendBufferSize() {},
|
|
45
|
-
nonBlocking() {},
|
|
46
|
-
setNonBlocking() {},
|
|
47
|
-
shutdown() {},
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
export const udp = {
|
|
51
|
-
subscribe() {},
|
|
52
|
-
|
|
53
|
-
dropUdpSocket() {},
|
|
54
|
-
|
|
55
|
-
bind() {},
|
|
56
|
-
|
|
57
|
-
connect() {},
|
|
58
|
-
|
|
59
|
-
receive() {},
|
|
60
|
-
|
|
61
|
-
send() {},
|
|
62
|
-
|
|
63
|
-
localAddress() {},
|
|
64
|
-
|
|
65
|
-
remoteAddress() {},
|
|
66
|
-
|
|
67
|
-
addressFamily() {},
|
|
68
|
-
|
|
69
|
-
unicastHopLimit() {},
|
|
70
|
-
|
|
71
|
-
setUnicastHopLimit() {},
|
|
72
|
-
|
|
73
|
-
receiveBufferSize() {},
|
|
74
|
-
|
|
75
|
-
setReceiveBufferSize() {},
|
|
76
|
-
|
|
77
|
-
sendBufferSize() {},
|
|
78
|
-
|
|
79
|
-
setSendBufferSize() {},
|
|
80
|
-
|
|
81
|
-
nonBlocking() {},
|
|
82
|
-
|
|
83
|
-
setNonBlocking() {},
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
export const udpCreateSocket = {
|
|
87
|
-
createUdpSocket() {},
|
|
88
|
-
};
|
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
import * as wasi from "@bytecodealliance/preview2-shim";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* (EXPERIMENTAL) A class that holds WASI shims and can be used to configure
|
|
5
|
-
* an instantiation of a WebAssembly component transpiled with jco
|
|
6
|
-
* (i.e. via `jco transpile`).
|
|
7
|
-
*
|
|
8
|
-
* Normally, transpiled components contain mapping for WASI interfaces
|
|
9
|
-
* and/or imports that import the relevant packages (ex. `@bytecodealliance/preview2-shim/clocks`)
|
|
10
|
-
* from the right sources.
|
|
11
|
-
*
|
|
12
|
-
* This function makes use of the `WASIShim` object to provide an object that can be easily
|
|
13
|
-
* fed to the `instantiate` function produced by a transpiled component:
|
|
14
|
-
*
|
|
15
|
-
* ```js
|
|
16
|
-
* import { WASIShim } from "@bytecodealliance/preview2-shim/instantiation"
|
|
17
|
-
* // ...
|
|
18
|
-
* import { instantiate } from "path/to/transpiled/component.js"
|
|
19
|
-
* // ...
|
|
20
|
-
* const component = await instantiate(null, new WASIShim().getImportObject())
|
|
21
|
-
* ```
|
|
22
|
-
*
|
|
23
|
-
* You can also replace imports that you'd like to override with custom implementations,
|
|
24
|
-
* by using the `WASIShim` object directly:
|
|
25
|
-
*
|
|
26
|
-
* ```js
|
|
27
|
-
* import { random } from "@bytecodealliance/preview2-shim"
|
|
28
|
-
* import { WASIShim } from "@bytecodealliance/preview2-shim/instantiation"
|
|
29
|
-
* // ...
|
|
30
|
-
* import { instantiate } from "path/to/transpiled/component.js"
|
|
31
|
-
* // ...
|
|
32
|
-
* const customWASIShim = new WASIShim({
|
|
33
|
-
* random: {
|
|
34
|
-
* // For these two interfaces we re-use the default provided shim
|
|
35
|
-
* random: random.random,
|
|
36
|
-
* insecure-seed: random.insecureSeed,
|
|
37
|
-
* // For insecure, we can supply our own custom implementation
|
|
38
|
-
* insecure: {
|
|
39
|
-
* ...
|
|
40
|
-
* }
|
|
41
|
-
* }
|
|
42
|
-
* });
|
|
43
|
-
*
|
|
44
|
-
* const component = await instantiate(null, customWASIShim.getImportObject())
|
|
45
|
-
* ```
|
|
46
|
-
*
|
|
47
|
-
* For sandboxing, you can configure preopens, environment variables, and other
|
|
48
|
-
* capabilities via the `sandbox` option:
|
|
49
|
-
*
|
|
50
|
-
* ```js
|
|
51
|
-
* import { WASIShim } from "@bytecodealliance/preview2-shim/instantiation"
|
|
52
|
-
*
|
|
53
|
-
* // Fully sandboxed - no filesystem, network, or env access
|
|
54
|
-
* const sandboxedShim = new WASIShim({
|
|
55
|
-
* sandbox: {
|
|
56
|
-
* preopens: {}, // No filesystem access
|
|
57
|
-
* env: {}, // No environment variables
|
|
58
|
-
* args: ['program'], // Custom arguments
|
|
59
|
-
* enableNetwork: false, // Disable network (default: true for backward compat)
|
|
60
|
-
* }
|
|
61
|
-
* });
|
|
62
|
-
*
|
|
63
|
-
* // Limited filesystem access
|
|
64
|
-
* const limitedShim = new WASIShim({
|
|
65
|
-
* sandbox: {
|
|
66
|
-
* preopens: {
|
|
67
|
-
* '/data': '/tmp/guest-data', // Guest sees /data, maps to /tmp/guest-data
|
|
68
|
-
* '/config': '/etc/app' // Guest sees /config, maps to /etc/app
|
|
69
|
-
* }
|
|
70
|
-
* }
|
|
71
|
-
* });
|
|
72
|
-
* ```
|
|
73
|
-
*
|
|
74
|
-
* Note that this object is similar but not identical to the Node `WASI` object --
|
|
75
|
-
* it is solely concerned with shimming of preview2 when dealing with a WebAssembly
|
|
76
|
-
* component transpiled by Jco. While this object *does* work with Node (and the browser)
|
|
77
|
-
* semantics are not the same as Node's `WASI` object.
|
|
78
|
-
*
|
|
79
|
-
* @class WASIShim
|
|
80
|
-
*/
|
|
81
|
-
export class WASIShim {
|
|
82
|
-
/** Object that confirms to the shim interface for `wasi:cli` */
|
|
83
|
-
#cli;
|
|
84
|
-
/** Object that confirms to the shim interface for `wasi:filesystem` */
|
|
85
|
-
#filesystem;
|
|
86
|
-
/** Object that confirms to the shim interface for `wasi:io` */
|
|
87
|
-
#io;
|
|
88
|
-
/** Object that confirms to the shim interface for `wasi:random` */
|
|
89
|
-
#random;
|
|
90
|
-
/** Object that confirms to the shim interface for `wasi:clocks` */
|
|
91
|
-
#clocks;
|
|
92
|
-
/** Object that confirms to the shim interface for `wasi:sockets` */
|
|
93
|
-
#sockets;
|
|
94
|
-
/** Object that confirms to the shim interface for `wasi:http` */
|
|
95
|
-
#http;
|
|
96
|
-
/** Isolated preopens for this instance */
|
|
97
|
-
#preopens;
|
|
98
|
-
/** Isolated environment for this instance */
|
|
99
|
-
#environment;
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Create a new WASIShim instance.
|
|
103
|
-
*
|
|
104
|
-
* @param {import('../types/instantiation.d.ts').WASIShimConfig} [config] - Configuration options
|
|
105
|
-
*/
|
|
106
|
-
constructor(config) {
|
|
107
|
-
// Support both old 'shims' parameter name and new 'config' style
|
|
108
|
-
const shims = config;
|
|
109
|
-
|
|
110
|
-
this.#cli = shims?.cli ?? wasi.cli;
|
|
111
|
-
this.#filesystem = shims?.filesystem ?? wasi.filesystem;
|
|
112
|
-
this.#io = shims?.io ?? wasi.io;
|
|
113
|
-
this.#random = shims?.random ?? wasi.random;
|
|
114
|
-
this.#clocks = shims?.clocks ?? wasi.clocks;
|
|
115
|
-
this.#sockets = shims?.sockets ?? wasi.sockets;
|
|
116
|
-
this.#http = shims?.http ?? wasi.http;
|
|
117
|
-
|
|
118
|
-
// Extract sandbox options
|
|
119
|
-
const sandbox = shims?.sandbox;
|
|
120
|
-
|
|
121
|
-
// Create isolated preopens if configured
|
|
122
|
-
if (sandbox?.preopens !== undefined) {
|
|
123
|
-
this.#preopens = createIsolatedPreopens(sandbox.preopens);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Create isolated environment if env or args are configured
|
|
127
|
-
if (sandbox?.env !== undefined || sandbox?.args !== undefined) {
|
|
128
|
-
this.#environment = createIsolatedEnvironment(sandbox?.env, sandbox?.args, this.#cli);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// Apply network restrictions if disabled
|
|
132
|
-
if (sandbox?.enableNetwork === false) {
|
|
133
|
-
// Use the sockets module's built-in deny functions
|
|
134
|
-
if (this.#sockets._denyTcp) {
|
|
135
|
-
this.#sockets._denyTcp();
|
|
136
|
-
}
|
|
137
|
-
if (this.#sockets._denyUdp) {
|
|
138
|
-
this.#sockets._denyUdp();
|
|
139
|
-
}
|
|
140
|
-
if (this.#sockets._denyDnsLookup) {
|
|
141
|
-
this.#sockets._denyDnsLookup();
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Generate an import object for the shim that can be used with
|
|
148
|
-
* functions like `instantiate` that are exposed from a transpiled
|
|
149
|
-
* WebAssembly component.
|
|
150
|
-
*
|
|
151
|
-
* @param {GetImportObjectArgs} [opts] - options for import object generation
|
|
152
|
-
* @returns {WASIImportObject}
|
|
153
|
-
*
|
|
154
|
-
* @typedef {{
|
|
155
|
-
* asVersion?: number,
|
|
156
|
-
* }} GetImportObjectArgs
|
|
157
|
-
*/
|
|
158
|
-
getImportObject(opts) {
|
|
159
|
-
const versionSuffix = opts?.asVersion ? `@${opts.asVersion}` : "";
|
|
160
|
-
|
|
161
|
-
const obj = {};
|
|
162
|
-
|
|
163
|
-
obj[`wasi:cli/environment${versionSuffix}`] = this.#environment ?? this.#cli.environment;
|
|
164
|
-
obj[`wasi:cli/exit${versionSuffix}`] = this.#cli.exit;
|
|
165
|
-
obj[`wasi:cli/stderr${versionSuffix}`] = this.#cli.stderr;
|
|
166
|
-
obj[`wasi:cli/stdin${versionSuffix}`] = this.#cli.stdin;
|
|
167
|
-
obj[`wasi:cli/stdout${versionSuffix}`] = this.#cli.stdout;
|
|
168
|
-
obj[`wasi:cli/terminal-input${versionSuffix}`] = this.#cli.terminalInput;
|
|
169
|
-
obj[`wasi:cli/terminal-output${versionSuffix}`] = this.#cli.terminalOutput;
|
|
170
|
-
obj[`wasi:cli/terminal-stderr${versionSuffix}`] = this.#cli.terminalStderr;
|
|
171
|
-
obj[`wasi:cli/terminal-stdin${versionSuffix}`] = this.#cli.terminalStdin;
|
|
172
|
-
obj[`wasi:cli/terminal-stdout${versionSuffix}`] = this.#cli.terminalStdout;
|
|
173
|
-
|
|
174
|
-
obj[`wasi:sockets/instance-network${versionSuffix}`] = this.#sockets.instanceNetwork;
|
|
175
|
-
obj[`wasi:sockets/ip-name-lookup${versionSuffix}`] = this.#sockets.ipNameLookup;
|
|
176
|
-
obj[`wasi:sockets/network${versionSuffix}`] = this.#sockets.network;
|
|
177
|
-
obj[`wasi:sockets/tcp${versionSuffix}`] = this.#sockets.tcp;
|
|
178
|
-
obj[`wasi:sockets/tcp-create-socket${versionSuffix}`] = this.#sockets.tcpCreateSocket;
|
|
179
|
-
obj[`wasi:sockets/udp${versionSuffix}`] = this.#sockets.udp;
|
|
180
|
-
obj[`wasi:sockets/udp-create-socket${versionSuffix}`] = this.#sockets.udpCreateSocket;
|
|
181
|
-
|
|
182
|
-
obj[`wasi:filesystem/preopens${versionSuffix}`] = this.#preopens ?? this.#filesystem.preopens;
|
|
183
|
-
obj[`wasi:filesystem/types${versionSuffix}`] = this.#filesystem.types;
|
|
184
|
-
|
|
185
|
-
obj[`wasi:io/error${versionSuffix}`] = this.#io.error;
|
|
186
|
-
obj[`wasi:io/poll${versionSuffix}`] = this.#io.poll;
|
|
187
|
-
obj[`wasi:io/streams${versionSuffix}`] = this.#io.streams;
|
|
188
|
-
|
|
189
|
-
obj[`wasi:random/random${versionSuffix}`] = this.#random.random;
|
|
190
|
-
obj[`wasi:random/insecure${versionSuffix}`] = this.#random.insecure;
|
|
191
|
-
obj[`wasi:random/insecure-seed${versionSuffix}`] = this.#random.insecureSeed;
|
|
192
|
-
|
|
193
|
-
obj[`wasi:clocks/monotonic-clock${versionSuffix}`] = this.#clocks.monotonicClock;
|
|
194
|
-
obj[`wasi:clocks/wall-clock${versionSuffix}`] = this.#clocks.wallClock;
|
|
195
|
-
|
|
196
|
-
obj[`wasi:http/types${versionSuffix}`] = this.#http.types;
|
|
197
|
-
obj[`wasi:http/outgoing-handler${versionSuffix}`] = this.#http.outgoingHandler;
|
|
198
|
-
|
|
199
|
-
return obj;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Create an isolated preopens object with its own preopen entries.
|
|
205
|
-
*
|
|
206
|
-
* @param {Record<string, string>} preopensConfig - Map of virtual paths to host paths
|
|
207
|
-
* @returns {object} A preopens object with Descriptor and getDirectories()
|
|
208
|
-
*/
|
|
209
|
-
function createIsolatedPreopens(preopensConfig) {
|
|
210
|
-
const { types, _createPreopenDescriptor } = wasi.filesystem;
|
|
211
|
-
const entries = [];
|
|
212
|
-
|
|
213
|
-
// Populate entries using the filesystem's descriptor creation
|
|
214
|
-
if (_createPreopenDescriptor) {
|
|
215
|
-
for (const [virtualPath, hostPath] of Object.entries(preopensConfig)) {
|
|
216
|
-
const descriptor = _createPreopenDescriptor(hostPath);
|
|
217
|
-
entries.push([descriptor, virtualPath]);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
return {
|
|
222
|
-
Descriptor: types.Descriptor,
|
|
223
|
-
getDirectories() {
|
|
224
|
-
return entries;
|
|
225
|
-
},
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* Create an isolated CLI environment with its own env and args.
|
|
231
|
-
*
|
|
232
|
-
* @param {Record<string, string>} env - Environment variables
|
|
233
|
-
* @param {string[]} args - Command-line arguments
|
|
234
|
-
* @param {object} baseCli - The base CLI module to extend
|
|
235
|
-
* @returns {object} An isolated CLI environment object
|
|
236
|
-
*/
|
|
237
|
-
function createIsolatedEnvironment(env, args, baseCli) {
|
|
238
|
-
const envEntries = env ? Object.entries(env) : null;
|
|
239
|
-
const argsArray = args || null;
|
|
240
|
-
|
|
241
|
-
return {
|
|
242
|
-
...baseCli.environment,
|
|
243
|
-
getEnvironment() {
|
|
244
|
-
return envEntries ?? baseCli.environment.getEnvironment();
|
|
245
|
-
},
|
|
246
|
-
getArguments() {
|
|
247
|
-
return argsArray ?? baseCli.environment.getArguments();
|
|
248
|
-
},
|
|
249
|
-
initialCwd() {
|
|
250
|
-
return baseCli.environment.initialCwd();
|
|
251
|
-
},
|
|
252
|
-
};
|
|
253
|
-
}
|