Skip to content

Commit

Permalink
feat: new hooks (#3878)
Browse files Browse the repository at this point in the history
* feat: new hooks

* fixup

* fixup

* fixup

* fixup

* fixup
  • Loading branch information
ronag authored Nov 25, 2024
1 parent 9b8abb8 commit 67f3c96
Show file tree
Hide file tree
Showing 32 changed files with 399 additions and 415 deletions.
14 changes: 6 additions & 8 deletions docs/docs/api/Dispatcher.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,14 +205,12 @@ Returns: `Boolean` - `false` if dispatcher is busy and further dispatch calls wo

#### Parameter: `DispatchHandler`

* **onConnect** `(abort: () => void, context: object) => void` - Invoked before request is dispatched on socket. May be invoked multiple times when a request is retried when the request at the head of the pipeline fails.
* **onError** `(error: Error) => void` - Invoked when an error has occurred. May not throw.
* **onUpgrade** `(statusCode: number, headers: Buffer[], socket: Duplex) => void` (optional) - Invoked when request is upgraded. Required if `DispatchOptions.upgrade` is defined or `DispatchOptions.method === 'CONNECT'`.
* **onResponseStarted** `() => void` (optional) - Invoked when response is received, before headers have been read.
* **onHeaders** `(statusCode: number, headers: Buffer[], resume: () => void, statusText: string) => boolean` - Invoked when statusCode and headers have been received. May be invoked multiple times due to 1xx informational headers. Not required for `upgrade` requests.
* **onData** `(chunk: Buffer) => boolean` - Invoked when response payload data is received. Not required for `upgrade` requests.
* **onComplete** `(trailers: Buffer[]) => void` - Invoked when response payload and trailers have been received and the request has completed. Not required for `upgrade` requests.
* **onBodySent** `(chunk: string | Buffer | Uint8Array) => void` - Invoked when a body chunk is sent to the server. Not required. For a stream or iterable body this will be invoked for every chunk. For other body types, it will be invoked once after the body is sent.
* **onRequestStart** `(controller: DispatchController, context: object) => void` - Invoked before request is dispatched on socket. May be invoked multiple times when a request is retried when the request at the head of the pipeline fails.
* **onRequestUpgrade** `(controller: DispatchController, statusCode: number, headers: Record<string, string | string[]>, socket: Duplex) => void` (optional) - Invoked when request is upgraded. Required if `DispatchOptions.upgrade` is defined or `DispatchOptions.method === 'CONNECT'`.
* **onResponseStart** `(controller: DispatchController, statusCode: number, statusMessage?: string, headers: Record<string, string | string []>) => void` - Invoked when statusCode and headers have been received. May be invoked multiple times due to 1xx informational headers. Not required for `upgrade` requests.
* **onResponseData** `(controller: DispatchController, chunk: Buffer) => void` - Invoked when response payload data is received. Not required for `upgrade` requests.
* **onResponseEnd** `(controller: DispatchController, trailers: Record<string, string | string[]>) => void` - Invoked when response payload and trailers have been received and the request has completed. Not required for `upgrade` requests.
* **onResponseError** `(error: Error) => void` - Invoked when an error has occurred. May not throw.

#### Example 1 - Dispatch GET request

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/api/RedirectHandler.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Returns: `RedirectHandler`

### Parameters

- **dispatch** `(options: Dispatch.DispatchOptions, handlers: Dispatch.DispatchHandlers) => Promise<Dispatch.DispatchResponse>` (required) - Dispatch function to be called after every redirection.
- **dispatch** `(options: Dispatch.DispatchOptions, handlers: Dispatch.DispatchHandler) => Promise<Dispatch.DispatchResponse>` (required) - Dispatch function to be called after every redirection.
- **maxRedirections** `number` (required) - Maximum number of redirections allowed.
- **opts** `object` (required) - Options for handling redirection.
- **handler** `object` (required) - Handlers for different stages of the request lifecycle.
Expand Down
4 changes: 2 additions & 2 deletions docs/docs/api/RetryHandler.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ It represents the retry state for a given request.

### Parameter `RetryHandlers`

- **dispatch** `(options: Dispatch.DispatchOptions, handlers: Dispatch.DispatchHandlers) => Promise<Dispatch.DispatchResponse>` (required) - Dispatch function to be called after every retry.
- **handler** Extends [`Dispatch.DispatchHandlers`](/docs/docs/api/Dispatcher.md#dispatcherdispatchoptions-handler) (required) - Handler function to be called after the request is successful or the retries are exhausted.
- **dispatch** `(options: Dispatch.DispatchOptions, handlers: Dispatch.DispatchHandler) => Promise<Dispatch.DispatchResponse>` (required) - Dispatch function to be called after every retry.
- **handler** Extends [`Dispatch.DispatchHandler`](/docs/docs/api/Dispatcher.md#dispatcherdispatchoptions-handler) (required) - Handler function to be called after the request is successful or the retries are exhausted.

>__Note__: The `RetryHandler` does not retry over stateful bodies (e.g. streams, AsyncIterable) as those, once consumed, are left in a state that cannot be reutilized. For these situations the `RetryHandler` will identify
>the body as stateful and will not retry the request rejecting with the error `UND_ERR_REQ_RETRY`.
Expand Down
2 changes: 1 addition & 1 deletion lib/cache/memory-cache-store.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ class MemoryCacheStore {
: {
statusMessage: entry.statusMessage,
statusCode: entry.statusCode,
rawHeaders: entry.rawHeaders,
headers: entry.headers,
body: entry.body,
etag: entry.etag,
cachedAt: entry.cachedAt,
Expand Down
18 changes: 9 additions & 9 deletions lib/cache/sqlite-cache-store.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ const { DatabaseSync } = require('node:sqlite')
const { Writable } = require('stream')
const { assertCacheKey, assertCacheValue } = require('../util/cache.js')

const VERSION = 1
const VERSION = 2

/**
* @typedef {import('../../types/cache-interceptor.d.ts').default.CacheStore} CacheStore
* @implements {CacheStore}
*
* @typedef {{
* id: Readonly<number>
* rawHeaders?: string
* headers?: Record<string, string | string[]>
* vary?: string | object
* body: string
* } & import('../../types/cache-interceptor.d.ts').default.CacheValue} SqliteStoreValue
Expand Down Expand Up @@ -107,7 +107,7 @@ class SqliteCacheStore {
deleteAt INTEGER NOT NULL,
statusCode INTEGER NOT NULL,
statusMessage TEXT NOT NULL,
rawHeaders TEXT NULL,
headers TEXT NULL,
etag TEXT NULL,
vary TEXT NULL,
cachedAt INTEGER NOT NULL,
Expand All @@ -126,7 +126,7 @@ class SqliteCacheStore {
deleteAt,
statusCode,
statusMessage,
rawHeaders,
headers,
etag,
vary,
cachedAt,
Expand All @@ -145,7 +145,7 @@ class SqliteCacheStore {
deleteAt = ?,
statusCode = ?,
statusMessage = ?,
rawHeaders = ?,
headers = ?,
etag = ?,
cachedAt = ?,
staleAt = ?,
Expand All @@ -162,7 +162,7 @@ class SqliteCacheStore {
deleteAt,
statusCode,
statusMessage,
rawHeaders,
headers,
etag,
vary,
cachedAt,
Expand Down Expand Up @@ -221,7 +221,7 @@ class SqliteCacheStore {
body: value.body ? parseBufferArray(JSON.parse(value.body)) : null,
statusCode: value.statusCode,
statusMessage: value.statusMessage,
rawHeaders: value.rawHeaders ? parseBufferArray(JSON.parse(value.rawHeaders)) : undefined,
headers: value.headers ? JSON.parse(value.headers) : undefined,
etag: value.etag ? value.etag : undefined,
cachedAt: value.cachedAt,
staleAt: value.staleAt,
Expand Down Expand Up @@ -273,7 +273,7 @@ class SqliteCacheStore {
value.deleteAt,
value.statusCode,
value.statusMessage,
value.rawHeaders ? JSON.stringify(stringifyBufferArray(value.rawHeaders)) : null,
value.headers ? JSON.stringify(value.headers) : null,
value.etag,
value.cachedAt,
value.staleAt,
Expand All @@ -290,7 +290,7 @@ class SqliteCacheStore {
value.deleteAt,
value.statusCode,
value.statusMessage,
value.rawHeaders ? JSON.stringify(stringifyBufferArray(value.rawHeaders)) : null,
value.headers ? JSON.stringify(value.headers) : null,
value.etag ? value.etag : null,
value.vary ? JSON.stringify(value.vary) : null,
value.cachedAt,
Expand Down
5 changes: 5 additions & 0 deletions lib/core/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,11 @@ function assertRequestHandler (handler, method, upgrade) {
throw new InvalidArgumentError('handler must be an object')
}

if (typeof handler.onRequestStart === 'function') {
// TODO (fix): More checks...
return
}

if (typeof handler.onConnect !== 'function') {
throw new InvalidArgumentError('invalid onConnect method')
}
Expand Down
3 changes: 2 additions & 1 deletion lib/dispatcher/dispatcher-base.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict'

const Dispatcher = require('./dispatcher')
const UnwrapHandler = require('../handler/unwrap-handler')
const {
ClientDestroyedError,
ClientClosedError,
Expand Down Expand Up @@ -142,7 +143,7 @@ class DispatcherBase extends Dispatcher {
throw new ClientClosedError()
}

return this[kDispatch](opts, handler)
return this[kDispatch](opts, UnwrapHandler.unwrap(handler))
} catch (err) {
if (typeof handler.onError !== 'function') {
throw new InvalidArgumentError('invalid onError method')
Expand Down
4 changes: 4 additions & 0 deletions lib/dispatcher/dispatcher.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
'use strict'
const EventEmitter = require('node:events')
const WrapHandler = require('../handler/wrap-handler')

const wrapInterceptor = (dispatch) => (opts, handler) => dispatch(opts, WrapHandler.wrap(handler))

class Dispatcher extends EventEmitter {
dispatch () {
Expand Down Expand Up @@ -29,6 +32,7 @@ class Dispatcher extends EventEmitter {
}

dispatch = interceptor(dispatch)
dispatch = wrapInterceptor(dispatch)

if (dispatch == null || typeof dispatch !== 'function' || dispatch.length !== 2) {
throw new TypeError('invalid interceptor')
Expand Down
Loading

0 comments on commit 67f3c96

Please sign in to comment.