unnbound-events 3.0.0-beta.0 → 3.0.0-beta.1
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/README.md +7 -3
- package/dist/lib/event.d.ts +1 -1
- package/dist/lib/routing/endpoint.d.ts +3 -4
- package/dist/lib/routing/endpoint.js +6 -26
- package/dist/lib/routing/middleware.d.ts +5 -4
- package/dist/lib/routing/middleware.js +12 -2
- package/dist/lib/routing/response.d.ts +4 -0
- package/dist/lib/routing/response.js +28 -0
- package/dist/lib/server.js +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Unnbound Events SDK
|
|
2
2
|
|
|
3
|
-
Unified HTTP and SQS queue routing with a single API. Register handlers once, handle requests from both transports. `c.request.body` is always an `ArrayBuffer` of the exact bytes
|
|
3
|
+
Unified HTTP and SQS queue routing with a single API. Register handlers once, handle requests from both transports. `c.request.body` is always an `ArrayBuffer` of the exact request-content bytes after HTTP transport framing — the SDK never parses by content type or decompresses content encodings.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -36,7 +36,7 @@ The server automatically:
|
|
|
36
36
|
|
|
37
37
|
## Handlers
|
|
38
38
|
|
|
39
|
-
Routes receive a context object with request details. `c.request.body` is an `ArrayBuffer` containing the
|
|
39
|
+
Routes receive a context object with request details. `c.request.body` is an `ArrayBuffer` containing the exact request-content bytes after HTTP transport framing, for **every** content type (zero-length when there is no body) — decode what you need inside the handler:
|
|
40
40
|
|
|
41
41
|
```ts
|
|
42
42
|
server.post('/users/:id', async (c) => {
|
|
@@ -72,6 +72,10 @@ server.post('/users/:id', async (c) => {
|
|
|
72
72
|
});
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
+
### Transport framing and content encoding
|
|
76
|
+
|
|
77
|
+
`c.request.body` contains request content, not HTTP transport framing. Content encodings such as gzip are preserved, so decompress them explicitly when needed.
|
|
78
|
+
|
|
75
79
|
**Response format:** `{ status?: number, body?: object | Uint8Array | ArrayBuffer, headers?: Record<string, string> }`
|
|
76
80
|
|
|
77
81
|
Objects are JSON-serialized. `Uint8Array`/`ArrayBuffer` bodies are sent verbatim as binary (set `content-type` explicitly) — required for protocols like AS2 whose responses must not be JSON-mangled.
|
|
@@ -80,7 +84,7 @@ Return `undefined`, `null`, or omit properties to default to `204 No Content`.
|
|
|
80
84
|
|
|
81
85
|
## Upgrading from 2.0.x
|
|
82
86
|
|
|
83
|
-
`c.request.body` used to vary by `content-type`. It is now always an `ArrayBuffer` of the exact bytes
|
|
87
|
+
`c.request.body` used to vary by `content-type`. It is now always an `ArrayBuffer` of the exact request-content bytes after HTTP transport framing.
|
|
84
88
|
|
|
85
89
|
| `content-type` | 2.0.x | Current version |
|
|
86
90
|
| --- | --- | --- |
|
package/dist/lib/event.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export interface IncomingRequest {
|
|
|
6
6
|
path: string;
|
|
7
7
|
headers: Record<string, string>;
|
|
8
8
|
query: Record<string, any>;
|
|
9
|
-
/** Exact request bytes; empty for bodyless requests. */
|
|
9
|
+
/** Exact request-content bytes after HTTP transport framing; empty for bodyless requests. */
|
|
10
10
|
body: ArrayBuffer;
|
|
11
11
|
}
|
|
12
12
|
export interface MatchedIncomingRequest extends IncomingRequest {
|
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
import type { Context } from 'hono';
|
|
2
|
-
import type { EventHandlerResult
|
|
2
|
+
import type { EventHandlerResult } from '../event';
|
|
3
3
|
import { type MiddlewareHandler } from './middleware';
|
|
4
4
|
import type { EventEnvironment, EventVariables, MaybePromise } from './types';
|
|
5
|
+
export { attachTraceHeaders, respondWith } from './response';
|
|
5
6
|
export type Handler<I, R = EventHandlerResult> = (input: I) => MaybePromise<R>;
|
|
6
7
|
export interface Endpoint<I> {
|
|
7
8
|
(path: string, handler: Handler<I>): MaybePromise<void>;
|
|
8
9
|
(path: string, middleware: MiddlewareHandler<I>, handler: Handler<I>): MaybePromise<void>;
|
|
9
10
|
}
|
|
10
11
|
export type EndpointArgs<I> = [path: string, handler: Handler<I>] | [path: string, middleware: MiddlewareHandler<I>, handler: Handler<I>];
|
|
11
|
-
export declare const buildEndpointArguments: (...args: EndpointArgs<EventVariables<{}>>) => (string | Handler<Context<EventEnvironment<{}>, any, {}>, Response> | MiddlewareHandler<
|
|
12
|
+
export declare const buildEndpointArguments: (...args: EndpointArgs<EventVariables<{}>>) => (string | Handler<Context<EventEnvironment<{}>, any, {}>, Response> | import("hono").MiddlewareHandler<EventEnvironment<{}>>)[];
|
|
12
13
|
export declare const parseEndpointArguments: (...args: EndpointArgs<EventVariables<{}>>) => {
|
|
13
14
|
path: string;
|
|
14
15
|
middlewares: MiddlewareHandler<EventVariables<{}>>[];
|
|
15
16
|
handler: Handler<EventVariables<{}>, EventHandlerResult>;
|
|
16
17
|
};
|
|
17
18
|
export declare const patchEndpoint: <V extends object>(handler: Handler<EventVariables<V>>) => Handler<Context<EventEnvironment<V>>, Response>;
|
|
18
|
-
export declare const respondWith: (context: Context, result: StrictEventHandlerResult) => (Response & import("hono").TypedResponse<never, -1 | 100 | 102 | 103 | 200 | 201 | 202 | 203 | 206 | 207 | 208 | 226 | 300 | 301 | 302 | 303 | 305 | 306 | 307 | 308 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511, "json">) | (Response & import("hono").TypedResponse<null, -1 | 100 | 101 | 102 | 103 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 226 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511, "body">) | (Response & import("hono").TypedResponse<ArrayBuffer, -1 | 100 | 102 | 103 | 200 | 201 | 202 | 203 | 206 | 207 | 208 | 226 | 300 | 301 | 302 | 303 | 305 | 306 | 307 | 308 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511, "body">);
|
|
19
|
-
export declare const attachTraceHeaders: (headers?: Record<string, string>) => Record<string, string> | undefined;
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.patchEndpoint = exports.parseEndpointArguments = exports.buildEndpointArguments = exports.respondWith = exports.attachTraceHeaders = void 0;
|
|
4
4
|
const unnbound_logger_sdk_1 = require("unnbound-logger-sdk");
|
|
5
5
|
const utils_1 = require("../utils");
|
|
6
6
|
const middleware_1 = require("./middleware");
|
|
7
|
+
const response_1 = require("./response");
|
|
8
|
+
var response_2 = require("./response");
|
|
9
|
+
Object.defineProperty(exports, "attachTraceHeaders", { enumerable: true, get: function () { return response_2.attachTraceHeaders; } });
|
|
10
|
+
Object.defineProperty(exports, "respondWith", { enumerable: true, get: function () { return response_2.respondWith; } });
|
|
7
11
|
const buildEndpointArguments = (...args) => {
|
|
8
12
|
const { path, middlewares, handler } = (0, exports.parseEndpointArguments)(...args);
|
|
9
13
|
const patchedHandler = (0, exports.patchEndpoint)(handler);
|
|
@@ -25,31 +29,7 @@ const patchEndpoint = (handler) => {
|
|
|
25
29
|
const result = await handler(state);
|
|
26
30
|
return { status: result?.status ?? 204, headers: result?.headers, body: result?.body };
|
|
27
31
|
}, (o) => (0, utils_1.buildIncomingPayload)(state, o));
|
|
28
|
-
return (0,
|
|
32
|
+
return (0, response_1.respondWith)(context, result);
|
|
29
33
|
};
|
|
30
34
|
};
|
|
31
35
|
exports.patchEndpoint = patchEndpoint;
|
|
32
|
-
const respondWith = (context, result) => {
|
|
33
|
-
const headers = (0, exports.attachTraceHeaders)(result.headers);
|
|
34
|
-
if (!result.body)
|
|
35
|
-
return context.body(null, result.status, headers);
|
|
36
|
-
// Signed protocol responses such as AS2 MDNs must remain byte-exact.
|
|
37
|
-
if (result.body instanceof Uint8Array || result.body instanceof ArrayBuffer) {
|
|
38
|
-
const bytes = result.body instanceof ArrayBuffer ? result.body : Uint8Array.from(result.body).buffer;
|
|
39
|
-
return context.body(bytes, result.status, headers);
|
|
40
|
-
}
|
|
41
|
-
return context.json(result.body, result.status, headers);
|
|
42
|
-
};
|
|
43
|
-
exports.respondWith = respondWith;
|
|
44
|
-
const attachTraceHeaders = (headers) => {
|
|
45
|
-
// storage can be undefined when CJS/ESM interop breaks re-exports (e.g. tsx in dev mode)
|
|
46
|
-
const { traceId, messageId } = unnbound_logger_sdk_1.storage?.getStore() ?? {};
|
|
47
|
-
if (!traceId || !messageId)
|
|
48
|
-
return headers;
|
|
49
|
-
return {
|
|
50
|
-
...headers,
|
|
51
|
-
[unnbound_logger_sdk_1.defaultTraceHeaderKey]: headers?.[unnbound_logger_sdk_1.defaultTraceHeaderKey] ?? traceId,
|
|
52
|
-
[unnbound_logger_sdk_1.defaultMessageHeaderKey]: headers?.[unnbound_logger_sdk_1.defaultMessageHeaderKey] ?? messageId,
|
|
53
|
-
};
|
|
54
|
-
};
|
|
55
|
-
exports.attachTraceHeaders = attachTraceHeaders;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { MiddlewareHandler as HonoMiddlewareHandler, Next } from 'hono';
|
|
2
|
+
import type { EventHandlerResult } from '../event';
|
|
2
3
|
import type { EventEnvironment, EventVariables, MaybePromise } from './types';
|
|
3
|
-
export type MiddlewareHandler<I> = (input: I, next: Next) => MaybePromise<void>;
|
|
4
|
+
export type MiddlewareHandler<I> = (input: I, next: Next) => MaybePromise<EventHandlerResult | void>;
|
|
4
5
|
export interface Middleware<I> {
|
|
5
6
|
(...middlewares: MiddlewareHandler<I>[]): MaybePromise<void>;
|
|
6
7
|
(path: string, ...middlewares: MiddlewareHandler<I>[]): MaybePromise<void>;
|
|
7
8
|
}
|
|
8
9
|
export type MiddlewareArgs<I> = [...middlewares: MiddlewareHandler<I>[]] | [path: string, ...middlewares: MiddlewareHandler<I>[]];
|
|
9
|
-
export declare const patchMiddleware: (handler: MiddlewareHandler<EventVariables<{}>>) =>
|
|
10
|
+
export declare const patchMiddleware: (handler: MiddlewareHandler<EventVariables<{}>>) => HonoMiddlewareHandler<EventEnvironment<{}>>;
|
|
10
11
|
export declare const parseMiddlewareArguments: (...args: MiddlewareArgs<EventVariables<{}>>) => {
|
|
11
12
|
path: string;
|
|
12
13
|
middlewares: MiddlewareHandler<EventVariables<{}>>[];
|
|
@@ -14,4 +15,4 @@ export declare const parseMiddlewareArguments: (...args: MiddlewareArgs<EventVar
|
|
|
14
15
|
path: undefined;
|
|
15
16
|
middlewares: MiddlewareHandler<EventVariables<{}>>[];
|
|
16
17
|
};
|
|
17
|
-
export declare const buildMiddlewareArguments: (...args: MiddlewareArgs<EventVariables<{}>>) =>
|
|
18
|
+
export declare const buildMiddlewareArguments: (...args: MiddlewareArgs<EventVariables<{}>>) => HonoMiddlewareHandler<EventEnvironment<{}>>[] | readonly [string, ...HonoMiddlewareHandler<EventEnvironment<{}>>[]];
|
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.buildMiddlewareArguments = exports.parseMiddlewareArguments = exports.patchMiddleware = void 0;
|
|
4
|
+
const response_1 = require("./response");
|
|
4
5
|
const patchMiddleware = (handler) => {
|
|
5
|
-
return (context, next) => {
|
|
6
|
+
return async (context, next) => {
|
|
6
7
|
const state = context.get('state');
|
|
7
8
|
// We have to recalculate the params because middleware path might contain url params
|
|
8
9
|
state.request.params = { ...state.request.params, ...context.req.param() };
|
|
9
|
-
|
|
10
|
+
const result = await handler(state, next);
|
|
11
|
+
// Auth and validation middleware must be able to fail closed with the same
|
|
12
|
+
// response contract as endpoint handlers.
|
|
13
|
+
if (result == null)
|
|
14
|
+
return;
|
|
15
|
+
return (0, response_1.respondWith)(context, {
|
|
16
|
+
status: result.status ?? 204,
|
|
17
|
+
headers: result.headers,
|
|
18
|
+
body: result.body,
|
|
19
|
+
});
|
|
10
20
|
};
|
|
11
21
|
};
|
|
12
22
|
exports.patchMiddleware = patchMiddleware;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Context } from 'hono';
|
|
2
|
+
import type { StrictEventHandlerResult } from '../event';
|
|
3
|
+
export declare const respondWith: (context: Context, result: StrictEventHandlerResult) => (Response & import("hono").TypedResponse<never, -1 | 100 | 102 | 103 | 200 | 201 | 202 | 203 | 206 | 207 | 208 | 226 | 300 | 301 | 302 | 303 | 305 | 306 | 307 | 308 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511, "json">) | (Response & import("hono").TypedResponse<null, -1 | 100 | 101 | 102 | 103 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 226 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511, "body">) | (Response & import("hono").TypedResponse<ArrayBuffer, -1 | 100 | 102 | 103 | 200 | 201 | 202 | 203 | 206 | 207 | 208 | 226 | 300 | 301 | 302 | 303 | 305 | 306 | 307 | 308 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511, "body">);
|
|
4
|
+
export declare const attachTraceHeaders: (headers?: Record<string, string>) => Record<string, string> | undefined;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.attachTraceHeaders = exports.respondWith = void 0;
|
|
4
|
+
const unnbound_logger_sdk_1 = require("unnbound-logger-sdk");
|
|
5
|
+
const respondWith = (context, result) => {
|
|
6
|
+
const headers = (0, exports.attachTraceHeaders)(result.headers);
|
|
7
|
+
if (!result.body)
|
|
8
|
+
return context.body(null, result.status, headers);
|
|
9
|
+
// Signed protocol responses such as AS2 MDNs must remain byte-exact.
|
|
10
|
+
if (result.body instanceof Uint8Array || result.body instanceof ArrayBuffer) {
|
|
11
|
+
const bytes = result.body instanceof ArrayBuffer ? result.body : Uint8Array.from(result.body).buffer;
|
|
12
|
+
return context.body(bytes, result.status, headers);
|
|
13
|
+
}
|
|
14
|
+
return context.json(result.body, result.status, headers);
|
|
15
|
+
};
|
|
16
|
+
exports.respondWith = respondWith;
|
|
17
|
+
const attachTraceHeaders = (headers) => {
|
|
18
|
+
// storage can be undefined when CJS/ESM interop breaks re-exports (e.g. tsx in dev mode)
|
|
19
|
+
const { traceId, messageId } = unnbound_logger_sdk_1.storage?.getStore() ?? {};
|
|
20
|
+
if (!traceId || !messageId)
|
|
21
|
+
return headers;
|
|
22
|
+
return {
|
|
23
|
+
...headers,
|
|
24
|
+
[unnbound_logger_sdk_1.defaultTraceHeaderKey]: headers?.[unnbound_logger_sdk_1.defaultTraceHeaderKey] ?? traceId,
|
|
25
|
+
[unnbound_logger_sdk_1.defaultMessageHeaderKey]: headers?.[unnbound_logger_sdk_1.defaultMessageHeaderKey] ?? messageId,
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
exports.attachTraceHeaders = attachTraceHeaders;
|
package/dist/lib/server.js
CHANGED
|
@@ -8,6 +8,7 @@ const queue_adapter_1 = require("./adapters/queue-adapter");
|
|
|
8
8
|
const error_1 = require("./error");
|
|
9
9
|
const endpoint_1 = require("./routing/endpoint");
|
|
10
10
|
const middleware_1 = require("./routing/middleware");
|
|
11
|
+
const response_1 = require("./routing/response");
|
|
11
12
|
const utils_1 = require("./utils");
|
|
12
13
|
class HttpQueueServer {
|
|
13
14
|
logger;
|
|
@@ -31,7 +32,7 @@ class HttpQueueServer {
|
|
|
31
32
|
this.app.onError((err, c) => {
|
|
32
33
|
const error = error_1.ServerError.fromError(err);
|
|
33
34
|
this.logger.error({ err: error.toError() }, error.message);
|
|
34
|
-
return (0,
|
|
35
|
+
return (0, response_1.respondWith)(c, error.toJson());
|
|
35
36
|
});
|
|
36
37
|
this.http = new http_adapter_1.HttpAdapter({ app: this.app, logger: this.logger, ...options.http });
|
|
37
38
|
this.queueEnabled = shouldEnableQueue(options.queue);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "unnbound-events",
|
|
3
3
|
"description": "Unified events SDK to handle HTTP routes and queued messages with a single routing API.",
|
|
4
|
-
"version": "3.0.0-beta.
|
|
4
|
+
"version": "3.0.0-beta.1",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"scripts": {
|