@vercube/serverless 0.0.23 → 0.0.24

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
@@ -34,10 +34,11 @@ The `@vercube/serverless` module provides unified, provider-agnostic adapters fo
34
34
  ### ✅ Key Features
35
35
 
36
36
  - **AWS Lambda Integration** - Full support for API Gateway v1 and v2
37
+ - **Azure Functions Integration** - Complete support for Azure Functions HTTP triggers
37
38
  - **Zero Configuration** - Works out-of-the-box with existing Vercube apps
38
39
  - **Type Safety** - Complete TypeScript support with proper type definitions
39
40
  - **Binary Support** - Automatic handling of binary content with base64 encoding
40
- - **Cookie Support** - Proper cookie handling for both API Gateway versions
41
+ - **Cookie Support** - Proper cookie handling for both API Gateway versions and Azure Functions
41
42
  - **Error Handling** - Robust error handling and validation
42
43
  - **Performance Optimized** - Efficient request/response conversion
43
44
 
@@ -66,6 +67,30 @@ const app = createApp();
66
67
  export const handler = toServerlessHandler(app);
67
68
  ```
68
69
 
70
+ ### Azure Functions Integration
71
+
72
+ Deploy your Vercube application to Azure Functions:
73
+
74
+ ```ts
75
+ // httpTrigger.ts
76
+ import { createApp } from '@vercube/core';
77
+ import { toServerlessHandler } from '@vercube/serverless/azure-functions';
78
+ import { app, HttpRequest, HttpResponseInit, InvocationContext } from '@azure/functions';
79
+
80
+ const vercubeApp = createApp();
81
+ const handler = toServerlessHandler(vercubeApp);
82
+
83
+ export async function httpTrigger(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
84
+ return await handler(request);
85
+ }
86
+
87
+ app.http('httpTrigger', {
88
+ methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'],
89
+ authLevel: 'anonymous',
90
+ handler: httpTrigger,
91
+ });
92
+ ```
93
+
69
94
  ### Serverless Framework Configuration
70
95
 
71
96
  ```yaml
@@ -101,6 +126,16 @@ Full support for AWS Lambda with API Gateway integration:
101
126
  - **Cookies** - Proper cookie handling for both API Gateway versions
102
127
  - **Headers** - Complete header conversion and processing
103
128
 
129
+ ### Azure Functions
130
+
131
+ Complete support for Azure Functions HTTP triggers:
132
+
133
+ - **HTTP Triggers** - Full compatibility with Azure Functions HTTP triggers
134
+ - **Request/Response Conversion** - Seamless conversion between Azure Functions and web standards
135
+ - **Cookie Support** - Proper handling of Set-Cookie headers and cookie parsing
136
+ - **Headers** - Complete header conversion and processing
137
+ - **Streaming Support** - Efficient handling of request/response bodies with AsyncIterableIterator
138
+
104
139
  ---
105
140
 
106
141
  ## 📋 API Reference
@@ -117,9 +152,10 @@ Converts a Vercube App instance into a serverless handler function.
117
152
 
118
153
  - An async function that accepts serverless events and returns platform-specific responses
119
154
 
120
- **Example:**
155
+ **Examples:**
121
156
 
122
157
  ```ts
158
+ // AWS Lambda
123
159
  import { createApp } from '@vercube/core';
124
160
  import { toServerlessHandler } from '@vercube/serverless/aws-lambda';
125
161
 
@@ -127,6 +163,15 @@ const app = createApp();
127
163
  export const handler = toServerlessHandler(app);
128
164
  ```
129
165
 
166
+ ```ts
167
+ // Azure Functions
168
+ import { createApp } from '@vercube/core';
169
+ import { toServerlessHandler } from '@vercube/serverless/azure-functions';
170
+
171
+ const app = createApp();
172
+ export const handler = toServerlessHandler(app);
173
+ ```
174
+
130
175
  ---
131
176
 
132
177
  ## 🔄 Request/Response Conversion
@@ -144,8 +189,8 @@ The serverless adapters handle automatic conversion between platform-specific ev
144
189
 
145
190
  - **Status Code** - Mapped from Response status
146
191
  - **Headers** - Converted to platform-specific format
147
- - **Body** - Encoded appropriately (text vs binary)
148
- - **Cookies** - Handled for both API Gateway versions
192
+ - **Body** - Encoded appropriately (text vs binary for AWS, AsyncIterableIterator for Azure)
193
+ - **Cookies** - Handled for both API Gateway versions and Azure Functions
149
194
 
150
195
  ---
151
196
 
@@ -154,7 +199,8 @@ The serverless adapters handle automatic conversion between platform-specific ev
154
199
  - **Streaming Support** - Efficient handling of large request/response bodies
155
200
  - **Memory Optimization** - Minimal memory footprint for serverless environments
156
201
  - **Cold Start Optimization** - Fast initialization and request processing
157
- - **Binary Content** - Optimized base64 encoding for binary responses
202
+ - **Binary Content** - Optimized base64 encoding for binary responses (AWS Lambda)
203
+ - **AsyncIterableIterator** - Efficient streaming for Azure Functions responses
158
204
 
159
205
  ---
160
206
 
@@ -191,6 +237,7 @@ This module is inspired by:
191
237
  - [Nitro AWS Lambda Preset](https://nitro.build/presets/aws-lambda)
192
238
  - [Hono AWS Lambda Adapter](https://hono.dev/guides/aws-lambda)
193
239
  - [Vercel Serverless Functions](https://vercel.com/docs/functions)
240
+ - [hono-azurefunc-adapter](https://github.com/Marplex/hono-azurefunc-adapter)
194
241
 
195
242
  ---
196
243
 
@@ -1,4 +1,4 @@
1
- import { ServerlessHandler } from "../../ServerlessTypes-lXnSKHNA.mjs";
1
+ import { ServerlessHandler } from "../../ServerlessTypes-WMcCL6v7.mjs";
2
2
  import { App } from "@vercube/core";
3
3
  import { APIGatewayProxyEvent, APIGatewayProxyEventV2 } from "aws-lambda";
4
4
 
@@ -1,15 +1,52 @@
1
+ import { getHeaderValue, toBuffer } from "../../streams-jCOA2riB.mjs";
1
2
  import { stringifyQuery } from "ufo";
2
3
 
3
- //#region src/Adapters/aws-lambda/Utils/Request.ts
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
4
34
  const DEFAULT_METHOD = "GET";
5
35
  const DEFAULT_HOSTNAME = ".";
6
36
  const HTTP_PROTOCOL = "http";
7
37
  const HTTPS_PROTOCOL = "https";
38
+ const DEFAULT_BODY = "";
39
+ const DEFAULT_CONTENT_TYPE = "";
40
+ const UTF8_ENCODING = "utf8";
41
+ const BASE64_ENCODING = "base64";
8
42
  const HEADER_KEYS = {
9
43
  HOST: ["host", "Host"],
10
44
  X_FORWARDED_PROTO: ["X-Forwarded-Proto", "x-forwarded-proto"],
11
45
  COOKIE: "cookie"
12
46
  };
47
+
48
+ //#endregion
49
+ //#region src/Adapters/aws-lambda/Utils/Request.ts
13
50
  /**
14
51
  * Type guard to check if an event is APIGatewayProxyEventV2
15
52
  */
@@ -23,17 +60,6 @@ function isV1Event(event) {
23
60
  return "httpMethod" in event;
24
61
  }
25
62
  /**
26
- * Safely gets a header value with case-insensitive fallback
27
- */
28
- function getHeaderValue(headers, keys) {
29
- if (!headers) return void 0;
30
- for (const key of keys) {
31
- const value = headers[key];
32
- if (value !== void 0) return value;
33
- }
34
- return void 0;
35
- }
36
- /**
37
63
  * Extracts the HTTP method from an API Gateway event.
38
64
  *
39
65
  * Handles both v1 and v2 event formats:
@@ -88,8 +114,7 @@ function getEventPath(event) {
88
114
  * Determines the protocol from the event headers
89
115
  */
90
116
  function getEventProtocol(event) {
91
- const forwardedProto = getHeaderValue(event.headers, HEADER_KEYS.X_FORWARDED_PROTO);
92
- return forwardedProto === HTTP_PROTOCOL ? HTTP_PROTOCOL : HTTPS_PROTOCOL;
117
+ return getHeaderValue(event.headers, HEADER_KEYS.X_FORWARDED_PROTO) === HTTP_PROTOCOL ? HTTP_PROTOCOL : HTTPS_PROTOCOL;
93
118
  }
94
119
  /**
95
120
  * Extracts and formats query parameters from an API Gateway event.
@@ -143,7 +168,7 @@ function getEventHeaders(event) {
143
168
  * @returns The request body as BodyInit (string, Buffer, or undefined)
144
169
  */
145
170
  function getEventBody(event) {
146
- if (!event.body || event.body === null) return void 0;
171
+ if (!event.body || event.body === null) return;
147
172
  if (event.isBase64Encoded) try {
148
173
  return Buffer.from(event.body, "base64");
149
174
  } catch {
@@ -179,17 +204,6 @@ function convertEventToRequest(event) {
179
204
 
180
205
  //#endregion
181
206
  //#region src/Adapters/aws-lambda/Utils/Response.ts
182
- const DEFAULT_BODY = "";
183
- const DEFAULT_CONTENT_TYPE = "";
184
- const UTF8_ENCODING = "utf8";
185
- const BASE64_ENCODING = "base64";
186
- const TEXT_CONTENT_TYPE_PATTERNS = [
187
- /^text\//,
188
- /^application\/(json|javascript|xml|xml\+text|x-www-form-urlencoded)$/,
189
- /^application\/.*\+json$/,
190
- /^application\/.*\+xml$/,
191
- /utf-?8/
192
- ];
193
207
  /**
194
208
  * Converts a standard web Response object to AWS API Gateway compatible response format.
195
209
  *
@@ -259,56 +273,6 @@ async function convertBodyToAWSResponse(response) {
259
273
  throw new Error(`Failed to convert response body: ${errorMessage}`);
260
274
  }
261
275
  }
262
- /**
263
- * Determines if a content type should be treated as text content.
264
- *
265
- * This function uses a set of patterns to identify text-based content types:
266
- * - Content types starting with "text/" (e.g., text/plain, text/html)
267
- * - JavaScript, JSON, or XML content types
268
- * - Content types containing UTF-8 encoding specification
269
- *
270
- * The function performs case-insensitive matching to handle various content type
271
- * formats and specifications.
272
- *
273
- * @param contentType - The content type string to evaluate (e.g., "text/plain", "application/json")
274
- * @returns True if the content type should be treated as text, false otherwise
275
- */
276
- function isTextType(contentType = DEFAULT_CONTENT_TYPE) {
277
- if (!contentType) return false;
278
- return TEXT_CONTENT_TYPE_PATTERNS.some((pattern) => pattern.test(contentType));
279
- }
280
- /**
281
- * Converts a ReadableStream to a Buffer using Web Streams API.
282
- *
283
- * This function reads all chunks from a ReadableStream and concatenates them
284
- * into a single Buffer. It uses the modern Web Streams API with WritableStream
285
- * to efficiently process the stream data without blocking.
286
- *
287
- * The function handles stream errors gracefully and provides proper cleanup
288
- * of stream resources. It's designed to work with Response.body streams
289
- * from fetch API responses.
290
- *
291
- * @param data - The ReadableStream to convert to a Buffer
292
- * @returns A promise that resolves to a Buffer containing all stream data
293
- * @throws {Error} If the stream cannot be read or an error occurs during processing
294
- */
295
- function toBuffer(data) {
296
- return new Promise((resolve, reject) => {
297
- const chunks = [];
298
- const writableStream = new WritableStream({
299
- write(chunk) {
300
- chunks.push(chunk);
301
- },
302
- close() {
303
- resolve(Buffer.concat(chunks));
304
- },
305
- abort(reason) {
306
- reject(/* @__PURE__ */ new Error("Stream aborted: " + String(reason)));
307
- }
308
- });
309
- data.pipeTo(writableStream).catch(reject);
310
- });
311
- }
312
276
 
313
277
  //#endregion
314
278
  //#region src/Adapters/aws-lambda/index.ts
@@ -0,0 +1,32 @@
1
+ import { ServerlessHandler } from "../../ServerlessTypes-WMcCL6v7.mjs";
2
+ import { App } from "@vercube/core";
3
+ import { HttpRequest } from "@azure/functions";
4
+
5
+ //#region src/Adapters/azure-functions/index.d.ts
6
+
7
+ /**
8
+ * Converts a Vercube App instance into an Azure Functions handler function for HTTP integration.
9
+ *
10
+ * This function creates a serverless handler that bridges between Azure Functions HTTP triggers
11
+ * and the Vercube application framework. It handles the conversion of Azure Functions HttpRequest
12
+ * objects to standard web Request objects, processes them through the Vercube app, and converts
13
+ * the responses back to the format expected by Azure Functions.
14
+ *
15
+ * The handler processes:
16
+ * - HTTP method, URL, headers, and body from the Azure Functions HttpRequest
17
+ * - Converts them to a standard web Request object
18
+ * - Passes the request through the Vercube application
19
+ * - Converts the Response back to Azure Functions HttpResponseInit format
20
+ *
21
+ * The returned handler function can be directly used as an Azure Functions HTTP trigger handler,
22
+ * providing seamless integration between Azure Functions and Vercube applications.
23
+ *
24
+ * @param app - The Vercube App instance that will handle the requests
25
+ * @returns An async function that accepts Azure Functions HttpRequest and returns HttpResponseInit
26
+ *
27
+ * @see {@link convertEventToRequest} For details on HttpRequest to Request conversion
28
+ * @see {@link convertResponseToAzureFunctionsResponse} For details on Response to HttpResponseInit conversion
29
+ */
30
+ declare function toServerlessHandler(app: App): ServerlessHandler<HttpRequest, any>;
31
+ //#endregion
32
+ export { toServerlessHandler };
@@ -0,0 +1,193 @@
1
+ import { headersToObject, streamToAsyncIterator } from "../../streams-jCOA2riB.mjs";
2
+
3
+ //#region src/Utils/cookies.ts
4
+ /**
5
+ * Parses a cookie string into a generic cookie object.
6
+ *
7
+ * This function parses a standard Set-Cookie header string and extracts all cookie attributes
8
+ * including name, value, path, sameSite, secure, httpOnly, domain, expires, and maxAge.
9
+ * It handles URL decoding of the cookie value and proper type conversion for boolean and
10
+ * numeric attributes.
11
+ *
12
+ * The function expects cookie strings in the format:
13
+ * "name=value; path=/; secure; httpOnly; sameSite=Strict; domain=example.com; expires=Wed, 09 Jun 2021 10:18:14 GMT; max-age=3600"
14
+ *
15
+ * @param cookieString - The Set-Cookie header string to parse
16
+ * @returns A GenericCookie object with all parsed attributes
17
+ * @throws {Error} If the cookie string format is invalid or cannot be parsed
18
+ */
19
+ function parseCookieString(cookieString) {
20
+ if (!cookieString || typeof cookieString !== "string") throw new Error("Invalid cookie string: must be a non-empty string");
21
+ const [nameValue, ...attributeParts] = cookieString.split(";");
22
+ const [nameRaw, encodedValue] = nameValue.split("=");
23
+ const name = nameRaw ? nameRaw.trim().toLowerCase() : "";
24
+ if (!name || encodedValue === void 0) throw new Error("Invalid cookie string: must contain a name and value separated by \"=\"");
25
+ const attributesArray = attributeParts.map((part) => part.split("=")).map(([key, value]) => [key.trim().toLowerCase(), value ?? "true"]);
26
+ const attrs = Object.fromEntries(attributesArray);
27
+ return {
28
+ name,
29
+ value: encodedValue ? decodeURIComponent(encodedValue) : "",
30
+ path: attrs["path"],
31
+ sameSite: attrs["samesite"],
32
+ secure: attrs["secure"] === "true",
33
+ httpOnly: attrs["httponly"] === "true",
34
+ domain: attrs["domain"],
35
+ expires: attrs["expires"] ? new Date(attrs["expires"]) : void 0,
36
+ maxAge: attrs["max-age"] ? Number.parseInt(attrs["max-age"], 10) : void 0
37
+ };
38
+ }
39
+ /**
40
+ * Extracts cookies from a Headers object and converts them to generic cookie format.
41
+ *
42
+ * This function processes the Set-Cookie headers from a standard web Response Headers object
43
+ * and converts them into generic cookie objects. It handles the case where no cookies are
44
+ * present by returning undefined.
45
+ *
46
+ * @param headers - The Headers object from a web Response
47
+ * @returns An array of GenericCookie objects, or undefined if no cookies are present
48
+ */
49
+ function cookiesFromHeaders$1(headers) {
50
+ const cookies = headers.getSetCookie();
51
+ if (cookies.length === 0) return void 0;
52
+ return cookies.map(parseCookieString);
53
+ }
54
+
55
+ //#endregion
56
+ //#region src/Adapters/azure-functions/Utils/Request.ts
57
+ /**
58
+ * Converts an Azure Functions HttpRequest to a standard web Request object.
59
+ *
60
+ * This function bridges the gap between Azure Functions HTTP triggers and the standard
61
+ * web Request API. It extracts the HTTP method, URL, headers, and body from the Azure
62
+ * Functions HttpRequest and creates a standard Request object that can be used with
63
+ * the Vercube application framework.
64
+ *
65
+ * The function handles:
66
+ * - HTTP method extraction from the request
67
+ * - URL preservation from the Azure Functions request
68
+ * - Header conversion from Azure Functions format to standard Headers
69
+ * - Body handling for non-GET/HEAD requests with proper duplex stream support
70
+ *
71
+ * This file is highly inspired by the `newRequestFromAzureFunctions` from `hono-azurefunc-adapter`
72
+ * @see https://github.com/Marplex/hono-azurefunc-adapter/blob/main/src/request.ts
73
+ *
74
+ * @param request - The Azure Functions HttpRequest object to convert
75
+ * @returns A standard web Request object compatible with the fetch API
76
+ * @throws {Error} If the request object is invalid or missing required properties
77
+ */
78
+ function convertEventToRequest(request) {
79
+ const hasBody = !["GET", "HEAD"].includes(request.method);
80
+ return new Request(request.url, {
81
+ method: request.method,
82
+ headers: headersToObject(request.headers),
83
+ ...hasBody ? {
84
+ body: request.body,
85
+ duplex: "half"
86
+ } : {}
87
+ });
88
+ }
89
+
90
+ //#endregion
91
+ //#region src/Adapters/azure-functions/Utils/Utils.ts
92
+ /**
93
+ * Extracts cookies from a Headers object and converts them to Azure Functions Cookie format.
94
+ *
95
+ * This function processes the Set-Cookie headers from a standard web Response Headers object
96
+ * and converts them into the Cookie format expected by Azure Functions. It handles the case
97
+ * where no cookies are present by returning undefined.
98
+ *
99
+ * @param headers - The Headers object from a web Response
100
+ * @returns An array of Cookie objects, or undefined if no cookies are present
101
+ */
102
+ function cookiesFromHeaders(headers) {
103
+ const genericCookies = cookiesFromHeaders$1(headers);
104
+ if (!genericCookies) return void 0;
105
+ return genericCookies.map(convertGenericCookieToAzure);
106
+ }
107
+ /**
108
+ * Converts a generic cookie object to Azure Functions Cookie format.
109
+ *
110
+ * @param genericCookie - The generic cookie object to convert
111
+ * @returns An Azure Functions Cookie object
112
+ */
113
+ function convertGenericCookieToAzure(genericCookie) {
114
+ return {
115
+ name: genericCookie.name,
116
+ value: genericCookie.value,
117
+ path: genericCookie.path,
118
+ sameSite: genericCookie.sameSite,
119
+ secure: genericCookie.secure,
120
+ httpOnly: genericCookie.httpOnly,
121
+ domain: genericCookie.domain,
122
+ expires: genericCookie.expires,
123
+ maxAge: genericCookie.maxAge
124
+ };
125
+ }
126
+
127
+ //#endregion
128
+ //#region src/Adapters/azure-functions/Utils/Response.ts
129
+ /**
130
+ * Converts a standard web Response object to Azure Functions HttpResponseInit format.
131
+ *
132
+ * This function transforms a standard web Response object into the format expected by
133
+ * Azure Functions HTTP responses. It handles the conversion of headers, cookies, status
134
+ * code, and body to ensure compatibility with Azure Functions runtime.
135
+ *
136
+ * The function processes:
137
+ * - Response headers conversion to plain object format
138
+ * - Set-Cookie headers extraction and conversion to Azure Functions Cookie format
139
+ * - HTTP status code preservation
140
+ * - Response body conversion to AsyncIterableIterator for Azure Functions compatibility
141
+ *
142
+ * This file is highly inspired by the `newAzureFunctionsResponse` from `hono-azurefunc-adapter`
143
+ * @see https://github.com/Marplex/hono-azurefunc-adapter/blob/main/src/response.ts
144
+ *
145
+ * @param response - The standard web Response object to convert
146
+ * @returns An HttpResponseInit object compatible with Azure Functions
147
+ * @throws {Error} If the response object is invalid or missing required properties
148
+ */
149
+ function convertResponseToAzureFunctionsResponse(response) {
150
+ const headers = headersToObject(response.headers);
151
+ return {
152
+ cookies: cookiesFromHeaders(response.headers),
153
+ headers,
154
+ status: response.status,
155
+ body: streamToAsyncIterator(response.body)
156
+ };
157
+ }
158
+
159
+ //#endregion
160
+ //#region src/Adapters/azure-functions/index.ts
161
+ /**
162
+ * Converts a Vercube App instance into an Azure Functions handler function for HTTP integration.
163
+ *
164
+ * This function creates a serverless handler that bridges between Azure Functions HTTP triggers
165
+ * and the Vercube application framework. It handles the conversion of Azure Functions HttpRequest
166
+ * objects to standard web Request objects, processes them through the Vercube app, and converts
167
+ * the responses back to the format expected by Azure Functions.
168
+ *
169
+ * The handler processes:
170
+ * - HTTP method, URL, headers, and body from the Azure Functions HttpRequest
171
+ * - Converts them to a standard web Request object
172
+ * - Passes the request through the Vercube application
173
+ * - Converts the Response back to Azure Functions HttpResponseInit format
174
+ *
175
+ * The returned handler function can be directly used as an Azure Functions HTTP trigger handler,
176
+ * providing seamless integration between Azure Functions and Vercube applications.
177
+ *
178
+ * @param app - The Vercube App instance that will handle the requests
179
+ * @returns An async function that accepts Azure Functions HttpRequest and returns HttpResponseInit
180
+ *
181
+ * @see {@link convertEventToRequest} For details on HttpRequest to Request conversion
182
+ * @see {@link convertResponseToAzureFunctionsResponse} For details on Response to HttpResponseInit conversion
183
+ */
184
+ function toServerlessHandler(app) {
185
+ return async (event) => {
186
+ const request = convertEventToRequest(event);
187
+ const response = await app.fetch(request);
188
+ return convertResponseToAzureFunctionsResponse(response);
189
+ };
190
+ }
191
+
192
+ //#endregion
193
+ export { toServerlessHandler };
package/dist/index.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { ServerlessHandler } from "./ServerlessTypes-lXnSKHNA.mjs";
1
+ import { ServerlessHandler } from "./ServerlessTypes-WMcCL6v7.mjs";
2
2
  export { ServerlessHandler };
@@ -0,0 +1,108 @@
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 { getHeaderValue, headersToObject, streamToAsyncIterator, toBuffer };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercube/serverless",
3
- "version": "0.0.23",
3
+ "version": "0.0.24",
4
4
  "description": "Serverless module for Vercube framework",
5
5
  "repository": {
6
6
  "type": "git",
@@ -15,7 +15,8 @@
15
15
  "exports": {
16
16
  ".": "./dist/index.mjs",
17
17
  "./package.json": "./package.json",
18
- "./aws-lambda": "./dist/Adapters/aws-lambda/index.mjs"
18
+ "./aws-lambda": "./dist/Adapters/aws-lambda/index.mjs",
19
+ "./azure-functions": "./dist/Adapters/azure-functions/index.mjs"
19
20
  },
20
21
  "types": "./dist/index.d.mts",
21
22
  "files": [
@@ -35,12 +36,12 @@
35
36
  ],
36
37
  "dependencies": {
37
38
  "ufo": "1.6.1",
38
- "@vercube/core": "0.0.23",
39
- "@vercube/di": "0.0.23"
39
+ "@vercube/core": "0.0.24",
40
+ "@vercube/di": "0.0.24"
40
41
  },
41
42
  "devDependencies": {
42
- "@types/aws-lambda": "8.10.152",
43
- "@azure/functions": "4.7.2-preview"
43
+ "@azure/functions": "4.8.0",
44
+ "@types/aws-lambda": "8.10.152"
44
45
  },
45
46
  "publishConfig": {
46
47
  "access": "public"