@johntalton/http-core 1.0.5 → 1.0.7
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 +6 -2
- package/src/epilogue.js +8 -8
- package/src/index.js +43 -22
- package/src/preamble.js +16 -11
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@johntalton/http-core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.7",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": "./src/index.js"
|
|
@@ -13,9 +13,13 @@
|
|
|
13
13
|
"url": "https://github.com/johntalton/http-core"
|
|
14
14
|
},
|
|
15
15
|
"scripts": {
|
|
16
|
+
"lint": "biome check"
|
|
16
17
|
},
|
|
17
18
|
"dependencies": {
|
|
18
|
-
"@johntalton/http-util": "^6.
|
|
19
|
+
"@johntalton/http-util": "^6.1.0",
|
|
19
20
|
"@johntalton/sse-util": "^1.0.0"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@biomejs/biome": "^2.4.15"
|
|
20
24
|
}
|
|
21
25
|
}
|
package/src/epilogue.js
CHANGED
|
@@ -54,10 +54,10 @@ export function epilogue(state) {
|
|
|
54
54
|
case 'trace': { Response.trace(stream, state.method, state.url, state.headers, meta) } break
|
|
55
55
|
//
|
|
56
56
|
case 'preflight': { Response.preflight(stream, state.methods, state.supportedQueryTypes, undefined, meta) } break
|
|
57
|
-
case 'no-content': { Response.noContent(stream, state.etag, meta)} break
|
|
57
|
+
case 'no-content': { Response.noContent(stream, state.etag, state.lastModified, meta)} break
|
|
58
58
|
// case 'accepted': { Response.accepted(stream, meta) } break
|
|
59
|
-
case 'created': { Response.created(stream, new URL(state.location, meta.origin), state.etag, meta) } break
|
|
60
|
-
case 'not-modified': { Response.notModified(stream, state.etag, state.
|
|
59
|
+
case 'created': { Response.created(stream, new URL(state.location, meta.origin), state.etag, state.lastModified, meta) } break
|
|
60
|
+
case 'not-modified': { Response.notModified(stream, state.etag, state.lastModified, state.age, state.cacheControl ?? {}, meta) } break
|
|
61
61
|
|
|
62
62
|
//
|
|
63
63
|
// case 'multiple-choices': { Response.multipleChoices(stream, meta) } break
|
|
@@ -74,7 +74,7 @@ export function epilogue(state) {
|
|
|
74
74
|
case 'not-acceptable': { Response.notAcceptable(stream, state.acceptableMediaTypes ?? [], meta)} break
|
|
75
75
|
case 'unsupported-media': { Response.unsupportedMediaType(stream, state.acceptableMediaTypes, state.supportedQueryTypes, meta) } break
|
|
76
76
|
case 'unprocessable': { Response.unprocessable(stream, meta) } break
|
|
77
|
-
case 'precondition-failed': { Response.preconditionFailed(stream, meta) } break
|
|
77
|
+
case 'precondition-failed': { Response.preconditionFailed(stream, state.etag, state.lastModified, meta) } break
|
|
78
78
|
case 'not-satisfiable': { Response.rangeNotSatisfiable(stream, { size: state.contentLength }, meta) } break
|
|
79
79
|
case 'content-too-large': { Response.contentTooLarge(stream, meta) } break
|
|
80
80
|
case 'insufficient-storage': { Response.insufficientStorage(stream, meta) } break
|
|
@@ -94,10 +94,10 @@ export function epilogue(state) {
|
|
|
94
94
|
}
|
|
95
95
|
break
|
|
96
96
|
case 'json': {
|
|
97
|
-
const { obj, accept, etag } = state
|
|
97
|
+
const { obj, accept, etag, lastModified } = state
|
|
98
98
|
|
|
99
99
|
if(accept.type === MIME_TYPE_JSON) {
|
|
100
|
-
Response.json(stream, obj, accept.encoding, etag, state.age,
|
|
100
|
+
Response.json(stream, obj, accept.encoding, etag, lastModified, state.age, state.cacheControl ?? {}, state.supportedQueryTypes, meta)
|
|
101
101
|
}
|
|
102
102
|
else {
|
|
103
103
|
// todo: but we did process the request - is that ok?
|
|
@@ -105,8 +105,8 @@ export function epilogue(state) {
|
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
break
|
|
108
|
-
case 'partial-bytes': { Response.partialContent(stream, state.contentType, state.objs, state.contentLength, undefined, state.etag, state.age,
|
|
109
|
-
case 'bytes': { Response.bytes(stream, state.contentType, state.obj, state.contentLength, 'identity', state.etag, state.age,
|
|
108
|
+
case 'partial-bytes': { Response.partialContent(stream, state.contentType, state.objs, state.contentLength, undefined, state.etag, state.lastModified, state.age, state.cacheControl ?? {}, meta) } break
|
|
109
|
+
case 'bytes': { Response.bytes(stream, state.contentType, state.obj, state.contentLength, 'identity', state.etag, state.lastModified, state.age, state.cacheControl ?? {}, state.acceptRanges, meta) } break
|
|
110
110
|
|
|
111
111
|
//
|
|
112
112
|
case 'error': {
|
package/src/index.js
CHANGED
|
@@ -42,7 +42,16 @@ export const KNOWN_METHODS = [
|
|
|
42
42
|
|
|
43
43
|
/** @import { Metadata } from '@johntalton/http-util/response' */
|
|
44
44
|
/** @import { BodyFuture } from '@johntalton/http-util/body' */
|
|
45
|
-
/** @import {
|
|
45
|
+
/** @import {
|
|
46
|
+
EtagItem,
|
|
47
|
+
IMFFixDate,
|
|
48
|
+
IMFFixDateInput,
|
|
49
|
+
ContentRangeDirective,
|
|
50
|
+
RateLimitPolicyInfo,
|
|
51
|
+
RateLimitInfo,
|
|
52
|
+
ChallengeItem,
|
|
53
|
+
CacheControlOptions
|
|
54
|
+
} from '@johntalton/http-util/headers' */
|
|
46
55
|
/** @import { SendBody } from '@johntalton/http-util/response' */
|
|
47
56
|
/** @import { SecFetchSite, SecFetchMode, SecFetchDest } from '@johntalton/http-util/headers' */
|
|
48
57
|
|
|
@@ -102,6 +111,20 @@ export const KNOWN_METHODS = [
|
|
|
102
111
|
* @property {AbortSignal} shutdownSignal
|
|
103
112
|
*/
|
|
104
113
|
|
|
114
|
+
/**
|
|
115
|
+
* @typedef {Object} RouteRequestAccept
|
|
116
|
+
* @property {string|undefined} type
|
|
117
|
+
* @property {string|undefined} encoding
|
|
118
|
+
* @property {string|undefined} language
|
|
119
|
+
*/
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* @typedef {Object} RouteRemoteClient
|
|
123
|
+
* @property {string|undefined} family
|
|
124
|
+
* @property {string|undefined} ip
|
|
125
|
+
* @property {number|undefined} port
|
|
126
|
+
*/
|
|
127
|
+
|
|
105
128
|
/**
|
|
106
129
|
* @typedef {Object} RouteRequestBase
|
|
107
130
|
* @property {'request'} type
|
|
@@ -141,24 +164,9 @@ export const KNOWN_METHODS = [
|
|
|
141
164
|
* @property {URL} url
|
|
142
165
|
* @property {IncomingHttpHeaders} headers
|
|
143
166
|
* @property {number} maxForwards
|
|
144
|
-
* @property {RouteRequestAccept} accept
|
|
145
167
|
*/
|
|
146
168
|
/** @typedef {RouteBase & RouteTraceBase} RouteTrace */
|
|
147
169
|
|
|
148
|
-
/**
|
|
149
|
-
* @typedef {Object} RouteRequestAccept
|
|
150
|
-
* @property {string|undefined} type
|
|
151
|
-
* @property {string|undefined} encoding
|
|
152
|
-
* @property {string|undefined} language
|
|
153
|
-
*/
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* @typedef {Object} RouteRemoteClient
|
|
157
|
-
* @property {string|undefined} family
|
|
158
|
-
* @property {string|undefined} ip
|
|
159
|
-
* @property {number|undefined} port
|
|
160
|
-
*/
|
|
161
|
-
|
|
162
170
|
/**
|
|
163
171
|
* @typedef {Object} RouteConditions
|
|
164
172
|
* @property {Array<EtagItem>} match
|
|
@@ -191,9 +199,10 @@ export const KNOWN_METHODS = [
|
|
|
191
199
|
* @property {'json'} type
|
|
192
200
|
* @property {RouteRequestAccept} accept
|
|
193
201
|
* @property {Record<any, any>} obj
|
|
194
|
-
* @property {
|
|
202
|
+
* @property {IMFFixDateInput|string|undefined} [lastModified]
|
|
195
203
|
* @property {EtagItem|undefined} [etag]
|
|
196
204
|
* @property {number|undefined} [age]
|
|
205
|
+
* @property {CacheControlOptions|undefined} [cacheControl]
|
|
197
206
|
* @property {Array<string>|undefined} [supportedQueryTypes]
|
|
198
207
|
*/
|
|
199
208
|
/** @typedef {RouteBase & RouteJSONBase} RouteJSON */
|
|
@@ -212,6 +221,7 @@ export const KNOWN_METHODS = [
|
|
|
212
221
|
* @property {'created'} type
|
|
213
222
|
* @property {URL|string} location
|
|
214
223
|
* @property {EtagItem|undefined} [etag]
|
|
224
|
+
* @property {IMFFixDateInput|string|undefined} [lastModified]
|
|
215
225
|
*/
|
|
216
226
|
/** @typedef {RouteBase & RouteCreatedBase} RouteCreated */
|
|
217
227
|
|
|
@@ -228,7 +238,9 @@ export const KNOWN_METHODS = [
|
|
|
228
238
|
* @property {'not-modified'} type
|
|
229
239
|
* @property {number} age
|
|
230
240
|
* @property {EtagItem|undefined} [etag]
|
|
241
|
+
* @property {IMFFixDateInput|string|undefined} [lastModified]
|
|
231
242
|
* @property {number|undefined} [age]
|
|
243
|
+
* @property {CacheControlOptions|undefined} [cacheControl]
|
|
232
244
|
*/
|
|
233
245
|
/** @typedef {RouteBase & RouteNotModifiedBase} RouteNotModified */
|
|
234
246
|
|
|
@@ -236,6 +248,7 @@ export const KNOWN_METHODS = [
|
|
|
236
248
|
* @typedef {Object} RoutePreconditionFailedBase
|
|
237
249
|
* @property {'precondition-failed'} type
|
|
238
250
|
* @property {EtagItem|undefined} [etag]
|
|
251
|
+
* @property {IMFFixDateInput|string|undefined} [lastModified]
|
|
239
252
|
*/
|
|
240
253
|
/** @typedef {RouteBase & RoutePreconditionFailedBase} RoutePreconditionFailed */
|
|
241
254
|
|
|
@@ -283,10 +296,10 @@ export const KNOWN_METHODS = [
|
|
|
283
296
|
* @property {string} contentType
|
|
284
297
|
* @property {number|undefined} [contentLength]
|
|
285
298
|
* @property {SendBody|undefined} obj
|
|
286
|
-
* @property {
|
|
299
|
+
* @property {IMFFixDateInput|string|undefined} [lastModified]
|
|
287
300
|
* @property {EtagItem|undefined} [etag]
|
|
288
301
|
* @property {number|undefined} [age]
|
|
289
|
-
* @property {
|
|
302
|
+
* @property {CacheControlOptions|undefined} [cacheControl]
|
|
290
303
|
* @property {'bytes'|'none'|undefined} [acceptRanges]
|
|
291
304
|
*/
|
|
292
305
|
/** @typedef {RouteBase & RouteBytesBase} RouteBytes */
|
|
@@ -309,8 +322,9 @@ export const KNOWN_METHODS = [
|
|
|
309
322
|
* @property {string} contentType
|
|
310
323
|
* @property {number|undefined} [contentLength]
|
|
311
324
|
* @property {EtagItem|undefined} [etag]
|
|
325
|
+
* @property {IMFFixDateInput|string|undefined} [lastModified]
|
|
312
326
|
* @property {number|undefined} [age]
|
|
313
|
-
* @property {
|
|
327
|
+
* @property {CacheControlOptions|undefined} [cacheControl]
|
|
314
328
|
*/
|
|
315
329
|
/** @typedef {RouteBase & RoutePartialBytesBase} RoutePartialBytes */
|
|
316
330
|
|
|
@@ -353,6 +367,7 @@ export const KNOWN_METHODS = [
|
|
|
353
367
|
* @typedef {Object} RouteNoContentBase
|
|
354
368
|
* @property {'no-content'} type
|
|
355
369
|
* @property {EtagItem|undefined} [etag]
|
|
370
|
+
* @property {IMFFixDateInput|string|undefined} [lastModified]
|
|
356
371
|
*/
|
|
357
372
|
/** @typedef {RouteBase & RouteNoContentBase} RouteNoContent */
|
|
358
373
|
|
|
@@ -407,7 +422,6 @@ export const KNOWN_METHODS = [
|
|
|
407
422
|
* @property {boolean} active
|
|
408
423
|
* @property {boolean} bom
|
|
409
424
|
* @property {MessagePort} port
|
|
410
|
-
* @property {RouteRequestAccept} accept
|
|
411
425
|
*/
|
|
412
426
|
/** @typedef {RouteBase & RouteSSEBase} RouteSSE */
|
|
413
427
|
|
|
@@ -615,7 +629,14 @@ export class H2CoreServer {
|
|
|
615
629
|
if(!isServerStream(stream)) { return }
|
|
616
630
|
|
|
617
631
|
// const start = performance.now()
|
|
618
|
-
const state = preamble(
|
|
632
|
+
const state = preamble({
|
|
633
|
+
config: this.#h2Options.config,
|
|
634
|
+
streamId,
|
|
635
|
+
stream,
|
|
636
|
+
shutdownSignal: this.#controller.signal
|
|
637
|
+
},
|
|
638
|
+
headers,
|
|
639
|
+
this.#h2Options.serverName)
|
|
619
640
|
router(state)
|
|
620
641
|
.then(epilogue)
|
|
621
642
|
.catch(e => epilogue({ ...state, type: 'error', cause: e.message, error: e }))
|
package/src/preamble.js
CHANGED
|
@@ -99,16 +99,24 @@ const BODY_BYTE_LENGTH = BYTE_PER_K * BYTE_PER_K
|
|
|
99
99
|
// }
|
|
100
100
|
|
|
101
101
|
/**
|
|
102
|
-
* @
|
|
103
|
-
* @
|
|
104
|
-
* @
|
|
102
|
+
* @typedef {Object} PreState
|
|
103
|
+
* @property {Config} config
|
|
104
|
+
* @property {StreamID} streamId
|
|
105
|
+
* @property {ServerHttp2Stream} stream
|
|
106
|
+
* @property {AbortSignal} shutdownSignal
|
|
107
|
+
*/
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* @param {PreState} preState
|
|
105
111
|
* @param {IncomingHttpHeaders} headers
|
|
106
112
|
* @param {string|undefined} servername
|
|
107
|
-
* @param {AbortSignal} shutdownSignal
|
|
108
113
|
* @returns {RouteRequest|RouteAction}
|
|
109
114
|
*/
|
|
110
|
-
|
|
115
|
+
|
|
116
|
+
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: work horse
|
|
117
|
+
export function preamble(preState, headers, servername) {
|
|
111
118
|
const preambleStart = performance.now()
|
|
119
|
+
const { stream, shutdownSignal } = preState
|
|
112
120
|
|
|
113
121
|
//
|
|
114
122
|
const method = headers[HTTP2_HEADER_METHOD]
|
|
@@ -159,16 +167,13 @@ export function preamble(config, streamId, stream, headers, servername, shutdown
|
|
|
159
167
|
const state = {
|
|
160
168
|
type: 'error',
|
|
161
169
|
cause: 'initialize',
|
|
162
|
-
|
|
163
|
-
streamId,
|
|
164
|
-
stream,
|
|
170
|
+
...preState,
|
|
165
171
|
meta: {
|
|
166
172
|
servername,
|
|
167
173
|
performance: [],
|
|
168
174
|
origin: allowedOrigin,
|
|
169
175
|
customHeaders: []
|
|
170
|
-
}
|
|
171
|
-
shutdownSignal
|
|
176
|
+
}
|
|
172
177
|
}
|
|
173
178
|
|
|
174
179
|
if(shutdownSignal.aborted) {
|
|
@@ -273,7 +278,7 @@ export function preamble(config, streamId, stream, headers, servername, shutdown
|
|
|
273
278
|
const preambleEnd = performance.now()
|
|
274
279
|
state.meta.performance.push({ name: 'preamble-trace', duration: preambleEnd - preambleStart })
|
|
275
280
|
if(acceptObject.type !== MIME_TYPE_MESSAGE_HTTP) { return { ...state, type: 'not-acceptable', acceptableMediaTypes: [ MIME_TYPE_MESSAGE_HTTP ] } }
|
|
276
|
-
return { ...state, type: 'trace', method, headers, url: requestUrl, maxForwards: maxForwardsValue
|
|
281
|
+
return { ...state, type: 'trace', method, headers, url: requestUrl, maxForwards: maxForwardsValue }
|
|
277
282
|
}
|
|
278
283
|
|
|
279
284
|
//
|