Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: new hooks #3878

Merged
merged 6 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -275,7 +275,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 @@ -291,7 +291,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
Loading