@reporters/mux 1.0.0 → 1.1.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/CHANGELOG.md +32 -0
- package/README.md +25 -1
- package/dist/index.d.ts +14 -2
- package/dist/index.js +17 -5
- package/package.json +3 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [1.1.0](https://github.com/MoLow/reporters/compare/mux-v1.0.0...mux-v1.1.0) (2026-07-02)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **mux:** start every sink before reporters consume events ([#221](https://github.com/MoLow/reporters/issues/221)) ([c5ef14f](https://github.com/MoLow/reporters/commit/c5ef14fbe0357a4f756fb170f69876396806abd6))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* **web:** stay a pure emitter under mux via symbol-declared default options ([#217](https://github.com/MoLow/reporters/issues/217)) ([96a7d14](https://github.com/MoLow/reporters/commit/96a7d14e82f69c6dc6d8d363645f94c09733fbda))
|
|
14
|
+
|
|
15
|
+
## 1.0.0 (2026-07-02)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Features
|
|
19
|
+
|
|
20
|
+
* @reporters/mux environment-aware reporter routing + web NDJSON redesign ([#203](https://github.com/MoLow/reporters/issues/203)) ([82d1e20](https://github.com/MoLow/reporters/commit/82d1e205949e6daa90b13aec5838ddb0c7e931a5))
|
|
21
|
+
* @reporters/sink — gist + s3 delivery sinks for viewing CI runs ([#211](https://github.com/MoLow/reporters/issues/211)) ([4b254b6](https://github.com/MoLow/reporters/commit/4b254b629236393b25c5903a976dbebfaf5ebc1a))
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
### Documentation
|
|
25
|
+
|
|
26
|
+
* flag-order fixes and the gh collapsible actions log ([#216](https://github.com/MoLow/reporters/issues/216)) ([131f410](https://github.com/MoLow/reporters/commit/131f4107712d6d0b899d3b8ca7a39496b6e05276))
|
|
27
|
+
* rewrite package READMEs with demos and clearer positioning ([#209](https://github.com/MoLow/reporters/issues/209)) ([e1265e5](https://github.com/MoLow/reporters/commit/e1265e5f6b8a0f34b80ef7ee725cede4ed16b6da))
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
### Miscellaneous Chores
|
|
31
|
+
|
|
32
|
+
* route this repo's tests through @reporters/mux ([#207](https://github.com/MoLow/reporters/issues/207)) ([85a5973](https://github.com/MoLow/reporters/commit/85a59737bc3d631b0293edf343b77fd82e0c459d))
|
package/README.md
CHANGED
|
@@ -60,7 +60,12 @@ Transform-stream reporters (like `@reporters/gh`) are supported as route reporte
|
|
|
60
60
|
`@reporters/web` accepts `{ open: boolean }`); most reporters need none.
|
|
61
61
|
- `sink` — `'stdout'`, `'stderr'`, a file path, or a `Sink` object.
|
|
62
62
|
- `open` — open the sink's viewer URL in a browser. Defaults to on locally, off
|
|
63
|
-
in CI. `open: false` opts out; `REPORTERS_OPEN=1|0` forces it.
|
|
63
|
+
in CI. `open: false` opts out; `REPORTERS_OPEN=1|0` forces it. This is the
|
|
64
|
+
only open gate: a reporter can declare default options for when it runs under
|
|
65
|
+
mux — attached to the reporter function under
|
|
66
|
+
`Symbol.for('reporters.mux.defaultOptions')`, merged beneath the route's
|
|
67
|
+
`options` — which is how reporters that self-open standalone (like
|
|
68
|
+
`@reporters/web`, declaring `{ open: false }`) stay pure emitters here.
|
|
64
69
|
|
|
65
70
|
### Profile resolution
|
|
66
71
|
|
|
@@ -95,3 +100,22 @@ Built in: `'stdout'`, `'stderr'`, and file paths. Beyond those:
|
|
|
95
100
|
|
|
96
101
|
When a sink exposes a `viewerUrl`, mux prints `report at <url>` to stderr and —
|
|
97
102
|
on GitHub Actions — adds a **View report** link to the job summary.
|
|
103
|
+
|
|
104
|
+
Reporters can consume a sink's viewer URL too: keep the sink instance and pass
|
|
105
|
+
a lazy getter into another route's `options`. Every sink in the profile has
|
|
106
|
+
started before any reporter receives events, so the getter is live from the
|
|
107
|
+
first event on (note `options` reach function reporters only — stream
|
|
108
|
+
reporters have no options channel):
|
|
109
|
+
|
|
110
|
+
```js
|
|
111
|
+
import { s3 } from '@reporters/sink';
|
|
112
|
+
|
|
113
|
+
const upload = s3({ bucket: 'ci-runs' });
|
|
114
|
+
|
|
115
|
+
export default {
|
|
116
|
+
ci: [
|
|
117
|
+
{ reporter: '@reporters/web', sink: upload },
|
|
118
|
+
{ reporter: './my-reporter.mjs', options: { viewerUrl: () => upload.viewerUrl() }, sink: 'stdout' },
|
|
119
|
+
],
|
|
120
|
+
};
|
|
121
|
+
```
|
package/dist/index.d.ts
CHANGED
|
@@ -40,7 +40,12 @@ interface Sink {
|
|
|
40
40
|
flush?(): Promise<void>;
|
|
41
41
|
/** The run ended; release resources. */
|
|
42
42
|
close(): Promise<void>;
|
|
43
|
-
/**
|
|
43
|
+
/**
|
|
44
|
+
* How a human views what was written, if anything. Valid once `start()` has
|
|
45
|
+
* resolved; under mux, every sink in the profile has started before any
|
|
46
|
+
* reporter receives events, so a getter wired into another route's
|
|
47
|
+
* `options` is live from the first event.
|
|
48
|
+
*/
|
|
44
49
|
viewerUrl?(): string | undefined;
|
|
45
50
|
}
|
|
46
51
|
type SinkSpec = string | Sink;
|
|
@@ -61,6 +66,13 @@ interface Route {
|
|
|
61
66
|
/** Map of profile name -> the routes active under that profile. */
|
|
62
67
|
type MuxConfig = Record<string, Route[]>;
|
|
63
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Well-known key under which a reporter function declares the options it wants
|
|
71
|
+
* by default when driven through mux (a route's own `options` win key-by-key).
|
|
72
|
+
* Lets a reporter behave differently under mux without env coupling — e.g.
|
|
73
|
+
* `@reporters/web` declares `{ open: false }` so the sink owns viewing.
|
|
74
|
+
*/
|
|
75
|
+
declare const MUX_DEFAULT_OPTIONS: unique symbol;
|
|
64
76
|
/** A reporter function, a stream instance, or a module specifier to `import()`. */
|
|
65
77
|
declare function resolveReporter(reporter: Reporter | Duplex | string): Promise<Reporter | Duplex>;
|
|
66
78
|
/**
|
|
@@ -76,4 +88,4 @@ declare function runRoutes(source: AsyncIterable<TestEvent>, config: MuxConfig,
|
|
|
76
88
|
*/
|
|
77
89
|
declare function mux(source: AsyncIterable<TestEvent>): AsyncGenerator<string>;
|
|
78
90
|
|
|
79
|
-
export { type MuxConfig, type Reporter, type Route, type Sink, type SinkSpec, mux as default, resolveReporter, runRoutes };
|
|
91
|
+
export { MUX_DEFAULT_OPTIONS, type MuxConfig, type Reporter, type Route, type Sink, type SinkSpec, mux as default, resolveReporter, runRoutes };
|
package/dist/index.js
CHANGED
|
@@ -183,6 +183,12 @@ function announce(url, env = process.env) {
|
|
|
183
183
|
var internals = { openInBrowser, announce };
|
|
184
184
|
|
|
185
185
|
// src/index.ts
|
|
186
|
+
var MUX_DEFAULT_OPTIONS = /* @__PURE__ */ Symbol.for("reporters.mux.defaultOptions");
|
|
187
|
+
function routeOptions(reporter, route) {
|
|
188
|
+
const defaults = reporter[MUX_DEFAULT_OPTIONS];
|
|
189
|
+
if (!defaults) return route.options;
|
|
190
|
+
return { ...defaults, ...route.options };
|
|
191
|
+
}
|
|
186
192
|
function isStreamReporter(value) {
|
|
187
193
|
return typeof value === "object" && value !== null && typeof value.pipe === "function";
|
|
188
194
|
}
|
|
@@ -196,12 +202,15 @@ async function resolveReporter(reporter) {
|
|
|
196
202
|
async function runRoutes(source, config, env = process.env, open = internals.openInBrowser) {
|
|
197
203
|
const routes = resolveProfile(config, env);
|
|
198
204
|
const streams = broadcast(source, routes.length);
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
205
|
+
const sinks = routes.map((route) => resolveSink(route.sink));
|
|
206
|
+
const starts = sinks.map((sink) => sink.start?.());
|
|
207
|
+
await Promise.allSettled(starts);
|
|
208
|
+
const results = await Promise.allSettled(routes.map(async (route, i) => {
|
|
209
|
+
const sink = sinks[i];
|
|
203
210
|
try {
|
|
204
|
-
|
|
211
|
+
await starts[i];
|
|
212
|
+
const reporter = await resolveReporter(route.reporter);
|
|
213
|
+
const stage = typeof reporter === "function" ? (src) => reporter(src, routeOptions(reporter, route)) : reporter;
|
|
205
214
|
const url = sink.viewerUrl?.();
|
|
206
215
|
if (url) {
|
|
207
216
|
internals.announce(url, env);
|
|
@@ -214,12 +223,15 @@ async function runRoutes(source, config, env = process.env, open = internals.ope
|
|
|
214
223
|
await sink.close();
|
|
215
224
|
}
|
|
216
225
|
}));
|
|
226
|
+
const failure = results.find((r) => r.status === "rejected");
|
|
227
|
+
if (failure) throw failure.reason;
|
|
217
228
|
}
|
|
218
229
|
async function* mux(source) {
|
|
219
230
|
const config = await loadConfig();
|
|
220
231
|
await runRoutes(source, config);
|
|
221
232
|
}
|
|
222
233
|
export {
|
|
234
|
+
MUX_DEFAULT_OPTIONS,
|
|
223
235
|
mux as default,
|
|
224
236
|
resolveReporter,
|
|
225
237
|
runRoutes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reporters/mux",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Environment-aware routing reporter for `node:test`: tee the event stream to multiple reporters and sinks",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"test": "node --test-reporter=@reporters/mux --test"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@reporters/tree-core": "
|
|
32
|
+
"@reporters/tree-core": "^0.0.0",
|
|
33
33
|
"tsup": "^8.5.0",
|
|
34
34
|
"typescript": "^5.7.0"
|
|
35
35
|
},
|
|
@@ -40,4 +40,4 @@
|
|
|
40
40
|
"repository": "https://github.com/MoLow/reporters.git",
|
|
41
41
|
"author": "Moshe Atlow",
|
|
42
42
|
"license": "MIT"
|
|
43
|
-
}
|
|
43
|
+
}
|