@bymax-one/nest-logger 1.2.6 → 1.2.9

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.
@@ -69,12 +69,55 @@ interface ILogDestination {
69
69
  *
70
70
  * @param payload — Newline-terminated JSON entry, UTF-8 encoded.
71
71
  */
72
- write(payload: string): void | Promise<void>;
72
+ write(payload: string): void | PromiseLike<void>;
73
73
  /**
74
74
  * Optional lifecycle hook — called once during NestJS module init.
75
75
  * Use for opening connections, allocating buffers, scheduling flushers.
76
76
  */
77
- onInit?(): void | Promise<void>;
77
+ onInit?(): void | PromiseLike<void>;
78
+ /**
79
+ * Optional lifecycle hook — called once after EVERY destination's `onInit`
80
+ * has settled, successfully or not, and before the bootstrap entry is emitted.
81
+ *
82
+ * Only useful to a destination that holds entries written before its own
83
+ * `onInit` ran: until this point it cannot know what became of them. The
84
+ * fan-out hands each entry to every registered destination whose level accepts
85
+ * it, so a held copy may be a SECOND copy.
86
+ *
87
+ * **This is a deduplication signal, not a proof — and the difference is the
88
+ * whole contract.** A held copy may be a second copy, so emitting it duplicates
89
+ * a line and dropping it may lose one. The flag says which risk is smaller, as
90
+ * far as this library can see; it does not say the entry is safe.
91
+ *
92
+ * The library's own destinations act on it by discarding when it is `true` and
93
+ * emitting otherwise, because a duplicated boot line is a smaller harm than a
94
+ * lost one. **A destination that cannot tolerate ANY loss should emit
95
+ * regardless** — see the accounting limits on the flag below.
96
+ *
97
+ * Called on failed destinations too, which is the point: the one that could not
98
+ * initialize is exactly the one still holding entries.
99
+ *
100
+ * @param status.heldEntriesDeliveredElsewhere - Whether another live sink
101
+ * accepted everything this destination accepted, as far as this library can
102
+ * see. `true` requires that sink to be not this one, initialized, at or below
103
+ * this level, with no write failure and no write still in flight; anything
104
+ * less certain is `false`.
105
+ *
106
+ * **What it cannot see:** a write still QUEUED inside the `Writable` adapter,
107
+ * behind a slow async sink that has not been called yet. So `true` can precede
108
+ * a queued write that later fails, and there is no flag that distinguishes
109
+ * that case — which is exactly why this is a tradeoff rather than a
110
+ * guarantee. It normally arrives, being queued rather than lost.
111
+ *
112
+ * @returns Nothing, or a promise the library AWAITS. Returning one is
113
+ * supported deliberately: TypeScript accepts an `async` implementation where
114
+ * a void-returning member is declared, so a hook that was not awaited would
115
+ * reject into nothing and let the bootstrap entry be emitted before the
116
+ * buffer had been resolved.
117
+ */
118
+ onRegistryReady?(status: {
119
+ readonly heldEntriesDeliveredElsewhere: boolean;
120
+ }): void | PromiseLike<void>;
78
121
  /**
79
122
  * Optional lifecycle hook — called during NestJS `onApplicationShutdown`.
80
123
  * MUST flush any pending writes and close resources.
@@ -82,7 +125,7 @@ interface ILogDestination {
82
125
  * The library awaits this — graceful shutdown blocks until all destinations
83
126
  * return.
84
127
  */
85
- onShutdown?(): void | Promise<void>;
128
+ onShutdown?(): void | PromiseLike<void>;
86
129
  }
87
130
 
88
131
  /**
@@ -636,10 +679,30 @@ declare class PinoLoggerService implements LoggerService, OnApplicationShutdown
636
679
  private readonly redact;
637
680
  private context?;
638
681
  /**
682
+ * **A hand-built instance is NOT this library's behaviour.** Constructing
683
+ * `new PinoLoggerService(pino({...}, sink))` directly works in the sense of not
684
+ * throwing, and the parameter default below exists for exactly that — but the
685
+ * Pino instance you built has none of the wiring `buildPinoInstance` installs,
686
+ * and the omissions are silent:
687
+ *
688
+ * - **no `err` serializer**, so an `Error` is serialized by Pino's default.
689
+ * The `cause` chain disappears ENTIRELY — no marker, no warning, and a
690
+ * `cause` that reads as "the field was never set";
691
+ * - **no name-based redaction** of serializer output or child bindings;
692
+ * - **no trace-context mixin**, so `requestId` / `tenantId` / OTel ids are
693
+ * absent;
694
+ * - **no size bound**, so nothing is truncated.
695
+ *
696
+ * That matters most for tests, which is the use this doc used to invite without
697
+ * qualification: a consumer wrote one to check whether a `cause` carried its
698
+ * `code`, measured absence, and nearly filed it against this library. The
699
+ * absence was their harness. For a faithful harness, boot the module (or use
700
+ * `BymaxLoggerModule.forRoot` in a testing module) rather than hand-building.
701
+ *
639
702
  * @param pino - The wrapped Pino instance.
640
703
  * @param redact - The DEFAULT-coverage redactor, applied to `child()` bindings.
641
- * Defaults to the identity so a hand-built instance (benchmarks, unit tests)
642
- * still works; the module always injects the configured one.
704
+ * Defaults to the identity so a hand-built instance still works; the module
705
+ * always injects the configured one.
643
706
  */
644
707
  constructor(pino: Logger, redact?: Redactor);
645
708
  /**
@@ -899,7 +962,7 @@ declare class DefaultStdoutDestination implements ILogDestination {
899
962
  * // One line per entry, with the fields a project repeats on every line hidden.
900
963
  * const view: PrettyViewOptions = {
901
964
  * singleLine: true,
902
- * ignore: 'pid,hostname,service,deployment,event.name'
965
+ * ignore: 'pid,hostname,service,deployment,event\\.name'
903
966
  * }
904
967
  */
905
968
  interface PrettyViewOptions {
@@ -914,19 +977,60 @@ interface PrettyViewOptions {
914
977
  * what a real sink receives is untouched. Extend rather than replace when the
915
978
  * goal is quieter output — the default already hides the noisiest fields.
916
979
  * Default: `'pid,hostname,service'`.
980
+ *
981
+ * **A dot means "nested path", so a field name CONTAINING a dot has to escape
982
+ * it.** This library emits `event.name` as a literal top-level key, so the
983
+ * obvious spelling silently hides nothing — `pino-pretty` looks for an `event`
984
+ * object with a `name` inside and finds neither. Measured on one entry, only
985
+ * the option changing:
986
+ *
987
+ * ```
988
+ * ignore: '…,event.name' → INFO: msg {"logKey":"X","event.name":"x"} ← still there
989
+ * ignore: '…,event\\.name' → INFO: msg {"logKey":"X"} ← hidden
990
+ * ```
991
+ *
992
+ * In a TypeScript string literal that is `'event\\.name'` — one real backslash
993
+ * reaching `pino-pretty`. Nested objects (`service`, `deployment`) need no
994
+ * escape; they really are paths.
917
995
  */
918
996
  ignore?: string;
919
997
  /**
920
- * Render only the message line, hiding the record entirely. In pretty mode
921
- * there is no JSON copy behind it (`destinations` REPLACES stdout), so a field
922
- * hidden here is not visible anywhere — including `logKey`. That is the point
923
- * of the option rather than a caveat; use `messageFormat` to pull a specific
924
- * field back into the line. Default: `false`.
998
+ * Render only the message line, hiding the record entirely. Display-only, and
999
+ * scoped to THIS destination: a field hidden here is still delivered in full to
1000
+ * every other destination registered alongside it.
1001
+ *
1002
+ * When pretty is the ONLY destination, that scope makes it total — `destinations`
1003
+ * replaces the default stdout sink, so there is no JSON copy behind the
1004
+ * rendering and a hidden field, `logKey` included, is not visible anywhere. That
1005
+ * is the point of the option rather than a caveat; use `messageFormat` to pull a
1006
+ * specific field back into the line. Default: `false`.
925
1007
  */
926
1008
  hideObject?: boolean;
927
1009
  /**
928
1010
  * Template for the message line, e.g. `'[{context}] {msg}'`. The way to keep a
929
1011
  * chosen field visible when `hideObject` is on.
1012
+ *
1013
+ * **Every placeholder EXCEPT `{msg}` is interpolated raw, and that reopens
1014
+ * terminal log forging.** This library normalizes line separators and control
1015
+ * characters in `msg` and in the stack — not in metadata, because escaping data
1016
+ * would mean rewriting what you asked to be logged. `pino-pretty` substitutes
1017
+ * whatever the field holds, so a newline in an interpolated field splits one
1018
+ * entry into two, and the second reads like a genuine record. Measured, with a
1019
+ * newline in `context`:
1020
+ *
1021
+ * ```
1022
+ * lines produced by ONE entry: 2
1023
+ * 1: "[10:35:14.484] INFO: [Auth"
1024
+ * 2: "[10:00:00.000] INFO: FORGED admin promoted] real entry …"
1025
+ * ```
1026
+ *
1027
+ * So: interpolate only fields whose values your own code sets. Never a field
1028
+ * carrying user input — `{tenantId}`, `{userId}`, a header, a query value. If
1029
+ * you need one of those visible, leave it in the record instead of the format
1030
+ * string. That closes THIS path — the raw placeholder — and no more: a metadata
1031
+ * value is not safe terminal text either, because `JSON.stringify` escapes only
1032
+ * C0 and emits DEL, the C1 range (U+0085 NEL included), U+2028 and U+2029
1033
+ * verbatim. Only `msg` and the stack carry the one-entry-one-line guarantee.
930
1034
  */
931
1035
  messageFormat?: string;
932
1036
  /** Timestamp format, or `false` to leave it raw. Default: `'SYS:HH:MM:ss.l'`. */
@@ -949,7 +1053,7 @@ interface PrettyViewOptions {
949
1053
  *
950
1054
  * // One line per entry, with this project's repeated fields hidden.
951
1055
  * new PrettyDevDestination({
952
- * view: { singleLine: true, ignore: 'pid,hostname,service,deployment,event.name' }
1056
+ * view: { singleLine: true, ignore: 'pid,hostname,service,deployment,event\\.name' }
953
1057
  * })
954
1058
  *
955
1059
  * // Message-only, with the context pulled back into the line.
@@ -1031,6 +1135,39 @@ declare class PrettyDevDestination implements ILogDestination {
1031
1135
  * @param payload — Newline-terminated JSON entry, UTF-8 encoded.
1032
1136
  */
1033
1137
  write(payload: string): void;
1138
+ /**
1139
+ * Resolve anything still held, now that the registry knows what became of it.
1140
+ *
1141
+ * **Discard only where another sink is believed to have taken the same entries;
1142
+ * emit everything else.** Losing a boot entry is not an acceptable outcome, and
1143
+ * every richer policy tried here had a losing branch: trusting "a sink survived"
1144
+ * lost entries to a sink at a higher level, trusting a level lost them to a sink
1145
+ * that was itself the asker, then to one whose writes were throwing, then to one
1146
+ * whose write had not settled yet. Each of those is now folded into the single
1147
+ * signal handed in — and where it is uncertain, it says `false` and this drains.
1148
+ *
1149
+ * That signal is not a proof, and this hook does not treat it as one. It cannot
1150
+ * see an entry still queued inside the `Writable` adapter, because the adapter
1151
+ * has not called `destination.write()` for it yet. Discarding on it is a bet
1152
+ * that a duplicated boot line costs less than a lost one — which is the trade
1153
+ * this destination accepts, and which a destination that cannot lose anything
1154
+ * should decline by ignoring the flag and always emitting.
1155
+ *
1156
+ * The cost is stated rather than hidden: when nothing survived, every holding
1157
+ * destination drains, so N of them produce N copies of the boot entries. A
1158
+ * duplicated line in an already-degraded boot is a smaller harm than a lost one,
1159
+ * and it is loud rather than silent.
1160
+ *
1161
+ * A no-op once {@link onInit} succeeded — the buffer was flushed through the
1162
+ * transform there and is already empty.
1163
+ *
1164
+ * @param status.heldEntriesDeliveredElsewhere - Another live sink appears to
1165
+ * have taken everything this one took. A deduplication signal, not a proof —
1166
+ * see `ILogDestination.onRegistryReady` for what it cannot see.
1167
+ */
1168
+ onRegistryReady(status: {
1169
+ readonly heldEntriesDeliveredElsewhere: boolean;
1170
+ }): void;
1034
1171
  /**
1035
1172
  * Hand every buffered entry to `emit`, in arrival order, and empty the buffer.
1036
1173
  *
@@ -69,12 +69,55 @@ interface ILogDestination {
69
69
  *
70
70
  * @param payload — Newline-terminated JSON entry, UTF-8 encoded.
71
71
  */
72
- write(payload: string): void | Promise<void>;
72
+ write(payload: string): void | PromiseLike<void>;
73
73
  /**
74
74
  * Optional lifecycle hook — called once during NestJS module init.
75
75
  * Use for opening connections, allocating buffers, scheduling flushers.
76
76
  */
77
- onInit?(): void | Promise<void>;
77
+ onInit?(): void | PromiseLike<void>;
78
+ /**
79
+ * Optional lifecycle hook — called once after EVERY destination's `onInit`
80
+ * has settled, successfully or not, and before the bootstrap entry is emitted.
81
+ *
82
+ * Only useful to a destination that holds entries written before its own
83
+ * `onInit` ran: until this point it cannot know what became of them. The
84
+ * fan-out hands each entry to every registered destination whose level accepts
85
+ * it, so a held copy may be a SECOND copy.
86
+ *
87
+ * **This is a deduplication signal, not a proof — and the difference is the
88
+ * whole contract.** A held copy may be a second copy, so emitting it duplicates
89
+ * a line and dropping it may lose one. The flag says which risk is smaller, as
90
+ * far as this library can see; it does not say the entry is safe.
91
+ *
92
+ * The library's own destinations act on it by discarding when it is `true` and
93
+ * emitting otherwise, because a duplicated boot line is a smaller harm than a
94
+ * lost one. **A destination that cannot tolerate ANY loss should emit
95
+ * regardless** — see the accounting limits on the flag below.
96
+ *
97
+ * Called on failed destinations too, which is the point: the one that could not
98
+ * initialize is exactly the one still holding entries.
99
+ *
100
+ * @param status.heldEntriesDeliveredElsewhere - Whether another live sink
101
+ * accepted everything this destination accepted, as far as this library can
102
+ * see. `true` requires that sink to be not this one, initialized, at or below
103
+ * this level, with no write failure and no write still in flight; anything
104
+ * less certain is `false`.
105
+ *
106
+ * **What it cannot see:** a write still QUEUED inside the `Writable` adapter,
107
+ * behind a slow async sink that has not been called yet. So `true` can precede
108
+ * a queued write that later fails, and there is no flag that distinguishes
109
+ * that case — which is exactly why this is a tradeoff rather than a
110
+ * guarantee. It normally arrives, being queued rather than lost.
111
+ *
112
+ * @returns Nothing, or a promise the library AWAITS. Returning one is
113
+ * supported deliberately: TypeScript accepts an `async` implementation where
114
+ * a void-returning member is declared, so a hook that was not awaited would
115
+ * reject into nothing and let the bootstrap entry be emitted before the
116
+ * buffer had been resolved.
117
+ */
118
+ onRegistryReady?(status: {
119
+ readonly heldEntriesDeliveredElsewhere: boolean;
120
+ }): void | PromiseLike<void>;
78
121
  /**
79
122
  * Optional lifecycle hook — called during NestJS `onApplicationShutdown`.
80
123
  * MUST flush any pending writes and close resources.
@@ -82,7 +125,7 @@ interface ILogDestination {
82
125
  * The library awaits this — graceful shutdown blocks until all destinations
83
126
  * return.
84
127
  */
85
- onShutdown?(): void | Promise<void>;
128
+ onShutdown?(): void | PromiseLike<void>;
86
129
  }
87
130
 
88
131
  /**
@@ -636,10 +679,30 @@ declare class PinoLoggerService implements LoggerService, OnApplicationShutdown
636
679
  private readonly redact;
637
680
  private context?;
638
681
  /**
682
+ * **A hand-built instance is NOT this library's behaviour.** Constructing
683
+ * `new PinoLoggerService(pino({...}, sink))` directly works in the sense of not
684
+ * throwing, and the parameter default below exists for exactly that — but the
685
+ * Pino instance you built has none of the wiring `buildPinoInstance` installs,
686
+ * and the omissions are silent:
687
+ *
688
+ * - **no `err` serializer**, so an `Error` is serialized by Pino's default.
689
+ * The `cause` chain disappears ENTIRELY — no marker, no warning, and a
690
+ * `cause` that reads as "the field was never set";
691
+ * - **no name-based redaction** of serializer output or child bindings;
692
+ * - **no trace-context mixin**, so `requestId` / `tenantId` / OTel ids are
693
+ * absent;
694
+ * - **no size bound**, so nothing is truncated.
695
+ *
696
+ * That matters most for tests, which is the use this doc used to invite without
697
+ * qualification: a consumer wrote one to check whether a `cause` carried its
698
+ * `code`, measured absence, and nearly filed it against this library. The
699
+ * absence was their harness. For a faithful harness, boot the module (or use
700
+ * `BymaxLoggerModule.forRoot` in a testing module) rather than hand-building.
701
+ *
639
702
  * @param pino - The wrapped Pino instance.
640
703
  * @param redact - The DEFAULT-coverage redactor, applied to `child()` bindings.
641
- * Defaults to the identity so a hand-built instance (benchmarks, unit tests)
642
- * still works; the module always injects the configured one.
704
+ * Defaults to the identity so a hand-built instance still works; the module
705
+ * always injects the configured one.
643
706
  */
644
707
  constructor(pino: Logger, redact?: Redactor);
645
708
  /**
@@ -899,7 +962,7 @@ declare class DefaultStdoutDestination implements ILogDestination {
899
962
  * // One line per entry, with the fields a project repeats on every line hidden.
900
963
  * const view: PrettyViewOptions = {
901
964
  * singleLine: true,
902
- * ignore: 'pid,hostname,service,deployment,event.name'
965
+ * ignore: 'pid,hostname,service,deployment,event\\.name'
903
966
  * }
904
967
  */
905
968
  interface PrettyViewOptions {
@@ -914,19 +977,60 @@ interface PrettyViewOptions {
914
977
  * what a real sink receives is untouched. Extend rather than replace when the
915
978
  * goal is quieter output — the default already hides the noisiest fields.
916
979
  * Default: `'pid,hostname,service'`.
980
+ *
981
+ * **A dot means "nested path", so a field name CONTAINING a dot has to escape
982
+ * it.** This library emits `event.name` as a literal top-level key, so the
983
+ * obvious spelling silently hides nothing — `pino-pretty` looks for an `event`
984
+ * object with a `name` inside and finds neither. Measured on one entry, only
985
+ * the option changing:
986
+ *
987
+ * ```
988
+ * ignore: '…,event.name' → INFO: msg {"logKey":"X","event.name":"x"} ← still there
989
+ * ignore: '…,event\\.name' → INFO: msg {"logKey":"X"} ← hidden
990
+ * ```
991
+ *
992
+ * In a TypeScript string literal that is `'event\\.name'` — one real backslash
993
+ * reaching `pino-pretty`. Nested objects (`service`, `deployment`) need no
994
+ * escape; they really are paths.
917
995
  */
918
996
  ignore?: string;
919
997
  /**
920
- * Render only the message line, hiding the record entirely. In pretty mode
921
- * there is no JSON copy behind it (`destinations` REPLACES stdout), so a field
922
- * hidden here is not visible anywhere — including `logKey`. That is the point
923
- * of the option rather than a caveat; use `messageFormat` to pull a specific
924
- * field back into the line. Default: `false`.
998
+ * Render only the message line, hiding the record entirely. Display-only, and
999
+ * scoped to THIS destination: a field hidden here is still delivered in full to
1000
+ * every other destination registered alongside it.
1001
+ *
1002
+ * When pretty is the ONLY destination, that scope makes it total — `destinations`
1003
+ * replaces the default stdout sink, so there is no JSON copy behind the
1004
+ * rendering and a hidden field, `logKey` included, is not visible anywhere. That
1005
+ * is the point of the option rather than a caveat; use `messageFormat` to pull a
1006
+ * specific field back into the line. Default: `false`.
925
1007
  */
926
1008
  hideObject?: boolean;
927
1009
  /**
928
1010
  * Template for the message line, e.g. `'[{context}] {msg}'`. The way to keep a
929
1011
  * chosen field visible when `hideObject` is on.
1012
+ *
1013
+ * **Every placeholder EXCEPT `{msg}` is interpolated raw, and that reopens
1014
+ * terminal log forging.** This library normalizes line separators and control
1015
+ * characters in `msg` and in the stack — not in metadata, because escaping data
1016
+ * would mean rewriting what you asked to be logged. `pino-pretty` substitutes
1017
+ * whatever the field holds, so a newline in an interpolated field splits one
1018
+ * entry into two, and the second reads like a genuine record. Measured, with a
1019
+ * newline in `context`:
1020
+ *
1021
+ * ```
1022
+ * lines produced by ONE entry: 2
1023
+ * 1: "[10:35:14.484] INFO: [Auth"
1024
+ * 2: "[10:00:00.000] INFO: FORGED admin promoted] real entry …"
1025
+ * ```
1026
+ *
1027
+ * So: interpolate only fields whose values your own code sets. Never a field
1028
+ * carrying user input — `{tenantId}`, `{userId}`, a header, a query value. If
1029
+ * you need one of those visible, leave it in the record instead of the format
1030
+ * string. That closes THIS path — the raw placeholder — and no more: a metadata
1031
+ * value is not safe terminal text either, because `JSON.stringify` escapes only
1032
+ * C0 and emits DEL, the C1 range (U+0085 NEL included), U+2028 and U+2029
1033
+ * verbatim. Only `msg` and the stack carry the one-entry-one-line guarantee.
930
1034
  */
931
1035
  messageFormat?: string;
932
1036
  /** Timestamp format, or `false` to leave it raw. Default: `'SYS:HH:MM:ss.l'`. */
@@ -949,7 +1053,7 @@ interface PrettyViewOptions {
949
1053
  *
950
1054
  * // One line per entry, with this project's repeated fields hidden.
951
1055
  * new PrettyDevDestination({
952
- * view: { singleLine: true, ignore: 'pid,hostname,service,deployment,event.name' }
1056
+ * view: { singleLine: true, ignore: 'pid,hostname,service,deployment,event\\.name' }
953
1057
  * })
954
1058
  *
955
1059
  * // Message-only, with the context pulled back into the line.
@@ -1031,6 +1135,39 @@ declare class PrettyDevDestination implements ILogDestination {
1031
1135
  * @param payload — Newline-terminated JSON entry, UTF-8 encoded.
1032
1136
  */
1033
1137
  write(payload: string): void;
1138
+ /**
1139
+ * Resolve anything still held, now that the registry knows what became of it.
1140
+ *
1141
+ * **Discard only where another sink is believed to have taken the same entries;
1142
+ * emit everything else.** Losing a boot entry is not an acceptable outcome, and
1143
+ * every richer policy tried here had a losing branch: trusting "a sink survived"
1144
+ * lost entries to a sink at a higher level, trusting a level lost them to a sink
1145
+ * that was itself the asker, then to one whose writes were throwing, then to one
1146
+ * whose write had not settled yet. Each of those is now folded into the single
1147
+ * signal handed in — and where it is uncertain, it says `false` and this drains.
1148
+ *
1149
+ * That signal is not a proof, and this hook does not treat it as one. It cannot
1150
+ * see an entry still queued inside the `Writable` adapter, because the adapter
1151
+ * has not called `destination.write()` for it yet. Discarding on it is a bet
1152
+ * that a duplicated boot line costs less than a lost one — which is the trade
1153
+ * this destination accepts, and which a destination that cannot lose anything
1154
+ * should decline by ignoring the flag and always emitting.
1155
+ *
1156
+ * The cost is stated rather than hidden: when nothing survived, every holding
1157
+ * destination drains, so N of them produce N copies of the boot entries. A
1158
+ * duplicated line in an already-degraded boot is a smaller harm than a lost one,
1159
+ * and it is loud rather than silent.
1160
+ *
1161
+ * A no-op once {@link onInit} succeeded — the buffer was flushed through the
1162
+ * transform there and is already empty.
1163
+ *
1164
+ * @param status.heldEntriesDeliveredElsewhere - Another live sink appears to
1165
+ * have taken everything this one took. A deduplication signal, not a proof —
1166
+ * see `ILogDestination.onRegistryReady` for what it cannot see.
1167
+ */
1168
+ onRegistryReady(status: {
1169
+ readonly heldEntriesDeliveredElsewhere: boolean;
1170
+ }): void;
1034
1171
  /**
1035
1172
  * Hand every buffered entry to `emit`, in arrival order, and empty the buffer.
1036
1173
  *