@johntalton/http-core 1.1.0 → 1.1.1
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 +2 -2
- package/src/epilogue.js +6 -14
- package/src/index.js +21 -4
- package/src/preamble.js +23 -9
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@johntalton/http-core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.1.
|
|
4
|
+
"version": "1.1.1",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": "./src/index.js"
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"lint": "biome check"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@johntalton/http-util": "^7.0.
|
|
19
|
+
"@johntalton/http-util": "^7.0.2",
|
|
20
20
|
"@johntalton/sse-util": "^1.0.0"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
package/src/epilogue.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { MIME_TYPE_JSON } from '@johntalton/http-util/headers'
|
|
2
1
|
import { Response } from '@johntalton/http-util/response/object'
|
|
3
2
|
import { ServerSentEvents } from '@johntalton/sse-util'
|
|
4
3
|
|
|
@@ -18,11 +17,11 @@ function addSSEPortHandler(stream, port, streamId, shutdownSignal) {
|
|
|
18
17
|
stream.end()
|
|
19
18
|
}
|
|
20
19
|
|
|
21
|
-
stream.once('close', (
|
|
20
|
+
stream.once('close', () => {
|
|
22
21
|
console.log('stream close in sse handler', streamId)
|
|
23
22
|
shutdownSignal.removeEventListener('abort', signalHandler)
|
|
24
23
|
port.close()
|
|
25
|
-
})
|
|
24
|
+
})
|
|
26
25
|
|
|
27
26
|
shutdownSignal.addEventListener('abort', signalHandler, { once: true })
|
|
28
27
|
|
|
@@ -97,15 +96,8 @@ export function epilogue(state) {
|
|
|
97
96
|
if(active) { addSSEPortHandler(stream, port, state.streamId, state.shutdownSignal) }
|
|
98
97
|
} break
|
|
99
98
|
case 'json': {
|
|
100
|
-
const { obj,
|
|
101
|
-
|
|
102
|
-
if(accept.type === MIME_TYPE_JSON) {
|
|
103
|
-
Response.json(stream, obj, { encoding: accept.encoding, etag, lastModified, age, cacheControl: state.cacheControl ?? {} }, { supportedQueryTypes }, meta)
|
|
104
|
-
}
|
|
105
|
-
else {
|
|
106
|
-
// todo: but we did process the request - is that ok?
|
|
107
|
-
Response.notAcceptable(stream, { supportedTypes: [ MIME_TYPE_JSON ] }, meta)
|
|
108
|
-
}
|
|
99
|
+
const { obj, encoding, etag, lastModified, age, supportedQueryTypes } = state
|
|
100
|
+
Response.json(stream, obj, { encoding, etag, lastModified, age, cacheControl: state.cacheControl ?? {} }, { supportedQueryTypes }, meta)
|
|
109
101
|
} break
|
|
110
102
|
case 'partial-bytes': {
|
|
111
103
|
const { contentType, contentLength, etag, lastModified, age } = state
|
|
@@ -120,12 +112,12 @@ export function epilogue(state) {
|
|
|
120
112
|
cacheControl: state.cacheControl ?? {} }, meta)
|
|
121
113
|
} break
|
|
122
114
|
case 'bytes': {
|
|
123
|
-
const { contentType, contentLength, etag, lastModified, age, acceptRanges } = state
|
|
115
|
+
const { contentType, contentLength, encoding, etag, lastModified, age, acceptRanges } = state
|
|
124
116
|
|
|
125
117
|
Response.bytes(stream, state.obj, {
|
|
126
118
|
contentType,
|
|
127
119
|
contentLength,
|
|
128
|
-
encoding: 'identity',
|
|
120
|
+
encoding: encoding ?? 'identity',
|
|
129
121
|
etag,
|
|
130
122
|
lastModified,
|
|
131
123
|
age,
|
package/src/index.js
CHANGED
|
@@ -43,6 +43,7 @@ export const KNOWN_METHODS = [
|
|
|
43
43
|
/** @import { Metadata } from '@johntalton/http-util/response' */
|
|
44
44
|
/** @import { BodyFuture } from '@johntalton/http-util/body' */
|
|
45
45
|
/** @import {
|
|
46
|
+
AcceptItem,
|
|
46
47
|
EtagItem,
|
|
47
48
|
IMFFixDate,
|
|
48
49
|
IMFFixDateInput,
|
|
@@ -52,6 +53,7 @@ export const KNOWN_METHODS = [
|
|
|
52
53
|
ChallengeItem,
|
|
53
54
|
CacheControlOptions
|
|
54
55
|
} from '@johntalton/http-util/headers' */
|
|
56
|
+
/** @import { AcceptStyleItem } from '@johntalton/http-util/util' */
|
|
55
57
|
/** @import { SendBody } from '@johntalton/http-util/response' */
|
|
56
58
|
/** @import { SecFetchSite, SecFetchMode, SecFetchDest } from '@johntalton/http-util/headers' */
|
|
57
59
|
|
|
@@ -119,8 +121,24 @@ export const KNOWN_METHODS = [
|
|
|
119
121
|
* @property {AbortSignal} shutdownSignal
|
|
120
122
|
*/
|
|
121
123
|
|
|
124
|
+
/**
|
|
125
|
+
* @typedef {Object} RouteRequestAcceptParsed
|
|
126
|
+
* @property {Array<AcceptItem> | undefined} type
|
|
127
|
+
* @property {Array<AcceptStyleItem> | undefined} encoding
|
|
128
|
+
* @property {Array<AcceptStyleItem>} language
|
|
129
|
+
*/
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* @typedef {Object} RouteRequestAcceptFn
|
|
133
|
+
* @property {(a: Array<string>|undefined) => AcceptItem|undefined} type
|
|
134
|
+
* @property {(a: Array<string>|undefined) => AcceptStyleItem|undefined} encoding
|
|
135
|
+
* @property {(a: Array<string>|undefined) => AcceptStyleItem|undefined} language
|
|
136
|
+
*/
|
|
137
|
+
|
|
122
138
|
/**
|
|
123
139
|
* @typedef {Object} RouteRequestAccept
|
|
140
|
+
* @property {RouteRequestAcceptParsed} parsed
|
|
141
|
+
* @property {RouteRequestAcceptFn} select
|
|
124
142
|
* @property {string|undefined} type
|
|
125
143
|
* @property {string|undefined} encoding
|
|
126
144
|
* @property {string|undefined} language
|
|
@@ -405,8 +423,9 @@ export const KNOWN_METHODS = [
|
|
|
405
423
|
* @typedef {Object} RouteBytesBase
|
|
406
424
|
* @property {'bytes'} type
|
|
407
425
|
* @property {string} contentType
|
|
408
|
-
* @property {number|undefined} [contentLength]
|
|
409
426
|
* @property {SendBody|undefined} obj
|
|
427
|
+
* @property {number|undefined} [contentLength]
|
|
428
|
+
* @property {string | undefined} [encoding]
|
|
410
429
|
* @property {IMFFixDateInput|string|undefined} [lastModified]
|
|
411
430
|
* @property {EtagItem|undefined} [etag]
|
|
412
431
|
* @property {number|undefined} [age]
|
|
@@ -415,8 +434,6 @@ export const KNOWN_METHODS = [
|
|
|
415
434
|
*/
|
|
416
435
|
/** @typedef {RouteBase & RouteBytesBase} RouteBytes */
|
|
417
436
|
|
|
418
|
-
|
|
419
|
-
|
|
420
437
|
/**
|
|
421
438
|
* @typedef {Object} RoutePartialBytesBase
|
|
422
439
|
* @property {'partial-bytes'} type
|
|
@@ -433,8 +450,8 @@ export const KNOWN_METHODS = [
|
|
|
433
450
|
/**
|
|
434
451
|
* @typedef {Object} RouteJSONBase
|
|
435
452
|
* @property {'json'} type
|
|
436
|
-
* @property {RouteRequestAccept} accept
|
|
437
453
|
* @property {Record<any, any>} obj
|
|
454
|
+
* @property {string | undefined} [encoding]
|
|
438
455
|
* @property {IMFFixDateInput|string|undefined} [lastModified]
|
|
439
456
|
* @property {EtagItem|undefined} [etag]
|
|
440
457
|
* @property {number|undefined} [age]
|
package/src/preamble.js
CHANGED
|
@@ -35,7 +35,7 @@ import {
|
|
|
35
35
|
import { isValidHeader, isValidLikeHeader, isValidMethod } from './index.js'
|
|
36
36
|
|
|
37
37
|
/** @import { ServerHttp2Stream, IncomingHttpHeaders } from 'node:http2' */
|
|
38
|
-
/** @import { Config, RouteRequest, RouteAction, StreamID, RouteConditions, SecFetchMetadata } from './index.js' */
|
|
38
|
+
/** @import { Config, RouteRequest, RouteAction, StreamID, RouteConditions, SecFetchMetadata, RouteRequestAccept } from './index.js' */
|
|
39
39
|
|
|
40
40
|
const { HTTP2_METHOD_OPTIONS, HTTP2_METHOD_TRACE } = http2.constants
|
|
41
41
|
|
|
@@ -258,21 +258,34 @@ export function preamble(preState, headers, servername) {
|
|
|
258
258
|
//
|
|
259
259
|
// content negotiation
|
|
260
260
|
//
|
|
261
|
-
const
|
|
262
|
-
const
|
|
263
|
-
const
|
|
264
|
-
|
|
261
|
+
const acceptItem = Accept.parse(fullAccept)
|
|
262
|
+
const acceptEncodingItem = AcceptEncoding.parse(fullAcceptEncoding)
|
|
263
|
+
const acceptLanguageItem = AcceptLanguage.parse(fullAcceptLanguage)
|
|
264
|
+
|
|
265
|
+
/** @type {RouteRequestAccept} */
|
|
265
266
|
const acceptObject = {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
267
|
+
parsed: {
|
|
268
|
+
type: acceptItem,
|
|
269
|
+
encoding: acceptEncodingItem,
|
|
270
|
+
language: acceptLanguageItem,
|
|
271
|
+
},
|
|
272
|
+
|
|
273
|
+
get type() { return Accept.selectFrom(acceptItem, DEFAULT_SUPPORTED_MIME_TYPES) },
|
|
274
|
+
get encoding() { return AcceptEncoding.selectFrom(acceptEncodingItem, DEFAULT_SUPPORTED_ENCODINGS) },
|
|
275
|
+
get language() { return AcceptLanguage.selectFrom(acceptLanguageItem, DEFAULT_SUPPORTED_LANGUAGES) },
|
|
276
|
+
|
|
277
|
+
select: {
|
|
278
|
+
type: acceptableTypes => Accept.selectItemFrom(acceptItem, acceptableTypes ?? DEFAULT_SUPPORTED_MIME_TYPES),
|
|
279
|
+
encoding: acceptableEncodings => AcceptEncoding.selectItemFrom(acceptEncodingItem, acceptableEncodings ?? DEFAULT_SUPPORTED_ENCODINGS),
|
|
280
|
+
language: acceptableLanguages => AcceptLanguage.selectItemFrom(acceptLanguageItem, acceptableLanguages ?? DEFAULT_SUPPORTED_LANGUAGES)
|
|
281
|
+
}
|
|
269
282
|
}
|
|
270
283
|
|
|
271
284
|
//
|
|
272
285
|
// Trace
|
|
273
286
|
//
|
|
274
287
|
if(method === HTTP2_METHOD_TRACE) {
|
|
275
|
-
if(!ALLOW_TRACE) { return { ...state, type: 'not-allowed', method, methods: []
|
|
288
|
+
if(!ALLOW_TRACE) { return { ...state, type: 'not-allowed', method, methods: [] }}
|
|
276
289
|
const maxForwardsValue = maxForwards === undefined ? 0 : Number.parseInt(maxForwards)
|
|
277
290
|
const preambleEnd = performance.now()
|
|
278
291
|
state.meta.performance.push({ name: 'preamble-trace', duration: preambleEnd - preambleStart })
|
|
@@ -283,6 +296,7 @@ export function preamble(preState, headers, servername) {
|
|
|
283
296
|
//
|
|
284
297
|
// setup future body
|
|
285
298
|
//
|
|
299
|
+
const contentType = ContentType.parse(fullContentType)
|
|
286
300
|
const contentLength = fullContentLength === undefined ? undefined : Number.parseInt(fullContentLength, 10)
|
|
287
301
|
const body = requestBody(stream, {
|
|
288
302
|
byteLimit: BODY_BYTE_LENGTH,
|