rouzer 5.2.1 → 5.2.2
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/dist/ndjson.d.ts +1 -1
- package/dist/ndjson.js +172 -99
- package/package.json +1 -1
package/dist/ndjson.d.ts
CHANGED
|
@@ -57,5 +57,5 @@ export declare function decodeNdjson<T = unknown>(stream: ReadableStream<Uint8Ar
|
|
|
57
57
|
* `content-type: application/x-ndjson; charset=utf-8` unless the caller supplies
|
|
58
58
|
* a content type in `init.headers`.
|
|
59
59
|
*/
|
|
60
|
-
export declare function ndjsonResponse<T>(source: NdjsonSource<T>, init?: ResponseInit & NdjsonEncodeOptions): Response;
|
|
60
|
+
export declare function ndjsonResponse<T>(source: NdjsonSource<T>, { signal, ...init }?: ResponseInit & NdjsonEncodeOptions): Response;
|
|
61
61
|
export {};
|
package/dist/ndjson.js
CHANGED
|
@@ -52,107 +52,184 @@ export const routerPlugin = {
|
|
|
52
52
|
* closed.
|
|
53
53
|
*/
|
|
54
54
|
export function encodeNdjson(source, options = {}) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
55
|
+
return new ReadableStream(new NdjsonEncoder(source, options));
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Decode a newline-delimited JSON byte stream.
|
|
59
|
+
*
|
|
60
|
+
* @remarks UTF-8 chunks may split JSON lines. Both `\n` and `\r\n` line endings
|
|
61
|
+
* are accepted, and a final line does not need a trailing newline. Malformed
|
|
62
|
+
* lines throw a `SyntaxError` that includes the 1-based line number.
|
|
63
|
+
*/
|
|
64
|
+
export function decodeNdjson(stream) {
|
|
65
|
+
return new NdjsonDecoder(stream);
|
|
66
|
+
}
|
|
67
|
+
class NdjsonEncoder {
|
|
68
|
+
options;
|
|
69
|
+
iterator;
|
|
70
|
+
encoder = new TextEncoder();
|
|
71
|
+
cancelled = false;
|
|
72
|
+
cleanup;
|
|
73
|
+
abortHandler;
|
|
74
|
+
constructor(source, options) {
|
|
75
|
+
this.options = options;
|
|
76
|
+
this.iterator = getAsyncIterator(source);
|
|
72
77
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
abortHandler = () => {
|
|
79
|
-
void cancelIterator(signal.reason).catch(() => { });
|
|
78
|
+
start(controller) {
|
|
79
|
+
const { signal } = this.options;
|
|
80
|
+
if (signal) {
|
|
81
|
+
this.abortHandler = () => {
|
|
82
|
+
void this.cancel(signal.reason).catch(() => { });
|
|
80
83
|
try {
|
|
81
84
|
controller.close();
|
|
82
85
|
}
|
|
83
86
|
catch { }
|
|
84
87
|
};
|
|
85
88
|
if (signal.aborted) {
|
|
86
|
-
abortHandler();
|
|
87
|
-
return;
|
|
89
|
+
this.abortHandler();
|
|
88
90
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
async pull(controller) {
|
|
92
|
-
if (cancelled) {
|
|
93
|
-
controller.close();
|
|
94
|
-
return;
|
|
91
|
+
else {
|
|
92
|
+
signal.addEventListener('abort', this.abortHandler, { once: true });
|
|
95
93
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
async pull(controller) {
|
|
97
|
+
if (this.cancelled) {
|
|
98
|
+
controller.close();
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const { done, value } = await this.iterator.next();
|
|
102
|
+
if (this.cancelled) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (done) {
|
|
106
|
+
this.removeAbortHandler();
|
|
107
|
+
controller.close();
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const line = JSON.stringify(value);
|
|
111
|
+
if (line === undefined) {
|
|
112
|
+
throw new TypeError('NDJSON items must serialize to a JSON text; received undefined');
|
|
113
|
+
}
|
|
114
|
+
controller.enqueue(this.encoder.encode(`${line}\n`));
|
|
115
|
+
}
|
|
116
|
+
async cancel(reason) {
|
|
117
|
+
if (!this.cancelled) {
|
|
118
|
+
this.cancelled = true;
|
|
119
|
+
this.removeAbortHandler();
|
|
120
|
+
this.cleanup ??= Promise.resolve(this.iterator.return?.(reason)).then(() => { });
|
|
121
|
+
}
|
|
122
|
+
await this.cleanup;
|
|
123
|
+
}
|
|
124
|
+
removeAbortHandler() {
|
|
125
|
+
const { signal } = this.options;
|
|
126
|
+
if (signal && this.abortHandler) {
|
|
127
|
+
signal.removeEventListener('abort', this.abortHandler);
|
|
128
|
+
this.abortHandler = undefined;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
class NdjsonDecoder {
|
|
133
|
+
reader;
|
|
134
|
+
decoder = new TextDecoder();
|
|
135
|
+
buffer = '';
|
|
136
|
+
lineNumber = 0;
|
|
137
|
+
closed = false;
|
|
138
|
+
doneReading = false;
|
|
139
|
+
readerReleased = false;
|
|
140
|
+
constructor(stream) {
|
|
141
|
+
this.reader = stream.getReader();
|
|
142
|
+
}
|
|
143
|
+
[Symbol.asyncIterator]() {
|
|
144
|
+
return new NdjsonAsyncIterator(this);
|
|
145
|
+
}
|
|
146
|
+
releaseReader() {
|
|
147
|
+
if (!this.readerReleased) {
|
|
148
|
+
this.readerReleased = true;
|
|
149
|
+
this.reader.releaseLock();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
async cancelReader(reason) {
|
|
153
|
+
if (!this.doneReading) {
|
|
154
|
+
await this.reader.cancel(reason).catch(() => { });
|
|
155
|
+
}
|
|
156
|
+
this.releaseReader();
|
|
157
|
+
}
|
|
158
|
+
async parseNextLine(line) {
|
|
159
|
+
try {
|
|
160
|
+
this.lineNumber += 1;
|
|
161
|
+
return {
|
|
162
|
+
done: false,
|
|
163
|
+
value: parseNdjsonLine(stripCarriageReturn(line), this.lineNumber),
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
this.closed = true;
|
|
168
|
+
await this.cancelReader(error);
|
|
169
|
+
throw error;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
class NdjsonAsyncIterator {
|
|
174
|
+
decoder;
|
|
175
|
+
closed = false;
|
|
176
|
+
constructor(decoder) {
|
|
177
|
+
this.decoder = decoder;
|
|
178
|
+
}
|
|
179
|
+
async next() {
|
|
180
|
+
if (this.closed || this.decoder.closed) {
|
|
181
|
+
return { done: true, value: undefined };
|
|
182
|
+
}
|
|
183
|
+
while (true) {
|
|
184
|
+
const newlineIndex = this.decoder.buffer.indexOf('\n');
|
|
185
|
+
if (newlineIndex !== -1) {
|
|
186
|
+
const line = this.decoder.buffer.slice(0, newlineIndex);
|
|
187
|
+
this.decoder.buffer = this.decoder.buffer.slice(newlineIndex + 1);
|
|
188
|
+
return this.decoder.parseNextLine(line);
|
|
99
189
|
}
|
|
100
|
-
if (
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
190
|
+
if (this.decoder.doneReading) {
|
|
191
|
+
this.close();
|
|
192
|
+
this.decoder.releaseReader();
|
|
193
|
+
if (this.decoder.buffer.length > 0) {
|
|
194
|
+
const line = this.decoder.buffer;
|
|
195
|
+
this.decoder.buffer = '';
|
|
196
|
+
return this.decoder.parseNextLine(line);
|
|
197
|
+
}
|
|
198
|
+
return { done: true, value: undefined };
|
|
104
199
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
200
|
+
let chunk;
|
|
201
|
+
try {
|
|
202
|
+
chunk = await this.decoder.reader.read();
|
|
108
203
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* Decode a newline-delimited JSON byte stream.
|
|
118
|
-
*
|
|
119
|
-
* @remarks UTF-8 chunks may split JSON lines. Both `\n` and `\r\n` line endings
|
|
120
|
-
* are accepted, and a final line does not need a trailing newline. Malformed
|
|
121
|
-
* lines throw a `SyntaxError` that includes the 1-based line number.
|
|
122
|
-
*/
|
|
123
|
-
export async function* decodeNdjson(stream) {
|
|
124
|
-
const reader = stream.getReader();
|
|
125
|
-
const decoder = new TextDecoder();
|
|
126
|
-
let buffer = '';
|
|
127
|
-
let lineNumber = 0;
|
|
128
|
-
let doneReading = false;
|
|
129
|
-
try {
|
|
130
|
-
while (true) {
|
|
131
|
-
const { done, value } = await reader.read();
|
|
132
|
-
if (done) {
|
|
133
|
-
buffer += decoder.decode();
|
|
134
|
-
doneReading = true;
|
|
135
|
-
break;
|
|
204
|
+
catch (error) {
|
|
205
|
+
this.close();
|
|
206
|
+
this.decoder.releaseReader();
|
|
207
|
+
throw error;
|
|
208
|
+
}
|
|
209
|
+
if (this.closed || this.decoder.closed) {
|
|
210
|
+
return { done: true, value: undefined };
|
|
136
211
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
212
|
+
if (chunk.done) {
|
|
213
|
+
this.decoder.buffer += this.decoder.decoder.decode();
|
|
214
|
+
this.decoder.doneReading = true;
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
this.decoder.buffer += this.decoder.decoder.decode(chunk.value, {
|
|
218
|
+
stream: true,
|
|
219
|
+
});
|
|
144
220
|
}
|
|
145
|
-
}
|
|
146
|
-
if (buffer.length > 0) {
|
|
147
|
-
lineNumber += 1;
|
|
148
|
-
yield parseNdjsonLine(stripCarriageReturn(buffer), lineNumber);
|
|
149
221
|
}
|
|
150
222
|
}
|
|
151
|
-
|
|
152
|
-
if (!
|
|
153
|
-
|
|
223
|
+
async return(reason) {
|
|
224
|
+
if (!this.closed) {
|
|
225
|
+
this.close();
|
|
226
|
+
await this.decoder.cancelReader(reason);
|
|
154
227
|
}
|
|
155
|
-
|
|
228
|
+
return { done: true, value: undefined };
|
|
229
|
+
}
|
|
230
|
+
close() {
|
|
231
|
+
this.closed = true;
|
|
232
|
+
this.decoder.closed = true;
|
|
156
233
|
}
|
|
157
234
|
}
|
|
158
235
|
/**
|
|
@@ -162,32 +239,28 @@ export async function* decodeNdjson(stream) {
|
|
|
162
239
|
* `content-type: application/x-ndjson; charset=utf-8` unless the caller supplies
|
|
163
240
|
* a content type in `init.headers`.
|
|
164
241
|
*/
|
|
165
|
-
export function ndjsonResponse(source, init = {}) {
|
|
166
|
-
const { signal, ...responseInit } = init;
|
|
242
|
+
export function ndjsonResponse(source, { signal, ...init } = {}) {
|
|
167
243
|
const headers = new Headers(init.headers);
|
|
168
244
|
if (!headers.has('content-type')) {
|
|
169
245
|
headers.set('content-type', 'application/x-ndjson; charset=utf-8');
|
|
170
246
|
}
|
|
171
247
|
return new Response(encodeNdjson(source, { signal }), {
|
|
172
|
-
...
|
|
248
|
+
...init,
|
|
173
249
|
headers,
|
|
174
250
|
});
|
|
175
251
|
}
|
|
176
252
|
function getAsyncIterator(source) {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
return asyncIterator;
|
|
253
|
+
if (Symbol.asyncIterator in source) {
|
|
254
|
+
return source[Symbol.asyncIterator]();
|
|
180
255
|
}
|
|
181
|
-
|
|
182
|
-
|
|
256
|
+
if (Symbol.iterator in source) {
|
|
257
|
+
const iterator = source[Symbol.iterator]();
|
|
183
258
|
return {
|
|
184
|
-
next()
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
return { done: true, value: undefined };
|
|
190
|
-
},
|
|
259
|
+
next: async (value) => iterator.next(value),
|
|
260
|
+
return: iterator.return
|
|
261
|
+
? async (value) => iterator.return(value)
|
|
262
|
+
: undefined,
|
|
263
|
+
throw: iterator.throw ? async (error) => iterator.throw(error) : undefined,
|
|
191
264
|
};
|
|
192
265
|
}
|
|
193
266
|
throw new TypeError('NDJSON source must be iterable');
|