@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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@johntalton/http-core",
3
3
  "type": "module",
4
- "version": "1.0.5",
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.0.0",
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.age, { priv: true, maxAge: 60 }, meta) } break
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, { priv: true, maxAge: 60 }, state.supportedQueryTypes, meta)
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, { maxAge: state.maxAge }, meta) } break
109
- case 'bytes': { Response.bytes(stream, state.contentType, state.obj, state.contentLength, 'identity', state.etag, state.age, { maxAge: state.maxAge }, state.acceptRanges, meta) } break
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 { EtagItem, IMFFixDate, ContentRangeDirective, RateLimitPolicyInfo, RateLimitInfo, ChallengeItem } from '@johntalton/http-util/headers' */
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 {IMFFixDate|string|undefined} [lastModified]
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 {IMFFixDate|string|undefined} [lastModified]
299
+ * @property {IMFFixDateInput|string|undefined} [lastModified]
287
300
  * @property {EtagItem|undefined} [etag]
288
301
  * @property {number|undefined} [age]
289
- * @property {number|undefined} [maxAge]
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 {number|undefined} [maxAge]
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(this.#h2Options.config, streamId, stream, headers, this.#h2Options.serverName, this.#controller.signal)
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
- * @param {Config} config
103
- * @param {StreamID} streamId
104
- * @param {ServerHttp2Stream} stream
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
- export function preamble(config, streamId, stream, headers, servername, shutdownSignal) {
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
- config,
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, accept: acceptObject }
281
+ return { ...state, type: 'trace', method, headers, url: requestUrl, maxForwards: maxForwardsValue }
277
282
  }
278
283
 
279
284
  //