@agoric/internal 0.3.3-dev-4ac8a49.0.4ac8a49 → 0.3.3-dev-28c592b.0.28c592b

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": "@agoric/internal",
3
- "version": "0.3.3-dev-4ac8a49.0.4ac8a49",
3
+ "version": "0.3.3-dev-28c592b.0.28c592b",
4
4
  "description": "Externally unsupported utilities internal to agoric-sdk",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -20,7 +20,7 @@
20
20
  "lint:types": "yarn run -T tsc"
21
21
  },
22
22
  "dependencies": {
23
- "@agoric/base-zone": "0.1.1-dev-4ac8a49.0.4ac8a49",
23
+ "@agoric/base-zone": "0.1.1-dev-28c592b.0.28c592b",
24
24
  "@endo/cache-map": "^1.1.0",
25
25
  "@endo/common": "^1.2.13",
26
26
  "@endo/compartment-mapper": "^1.6.3",
@@ -38,7 +38,7 @@
38
38
  "jessie.js": "^0.3.4"
39
39
  },
40
40
  "devDependencies": {
41
- "@agoric/cosmic-proto": "0.4.1-dev-4ac8a49.0.4ac8a49",
41
+ "@agoric/cosmic-proto": "0.4.1-dev-28c592b.0.28c592b",
42
42
  "@endo/exo": "^1.5.12",
43
43
  "@endo/init": "^1.1.12",
44
44
  "@endo/ses-ava": "^1.3.2",
@@ -66,5 +66,5 @@
66
66
  "typeCoverage": {
67
67
  "atLeast": 92.84
68
68
  },
69
- "gitHead": "4ac8a4962fdaba6b98d4f171e2e0701026ca753e"
69
+ "gitHead": "28c592b4b262dcb4a35c9fa4adbda76db0858953"
70
70
  }
@@ -1,9 +1,11 @@
1
- export function fsStreamReady(stream: ReadStream | WriteStream | Socket): Promise<void>;
1
+ export function fsStreamReady(stream: StreamLike): Promise<void>;
2
2
  export function makeFsStreamWriter(filePath: string | undefined | null): Promise<{
3
3
  write: (data: any) => Promise<void>;
4
4
  flush: () => Promise<void>;
5
5
  close: () => Promise<void>;
6
6
  } | undefined>;
7
+ export type StreamLike = ReadStream | WriteStream | Socket;
8
+ export type EventName = "drain" | "ready";
7
9
  export type FsStreamWriter = NonNullable<Awaited<ReturnType<typeof makeFsStreamWriter>>>;
8
10
  import type { ReadStream } from 'fs';
9
11
  import type { WriteStream } from 'fs';
@@ -1 +1 @@
1
- {"version":3,"file":"fs-stream.d.ts","sourceRoot":"","sources":["fs-stream.js"],"names":[],"mappings":"AAcO,sCAHI,UAAU,GAAG,WAAW,GAAG,MAAM,GAC/B,OAAO,CAAC,IAAI,CAAC,CAgCtB;AAmDG,6CADK,MAAM,GAAG,SAAS,GAAG,IAAI;;;;eAsEpC;6BAvEa,WAAW,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC,CAAC;gCAxF5C,IAAI;iCACH,IAAI;4BACT,KAAK"}
1
+ {"version":3,"file":"fs-stream.d.ts","sourceRoot":"","sources":["fs-stream.js"],"names":[],"mappings":"AAiBO,sCAHI,UAAU,GACR,OAAO,CAAC,IAAI,CAAC,CAgCtB;AA8GG,6CADK,MAAM,GAAG,SAAS,GAAG,IAAI;;;;eAsEpC;yBAxNa,UAAU,GAAG,WAAW,GAAG,MAAM;wBACjC,OAAO,GAAG,OAAO;6BAgJjB,WAAW,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC,CAAC;gCAtJ5C,IAAI;iCACH,IAAI;4BACT,KAAK"}
@@ -8,8 +8,11 @@ import { promisify } from 'node:util';
8
8
  * @import {Socket} from 'net';
9
9
  */
10
10
 
11
+ /** @typedef {ReadStream | WriteStream | Socket} StreamLike */
12
+ /** @typedef {'drain' | 'ready'} EventName */
13
+
11
14
  /**
12
- * @param {ReadStream | WriteStream | Socket} stream
15
+ * @param {StreamLike} stream
13
16
  * @returns {Promise<void>}
14
17
  */
15
18
  export const fsStreamReady = stream =>
@@ -45,13 +48,15 @@ export const fsStreamReady = stream =>
45
48
  });
46
49
 
47
50
  /**
48
- * Wait for a stream event and reject on stream error first.
51
+ * Subscribe fresh listeners for a single stream event and reject on stream
52
+ * error first.
49
53
  *
50
- * @param {ReadStream | WriteStream | Socket} stream
51
- * @param {'drain' | 'ready'} eventName
54
+ * @param {StreamLike} stream
55
+ * @param {EventName} eventName
56
+ * @param {() => void} [onCleanup] called when the event is emitted or an error occurs, after listeners are removed
52
57
  * @returns {Promise<void>}
53
58
  */
54
- const onceWithError = (stream, eventName) =>
59
+ const subscribeOnceWithError = (stream, eventName, onCleanup = () => {}) =>
55
60
  new Promise((resolve, reject) => {
56
61
  const onEvent = () => {
57
62
  cleanup();
@@ -65,11 +70,68 @@ const onceWithError = (stream, eventName) =>
65
70
  const cleanup = () => {
66
71
  stream.off(eventName, onEvent);
67
72
  stream.off('error', onError);
73
+ onCleanup();
68
74
  };
69
75
  stream.on(eventName, onEvent);
70
76
  stream.on('error', onError);
71
77
  });
72
78
 
79
+ /**
80
+ * Memoize promises to prevent multiple subscriptions to the same event on the
81
+ * same stream. This is necessary to prevent:
82
+ *
83
+ * (node:1224) MaxListenersExceededWarning: Possible EventEmitter memory leak
84
+ * detected. 11 drain listeners added to [WriteStream]. MaxListeners is 10. Use
85
+ * emitter.setMaxListeners() to increase limit
86
+ *
87
+ * @param {(stream: StreamLike,
88
+ * eventName: EventName, onDone?: () => void) => Promise<void>} doOnceWithError
89
+ * @returns {(stream: StreamLike,
90
+ * eventName: EventName) => Promise<void>}
91
+ */
92
+ const makeMemoizedOnceWithError = doOnceWithError => {
93
+ /**
94
+ * @type {Map<string, WeakMap<StreamLike, Promise<void>>>}
95
+ */
96
+ const promiseFromEventAndStream = new Map();
97
+
98
+ /**
99
+ * Wait for a stream event and reject on stream error first.
100
+ *
101
+ * @param {StreamLike} stream
102
+ * @param {EventName} eventName
103
+ * @returns {Promise<void>}
104
+ */
105
+ const memoizedOnceWithError = (stream, eventName) => {
106
+ let promiseFromStream = promiseFromEventAndStream.get(eventName);
107
+ if (!promiseFromStream) {
108
+ promiseFromStream = new WeakMap();
109
+ promiseFromEventAndStream.set(eventName, promiseFromStream);
110
+ }
111
+ /** @type {Promise<void> | undefined} */
112
+ let promise = promiseFromStream.get(stream);
113
+ if (promise) {
114
+ return promise;
115
+ }
116
+ promise = doOnceWithError(stream, eventName, () =>
117
+ promiseFromStream.delete(stream),
118
+ );
119
+ promiseFromStream.set(stream, promise);
120
+ return promise;
121
+ };
122
+
123
+ return memoizedOnceWithError;
124
+ };
125
+
126
+ /**
127
+ * Wait for a stream event and reject on stream error first.
128
+ *
129
+ * @param {StreamLike} stream
130
+ * @param {EventName} eventName
131
+ * @returns {Promise<void>}
132
+ */
133
+ const onceWithError = makeMemoizedOnceWithError(subscribeOnceWithError);
134
+
73
135
  /**
74
136
  * @param {WriteStream | Socket} stream
75
137
  * @param {string | Uint8Array} data