@fluojs/testing 1.0.0-beta.2 → 1.0.0-beta.4
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/README.ko.md +68 -17
- package/README.md +66 -15
- package/dist/app.d.ts +2 -2
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +1 -1
- package/dist/babel-decorators-plugin.d.ts +2 -2
- package/dist/babel-decorators-plugin.d.ts.map +1 -1
- package/dist/babel-decorators-plugin.js +26 -12
- package/dist/conformance/fetch-style-websocket-conformance.d.ts +12 -0
- package/dist/conformance/fetch-style-websocket-conformance.d.ts.map +1 -1
- package/dist/conformance/fetch-style-websocket-conformance.js +14 -0
- package/dist/conformance/platform-conformance.d.ts +21 -0
- package/dist/conformance/platform-conformance.d.ts.map +1 -1
- package/dist/conformance/platform-conformance.js +27 -0
- package/dist/mock.d.ts +17 -0
- package/dist/mock.d.ts.map +1 -1
- package/dist/mock.js +19 -0
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +106 -11
- package/dist/portability/http-adapter-portability.d.ts +9 -0
- package/dist/portability/http-adapter-portability.d.ts.map +1 -1
- package/dist/portability/http-adapter-portability.js +135 -79
- package/dist/portability/web-runtime-adapter-portability.d.ts +13 -0
- package/dist/portability/web-runtime-adapter-portability.d.ts.map +1 -1
- package/dist/portability/web-runtime-adapter-portability.js +100 -40
- package/dist/types.d.ts +7 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +12 -9
|
@@ -57,10 +57,26 @@ async function requestHttps(url) {
|
|
|
57
57
|
request.end();
|
|
58
58
|
});
|
|
59
59
|
}
|
|
60
|
-
async function
|
|
60
|
+
async function runWithCleanup(app, adapterName, assertion) {
|
|
61
|
+
let hasAssertionError = false;
|
|
62
|
+
let assertionError;
|
|
63
|
+
try {
|
|
64
|
+
await assertion();
|
|
65
|
+
} catch (error) {
|
|
66
|
+
hasAssertionError = true;
|
|
67
|
+
assertionError = error;
|
|
68
|
+
}
|
|
61
69
|
try {
|
|
62
70
|
await app.close();
|
|
63
|
-
} catch {
|
|
71
|
+
} catch (cleanupError) {
|
|
72
|
+
if (hasAssertionError) {
|
|
73
|
+
throw new AggregateError([assertionError, cleanupError], `${adapterName} adapter portability assertion failed and app.close() also failed during harness cleanup.`);
|
|
74
|
+
}
|
|
75
|
+
throw new AggregateError([cleanupError], `${adapterName} adapter app.close() failed during portability harness cleanup.`);
|
|
76
|
+
}
|
|
77
|
+
if (hasAssertionError) {
|
|
78
|
+
throw assertionError;
|
|
79
|
+
}
|
|
64
80
|
}
|
|
65
81
|
|
|
66
82
|
/**
|
|
@@ -115,7 +131,7 @@ export class HttpAdapterPortabilityHarness {
|
|
|
115
131
|
port
|
|
116
132
|
});
|
|
117
133
|
await app.listen();
|
|
118
|
-
|
|
134
|
+
await runWithCleanup(app, this.options.name, async () => {
|
|
119
135
|
const response = await fetch(`http://127.0.0.1:${String(port)}/cookies`, {
|
|
120
136
|
headers: {
|
|
121
137
|
cookie: 'good=hello%20world; bad=%E0%A4%A'
|
|
@@ -128,9 +144,7 @@ export class HttpAdapterPortabilityHarness {
|
|
|
128
144
|
if (typeof body !== 'object' || body === null || !('bad' in body) || !('good' in body) || body.bad !== '%E0%A4%A' || body.good !== 'hello world' || Object.keys(body).length !== 2) {
|
|
129
145
|
throw new Error(`${this.options.name} adapter changed malformed-cookie normalization.`);
|
|
130
146
|
}
|
|
131
|
-
}
|
|
132
|
-
await closeSilently(app);
|
|
133
|
-
}
|
|
147
|
+
});
|
|
134
148
|
}
|
|
135
149
|
async assertPreservesRawBodyForJsonAndText() {
|
|
136
150
|
let _initProto2, _initClass2;
|
|
@@ -172,7 +186,7 @@ export class HttpAdapterPortabilityHarness {
|
|
|
172
186
|
rawBody: true
|
|
173
187
|
});
|
|
174
188
|
await app.listen();
|
|
175
|
-
|
|
189
|
+
await runWithCleanup(app, this.options.name, async () => {
|
|
176
190
|
const [jsonResponse, textResponse] = await Promise.all([fetch(`http://127.0.0.1:${String(port)}/webhooks/json`, {
|
|
177
191
|
body: JSON.stringify({
|
|
178
192
|
provider: 'stripe'
|
|
@@ -206,22 +220,75 @@ export class HttpAdapterPortabilityHarness {
|
|
|
206
220
|
})) {
|
|
207
221
|
throw new Error(`${this.options.name} adapter changed text rawBody semantics.`);
|
|
208
222
|
}
|
|
209
|
-
}
|
|
210
|
-
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
async assertPreservesExactRawBodyBytesForByteSensitivePayloads() {
|
|
226
|
+
let _initProto3, _initClass3;
|
|
227
|
+
let _WebhookController2;
|
|
228
|
+
class WebhookController {
|
|
229
|
+
static {
|
|
230
|
+
({
|
|
231
|
+
e: [_initProto3],
|
|
232
|
+
c: [_WebhookController2, _initClass3]
|
|
233
|
+
} = _applyDecs(this, [Controller('/webhooks')], [[Post('/bytes'), 2, "handleBytes"]]));
|
|
234
|
+
}
|
|
235
|
+
constructor() {
|
|
236
|
+
_initProto3(this);
|
|
237
|
+
}
|
|
238
|
+
handleBytes(_input, context) {
|
|
239
|
+
return {
|
|
240
|
+
rawBytes: Array.from(context.request.rawBody ?? new Uint8Array())
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
static {
|
|
244
|
+
_initClass3();
|
|
245
|
+
}
|
|
211
246
|
}
|
|
247
|
+
class AppModule {}
|
|
248
|
+
defineModule(AppModule, {
|
|
249
|
+
controllers: [_WebhookController2]
|
|
250
|
+
});
|
|
251
|
+
const port = await findAvailablePort();
|
|
252
|
+
const app = await this.options.bootstrap(AppModule, {
|
|
253
|
+
cors: false,
|
|
254
|
+
port,
|
|
255
|
+
rawBody: true
|
|
256
|
+
});
|
|
257
|
+
await this.options.prepareExactRawBodyByteTest?.(app);
|
|
258
|
+
await app.listen();
|
|
259
|
+
await runWithCleanup(app, this.options.name, async () => {
|
|
260
|
+
const payload = Uint8Array.from([0xe9, 0x41]);
|
|
261
|
+
const contentType = this.options.exactRawBodyByteContentType ?? 'text/plain; charset=latin1';
|
|
262
|
+
const response = await fetch(`http://127.0.0.1:${String(port)}/webhooks/bytes`, {
|
|
263
|
+
body: payload,
|
|
264
|
+
headers: {
|
|
265
|
+
'content-type': contentType
|
|
266
|
+
},
|
|
267
|
+
method: 'POST'
|
|
268
|
+
});
|
|
269
|
+
if (response.status !== 201) {
|
|
270
|
+
throw new Error(`${this.options.name} adapter changed byte-sensitive rawBody response status semantics.`);
|
|
271
|
+
}
|
|
272
|
+
const body = await response.json();
|
|
273
|
+
if (JSON.stringify(body) !== JSON.stringify({
|
|
274
|
+
rawBytes: Array.from(payload)
|
|
275
|
+
})) {
|
|
276
|
+
throw new Error(`${this.options.name} adapter changed exact-byte rawBody semantics.`);
|
|
277
|
+
}
|
|
278
|
+
});
|
|
212
279
|
}
|
|
213
280
|
async assertExcludesRawBodyForMultipart() {
|
|
214
|
-
let
|
|
281
|
+
let _initProto4, _initClass4;
|
|
215
282
|
let _UploadController;
|
|
216
283
|
class UploadController {
|
|
217
284
|
static {
|
|
218
285
|
({
|
|
219
|
-
e: [
|
|
220
|
-
c: [_UploadController,
|
|
286
|
+
e: [_initProto4],
|
|
287
|
+
c: [_UploadController, _initClass4]
|
|
221
288
|
} = _applyDecs(this, [Controller('/uploads')], [[Post('/'), 2, "upload"]]));
|
|
222
289
|
}
|
|
223
290
|
constructor() {
|
|
224
|
-
|
|
291
|
+
_initProto4(this);
|
|
225
292
|
}
|
|
226
293
|
upload(_input, context) {
|
|
227
294
|
return {
|
|
@@ -231,7 +298,7 @@ export class HttpAdapterPortabilityHarness {
|
|
|
231
298
|
};
|
|
232
299
|
}
|
|
233
300
|
static {
|
|
234
|
-
|
|
301
|
+
_initClass4();
|
|
235
302
|
}
|
|
236
303
|
}
|
|
237
304
|
class AppModule {}
|
|
@@ -245,7 +312,7 @@ export class HttpAdapterPortabilityHarness {
|
|
|
245
312
|
rawBody: true
|
|
246
313
|
});
|
|
247
314
|
await app.listen();
|
|
248
|
-
|
|
315
|
+
await runWithCleanup(app, this.options.name, async () => {
|
|
249
316
|
const form = new FormData();
|
|
250
317
|
form.set('name', 'Ada');
|
|
251
318
|
form.set('payload', new Blob(['hello'], {
|
|
@@ -268,22 +335,20 @@ export class HttpAdapterPortabilityHarness {
|
|
|
268
335
|
})) {
|
|
269
336
|
throw new Error(`${this.options.name} adapter changed multipart rawBody semantics.`);
|
|
270
337
|
}
|
|
271
|
-
}
|
|
272
|
-
await closeSilently(app);
|
|
273
|
-
}
|
|
338
|
+
});
|
|
274
339
|
}
|
|
275
340
|
async assertDefaultsMultipartTotalLimitToMaxBodySize() {
|
|
276
|
-
let
|
|
341
|
+
let _initProto5, _initClass5;
|
|
277
342
|
let _UploadController2;
|
|
278
343
|
class UploadController {
|
|
279
344
|
static {
|
|
280
345
|
({
|
|
281
|
-
e: [
|
|
282
|
-
c: [_UploadController2,
|
|
346
|
+
e: [_initProto5],
|
|
347
|
+
c: [_UploadController2, _initClass5]
|
|
283
348
|
} = _applyDecs(this, [Controller('/uploads')], [[Post('/'), 2, "upload"]]));
|
|
284
349
|
}
|
|
285
350
|
constructor() {
|
|
286
|
-
|
|
351
|
+
_initProto5(this);
|
|
287
352
|
}
|
|
288
353
|
upload(_input, context) {
|
|
289
354
|
return {
|
|
@@ -292,7 +357,7 @@ export class HttpAdapterPortabilityHarness {
|
|
|
292
357
|
};
|
|
293
358
|
}
|
|
294
359
|
static {
|
|
295
|
-
|
|
360
|
+
_initClass5();
|
|
296
361
|
}
|
|
297
362
|
}
|
|
298
363
|
class AppModule {}
|
|
@@ -309,7 +374,7 @@ export class HttpAdapterPortabilityHarness {
|
|
|
309
374
|
port
|
|
310
375
|
});
|
|
311
376
|
await app.listen();
|
|
312
|
-
|
|
377
|
+
await runWithCleanup(app, this.options.name, async () => {
|
|
313
378
|
const form = new FormData();
|
|
314
379
|
form.set('name', 'Ada');
|
|
315
380
|
form.set('payload', new Blob(['12345678'], {
|
|
@@ -326,22 +391,20 @@ export class HttpAdapterPortabilityHarness {
|
|
|
326
391
|
if (typeof body !== 'object' || body === null || body.error?.code !== 'PAYLOAD_TOO_LARGE') {
|
|
327
392
|
throw new Error(`${this.options.name} adapter changed multipart limit error semantics.`);
|
|
328
393
|
}
|
|
329
|
-
}
|
|
330
|
-
await closeSilently(app);
|
|
331
|
-
}
|
|
394
|
+
});
|
|
332
395
|
}
|
|
333
396
|
async assertSupportsSseStreaming() {
|
|
334
|
-
let
|
|
397
|
+
let _initProto6, _initClass6;
|
|
335
398
|
let _EventsController;
|
|
336
399
|
class EventsController {
|
|
337
400
|
static {
|
|
338
401
|
({
|
|
339
|
-
e: [
|
|
340
|
-
c: [_EventsController,
|
|
402
|
+
e: [_initProto6],
|
|
403
|
+
c: [_EventsController, _initClass6]
|
|
341
404
|
} = _applyDecs(this, [Controller('/events')], [[Get('/'), 2, "stream"]]));
|
|
342
405
|
}
|
|
343
406
|
constructor() {
|
|
344
|
-
|
|
407
|
+
_initProto6(this);
|
|
345
408
|
}
|
|
346
409
|
stream(_input, context) {
|
|
347
410
|
const stream = new SseResponse(context);
|
|
@@ -352,13 +415,13 @@ export class HttpAdapterPortabilityHarness {
|
|
|
352
415
|
event: 'ready',
|
|
353
416
|
id: 'evt-1'
|
|
354
417
|
});
|
|
355
|
-
|
|
418
|
+
queueMicrotask(() => {
|
|
356
419
|
stream.close();
|
|
357
|
-
}
|
|
420
|
+
});
|
|
358
421
|
return stream;
|
|
359
422
|
}
|
|
360
423
|
static {
|
|
361
|
-
|
|
424
|
+
_initClass6();
|
|
362
425
|
}
|
|
363
426
|
}
|
|
364
427
|
class AppModule {}
|
|
@@ -371,7 +434,7 @@ export class HttpAdapterPortabilityHarness {
|
|
|
371
434
|
port
|
|
372
435
|
});
|
|
373
436
|
await app.listen();
|
|
374
|
-
|
|
437
|
+
await runWithCleanup(app, this.options.name, async () => {
|
|
375
438
|
const response = await fetch(`http://127.0.0.1:${String(port)}/events`, {
|
|
376
439
|
headers: {
|
|
377
440
|
accept: 'text/event-stream'
|
|
@@ -388,9 +451,7 @@ export class HttpAdapterPortabilityHarness {
|
|
|
388
451
|
if (!body.includes('event: ready') || !body.includes('data: {"ready":true}')) {
|
|
389
452
|
throw new Error(`${this.options.name} adapter changed SSE body framing.`);
|
|
390
453
|
}
|
|
391
|
-
}
|
|
392
|
-
await closeSilently(app);
|
|
393
|
-
}
|
|
454
|
+
});
|
|
394
455
|
}
|
|
395
456
|
|
|
396
457
|
/**
|
|
@@ -398,7 +459,7 @@ export class HttpAdapterPortabilityHarness {
|
|
|
398
459
|
* closes before a `drain` event is emitted.
|
|
399
460
|
*/
|
|
400
461
|
async assertSettlesStreamDrainWaitOnClose() {
|
|
401
|
-
let
|
|
462
|
+
let _initProto7, _initClass7;
|
|
402
463
|
const adapterName = this.options.name;
|
|
403
464
|
let resolveDrainWait;
|
|
404
465
|
const drainWaitSettled = new Promise(resolve => {
|
|
@@ -408,12 +469,12 @@ export class HttpAdapterPortabilityHarness {
|
|
|
408
469
|
class EventsController {
|
|
409
470
|
static {
|
|
410
471
|
({
|
|
411
|
-
e: [
|
|
412
|
-
c: [_EventsController2,
|
|
472
|
+
e: [_initProto7],
|
|
473
|
+
c: [_EventsController2, _initClass7]
|
|
413
474
|
} = _applyDecs(this, [Controller('/events')], [[Get('/'), 2, "stream"]]));
|
|
414
475
|
}
|
|
415
476
|
constructor() {
|
|
416
|
-
|
|
477
|
+
_initProto7(this);
|
|
417
478
|
}
|
|
418
479
|
async stream(_input, context) {
|
|
419
480
|
const stream = new SseResponse(context);
|
|
@@ -428,7 +489,7 @@ export class HttpAdapterPortabilityHarness {
|
|
|
428
489
|
return stream;
|
|
429
490
|
}
|
|
430
491
|
static {
|
|
431
|
-
|
|
492
|
+
_initClass7();
|
|
432
493
|
}
|
|
433
494
|
}
|
|
434
495
|
class AppModule {}
|
|
@@ -441,7 +502,7 @@ export class HttpAdapterPortabilityHarness {
|
|
|
441
502
|
port
|
|
442
503
|
});
|
|
443
504
|
await app.listen();
|
|
444
|
-
|
|
505
|
+
await runWithCleanup(app, this.options.name, async () => {
|
|
445
506
|
const response = await fetch(`http://127.0.0.1:${String(port)}/events`, {
|
|
446
507
|
headers: {
|
|
447
508
|
accept: 'text/event-stream'
|
|
@@ -452,12 +513,10 @@ export class HttpAdapterPortabilityHarness {
|
|
|
452
513
|
}
|
|
453
514
|
await response.text();
|
|
454
515
|
await withTimeout(drainWaitSettled, 2_000, `${this.options.name} adapter left response.stream.waitForDrain() pending after close.`);
|
|
455
|
-
}
|
|
456
|
-
await closeSilently(app);
|
|
457
|
-
}
|
|
516
|
+
});
|
|
458
517
|
}
|
|
459
518
|
async assertReportsConfiguredHostInStartupLogs() {
|
|
460
|
-
let
|
|
519
|
+
let _initProto8, _initClass8;
|
|
461
520
|
const loggerEvents = [];
|
|
462
521
|
const logger = {
|
|
463
522
|
debug() {},
|
|
@@ -473,12 +532,12 @@ export class HttpAdapterPortabilityHarness {
|
|
|
473
532
|
class HealthController {
|
|
474
533
|
static {
|
|
475
534
|
({
|
|
476
|
-
e: [
|
|
477
|
-
c: [_HealthController,
|
|
535
|
+
e: [_initProto8],
|
|
536
|
+
c: [_HealthController, _initClass8]
|
|
478
537
|
} = _applyDecs(this, [Controller('/health')], [[Get('/'), 2, "getHealth"]]));
|
|
479
538
|
}
|
|
480
539
|
constructor() {
|
|
481
|
-
|
|
540
|
+
_initProto8(this);
|
|
482
541
|
}
|
|
483
542
|
getHealth() {
|
|
484
543
|
return {
|
|
@@ -486,7 +545,7 @@ export class HttpAdapterPortabilityHarness {
|
|
|
486
545
|
};
|
|
487
546
|
}
|
|
488
547
|
static {
|
|
489
|
-
|
|
548
|
+
_initClass8();
|
|
490
549
|
}
|
|
491
550
|
}
|
|
492
551
|
class AppModule {}
|
|
@@ -500,7 +559,7 @@ export class HttpAdapterPortabilityHarness {
|
|
|
500
559
|
logger,
|
|
501
560
|
port
|
|
502
561
|
});
|
|
503
|
-
|
|
562
|
+
await runWithCleanup(app, this.options.name, async () => {
|
|
504
563
|
const response = await fetch(`http://127.0.0.1:${String(port)}/health`);
|
|
505
564
|
if (response.status !== 200) {
|
|
506
565
|
throw new Error(`${this.options.name} adapter changed host-bound health response semantics.`);
|
|
@@ -515,12 +574,10 @@ export class HttpAdapterPortabilityHarness {
|
|
|
515
574
|
if (!loggerEvents.includes(expectedLog)) {
|
|
516
575
|
throw new Error(`${this.options.name} adapter changed startup host logging.`);
|
|
517
576
|
}
|
|
518
|
-
}
|
|
519
|
-
await closeSilently(app);
|
|
520
|
-
}
|
|
577
|
+
});
|
|
521
578
|
}
|
|
522
579
|
async assertReportsHttpsStartupUrl(https) {
|
|
523
|
-
let
|
|
580
|
+
let _initProto9, _initClass9;
|
|
524
581
|
const loggerEvents = [];
|
|
525
582
|
const logger = {
|
|
526
583
|
debug() {},
|
|
@@ -536,12 +593,12 @@ export class HttpAdapterPortabilityHarness {
|
|
|
536
593
|
class HealthController {
|
|
537
594
|
static {
|
|
538
595
|
({
|
|
539
|
-
e: [
|
|
540
|
-
c: [_HealthController2,
|
|
596
|
+
e: [_initProto9],
|
|
597
|
+
c: [_HealthController2, _initClass9]
|
|
541
598
|
} = _applyDecs(this, [Controller('/health')], [[Get('/'), 2, "getHealth"]]));
|
|
542
599
|
}
|
|
543
600
|
constructor() {
|
|
544
|
-
|
|
601
|
+
_initProto9(this);
|
|
545
602
|
}
|
|
546
603
|
getHealth() {
|
|
547
604
|
return {
|
|
@@ -549,7 +606,7 @@ export class HttpAdapterPortabilityHarness {
|
|
|
549
606
|
};
|
|
550
607
|
}
|
|
551
608
|
static {
|
|
552
|
-
|
|
609
|
+
_initClass9();
|
|
553
610
|
}
|
|
554
611
|
}
|
|
555
612
|
class AppModule {}
|
|
@@ -564,7 +621,7 @@ export class HttpAdapterPortabilityHarness {
|
|
|
564
621
|
logger,
|
|
565
622
|
port
|
|
566
623
|
});
|
|
567
|
-
|
|
624
|
+
await runWithCleanup(app, this.options.name, async () => {
|
|
568
625
|
const response = await requestHttps(`https://127.0.0.1:${String(port)}/health`);
|
|
569
626
|
if (response.statusCode !== 200) {
|
|
570
627
|
throw new Error(`${this.options.name} adapter changed HTTPS response status semantics.`);
|
|
@@ -578,12 +635,10 @@ export class HttpAdapterPortabilityHarness {
|
|
|
578
635
|
if (!loggerEvents.includes(expectedLog)) {
|
|
579
636
|
throw new Error(`${this.options.name} adapter changed HTTPS startup logging.`);
|
|
580
637
|
}
|
|
581
|
-
}
|
|
582
|
-
await closeSilently(app);
|
|
583
|
-
}
|
|
638
|
+
});
|
|
584
639
|
}
|
|
585
640
|
async assertRemovesShutdownSignalListenersAfterClose() {
|
|
586
|
-
let
|
|
641
|
+
let _initProto0, _initClass0;
|
|
587
642
|
const logger = {
|
|
588
643
|
debug() {},
|
|
589
644
|
error() {},
|
|
@@ -594,12 +649,12 @@ export class HttpAdapterPortabilityHarness {
|
|
|
594
649
|
class HealthController {
|
|
595
650
|
static {
|
|
596
651
|
({
|
|
597
|
-
e: [
|
|
598
|
-
c: [_HealthController3,
|
|
652
|
+
e: [_initProto0],
|
|
653
|
+
c: [_HealthController3, _initClass0]
|
|
599
654
|
} = _applyDecs(this, [Controller('/health')], [[Get('/'), 2, "getHealth"]]));
|
|
600
655
|
}
|
|
601
656
|
constructor() {
|
|
602
|
-
|
|
657
|
+
_initProto0(this);
|
|
603
658
|
}
|
|
604
659
|
getHealth() {
|
|
605
660
|
return {
|
|
@@ -607,7 +662,7 @@ export class HttpAdapterPortabilityHarness {
|
|
|
607
662
|
};
|
|
608
663
|
}
|
|
609
664
|
static {
|
|
610
|
-
|
|
665
|
+
_initClass0();
|
|
611
666
|
}
|
|
612
667
|
}
|
|
613
668
|
class AppModule {}
|
|
@@ -615,7 +670,7 @@ export class HttpAdapterPortabilityHarness {
|
|
|
615
670
|
controllers: [_HealthController3]
|
|
616
671
|
});
|
|
617
672
|
const signal = 'SIGTERM';
|
|
618
|
-
const listenersBefore = process.listeners(signal)
|
|
673
|
+
const listenersBefore = new Set(process.listeners(signal));
|
|
619
674
|
const port = await findAvailablePort();
|
|
620
675
|
const app = await this.options.run(AppModule, {
|
|
621
676
|
cors: false,
|
|
@@ -623,14 +678,15 @@ export class HttpAdapterPortabilityHarness {
|
|
|
623
678
|
port,
|
|
624
679
|
shutdownSignals: [signal]
|
|
625
680
|
});
|
|
626
|
-
|
|
627
|
-
|
|
681
|
+
const registeredListeners = process.listeners(signal).filter(listener => !listenersBefore.has(listener));
|
|
682
|
+
await runWithCleanup(app, this.options.name, async () => {
|
|
683
|
+
if (registeredListeners.length === 0) {
|
|
628
684
|
throw new Error(`${this.options.name} adapter did not register the expected shutdown listener.`);
|
|
629
685
|
}
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
if (
|
|
686
|
+
});
|
|
687
|
+
const remainingListeners = process.listeners(signal);
|
|
688
|
+
const leakedListeners = registeredListeners.filter(listener => remainingListeners.includes(listener));
|
|
689
|
+
if (leakedListeners.length > 0) {
|
|
634
690
|
throw new Error(`${this.options.name} adapter leaked shutdown signal listeners after close().`);
|
|
635
691
|
}
|
|
636
692
|
}
|
|
@@ -648,14 +704,14 @@ export class HttpAdapterPortabilityHarness {
|
|
|
648
704
|
export function createHttpAdapterPortabilityHarness(options) {
|
|
649
705
|
return new HttpAdapterPortabilityHarness(options);
|
|
650
706
|
}
|
|
651
|
-
function withTimeout(promise, timeoutMs, message) {
|
|
707
|
+
async function withTimeout(promise, timeoutMs, message) {
|
|
652
708
|
let timeout;
|
|
653
709
|
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
654
710
|
timeout = setTimeout(() => {
|
|
655
711
|
reject(new Error(message));
|
|
656
712
|
}, timeoutMs);
|
|
657
713
|
});
|
|
658
|
-
return Promise.race([promise, timeoutPromise]).finally(() => {
|
|
714
|
+
return await Promise.race([promise, timeoutPromise]).finally(() => {
|
|
659
715
|
if (timeout !== undefined) {
|
|
660
716
|
clearTimeout(timeout);
|
|
661
717
|
}
|
|
@@ -9,18 +9,31 @@ type WebRuntimePortabilityAppLike = {
|
|
|
9
9
|
close(): Promise<void>;
|
|
10
10
|
dispatch(request: Request): Promise<Response>;
|
|
11
11
|
};
|
|
12
|
+
/**
|
|
13
|
+
* Describes the web runtime http adapter portability harness options contract.
|
|
14
|
+
*/
|
|
12
15
|
export interface WebRuntimeHttpAdapterPortabilityHarnessOptions<TBootstrapOptions extends object, TApp extends WebRuntimePortabilityAppLike = WebRuntimePortabilityAppLike> {
|
|
13
16
|
bootstrap: (rootModule: ModuleType, options: TBootstrapOptions) => Promise<TApp>;
|
|
14
17
|
name: string;
|
|
15
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Represents the web runtime http adapter portability harness.
|
|
21
|
+
*/
|
|
16
22
|
export declare class WebRuntimeHttpAdapterPortabilityHarness<TBootstrapOptions extends object, TApp extends WebRuntimePortabilityAppLike = WebRuntimePortabilityAppLike> {
|
|
17
23
|
private readonly options;
|
|
18
24
|
constructor(options: WebRuntimeHttpAdapterPortabilityHarnessOptions<TBootstrapOptions, TApp>);
|
|
25
|
+
assertPreservesQueryArraysAndDecoding(): Promise<void>;
|
|
19
26
|
assertPreservesMalformedCookieValues(): Promise<void>;
|
|
20
27
|
assertPreservesRawBodyForJsonAndText(): Promise<void>;
|
|
21
28
|
assertExcludesRawBodyForMultipart(): Promise<void>;
|
|
22
29
|
assertSupportsSseStreaming(): Promise<void>;
|
|
23
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Create web runtime http adapter portability harness.
|
|
33
|
+
*
|
|
34
|
+
* @param options The options.
|
|
35
|
+
* @returns The create web runtime http adapter portability harness result.
|
|
36
|
+
*/
|
|
24
37
|
export declare function createWebRuntimeHttpAdapterPortabilityHarness<TBootstrapOptions extends object, TApp extends WebRuntimePortabilityAppLike = WebRuntimePortabilityAppLike>(options: WebRuntimeHttpAdapterPortabilityHarnessOptions<TBootstrapOptions, TApp>): WebRuntimeHttpAdapterPortabilityHarness<TBootstrapOptions, TApp>;
|
|
25
38
|
export {};
|
|
26
39
|
//# sourceMappingURL=web-runtime-adapter-portability.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web-runtime-adapter-portability.d.ts","sourceRoot":"","sources":["../../src/portability/web-runtime-adapter-portability.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"web-runtime-adapter-portability.d.ts","sourceRoot":"","sources":["../../src/portability/web-runtime-adapter-portability.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,KAAK,UAAU,EAAE,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEnF,OAAO,QAAQ,cAAc,CAAC;IAC5B,UAAU,gBAAgB;QACxB,KAAK,CAAC,EAAE,YAAY,EAAE,CAAC;QACvB,OAAO,CAAC,EAAE,UAAU,CAAC;KACtB;CACF;AAED,KAAK,4BAA4B,GAAG;IAClC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CAC/C,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,8CAA8C,CAC7D,iBAAiB,SAAS,MAAM,EAChC,IAAI,SAAS,4BAA4B,GAAG,4BAA4B;IAExE,SAAS,EAAE,CAAC,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjF,IAAI,EAAE,MAAM,CAAC;CACd;AA0CD;;GAEG;AACH,qBAAa,uCAAuC,CAClD,iBAAiB,SAAS,MAAM,EAChC,IAAI,SAAS,4BAA4B,GAAG,4BAA4B;IAE5D,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,8CAA8C,CAAC,iBAAiB,EAAE,IAAI,CAAC;IAEvG,qCAAqC,IAAI,OAAO,CAAC,IAAI,CAAC;IAyCtD,oCAAoC,IAAI,OAAO,CAAC,IAAI,CAAC;IAgDrD,oCAAoC,IAAI,OAAO,CAAC,IAAI,CAAC;IAsErD,iCAAiC,IAAI,OAAO,CAAC,IAAI,CAAC;IAqDlD,0BAA0B,IAAI,OAAO,CAAC,IAAI,CAAC;CA8ClD;AAED;;;;;GAKG;AACH,wBAAgB,6CAA6C,CAC3D,iBAAiB,SAAS,MAAM,EAChC,IAAI,SAAS,4BAA4B,GAAG,4BAA4B,EAExE,OAAO,EAAE,8CAA8C,CAAC,iBAAiB,EAAE,IAAI,CAAC,GAC/E,uCAAuC,CAAC,iBAAiB,EAAE,IAAI,CAAC,CAElE"}
|