@bytecodealliance/preview2-shim 0.17.3 → 0.17.4

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.
@@ -8,6 +8,7 @@ import {
8
8
  setOutgoingResponse,
9
9
  startHttpServer,
10
10
  stopHttpServer,
11
+ getHttpServerAddress,
11
12
  } from './worker-http.js';
12
13
  import { Readable } from 'node:stream';
13
14
  import { read } from 'node:fs';
@@ -29,6 +30,7 @@ import {
29
30
  HTTP_SERVER_SET_OUTGOING_RESPONSE,
30
31
  HTTP_SERVER_START,
31
32
  HTTP_SERVER_STOP,
33
+ HTTP_SERVER_GET_ADDRESS,
32
34
  INPUT_STREAM_BLOCKING_READ,
33
35
  INPUT_STREAM_BLOCKING_SKIP,
34
36
  INPUT_STREAM_CREATE,
@@ -303,9 +305,21 @@ function handle(call, id, payload) {
303
305
  throw uncaughtException;
304
306
  }
305
307
  switch (call) {
306
- // Http
307
- case HTTP_CREATE_REQUEST: {
308
- const {
308
+ // Http
309
+ case HTTP_CREATE_REQUEST: {
310
+ const {
311
+ method,
312
+ scheme,
313
+ authority,
314
+ pathWithQuery,
315
+ headers,
316
+ body,
317
+ connectTimeout,
318
+ betweenBytesTimeout,
319
+ firstByteTimeout,
320
+ } = payload;
321
+ return createFuture(
322
+ createHttpRequest(
309
323
  method,
310
324
  scheme,
311
325
  authority,
@@ -314,51 +328,23 @@ function handle(call, id, payload) {
314
328
  body,
315
329
  connectTimeout,
316
330
  betweenBytesTimeout,
317
- firstByteTimeout,
318
- } = payload;
319
- return createFuture(
320
- createHttpRequest(
321
- method,
322
- scheme,
323
- authority,
324
- pathWithQuery,
325
- headers,
326
- body,
327
- connectTimeout,
328
- betweenBytesTimeout,
329
- firstByteTimeout
330
- )
331
- );
332
- }
333
- case OUTPUT_STREAM_CREATE | HTTP: {
334
- const stream = new PassThrough();
335
- // content length is passed as payload
336
- stream.contentLength = payload;
337
- stream.bytesRemaining = payload;
338
- return createWritableStream(stream);
339
- }
340
- case OUTPUT_STREAM_SUBSCRIBE | HTTP:
341
- case OUTPUT_STREAM_FLUSH | HTTP:
342
- case OUTPUT_STREAM_BLOCKING_WRITE_AND_FLUSH | HTTP: {
343
- // http flush is a noop
344
- const { stream } = getStreamOrThrow(id);
345
- if (call === (OUTPUT_STREAM_BLOCKING_WRITE_AND_FLUSH | HTTP)) {
346
- stream.bytesRemaining -= payload.byteLength;
347
- if (stream.bytesRemaining < 0) {
348
- throw {
349
- tag: 'last-operation-failed',
350
- val: {
351
- tag: 'HTTP-request-body-size',
352
- val: stream.contentLength - stream.bytesRemaining,
353
- },
354
- };
355
- }
356
- }
357
- // otherwise fall through to generic implementation
358
- return handle(call & ~HTTP, id, payload);
359
- }
360
- case OUTPUT_STREAM_WRITE | HTTP: {
361
- const { stream } = getStreamOrThrow(id);
331
+ firstByteTimeout
332
+ )
333
+ );
334
+ }
335
+ case OUTPUT_STREAM_CREATE | HTTP: {
336
+ const stream = new PassThrough();
337
+ // content length is passed as payload
338
+ stream.contentLength = payload;
339
+ stream.bytesRemaining = payload;
340
+ return createWritableStream(stream);
341
+ }
342
+ case OUTPUT_STREAM_SUBSCRIBE | HTTP:
343
+ case OUTPUT_STREAM_FLUSH | HTTP:
344
+ case OUTPUT_STREAM_BLOCKING_WRITE_AND_FLUSH | HTTP: {
345
+ // http flush is a noop
346
+ const { stream } = getStreamOrThrow(id);
347
+ if (call === (OUTPUT_STREAM_BLOCKING_WRITE_AND_FLUSH | HTTP)) {
362
348
  stream.bytesRemaining -= payload.byteLength;
363
349
  if (stream.bytesRemaining < 0) {
364
350
  throw {
@@ -369,444 +355,462 @@ function handle(call, id, payload) {
369
355
  },
370
356
  };
371
357
  }
372
- const output = handle(OUTPUT_STREAM_WRITE, id, payload);
373
- return output;
374
358
  }
375
- case OUTPUT_STREAM_DISPOSE | HTTP:
376
- throw new Error(
377
- 'wasi-io trap: Output stream dispose not implemented as an IO-call for HTTP'
378
- );
379
- case HTTP_OUTPUT_STREAM_FINISH: {
380
- let stream;
381
- try {
382
- ({ stream } = getStreamOrThrow(id));
383
- } catch (e) {
384
- if (e.tag === 'closed') {
385
- throw { tag: 'internal-error', val: 'stream closed' };
386
- }
387
- if (e.tag === 'last-operation-failed') {
388
- throw { tag: 'internal-error', val: e.val.message };
389
- }
390
- }
391
- if (stream.bytesRemaining > 0) {
392
- throw {
359
+ // otherwise fall through to generic implementation
360
+ return handle(call & ~HTTP, id, payload);
361
+ }
362
+ case OUTPUT_STREAM_WRITE | HTTP: {
363
+ const { stream } = getStreamOrThrow(id);
364
+ stream.bytesRemaining -= payload.byteLength;
365
+ if (stream.bytesRemaining < 0) {
366
+ throw {
367
+ tag: 'last-operation-failed',
368
+ val: {
393
369
  tag: 'HTTP-request-body-size',
394
370
  val: stream.contentLength - stream.bytesRemaining,
395
- };
371
+ },
372
+ };
373
+ }
374
+ const output = handle(OUTPUT_STREAM_WRITE, id, payload);
375
+ return output;
376
+ }
377
+ case OUTPUT_STREAM_DISPOSE | HTTP:
378
+ throw new Error(
379
+ 'wasi-io trap: Output stream dispose not implemented as an IO-call for HTTP'
380
+ );
381
+ case HTTP_OUTPUT_STREAM_FINISH: {
382
+ let stream;
383
+ try {
384
+ ({ stream } = getStreamOrThrow(id));
385
+ } catch (e) {
386
+ if (e.tag === 'closed') {
387
+ throw { tag: 'internal-error', val: 'stream closed' };
396
388
  }
397
- if (stream.bytesRemaining < 0) {
398
- throw {
399
- tag: 'HTTP-request-body-size',
400
- val: stream.contentLength - stream.bytesRemaining,
401
- };
389
+ if (e.tag === 'last-operation-failed') {
390
+ throw { tag: 'internal-error', val: e.val.message };
402
391
  }
403
- stream.end();
404
- return;
405
392
  }
406
- case HTTP_OUTGOING_BODY_DISPOSE:
407
- if (debug && !streams.has(id)) {
408
- console.warn(`wasi-io: stream ${id} not found to dispose`);
409
- }
410
- streams.delete(id);
411
- return;
412
- case HTTP_SERVER_START:
413
- return startHttpServer(id, payload);
414
- case HTTP_SERVER_STOP:
415
- return stopHttpServer(id);
416
- case HTTP_SERVER_SET_OUTGOING_RESPONSE:
417
- return setOutgoingResponse(id, payload);
418
- case HTTP_SERVER_CLEAR_OUTGOING_RESPONSE:
419
- return clearOutgoingResponse(id);
393
+ if (stream.bytesRemaining > 0) {
394
+ throw {
395
+ tag: 'HTTP-request-body-size',
396
+ val: stream.contentLength - stream.bytesRemaining,
397
+ };
398
+ }
399
+ if (stream.bytesRemaining < 0) {
400
+ throw {
401
+ tag: 'HTTP-request-body-size',
402
+ val: stream.contentLength - stream.bytesRemaining,
403
+ };
404
+ }
405
+ stream.end();
406
+ return;
407
+ }
408
+ case HTTP_OUTGOING_BODY_DISPOSE:
409
+ if (debug && !streams.has(id)) {
410
+ console.warn(`wasi-io: stream ${id} not found to dispose`);
411
+ }
412
+ streams.delete(id);
413
+ return;
414
+ case HTTP_SERVER_START:
415
+ return startHttpServer(id, payload);
416
+ case HTTP_SERVER_STOP:
417
+ return stopHttpServer(id);
418
+ case HTTP_SERVER_SET_OUTGOING_RESPONSE:
419
+ return setOutgoingResponse(id, payload);
420
+ case HTTP_SERVER_CLEAR_OUTGOING_RESPONSE:
421
+ return clearOutgoingResponse(id);
422
+ case HTTP_SERVER_GET_ADDRESS:
423
+ return getHttpServerAddress(id);
420
424
 
421
425
  // Sockets name resolution
422
- case SOCKET_RESOLVE_ADDRESS_CREATE_REQUEST:
423
- return createFuture(socketResolveAddress(payload));
424
- case SOCKET_RESOLVE_ADDRESS_SUBSCRIBE_REQUEST:
425
- return createPoll(futures.get(id).pollState);
426
- case SOCKET_RESOLVE_ADDRESS_DISPOSE_REQUEST:
427
- return void futureDispose(id, true);
428
- case SOCKET_RESOLVE_ADDRESS_TAKE_REQUEST: {
429
- const val = futureTakeValue(id);
430
- if (val === undefined) {
431
- throw 'would-block';
432
- }
433
- // double take avoidance is ensured
434
- return val.val;
426
+ case SOCKET_RESOLVE_ADDRESS_CREATE_REQUEST:
427
+ return createFuture(socketResolveAddress(payload));
428
+ case SOCKET_RESOLVE_ADDRESS_SUBSCRIBE_REQUEST:
429
+ return createPoll(futures.get(id).pollState);
430
+ case SOCKET_RESOLVE_ADDRESS_DISPOSE_REQUEST:
431
+ return void futureDispose(id, true);
432
+ case SOCKET_RESOLVE_ADDRESS_TAKE_REQUEST: {
433
+ const val = futureTakeValue(id);
434
+ if (val === undefined) {
435
+ throw 'would-block';
435
436
  }
437
+ // double take avoidance is ensured
438
+ return val.val;
439
+ }
436
440
 
437
- // Sockets TCP
438
- case SOCKET_TCP_ACCEPT:
439
- return socketTcpAccept(id);
440
- case SOCKET_TCP_CREATE_HANDLE:
441
- return createTcpSocket();
442
- case SOCKET_TCP_BIND_START:
443
- return socketTcpBindStart(id, payload.localAddress, payload.family);
444
- case SOCKET_TCP_BIND_FINISH:
445
- return socketTcpFinish(id, SOCKET_STATE_BIND, SOCKET_STATE_BOUND);
446
- case SOCKET_TCP_CONNECT_START:
447
- return socketTcpConnectStart(
448
- id,
449
- payload.remoteAddress,
450
- payload.family
451
- );
452
- case SOCKET_TCP_CONNECT_FINISH:
453
- return socketTcpFinish(
454
- id,
455
- SOCKET_STATE_CONNECT,
456
- SOCKET_STATE_CONNECTION
457
- );
458
- case SOCKET_TCP_LISTEN_START:
459
- return socketTcpListenStart(id);
460
- case SOCKET_TCP_LISTEN_FINISH:
461
- return socketTcpFinish(
462
- id,
463
- SOCKET_STATE_LISTEN,
464
- SOCKET_STATE_LISTENER
465
- );
466
- case SOCKET_TCP_IS_LISTENING:
467
- return tcpSockets.get(id).state === SOCKET_STATE_LISTENER;
468
- case SOCKET_GET_DEFAULT_SEND_BUFFER_SIZE:
469
- return getDefaultSendBufferSize(id);
470
- case SOCKET_GET_DEFAULT_RECEIVE_BUFFER_SIZE:
471
- return getDefaultReceiveBufferSize(id);
472
- case SOCKET_TCP_SET_LISTEN_BACKLOG_SIZE:
473
- return socketTcpSetListenBacklogSize(id);
474
- case SOCKET_TCP_GET_LOCAL_ADDRESS:
475
- return socketTcpGetLocalAddress(id);
476
- case SOCKET_TCP_GET_REMOTE_ADDRESS:
477
- return socketTcpGetRemoteAddress(id);
478
- case SOCKET_TCP_SHUTDOWN:
479
- return socketTcpShutdown(id, payload);
480
- case SOCKET_TCP_SUBSCRIBE:
481
- return createPoll(tcpSockets.get(id).pollState);
482
- case SOCKET_TCP_SET_KEEP_ALIVE:
483
- return socketTcpSetKeepAlive(id, payload);
484
- case SOCKET_TCP_DISPOSE:
485
- return socketTcpDispose(id);
441
+ // Sockets TCP
442
+ case SOCKET_TCP_ACCEPT:
443
+ return socketTcpAccept(id);
444
+ case SOCKET_TCP_CREATE_HANDLE:
445
+ return createTcpSocket();
446
+ case SOCKET_TCP_BIND_START:
447
+ return socketTcpBindStart(id, payload.localAddress, payload.family);
448
+ case SOCKET_TCP_BIND_FINISH:
449
+ return socketTcpFinish(id, SOCKET_STATE_BIND, SOCKET_STATE_BOUND);
450
+ case SOCKET_TCP_CONNECT_START:
451
+ return socketTcpConnectStart(
452
+ id,
453
+ payload.remoteAddress,
454
+ payload.family
455
+ );
456
+ case SOCKET_TCP_CONNECT_FINISH:
457
+ return socketTcpFinish(
458
+ id,
459
+ SOCKET_STATE_CONNECT,
460
+ SOCKET_STATE_CONNECTION
461
+ );
462
+ case SOCKET_TCP_LISTEN_START:
463
+ return socketTcpListenStart(id);
464
+ case SOCKET_TCP_LISTEN_FINISH:
465
+ return socketTcpFinish(
466
+ id,
467
+ SOCKET_STATE_LISTEN,
468
+ SOCKET_STATE_LISTENER
469
+ );
470
+ case SOCKET_TCP_IS_LISTENING:
471
+ return tcpSockets.get(id).state === SOCKET_STATE_LISTENER;
472
+ case SOCKET_GET_DEFAULT_SEND_BUFFER_SIZE:
473
+ return getDefaultSendBufferSize(id);
474
+ case SOCKET_GET_DEFAULT_RECEIVE_BUFFER_SIZE:
475
+ return getDefaultReceiveBufferSize(id);
476
+ case SOCKET_TCP_SET_LISTEN_BACKLOG_SIZE:
477
+ return socketTcpSetListenBacklogSize(id);
478
+ case SOCKET_TCP_GET_LOCAL_ADDRESS:
479
+ return socketTcpGetLocalAddress(id);
480
+ case SOCKET_TCP_GET_REMOTE_ADDRESS:
481
+ return socketTcpGetRemoteAddress(id);
482
+ case SOCKET_TCP_SHUTDOWN:
483
+ return socketTcpShutdown(id, payload);
484
+ case SOCKET_TCP_SUBSCRIBE:
485
+ return createPoll(tcpSockets.get(id).pollState);
486
+ case SOCKET_TCP_SET_KEEP_ALIVE:
487
+ return socketTcpSetKeepAlive(id, payload);
488
+ case SOCKET_TCP_DISPOSE:
489
+ return socketTcpDispose(id);
486
490
 
487
491
  // Sockets UDP
488
- case SOCKET_UDP_CREATE_HANDLE:
489
- return createUdpSocket(payload);
490
- case SOCKET_UDP_BIND_START:
491
- return socketUdpBindStart(id, payload.localAddress, payload.family);
492
- case SOCKET_UDP_BIND_FINISH:
493
- return socketUdpBindFinish(id);
494
- case SOCKET_UDP_STREAM:
495
- return socketUdpStream(id, payload);
496
- case SOCKET_UDP_SUBSCRIBE:
497
- return createPoll(udpSockets.get(id).pollState);
498
- case SOCKET_UDP_GET_LOCAL_ADDRESS:
499
- return socketUdpGetLocalAddress(id);
500
- case SOCKET_UDP_GET_REMOTE_ADDRESS:
501
- return socketUdpGetRemoteAddress(id);
502
- case SOCKET_UDP_SET_RECEIVE_BUFFER_SIZE:
503
- return socketUdpSetReceiveBufferSize(id, payload);
504
- case SOCKET_UDP_SET_SEND_BUFFER_SIZE:
505
- return socketUdpSetSendBufferSize(id, payload);
506
- case SOCKET_UDP_SET_UNICAST_HOP_LIMIT:
507
- return socketUdpSetUnicastHopLimit(id, payload);
508
- case SOCKET_UDP_GET_RECEIVE_BUFFER_SIZE:
509
- return socketUdpGetReceiveBufferSize(id);
510
- case SOCKET_UDP_GET_SEND_BUFFER_SIZE:
511
- return socketUdpGetSendBufferSize(id);
512
- case SOCKET_UDP_GET_UNICAST_HOP_LIMIT:
513
- return socketUdpGetUnicastHopLimit(id);
514
- case SOCKET_UDP_DISPOSE:
515
- return socketUdpDispose(id);
492
+ case SOCKET_UDP_CREATE_HANDLE:
493
+ return createUdpSocket(payload);
494
+ case SOCKET_UDP_BIND_START:
495
+ return socketUdpBindStart(id, payload.localAddress, payload.family);
496
+ case SOCKET_UDP_BIND_FINISH:
497
+ return socketUdpBindFinish(id);
498
+ case SOCKET_UDP_STREAM:
499
+ return socketUdpStream(id, payload);
500
+ case SOCKET_UDP_SUBSCRIBE:
501
+ return createPoll(udpSockets.get(id).pollState);
502
+ case SOCKET_UDP_GET_LOCAL_ADDRESS:
503
+ return socketUdpGetLocalAddress(id);
504
+ case SOCKET_UDP_GET_REMOTE_ADDRESS:
505
+ return socketUdpGetRemoteAddress(id);
506
+ case SOCKET_UDP_SET_RECEIVE_BUFFER_SIZE:
507
+ return socketUdpSetReceiveBufferSize(id, payload);
508
+ case SOCKET_UDP_SET_SEND_BUFFER_SIZE:
509
+ return socketUdpSetSendBufferSize(id, payload);
510
+ case SOCKET_UDP_SET_UNICAST_HOP_LIMIT:
511
+ return socketUdpSetUnicastHopLimit(id, payload);
512
+ case SOCKET_UDP_GET_RECEIVE_BUFFER_SIZE:
513
+ return socketUdpGetReceiveBufferSize(id);
514
+ case SOCKET_UDP_GET_SEND_BUFFER_SIZE:
515
+ return socketUdpGetSendBufferSize(id);
516
+ case SOCKET_UDP_GET_UNICAST_HOP_LIMIT:
517
+ return socketUdpGetUnicastHopLimit(id);
518
+ case SOCKET_UDP_DISPOSE:
519
+ return socketUdpDispose(id);
516
520
 
517
- case SOCKET_INCOMING_DATAGRAM_STREAM_RECEIVE:
518
- return socketIncomingDatagramStreamReceive(id, payload);
519
- case SOCKET_OUTGOING_DATAGRAM_STREAM_CHECK_SEND:
520
- return socketOutgoingDatagramStreamCheckSend(id);
521
- case SOCKET_OUTGOING_DATAGRAM_STREAM_SEND:
522
- return socketOutgoingDatagramStreamSend(id, payload);
523
- case SOCKET_DATAGRAM_STREAM_SUBSCRIBE:
524
- return createPoll(datagramStreams.get(id).pollState);
525
- case SOCKET_DATAGRAM_STREAM_DISPOSE:
526
- return socketDatagramStreamDispose(id);
521
+ case SOCKET_INCOMING_DATAGRAM_STREAM_RECEIVE:
522
+ return socketIncomingDatagramStreamReceive(id, payload);
523
+ case SOCKET_OUTGOING_DATAGRAM_STREAM_CHECK_SEND:
524
+ return socketOutgoingDatagramStreamCheckSend(id);
525
+ case SOCKET_OUTGOING_DATAGRAM_STREAM_SEND:
526
+ return socketOutgoingDatagramStreamSend(id, payload);
527
+ case SOCKET_DATAGRAM_STREAM_SUBSCRIBE:
528
+ return createPoll(datagramStreams.get(id).pollState);
529
+ case SOCKET_DATAGRAM_STREAM_DISPOSE:
530
+ return socketDatagramStreamDispose(id);
527
531
 
528
532
  // Stdio
529
- case OUTPUT_STREAM_BLOCKING_FLUSH | STDOUT:
530
- case OUTPUT_STREAM_BLOCKING_FLUSH | STDERR:
531
- // no blocking flush for stdio in Node.js
532
- return;
533
- case OUTPUT_STREAM_DISPOSE | STDOUT:
534
- case OUTPUT_STREAM_DISPOSE | STDERR:
535
- return;
536
- case INPUT_STREAM_CREATE | STDIN: {
537
- return createReadableStream(
538
- new Readable({
539
- read(n) {
540
- if (n <= 0) {
541
- return void this.push(null);
542
- }
543
- let buf = Buffer.allocUnsafeSlow(n);
544
- read(0, buf, 0, n, null, (err, bytesRead) => {
545
- if (err) {
546
- if (err.code === 'EAGAIN') {
547
- nextTick(() => void this._read(n));
548
- return;
549
- }
550
- this.destroy(err);
551
- } else if (bytesRead > 0) {
552
- if (bytesRead !== buf.length) {
553
- const dst =
533
+ case OUTPUT_STREAM_BLOCKING_FLUSH | STDOUT:
534
+ case OUTPUT_STREAM_BLOCKING_FLUSH | STDERR:
535
+ // no blocking flush for stdio in Node.js
536
+ return;
537
+ case OUTPUT_STREAM_DISPOSE | STDOUT:
538
+ case OUTPUT_STREAM_DISPOSE | STDERR:
539
+ return;
540
+ case INPUT_STREAM_CREATE | STDIN: {
541
+ return createReadableStream(
542
+ new Readable({
543
+ read(n) {
544
+ if (n <= 0) {
545
+ return void this.push(null);
546
+ }
547
+ let buf = Buffer.allocUnsafeSlow(n);
548
+ read(0, buf, 0, n, null, (err, bytesRead) => {
549
+ if (err) {
550
+ if (err.code === 'EAGAIN') {
551
+ nextTick(() => void this._read(n));
552
+ return;
553
+ }
554
+ this.destroy(err);
555
+ } else if (bytesRead > 0) {
556
+ if (bytesRead !== buf.length) {
557
+ const dst =
554
558
  Buffer.allocUnsafeSlow(bytesRead);
555
- buf.copy(dst, 0, 0, bytesRead);
556
- buf = dst;
557
- }
558
- this.push(buf);
559
- } else {
560
- this.push(null);
559
+ buf.copy(dst, 0, 0, bytesRead);
560
+ buf = dst;
561
561
  }
562
- });
563
- },
564
- })
565
- );
566
- }
562
+ this.push(buf);
563
+ } else {
564
+ this.push(null);
565
+ }
566
+ });
567
+ },
568
+ })
569
+ );
570
+ }
567
571
 
568
- // Clocks
569
- case CLOCKS_DURATION_SUBSCRIBE:
570
- payload = hrtime.bigint() + payload;
572
+ // Clocks
573
+ case CLOCKS_DURATION_SUBSCRIBE:
574
+ payload = hrtime.bigint() + payload;
571
575
  // fallthrough
572
- case CLOCKS_INSTANT_SUBSCRIBE: {
573
- const pollState = {
574
- ready: false,
575
- listener: null,
576
- polls: [],
577
- parentStream: null,
578
- };
579
- subscribeInstant(pollState, payload);
580
- return createPoll(pollState);
581
- }
576
+ case CLOCKS_INSTANT_SUBSCRIBE: {
577
+ const pollState = {
578
+ ready: false,
579
+ listener: null,
580
+ polls: [],
581
+ parentStream: null,
582
+ };
583
+ subscribeInstant(pollState, payload);
584
+ return createPoll(pollState);
585
+ }
582
586
 
583
- // Filesystem
584
- case INPUT_STREAM_CREATE | FILE: {
585
- const { fd, offset } = payload;
586
- const stream = createReadStream(null, {
587
- fd,
588
- autoClose: false,
589
- highWaterMark: 64 * 1024,
590
- start: Number(offset),
591
- });
592
- return createReadableStream(stream);
593
- }
594
- case OUTPUT_STREAM_CREATE | FILE: {
595
- const { fd, offset } = payload;
596
- const stream = createWriteStream(null, {
597
- fd,
598
- autoClose: false,
599
- emitClose: false,
600
- highWaterMark: 64 * 1024,
601
- start: Number(offset),
602
- });
603
- return createWritableStream(stream);
604
- }
587
+ // Filesystem
588
+ case INPUT_STREAM_CREATE | FILE: {
589
+ const { fd, offset } = payload;
590
+ const stream = createReadStream(null, {
591
+ fd,
592
+ autoClose: false,
593
+ highWaterMark: 64 * 1024,
594
+ start: Number(offset),
595
+ });
596
+ return createReadableStream(stream);
597
+ }
598
+ case OUTPUT_STREAM_CREATE | FILE: {
599
+ const { fd, offset } = payload;
600
+ const stream = createWriteStream(null, {
601
+ fd,
602
+ autoClose: false,
603
+ emitClose: false,
604
+ highWaterMark: 64 * 1024,
605
+ start: Number(offset),
606
+ });
607
+ return createWritableStream(stream);
608
+ }
605
609
  }
606
610
 
607
611
  // Generic call implementations (streams + polls)
608
612
  switch (call & CALL_MASK) {
609
- case INPUT_STREAM_READ: {
610
- const stream = getStreamOrThrow(id);
611
- if (!stream.pollState.ready) {
612
- return new Uint8Array();
613
- }
614
- const res = stream.stream.read(
615
- Math.min(stream.stream.readableLength, Number(payload))
616
- );
617
- if (res) {
618
- return res;
619
- }
620
- if (stream.stream.readableEnded) {
621
- throw { tag: 'closed' };
622
- }
613
+ case INPUT_STREAM_READ: {
614
+ const stream = getStreamOrThrow(id);
615
+ if (!stream.pollState.ready) {
623
616
  return new Uint8Array();
624
617
  }
625
- case INPUT_STREAM_BLOCKING_READ: {
626
- const { pollState } = streams.get(id);
627
- pollStateCheck(pollState);
628
- if (pollState.ready) {
629
- return handle(
630
- INPUT_STREAM_READ | (call & CALL_TYPE_MASK),
631
- id,
632
- payload
633
- );
634
- }
635
- return new Promise(
636
- (resolve) => void (pollState.listener = resolve)
637
- ).then(() =>
638
- handle(INPUT_STREAM_READ | (call & CALL_TYPE_MASK), id, payload)
639
- );
618
+ const res = stream.stream.read(
619
+ Math.min(stream.stream.readableLength, Number(payload))
620
+ );
621
+ if (res) {
622
+ return res;
623
+ }
624
+ if (stream.stream.readableEnded) {
625
+ throw { tag: 'closed' };
640
626
  }
641
- case INPUT_STREAM_SKIP:
627
+ return new Uint8Array();
628
+ }
629
+ case INPUT_STREAM_BLOCKING_READ: {
630
+ const { pollState } = streams.get(id);
631
+ pollStateCheck(pollState);
632
+ if (pollState.ready) {
642
633
  return handle(
643
634
  INPUT_STREAM_READ | (call & CALL_TYPE_MASK),
644
635
  id,
645
- new Uint8Array(Number(payload))
646
- );
647
- case INPUT_STREAM_BLOCKING_SKIP:
648
- return handle(
649
- INPUT_STREAM_BLOCKING_READ | (call & CALL_TYPE_MASK),
650
- id,
651
- new Uint8Array(Number(payload))
636
+ payload
652
637
  );
653
- case INPUT_STREAM_SUBSCRIBE:
654
- return createPoll(streams.get(id).pollState);
655
- case INPUT_STREAM_DISPOSE: {
656
- const stream = streams.get(id);
657
- verifyPollsDroppedForDrop(stream.pollState, 'input stream');
658
- streams.delete(id);
659
- return;
660
638
  }
661
- case OUTPUT_STREAM_CHECK_WRITE: {
662
- const { stream, pollState } = getStreamOrThrow(id);
663
- const bytes = stream.writableHighWaterMark - stream.writableLength;
664
- if (bytes === 0) {
665
- pollState.ready = false;
666
- }
667
- return BigInt(bytes);
639
+ return new Promise(
640
+ (resolve) => void (pollState.listener = resolve)
641
+ ).then(() =>
642
+ handle(INPUT_STREAM_READ | (call & CALL_TYPE_MASK), id, payload)
643
+ );
644
+ }
645
+ case INPUT_STREAM_SKIP:
646
+ return handle(
647
+ INPUT_STREAM_READ | (call & CALL_TYPE_MASK),
648
+ id,
649
+ new Uint8Array(Number(payload))
650
+ );
651
+ case INPUT_STREAM_BLOCKING_SKIP:
652
+ return handle(
653
+ INPUT_STREAM_BLOCKING_READ | (call & CALL_TYPE_MASK),
654
+ id,
655
+ new Uint8Array(Number(payload))
656
+ );
657
+ case INPUT_STREAM_SUBSCRIBE:
658
+ return createPoll(streams.get(id).pollState);
659
+ case INPUT_STREAM_DISPOSE: {
660
+ const stream = streams.get(id);
661
+ verifyPollsDroppedForDrop(stream.pollState, 'input stream');
662
+ streams.delete(id);
663
+ return;
664
+ }
665
+ case OUTPUT_STREAM_CHECK_WRITE: {
666
+ const { stream, pollState } = getStreamOrThrow(id);
667
+ const bytes = stream.writableHighWaterMark - stream.writableLength;
668
+ if (bytes === 0) {
669
+ pollState.ready = false;
668
670
  }
669
- case OUTPUT_STREAM_WRITE: {
670
- const { stream } = getStreamOrThrow(id);
671
- if (
672
- payload.byteLength >
671
+ return BigInt(bytes);
672
+ }
673
+ case OUTPUT_STREAM_WRITE: {
674
+ const { stream } = getStreamOrThrow(id);
675
+ if (
676
+ payload.byteLength >
673
677
  stream.writableHighWaterMark - stream.writableLength
674
- ) {
675
- throw new Error(
676
- 'wasi-io trap: attempt to write too many bytes'
677
- );
678
- }
679
- return void stream.write(payload);
678
+ ) {
679
+ throw new Error(
680
+ 'wasi-io trap: attempt to write too many bytes'
681
+ );
680
682
  }
681
- case OUTPUT_STREAM_BLOCKING_WRITE_AND_FLUSH: {
682
- const stream = getStreamOrThrow(id);
683
- // if an existing flush, try again after that
684
- if (stream.flushPromise) {
685
- return stream.flushPromise.then(() =>
686
- handle(call, id, payload)
687
- );
688
- }
689
- if (
690
- payload.byteLength >
683
+ return void stream.write(payload);
684
+ }
685
+ case OUTPUT_STREAM_BLOCKING_WRITE_AND_FLUSH: {
686
+ const stream = getStreamOrThrow(id);
687
+ // if an existing flush, try again after that
688
+ if (stream.flushPromise) {
689
+ return stream.flushPromise.then(() =>
690
+ handle(call, id, payload)
691
+ );
692
+ }
693
+ if (
694
+ payload.byteLength >
691
695
  stream.stream.writableHighWaterMark -
692
696
  stream.stream.writableLength
693
- ) {
694
- throw new Error(
695
- 'wasi-io trap: Cannot write more than permitted writable length'
696
- );
697
- }
698
- stream.pollState.ready = false;
699
- return (stream.flushPromise = new Promise((resolve, reject) => {
700
- if (stream.stream === stdout || stream.stream === stderr) {
701
- // Inside workers, NodeJS actually queues writes destined for
702
- // stdout/stderr in a port that is only flushed on exit of the worker.
703
- //
704
- // In this case, we cannot attempt to wait for the promise.
705
- //
706
- // This code may have to be reworked for browsers.
707
- //
708
- // see: https://github.com/nodejs/node/blob/v22.12.0/lib/internal/worker/io.js#L288
709
- // see: https://github.com/nodejs/node/blob/v22.12.0/lib/internal/worker.js#L303
710
- // see: https://github.com/nodejs/node/blob/v22.12.0/typings/internalBinding/messaging.d.ts#L27
711
- stream.stream.write(payload);
697
+ ) {
698
+ throw new Error(
699
+ 'wasi-io trap: Cannot write more than permitted writable length'
700
+ );
701
+ }
702
+ stream.pollState.ready = false;
703
+ return (stream.flushPromise = new Promise((resolve, reject) => {
704
+ if (stream.stream === stdout || stream.stream === stderr) {
705
+ // Inside workers, NodeJS actually queues writes destined for
706
+ // stdout/stderr in a port that is only flushed on exit of the worker.
707
+ //
708
+ // In this case, we cannot attempt to wait for the promise.
709
+ //
710
+ // This code may have to be reworked for browsers.
711
+ //
712
+ // see: https://github.com/nodejs/node/blob/v22.12.0/lib/internal/worker/io.js#L288
713
+ // see: https://github.com/nodejs/node/blob/v22.12.0/lib/internal/worker.js#L303
714
+ // see: https://github.com/nodejs/node/blob/v22.12.0/typings/internalBinding/messaging.d.ts#L27
715
+ stream.stream.write(payload);
716
+ stream.flushPromise = null;
717
+ pollStateReady(stream.pollState);
718
+ resolve(BigInt(payload.byteLength));
719
+ } else {
720
+ stream.stream.write(payload, (err) => {
712
721
  stream.flushPromise = null;
713
722
  pollStateReady(stream.pollState);
723
+ if (err) {
724
+ return void reject(streamError(err));
725
+ }
714
726
  resolve(BigInt(payload.byteLength));
715
- } else {
716
- stream.stream.write(payload, (err) => {
717
- stream.flushPromise = null;
718
- pollStateReady(stream.pollState);
719
- if (err) {
720
- return void reject(streamError(err));
721
- }
722
- resolve(BigInt(payload.byteLength));
723
- });
724
- }
725
- }));
726
- }
727
- case OUTPUT_STREAM_FLUSH: {
728
- const stream = getStreamOrThrow(id);
729
- if (stream.flushPromise) {
730
- return;
727
+ });
731
728
  }
732
- stream.pollState.ready = false;
733
- stream.flushPromise = new Promise((resolve, reject) => {
734
- if (stream.stream === stdout || stream.stream === stderr) {
735
- // Inside workers, NodeJS actually queues writes destined for
736
- // stdout/stderr in a port that is only flushed on exit of the worker.
737
- //
738
- // In this case, we cannot attempt to wait for the promise.
739
- //
740
- // This code may have to be reworked for browsers.
741
- //
742
- // see: https://github.com/nodejs/node/blob/v22.12.0/lib/internal/worker/io.js#L288
743
- // see: https://github.com/nodejs/node/blob/v22.12.0/lib/internal/worker.js#L303
744
- // see: https://github.com/nodejs/node/blob/v22.12.0/typings/internalBinding/messaging.d.ts#L27
729
+ }));
730
+ }
731
+ case OUTPUT_STREAM_FLUSH: {
732
+ const stream = getStreamOrThrow(id);
733
+ if (stream.flushPromise) {
734
+ return;
735
+ }
736
+ stream.pollState.ready = false;
737
+ stream.flushPromise = new Promise((resolve, reject) => {
738
+ if (stream.stream === stdout || stream.stream === stderr) {
739
+ // Inside workers, NodeJS actually queues writes destined for
740
+ // stdout/stderr in a port that is only flushed on exit of the worker.
741
+ //
742
+ // In this case, we cannot attempt to wait for the promise.
743
+ //
744
+ // This code may have to be reworked for browsers.
745
+ //
746
+ // see: https://github.com/nodejs/node/blob/v22.12.0/lib/internal/worker/io.js#L288
747
+ // see: https://github.com/nodejs/node/blob/v22.12.0/lib/internal/worker.js#L303
748
+ // see: https://github.com/nodejs/node/blob/v22.12.0/typings/internalBinding/messaging.d.ts#L27
749
+ stream.flushPromise = null;
750
+ pollStateReady(stream.pollState);
751
+ resolve();
752
+ } else {
753
+ // For all other writes, we can perform the actual write and expect the write to complete
754
+ // and trigger the relevant callback
755
+ stream.stream.write(new Uint8Array([]), (err) => {
745
756
  stream.flushPromise = null;
746
757
  pollStateReady(stream.pollState);
758
+ if (err) {
759
+ return void reject(streamError(err));
760
+ }
747
761
  resolve();
748
- } else {
749
- // For all other writes, we can perform the actual write and expect the write to complete
750
- // and trigger the relevant callback
751
- stream.stream.write(new Uint8Array([]), (err) => {
752
- stream.flushPromise = null;
753
- pollStateReady(stream.pollState);
754
- if (err) {
755
- return void reject(streamError(err));
756
- }
757
- resolve();
758
- });
759
- }
760
- });
762
+ });
763
+ }
764
+ });
765
+ return stream.flushPromise;
766
+ }
767
+ case OUTPUT_STREAM_BLOCKING_FLUSH: {
768
+ const stream = getStreamOrThrow(id);
769
+ if (stream.flushPromise) {
761
770
  return stream.flushPromise;
762
771
  }
763
- case OUTPUT_STREAM_BLOCKING_FLUSH: {
764
- const stream = getStreamOrThrow(id);
765
- if (stream.flushPromise) {
766
- return stream.flushPromise;
772
+ return new Promise((resolve, reject) => {
773
+ if (stream.stream === stdout || stream.stream === stderr) {
774
+ // Inside workers, NodeJS actually queues writes destined for
775
+ // stdout/stderr in a port that is only flushed on exit of the worker.
776
+ //
777
+ // In this case, we cannot attempt to wait for the promise.
778
+ //
779
+ // This code may have to be reworked for browsers.
780
+ //
781
+ // see: https://github.com/nodejs/node/blob/v22.12.0/lib/internal/worker/io.js#L288
782
+ // see: https://github.com/nodejs/node/blob/v22.12.0/lib/internal/worker.js#L303
783
+ // see: https://github.com/nodejs/node/blob/v22.12.0/typings/internalBinding/messaging.d.ts#L27
784
+ resolve();
785
+ } else {
786
+ // For all other writes, we can perform the actual write and expect the write to complete
787
+ // and trigger the relevant callback
788
+ stream.stream.write(new Uint8Array([]), (err) =>
789
+ err ? reject(streamError(err)) : resolve()
790
+ );
767
791
  }
768
- return new Promise((resolve, reject) => {
769
- if (stream.stream === stdout || stream.stream === stderr) {
770
- // Inside workers, NodeJS actually queues writes destined for
771
- // stdout/stderr in a port that is only flushed on exit of the worker.
772
- //
773
- // In this case, we cannot attempt to wait for the promise.
774
- //
775
- // This code may have to be reworked for browsers.
776
- //
777
- // see: https://github.com/nodejs/node/blob/v22.12.0/lib/internal/worker/io.js#L288
778
- // see: https://github.com/nodejs/node/blob/v22.12.0/lib/internal/worker.js#L303
779
- // see: https://github.com/nodejs/node/blob/v22.12.0/typings/internalBinding/messaging.d.ts#L27
780
- resolve();
781
- } else {
782
- // For all other writes, we can perform the actual write and expect the write to complete
783
- // and trigger the relevant callback
784
- stream.stream.write(new Uint8Array([]), (err) =>
785
- err ? reject(streamError(err)) : resolve()
786
- );
787
- }
788
- });
789
- }
790
- case OUTPUT_STREAM_WRITE_ZEROES:
791
- return handle(
792
- OUTPUT_STREAM_WRITE | (call & CALL_TYPE_MASK),
793
- id,
794
- new Uint8Array(Number(payload))
795
- );
796
- case OUTPUT_STREAM_BLOCKING_WRITE_ZEROES_AND_FLUSH:
797
- return handle(
798
- OUTPUT_STREAM_BLOCKING_WRITE_AND_FLUSH |
792
+ });
793
+ }
794
+ case OUTPUT_STREAM_WRITE_ZEROES:
795
+ return handle(
796
+ OUTPUT_STREAM_WRITE | (call & CALL_TYPE_MASK),
797
+ id,
798
+ new Uint8Array(Number(payload))
799
+ );
800
+ case OUTPUT_STREAM_BLOCKING_WRITE_ZEROES_AND_FLUSH:
801
+ return handle(
802
+ OUTPUT_STREAM_BLOCKING_WRITE_AND_FLUSH |
799
803
  (call & CALL_TYPE_MASK),
800
- id,
801
- new Uint8Array(Number(payload))
802
- );
803
- case OUTPUT_STREAM_SPLICE: {
804
- const outputStream = getStreamOrThrow(id);
805
- const inputStream = getStreamOrThrow(payload.src);
806
- let bytesRemaining = Number(payload.len);
807
- let chunk;
808
- while (
809
- bytesRemaining > 0 &&
804
+ id,
805
+ new Uint8Array(Number(payload))
806
+ );
807
+ case OUTPUT_STREAM_SPLICE: {
808
+ const outputStream = getStreamOrThrow(id);
809
+ const inputStream = getStreamOrThrow(payload.src);
810
+ let bytesRemaining = Number(payload.len);
811
+ let chunk;
812
+ while (
813
+ bytesRemaining > 0 &&
810
814
  (chunk = inputStream.stream.read(
811
815
  Math.min(
812
816
  outputStream.writableHighWaterMark -
@@ -814,131 +818,131 @@ function handle(call, id, payload) {
814
818
  bytesRemaining
815
819
  )
816
820
  ))
817
- ) {
818
- bytesRemaining -= chunk.byteLength;
819
- outputStream.stream.write(chunk);
820
- }
821
- if (inputStream.stream.errored) {
822
- throw streamError(inputStream.stream.errored);
823
- }
824
- if (outputStream.stream.errored) {
825
- throw streamError(outputStream.stream.errored);
826
- }
827
- return payload.len - BigInt(bytesRemaining);
821
+ ) {
822
+ bytesRemaining -= chunk.byteLength;
823
+ outputStream.stream.write(chunk);
824
+ }
825
+ if (inputStream.stream.errored) {
826
+ throw streamError(inputStream.stream.errored);
827
+ }
828
+ if (outputStream.stream.errored) {
829
+ throw streamError(outputStream.stream.errored);
830
+ }
831
+ return payload.len - BigInt(bytesRemaining);
832
+ }
833
+ case OUTPUT_STREAM_SUBSCRIBE:
834
+ return createPoll(streams.get(id).pollState);
835
+ case OUTPUT_STREAM_BLOCKING_SPLICE: {
836
+ const outputStream = getStreamOrThrow(id);
837
+ let promise = Promise.resolve();
838
+ let resolve, reject;
839
+ if (outputStream.stream.writableNeedDrain) {
840
+ promise = new Promise((_resolve, _reject) => {
841
+ outputStream.stream
842
+ .once('drain', (resolve = _resolve))
843
+ .once('error', (reject = _reject));
844
+ }).then(
845
+ () => {
846
+ outputStream.stream.off('error', reject);
847
+ },
848
+ (err) => {
849
+ outputStream.stream.off('drain', resolve);
850
+ throw streamError(err);
851
+ }
852
+ );
828
853
  }
829
- case OUTPUT_STREAM_SUBSCRIBE:
830
- return createPoll(streams.get(id).pollState);
831
- case OUTPUT_STREAM_BLOCKING_SPLICE: {
832
- const outputStream = getStreamOrThrow(id);
833
- let promise = Promise.resolve();
834
- let resolve, reject;
835
- if (outputStream.stream.writableNeedDrain) {
836
- promise = new Promise((_resolve, _reject) => {
837
- outputStream.stream
838
- .once('drain', (resolve = _resolve))
854
+ const inputStream = getStreamOrThrow(payload.src);
855
+ if (!inputStream.stream.readable) {
856
+ promise = promise.then(() =>
857
+ new Promise((_resolve, _reject) => {
858
+ inputStream.stream
859
+ .once('readable', (resolve = _resolve))
839
860
  .once('error', (reject = _reject));
840
861
  }).then(
841
862
  () => {
842
- outputStream.stream.off('error', reject);
863
+ inputStream.stream.off('error', reject);
843
864
  },
844
865
  (err) => {
845
- outputStream.stream.off('drain', resolve);
866
+ inputStream.stream.off('readable', resolve);
846
867
  throw streamError(err);
847
868
  }
848
- );
849
- }
850
- const inputStream = getStreamOrThrow(payload.src);
851
- if (!inputStream.stream.readable) {
852
- promise = promise.then(() =>
853
- new Promise((_resolve, _reject) => {
854
- inputStream.stream
855
- .once('readable', (resolve = _resolve))
856
- .once('error', (reject = _reject));
857
- }).then(
858
- () => {
859
- inputStream.stream.off('error', reject);
860
- },
861
- (err) => {
862
- inputStream.stream.off('readable', resolve);
863
- throw streamError(err);
864
- }
865
- )
866
- );
867
- }
868
- return promise.then(() =>
869
- handle(OUTPUT_STREAM_SPLICE, id, payload)
869
+ )
870
870
  );
871
871
  }
872
- case OUTPUT_STREAM_DISPOSE: {
873
- const stream = streams.get(id);
874
- verifyPollsDroppedForDrop(stream.pollState, 'output stream');
875
- stream.stream.end();
876
- streams.delete(id);
877
- return;
878
- }
872
+ return promise.then(() =>
873
+ handle(OUTPUT_STREAM_SPLICE, id, payload)
874
+ );
875
+ }
876
+ case OUTPUT_STREAM_DISPOSE: {
877
+ const stream = streams.get(id);
878
+ verifyPollsDroppedForDrop(stream.pollState, 'output stream');
879
+ stream.stream.end();
880
+ streams.delete(id);
881
+ return;
882
+ }
879
883
 
880
- case POLL_POLLABLE_READY:
881
- return polls.get(id).ready;
882
- case POLL_POLLABLE_BLOCK:
883
- payload = [id];
884
+ case POLL_POLLABLE_READY:
885
+ return polls.get(id).ready;
886
+ case POLL_POLLABLE_BLOCK:
887
+ payload = [id];
884
888
  // [intentional case fall-through]
885
- case POLL_POLL_LIST: {
886
- if (payload.length === 0) {
887
- throw new Error('wasi-io trap: attempt to poll on empty list');
889
+ case POLL_POLL_LIST: {
890
+ if (payload.length === 0) {
891
+ throw new Error('wasi-io trap: attempt to poll on empty list');
892
+ }
893
+ const doneList = [];
894
+ const pollList = payload.map((pollId) => polls.get(pollId));
895
+ for (const [idx, pollState] of pollList.entries()) {
896
+ pollStateCheck(pollState);
897
+ if (pollState.ready) {
898
+ doneList.push(idx);
888
899
  }
889
- const doneList = [];
890
- const pollList = payload.map((pollId) => polls.get(pollId));
900
+ }
901
+ if (doneList.length > 0) {
902
+ return new Uint32Array(doneList);
903
+ }
904
+ let readyPromiseResolve;
905
+ const readyPromise = new Promise(
906
+ (resolve) => void (readyPromiseResolve = resolve)
907
+ );
908
+ for (const poll of pollList) {
909
+ poll.listener = readyPromiseResolve;
910
+ }
911
+ return readyPromise.then(() => {
891
912
  for (const [idx, pollState] of pollList.entries()) {
892
- pollStateCheck(pollState);
913
+ pollState.listener = null;
893
914
  if (pollState.ready) {
894
915
  doneList.push(idx);
895
916
  }
896
917
  }
897
- if (doneList.length > 0) {
898
- return new Uint32Array(doneList);
899
- }
900
- let readyPromiseResolve;
901
- const readyPromise = new Promise(
902
- (resolve) => void (readyPromiseResolve = resolve)
918
+ return new Uint32Array(doneList);
919
+ });
920
+ }
921
+ case POLL_POLLABLE_DISPOSE:
922
+ if (!polls.delete(id)) {
923
+ throw new Error(
924
+ `wasi-io trap: Disposed a poll ${id} that does not exist`
903
925
  );
904
- for (const poll of pollList) {
905
- poll.listener = readyPromiseResolve;
906
- }
907
- return readyPromise.then(() => {
908
- for (const [idx, pollState] of pollList.entries()) {
909
- pollState.listener = null;
910
- if (pollState.ready) {
911
- doneList.push(idx);
912
- }
913
- }
914
- return new Uint32Array(doneList);
915
- });
916
926
  }
917
- case POLL_POLLABLE_DISPOSE:
918
- if (!polls.delete(id)) {
919
- throw new Error(
920
- `wasi-io trap: Disposed a poll ${id} that does not exist`
921
- );
922
- }
923
- return;
927
+ return;
924
928
 
925
- case FUTURE_TAKE_VALUE:
926
- return futureTakeValue(id);
929
+ case FUTURE_TAKE_VALUE:
930
+ return futureTakeValue(id);
927
931
 
928
- case FUTURE_SUBSCRIBE: {
929
- const { pollState } = futures.get(id);
930
- const pollId = ++pollCnt;
931
- polls.set(pollId, pollState);
932
- return pollId;
933
- }
934
- case FUTURE_DISPOSE:
935
- return void futureDispose(id, true);
936
- default:
937
- throw new Error(
938
- `wasi-io trap: Unknown call ${call} (${reverseMap[call]}) with type ${
939
- reverseMap[call & CALL_TYPE_MASK]
940
- }`
941
- );
932
+ case FUTURE_SUBSCRIBE: {
933
+ const { pollState } = futures.get(id);
934
+ const pollId = ++pollCnt;
935
+ polls.set(pollId, pollState);
936
+ return pollId;
937
+ }
938
+ case FUTURE_DISPOSE:
939
+ return void futureDispose(id, true);
940
+ default:
941
+ throw new Error(
942
+ `wasi-io trap: Unknown call ${call} (${reverseMap[call]}) with type ${
943
+ reverseMap[call & CALL_TYPE_MASK]
944
+ }`
945
+ );
942
946
  }
943
947
  }
944
948