@vercube/serverless 0.0.41 → 0.0.43

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.
@@ -1,4 +1,4 @@
1
- import { t as ServerlessHandler } from "../../ServerlessTypes-CIdGp_-x.mjs";
1
+ import { t as ServerlessHandler } from "../../ServerlessTypes-XdyGzZOn.mjs";
2
2
  import { App } from "@vercube/core";
3
3
  import { Writable } from "node:stream";
4
4
 
@@ -242,6 +242,21 @@ interface APIGatewayProxyEventBase<TAuthorizerContext> {
242
242
  requestContext: APIGatewayEventRequestContextWithAuthorizer<TAuthorizerContext>;
243
243
  resource: string;
244
244
  }
245
+ /**
246
+ * Works with Lambda Proxy Integration for Rest API or HTTP API integration Payload Format version 1.0
247
+ * @see - https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html
248
+ */
249
+ interface APIGatewayProxyResult {
250
+ statusCode: number;
251
+ headers?: {
252
+ [header: string]: boolean | number | string;
253
+ } | undefined;
254
+ multiValueHeaders?: {
255
+ [header: string]: Array<boolean | number | string>;
256
+ } | undefined;
257
+ body: string;
258
+ isBase64Encoded?: boolean | undefined;
259
+ }
245
260
  /**
246
261
  * Works with HTTP API integration Payload Format version 2.0
247
262
  * @see - https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html
@@ -288,6 +303,25 @@ interface APIGatewayProxyEventV2WithRequestContext<TRequestContext> {
288
303
  * Default Proxy event with no Authorizer
289
304
  */
290
305
  type APIGatewayProxyEventV2 = APIGatewayProxyEventV2WithRequestContext<APIGatewayEventRequestContextV2>;
306
+ /**
307
+ * Works with HTTP API integration Payload Format version 2.0
308
+ * @see - https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html
309
+ */
310
+ type APIGatewayProxyResultV2<T = never> = APIGatewayProxyStructuredResultV2 | string | T;
311
+ /**
312
+ * Interface for structured response with `statusCode` and`headers`
313
+ * Works with HTTP API integration Payload Format version 2.0
314
+ * @see - https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html
315
+ */
316
+ interface APIGatewayProxyStructuredResultV2 {
317
+ statusCode?: number | undefined;
318
+ headers?: {
319
+ [header: string]: boolean | number | string;
320
+ } | undefined;
321
+ body?: string | undefined;
322
+ isBase64Encoded?: boolean | undefined;
323
+ cookies?: string[] | undefined;
324
+ }
291
325
  //#endregion
292
326
  //#region src/Adapters/aws-lambda/index.d.ts
293
327
  /**
@@ -315,6 +349,6 @@ type APIGatewayProxyEventV2 = APIGatewayProxyEventV2WithRequestContext<APIGatewa
315
349
  * @see {@link convertResponseToAWSResponse} For details on response header conversion
316
350
  * @see {@link convertBodyToAWSResponse} For details on response body conversion
317
351
  */
318
- declare function toServerlessHandler(app: App): ServerlessHandler<APIGatewayProxyEvent | APIGatewayProxyEventV2>;
352
+ declare function toServerlessHandler(app: App): ServerlessHandler<APIGatewayProxyEvent | APIGatewayProxyEventV2, APIGatewayProxyResult | APIGatewayProxyResultV2, Context>;
319
353
  //#endregion
320
354
  export { toServerlessHandler };
@@ -1,278 +1,5 @@
1
- import { n as toBuffer, r as getHeaderValue } from "../../streams-gpVDFRFm.mjs";
2
- import { stringifyQuery } from "ufo";
1
+ import { toLambdaHandler } from "srvx/aws-lambda";
3
2
 
4
- //#region src/Utils/content-type.ts
5
- const DEFAULT_CONTENT_TYPE$1 = "";
6
- const TEXT_CONTENT_TYPE_PATTERNS = [
7
- /^text\//,
8
- /^application\/(json|javascript|xml|xml\+text|x-www-form-urlencoded)$/,
9
- /^application\/.*\+json$/,
10
- /^application\/.*\+xml$/,
11
- /utf-?8/
12
- ];
13
- /**
14
- * Determines if a content type should be treated as text content.
15
- *
16
- * This function uses a set of patterns to identify text-based content types:
17
- * - Content types starting with "text/" (e.g., text/plain, text/html)
18
- * - JavaScript, JSON, or XML content types
19
- * - Content types containing UTF-8 encoding specification
20
- *
21
- * The function performs case-insensitive matching to handle various content type
22
- * formats and specifications.
23
- *
24
- * @param contentType - The content type string to evaluate (e.g., "text/plain", "application/json")
25
- * @returns True if the content type should be treated as text, false otherwise
26
- */
27
- function isTextType(contentType = DEFAULT_CONTENT_TYPE$1) {
28
- if (!contentType) return false;
29
- return TEXT_CONTENT_TYPE_PATTERNS.some((pattern) => pattern.test(contentType));
30
- }
31
-
32
- //#endregion
33
- //#region src/Utils/constants.ts
34
- const DEFAULT_METHOD = "GET";
35
- const DEFAULT_HOSTNAME = ".";
36
- const HTTP_PROTOCOL = "http";
37
- const HTTPS_PROTOCOL = "https";
38
- const DEFAULT_BODY = "";
39
- const DEFAULT_CONTENT_TYPE = "";
40
- const UTF8_ENCODING = "utf8";
41
- const BASE64_ENCODING = "base64";
42
- const HEADER_KEYS = {
43
- HOST: ["host", "Host"],
44
- X_FORWARDED_PROTO: ["X-Forwarded-Proto", "x-forwarded-proto"],
45
- COOKIE: "cookie"
46
- };
47
-
48
- //#endregion
49
- //#region src/Adapters/aws-lambda/Utils/Request.ts
50
- /**
51
- * Type guard to check if an event is APIGatewayProxyEventV2
52
- */
53
- function isV2Event(event) {
54
- return "requestContext" in event && "http" in event.requestContext && "method" in event.requestContext.http;
55
- }
56
- /**
57
- * Type guard to check if an event is APIGatewayProxyEvent
58
- */
59
- function isV1Event(event) {
60
- return "httpMethod" in event;
61
- }
62
- /**
63
- * Extracts the HTTP method from an API Gateway event.
64
- *
65
- * Handles both v1 and v2 event formats:
66
- * - v1: Uses `httpMethod` property
67
- * - v2: Uses `requestContext.http.method` property
68
- *
69
- * @param event - The AWS API Gateway event object (v1 or v2 format)
70
- * @returns The HTTP method as a string, defaults to 'GET' if not found
71
- */
72
- function getEventMethod(event) {
73
- if (isV1Event(event)) return event.httpMethod || DEFAULT_METHOD;
74
- if (isV2Event(event)) return event.requestContext?.http?.method || DEFAULT_METHOD;
75
- return DEFAULT_METHOD;
76
- }
77
- /**
78
- * Constructs a complete URL from an API Gateway event.
79
- *
80
- * Builds the URL by combining:
81
- * - Protocol (http/https based on X-Forwarded-Proto header)
82
- * - Hostname (from headers or requestContext)
83
- * - Path (from event path properties)
84
- * - Query string (from query parameters)
85
- *
86
- * @param event - The AWS API Gateway event object (v1 or v2 format)
87
- * @returns A complete URL object
88
- */
89
- function getEventUrl(event) {
90
- const hostname = getEventHostname(event);
91
- const path = getEventPath(event);
92
- const query = getEventQuery(event);
93
- const protocol = getEventProtocol(event);
94
- const urlPath = query ? `${path}?${query}` : path;
95
- return new URL(urlPath, `${protocol}://${hostname}`);
96
- }
97
- /**
98
- * Extracts the hostname from the event
99
- */
100
- function getEventHostname(event) {
101
- const hostHeader = getHeaderValue(event.headers, HEADER_KEYS.HOST);
102
- if (hostHeader) return hostHeader;
103
- return event.requestContext?.domainName || DEFAULT_HOSTNAME;
104
- }
105
- /**
106
- * Extracts the path from the event
107
- */
108
- function getEventPath(event) {
109
- if (isV1Event(event)) return event.path || "/";
110
- if (isV2Event(event)) return event.rawPath || "/";
111
- return "/";
112
- }
113
- /**
114
- * Determines the protocol from the event headers
115
- */
116
- function getEventProtocol(event) {
117
- return getHeaderValue(event.headers, HEADER_KEYS.X_FORWARDED_PROTO) === HTTP_PROTOCOL ? HTTP_PROTOCOL : HTTPS_PROTOCOL;
118
- }
119
- /**
120
- * Extracts and formats query parameters from an API Gateway event.
121
- *
122
- * Handles both v1 and v2 event formats:
123
- * - v2: Uses `rawQueryString` if available
124
- * - v1: Combines `queryStringParameters` and `multiValueQueryStringParameters`
125
- *
126
- * @param event - The AWS API Gateway event object (v1 or v2 format)
127
- * @returns A formatted query string (without the leading '?')
128
- */
129
- function getEventQuery(event) {
130
- if (isV2Event(event) && typeof event.rawQueryString === "string") return event.rawQueryString;
131
- const queryParams = event.queryStringParameters || {};
132
- const multiValueParams = isV1Event(event) ? event.multiValueQueryStringParameters || {} : {};
133
- return stringifyQuery({
134
- ...queryParams,
135
- ...multiValueParams
136
- });
137
- }
138
- /**
139
- * Converts API Gateway event headers to a standard Headers object.
140
- *
141
- * Processes all headers from the event and handles cookies specially:
142
- * - Sets all event headers in the Headers object
143
- * - Appends cookies from the event's cookies array (v2 format)
144
- *
145
- * @param event - The AWS API Gateway event object (v1 or v2 format)
146
- * @returns A Headers object with all event headers and cookies
147
- */
148
- function getEventHeaders(event) {
149
- const headers = new Headers();
150
- if (event.headers) {
151
- for (const [key, value] of Object.entries(event.headers)) if (value !== void 0 && value !== null) headers.set(key, value);
152
- }
153
- if (isV2Event(event) && event.cookies && Array.isArray(event.cookies)) {
154
- for (const cookie of event.cookies) if (cookie) headers.append(HEADER_KEYS.COOKIE, cookie);
155
- }
156
- return headers;
157
- }
158
- /**
159
- * Extracts the request body from an API Gateway event.
160
- *
161
- * Handles different body formats:
162
- * - Returns undefined if no body is present
163
- * - Decodes base64-encoded bodies when `isBase64Encoded` is true
164
- * - Returns the raw body string for regular requests
165
- *
166
- * @param event - The AWS API Gateway event object (v1 or v2 format)
167
- * @returns The request body as BodyInit (string, Buffer, or undefined)
168
- */
169
- function getEventBody(event) {
170
- if (!event.body || event.body === null) return;
171
- if (event.isBase64Encoded) try {
172
- return Buffer.from(event.body, "base64");
173
- } catch {
174
- return event.body;
175
- }
176
- return event.body;
177
- }
178
- /**
179
- * Converts an AWS API Gateway event to a standard Request object.
180
- *
181
- * This function handles both APIGatewayProxyEvent (v1) and APIGatewayProxyEventV2 (v2) formats,
182
- * extracting the HTTP method, URL, headers, and body to create a web-standard Request object.
183
- *
184
- * This file is highly inspired by the `awsRequest` from `nitro`
185
- * @see https://github.com/nitrojs/nitro/blob/v3/src/presets/aws-lambda/runtime/_utils.ts
186
- *
187
- * @param event - The AWS API Gateway event object (v1 or v2 format)
188
- * @returns A new Request object with the extracted event data
189
- * @throws {Error} If the event is invalid or missing required properties
190
- */
191
- function convertEventToRequest(event) {
192
- if (!event || typeof event !== "object") throw new Error("Invalid event: event must be a valid object");
193
- const method = getEventMethod(event);
194
- const url = getEventUrl(event);
195
- const headers = getEventHeaders(event);
196
- const body = getEventBody(event);
197
- return new Request(url, {
198
- method,
199
- headers,
200
- body
201
- });
202
- }
203
-
204
- //#endregion
205
- //#region src/Adapters/aws-lambda/Utils/Response.ts
206
- /**
207
- * Converts a standard web Response object to AWS API Gateway compatible response format.
208
- *
209
- * This function transforms the Response headers and cookies into the format expected by
210
- * AWS API Gateway proxy integrations. It handles both v1 and v2 API Gateway formats:
211
- * - v1: Uses `multiValueHeaders` for cookies
212
- * - v2: Uses `cookies` array for cookies
213
- *
214
- * The function processes all response headers, converting them to the appropriate format
215
- * for AWS Lambda integration. Headers with multiple values are joined with commas,
216
- * and cookies are handled specially for both API Gateway versions.
217
- *
218
- * @param response - The standard web Response object to convert
219
- * @returns An object containing headers and cookies in AWS API Gateway format
220
- * @throws {Error} If the response object is invalid or headers cannot be processed
221
- */
222
- function convertResponseToAWSResponse(response) {
223
- if (!response || !response.headers) throw new Error("Invalid response: response must be a valid Response object with headers");
224
- const headers = Object.create(null);
225
- response.headers.forEach((value, key) => {
226
- if (value !== void 0 && value !== null) headers[key] = Array.isArray(value) ? value.join(",") : String(value);
227
- else if (value === null) headers[key] = "null";
228
- else if (value === void 0) headers[key] = "undefined";
229
- });
230
- const cookies = typeof response.headers.getSetCookie === "function" ? response.headers.getSetCookie() : [];
231
- if (cookies.length > 0) return {
232
- headers,
233
- cookies,
234
- multiValueHeaders: { "set-cookie": cookies }
235
- };
236
- return { headers };
237
- }
238
- /**
239
- * Converts a Response body to AWS API Gateway compatible format with proper encoding.
240
- *
241
- * AWS Lambda proxy integrations require special handling for binary content:
242
- * - Text content types are returned as UTF-8 strings
243
- * - Binary content types are base64 encoded with the `isBase64Encoded` flag set
244
- *
245
- * This function determines the appropriate encoding based on the response's content-type
246
- * header and converts the body accordingly. It supports both text and binary content
247
- * types, ensuring compatibility with API Gateway's payload encoding requirements.
248
- *
249
- * Binary media types should be configured as * in API Gateway settings.
250
- * @see https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-payload-encodings.html
251
- *
252
- * This function is heavily inspired by the `awsResponseBody` from `nitro`
253
- * @see https://github.com/nitrojs/nitro/blob/v3/src/presets/aws-lambda/runtime/_utils.ts
254
- *
255
- * @param response - The standard web Response object containing the body to convert
256
- * @returns A promise that resolves to an object with the encoded body and encoding flag
257
- * @throws {Error} If the response body cannot be read or converted
258
- */
259
- async function convertBodyToAWSResponse(response) {
260
- if (!response) throw new Error("Invalid response: response must be a valid Response object");
261
- if (!response.body) return { body: DEFAULT_BODY };
262
- try {
263
- const buffer = await toBuffer(response.body);
264
- if (isTextType(response.headers.get("content-type") || DEFAULT_CONTENT_TYPE)) return { body: buffer.toString(UTF8_ENCODING) };
265
- else return {
266
- body: buffer.toString(BASE64_ENCODING),
267
- isBase64Encoded: true
268
- };
269
- } catch (error) {
270
- const errorMessage = error instanceof Error ? error.message : "Unknown error";
271
- throw new Error(`Failed to convert response body: ${errorMessage}`);
272
- }
273
- }
274
-
275
- //#endregion
276
3
  //#region src/Adapters/aws-lambda/index.ts
277
4
  /**
278
5
  * Converts a Vercube App instance into an AWS Lambda handler function for API Gateway integration.
@@ -300,15 +27,9 @@ async function convertBodyToAWSResponse(response) {
300
27
  * @see {@link convertBodyToAWSResponse} For details on response body conversion
301
28
  */
302
29
  function toServerlessHandler(app) {
303
- return async (event) => {
304
- const request = convertEventToRequest(event);
305
- const response = await app.fetch(request);
306
- return {
307
- statusCode: response.status,
308
- ...convertResponseToAWSResponse(response),
309
- ...await convertBodyToAWSResponse(response)
310
- };
311
- };
30
+ return toLambdaHandler({ fetch: async (request) => {
31
+ return await app.fetch(request);
32
+ } });
312
33
  }
313
34
 
314
35
  //#endregion
@@ -1,10 +1,10 @@
1
- import { t as ServerlessHandler } from "../../ServerlessTypes-CIdGp_-x.mjs";
1
+ import { t as ServerlessHandler } from "../../ServerlessTypes-XdyGzZOn.mjs";
2
2
  import { App } from "@vercube/core";
3
3
  import { Blob } from "buffer";
4
4
  import { ReadableStream } from "stream/web";
5
5
  import { URLSearchParams } from "url";
6
6
 
7
- //#region ../../node_modules/.pnpm/@azure+functions@4.11.0/node_modules/@azure/functions/types/http.d.ts
7
+ //#region ../../node_modules/.pnpm/@azure+functions@4.11.1/node_modules/@azure/functions/types/http.d.ts
8
8
  /**
9
9
  * HTTP request object. Provided to your function when using HTTP Bindings.
10
10
  */
@@ -1,5 +1,23 @@
1
- import { i as headersToObject, t as streamToAsyncIterator } from "../../streams-gpVDFRFm.mjs";
1
+ //#region src/Utils/headers.ts
2
+ /**
3
+ * Converts a loopable header object to a plain JavaScript object.
4
+ *
5
+ * This function is used to convert header objects (which have a forEach method)
6
+ * into standard JavaScript objects with string keys and values. This is necessary for
7
+ * compatibility with the standard web Headers API and other parts of the application.
8
+ *
9
+ * @param input - A header-like object with a forEach method
10
+ * @returns A plain object with string keys and string values representing the headers
11
+ */
12
+ function headersToObject(input) {
13
+ const headers = {};
14
+ input.forEach((value, key) => {
15
+ headers[key] = value;
16
+ });
17
+ return headers;
18
+ }
2
19
 
20
+ //#endregion
3
21
  //#region src/Utils/cookies.ts
4
22
  /**
5
23
  * Parses a cookie string into a generic cookie object.
@@ -152,7 +170,7 @@ function convertResponseToAzureFunctionsResponse(response) {
152
170
  cookies: cookiesFromHeaders(response.headers),
153
171
  headers,
154
172
  status: response.status,
155
- body: streamToAsyncIterator(response.body)
173
+ body: response.body
156
174
  };
157
175
  }
158
176
 
@@ -1,6 +1,6 @@
1
1
  import { MaybePromise } from "@vercube/core";
2
2
 
3
3
  //#region src/Types/ServerlessTypes.d.ts
4
- type ServerlessHandler<Event = unknown, HandlerResponse = unknown> = (event: Event) => MaybePromise<HandlerResponse>;
4
+ type ServerlessHandler<Event = unknown, HandlerResponse = unknown, Context = unknown> = (event: Event, context?: Context) => MaybePromise<HandlerResponse>;
5
5
  //#endregion
6
6
  export { ServerlessHandler as t };
package/dist/index.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { t as ServerlessHandler } from "./ServerlessTypes-CIdGp_-x.mjs";
1
+ import { t as ServerlessHandler } from "./ServerlessTypes-XdyGzZOn.mjs";
2
2
  export { ServerlessHandler };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercube/serverless",
3
- "version": "0.0.41",
3
+ "version": "0.0.43",
4
4
  "description": "Serverless module for Vercube framework",
5
5
  "repository": {
6
6
  "type": "git",
@@ -36,12 +36,13 @@
36
36
  "azure-function-http"
37
37
  ],
38
38
  "dependencies": {
39
+ "srvx": "0.11.0",
39
40
  "ufo": "1.6.3",
40
- "@vercube/core": "0.0.41",
41
- "@vercube/di": "0.0.41"
41
+ "@vercube/core": "0.0.43",
42
+ "@vercube/di": "0.0.43"
42
43
  },
43
44
  "devDependencies": {
44
- "@azure/functions": "4.11.0",
45
+ "@azure/functions": "4.11.1",
45
46
  "@types/aws-lambda": "8.10.160"
46
47
  },
47
48
  "publishConfig": {
@@ -1,108 +0,0 @@
1
- //#region src/Utils/headers.ts
2
- /**
3
- * Converts a loopable header object to a plain JavaScript object.
4
- *
5
- * This function is used to convert header objects (which have a forEach method)
6
- * into standard JavaScript objects with string keys and values. This is necessary for
7
- * compatibility with the standard web Headers API and other parts of the application.
8
- *
9
- * @param input - A header-like object with a forEach method
10
- * @returns A plain object with string keys and string values representing the headers
11
- */
12
- function headersToObject(input) {
13
- const headers = {};
14
- input.forEach((value, key) => {
15
- headers[key] = value;
16
- });
17
- return headers;
18
- }
19
- /**
20
- * Safely gets a header value with case-insensitive fallback.
21
- *
22
- * This utility function searches through a headers object using multiple possible
23
- * key variations to find a header value. It's useful for handling headers that
24
- * might have different casing across different platforms.
25
- *
26
- * @param headers - The headers object to search in
27
- * @param keys - Array of possible header keys to try (in order of preference)
28
- * @returns The header value if found, undefined otherwise
29
- */
30
- function getHeaderValue(headers, keys) {
31
- if (!headers) return;
32
- for (const key of keys) {
33
- const value = headers[key];
34
- if (value !== void 0) return value;
35
- }
36
- }
37
-
38
- //#endregion
39
- //#region src/Utils/streams.ts
40
- /**
41
- * Converts a ReadableStream to a Buffer using Web Streams API.
42
- *
43
- * This function reads all chunks from a ReadableStream and concatenates them
44
- * into a single Buffer. It uses the modern Web Streams API with WritableStream
45
- * to efficiently process the stream data without blocking.
46
- *
47
- * The function handles stream errors gracefully and provides proper cleanup
48
- * of stream resources. It's designed to work with Response.body streams
49
- * from fetch API responses.
50
- *
51
- * @param data - The ReadableStream to convert to a Buffer
52
- * @returns A promise that resolves to a Buffer containing all stream data
53
- * @throws {Error} If the stream cannot be read or an error occurs during processing
54
- */
55
- function toBuffer(data) {
56
- return new Promise((resolve, reject) => {
57
- const chunks = [];
58
- const writableStream = new WritableStream({
59
- write(chunk) {
60
- chunks.push(chunk);
61
- },
62
- close() {
63
- resolve(Buffer.concat(chunks));
64
- },
65
- abort(reason) {
66
- reject(/* @__PURE__ */ new Error("Stream aborted: " + String(reason)));
67
- }
68
- });
69
- data.pipeTo(writableStream).catch(reject);
70
- });
71
- }
72
- /**
73
- * Converts a ReadableStream to an AsyncIterableIterator for platform compatibility.
74
- *
75
- * Some serverless platforms expect response bodies to be AsyncIterableIterator<Uint8Array>.
76
- * This function wraps a standard web ReadableStream to provide the required interface
77
- * for serverless HTTP responses.
78
- *
79
- * The returned iterator provides:
80
- * - `next()` method that reads chunks from the stream
81
- * - `return()` method that releases the stream reader lock
82
- * - Symbol.asyncIterator for async iteration support
83
- *
84
- * @param readable - The ReadableStream from a Response body, or null/undefined
85
- * @returns An AsyncIterableIterator<Uint8Array> or null if no readable stream provided
86
- */
87
- function streamToAsyncIterator(readable) {
88
- if (readable == null) return null;
89
- const reader = readable.getReader();
90
- return {
91
- next() {
92
- return reader.read();
93
- },
94
- return() {
95
- reader.releaseLock();
96
- return Promise.resolve({
97
- done: true,
98
- value: void 0
99
- });
100
- },
101
- [Symbol.asyncIterator]() {
102
- return this;
103
- }
104
- };
105
- }
106
-
107
- //#endregion
108
- export { headersToObject as i, toBuffer as n, getHeaderValue as r, streamToAsyncIterator as t };