shelving 1.180.0 → 1.181.0

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.
@@ -5,7 +5,7 @@ import type { AnyCaller } from "../../util/function.js";
5
5
  import type { RequestMethod, RequestParams } from "../../util/http.js";
6
6
  import type { AbsolutePath } from "../../util/path.js";
7
7
  import { type TemplatePlaceholders } from "../../util/template.js";
8
- import type { EndpointCallback, EndpointContext, EndpointHandler } from "./util.js";
8
+ import type { EndpointCallback, EndpointHandler } from "./util.js";
9
9
  /**
10
10
  * An abstract API resource definition, used to specify types for e.g. serverless functions.
11
11
  *
@@ -44,7 +44,7 @@ export declare class Endpoint<P, R> {
44
44
  * @param callback The callback function that implements the logic for this endpoint by receiving the payload and returning the response.
45
45
  * @returns An `EndpointHandler` object combining this endpoint and the callback into a single typed object.
46
46
  */
47
- handler<C extends EndpointContext>(callback: EndpointCallback<P, R, C>): EndpointHandler<P, R, C>;
47
+ handler<C>(callback: EndpointCallback<P, R, C>): EndpointHandler<P, R, C>;
48
48
  /** Convert to string, e.g. `GET /user/{id}` */
49
49
  toString(): string;
50
50
  }
@@ -1,32 +1,26 @@
1
1
  import type { AnyCaller } from "../../util/function.js";
2
2
  import { type PossibleURL } from "../../util/url.js";
3
3
  import type { Endpoint } from "./Endpoint.js";
4
- /**
5
- * The second argument to an `EndpointCallback` is its context.
6
- * This must contain the `Request` that triggered the callback, but may contain additional details too. */
7
- export interface EndpointContext {
8
- readonly request: Request;
9
- }
10
4
  /**
11
5
  * A function that handles an endpoint request, with a payload and returns a result.
12
6
  *
13
7
  * @param payload The payload for the callback combining the `{placeholders}`, `?search` params, and body content (this has been validated against the Endpoint's payload schema).
14
8
  * @param request The original incoming request object.
15
- * @param args Any additional arguments to pass into the endpoint callback
9
+ * @param context An additional context argument that can be passed into the callback.
16
10
  *
17
11
  * @returns {Response} Returning a `Response` object (this will pass back to the client without validation).
18
12
  * @returns {R} Returning the return type of the handler (this will be validated against the Endpoint's result schema).
19
13
  */
20
- export type EndpointCallback<P, R, C extends EndpointContext> = (payload: P, context: C) => R | Response | Promise<R | Response>;
14
+ export type EndpointCallback<P, R, C = void> = (payload: P, request: Request, context: C) => R | Response | Promise<R | Response>;
21
15
  /** A typed endpoint definition paired with its implementation callback. */
22
- export interface EndpointHandler<P, R, C extends EndpointContext> {
16
+ export interface EndpointHandler<P, R, C = void> {
23
17
  readonly endpoint: Endpoint<P, R>;
24
18
  readonly callback: EndpointCallback<P, R, C>;
25
19
  }
26
20
  /** Any endpoint handler. */
27
- export type AnyEndpointHandler<C extends EndpointContext = EndpointContext> = EndpointHandler<any, any, C>;
21
+ export type AnyEndpointHandler<C = any> = EndpointHandler<any, any, C>;
28
22
  /** A collection of endpoint handlers that can be matched and invoked by `handleEndpoints()`. */
29
- export type EndpointHandlers<C extends EndpointContext = EndpointContext> = Iterable<AnyEndpointHandler<C>>;
23
+ export type EndpointHandlers<C = void> = Iterable<AnyEndpointHandler<C>>;
30
24
  /**
31
25
  * Handle a `Request` with the first matching endpoint handler after stripping any base-path prefix from the request pathname.
32
26
  * - The original `Request` object is passed through to the callback unchanged.
@@ -37,4 +31,5 @@ export type EndpointHandlers<C extends EndpointContext = EndpointContext> = Iter
37
31
  * @param base The base URL for the API, e.g. `https://myapi.com/a/b`
38
32
  * - `pathname` of this URL gets trimmed from `request.path` to form the target path when matching against endpoints, e.g. `/a/b/c/d` will produce `/c/d` for matching.
39
33
  */
40
- export declare function handleEndpoints<C extends EndpointContext>(base: PossibleURL, handlers: EndpointHandlers<C>, context: C, caller?: AnyCaller): Promise<Response>;
34
+ export declare function handleEndpoints<C>(base: PossibleURL, handlers: EndpointHandlers<C>, request: Request, context: C, caller?: AnyCaller): Promise<Response>;
35
+ export declare function handleEndpoints(base: PossibleURL, handlers: EndpointHandlers<void>, request: Request, context?: undefined, caller?: AnyCaller): Promise<Response>;
@@ -4,18 +4,8 @@ import { getDictionary } from "../../util/dictionary.js";
4
4
  import { getRequestContent, getResponse, isRequestMethod } from "../../util/http.js";
5
5
  import { isPlainObject } from "../../util/object.js";
6
6
  import { requireURL } from "../../util/url.js";
7
- /**
8
- * Handle a `Request` with the first matching endpoint handler after stripping any base-path prefix from the request pathname.
9
- * - The original `Request` object is passed through to the callback unchanged.
10
- * - Path params and query params are merged before payload validation.
11
- *
12
- * @param request The input request to handle.
13
- *
14
- * @param base The base URL for the API, e.g. `https://myapi.com/a/b`
15
- * - `pathname` of this URL gets trimmed from `request.path` to form the target path when matching against endpoints, e.g. `/a/b/c/d` will produce `/c/d` for matching.
16
- */
17
- export function handleEndpoints(base, handlers, context, caller = handleEndpoints) {
18
- const { url, method } = context.request;
7
+ export function handleEndpoints(base, handlers, request, context, caller = handleEndpoints) {
8
+ const { url, method } = request;
19
9
  if (!isRequestMethod(method))
20
10
  throw new MethodNotAllowedError("Unsupported request method", { received: method, caller });
21
11
  const { origin: baseOrigin, pathname: basePath } = requireURL(base, undefined, caller);
@@ -30,7 +20,7 @@ export function handleEndpoints(base, handlers, context, caller = handleEndpoint
30
20
  if (!pathParams)
31
21
  continue;
32
22
  const params = searchParams.size ? { ...getDictionary(searchParams), ...pathParams } : pathParams;
33
- return _handleEndpoint(handler, params, context, handleEndpoints);
23
+ return _handleEndpoint(handler, params, request, context, handleEndpoints);
34
24
  }
35
25
  throw new NotFoundError("No matching endpoint", { received: targetPath, caller });
36
26
  }
@@ -39,11 +29,11 @@ export function handleEndpoints(base, handlers, context, caller = handleEndpoint
39
29
  */
40
30
  async function _handleEndpoint({ endpoint, callback },
41
31
  /** Params we already matched/parsed from the URL. */
42
- params, context, caller) {
43
- const content = await getRequestContent(context.request, caller);
32
+ params, request, context, caller) {
33
+ const content = await getRequestContent(request, caller);
44
34
  const unsafePayload = content === undefined ? params : isPlainObject(content) ? { ...content, ...params } : content;
45
35
  const payload = endpoint.payload.validate(unsafePayload);
46
- const unsafeResult = await callback(payload, context);
36
+ const unsafeResult = await callback(payload, request, context);
47
37
  if (unsafeResult instanceof Response)
48
38
  return unsafeResult;
49
39
  try {
package/api/index.d.ts CHANGED
@@ -6,7 +6,7 @@ export * from "./provider/APIProvider.js";
6
6
  export * from "./provider/ClientAPIProvider.js";
7
7
  export * from "./provider/DebugAPIProvider.js";
8
8
  export * from "./provider/MockAPIProvider.js";
9
- export * from "./provider/MockEnpdointAPIProvider.js";
9
+ export * from "./provider/MockEndpointAPIProvider.js";
10
10
  export * from "./provider/ThroughAPIProvider.js";
11
11
  export * from "./provider/ValidationAPIProvider.js";
12
12
  export * from "./store/EndpointStore.js";
package/api/index.js CHANGED
@@ -6,7 +6,7 @@ export * from "./provider/APIProvider.js";
6
6
  export * from "./provider/ClientAPIProvider.js";
7
7
  export * from "./provider/DebugAPIProvider.js";
8
8
  export * from "./provider/MockAPIProvider.js";
9
- export * from "./provider/MockEnpdointAPIProvider.js";
9
+ export * from "./provider/MockEndpointAPIProvider.js";
10
10
  export * from "./provider/ThroughAPIProvider.js";
11
11
  export * from "./provider/ValidationAPIProvider.js";
12
12
  export * from "./store/EndpointStore.js";
@@ -1,5 +1,8 @@
1
- import { type EndpointContext, type EndpointHandlers } from "../endpoint/util.js";
1
+ import { type EndpointHandlers } from "../endpoint/util.js";
2
2
  import { MockAPIProvider, type MockAPIProviderOptions } from "./MockAPIProvider.js";
3
+ export interface MockEndpointAPIProviderOptions<C> extends MockAPIProviderOptions {
4
+ context: C;
5
+ }
3
6
  /**
4
7
  * Provider that mocks an API that calls and matches an array of `EndpointHandler` objects returned from `Endpoint.handler()`
5
8
  * - Used to test server-side API code, calls against an API made up of multiple `Endpoint` instances.
@@ -11,6 +14,6 @@ import { MockAPIProvider, type MockAPIProviderOptions } from "./MockAPIProvider.
11
14
  * const result = await api.fetch(endpoint, 4); // Mock a call to the endpoint through the provider.
12
15
  * expect(result).toBe(16);
13
16
  */
14
- export declare class MockEnpdointAPIProvider<C extends EndpointContext> extends MockAPIProvider {
15
- constructor(handlers: EndpointHandlers<C>, c: Omit<EndpointContext, "request">, options: MockAPIProviderOptions);
17
+ export declare class MockEndpointAPIProvider<C> extends MockAPIProvider {
18
+ constructor(handlers: EndpointHandlers<C>, { context, ...options }: MockEndpointAPIProviderOptions<C>);
16
19
  }
@@ -11,8 +11,8 @@ import { MockAPIProvider } from "./MockAPIProvider.js";
11
11
  * const result = await api.fetch(endpoint, 4); // Mock a call to the endpoint through the provider.
12
12
  * expect(result).toBe(16);
13
13
  */
14
- export class MockEnpdointAPIProvider extends MockAPIProvider {
15
- constructor(handlers, c, options) {
16
- super(request => handleEndpoints(this.url, handlers, { ...c, request }), options);
14
+ export class MockEndpointAPIProvider extends MockAPIProvider {
15
+ constructor(handlers, { context, ...options }) {
16
+ super(request => handleEndpoints(this.url, handlers, request, context), options);
17
17
  }
18
18
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shelving",
3
- "version": "1.180.0",
3
+ "version": "1.181.0",
4
4
  "author": "Dave Houlbrooke <dave@shax.com>",
5
5
  "repository": {
6
6
  "type": "git",