@intentic/sandbox-contract 1.297.0 → 1.298.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentic/sandbox-contract",
3
- "version": "1.297.0",
3
+ "version": "1.298.0",
4
4
  "description": "oRPC wire contract for the intentic sandbox daemon, shared by the daemon and its browser client",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -207,10 +207,10 @@
207
207
  }
208
208
  },
209
209
  "dependencies": {
210
- "@intentic/base": "1.297.0",
211
- "@intentic/constants": "1.297.0",
212
- "@intentic/extension-manifest": "1.297.0",
213
- "@intentic/registry": "1.297.0",
210
+ "@intentic/base": "1.298.0",
211
+ "@intentic/constants": "1.298.0",
212
+ "@intentic/extension-manifest": "1.298.0",
213
+ "@intentic/registry": "1.298.0",
214
214
  "@orpc/contract": "1.14.13",
215
215
  "tslib": "2.8.1",
216
216
  "zod": "4.5.4"
@@ -49,6 +49,11 @@ const firstChunk = gate();
49
49
  const secondSent = gate();
50
50
  const uploadStarted = gate();
51
51
 
52
+ const floodReleased = gate();
53
+
54
+ // One entry per live /flood response, opened once that response's write queue is non-empty.
55
+ const floodPressure: Promise<void>[] = [];
56
+
52
57
  // 64KB per write, keeping node's write queue non-empty so a reset lands on an unfinished write.
53
58
  const FLOOD_CHUNK = Buffer.alloc(64 * 1024, 7);
54
59
 
@@ -95,14 +100,19 @@ const routes: Record<string, Route> = {
95
100
  response.on("close", () => cancelled.open(response.writableEnded ? "ended" : "aborted"));
96
101
  },
97
102
  // Large enough that writes are still pending when the client resets mid-stream.
98
- "/flood": (_request, response) => {
103
+ "/flood": async (_request, response) => {
104
+ const pressured = gate();
105
+ floodPressure.push(pressured.opened);
99
106
  response.writeHead(200, { "content-type": "application/octet-stream" });
107
+ // One byte now, the flood only once every stream has had its byte: a stream's DATA head-of-line blocks a later
108
+ // stream's HEADERS on the one h2 session, which starves the last of eight for seconds on a loaded machine.
109
+ response.write(FLOOD_CHUNK.subarray(0, 1));
110
+ await floodReleased.opened;
100
111
  const pump = (): void => {
101
- while (response.write(FLOOD_CHUNK)) {
102
- if (response.writableEnded) {
103
- return;
104
- }
112
+ while (response.write(FLOOD_CHUNK) && !response.writableEnded) {
113
+ // Writes until the queue backs up; `pressured` then says the shutdown has something to land on.
105
114
  }
115
+ pressured.open();
106
116
  };
107
117
  response.on("drain", pump);
108
118
  pump();
@@ -391,16 +401,20 @@ test("a shutdown landing on top of pending writes neither crashes nor wedges the
391
401
  const ownPort = await listen(own.server);
392
402
 
393
403
  // All eight stay live: resetting some first would drain the pending-write pressure the shutdown needs to land on.
394
- const flooding = Array.from({ length: 8 }, () =>
395
- new Promise<void>((resolve) => {
396
- const request = h1Request({ host: "127.0.0.1", port: ownPort, path: "/flood", headers: { host: HOST } }, (response) => {
397
- response.once("data", () => resolve());
398
- });
399
- request.on("error", () => resolve());
400
- request.end();
401
- }),
402
- );
404
+ const flooding = Array.from({ length: 8 }, () => {
405
+ const opened = gate();
406
+ const request = h1Request({ host: "127.0.0.1", port: ownPort, path: "/flood", headers: { host: HOST } }, (response) => {
407
+ response.once("data", () => opened.open());
408
+ });
409
+ request.on("error", () => opened.open());
410
+ request.end();
411
+ return opened.opened;
412
+ });
413
+
414
+ // Every stream open before any of them floods, and every one of them backed up before the shutdown lands.
403
415
  await Promise.all(flooding);
416
+ floodReleased.open();
417
+ await Promise.all(floodPressure);
404
418
 
405
419
  own.close();
406
420
  await new Promise((resolve) => setTimeout(resolve, 400));