@webiny/event-handler-core 6.6.0-alpha.3 → 6.6.0-alpha.5

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.
@@ -97,7 +97,7 @@ class HttpResponseBuilder {
97
97
  sse(source) {
98
98
  return this.setHeaders({
99
99
  "content-type": "text/event-stream",
100
- "cache-control": "no-cache, no-transform",
100
+ "cache-control": "no-store, no-cache, no-transform",
101
101
  connection: "keep-alive",
102
102
  "x-accel-buffering": "no"
103
103
  }).end(new HttpStreamBody(source));
@@ -1 +1 @@
1
- {"version":3,"file":"features/http/HttpResponseBuilder.js","sources":["../../../src/features/http/HttpResponseBuilder.ts"],"sourcesContent":["import type { CookieOptions, IHttpResponse, IHttpResponseBuilder } from \"./abstractions.js\";\nimport { HttpStreamBody } from \"./HttpStreamBody.js\";\nimport type { HttpStreamSource } from \"./HttpStreamBody.js\";\n\nconst CONTENT_TYPE = \"content-type\";\n\nconst TYPE_SHORTHANDS: Record<string, string> = {\n json: \"application/json\",\n text: \"text/plain; charset=utf-8\",\n html: \"text/html; charset=utf-8\",\n xml: \"application/xml\",\n bin: \"application/octet-stream\"\n};\n\n/**\n * Serialize a single `Set-Cookie` value. Kept dependency-free (no `cookie` package) — the attribute\n * set below is everything the framework needs.\n */\nexport function serializeCookie(name: string, value: string, options: CookieOptions = {}): string {\n const parts = [`${name}=${encodeURIComponent(value)}`];\n\n if (options.maxAge !== undefined) {\n parts.push(`Max-Age=${Math.floor(options.maxAge)}`);\n }\n if (options.domain) {\n parts.push(`Domain=${options.domain}`);\n }\n // Default to \"/\" so a cookie set on e.g. POST /graphql isn't scoped to that one path.\n parts.push(`Path=${options.path ?? \"/\"}`);\n if (options.expires) {\n parts.push(`Expires=${options.expires.toUTCString()}`);\n }\n if (options.httpOnly) {\n parts.push(\"HttpOnly\");\n }\n if (options.secure) {\n parts.push(\"Secure\");\n }\n if (options.partitioned) {\n parts.push(\"Partitioned\");\n }\n if (options.sameSite) {\n const sameSite = options.sameSite;\n parts.push(`SameSite=${sameSite.charAt(0).toUpperCase()}${sameSite.slice(1)}`);\n }\n\n return parts.join(\"; \");\n}\n\nexport class HttpResponseBuilder implements IHttpResponseBuilder {\n private statusCodeValue = 200;\n private headerValues: Record<string, string> = {};\n private cookieValues: string[] = [];\n private bodyValue: any;\n private modified = false;\n\n status(statusCode: number): this {\n this.statusCodeValue = statusCode;\n this.modified = true;\n return this;\n }\n\n header(name: string, value: string): this {\n this.headerValues[name.toLowerCase()] = value;\n this.modified = true;\n return this;\n }\n\n setHeaders(headers: Record<string, string>): this {\n for (const [name, value] of Object.entries(headers)) {\n this.header(name, value);\n }\n return this;\n }\n\n getHeader(name: string): string | undefined {\n return this.headerValues[name.toLowerCase()];\n }\n\n removeHeader(name: string): this {\n delete this.headerValues[name.toLowerCase()];\n this.modified = true;\n return this;\n }\n\n type(contentType: string): this {\n return this.header(CONTENT_TYPE, TYPE_SHORTHANDS[contentType] ?? contentType);\n }\n\n cookie(name: string, value: string, options?: CookieOptions): this {\n this.cookieValues.push(serializeCookie(name, value, options));\n this.modified = true;\n return this;\n }\n\n clearCookie(name: string, options?: Omit<CookieOptions, \"expires\" | \"maxAge\">): this {\n return this.cookie(name, \"\", {\n ...options,\n expires: new Date(0),\n maxAge: 0\n });\n }\n\n json(body?: any): this {\n if (this.getHeader(CONTENT_TYPE) === undefined) {\n this.type(\"json\");\n }\n // Serialize here rather than leaving an object for the transport, so the body a route\n // produces is the exact bytes that go out regardless of transport.\n this.bodyValue = body === undefined ? undefined : JSON.stringify(body);\n this.modified = true;\n return this;\n }\n\n send(body?: any): this {\n if (body === undefined || body === null) {\n return this.end(body);\n }\n if (typeof body === \"string\") {\n if (this.getHeader(CONTENT_TYPE) === undefined) {\n this.type(\"html\");\n }\n return this.end(body);\n }\n if (Buffer.isBuffer(body) || body instanceof Uint8Array) {\n if (this.getHeader(CONTENT_TYPE) === undefined) {\n this.type(\"bin\");\n }\n return this.end(body);\n }\n return this.json(body);\n }\n\n text(body: string): this {\n return this.type(\"text\").end(body);\n }\n\n html(body: string): this {\n return this.type(\"html\").end(body);\n }\n\n redirect(url: string, statusCode = 302): this {\n return this.status(statusCode).header(\"location\", url).end();\n }\n\n end(body?: any): this {\n this.bodyValue = body;\n this.modified = true;\n return this;\n }\n\n sse(source: HttpStreamSource): this {\n // `no-transform` and `x-accel-buffering: no` are the two that silently matter: without them a\n // proxy compresses or buffers the body and the response stops being incremental while still\n // looking correct. See the interface docs.\n return this.setHeaders({\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-cache, no-transform\",\n connection: \"keep-alive\",\n \"x-accel-buffering\": \"no\"\n }).end(new HttpStreamBody(source));\n }\n\n /**\n * Whether anything was set on this builder. The router uses it to decide if builder state needs\n * merging into a plain IHttpResponse a route returned instead.\n */\n isModified(): boolean {\n return this.modified;\n }\n\n toResponse(): IHttpResponse {\n const response: IHttpResponse = { statusCode: this.statusCodeValue };\n if (Object.keys(this.headerValues).length > 0) {\n response.headers = { ...this.headerValues };\n }\n if (this.cookieValues.length > 0) {\n response.cookies = [...this.cookieValues];\n }\n if (this.bodyValue !== undefined) {\n response.body = this.bodyValue;\n }\n return response;\n }\n}\n\nexport function createHttpResponseBuilder(): HttpResponseBuilder {\n return new HttpResponseBuilder();\n}\n"],"names":["CONTENT_TYPE","TYPE_SHORTHANDS","serializeCookie","name","value","options","parts","encodeURIComponent","undefined","Math","sameSite","HttpResponseBuilder","statusCode","headers","Object","contentType","Date","body","JSON","Buffer","Uint8Array","url","source","HttpStreamBody","response","createHttpResponseBuilder"],"mappings":"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"}
1
+ {"version":3,"file":"features/http/HttpResponseBuilder.js","sources":["../../../src/features/http/HttpResponseBuilder.ts"],"sourcesContent":["import type { CookieOptions, IHttpResponse, IHttpResponseBuilder } from \"./abstractions.js\";\nimport { HttpStreamBody } from \"./HttpStreamBody.js\";\nimport type { HttpStreamSource } from \"./HttpStreamBody.js\";\n\nconst CONTENT_TYPE = \"content-type\";\n\nconst TYPE_SHORTHANDS: Record<string, string> = {\n json: \"application/json\",\n text: \"text/plain; charset=utf-8\",\n html: \"text/html; charset=utf-8\",\n xml: \"application/xml\",\n bin: \"application/octet-stream\"\n};\n\n/**\n * Serialize a single `Set-Cookie` value. Kept dependency-free (no `cookie` package) — the attribute\n * set below is everything the framework needs.\n */\nexport function serializeCookie(name: string, value: string, options: CookieOptions = {}): string {\n const parts = [`${name}=${encodeURIComponent(value)}`];\n\n if (options.maxAge !== undefined) {\n parts.push(`Max-Age=${Math.floor(options.maxAge)}`);\n }\n if (options.domain) {\n parts.push(`Domain=${options.domain}`);\n }\n // Default to \"/\" so a cookie set on e.g. POST /graphql isn't scoped to that one path.\n parts.push(`Path=${options.path ?? \"/\"}`);\n if (options.expires) {\n parts.push(`Expires=${options.expires.toUTCString()}`);\n }\n if (options.httpOnly) {\n parts.push(\"HttpOnly\");\n }\n if (options.secure) {\n parts.push(\"Secure\");\n }\n if (options.partitioned) {\n parts.push(\"Partitioned\");\n }\n if (options.sameSite) {\n const sameSite = options.sameSite;\n parts.push(`SameSite=${sameSite.charAt(0).toUpperCase()}${sameSite.slice(1)}`);\n }\n\n return parts.join(\"; \");\n}\n\nexport class HttpResponseBuilder implements IHttpResponseBuilder {\n private statusCodeValue = 200;\n private headerValues: Record<string, string> = {};\n private cookieValues: string[] = [];\n private bodyValue: any;\n private modified = false;\n\n status(statusCode: number): this {\n this.statusCodeValue = statusCode;\n this.modified = true;\n return this;\n }\n\n header(name: string, value: string): this {\n this.headerValues[name.toLowerCase()] = value;\n this.modified = true;\n return this;\n }\n\n setHeaders(headers: Record<string, string>): this {\n for (const [name, value] of Object.entries(headers)) {\n this.header(name, value);\n }\n return this;\n }\n\n getHeader(name: string): string | undefined {\n return this.headerValues[name.toLowerCase()];\n }\n\n removeHeader(name: string): this {\n delete this.headerValues[name.toLowerCase()];\n this.modified = true;\n return this;\n }\n\n type(contentType: string): this {\n return this.header(CONTENT_TYPE, TYPE_SHORTHANDS[contentType] ?? contentType);\n }\n\n cookie(name: string, value: string, options?: CookieOptions): this {\n this.cookieValues.push(serializeCookie(name, value, options));\n this.modified = true;\n return this;\n }\n\n clearCookie(name: string, options?: Omit<CookieOptions, \"expires\" | \"maxAge\">): this {\n return this.cookie(name, \"\", {\n ...options,\n expires: new Date(0),\n maxAge: 0\n });\n }\n\n json(body?: any): this {\n if (this.getHeader(CONTENT_TYPE) === undefined) {\n this.type(\"json\");\n }\n // Serialize here rather than leaving an object for the transport, so the body a route\n // produces is the exact bytes that go out regardless of transport.\n this.bodyValue = body === undefined ? undefined : JSON.stringify(body);\n this.modified = true;\n return this;\n }\n\n send(body?: any): this {\n if (body === undefined || body === null) {\n return this.end(body);\n }\n if (typeof body === \"string\") {\n if (this.getHeader(CONTENT_TYPE) === undefined) {\n this.type(\"html\");\n }\n return this.end(body);\n }\n if (Buffer.isBuffer(body) || body instanceof Uint8Array) {\n if (this.getHeader(CONTENT_TYPE) === undefined) {\n this.type(\"bin\");\n }\n return this.end(body);\n }\n return this.json(body);\n }\n\n text(body: string): this {\n return this.type(\"text\").end(body);\n }\n\n html(body: string): this {\n return this.type(\"html\").end(body);\n }\n\n redirect(url: string, statusCode = 302): this {\n return this.status(statusCode).header(\"location\", url).end();\n }\n\n end(body?: any): this {\n this.bodyValue = body;\n this.modified = true;\n return this;\n }\n\n sse(source: HttpStreamSource): this {\n // `no-transform` and `x-accel-buffering: no` are the two that silently matter: without them a\n // proxy compresses or buffers the body and the response stops being incremental while still\n // looking correct. `no-store` is about something else entirely — see the interface docs.\n return this.setHeaders({\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-store, no-cache, no-transform\",\n connection: \"keep-alive\",\n \"x-accel-buffering\": \"no\"\n }).end(new HttpStreamBody(source));\n }\n\n /**\n * Whether anything was set on this builder. The router uses it to decide if builder state needs\n * merging into a plain IHttpResponse a route returned instead.\n */\n isModified(): boolean {\n return this.modified;\n }\n\n toResponse(): IHttpResponse {\n const response: IHttpResponse = { statusCode: this.statusCodeValue };\n if (Object.keys(this.headerValues).length > 0) {\n response.headers = { ...this.headerValues };\n }\n if (this.cookieValues.length > 0) {\n response.cookies = [...this.cookieValues];\n }\n if (this.bodyValue !== undefined) {\n response.body = this.bodyValue;\n }\n return response;\n }\n}\n\nexport function createHttpResponseBuilder(): HttpResponseBuilder {\n return new HttpResponseBuilder();\n}\n"],"names":["CONTENT_TYPE","TYPE_SHORTHANDS","serializeCookie","name","value","options","parts","encodeURIComponent","undefined","Math","sameSite","HttpResponseBuilder","statusCode","headers","Object","contentType","Date","body","JSON","Buffer","Uint8Array","url","source","HttpStreamBody","response","createHttpResponseBuilder"],"mappings":"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"}
@@ -108,6 +108,11 @@ export interface IHttpResponseBuilder {
108
108
  * proxies) compressing the body, which buffers chunks, and `x-accel-buffering: no` opts out of
109
109
  * nginx-family response buffering.
110
110
  *
111
+ * `no-store` is not about delivery. Every stream that goes through here carries per-identity
112
+ * output — an assistant's answer, an enrichment for one file — and `no-cache` alone permits an
113
+ * intermediary to STORE the response and merely revalidate before reusing it. `no-store` is the
114
+ * directive that forbids keeping a copy at all.
115
+ *
111
116
  * Framing is the caller's job — `source` should yield complete `data: ...\n\n` records.
112
117
  */
113
118
  sse(source: HttpStreamSource): this;
@@ -1 +1 @@
1
- {"version":3,"file":"features/http/abstractions.js","sources":["../../../src/features/http/abstractions.ts"],"sourcesContent":["import { Abstraction } from \"@webiny/di\";\nimport type { Constructor } from \"@webiny/di\";\nimport type { HttpStreamSource } from \"./HttpStreamBody.js\";\n\n/**\n * Which route the router matched, as seen from inside `handle()` — the `req.route` of Express-style\n * handlers. It is the definition without its `handler`, so a route (or anything wrapping one) can\n * tell WHICH route is running and act only on the one it cares about.\n */\nexport interface IMatchedRouteDefinition {\n readonly name: string;\n readonly method: string;\n readonly path: string;\n}\n\nexport interface IHttpRequest {\n method: string;\n path: string;\n headers: Record<string, string>;\n query: Record<string, string>;\n pathParameters: Record<string, string>;\n body: any;\n /**\n * Set by `HttpRouter` once a route matches, so it is absent on the request a transport builds\n * and always present by the time `handle()` runs. Handlers should take\n * {@link HttpRouteHandler.Request}, where it is required.\n */\n route?: IMatchedRouteDefinition;\n}\n\nexport interface IHttpResponse {\n statusCode: number;\n headers?: Record<string, string>;\n /**\n * Serialized `Set-Cookie` values. A separate field (not a header) because `Set-Cookie` is the\n * one response header that can legally repeat, which `headers: Record<string, string>` cannot\n * express. Transports map it to whatever their protocol needs — API Gateway's\n * `multiValueHeaders` / `cookies`, or a repeated header on a Node `ServerResponse`.\n */\n cookies?: string[];\n body?: any;\n}\n\nexport interface CookieOptions {\n domain?: string;\n path?: string;\n expires?: Date;\n /**\n * Cookie lifetime in SECONDS — the `Max-Age` attribute value as the HTTP spec defines it.\n * Note this differs from Express, whose `maxAge` is in milliseconds.\n */\n maxAge?: number;\n httpOnly?: boolean;\n secure?: boolean;\n partitioned?: boolean;\n sameSite?: \"strict\" | \"lax\" | \"none\";\n}\n\n/**\n * The mutable response handed to every route as the second argument to `handle()` — the `res` of\n * Express-style handlers. Every method returns `this`, so a route can chain and then return the\n * builder directly:\n *\n * ```ts\n * async handle(request: IHttpRequest, response: IHttpResponseBuilder) {\n * return response.status(201).cookie(\"sid\", id, { httpOnly: true }).json({ id });\n * }\n * ```\n *\n * Returning it is optional: a route that mutates it and returns nothing gets the same response.\n * Routes returning a plain {@link IHttpResponse} keep working — anything set on the builder\n * (headers, cookies) is merged underneath the returned object, which wins on conflicts.\n */\nexport interface IHttpResponseBuilder {\n /** Set the status code. Defaults to 200. */\n status(statusCode: number): this;\n /** Set a single response header (header names are stored lowercase). */\n header(name: string, value: string): this;\n /** Merge multiple response headers at once. */\n setHeaders(headers: Record<string, string>): this;\n getHeader(name: string): string | undefined;\n removeHeader(name: string): this;\n /**\n * Set `Content-Type`. Accepts a full media type (`\"image/png\"`) or one of the shorthands\n * `json`, `text`, `html`, `xml`, `bin`.\n */\n type(contentType: string): this;\n /** Append a `Set-Cookie` value. Can be called multiple times for multiple cookies. */\n cookie(name: string, value: string, options?: CookieOptions): this;\n /** Append a `Set-Cookie` value that expires the cookie immediately. */\n clearCookie(name: string, options?: Omit<CookieOptions, \"expires\" | \"maxAge\">): this;\n /** JSON-serialize the body and set `Content-Type: application/json` (unless already set). */\n json(body?: any): this;\n /**\n * Set the body, inferring `Content-Type` when it hasn't been set: `text/html` for a string,\n * `application/octet-stream` for a Buffer/Uint8Array, `application/json` for anything else.\n */\n send(body?: any): this;\n /** Set the body with `Content-Type: text/plain`. */\n text(body: string): this;\n /** Set the body with `Content-Type: text/html`. */\n html(body: string): this;\n /** Set `Location` and a redirect status code (302 by default). */\n redirect(url: string, statusCode?: number): this;\n /** Set the body verbatim, without touching `Content-Type`. */\n end(body?: any): this;\n /**\n * Stream the response as server-sent events: sets the SSE headers and wraps `source` in an\n * {@link HttpStreamBody} so transports that can stream write each chunk as it is produced.\n *\n * Two of the headers are not obvious and are easy to omit, and omitting either yields a response\n * that looks correct yet never arrives incrementally: `no-transform` stops CloudFront (and other\n * proxies) compressing the body, which buffers chunks, and `x-accel-buffering: no` opts out of\n * nginx-family response buffering.\n *\n * Framing is the caller's job — `source` should yield complete `data: ...\\n\\n` records.\n */\n sse(source: HttpStreamSource): this;\n /** Materialize the transport-agnostic response. Called by the router; routes rarely need it. */\n toResponse(): IHttpResponse;\n}\n\nexport interface IHttpRoute {\n /**\n * Handle the request. Either return a response (a plain {@link IHttpResponse}, or the\n * {@link IHttpResponseBuilder} passed in as `response`), or mutate `response` and return\n * nothing.\n */\n handle(\n request: IHttpRequest,\n response: IHttpResponseBuilder\n ): Promise<IHttpResponse | IHttpResponseBuilder | void>;\n}\n\n/**\n * What a route IS, separated from what it DOES.\n *\n * `method` and `path` are plain data, so the router matches a request without building anything.\n * `handler` is the route's implementation class — declared with\n * `HttpRouteHandler.createImplementation`, so it carries its own dependency metadata — and the\n * router builds it only once this definition matches.\n *\n * Resolving every route just to read its path used to drag in each one's whole dependency graph, so\n * a request for a static asset built the entire GraphQL engine, every contextual schema and the AI\n * provider before finding the route it wanted.\n */\nexport interface IHttpRouteDefinition {\n /**\n * Identifies this route so a decorator can pick it out.\n *\n * Decorators DO reach `HttpRouteDefinition` (unlike `HttpRouteHandler`, which the router builds\n * directly), so decorating it hands you every route in turn — `name` is how you tell which one\n * you have, and whether to wrap its handler or pass it through.\n */\n readonly name: string;\n readonly method: string;\n readonly path: string;\n readonly handler: Constructor<IHttpRoute>;\n}\n\nexport interface IHttpRouter {\n route(request: IHttpRequest): Promise<IHttpResponse>;\n}\n\nexport const HttpRouteDefinition = new Abstraction<IHttpRouteDefinition>(\"HttpRouteDefinition\");\n/**\n * Declares a route's request handling. One shared abstraction: the router never resolves it from the\n * container (that would build every route), it builds the ONE class a matched definition points at.\n * Declaring implementations through it is what attaches their dependency metadata.\n */\nexport const HttpRouteHandler = new Abstraction<IHttpRoute>(\"HttpRouteHandler\");\nexport const HttpRouter = new Abstraction<IHttpRouter>(\"HttpRouter\");\n\nexport namespace HttpRouteDefinition {\n export type Interface = IHttpRouteDefinition;\n}\n\nexport namespace HttpRouteHandler {\n export type Interface = IHttpRoute;\n /**\n * The request handed to `handle()`: an {@link IHttpRequest} that has been through the router,\n * so {@link IMatchedRouteDefinition} is guaranteed rather than optional.\n */\n export type Request = IHttpRequest & { route: IMatchedRouteDefinition };\n /**\n * The response handed to `handle()` — the mutable builder, not the materialized\n * {@link IHttpResponse}. Shorthand for {@link IHttpResponseBuilder}.\n */\n export type Response = IHttpResponseBuilder;\n}\n\nexport namespace HttpRouter {\n export type Interface = IHttpRouter;\n}\n\nexport class RouteNotFoundError extends Error {\n readonly code = \"ROUTE_NOT_FOUND\" as const;\n\n constructor(method: string, path: string) {\n super(`Route not found: ${method} ${path}`);\n }\n}\n"],"names":["HttpRouteDefinition","Abstraction","HttpRouteHandler","HttpRouter","RouteNotFoundError","Error","method","path"],"mappings":";AAoKO,MAAMA,sBAAsB,IAAIC,YAAkC;AAMlE,MAAMC,mBAAmB,IAAID,YAAwB;AACrD,MAAME,aAAa,IAAIF,YAAyB;AAwBhD,MAAMG,2BAA2BC;IAGpC,YAAYC,MAAc,EAAEC,IAAY,CAAE;QACtC,KAAK,CAAC,CAAC,iBAAiB,EAAED,OAAO,CAAC,EAAEC,MAAM,QAHrC,IAAI,GAAG;IAIhB;AACJ"}
1
+ {"version":3,"file":"features/http/abstractions.js","sources":["../../../src/features/http/abstractions.ts"],"sourcesContent":["import { Abstraction } from \"@webiny/di\";\nimport type { Constructor } from \"@webiny/di\";\nimport type { HttpStreamSource } from \"./HttpStreamBody.js\";\n\n/**\n * Which route the router matched, as seen from inside `handle()` — the `req.route` of Express-style\n * handlers. It is the definition without its `handler`, so a route (or anything wrapping one) can\n * tell WHICH route is running and act only on the one it cares about.\n */\nexport interface IMatchedRouteDefinition {\n readonly name: string;\n readonly method: string;\n readonly path: string;\n}\n\nexport interface IHttpRequest {\n method: string;\n path: string;\n headers: Record<string, string>;\n query: Record<string, string>;\n pathParameters: Record<string, string>;\n body: any;\n /**\n * Set by `HttpRouter` once a route matches, so it is absent on the request a transport builds\n * and always present by the time `handle()` runs. Handlers should take\n * {@link HttpRouteHandler.Request}, where it is required.\n */\n route?: IMatchedRouteDefinition;\n}\n\nexport interface IHttpResponse {\n statusCode: number;\n headers?: Record<string, string>;\n /**\n * Serialized `Set-Cookie` values. A separate field (not a header) because `Set-Cookie` is the\n * one response header that can legally repeat, which `headers: Record<string, string>` cannot\n * express. Transports map it to whatever their protocol needs — API Gateway's\n * `multiValueHeaders` / `cookies`, or a repeated header on a Node `ServerResponse`.\n */\n cookies?: string[];\n body?: any;\n}\n\nexport interface CookieOptions {\n domain?: string;\n path?: string;\n expires?: Date;\n /**\n * Cookie lifetime in SECONDS — the `Max-Age` attribute value as the HTTP spec defines it.\n * Note this differs from Express, whose `maxAge` is in milliseconds.\n */\n maxAge?: number;\n httpOnly?: boolean;\n secure?: boolean;\n partitioned?: boolean;\n sameSite?: \"strict\" | \"lax\" | \"none\";\n}\n\n/**\n * The mutable response handed to every route as the second argument to `handle()` — the `res` of\n * Express-style handlers. Every method returns `this`, so a route can chain and then return the\n * builder directly:\n *\n * ```ts\n * async handle(request: IHttpRequest, response: IHttpResponseBuilder) {\n * return response.status(201).cookie(\"sid\", id, { httpOnly: true }).json({ id });\n * }\n * ```\n *\n * Returning it is optional: a route that mutates it and returns nothing gets the same response.\n * Routes returning a plain {@link IHttpResponse} keep working — anything set on the builder\n * (headers, cookies) is merged underneath the returned object, which wins on conflicts.\n */\nexport interface IHttpResponseBuilder {\n /** Set the status code. Defaults to 200. */\n status(statusCode: number): this;\n /** Set a single response header (header names are stored lowercase). */\n header(name: string, value: string): this;\n /** Merge multiple response headers at once. */\n setHeaders(headers: Record<string, string>): this;\n getHeader(name: string): string | undefined;\n removeHeader(name: string): this;\n /**\n * Set `Content-Type`. Accepts a full media type (`\"image/png\"`) or one of the shorthands\n * `json`, `text`, `html`, `xml`, `bin`.\n */\n type(contentType: string): this;\n /** Append a `Set-Cookie` value. Can be called multiple times for multiple cookies. */\n cookie(name: string, value: string, options?: CookieOptions): this;\n /** Append a `Set-Cookie` value that expires the cookie immediately. */\n clearCookie(name: string, options?: Omit<CookieOptions, \"expires\" | \"maxAge\">): this;\n /** JSON-serialize the body and set `Content-Type: application/json` (unless already set). */\n json(body?: any): this;\n /**\n * Set the body, inferring `Content-Type` when it hasn't been set: `text/html` for a string,\n * `application/octet-stream` for a Buffer/Uint8Array, `application/json` for anything else.\n */\n send(body?: any): this;\n /** Set the body with `Content-Type: text/plain`. */\n text(body: string): this;\n /** Set the body with `Content-Type: text/html`. */\n html(body: string): this;\n /** Set `Location` and a redirect status code (302 by default). */\n redirect(url: string, statusCode?: number): this;\n /** Set the body verbatim, without touching `Content-Type`. */\n end(body?: any): this;\n /**\n * Stream the response as server-sent events: sets the SSE headers and wraps `source` in an\n * {@link HttpStreamBody} so transports that can stream write each chunk as it is produced.\n *\n * Two of the headers are not obvious and are easy to omit, and omitting either yields a response\n * that looks correct yet never arrives incrementally: `no-transform` stops CloudFront (and other\n * proxies) compressing the body, which buffers chunks, and `x-accel-buffering: no` opts out of\n * nginx-family response buffering.\n *\n * `no-store` is not about delivery. Every stream that goes through here carries per-identity\n * output — an assistant's answer, an enrichment for one file — and `no-cache` alone permits an\n * intermediary to STORE the response and merely revalidate before reusing it. `no-store` is the\n * directive that forbids keeping a copy at all.\n *\n * Framing is the caller's job — `source` should yield complete `data: ...\\n\\n` records.\n */\n sse(source: HttpStreamSource): this;\n /** Materialize the transport-agnostic response. Called by the router; routes rarely need it. */\n toResponse(): IHttpResponse;\n}\n\nexport interface IHttpRoute {\n /**\n * Handle the request. Either return a response (a plain {@link IHttpResponse}, or the\n * {@link IHttpResponseBuilder} passed in as `response`), or mutate `response` and return\n * nothing.\n */\n handle(\n request: IHttpRequest,\n response: IHttpResponseBuilder\n ): Promise<IHttpResponse | IHttpResponseBuilder | void>;\n}\n\n/**\n * What a route IS, separated from what it DOES.\n *\n * `method` and `path` are plain data, so the router matches a request without building anything.\n * `handler` is the route's implementation class — declared with\n * `HttpRouteHandler.createImplementation`, so it carries its own dependency metadata — and the\n * router builds it only once this definition matches.\n *\n * Resolving every route just to read its path used to drag in each one's whole dependency graph, so\n * a request for a static asset built the entire GraphQL engine, every contextual schema and the AI\n * provider before finding the route it wanted.\n */\nexport interface IHttpRouteDefinition {\n /**\n * Identifies this route so a decorator can pick it out.\n *\n * Decorators DO reach `HttpRouteDefinition` (unlike `HttpRouteHandler`, which the router builds\n * directly), so decorating it hands you every route in turn — `name` is how you tell which one\n * you have, and whether to wrap its handler or pass it through.\n */\n readonly name: string;\n readonly method: string;\n readonly path: string;\n readonly handler: Constructor<IHttpRoute>;\n}\n\nexport interface IHttpRouter {\n route(request: IHttpRequest): Promise<IHttpResponse>;\n}\n\nexport const HttpRouteDefinition = new Abstraction<IHttpRouteDefinition>(\"HttpRouteDefinition\");\n/**\n * Declares a route's request handling. One shared abstraction: the router never resolves it from the\n * container (that would build every route), it builds the ONE class a matched definition points at.\n * Declaring implementations through it is what attaches their dependency metadata.\n */\nexport const HttpRouteHandler = new Abstraction<IHttpRoute>(\"HttpRouteHandler\");\nexport const HttpRouter = new Abstraction<IHttpRouter>(\"HttpRouter\");\n\nexport namespace HttpRouteDefinition {\n export type Interface = IHttpRouteDefinition;\n}\n\nexport namespace HttpRouteHandler {\n export type Interface = IHttpRoute;\n /**\n * The request handed to `handle()`: an {@link IHttpRequest} that has been through the router,\n * so {@link IMatchedRouteDefinition} is guaranteed rather than optional.\n */\n export type Request = IHttpRequest & { route: IMatchedRouteDefinition };\n /**\n * The response handed to `handle()` — the mutable builder, not the materialized\n * {@link IHttpResponse}. Shorthand for {@link IHttpResponseBuilder}.\n */\n export type Response = IHttpResponseBuilder;\n}\n\nexport namespace HttpRouter {\n export type Interface = IHttpRouter;\n}\n\nexport class RouteNotFoundError extends Error {\n readonly code = \"ROUTE_NOT_FOUND\" as const;\n\n constructor(method: string, path: string) {\n super(`Route not found: ${method} ${path}`);\n }\n}\n"],"names":["HttpRouteDefinition","Abstraction","HttpRouteHandler","HttpRouter","RouteNotFoundError","Error","method","path"],"mappings":";AAyKO,MAAMA,sBAAsB,IAAIC,YAAkC;AAMlE,MAAMC,mBAAmB,IAAID,YAAwB;AACrD,MAAME,aAAa,IAAIF,YAAyB;AAwBhD,MAAMG,2BAA2BC;IAGpC,YAAYC,MAAc,EAAEC,IAAY,CAAE;QACtC,KAAK,CAAC,CAAC,iBAAiB,EAAED,OAAO,CAAC,EAAEC,MAAM,QAHrC,IAAI,GAAG;IAIhB;AACJ"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webiny/event-handler-core",
3
- "version": "6.6.0-alpha.3",
3
+ "version": "6.6.0-alpha.5",
4
4
  "type": "module",
5
5
  "main": "index.js",
6
6
  "exports": {
@@ -18,13 +18,13 @@
18
18
  ],
19
19
  "license": "MIT",
20
20
  "dependencies": {
21
- "@webiny/feature": "6.6.0-alpha.3"
21
+ "@webiny/feature": "6.6.0-alpha.5"
22
22
  },
23
23
  "peerDependencies": {
24
24
  "@webiny/di": "1.1.0"
25
25
  },
26
26
  "devDependencies": {
27
- "@webiny/build-tools": "6.6.0-alpha.3",
27
+ "@webiny/build-tools": "6.6.0-alpha.5",
28
28
  "@webiny/di": "1.1.0",
29
29
  "rimraf": "6.1.3",
30
30
  "typescript": "7.0.2",