@adaas/a-server 0.0.27 → 0.0.29

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.
@@ -73,7 +73,7 @@ class A_RequestHelper {
73
73
  let bodyType;
74
74
  switch (true) {
75
75
  case (!!context.contentType && context.contentType.includes("application/json")):
76
- parsedBody = JSON.parse(context.data);
76
+ parsedBody = JSON.parse(context.data || "{}");
77
77
  bodyType = "json";
78
78
  break;
79
79
  case (!!context.contentType && context.contentType.includes("application/x-www-form-urlencoded")):
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/lib/A-Request/A-Request.helper.ts"],"names":["A_RequestError"],"mappings":"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","file":"A-Request.helper.js","sourcesContent":["import { A_HttpServerRequestContext } from \"./A-HttpServerRequest.context\";\nimport { A_RequestError } from \"./A-Request.error\";\nimport { A_Request_BodyType, A_Request_FileUpload } from \"./A-Request.types\";\n\n/**\n * A_RequestHelper - Stateless utility class for HTTP request processing\n * \n * This helper class provides static methods for parsing and processing HTTP request data:\n * - URL parameter extraction from route patterns\n * - Query string parsing\n * - Request body parsing (JSON, form-data, multipart, raw)\n * - URL-encoded form data parsing\n * - Multipart form data parsing (including file uploads)\n * \n * All methods are stateless and only depend on input parameters.\n * \n * @example\n * ```typescript\n * // Extract URL parameters\n * const params = A_RequestHelper.extractParams('/users/123', '/users/:id');\n * // { id: '123' }\n * \n * // Parse query string\n * const query = A_RequestHelper.extractQuery('/api/users?page=1&limit=10');\n * // { page: '1', limit: '10' }\n * \n * // Parse request body\n * const result = await A_RequestHelper.parseRequestBody(req, { maxBodySize: 1024 * 1024 });\n * // { data: {...}, type: 'json' }\n * ```\n */\nexport class A_RequestHelper {\n\n /**\n * Extract URL parameters from a URL using a route pattern\n * @param url - The actual URL to extract parameters from\n * @param routePattern - The route pattern with parameters (e.g., \"/users/:id/posts/:postId\")\n * @returns Object containing extracted parameters\n */\n static extractParams(url: string, routePattern: string): Record<string, string> {\n // Remove query string (anything after ?)\n const cleanUrl = url.split('?')[0];\n const cleanPattern = routePattern.split('?')[0];\n\n const urlSegments = cleanUrl.split('/').filter(Boolean);\n const patternSegments = cleanPattern.split('/').filter(Boolean);\n\n const params: Record<string, string> = {};\n\n for (let i = 0; i < patternSegments.length; i++) {\n const patternSegment = patternSegments[i];\n const urlSegment = urlSegments[i];\n\n if (patternSegment.startsWith(':')) {\n const paramName = patternSegment.slice(1); // Remove ':' from pattern\n if (urlSegment) {\n params[paramName] = decodeURIComponent(urlSegment);\n }\n } else if (patternSegment !== urlSegment) {\n // If static segments don't match → fail\n return {};\n }\n }\n\n return params;\n }\n\n\n\n /**\n * Extract query parameters from URL\n * @param url - The URL to extract query parameters from\n * @returns Object containing query parameters\n */\n static extractQuery<T = Record<string, string>>(url: string): T {\n const query: Record<string, string> = {};\n\n // Take only the part after \"?\"\n const queryString = url.split('?')[1];\n if (!queryString) return query as T;\n\n // Remove fragment (#...) if present\n const cleanQuery = queryString.split('#')[0];\n\n // Split into key=value pairs\n for (const pair of cleanQuery.split('&')) {\n if (!pair) continue;\n const [key, value = ''] = pair.split('=');\n query[decodeURIComponent(key)] = decodeURIComponent(value);\n }\n\n return query as T;\n }\n\n\n /**\n * Parse cookies from Cookie header\n */\n static parseCookies(\n cookieHeader?: string\n ): Record<string, string> {\n const cookies: Record<string, string> = {};\n\n if (!cookieHeader) return {};\n\n cookieHeader.split(';').forEach(cookie => {\n const [name, ...rest] = cookie.trim().split('=');\n const value = rest.join('=');\n if (name && value) {\n cookies[name] = decodeURIComponent(value);\n }\n });\n\n return cookies;\n }\n\n /**\n * Parse request body based on Content-Type\n * \n * \n * @param context - The HTTP server request context\n * @returns Parsed body data and detected body type\n */\n static parseRequestBody<T extends any = any>(\n context: A_HttpServerRequestContext\n ): {\n data: T;\n type: A_Request_BodyType;\n } {\n let parsedBody: any;\n let bodyType: A_Request_BodyType;\n\n switch (true) {\n case !!context.contentType && context.contentType.includes('application/json'):\n parsedBody = JSON.parse(context.data);\n bodyType = 'json';\n break;\n case !!context.contentType && context.contentType.includes('application/x-www-form-urlencoded'):\n parsedBody = A_RequestHelper.parseFormUrlEncoded(context.data) as T;\n bodyType = 'form';\n break;\n case !!context.contentType && context.contentType.includes('multipart/form-data'):\n const multipartResult = A_RequestHelper.parseMultipartData(Buffer.concat(context.buffers), context.contentType);\n // Return the entire multipart result (fields + files) as T\n parsedBody = {\n ...multipartResult.fields,\n _files: multipartResult.files\n } as T;\n bodyType = 'multipart';\n break;\n case !!context.contentType && context.contentType.includes('text/'):\n parsedBody = context.data as T;\n bodyType = 'text';\n break;\n default:\n parsedBody = Buffer.concat(context.buffers) as T;\n bodyType = 'raw';\n break;\n }\n\n\n return {\n data: parsedBody,\n type: bodyType\n };\n }\n\n /**\n * Parse URL-encoded form data (application/x-www-form-urlencoded)\n * @param body - The URL-encoded body string\n * @returns Object containing form data\n */\n static parseFormUrlEncoded(\n /**\n * The URL-encoded body string\n */\n body: string\n ): Record<string, string | string[]> {\n const result: Record<string, string | string[]> = {};\n\n if (!body) return result;\n\n const pairs = body.split('&');\n\n for (const pair of pairs) {\n if (!pair) continue;\n\n const [key, value = ''] = pair.split('=');\n const decodedKey = decodeURIComponent(key.replace(/\\+/g, ' '));\n const decodedValue = decodeURIComponent(value.replace(/\\+/g, ' '));\n\n // Handle multiple values for the same key (arrays)\n if (decodedKey in result) {\n const existing = result[decodedKey];\n if (Array.isArray(existing)) {\n existing.push(decodedValue);\n } else {\n result[decodedKey] = [existing, decodedValue];\n }\n } else {\n result[decodedKey] = decodedValue;\n }\n }\n\n return result;\n }\n\n /**\n * Parse multipart form data (for file uploads and form data)\n * @param buffer - The raw buffer containing multipart data\n * @param contentType - The content type header\n * @returns Object containing fields and files\n */\n static parseMultipartData(\n /**\n * The raw buffer containing multipart data\n */\n buffer: Buffer,\n /**\n * The content type header\n */\n contentType: string\n ): {\n fields: Record<string, string>;\n files: A_Request_FileUpload[];\n } {\n // Extract boundary\n const boundaryMatch = contentType.match(/boundary=(.+)/);\n if (!boundaryMatch) {\n throw new A_RequestError(\n A_RequestError.RequestBodyParsingError,\n 'Missing boundary in multipart/form-data content type'\n )\n }\n\n const boundary = '--' + boundaryMatch[1];\n const textData = buffer.toString();\n const parts = textData.split(boundary).filter(part => part.trim() && !part.includes('--'));\n\n const fields: Record<string, string> = {};\n const files: A_Request_FileUpload[] = [];\n\n parts.forEach(part => {\n const [headers, content] = part.split('\\r\\n\\r\\n');\n if (!headers || content === undefined) return;\n\n const nameMatch = headers.match(/name=\"([^\"]+)\"/);\n const filenameMatch = headers.match(/filename=\"([^\"]+)\"/);\n const contentTypeMatch = headers.match(/Content-Type: ([^\\r\\n]+)/);\n\n if (nameMatch) {\n const fieldName = nameMatch[1];\n const cleanContent = content.replace(/\\r\\n$/, '');\n\n if (filenameMatch) {\n // It's a file upload\n const file: A_Request_FileUpload = {\n fieldName,\n filename: filenameMatch[1],\n encoding: 'binary',\n mimetype: contentTypeMatch?.[1] || 'application/octet-stream',\n size: Buffer.byteLength(cleanContent),\n buffer: Buffer.from(cleanContent, 'binary')\n };\n files.push(file);\n } else {\n // It's a regular field\n fields[fieldName] = cleanContent;\n }\n }\n });\n\n return { fields, files };\n }\n\n}"]}
1
+ {"version":3,"sources":["../../../../src/lib/A-Request/A-Request.helper.ts"],"names":["A_RequestError"],"mappings":"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","file":"A-Request.helper.js","sourcesContent":["import { A_HttpServerRequestContext } from \"./A-HttpServerRequest.context\";\nimport { A_RequestError } from \"./A-Request.error\";\nimport { A_Request_BodyType, A_Request_FileUpload } from \"./A-Request.types\";\n\n/**\n * A_RequestHelper - Stateless utility class for HTTP request processing\n * \n * This helper class provides static methods for parsing and processing HTTP request data:\n * - URL parameter extraction from route patterns\n * - Query string parsing\n * - Request body parsing (JSON, form-data, multipart, raw)\n * - URL-encoded form data parsing\n * - Multipart form data parsing (including file uploads)\n * \n * All methods are stateless and only depend on input parameters.\n * \n * @example\n * ```typescript\n * // Extract URL parameters\n * const params = A_RequestHelper.extractParams('/users/123', '/users/:id');\n * // { id: '123' }\n * \n * // Parse query string\n * const query = A_RequestHelper.extractQuery('/api/users?page=1&limit=10');\n * // { page: '1', limit: '10' }\n * \n * // Parse request body\n * const result = await A_RequestHelper.parseRequestBody(req, { maxBodySize: 1024 * 1024 });\n * // { data: {...}, type: 'json' }\n * ```\n */\nexport class A_RequestHelper {\n\n /**\n * Extract URL parameters from a URL using a route pattern\n * @param url - The actual URL to extract parameters from\n * @param routePattern - The route pattern with parameters (e.g., \"/users/:id/posts/:postId\")\n * @returns Object containing extracted parameters\n */\n static extractParams(url: string, routePattern: string): Record<string, string> {\n // Remove query string (anything after ?)\n const cleanUrl = url.split('?')[0];\n const cleanPattern = routePattern.split('?')[0];\n\n const urlSegments = cleanUrl.split('/').filter(Boolean);\n const patternSegments = cleanPattern.split('/').filter(Boolean);\n\n const params: Record<string, string> = {};\n\n for (let i = 0; i < patternSegments.length; i++) {\n const patternSegment = patternSegments[i];\n const urlSegment = urlSegments[i];\n\n if (patternSegment.startsWith(':')) {\n const paramName = patternSegment.slice(1); // Remove ':' from pattern\n if (urlSegment) {\n params[paramName] = decodeURIComponent(urlSegment);\n }\n } else if (patternSegment !== urlSegment) {\n // If static segments don't match → fail\n return {};\n }\n }\n\n return params;\n }\n\n\n\n /**\n * Extract query parameters from URL\n * @param url - The URL to extract query parameters from\n * @returns Object containing query parameters\n */\n static extractQuery<T = Record<string, string>>(url: string): T {\n const query: Record<string, string> = {};\n\n // Take only the part after \"?\"\n const queryString = url.split('?')[1];\n if (!queryString) return query as T;\n\n // Remove fragment (#...) if present\n const cleanQuery = queryString.split('#')[0];\n\n // Split into key=value pairs\n for (const pair of cleanQuery.split('&')) {\n if (!pair) continue;\n const [key, value = ''] = pair.split('=');\n query[decodeURIComponent(key)] = decodeURIComponent(value);\n }\n\n return query as T;\n }\n\n\n /**\n * Parse cookies from Cookie header\n */\n static parseCookies(\n cookieHeader?: string\n ): Record<string, string> {\n const cookies: Record<string, string> = {};\n\n if (!cookieHeader) return {};\n\n cookieHeader.split(';').forEach(cookie => {\n const [name, ...rest] = cookie.trim().split('=');\n const value = rest.join('=');\n if (name && value) {\n cookies[name] = decodeURIComponent(value);\n }\n });\n\n return cookies;\n }\n\n /**\n * Parse request body based on Content-Type\n * \n * \n * @param context - The HTTP server request context\n * @returns Parsed body data and detected body type\n */\n static parseRequestBody<T extends any = any>(\n context: A_HttpServerRequestContext\n ): {\n data: T;\n type: A_Request_BodyType;\n } {\n let parsedBody: any;\n let bodyType: A_Request_BodyType;\n\n switch (true) {\n case !!context.contentType && context.contentType.includes('application/json'):\n parsedBody = JSON.parse(context.data || '{}');\n bodyType = 'json';\n break;\n case !!context.contentType && context.contentType.includes('application/x-www-form-urlencoded'):\n parsedBody = A_RequestHelper.parseFormUrlEncoded(context.data) as T;\n bodyType = 'form';\n break;\n case !!context.contentType && context.contentType.includes('multipart/form-data'):\n const multipartResult = A_RequestHelper.parseMultipartData(Buffer.concat(context.buffers), context.contentType);\n // Return the entire multipart result (fields + files) as T\n parsedBody = {\n ...multipartResult.fields,\n _files: multipartResult.files\n } as T;\n bodyType = 'multipart';\n break;\n case !!context.contentType && context.contentType.includes('text/'):\n parsedBody = context.data as T;\n bodyType = 'text';\n break;\n default:\n parsedBody = Buffer.concat(context.buffers) as T;\n bodyType = 'raw';\n break;\n }\n\n\n return {\n data: parsedBody,\n type: bodyType\n };\n }\n\n /**\n * Parse URL-encoded form data (application/x-www-form-urlencoded)\n * @param body - The URL-encoded body string\n * @returns Object containing form data\n */\n static parseFormUrlEncoded(\n /**\n * The URL-encoded body string\n */\n body: string\n ): Record<string, string | string[]> {\n const result: Record<string, string | string[]> = {};\n\n if (!body) return result;\n\n const pairs = body.split('&');\n\n for (const pair of pairs) {\n if (!pair) continue;\n\n const [key, value = ''] = pair.split('=');\n const decodedKey = decodeURIComponent(key.replace(/\\+/g, ' '));\n const decodedValue = decodeURIComponent(value.replace(/\\+/g, ' '));\n\n // Handle multiple values for the same key (arrays)\n if (decodedKey in result) {\n const existing = result[decodedKey];\n if (Array.isArray(existing)) {\n existing.push(decodedValue);\n } else {\n result[decodedKey] = [existing, decodedValue];\n }\n } else {\n result[decodedKey] = decodedValue;\n }\n }\n\n return result;\n }\n\n /**\n * Parse multipart form data (for file uploads and form data)\n * @param buffer - The raw buffer containing multipart data\n * @param contentType - The content type header\n * @returns Object containing fields and files\n */\n static parseMultipartData(\n /**\n * The raw buffer containing multipart data\n */\n buffer: Buffer,\n /**\n * The content type header\n */\n contentType: string\n ): {\n fields: Record<string, string>;\n files: A_Request_FileUpload[];\n } {\n // Extract boundary\n const boundaryMatch = contentType.match(/boundary=(.+)/);\n if (!boundaryMatch) {\n throw new A_RequestError(\n A_RequestError.RequestBodyParsingError,\n 'Missing boundary in multipart/form-data content type'\n )\n }\n\n const boundary = '--' + boundaryMatch[1];\n const textData = buffer.toString();\n const parts = textData.split(boundary).filter(part => part.trim() && !part.includes('--'));\n\n const fields: Record<string, string> = {};\n const files: A_Request_FileUpload[] = [];\n\n parts.forEach(part => {\n const [headers, content] = part.split('\\r\\n\\r\\n');\n if (!headers || content === undefined) return;\n\n const nameMatch = headers.match(/name=\"([^\"]+)\"/);\n const filenameMatch = headers.match(/filename=\"([^\"]+)\"/);\n const contentTypeMatch = headers.match(/Content-Type: ([^\\r\\n]+)/);\n\n if (nameMatch) {\n const fieldName = nameMatch[1];\n const cleanContent = content.replace(/\\r\\n$/, '');\n\n if (filenameMatch) {\n // It's a file upload\n const file: A_Request_FileUpload = {\n fieldName,\n filename: filenameMatch[1],\n encoding: 'binary',\n mimetype: contentTypeMatch?.[1] || 'application/octet-stream',\n size: Buffer.byteLength(cleanContent),\n buffer: Buffer.from(cleanContent, 'binary')\n };\n files.push(file);\n } else {\n // It's a regular field\n fields[fieldName] = cleanContent;\n }\n }\n });\n\n return { fields, files };\n }\n\n}"]}
@@ -72,7 +72,7 @@ class A_RequestHelper {
72
72
  let bodyType;
73
73
  switch (true) {
74
74
  case (!!context.contentType && context.contentType.includes("application/json")):
75
- parsedBody = JSON.parse(context.data);
75
+ parsedBody = JSON.parse(context.data || "{}");
76
76
  bodyType = "json";
77
77
  break;
78
78
  case (!!context.contentType && context.contentType.includes("application/x-www-form-urlencoded")):
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/lib/A-Request/A-Request.helper.ts"],"names":[],"mappings":"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","file":"A-Request.helper.mjs","sourcesContent":["import { A_HttpServerRequestContext } from \"./A-HttpServerRequest.context\";\nimport { A_RequestError } from \"./A-Request.error\";\nimport { A_Request_BodyType, A_Request_FileUpload } from \"./A-Request.types\";\n\n/**\n * A_RequestHelper - Stateless utility class for HTTP request processing\n * \n * This helper class provides static methods for parsing and processing HTTP request data:\n * - URL parameter extraction from route patterns\n * - Query string parsing\n * - Request body parsing (JSON, form-data, multipart, raw)\n * - URL-encoded form data parsing\n * - Multipart form data parsing (including file uploads)\n * \n * All methods are stateless and only depend on input parameters.\n * \n * @example\n * ```typescript\n * // Extract URL parameters\n * const params = A_RequestHelper.extractParams('/users/123', '/users/:id');\n * // { id: '123' }\n * \n * // Parse query string\n * const query = A_RequestHelper.extractQuery('/api/users?page=1&limit=10');\n * // { page: '1', limit: '10' }\n * \n * // Parse request body\n * const result = await A_RequestHelper.parseRequestBody(req, { maxBodySize: 1024 * 1024 });\n * // { data: {...}, type: 'json' }\n * ```\n */\nexport class A_RequestHelper {\n\n /**\n * Extract URL parameters from a URL using a route pattern\n * @param url - The actual URL to extract parameters from\n * @param routePattern - The route pattern with parameters (e.g., \"/users/:id/posts/:postId\")\n * @returns Object containing extracted parameters\n */\n static extractParams(url: string, routePattern: string): Record<string, string> {\n // Remove query string (anything after ?)\n const cleanUrl = url.split('?')[0];\n const cleanPattern = routePattern.split('?')[0];\n\n const urlSegments = cleanUrl.split('/').filter(Boolean);\n const patternSegments = cleanPattern.split('/').filter(Boolean);\n\n const params: Record<string, string> = {};\n\n for (let i = 0; i < patternSegments.length; i++) {\n const patternSegment = patternSegments[i];\n const urlSegment = urlSegments[i];\n\n if (patternSegment.startsWith(':')) {\n const paramName = patternSegment.slice(1); // Remove ':' from pattern\n if (urlSegment) {\n params[paramName] = decodeURIComponent(urlSegment);\n }\n } else if (patternSegment !== urlSegment) {\n // If static segments don't match → fail\n return {};\n }\n }\n\n return params;\n }\n\n\n\n /**\n * Extract query parameters from URL\n * @param url - The URL to extract query parameters from\n * @returns Object containing query parameters\n */\n static extractQuery<T = Record<string, string>>(url: string): T {\n const query: Record<string, string> = {};\n\n // Take only the part after \"?\"\n const queryString = url.split('?')[1];\n if (!queryString) return query as T;\n\n // Remove fragment (#...) if present\n const cleanQuery = queryString.split('#')[0];\n\n // Split into key=value pairs\n for (const pair of cleanQuery.split('&')) {\n if (!pair) continue;\n const [key, value = ''] = pair.split('=');\n query[decodeURIComponent(key)] = decodeURIComponent(value);\n }\n\n return query as T;\n }\n\n\n /**\n * Parse cookies from Cookie header\n */\n static parseCookies(\n cookieHeader?: string\n ): Record<string, string> {\n const cookies: Record<string, string> = {};\n\n if (!cookieHeader) return {};\n\n cookieHeader.split(';').forEach(cookie => {\n const [name, ...rest] = cookie.trim().split('=');\n const value = rest.join('=');\n if (name && value) {\n cookies[name] = decodeURIComponent(value);\n }\n });\n\n return cookies;\n }\n\n /**\n * Parse request body based on Content-Type\n * \n * \n * @param context - The HTTP server request context\n * @returns Parsed body data and detected body type\n */\n static parseRequestBody<T extends any = any>(\n context: A_HttpServerRequestContext\n ): {\n data: T;\n type: A_Request_BodyType;\n } {\n let parsedBody: any;\n let bodyType: A_Request_BodyType;\n\n switch (true) {\n case !!context.contentType && context.contentType.includes('application/json'):\n parsedBody = JSON.parse(context.data);\n bodyType = 'json';\n break;\n case !!context.contentType && context.contentType.includes('application/x-www-form-urlencoded'):\n parsedBody = A_RequestHelper.parseFormUrlEncoded(context.data) as T;\n bodyType = 'form';\n break;\n case !!context.contentType && context.contentType.includes('multipart/form-data'):\n const multipartResult = A_RequestHelper.parseMultipartData(Buffer.concat(context.buffers), context.contentType);\n // Return the entire multipart result (fields + files) as T\n parsedBody = {\n ...multipartResult.fields,\n _files: multipartResult.files\n } as T;\n bodyType = 'multipart';\n break;\n case !!context.contentType && context.contentType.includes('text/'):\n parsedBody = context.data as T;\n bodyType = 'text';\n break;\n default:\n parsedBody = Buffer.concat(context.buffers) as T;\n bodyType = 'raw';\n break;\n }\n\n\n return {\n data: parsedBody,\n type: bodyType\n };\n }\n\n /**\n * Parse URL-encoded form data (application/x-www-form-urlencoded)\n * @param body - The URL-encoded body string\n * @returns Object containing form data\n */\n static parseFormUrlEncoded(\n /**\n * The URL-encoded body string\n */\n body: string\n ): Record<string, string | string[]> {\n const result: Record<string, string | string[]> = {};\n\n if (!body) return result;\n\n const pairs = body.split('&');\n\n for (const pair of pairs) {\n if (!pair) continue;\n\n const [key, value = ''] = pair.split('=');\n const decodedKey = decodeURIComponent(key.replace(/\\+/g, ' '));\n const decodedValue = decodeURIComponent(value.replace(/\\+/g, ' '));\n\n // Handle multiple values for the same key (arrays)\n if (decodedKey in result) {\n const existing = result[decodedKey];\n if (Array.isArray(existing)) {\n existing.push(decodedValue);\n } else {\n result[decodedKey] = [existing, decodedValue];\n }\n } else {\n result[decodedKey] = decodedValue;\n }\n }\n\n return result;\n }\n\n /**\n * Parse multipart form data (for file uploads and form data)\n * @param buffer - The raw buffer containing multipart data\n * @param contentType - The content type header\n * @returns Object containing fields and files\n */\n static parseMultipartData(\n /**\n * The raw buffer containing multipart data\n */\n buffer: Buffer,\n /**\n * The content type header\n */\n contentType: string\n ): {\n fields: Record<string, string>;\n files: A_Request_FileUpload[];\n } {\n // Extract boundary\n const boundaryMatch = contentType.match(/boundary=(.+)/);\n if (!boundaryMatch) {\n throw new A_RequestError(\n A_RequestError.RequestBodyParsingError,\n 'Missing boundary in multipart/form-data content type'\n )\n }\n\n const boundary = '--' + boundaryMatch[1];\n const textData = buffer.toString();\n const parts = textData.split(boundary).filter(part => part.trim() && !part.includes('--'));\n\n const fields: Record<string, string> = {};\n const files: A_Request_FileUpload[] = [];\n\n parts.forEach(part => {\n const [headers, content] = part.split('\\r\\n\\r\\n');\n if (!headers || content === undefined) return;\n\n const nameMatch = headers.match(/name=\"([^\"]+)\"/);\n const filenameMatch = headers.match(/filename=\"([^\"]+)\"/);\n const contentTypeMatch = headers.match(/Content-Type: ([^\\r\\n]+)/);\n\n if (nameMatch) {\n const fieldName = nameMatch[1];\n const cleanContent = content.replace(/\\r\\n$/, '');\n\n if (filenameMatch) {\n // It's a file upload\n const file: A_Request_FileUpload = {\n fieldName,\n filename: filenameMatch[1],\n encoding: 'binary',\n mimetype: contentTypeMatch?.[1] || 'application/octet-stream',\n size: Buffer.byteLength(cleanContent),\n buffer: Buffer.from(cleanContent, 'binary')\n };\n files.push(file);\n } else {\n // It's a regular field\n fields[fieldName] = cleanContent;\n }\n }\n });\n\n return { fields, files };\n }\n\n}"]}
1
+ {"version":3,"sources":["../../../../src/lib/A-Request/A-Request.helper.ts"],"names":[],"mappings":"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","file":"A-Request.helper.mjs","sourcesContent":["import { A_HttpServerRequestContext } from \"./A-HttpServerRequest.context\";\nimport { A_RequestError } from \"./A-Request.error\";\nimport { A_Request_BodyType, A_Request_FileUpload } from \"./A-Request.types\";\n\n/**\n * A_RequestHelper - Stateless utility class for HTTP request processing\n * \n * This helper class provides static methods for parsing and processing HTTP request data:\n * - URL parameter extraction from route patterns\n * - Query string parsing\n * - Request body parsing (JSON, form-data, multipart, raw)\n * - URL-encoded form data parsing\n * - Multipart form data parsing (including file uploads)\n * \n * All methods are stateless and only depend on input parameters.\n * \n * @example\n * ```typescript\n * // Extract URL parameters\n * const params = A_RequestHelper.extractParams('/users/123', '/users/:id');\n * // { id: '123' }\n * \n * // Parse query string\n * const query = A_RequestHelper.extractQuery('/api/users?page=1&limit=10');\n * // { page: '1', limit: '10' }\n * \n * // Parse request body\n * const result = await A_RequestHelper.parseRequestBody(req, { maxBodySize: 1024 * 1024 });\n * // { data: {...}, type: 'json' }\n * ```\n */\nexport class A_RequestHelper {\n\n /**\n * Extract URL parameters from a URL using a route pattern\n * @param url - The actual URL to extract parameters from\n * @param routePattern - The route pattern with parameters (e.g., \"/users/:id/posts/:postId\")\n * @returns Object containing extracted parameters\n */\n static extractParams(url: string, routePattern: string): Record<string, string> {\n // Remove query string (anything after ?)\n const cleanUrl = url.split('?')[0];\n const cleanPattern = routePattern.split('?')[0];\n\n const urlSegments = cleanUrl.split('/').filter(Boolean);\n const patternSegments = cleanPattern.split('/').filter(Boolean);\n\n const params: Record<string, string> = {};\n\n for (let i = 0; i < patternSegments.length; i++) {\n const patternSegment = patternSegments[i];\n const urlSegment = urlSegments[i];\n\n if (patternSegment.startsWith(':')) {\n const paramName = patternSegment.slice(1); // Remove ':' from pattern\n if (urlSegment) {\n params[paramName] = decodeURIComponent(urlSegment);\n }\n } else if (patternSegment !== urlSegment) {\n // If static segments don't match → fail\n return {};\n }\n }\n\n return params;\n }\n\n\n\n /**\n * Extract query parameters from URL\n * @param url - The URL to extract query parameters from\n * @returns Object containing query parameters\n */\n static extractQuery<T = Record<string, string>>(url: string): T {\n const query: Record<string, string> = {};\n\n // Take only the part after \"?\"\n const queryString = url.split('?')[1];\n if (!queryString) return query as T;\n\n // Remove fragment (#...) if present\n const cleanQuery = queryString.split('#')[0];\n\n // Split into key=value pairs\n for (const pair of cleanQuery.split('&')) {\n if (!pair) continue;\n const [key, value = ''] = pair.split('=');\n query[decodeURIComponent(key)] = decodeURIComponent(value);\n }\n\n return query as T;\n }\n\n\n /**\n * Parse cookies from Cookie header\n */\n static parseCookies(\n cookieHeader?: string\n ): Record<string, string> {\n const cookies: Record<string, string> = {};\n\n if (!cookieHeader) return {};\n\n cookieHeader.split(';').forEach(cookie => {\n const [name, ...rest] = cookie.trim().split('=');\n const value = rest.join('=');\n if (name && value) {\n cookies[name] = decodeURIComponent(value);\n }\n });\n\n return cookies;\n }\n\n /**\n * Parse request body based on Content-Type\n * \n * \n * @param context - The HTTP server request context\n * @returns Parsed body data and detected body type\n */\n static parseRequestBody<T extends any = any>(\n context: A_HttpServerRequestContext\n ): {\n data: T;\n type: A_Request_BodyType;\n } {\n let parsedBody: any;\n let bodyType: A_Request_BodyType;\n\n switch (true) {\n case !!context.contentType && context.contentType.includes('application/json'):\n parsedBody = JSON.parse(context.data || '{}');\n bodyType = 'json';\n break;\n case !!context.contentType && context.contentType.includes('application/x-www-form-urlencoded'):\n parsedBody = A_RequestHelper.parseFormUrlEncoded(context.data) as T;\n bodyType = 'form';\n break;\n case !!context.contentType && context.contentType.includes('multipart/form-data'):\n const multipartResult = A_RequestHelper.parseMultipartData(Buffer.concat(context.buffers), context.contentType);\n // Return the entire multipart result (fields + files) as T\n parsedBody = {\n ...multipartResult.fields,\n _files: multipartResult.files\n } as T;\n bodyType = 'multipart';\n break;\n case !!context.contentType && context.contentType.includes('text/'):\n parsedBody = context.data as T;\n bodyType = 'text';\n break;\n default:\n parsedBody = Buffer.concat(context.buffers) as T;\n bodyType = 'raw';\n break;\n }\n\n\n return {\n data: parsedBody,\n type: bodyType\n };\n }\n\n /**\n * Parse URL-encoded form data (application/x-www-form-urlencoded)\n * @param body - The URL-encoded body string\n * @returns Object containing form data\n */\n static parseFormUrlEncoded(\n /**\n * The URL-encoded body string\n */\n body: string\n ): Record<string, string | string[]> {\n const result: Record<string, string | string[]> = {};\n\n if (!body) return result;\n\n const pairs = body.split('&');\n\n for (const pair of pairs) {\n if (!pair) continue;\n\n const [key, value = ''] = pair.split('=');\n const decodedKey = decodeURIComponent(key.replace(/\\+/g, ' '));\n const decodedValue = decodeURIComponent(value.replace(/\\+/g, ' '));\n\n // Handle multiple values for the same key (arrays)\n if (decodedKey in result) {\n const existing = result[decodedKey];\n if (Array.isArray(existing)) {\n existing.push(decodedValue);\n } else {\n result[decodedKey] = [existing, decodedValue];\n }\n } else {\n result[decodedKey] = decodedValue;\n }\n }\n\n return result;\n }\n\n /**\n * Parse multipart form data (for file uploads and form data)\n * @param buffer - The raw buffer containing multipart data\n * @param contentType - The content type header\n * @returns Object containing fields and files\n */\n static parseMultipartData(\n /**\n * The raw buffer containing multipart data\n */\n buffer: Buffer,\n /**\n * The content type header\n */\n contentType: string\n ): {\n fields: Record<string, string>;\n files: A_Request_FileUpload[];\n } {\n // Extract boundary\n const boundaryMatch = contentType.match(/boundary=(.+)/);\n if (!boundaryMatch) {\n throw new A_RequestError(\n A_RequestError.RequestBodyParsingError,\n 'Missing boundary in multipart/form-data content type'\n )\n }\n\n const boundary = '--' + boundaryMatch[1];\n const textData = buffer.toString();\n const parts = textData.split(boundary).filter(part => part.trim() && !part.includes('--'));\n\n const fields: Record<string, string> = {};\n const files: A_Request_FileUpload[] = [];\n\n parts.forEach(part => {\n const [headers, content] = part.split('\\r\\n\\r\\n');\n if (!headers || content === undefined) return;\n\n const nameMatch = headers.match(/name=\"([^\"]+)\"/);\n const filenameMatch = headers.match(/filename=\"([^\"]+)\"/);\n const contentTypeMatch = headers.match(/Content-Type: ([^\\r\\n]+)/);\n\n if (nameMatch) {\n const fieldName = nameMatch[1];\n const cleanContent = content.replace(/\\r\\n$/, '');\n\n if (filenameMatch) {\n // It's a file upload\n const file: A_Request_FileUpload = {\n fieldName,\n filename: filenameMatch[1],\n encoding: 'binary',\n mimetype: contentTypeMatch?.[1] || 'application/octet-stream',\n size: Buffer.byteLength(cleanContent),\n buffer: Buffer.from(cleanContent, 'binary')\n };\n files.push(file);\n } else {\n // It's a regular field\n fields[fieldName] = cleanContent;\n }\n }\n });\n\n return { fields, files };\n }\n\n}"]}
@@ -25,12 +25,12 @@ var __decorateClass = (decorators, target, key, kind) => {
25
25
  };
26
26
  var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
27
27
  var _a, _b, _c, _d, _e;
28
- class A_HttpServer extends aService.A_Service {
28
+ const _A_HttpServer = class _A_HttpServer extends aService.A_Service {
29
29
  static get onBeforeRequest() {
30
30
  return (target, propertyKey, descriptor) => {
31
31
  return aConcept.A_Feature.Extend({
32
32
  name: AHttpServer_constants.A_HttpServerFeatures.onBeforeRequest,
33
- scope: [target.constructor]
33
+ scope: [_A_HttpServer]
34
34
  })(target, propertyKey, descriptor);
35
35
  };
36
36
  }
@@ -38,7 +38,7 @@ class A_HttpServer extends aService.A_Service {
38
38
  return (target, propertyKey, descriptor) => {
39
39
  return aConcept.A_Feature.Extend({
40
40
  name: AHttpServer_constants.A_HttpServerFeatures.onRequest,
41
- scope: [target.constructor]
41
+ scope: [_A_HttpServer]
42
42
  })(target, propertyKey, descriptor);
43
43
  };
44
44
  }
@@ -46,7 +46,7 @@ class A_HttpServer extends aService.A_Service {
46
46
  return (target, propertyKey, descriptor) => {
47
47
  return aConcept.A_Feature.Extend({
48
48
  name: AHttpServer_constants.A_HttpServerFeatures.onAfterRequest,
49
- scope: [target.constructor]
49
+ scope: [_A_HttpServer]
50
50
  })(target, propertyKey, descriptor);
51
51
  };
52
52
  }
@@ -188,28 +188,29 @@ class A_HttpServer extends aService.A_Service {
188
188
  }
189
189
  scope.destroy();
190
190
  }
191
- }
191
+ };
192
192
  __decorateClass([
193
193
  aConcept.A_Feature.Extend(),
194
194
  __decorateParam(0, aConcept.A_Dependency.Required()),
195
195
  __decorateParam(0, aConcept.A_Inject(aPolyfill.A_Polyfill)),
196
196
  __decorateParam(1, aConcept.A_Dependency.Required()),
197
197
  __decorateParam(1, aConcept.A_Inject(aConfig.A_Config))
198
- ], A_HttpServer.prototype, _e);
198
+ ], _A_HttpServer.prototype, _e);
199
199
  __decorateClass([
200
200
  aConcept.A_Feature.Extend(),
201
201
  __decorateParam(0, aConcept.A_Inject(aConfig.A_Config)),
202
202
  __decorateParam(1, aConcept.A_Inject(AServerLogger_component.A_ServerLogger))
203
- ], A_HttpServer.prototype, _d);
203
+ ], _A_HttpServer.prototype, _d);
204
204
  __decorateClass([
205
205
  aConcept.A_Feature.Extend()
206
- ], A_HttpServer.prototype, _c);
206
+ ], _A_HttpServer.prototype, _c);
207
207
  __decorateClass([
208
208
  aConcept.A_Feature.Extend()
209
- ], A_HttpServer.prototype, _b);
209
+ ], _A_HttpServer.prototype, _b);
210
210
  __decorateClass([
211
211
  aConcept.A_Feature.Extend()
212
- ], A_HttpServer.prototype, _a);
212
+ ], _A_HttpServer.prototype, _a);
213
+ let A_HttpServer = _A_HttpServer;
213
214
 
214
215
  exports.A_HttpServer = A_HttpServer;
215
216
  //# sourceMappingURL=A-HttpServer.container.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/lib/A-Server/A-HttpServer.container.ts"],"names":["A_Service","A_Feature","A_HttpServerFeatures","A_ServiceFeatures","A_ServerRoute","A_IdentityHelper","A_Request","A_Response","A_HttpServerRequestContext","A_Scope","A_RequestFeatures","A_Error","A_HttpServerError","A_Polyfill","A_Config","A_ServerLogger"],"mappings":"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","file":"A-HttpServer.container.js","sourcesContent":["import type { IncomingMessage, Server, ServerResponse } from \"http\";\nimport { A_HttpServerFeatures } from \"./A-HttpServer.constants\";\nimport { A_Request } from \"@adaas/a-server/request/A-Request.entity\";\nimport { A_Response } from \"@adaas/a-server/response/A-Response.entity\";\nimport { A_TYPES__ServerENVVariables } from \"@adaas/a-server/constants/env.constants\";\nimport { A_Dependency, A_Error, A_Feature, A_IdentityHelper, A_Inject, A_Scope } from \"@adaas/a-concept\";\nimport { A_ServerRoute } from \"@adaas/a-server/route/A-ServerRoute.entity\";\nimport { A_HttpServerRequestMethod } from \"./A-HttpServer.types\";\nimport { A_HttpServerError } from \"./A-HttpServer.error\";\nimport { A_RequestFeatures } from \"@adaas/a-server/request/A-Request.constants\";\nimport { A_HttpServerRequestContext } from \"@adaas/a-server/request/A-HttpServerRequest.context\";\nimport { A_ServerLogger } from \"@adaas/a-server/logger/A-ServerLogger.component\";\nimport { A_Service, A_ServiceFeatures } from \"@adaas/a-utils/a-service\";\nimport { A_Polyfill } from \"@adaas/a-utils/a-polyfill\";\nimport { A_Config } from \"@adaas/a-utils/a-config\";\n\n\n\n\n/**\n * A-Service is a container that can run different types of services, such as HTTP servers, workers, etc.\n * Depending on the provided config and configuration, it will load the necessary components and start the service.\n * \n */\nexport class A_HttpServer extends A_Service {\n\n protected server!: Server;\n\n\n static get onBeforeRequest() {\n return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {\n return A_Feature.Extend({\n name: A_HttpServerFeatures.onBeforeRequest,\n scope: [target.constructor],\n })(target, propertyKey, descriptor);\n }\n }\n\n static get onRequest() {\n return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {\n return A_Feature.Extend({\n name: A_HttpServerFeatures.onRequest,\n scope: [target.constructor],\n })(target, propertyKey, descriptor);\n }\n }\n\n static get onAfterRequest() {\n return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {\n return A_Feature.Extend({\n name: A_HttpServerFeatures.onAfterRequest,\n scope: [target.constructor],\n })(target, propertyKey, descriptor);\n }\n }\n\n\n\n @A_Feature.Extend()\n protected async [A_ServiceFeatures.onStart](\n\n @A_Dependency.Required()\n @A_Inject(A_Polyfill) polyfill: A_Polyfill,\n\n @A_Dependency.Required()\n @A_Inject(A_Config) config: A_Config<A_TYPES__ServerENVVariables>,\n\n ): Promise<void> {\n const http = await polyfill.http();\n\n // Create the HTTP server\n this.server = http.createServer(this.handleRequest.bind(this));\n\n // Start listening on the specified port\n await this.listen(config.get('A_SERVER_PORT'));\n }\n\n @A_Feature.Extend()\n protected async [A_ServiceFeatures.onAfterStart](\n @A_Inject(A_Config) config: A_Config<A_TYPES__ServerENVVariables>,\n @A_Inject(A_ServerLogger) logger: A_ServerLogger,\n ): Promise<void> {\n logger.serverReady({\n port: config.get('A_SERVER_PORT'),\n app: {\n name: this.scope.name,\n }\n });\n }\n\n protected async [A_ServiceFeatures.onStop](...args: any[]): Promise<void> {\n await this.close();\n }\n\n close() {\n return new Promise<void>((resolve, reject) => {\n this.server.close(() => {\n resolve();\n });\n });\n }\n\n listen(port: number) {\n return new Promise<void>((resolve, reject) => {\n this.server.listen(port, () => {\n resolve();\n });\n });\n }\n\n\n // ======================================================================================\n // ============================= A_HttpServer Lifecycle =================================\n // ======================================================================================\n\n @A_Feature.Extend()\n protected async [A_HttpServerFeatures.onBeforeRequest](...args: any[]) { }\n\n @A_Feature.Extend()\n protected async [A_HttpServerFeatures.onRequest](...args: any[]) { }\n\n @A_Feature.Extend()\n protected async [A_HttpServerFeatures.onAfterRequest](...args: any[]) { }\n\n\n // ======================================================================================\n // ============================= A_HttpServer Methods =================================\n // ======================================================================================\n\n async handleRequest(\n request: IncomingMessage,\n response: ServerResponse\n ) {\n const route = new A_ServerRoute(\n request.url || '',\n request.method as A_HttpServerRequestMethod\n );\n\n const id = A_IdentityHelper.generateTimeId();\n const shard = `${request.method}-${route.path.replace('/', '-')}`;\n\n const req = new A_Request({ id, shard, request, scope: this.scope.name });\n const res = new A_Response({ id, shard, response, scope: this.scope.name });\n const context = new A_HttpServerRequestContext(request, response);\n\n const scope = new A_Scope({\n name: id,\n entities: [req, res],\n fragments: [route, context]\n }).inherit(this.scope);\n\n try {\n const onBeforeRequestFeature = new A_Feature({\n name: A_HttpServerFeatures.onBeforeRequest,\n component: this\n });\n\n const onRequestFeature = new A_Feature({\n name: A_HttpServerFeatures.onRequest,\n component: this\n });\n\n const onAfterRequestFeature = new A_Feature({\n name: A_HttpServerFeatures.onAfterRequest,\n component: this\n });\n\n await new Promise<void>(async (resolve, reject) => {\n\n const cleanup = () => {\n onBeforeRequestFeature.interrupt();\n onRequestFeature.interrupt();\n onAfterRequestFeature.interrupt();\n\n req.off(A_RequestFeatures.onError, cleanup);\n req.off(A_RequestFeatures.onClose, cleanup);\n req.off(A_RequestFeatures.onTimeout, cleanup);\n\n\n reject(scope.resolve(A_Error)!);\n }\n\n\n req.on(A_RequestFeatures.onError, cleanup.bind(this));\n req.on(A_RequestFeatures.onClose, cleanup.bind(this));\n\n try {\n await req.load();\n await res.load();\n\n\n await onBeforeRequestFeature.process(scope);\n\n await onRequestFeature.process(scope);\n\n await onAfterRequestFeature.process(scope);\n\n\n req.clearTimeout();\n\n // For SSE streams the controller calls response.sseOpen() which keeps\n // the socket alive; skip the auto-send so we don't close it here.\n if (!res.isStreaming) {\n await res.status(200).send();\n }\n\n resolve();\n } catch (error) {\n\n req.clearTimeout();\n reject(error);\n }\n });\n\n } catch (error) {\n\n let wrappedError;\n\n switch (true) {\n case error instanceof A_HttpServerError:\n wrappedError = error;\n break;\n\n case error instanceof A_Error && error.originalError instanceof A_HttpServerError:\n wrappedError = error.originalError;\n break;\n\n // Duck-type: A_Error (e.g. A_FeatureError) wrapping an HttpError-like original.\n // A_Error.fromConstructor() unwraps nested A_Error chains, so originalError is\n // always the root non-A_Error cause — check it for a numeric statusCode.\n case error instanceof A_Error &&\n error.originalError instanceof Error &&\n typeof (error.originalError as any).statusCode === 'number':\n wrappedError = new A_HttpServerError({\n status: (error.originalError as any).statusCode as number,\n description: (error.originalError as Error).message,\n originalError: error.originalError,\n });\n break;\n\n // Duck-type: any Error with a numeric statusCode property (e.g. http-errors,\n // Express-style errors, or plain project HttpError classes). Honour the\n // status code so the caller gets the right 4xx / 5xx rather than a blanket 500.\n case error instanceof Error && typeof (error as any).statusCode === 'number':\n wrappedError = new A_HttpServerError({\n status: (error as any).statusCode as number,\n description: error.message,\n originalError: error,\n });\n break;\n\n default:\n wrappedError = new A_HttpServerError({\n status: 500,\n description: 'An error occurred while processing the request.',\n originalError: error\n })\n break;\n }\n\n\n scope.register(wrappedError);\n\n await res.fail(wrappedError);\n\n await this.call(A_ServiceFeatures.onError, scope);\n }\n\n scope.destroy();\n }\n\n}\n\n\n\n\n\n\n\n\n"]}
1
+ {"version":3,"sources":["../../../../src/lib/A-Server/A-HttpServer.container.ts"],"names":["A_Service","A_Feature","A_HttpServerFeatures","A_ServiceFeatures","A_ServerRoute","A_IdentityHelper","A_Request","A_Response","A_HttpServerRequestContext","A_Scope","A_RequestFeatures","A_Error","A_HttpServerError","A_Polyfill","A_Config","A_ServerLogger"],"mappings":"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","file":"A-HttpServer.container.js","sourcesContent":["import type { IncomingMessage, Server, ServerResponse } from \"http\";\nimport { A_HttpServerFeatures } from \"./A-HttpServer.constants\";\nimport { A_Request } from \"@adaas/a-server/request/A-Request.entity\";\nimport { A_Response } from \"@adaas/a-server/response/A-Response.entity\";\nimport { A_TYPES__ServerENVVariables } from \"@adaas/a-server/constants/env.constants\";\nimport { A_Dependency, A_Error, A_Feature, A_IdentityHelper, A_Inject, A_Scope } from \"@adaas/a-concept\";\nimport { A_ServerRoute } from \"@adaas/a-server/route/A-ServerRoute.entity\";\nimport { A_HttpServerRequestMethod } from \"./A-HttpServer.types\";\nimport { A_HttpServerError } from \"./A-HttpServer.error\";\nimport { A_RequestFeatures } from \"@adaas/a-server/request/A-Request.constants\";\nimport { A_HttpServerRequestContext } from \"@adaas/a-server/request/A-HttpServerRequest.context\";\nimport { A_ServerLogger } from \"@adaas/a-server/logger/A-ServerLogger.component\";\nimport { A_Service, A_ServiceFeatures } from \"@adaas/a-utils/a-service\";\nimport { A_Polyfill } from \"@adaas/a-utils/a-polyfill\";\nimport { A_Config } from \"@adaas/a-utils/a-config\";\n\n\n\n\n/**\n * A-Service is a container that can run different types of services, such as HTTP servers, workers, etc.\n * Depending on the provided config and configuration, it will load the necessary components and start the service.\n * \n */\nexport class A_HttpServer extends A_Service {\n\n protected server!: Server;\n\n\n static get onBeforeRequest() {\n return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {\n return A_Feature.Extend({\n name: A_HttpServerFeatures.onBeforeRequest,\n scope: [A_HttpServer],\n })(target, propertyKey, descriptor);\n }\n }\n\n static get onRequest() {\n return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {\n return A_Feature.Extend({\n name: A_HttpServerFeatures.onRequest,\n scope: [A_HttpServer],\n })(target, propertyKey, descriptor);\n }\n }\n\n static get onAfterRequest() {\n return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {\n return A_Feature.Extend({\n name: A_HttpServerFeatures.onAfterRequest,\n scope: [A_HttpServer],\n })(target, propertyKey, descriptor);\n }\n }\n\n\n\n @A_Feature.Extend()\n protected async [A_ServiceFeatures.onStart](\n\n @A_Dependency.Required()\n @A_Inject(A_Polyfill) polyfill: A_Polyfill,\n\n @A_Dependency.Required()\n @A_Inject(A_Config) config: A_Config<A_TYPES__ServerENVVariables>,\n\n ): Promise<void> {\n const http = await polyfill.http();\n\n // Create the HTTP server\n this.server = http.createServer(this.handleRequest.bind(this));\n\n // Start listening on the specified port\n await this.listen(config.get('A_SERVER_PORT'));\n }\n\n @A_Feature.Extend()\n protected async [A_ServiceFeatures.onAfterStart](\n @A_Inject(A_Config) config: A_Config<A_TYPES__ServerENVVariables>,\n @A_Inject(A_ServerLogger) logger: A_ServerLogger,\n ): Promise<void> {\n logger.serverReady({\n port: config.get('A_SERVER_PORT'),\n app: {\n name: this.scope.name,\n }\n });\n }\n\n protected async [A_ServiceFeatures.onStop](...args: any[]): Promise<void> {\n await this.close();\n }\n\n close() {\n return new Promise<void>((resolve, reject) => {\n this.server.close(() => {\n resolve();\n });\n });\n }\n\n listen(port: number) {\n return new Promise<void>((resolve, reject) => {\n this.server.listen(port, () => {\n resolve();\n });\n });\n }\n\n\n // ======================================================================================\n // ============================= A_HttpServer Lifecycle =================================\n // ======================================================================================\n\n @A_Feature.Extend()\n protected async [A_HttpServerFeatures.onBeforeRequest](...args: any[]) { }\n\n @A_Feature.Extend()\n protected async [A_HttpServerFeatures.onRequest](...args: any[]) { }\n\n @A_Feature.Extend()\n protected async [A_HttpServerFeatures.onAfterRequest](...args: any[]) { }\n\n\n // ======================================================================================\n // ============================= A_HttpServer Methods =================================\n // ======================================================================================\n\n async handleRequest(\n request: IncomingMessage,\n response: ServerResponse\n ) {\n const route = new A_ServerRoute(\n request.url || '',\n request.method as A_HttpServerRequestMethod\n );\n\n const id = A_IdentityHelper.generateTimeId();\n const shard = `${request.method}-${route.path.replace('/', '-')}`;\n\n const req = new A_Request({ id, shard, request, scope: this.scope.name });\n const res = new A_Response({ id, shard, response, scope: this.scope.name });\n const context = new A_HttpServerRequestContext(request, response);\n\n const scope = new A_Scope({\n name: id,\n entities: [req, res],\n fragments: [route, context]\n }).inherit(this.scope);\n\n try {\n const onBeforeRequestFeature = new A_Feature({\n name: A_HttpServerFeatures.onBeforeRequest,\n component: this\n });\n\n const onRequestFeature = new A_Feature({\n name: A_HttpServerFeatures.onRequest,\n component: this\n });\n\n const onAfterRequestFeature = new A_Feature({\n name: A_HttpServerFeatures.onAfterRequest,\n component: this\n });\n\n await new Promise<void>(async (resolve, reject) => {\n\n const cleanup = () => {\n onBeforeRequestFeature.interrupt();\n onRequestFeature.interrupt();\n onAfterRequestFeature.interrupt();\n\n req.off(A_RequestFeatures.onError, cleanup);\n req.off(A_RequestFeatures.onClose, cleanup);\n req.off(A_RequestFeatures.onTimeout, cleanup);\n\n\n reject(scope.resolve(A_Error)!);\n }\n\n\n req.on(A_RequestFeatures.onError, cleanup.bind(this));\n req.on(A_RequestFeatures.onClose, cleanup.bind(this));\n\n try {\n await req.load();\n await res.load();\n\n\n await onBeforeRequestFeature.process(scope);\n\n await onRequestFeature.process(scope);\n\n await onAfterRequestFeature.process(scope);\n\n\n req.clearTimeout();\n\n // For SSE streams the controller calls response.sseOpen() which keeps\n // the socket alive; skip the auto-send so we don't close it here.\n if (!res.isStreaming) {\n await res.status(200).send();\n }\n\n resolve();\n } catch (error) {\n\n req.clearTimeout();\n reject(error);\n }\n });\n\n } catch (error) {\n\n let wrappedError;\n\n switch (true) {\n case error instanceof A_HttpServerError:\n wrappedError = error;\n break;\n\n case error instanceof A_Error && error.originalError instanceof A_HttpServerError:\n wrappedError = error.originalError;\n break;\n\n // Duck-type: A_Error (e.g. A_FeatureError) wrapping an HttpError-like original.\n // A_Error.fromConstructor() unwraps nested A_Error chains, so originalError is\n // always the root non-A_Error cause — check it for a numeric statusCode.\n case error instanceof A_Error &&\n error.originalError instanceof Error &&\n typeof (error.originalError as any).statusCode === 'number':\n wrappedError = new A_HttpServerError({\n status: (error.originalError as any).statusCode as number,\n description: (error.originalError as Error).message,\n originalError: error.originalError,\n });\n break;\n\n // Duck-type: any Error with a numeric statusCode property (e.g. http-errors,\n // Express-style errors, or plain project HttpError classes). Honour the\n // status code so the caller gets the right 4xx / 5xx rather than a blanket 500.\n case error instanceof Error && typeof (error as any).statusCode === 'number':\n wrappedError = new A_HttpServerError({\n status: (error as any).statusCode as number,\n description: error.message,\n originalError: error,\n });\n break;\n\n default:\n wrappedError = new A_HttpServerError({\n status: 500,\n description: 'An error occurred while processing the request.',\n originalError: error\n })\n break;\n }\n\n\n scope.register(wrappedError);\n\n await res.fail(wrappedError);\n\n await this.call(A_ServiceFeatures.onError, scope);\n }\n\n scope.destroy();\n }\n\n}\n\n\n\n\n\n\n\n\n"]}
@@ -13,12 +13,12 @@ import { A_Polyfill } from '@adaas/a-utils/a-polyfill';
13
13
  import { A_Config } from '@adaas/a-utils/a-config';
14
14
 
15
15
  var _a, _b, _c, _d, _e;
16
- class A_HttpServer extends A_Service {
16
+ const _A_HttpServer = class _A_HttpServer extends A_Service {
17
17
  static get onBeforeRequest() {
18
18
  return (target, propertyKey, descriptor) => {
19
19
  return A_Feature.Extend({
20
20
  name: A_HttpServerFeatures.onBeforeRequest,
21
- scope: [target.constructor]
21
+ scope: [_A_HttpServer]
22
22
  })(target, propertyKey, descriptor);
23
23
  };
24
24
  }
@@ -26,7 +26,7 @@ class A_HttpServer extends A_Service {
26
26
  return (target, propertyKey, descriptor) => {
27
27
  return A_Feature.Extend({
28
28
  name: A_HttpServerFeatures.onRequest,
29
- scope: [target.constructor]
29
+ scope: [_A_HttpServer]
30
30
  })(target, propertyKey, descriptor);
31
31
  };
32
32
  }
@@ -34,7 +34,7 @@ class A_HttpServer extends A_Service {
34
34
  return (target, propertyKey, descriptor) => {
35
35
  return A_Feature.Extend({
36
36
  name: A_HttpServerFeatures.onAfterRequest,
37
- scope: [target.constructor]
37
+ scope: [_A_HttpServer]
38
38
  })(target, propertyKey, descriptor);
39
39
  };
40
40
  }
@@ -176,28 +176,29 @@ class A_HttpServer extends A_Service {
176
176
  }
177
177
  scope.destroy();
178
178
  }
179
- }
179
+ };
180
180
  __decorateClass([
181
181
  A_Feature.Extend(),
182
182
  __decorateParam(0, A_Dependency.Required()),
183
183
  __decorateParam(0, A_Inject(A_Polyfill)),
184
184
  __decorateParam(1, A_Dependency.Required()),
185
185
  __decorateParam(1, A_Inject(A_Config))
186
- ], A_HttpServer.prototype, _e, 1);
186
+ ], _A_HttpServer.prototype, _e, 1);
187
187
  __decorateClass([
188
188
  A_Feature.Extend(),
189
189
  __decorateParam(0, A_Inject(A_Config)),
190
190
  __decorateParam(1, A_Inject(A_ServerLogger))
191
- ], A_HttpServer.prototype, _d, 1);
191
+ ], _A_HttpServer.prototype, _d, 1);
192
192
  __decorateClass([
193
193
  A_Feature.Extend()
194
- ], A_HttpServer.prototype, _c, 1);
194
+ ], _A_HttpServer.prototype, _c, 1);
195
195
  __decorateClass([
196
196
  A_Feature.Extend()
197
- ], A_HttpServer.prototype, _b, 1);
197
+ ], _A_HttpServer.prototype, _b, 1);
198
198
  __decorateClass([
199
199
  A_Feature.Extend()
200
- ], A_HttpServer.prototype, _a, 1);
200
+ ], _A_HttpServer.prototype, _a, 1);
201
+ let A_HttpServer = _A_HttpServer;
201
202
 
202
203
  export { A_HttpServer };
203
204
  //# sourceMappingURL=A-HttpServer.container.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/lib/A-Server/A-HttpServer.container.ts"],"names":[],"mappings":"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","file":"A-HttpServer.container.mjs","sourcesContent":["import type { IncomingMessage, Server, ServerResponse } from \"http\";\nimport { A_HttpServerFeatures } from \"./A-HttpServer.constants\";\nimport { A_Request } from \"@adaas/a-server/request/A-Request.entity\";\nimport { A_Response } from \"@adaas/a-server/response/A-Response.entity\";\nimport { A_TYPES__ServerENVVariables } from \"@adaas/a-server/constants/env.constants\";\nimport { A_Dependency, A_Error, A_Feature, A_IdentityHelper, A_Inject, A_Scope } from \"@adaas/a-concept\";\nimport { A_ServerRoute } from \"@adaas/a-server/route/A-ServerRoute.entity\";\nimport { A_HttpServerRequestMethod } from \"./A-HttpServer.types\";\nimport { A_HttpServerError } from \"./A-HttpServer.error\";\nimport { A_RequestFeatures } from \"@adaas/a-server/request/A-Request.constants\";\nimport { A_HttpServerRequestContext } from \"@adaas/a-server/request/A-HttpServerRequest.context\";\nimport { A_ServerLogger } from \"@adaas/a-server/logger/A-ServerLogger.component\";\nimport { A_Service, A_ServiceFeatures } from \"@adaas/a-utils/a-service\";\nimport { A_Polyfill } from \"@adaas/a-utils/a-polyfill\";\nimport { A_Config } from \"@adaas/a-utils/a-config\";\n\n\n\n\n/**\n * A-Service is a container that can run different types of services, such as HTTP servers, workers, etc.\n * Depending on the provided config and configuration, it will load the necessary components and start the service.\n * \n */\nexport class A_HttpServer extends A_Service {\n\n protected server!: Server;\n\n\n static get onBeforeRequest() {\n return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {\n return A_Feature.Extend({\n name: A_HttpServerFeatures.onBeforeRequest,\n scope: [target.constructor],\n })(target, propertyKey, descriptor);\n }\n }\n\n static get onRequest() {\n return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {\n return A_Feature.Extend({\n name: A_HttpServerFeatures.onRequest,\n scope: [target.constructor],\n })(target, propertyKey, descriptor);\n }\n }\n\n static get onAfterRequest() {\n return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {\n return A_Feature.Extend({\n name: A_HttpServerFeatures.onAfterRequest,\n scope: [target.constructor],\n })(target, propertyKey, descriptor);\n }\n }\n\n\n\n @A_Feature.Extend()\n protected async [A_ServiceFeatures.onStart](\n\n @A_Dependency.Required()\n @A_Inject(A_Polyfill) polyfill: A_Polyfill,\n\n @A_Dependency.Required()\n @A_Inject(A_Config) config: A_Config<A_TYPES__ServerENVVariables>,\n\n ): Promise<void> {\n const http = await polyfill.http();\n\n // Create the HTTP server\n this.server = http.createServer(this.handleRequest.bind(this));\n\n // Start listening on the specified port\n await this.listen(config.get('A_SERVER_PORT'));\n }\n\n @A_Feature.Extend()\n protected async [A_ServiceFeatures.onAfterStart](\n @A_Inject(A_Config) config: A_Config<A_TYPES__ServerENVVariables>,\n @A_Inject(A_ServerLogger) logger: A_ServerLogger,\n ): Promise<void> {\n logger.serverReady({\n port: config.get('A_SERVER_PORT'),\n app: {\n name: this.scope.name,\n }\n });\n }\n\n protected async [A_ServiceFeatures.onStop](...args: any[]): Promise<void> {\n await this.close();\n }\n\n close() {\n return new Promise<void>((resolve, reject) => {\n this.server.close(() => {\n resolve();\n });\n });\n }\n\n listen(port: number) {\n return new Promise<void>((resolve, reject) => {\n this.server.listen(port, () => {\n resolve();\n });\n });\n }\n\n\n // ======================================================================================\n // ============================= A_HttpServer Lifecycle =================================\n // ======================================================================================\n\n @A_Feature.Extend()\n protected async [A_HttpServerFeatures.onBeforeRequest](...args: any[]) { }\n\n @A_Feature.Extend()\n protected async [A_HttpServerFeatures.onRequest](...args: any[]) { }\n\n @A_Feature.Extend()\n protected async [A_HttpServerFeatures.onAfterRequest](...args: any[]) { }\n\n\n // ======================================================================================\n // ============================= A_HttpServer Methods =================================\n // ======================================================================================\n\n async handleRequest(\n request: IncomingMessage,\n response: ServerResponse\n ) {\n const route = new A_ServerRoute(\n request.url || '',\n request.method as A_HttpServerRequestMethod\n );\n\n const id = A_IdentityHelper.generateTimeId();\n const shard = `${request.method}-${route.path.replace('/', '-')}`;\n\n const req = new A_Request({ id, shard, request, scope: this.scope.name });\n const res = new A_Response({ id, shard, response, scope: this.scope.name });\n const context = new A_HttpServerRequestContext(request, response);\n\n const scope = new A_Scope({\n name: id,\n entities: [req, res],\n fragments: [route, context]\n }).inherit(this.scope);\n\n try {\n const onBeforeRequestFeature = new A_Feature({\n name: A_HttpServerFeatures.onBeforeRequest,\n component: this\n });\n\n const onRequestFeature = new A_Feature({\n name: A_HttpServerFeatures.onRequest,\n component: this\n });\n\n const onAfterRequestFeature = new A_Feature({\n name: A_HttpServerFeatures.onAfterRequest,\n component: this\n });\n\n await new Promise<void>(async (resolve, reject) => {\n\n const cleanup = () => {\n onBeforeRequestFeature.interrupt();\n onRequestFeature.interrupt();\n onAfterRequestFeature.interrupt();\n\n req.off(A_RequestFeatures.onError, cleanup);\n req.off(A_RequestFeatures.onClose, cleanup);\n req.off(A_RequestFeatures.onTimeout, cleanup);\n\n\n reject(scope.resolve(A_Error)!);\n }\n\n\n req.on(A_RequestFeatures.onError, cleanup.bind(this));\n req.on(A_RequestFeatures.onClose, cleanup.bind(this));\n\n try {\n await req.load();\n await res.load();\n\n\n await onBeforeRequestFeature.process(scope);\n\n await onRequestFeature.process(scope);\n\n await onAfterRequestFeature.process(scope);\n\n\n req.clearTimeout();\n\n // For SSE streams the controller calls response.sseOpen() which keeps\n // the socket alive; skip the auto-send so we don't close it here.\n if (!res.isStreaming) {\n await res.status(200).send();\n }\n\n resolve();\n } catch (error) {\n\n req.clearTimeout();\n reject(error);\n }\n });\n\n } catch (error) {\n\n let wrappedError;\n\n switch (true) {\n case error instanceof A_HttpServerError:\n wrappedError = error;\n break;\n\n case error instanceof A_Error && error.originalError instanceof A_HttpServerError:\n wrappedError = error.originalError;\n break;\n\n // Duck-type: A_Error (e.g. A_FeatureError) wrapping an HttpError-like original.\n // A_Error.fromConstructor() unwraps nested A_Error chains, so originalError is\n // always the root non-A_Error cause — check it for a numeric statusCode.\n case error instanceof A_Error &&\n error.originalError instanceof Error &&\n typeof (error.originalError as any).statusCode === 'number':\n wrappedError = new A_HttpServerError({\n status: (error.originalError as any).statusCode as number,\n description: (error.originalError as Error).message,\n originalError: error.originalError,\n });\n break;\n\n // Duck-type: any Error with a numeric statusCode property (e.g. http-errors,\n // Express-style errors, or plain project HttpError classes). Honour the\n // status code so the caller gets the right 4xx / 5xx rather than a blanket 500.\n case error instanceof Error && typeof (error as any).statusCode === 'number':\n wrappedError = new A_HttpServerError({\n status: (error as any).statusCode as number,\n description: error.message,\n originalError: error,\n });\n break;\n\n default:\n wrappedError = new A_HttpServerError({\n status: 500,\n description: 'An error occurred while processing the request.',\n originalError: error\n })\n break;\n }\n\n\n scope.register(wrappedError);\n\n await res.fail(wrappedError);\n\n await this.call(A_ServiceFeatures.onError, scope);\n }\n\n scope.destroy();\n }\n\n}\n\n\n\n\n\n\n\n\n"]}
1
+ {"version":3,"sources":["../../../../src/lib/A-Server/A-HttpServer.container.ts"],"names":[],"mappings":"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","file":"A-HttpServer.container.mjs","sourcesContent":["import type { IncomingMessage, Server, ServerResponse } from \"http\";\nimport { A_HttpServerFeatures } from \"./A-HttpServer.constants\";\nimport { A_Request } from \"@adaas/a-server/request/A-Request.entity\";\nimport { A_Response } from \"@adaas/a-server/response/A-Response.entity\";\nimport { A_TYPES__ServerENVVariables } from \"@adaas/a-server/constants/env.constants\";\nimport { A_Dependency, A_Error, A_Feature, A_IdentityHelper, A_Inject, A_Scope } from \"@adaas/a-concept\";\nimport { A_ServerRoute } from \"@adaas/a-server/route/A-ServerRoute.entity\";\nimport { A_HttpServerRequestMethod } from \"./A-HttpServer.types\";\nimport { A_HttpServerError } from \"./A-HttpServer.error\";\nimport { A_RequestFeatures } from \"@adaas/a-server/request/A-Request.constants\";\nimport { A_HttpServerRequestContext } from \"@adaas/a-server/request/A-HttpServerRequest.context\";\nimport { A_ServerLogger } from \"@adaas/a-server/logger/A-ServerLogger.component\";\nimport { A_Service, A_ServiceFeatures } from \"@adaas/a-utils/a-service\";\nimport { A_Polyfill } from \"@adaas/a-utils/a-polyfill\";\nimport { A_Config } from \"@adaas/a-utils/a-config\";\n\n\n\n\n/**\n * A-Service is a container that can run different types of services, such as HTTP servers, workers, etc.\n * Depending on the provided config and configuration, it will load the necessary components and start the service.\n * \n */\nexport class A_HttpServer extends A_Service {\n\n protected server!: Server;\n\n\n static get onBeforeRequest() {\n return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {\n return A_Feature.Extend({\n name: A_HttpServerFeatures.onBeforeRequest,\n scope: [A_HttpServer],\n })(target, propertyKey, descriptor);\n }\n }\n\n static get onRequest() {\n return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {\n return A_Feature.Extend({\n name: A_HttpServerFeatures.onRequest,\n scope: [A_HttpServer],\n })(target, propertyKey, descriptor);\n }\n }\n\n static get onAfterRequest() {\n return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {\n return A_Feature.Extend({\n name: A_HttpServerFeatures.onAfterRequest,\n scope: [A_HttpServer],\n })(target, propertyKey, descriptor);\n }\n }\n\n\n\n @A_Feature.Extend()\n protected async [A_ServiceFeatures.onStart](\n\n @A_Dependency.Required()\n @A_Inject(A_Polyfill) polyfill: A_Polyfill,\n\n @A_Dependency.Required()\n @A_Inject(A_Config) config: A_Config<A_TYPES__ServerENVVariables>,\n\n ): Promise<void> {\n const http = await polyfill.http();\n\n // Create the HTTP server\n this.server = http.createServer(this.handleRequest.bind(this));\n\n // Start listening on the specified port\n await this.listen(config.get('A_SERVER_PORT'));\n }\n\n @A_Feature.Extend()\n protected async [A_ServiceFeatures.onAfterStart](\n @A_Inject(A_Config) config: A_Config<A_TYPES__ServerENVVariables>,\n @A_Inject(A_ServerLogger) logger: A_ServerLogger,\n ): Promise<void> {\n logger.serverReady({\n port: config.get('A_SERVER_PORT'),\n app: {\n name: this.scope.name,\n }\n });\n }\n\n protected async [A_ServiceFeatures.onStop](...args: any[]): Promise<void> {\n await this.close();\n }\n\n close() {\n return new Promise<void>((resolve, reject) => {\n this.server.close(() => {\n resolve();\n });\n });\n }\n\n listen(port: number) {\n return new Promise<void>((resolve, reject) => {\n this.server.listen(port, () => {\n resolve();\n });\n });\n }\n\n\n // ======================================================================================\n // ============================= A_HttpServer Lifecycle =================================\n // ======================================================================================\n\n @A_Feature.Extend()\n protected async [A_HttpServerFeatures.onBeforeRequest](...args: any[]) { }\n\n @A_Feature.Extend()\n protected async [A_HttpServerFeatures.onRequest](...args: any[]) { }\n\n @A_Feature.Extend()\n protected async [A_HttpServerFeatures.onAfterRequest](...args: any[]) { }\n\n\n // ======================================================================================\n // ============================= A_HttpServer Methods =================================\n // ======================================================================================\n\n async handleRequest(\n request: IncomingMessage,\n response: ServerResponse\n ) {\n const route = new A_ServerRoute(\n request.url || '',\n request.method as A_HttpServerRequestMethod\n );\n\n const id = A_IdentityHelper.generateTimeId();\n const shard = `${request.method}-${route.path.replace('/', '-')}`;\n\n const req = new A_Request({ id, shard, request, scope: this.scope.name });\n const res = new A_Response({ id, shard, response, scope: this.scope.name });\n const context = new A_HttpServerRequestContext(request, response);\n\n const scope = new A_Scope({\n name: id,\n entities: [req, res],\n fragments: [route, context]\n }).inherit(this.scope);\n\n try {\n const onBeforeRequestFeature = new A_Feature({\n name: A_HttpServerFeatures.onBeforeRequest,\n component: this\n });\n\n const onRequestFeature = new A_Feature({\n name: A_HttpServerFeatures.onRequest,\n component: this\n });\n\n const onAfterRequestFeature = new A_Feature({\n name: A_HttpServerFeatures.onAfterRequest,\n component: this\n });\n\n await new Promise<void>(async (resolve, reject) => {\n\n const cleanup = () => {\n onBeforeRequestFeature.interrupt();\n onRequestFeature.interrupt();\n onAfterRequestFeature.interrupt();\n\n req.off(A_RequestFeatures.onError, cleanup);\n req.off(A_RequestFeatures.onClose, cleanup);\n req.off(A_RequestFeatures.onTimeout, cleanup);\n\n\n reject(scope.resolve(A_Error)!);\n }\n\n\n req.on(A_RequestFeatures.onError, cleanup.bind(this));\n req.on(A_RequestFeatures.onClose, cleanup.bind(this));\n\n try {\n await req.load();\n await res.load();\n\n\n await onBeforeRequestFeature.process(scope);\n\n await onRequestFeature.process(scope);\n\n await onAfterRequestFeature.process(scope);\n\n\n req.clearTimeout();\n\n // For SSE streams the controller calls response.sseOpen() which keeps\n // the socket alive; skip the auto-send so we don't close it here.\n if (!res.isStreaming) {\n await res.status(200).send();\n }\n\n resolve();\n } catch (error) {\n\n req.clearTimeout();\n reject(error);\n }\n });\n\n } catch (error) {\n\n let wrappedError;\n\n switch (true) {\n case error instanceof A_HttpServerError:\n wrappedError = error;\n break;\n\n case error instanceof A_Error && error.originalError instanceof A_HttpServerError:\n wrappedError = error.originalError;\n break;\n\n // Duck-type: A_Error (e.g. A_FeatureError) wrapping an HttpError-like original.\n // A_Error.fromConstructor() unwraps nested A_Error chains, so originalError is\n // always the root non-A_Error cause — check it for a numeric statusCode.\n case error instanceof A_Error &&\n error.originalError instanceof Error &&\n typeof (error.originalError as any).statusCode === 'number':\n wrappedError = new A_HttpServerError({\n status: (error.originalError as any).statusCode as number,\n description: (error.originalError as Error).message,\n originalError: error.originalError,\n });\n break;\n\n // Duck-type: any Error with a numeric statusCode property (e.g. http-errors,\n // Express-style errors, or plain project HttpError classes). Honour the\n // status code so the caller gets the right 4xx / 5xx rather than a blanket 500.\n case error instanceof Error && typeof (error as any).statusCode === 'number':\n wrappedError = new A_HttpServerError({\n status: (error as any).statusCode as number,\n description: error.message,\n originalError: error,\n });\n break;\n\n default:\n wrappedError = new A_HttpServerError({\n status: 500,\n description: 'An error occurred while processing the request.',\n originalError: error\n })\n break;\n }\n\n\n scope.register(wrappedError);\n\n await res.fail(wrappedError);\n\n await this.call(A_ServiceFeatures.onError, scope);\n }\n\n scope.destroy();\n }\n\n}\n\n\n\n\n\n\n\n\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adaas/a-server",
3
- "version": "0.0.27",
3
+ "version": "0.0.29",
4
4
  "description": "A-Server is a powerful server framework designed to work seamlessly with the A-Concept framework. This library provides a robust and flexible server implementation of A-Server, enabling developers to create scalable and efficient server-side applications using the A-Concept architecture.",
5
5
  "keywords": [
6
6
  "adaas",
@@ -132,7 +132,7 @@ export class A_RequestHelper {
132
132
 
133
133
  switch (true) {
134
134
  case !!context.contentType && context.contentType.includes('application/json'):
135
- parsedBody = JSON.parse(context.data);
135
+ parsedBody = JSON.parse(context.data || '{}');
136
136
  bodyType = 'json';
137
137
  break;
138
138
  case !!context.contentType && context.contentType.includes('application/x-www-form-urlencoded'):
@@ -31,7 +31,7 @@ export class A_HttpServer extends A_Service {
31
31
  return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
32
32
  return A_Feature.Extend({
33
33
  name: A_HttpServerFeatures.onBeforeRequest,
34
- scope: [target.constructor],
34
+ scope: [A_HttpServer],
35
35
  })(target, propertyKey, descriptor);
36
36
  }
37
37
  }
@@ -40,7 +40,7 @@ export class A_HttpServer extends A_Service {
40
40
  return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
41
41
  return A_Feature.Extend({
42
42
  name: A_HttpServerFeatures.onRequest,
43
- scope: [target.constructor],
43
+ scope: [A_HttpServer],
44
44
  })(target, propertyKey, descriptor);
45
45
  }
46
46
  }
@@ -49,7 +49,7 @@ export class A_HttpServer extends A_Service {
49
49
  return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
50
50
  return A_Feature.Extend({
51
51
  name: A_HttpServerFeatures.onAfterRequest,
52
- scope: [target.constructor],
52
+ scope: [A_HttpServer],
53
53
  })(target, propertyKey, descriptor);
54
54
  }
55
55
  }