@johnhenry/wsh 0.7.0 → 0.13.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/src/session.mjs CHANGED
@@ -131,6 +131,16 @@ export class WshSession {
131
131
  /** @type {object|null} */
132
132
  #lastTermDiff = null;
133
133
 
134
+ /**
135
+ * Queue of received FileChunk payloads not yet consumed by
136
+ * _readFileChunk(). 'file'-kind sessions only.
137
+ * @type {Array<object>}
138
+ */
139
+ #fileChunkQueue = [];
140
+
141
+ /** @type {{resolve: function, reject: function}|null} */
142
+ #fileChunkWaiter = null;
143
+
134
144
  // ── Constructor ─────────────────────────────────────────────────────
135
145
 
136
146
  /**
@@ -358,6 +368,7 @@ export class WshSession {
358
368
 
359
369
  this.#stdinWriter = null;
360
370
  this.#stdoutReadable = null;
371
+ this.#resolvePendingFileChunk(null);
361
372
  this.#emitClose();
362
373
  }
363
374
 
@@ -382,6 +393,17 @@ export class WshSession {
382
393
  break;
383
394
  }
384
395
 
396
+ case MSG.FILE_CHUNK: {
397
+ if (this.#fileChunkWaiter) {
398
+ const { resolve } = this.#fileChunkWaiter;
399
+ this.#fileChunkWaiter = null;
400
+ resolve(msg);
401
+ } else {
402
+ this.#fileChunkQueue.push(msg);
403
+ }
404
+ break;
405
+ }
406
+
385
407
  case MSG.EXIT: {
386
408
  this.#exitCode = msg.code ?? -1;
387
409
  try {
@@ -399,6 +421,7 @@ export class WshSession {
399
421
  this.#abort.abort();
400
422
  this.#virtualBackend?.close();
401
423
  this.#releaseStreams();
424
+ this.#resolvePendingFileChunk(null);
402
425
  this.#emitClose();
403
426
  }
404
427
  break;
@@ -469,6 +492,45 @@ export class WshSession {
469
492
  }
470
493
  }
471
494
 
495
+ // ── File transfer ────────────────────────────────────────────────────
496
+
497
+ /**
498
+ * Wait for the next FileChunk control message on this channel.
499
+ * Used by WshClient.upload/download for 'file'-kind sessions — file
500
+ * transfer moves bytes as ordinary FileChunk control messages rather
501
+ * than through write()/read(), so it works the same whether the
502
+ * channel's data plane is stream- or virtual-backed.
503
+ *
504
+ * Returns `null` if the session closes before another chunk arrives
505
+ * (a truncated transfer, distinct from a chunk with is_final=true).
506
+ *
507
+ * @returns {Promise<object|null>}
508
+ * @internal
509
+ */
510
+ async _readFileChunk() {
511
+ if (this.#fileChunkQueue.length > 0) {
512
+ return this.#fileChunkQueue.shift();
513
+ }
514
+ if (this.#state === STATE_CLOSED) {
515
+ return null;
516
+ }
517
+ return new Promise((resolve, reject) => {
518
+ this.#fileChunkWaiter = { resolve, reject };
519
+ });
520
+ }
521
+
522
+ /**
523
+ * Resolve (or clear) any pending _readFileChunk() waiter.
524
+ * @private
525
+ */
526
+ #resolvePendingFileChunk(value) {
527
+ if (this.#fileChunkWaiter) {
528
+ const { resolve } = this.#fileChunkWaiter;
529
+ this.#fileChunkWaiter = null;
530
+ resolve(value);
531
+ }
532
+ }
533
+
472
534
  // ── Data stream pump ────────────────────────────────────────────────
473
535
 
474
536
  /**