unnbound-events 3.0.0-beta.0 → 3.0.0-beta.2

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 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 received on the wire — the SDK never parses; decoding is an explicit workflow choice.
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 entity exactly as received on the wire, for **every** content type (zero-length when there is no body) — decode what you need inside the handler:
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,9 @@ 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 received.
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.
88
+
89
+ Queued (SQS) messages replay through the same router, so the table below applies to queue handlers too — migrate them alongside your HTTP handlers. The bytes differ only for queued JSON, which is re-serialized through the queue envelope and so arrives as equivalent JSON rather than the publisher's original bytes; every other queued content type is byte-exact.
84
90
 
85
91
  | `content-type` | 2.0.x | Current version |
86
92
  | --- | --- | --- |
@@ -92,9 +98,10 @@ Return `undefined`, `null`, or omit properties to default to `204 No Content`.
92
98
 
93
99
  Handlers for the first four must decode explicitly — see [Handlers](#handlers) for the per-type recipes. Handlers that already received bytes (XML, EDI, CSV, binary) are unaffected.
94
100
 
95
- Two things to check when upgrading an existing workflow:
101
+ Three things to check when upgrading an existing workflow:
96
102
 
97
103
  - A malformed JSON body used to arrive as `undefined`. It now arrives as raw bytes and `JSON.parse` throws — handle it where you decode.
104
+ - A missing body used to arrive as `undefined`, so `if (!c.request.body)` guards fired. Over HTTP it is now a zero-length `ArrayBuffer`, which is truthy, and those guards silently stop firing. Check `c.request.body.byteLength` instead. Queued delivery is the exception: a bodyless async request replays as the four bytes `null`, because the queue envelope stores `null` and it is re-serialized on the way in.
98
105
  - `tsc` catches direct property access on the body, but not a body passed straight to a logger or serializer. Those compile clean and emit `{}` at runtime. Audit every `server.post` / `server.put` handler before deploying.
99
106
 
100
107
  ## Middleware
@@ -7,12 +7,7 @@ export interface S3Pointer {
7
7
  }
8
8
  export type S3PointerMessage = ['software.amazon.payloadoffloading.PayloadS3Pointer', S3Pointer];
9
9
  type SQSClientConfig = ConstructorParameters<typeof SQSClient>[0];
10
- /**
11
- * Internal SQS envelope before it re-enters the HTTP router. Inline bodies
12
- * remain decoded JSON values until QueueAdapter serializes them into request
13
- * bytes, so this must not claim the public IncomingRequest body contract.
14
- * This distinction changes only the type, not SQS delivery behavior.
15
- */
10
+ /** Queue envelopes hold decoded values until replay, so body is not yet an ArrayBuffer. */
16
11
  interface SqsEnvelopeRequest extends Omit<IncomingRequest, 'body'> {
17
12
  body: unknown;
18
13
  }
@@ -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,5 +1,5 @@
1
1
  import type { Context } from 'hono';
2
- import type { EventHandlerResult, StrictEventHandlerResult } from '../event';
2
+ import type { EventHandlerResult } from '../event';
3
3
  import { type MiddlewareHandler } from './middleware';
4
4
  import type { EventEnvironment, EventVariables, MaybePromise } from './types';
5
5
  export type Handler<I, R = EventHandlerResult> = (input: I) => MaybePromise<R>;
@@ -8,12 +8,10 @@ export interface Endpoint<I> {
8
8
  (path: string, middleware: MiddlewareHandler<I>, handler: Handler<I>): MaybePromise<void>;
9
9
  }
10
10
  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<Context<EventEnvironment<{}>, any, {}>>)[];
11
+ export declare const buildEndpointArguments: (...args: EndpointArgs<EventVariables<{}>>) => (string | Handler<Context<EventEnvironment<{}>, any, {}>, Response> | import("hono").MiddlewareHandler<EventEnvironment<{}>>)[];
12
12
  export declare const parseEndpointArguments: (...args: EndpointArgs<EventVariables<{}>>) => {
13
13
  path: string;
14
14
  middlewares: MiddlewareHandler<EventVariables<{}>>[];
15
15
  handler: Handler<EventVariables<{}>, EventHandlerResult>;
16
16
  };
17
17
  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,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.attachTraceHeaders = exports.respondWith = exports.patchEndpoint = exports.parseEndpointArguments = exports.buildEndpointArguments = void 0;
3
+ exports.patchEndpoint = exports.parseEndpointArguments = exports.buildEndpointArguments = 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");
7
8
  const buildEndpointArguments = (...args) => {
8
9
  const { path, middlewares, handler } = (0, exports.parseEndpointArguments)(...args);
9
10
  const patchedHandler = (0, exports.patchEndpoint)(handler);
@@ -23,33 +24,9 @@ const patchEndpoint = (handler) => {
23
24
  state.request.params = { ...state.request.params, ...context.req.param() };
24
25
  const result = await (0, unnbound_logger_sdk_1.startSpan)('Event request', async () => {
25
26
  const result = await handler(state);
26
- return { status: result?.status ?? 204, headers: result?.headers, body: result?.body };
27
+ return { status: (0, response_1.resolveStatus)(result), headers: result?.headers, body: result?.body };
27
28
  }, (o) => (0, utils_1.buildIncomingPayload)(state, o));
28
- return (0, exports.respondWith)(context, result);
29
+ return (0, response_1.respondWith)(context, result);
29
30
  };
30
31
  };
31
32
  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 { Context, Next } from 'hono';
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<{}>>) => MiddlewareHandler<Context<EventEnvironment<{}>>>;
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<{}>>) => MiddlewareHandler<Context<EventEnvironment<{}>, any, {}>>[] | readonly [string, ...MiddlewareHandler<Context<EventEnvironment<{}>, any, {}>>[]];
18
+ export declare const buildMiddlewareArguments: (...args: MiddlewareArgs<EventVariables<{}>>) => HonoMiddlewareHandler<EventEnvironment<{}>>[] | readonly [string, ...HonoMiddlewareHandler<EventEnvironment<{}>>[]];
@@ -1,12 +1,23 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.buildMiddlewareArguments = exports.parseMiddlewareArguments = exports.patchMiddleware = void 0;
4
+ const unnbound_logger_sdk_1 = require("unnbound-logger-sdk");
5
+ const utils_1 = require("../utils");
6
+ const response_1 = require("./response");
4
7
  const patchMiddleware = (handler) => {
5
- return (context, next) => {
8
+ return async (context, next) => {
6
9
  const state = context.get('state');
7
10
  // We have to recalculate the params because middleware path might contain url params
8
11
  state.request.params = { ...state.request.params, ...context.req.param() };
9
- return handler(state, next);
12
+ const result = await handler(state, next);
13
+ // Auth and validation middleware must be able to fail closed with the same
14
+ // response contract as endpoint handlers.
15
+ if (result == null)
16
+ return;
17
+ // Short-circuiting skips patchEndpoint, so nothing else emits the request
18
+ // span. Without this, denied requests are absent from workflow traces.
19
+ const traced = await (0, unnbound_logger_sdk_1.startSpan)('Event request', async () => ({ status: (0, response_1.resolveStatus)(result), headers: result.headers, body: result.body }), (o) => (0, utils_1.buildIncomingPayload)(state, o));
20
+ return (0, response_1.respondWith)(context, traced);
10
21
  };
11
22
  };
12
23
  exports.patchMiddleware = patchMiddleware;
@@ -0,0 +1,6 @@
1
+ import type { Context } from 'hono';
2
+ import type { EventHandlerResult, StrictEventHandlerResult } from '../event';
3
+ export declare const isContentlessStatus: (status: number) => boolean;
4
+ export declare const resolveStatus: (result?: EventHandlerResult) => import("hono/utils/http-status").StatusCode;
5
+ 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">);
6
+ export declare const attachTraceHeaders: (headers?: Record<string, string>) => Record<string, string> | undefined;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.attachTraceHeaders = exports.respondWith = exports.resolveStatus = exports.isContentlessStatus = void 0;
4
+ const unnbound_logger_sdk_1 = require("unnbound-logger-sdk");
5
+ // Response rejects bodies on these statuses; dropping one prevents a 500.
6
+ const CONTENTLESS_STATUSES = new Set([204, 205, 304]);
7
+ const isContentlessStatus = (status) => CONTENTLESS_STATUSES.has(status);
8
+ exports.isContentlessStatus = isContentlessStatus;
9
+ const resolveStatus = (result) => result?.status ?? (result?.body ? 200 : 204);
10
+ exports.resolveStatus = resolveStatus;
11
+ const respondWith = (context, result) => {
12
+ const headers = (0, exports.attachTraceHeaders)(result.headers);
13
+ if (!result.body || CONTENTLESS_STATUSES.has(result.status)) {
14
+ return context.body(null, result.status, headers);
15
+ }
16
+ // Signed protocol responses such as AS2 MDNs must remain byte-exact.
17
+ if (result.body instanceof Uint8Array || result.body instanceof ArrayBuffer) {
18
+ const bytes = result.body instanceof ArrayBuffer ? result.body : Uint8Array.from(result.body).buffer;
19
+ return context.body(bytes, result.status, headers);
20
+ }
21
+ return context.json(result.body, result.status, headers);
22
+ };
23
+ exports.respondWith = respondWith;
24
+ const attachTraceHeaders = (headers) => {
25
+ // storage can be undefined when CJS/ESM interop breaks re-exports (e.g. tsx in dev mode)
26
+ const { traceId, messageId } = unnbound_logger_sdk_1.storage?.getStore() ?? {};
27
+ if (!traceId || !messageId)
28
+ return headers;
29
+ return {
30
+ ...headers,
31
+ [unnbound_logger_sdk_1.defaultTraceHeaderKey]: headers?.[unnbound_logger_sdk_1.defaultTraceHeaderKey] ?? traceId,
32
+ [unnbound_logger_sdk_1.defaultMessageHeaderKey]: headers?.[unnbound_logger_sdk_1.defaultMessageHeaderKey] ?? messageId,
33
+ };
34
+ };
35
+ exports.attachTraceHeaders = attachTraceHeaders;
@@ -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, endpoint_1.respondWith)(c, error.toJson());
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/dist/lib/utils.js CHANGED
@@ -6,6 +6,7 @@ const trace_1 = require("unnbound-logger-sdk/dist/trace");
6
6
  const types_1 = require("unnbound-logger-sdk/dist/types");
7
7
  const utils_1 = require("unnbound-logger-sdk/dist/utils");
8
8
  const error_1 = require("./error");
9
+ const response_1 = require("./routing/response");
9
10
  const normalizeHeaders = (headers) => {
10
11
  return Object.fromEntries(Object.entries(headers).map(([key, value]) => [
11
12
  key,
@@ -115,16 +116,18 @@ const buildResponsePayload = (result) => {
115
116
  const declaredHeaders = result?.headers
116
117
  ? Object.fromEntries(Object.entries((0, exports.normalizeHeaders)(result.headers)).map(([name, value]) => [name.toLowerCase(), value]))
117
118
  : undefined;
118
- // Byte responses go out with exactly the declared headers (no content-type
119
- // unless the handler set one); everything else is JSON-serialized on the
120
- // wire. The trace mirrors that, and the declared content-type drives the
121
- // display decode so byte responses labeled JSON/XML/text trace readably.
122
- const isByteBody = result?.body instanceof Uint8Array || result?.body instanceof ArrayBuffer;
119
+ // Binary responses keep declared headers; JSON gets the SDK default.
120
+ // The declared content type also controls trace decoding.
123
121
  const traceHeaders = headersForTrace(declaredHeaders ?? {});
122
+ const status = (0, response_1.resolveStatus)(result);
123
+ // Mirror the wire: respondWith drops the body on contentless statuses, so the
124
+ // trace must not claim one — nor a content type for a body never sent.
125
+ const body = (0, response_1.isContentlessStatus)(status) ? undefined : result?.body;
126
+ const isByteBody = body instanceof Uint8Array || body instanceof ArrayBuffer;
124
127
  return {
125
- status: result?.status ?? 204,
126
- headers: isByteBody ? traceHeaders : { 'content-type': 'application/json; charset=utf-8', ...traceHeaders },
127
- body: result?.body ? describeBody(result.body, declaredHeaders?.['content-type']) : undefined,
128
+ status,
129
+ headers: body && !isByteBody ? { 'content-type': 'application/json; charset=utf-8', ...traceHeaders } : traceHeaders,
130
+ body: body ? describeBody(body, declaredHeaders?.['content-type']) : undefined,
128
131
  };
129
132
  };
130
133
  const buildIncomingPayload = (event, result) => {
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.0",
4
+ "version": "3.0.0-beta.2",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "scripts": {