exlo 0.0.1

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.
Files changed (151) hide show
  1. package/dist/cli.d.ts +2 -0
  2. package/dist/cli.mjs +11 -0
  3. package/dist/config.d.ts +35 -0
  4. package/dist/defineConfig.d.ts +125 -0
  5. package/dist/defineConfig.mjs +1 -0
  6. package/dist/lib/esbuild/buildOptimizer.d.ts +9 -0
  7. package/dist/lib/esbuild/knownCjs.d.ts +1 -0
  8. package/dist/lib/esbuild/mergeEsbuildConfig.d.ts +2 -0
  9. package/dist/lib/esbuild/parseCustomEsbuild.d.ts +2 -0
  10. package/dist/lib/parseEvents/ddbStream.d.ts +17 -0
  11. package/dist/lib/parseEvents/endpoints.d.ts +29 -0
  12. package/dist/lib/parseEvents/funcUrl.d.ts +2 -0
  13. package/dist/lib/parseEvents/index.d.ts +16 -0
  14. package/dist/lib/parseEvents/sqs.d.ts +11 -0
  15. package/dist/lib/runtime/bufferedStreamResponse.d.ts +24 -0
  16. package/dist/lib/runtime/callDestinations.d.ts +12 -0
  17. package/dist/lib/runtime/eventSourceMapping/base.d.ts +66 -0
  18. package/dist/lib/runtime/eventSourceMapping/base.mjs +1 -0
  19. package/dist/lib/runtime/eventSourceMapping/errors/eventSourceMappingError.d.ts +5 -0
  20. package/dist/lib/runtime/eventSourceMapping/esmBatch.d.ts +15 -0
  21. package/dist/lib/runtime/eventSourceMapping/filter/compileFilterPolicy.d.ts +12 -0
  22. package/dist/lib/runtime/eventSourceMapping/filter/compileFilterPolicy.test.d.ts +1 -0
  23. package/dist/lib/runtime/eventSourceMapping/filter/compileWildcard.d.ts +1 -0
  24. package/dist/lib/runtime/eventSourceMapping/filter/compileWildcard.test.d.ts +1 -0
  25. package/dist/lib/runtime/eventSourceMapping/filter/expandDotPathsWithStrictConflicts.d.ts +1 -0
  26. package/dist/lib/runtime/eventSourceMapping/filter/expandDotPathsWithStrictConflicts.test.d.ts +1 -0
  27. package/dist/lib/runtime/eventSourceMapping/filter/matchesFilterPolicy.d.ts +2 -0
  28. package/dist/lib/runtime/eventSourceMapping/filter/matchesFilterPolicy.test.d.ts +1 -0
  29. package/dist/lib/runtime/eventSourceMapping/sqs.d.ts +19 -0
  30. package/dist/lib/runtime/eventSourceMapping/utils.d.ts +6 -0
  31. package/dist/lib/runtime/rapidApi.d.ts +97 -0
  32. package/dist/lib/runtime/runners/index.d.ts +25 -0
  33. package/dist/lib/runtime/runners/node/awslambda.d.ts +11 -0
  34. package/dist/lib/runtime/runners/node/index.d.ts +1 -0
  35. package/dist/lib/runtime/runners/node/index.js +19 -0
  36. package/dist/lib/runtime/runners/node/runner.d.ts +34 -0
  37. package/dist/lib/runtime/runners/node/streamResponse.d.ts +90 -0
  38. package/dist/lib/runtime/runners/node/utils.d.ts +39 -0
  39. package/dist/lib/runtime/runners/python/runner.d.ts +48 -0
  40. package/dist/lib/runtime/runners/ruby/runner.d.ts +43 -0
  41. package/dist/lib/server/daemon.d.ts +27 -0
  42. package/dist/lib/server/handlers.d.ts +13 -0
  43. package/dist/lib/services/index.d.ts +10 -0
  44. package/dist/lib/utils/amazonifyHeaders.d.ts +3 -0
  45. package/dist/lib/utils/colorize.d.ts +12 -0
  46. package/dist/lib/utils/getPackageInstalledDir.d.ts +1 -0
  47. package/dist/lib/utils/readDefineConfig.d.ts +6 -0
  48. package/dist/main.d.ts +80 -0
  49. package/dist/plugins/lambda/events/alb.d.ts +44 -0
  50. package/dist/plugins/lambda/events/apg.d.ts +111 -0
  51. package/dist/plugins/lambda/events/common.d.ts +114 -0
  52. package/dist/plugins/lambda/functionUrlInvoke.d.ts +3 -0
  53. package/dist/plugins/lambda/htmlStatusMsg.d.ts +4 -0
  54. package/dist/plugins/lambda/index.d.ts +3 -0
  55. package/dist/plugins/lambda/invokeRequests.d.ts +3 -0
  56. package/dist/plugins/lambda/lambdaApi.d.ts +6 -0
  57. package/dist/plugins/lambda/responseStreamingInvoke.d.ts +3 -0
  58. package/dist/plugins/lambda/streamEncoder.d.ts +19 -0
  59. package/dist/plugins/lambda/utils.d.ts +29 -0
  60. package/dist/plugins/restApi/compileAjvSchema.d.ts +1 -0
  61. package/dist/plugins/restApi/errors.d.ts +32 -0
  62. package/dist/plugins/restApi/findRequestResource.d.ts +9 -0
  63. package/dist/plugins/restApi/findRequestResource.test.d.ts +1 -0
  64. package/dist/plugins/restApi/index.d.ts +8 -0
  65. package/dist/plugins/restApi/index.mjs +1 -0
  66. package/dist/plugins/restApi/resourcesFromOpenApi.d.ts +4 -0
  67. package/dist/plugins/restApi/restApiServer.d.ts +265 -0
  68. package/dist/plugins/restApi/restApiServer.test.d.ts +1 -0
  69. package/dist/plugins/restApi/utils.d.ts +9 -0
  70. package/dist/plugins/s3/actions/AbortMultipartUploadAction.d.ts +10 -0
  71. package/dist/plugins/s3/actions/CompleteMultipartUploadAction.d.ts +15 -0
  72. package/dist/plugins/s3/actions/CopyObjectAction.d.ts +24 -0
  73. package/dist/plugins/s3/actions/CreateBucketAction.d.ts +8 -0
  74. package/dist/plugins/s3/actions/CreateMultipartUploadAction.d.ts +13 -0
  75. package/dist/plugins/s3/actions/DeleteBucketAction.d.ts +8 -0
  76. package/dist/plugins/s3/actions/DeleteBucketPolicyAction.d.ts +8 -0
  77. package/dist/plugins/s3/actions/DeleteBucketTaggingAction.d.ts +8 -0
  78. package/dist/plugins/s3/actions/DeleteObjectAction.d.ts +10 -0
  79. package/dist/plugins/s3/actions/DeleteObjectTaggingAction.d.ts +9 -0
  80. package/dist/plugins/s3/actions/DeleteObjectsAction.d.ts +8 -0
  81. package/dist/plugins/s3/actions/GetBucketAclAction.d.ts +8 -0
  82. package/dist/plugins/s3/actions/GetBucketPolicy.d.ts +8 -0
  83. package/dist/plugins/s3/actions/GetBucketTaggingAction.d.ts +8 -0
  84. package/dist/plugins/s3/actions/GetObjectAclAction.d.ts +8 -0
  85. package/dist/plugins/s3/actions/GetObjectAction.d.ts +30 -0
  86. package/dist/plugins/s3/actions/GetObjectTaggingAction.d.ts +10 -0
  87. package/dist/plugins/s3/actions/HeadBucketAction.d.ts +8 -0
  88. package/dist/plugins/s3/actions/HeadObjectAction.d.ts +18 -0
  89. package/dist/plugins/s3/actions/ListBucketsAction.d.ts +15 -0
  90. package/dist/plugins/s3/actions/ListMultipartUploadsAction.d.ts +19 -0
  91. package/dist/plugins/s3/actions/ListObjectsAction.d.ts +31 -0
  92. package/dist/plugins/s3/actions/ListPartsAction.d.ts +14 -0
  93. package/dist/plugins/s3/actions/PutBucketAclAction.d.ts +11 -0
  94. package/dist/plugins/s3/actions/PutBucketCorsAction.d.ts +8 -0
  95. package/dist/plugins/s3/actions/PutBucketPolicyAction.d.ts +9 -0
  96. package/dist/plugins/s3/actions/PutBucketTaggingAction.d.ts +8 -0
  97. package/dist/plugins/s3/actions/PutObjectAclAction.d.ts +8 -0
  98. package/dist/plugins/s3/actions/PutObjectAction.d.ts +22 -0
  99. package/dist/plugins/s3/actions/PutObjectTaggingAction.d.ts +9 -0
  100. package/dist/plugins/s3/actions/UnknownAction.d.ts +7 -0
  101. package/dist/plugins/s3/actions/UploadPartAction.d.ts +12 -0
  102. package/dist/plugins/s3/actions/localAction.d.ts +92 -0
  103. package/dist/plugins/s3/calulcateETag.d.ts +1 -0
  104. package/dist/plugins/s3/commons/constants.d.ts +6 -0
  105. package/dist/plugins/s3/commons/utils.d.ts +3 -0
  106. package/dist/plugins/s3/errors/notFound.d.ts +8 -0
  107. package/dist/plugins/s3/errors/s3Error.d.ts +65 -0
  108. package/dist/plugins/s3/getLocalStoragePath.d.ts +1 -0
  109. package/dist/plugins/s3/index.d.ts +32 -0
  110. package/dist/plugins/s3/index.mjs +97 -0
  111. package/dist/plugins/s3/lib/createS3Server.d.ts +38 -0
  112. package/dist/plugins/s3/parsers/parseDeleteRequest.d.ts +10 -0
  113. package/dist/plugins/s3/parsers/parseGetRequest.d.ts +14 -0
  114. package/dist/plugins/s3/parsers/parseHeadRequest.d.ts +5 -0
  115. package/dist/plugins/s3/parsers/parsePostRequest.d.ts +7 -0
  116. package/dist/plugins/s3/parsers/parsePutRequest.d.ts +14 -0
  117. package/dist/plugins/s3/triggerEvent.d.ts +12 -0
  118. package/dist/plugins/sns/errors.d.ts +26 -0
  119. package/dist/plugins/sns/filter.d.ts +1 -0
  120. package/dist/plugins/sns/filter.test.d.ts +1 -0
  121. package/dist/plugins/sns/index.d.ts +23 -0
  122. package/dist/plugins/sns/index.mjs +106 -0
  123. package/dist/plugins/sns/parsers/parseCreateTopic.d.ts +2 -0
  124. package/dist/plugins/sns/parsers/parseMessage.d.ts +18 -0
  125. package/dist/plugins/sns/parsers/parsePublishMessage.d.ts +6 -0
  126. package/dist/plugins/sns/parsers/parsePublishMessageBatch.d.ts +9 -0
  127. package/dist/plugins/sns/parsers/parseSubscribe.d.ts +17 -0
  128. package/dist/plugins/sns/parsers/parseSubscriptionArn.d.ts +6 -0
  129. package/dist/plugins/sns/parsers/parseTopicArn.d.ts +4 -0
  130. package/dist/plugins/sns/server.d.ts +36 -0
  131. package/dist/plugins/sns/server.test.d.ts +1 -0
  132. package/dist/plugins/sns/subscriber/index.d.ts +61 -0
  133. package/dist/plugins/sns/subscriber/validateConfig.d.ts +0 -0
  134. package/dist/plugins/sns/topic.d.ts +91 -0
  135. package/dist/plugins/sns/utils.d.ts +20 -0
  136. package/dist/plugins/sns/validateFilterPolicy.d.ts +19 -0
  137. package/dist/plugins/sns/validateFilterPolicy.test.d.ts +1 -0
  138. package/dist/plugins/sqs/index.d.ts +16 -0
  139. package/dist/plugins/sqs/index.mjs +1 -0
  140. package/dist/plugins/sqs/types.d.ts +11 -0
  141. package/dist/plugins/sqs/utils.d.ts +7 -0
  142. package/dist/plugins/vitest/coverage.d.ts +6 -0
  143. package/dist/plugins/vitest/index.d.ts +29 -0
  144. package/dist/plugins/vitest/index.mjs +1 -0
  145. package/dist/standalone.d.ts +17 -0
  146. package/dist/standalone.js +13 -0
  147. package/dist/standalone.mjs +13 -0
  148. package/dist/standalone_types.d.ts +190 -0
  149. package/package.json +119 -0
  150. package/src/lib/runtime/runners/python/index.py +105 -0
  151. package/src/lib/runtime/runners/ruby/index.rb +67 -0
@@ -0,0 +1,114 @@
1
+ import type { IncomingHttpHeaders, IncomingMessage } from "node:http";
2
+ import type { LambdaEndpoint } from "../../../lib/parseEvents/endpoints";
3
+ export type normalizedSearchParams = {
4
+ toString: () => string;
5
+ } & {
6
+ [key: string]: string[] | undefined;
7
+ };
8
+ export declare class CommonEventGenerator {
9
+ static apiId: string;
10
+ static accountId: string;
11
+ static port: number;
12
+ static serve: any;
13
+ static contentType: {
14
+ json: string;
15
+ text: string;
16
+ octet: string;
17
+ };
18
+ static keepAlive: string[];
19
+ static dummyHost: string;
20
+ static httpErrMsg: string;
21
+ static apigJsonParseErrMsg: string;
22
+ static apigForbiddenErrMsg: string;
23
+ static amzMsgNull: string;
24
+ static apgTimeoutMsg: string;
25
+ static unavailable: string;
26
+ static timeoutRegex: RegExp;
27
+ static apgRequestTimeout: number;
28
+ static normalizeHeaderKey: (key: string) => string;
29
+ static getMultiValueHeaders: (rawHeaders: string[]) => any;
30
+ static getIsBase64Encoded: (headers: IncomingHttpHeaders) => boolean;
31
+ static knownHeaders: string[];
32
+ static getApiGV1Headers(req: IncomingMessage, mockEvent: LambdaEndpoint): {
33
+ headers: any;
34
+ multiValueHeaders: Record<string, any[]>;
35
+ apiKey: string | undefined;
36
+ };
37
+ static getCustomHeaders(req: IncomingMessage, mockEvent: LambdaEndpoint): {
38
+ accept?: string | undefined;
39
+ "accept-encoding"?: string | undefined;
40
+ "accept-language"?: string | undefined;
41
+ "accept-patch"?: string | undefined;
42
+ "accept-ranges"?: string | undefined;
43
+ "access-control-allow-credentials"?: string | undefined;
44
+ "access-control-allow-headers"?: string | undefined;
45
+ "access-control-allow-methods"?: string | undefined;
46
+ "access-control-allow-origin"?: string | undefined;
47
+ "access-control-expose-headers"?: string | undefined;
48
+ "access-control-max-age"?: string | undefined;
49
+ "access-control-request-headers"?: string | undefined;
50
+ "access-control-request-method"?: string | undefined;
51
+ age?: string | undefined;
52
+ allow?: string | undefined;
53
+ "alt-svc"?: string | undefined;
54
+ authorization?: string | undefined;
55
+ "cache-control"?: string | undefined;
56
+ connection?: string | undefined;
57
+ "content-disposition"?: string | undefined;
58
+ "content-encoding"?: string | undefined;
59
+ "content-language"?: string | undefined;
60
+ "content-length"?: string | undefined;
61
+ "content-location"?: string | undefined;
62
+ "content-range"?: string | undefined;
63
+ "content-type"?: string | undefined;
64
+ cookie?: string | undefined;
65
+ date?: string | undefined;
66
+ etag?: string | undefined;
67
+ expect?: string | undefined;
68
+ expires?: string | undefined;
69
+ forwarded?: string | undefined;
70
+ from?: string | undefined;
71
+ host?: string | undefined;
72
+ "if-match"?: string | undefined;
73
+ "if-modified-since"?: string | undefined;
74
+ "if-none-match"?: string | undefined;
75
+ "if-unmodified-since"?: string | undefined;
76
+ "last-modified"?: string | undefined;
77
+ location?: string | undefined;
78
+ origin?: string | undefined;
79
+ pragma?: string | undefined;
80
+ "proxy-authenticate"?: string | undefined;
81
+ "proxy-authorization"?: string | undefined;
82
+ "public-key-pins"?: string | undefined;
83
+ range?: string | undefined;
84
+ referer?: string | undefined;
85
+ "retry-after"?: string | undefined;
86
+ "sec-fetch-site"?: string | undefined;
87
+ "sec-fetch-mode"?: string | undefined;
88
+ "sec-fetch-user"?: string | undefined;
89
+ "sec-fetch-dest"?: string | undefined;
90
+ "sec-websocket-accept"?: string | undefined;
91
+ "sec-websocket-extensions"?: string | undefined;
92
+ "sec-websocket-key"?: string | undefined;
93
+ "sec-websocket-protocol"?: string | undefined;
94
+ "sec-websocket-version"?: string | undefined;
95
+ "set-cookie"?: string[] | undefined;
96
+ "strict-transport-security"?: string | undefined;
97
+ tk?: string | undefined;
98
+ trailer?: string | undefined;
99
+ "transfer-encoding"?: string | undefined;
100
+ upgrade?: string | undefined;
101
+ "user-agent"?: string | undefined;
102
+ vary?: string | undefined;
103
+ via?: string | undefined;
104
+ warning?: string | undefined;
105
+ "www-authenticate"?: string | undefined;
106
+ "X-Forwarded-For": string | undefined;
107
+ "X-Forwarded-Proto": string;
108
+ "X-Forwarded-Port": string;
109
+ };
110
+ static getPathParameters(mockEvent: LambdaEndpoint, parsedURL: URL): any;
111
+ static normalizeSearchParams: (searchParams: URLSearchParams, rawUrl: string) => normalizedSearchParams;
112
+ static getMultiValueQueryStringParameters: (searchParams: URLSearchParams) => any;
113
+ static isEndpointTimeoutError: (errorMessage?: string) => boolean | undefined;
114
+ }
@@ -0,0 +1,3 @@
1
+ import type { OfflineRequest } from "../../defineConfig";
2
+ import type { ExloApp } from "../../main";
3
+ export declare const createFunctionUrlInvokeHandler: (self: ExloApp) => OfflineRequest;
@@ -0,0 +1,4 @@
1
+ export declare const html502 = "<html><head><title>502 Bad Gateway</title></head><body><center><h1>502 Bad Gateway</h1></center></body></html>";
2
+ export declare const html404 = "<html><head><title>404 Not Found</title></head><body><center><h1>404 Not Found</h1></center></body></html>";
3
+ export declare const headerTooLarge = "<html><head><title>400 Request Header Or Cookie Too Large</title></head><body><center><h1>400 Bad Request</h1></center><center>Request Header Or Cookie Too Large</center></body></html>";
4
+ export declare const badRequest = "<html><head><title>400 Bad Request</title></head><body><center><h1>400 Bad Request</h1></center></body></html>";
@@ -0,0 +1,3 @@
1
+ import type { OfflineRequest } from "../../defineConfig";
2
+ import type { ExloApp } from "../../main";
3
+ export declare const createLambdaRequestsHandlers: (self: ExloApp) => OfflineRequest[];
@@ -0,0 +1,3 @@
1
+ import type { OfflineRequest } from "../../defineConfig";
2
+ import type { ExloApp } from "../../main";
3
+ export declare const creatInvokeRequestsHandler: (self: ExloApp) => OfflineRequest;
@@ -0,0 +1,6 @@
1
+ import type { OfflineRequest } from "../../defineConfig";
2
+ import type { ExloApp } from "../../main";
3
+ export declare const creatCreateLambdaHandler: (self: ExloApp) => OfflineRequest;
4
+ export declare const creatGetLambdaHandler: (self: ExloApp) => OfflineRequest;
5
+ export declare const createListVersionsByFunction: (self: ExloApp) => OfflineRequest;
6
+ export declare const createGetFunctionCodeSigningConfig: (self: ExloApp) => OfflineRequest;
@@ -0,0 +1,3 @@
1
+ import type { OfflineRequest } from "../../defineConfig";
2
+ import type { ExloApp } from "../../main";
3
+ export declare const createResponseStreamingInvokeHandler: (self: ExloApp) => OfflineRequest;
@@ -0,0 +1,19 @@
1
+ import type { ServerResponse } from "node:http";
2
+ interface ErrorMessage {
3
+ errorType: string;
4
+ errorMessage: string;
5
+ trace: string[];
6
+ }
7
+ export declare class StreamEncoder {
8
+ #private;
9
+ res: ServerResponse;
10
+ static complete: Buffer<ArrayBuffer>;
11
+ constructor(res: ServerResponse);
12
+ write(chunk: any, encoding: BufferEncoding, cb?: (error: Error | null | undefined) => void): void;
13
+ end(chunk?: Uint8Array): void;
14
+ setHeader(key: string, value: string): void;
15
+ destroy(): void;
16
+ endWithError(payload: ErrorMessage): void;
17
+ endWithJson(payload: any): void;
18
+ }
19
+ export {};
@@ -0,0 +1,29 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ import type { LambdaEndpoint } from "../../lib/parseEvents/endpoints";
3
+ import { BufferedStreamResponse } from "../../lib/runtime/bufferedStreamResponse";
4
+ export declare enum InvokationType {
5
+ DryRun = 204,
6
+ Event = 202,
7
+ RequestResponse = 200
8
+ }
9
+ export declare enum errorType {
10
+ invalidRequest = "InvalidRequestContentException",
11
+ notFound = "ResourceNotFoundException"
12
+ }
13
+ export declare const parseClientContext: (contextAsBase64?: string) => any;
14
+ export declare const unsupportedMethod: (res: ServerResponse, method: string) => true | undefined;
15
+ export declare const collectBody: (req: IncomingMessage, isBase64?: boolean) => Promise<string | undefined>;
16
+ export declare const parseBody: (collecteBody: any) => any;
17
+ export declare const isStreamResponse: (result: any) => result is BufferedStreamResponse;
18
+ export declare const chunkToJs: (chunk: Uint8Array) => any;
19
+ export declare const setRequestId: (res: ServerResponse) => `${string}-${string}-${string}-${string}-${string}`;
20
+ export declare const invalidPayloadErrorMsg: (msg: string) => string;
21
+ export declare const base64ErorMsg: string;
22
+ export declare const notFound: (lambdaName: string, region: string, accountId: string) => string;
23
+ export declare const internalServerError: (res: ServerResponse) => void;
24
+ export declare const isDelimiter: (chunk: Buffer) => boolean;
25
+ export declare const getMultiValueHeaders: (rawHeaders: string[]) => any;
26
+ export declare const checkHeaders: (headers: {
27
+ [key: string]: any;
28
+ }, kind: LambdaEndpoint["kind"]) => void;
29
+ export declare const capitalize: (word: string) => string;
@@ -0,0 +1 @@
1
+ export declare const compileAjvSchema: (schema: any) => import("ajv").ValidateFunction<unknown>;
@@ -0,0 +1,32 @@
1
+ import type { OutgoingHttpHeaders, ServerResponse } from "node:http";
2
+ interface IRestApiError {
3
+ statusCode: number;
4
+ statusText?: string;
5
+ headers: OutgoingHttpHeaders;
6
+ body?: string;
7
+ }
8
+ export declare class RestApiError extends Error {
9
+ res: IRestApiError;
10
+ constructor(error: IRestApiError);
11
+ private setHeaders;
12
+ completeRequest(res: ServerResponse, requestId: string): void;
13
+ }
14
+ export declare class RestApiUnsupportedMethodError extends RestApiError {
15
+ constructor();
16
+ }
17
+ export declare class RestApiUnsupportedMediaTypeError extends RestApiError {
18
+ constructor();
19
+ }
20
+ export declare class RestApiBadRequestError extends RestApiError {
21
+ constructor(body: string);
22
+ }
23
+ export declare class RestApiForbiddenError extends RestApiError {
24
+ constructor();
25
+ }
26
+ export declare class RestApiMissingAuthTokenError extends RestApiError {
27
+ constructor();
28
+ }
29
+ export declare class RestApiInternalServerError extends RestApiError {
30
+ constructor(statusCode?: number);
31
+ }
32
+ export {};
@@ -0,0 +1,9 @@
1
+ import type { IRestApiGatewayResource } from "./restApiServer";
2
+ interface ResolvedResource {
3
+ matchedMethod: string;
4
+ pathParams: Record<string, string>;
5
+ resource: IRestApiGatewayResource;
6
+ resourcePath: string;
7
+ }
8
+ export declare function findRequestResource(method: keyof IRestApiGatewayResource, requestPath: string, resources: IRestApiGatewayResource): ResolvedResource | undefined;
9
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ import type { ExloPlugin } from "../../defineConfig";
2
+ import { type IRestApiServer, type RestApiKey } from "./restApiServer";
3
+ export type IRestApiGatewayOptions = Omit<IRestApiServer, "getLambdas" | "ip">;
4
+ export interface IRestApiPluginOptions {
5
+ gateways: IRestApiGatewayOptions[];
6
+ apiKeys?: RestApiKey[];
7
+ }
8
+ export declare const restApiPlugin: (options: IRestApiPluginOptions) => ExloPlugin;
@@ -0,0 +1 @@
1
+ import{randomUUID as oe}from"node:crypto";import{randomUUID as $}from"node:crypto";import{createServer as te}from"node:http";import{EventSourceMapping as Ae}from"exlo/internal/esm";import{EventSourceMapping as pe}from"exlo/internal/esm";var S=c=>Object.prototype.toString.call(c)=="[object Object]";import _ from"ajv";import A from"ajv-formats";var h=new _({discriminator:!1,useDefaults:!1,validateFormats:!0,jtd:!1,strictRequired:!0,allowUnionTypes:!0,unevaluated:!1,formats:{"date-time":A.get("date-time"),email:A.get("email"),hostname:A.get("hostname"),ipv4:A.get("ipv4"),ipv6:A.get("ipv6"),uri:A.get("uri")}});h.removeKeyword("if");h.removeKeyword("else");h.removeKeyword("then");h.removeKeyword("const");h.removeKeyword("contains");h.removeKeyword("contentEncoding");h.removeKeyword("contentMediaType");h.removeKeyword("contentSchema");h.removeKeyword("nullable");h.removeKeyword("prefixItems");h.removeKeyword("example");h.removeKeyword("examples");h.removeKeyword("deprecated");h.removeKeyword("readOnly");h.removeKeyword("writeOnly");h.removeKeyword("$comment");h.removeKeyword("$defs");h.removeKeyword("exclusiveMinimum");h.removeKeyword("exclusiveMaximum");h.removeKeyword("propertyNames");h.removeKeyword("$id");h.removeKeyword("id");h.addKeyword({keyword:["exclusiveMaximum","exclusiveMinimum"],type:["number"],schemaType:["number"],$data:!0,code(c){if(c.it.rootId!="http://json-schema.org/draft-07/schema#")throw new Error(`unsupported keyword "${c.keyword}"`)}});h.addKeyword({keyword:"propertyNames",type:["object"],schemaType:["object","boolean"],code(c){if(c.it.rootId!="http://json-schema.org/draft-07/schema#")throw new Error('unsupported keyword "propertyNames"')}});h.addKeyword({keyword:"$id",type:["object"],schemaType:["string"],code(c){if(c.it.rootId!="http://json-schema.org/draft-07/schema#")throw new Error('unsupported keyword "$id"')}});h.addKeyword({keyword:"id",schemaType:["string"]});var K=c=>{if(c&&typeof c=="object"&&!Array.isArray(c)){let e;return c.$schema?e={...c,$schema:"http://json-schema.org/draft-07/schema#"}:e=c,h.compile(e)}throw new Error("API Gateway validator Schema must be an object")};var w=class extends Error{res;constructor(e){super("RestApiError"),this.res=e}setHeaders(e){this.res.headers.Connection="keep-alive",this.res.headers["x-amzn-RequestId"]=e,this.res.body?this.res.headers["Content-Length"]=Buffer.byteLength(this.res.body,"utf-8").toString():this.res.headers["Content-Length"]="0"}completeRequest(e,t){e.shouldKeepAlive=!1,this.setHeaders(t),e.writeHead(this.res.statusCode,this.res.statusText,this.res.headers),e.end(this.res.body)}},T=class extends w{constructor(){super({statusCode:405,statusText:"Method Not Allowed",headers:{"Content-Type":"null"},body:"Unsupported HTTP method"})}},M=class extends w{constructor(){super({statusCode:415,statusText:"Unsupported Media Type",headers:{"Content-Type":"application/json","x-amzn-ErrorType":"BadRequestException"},body:'{"message": "Unsupported Media Type"}'})}},I=class extends w{constructor(e){super({statusCode:400,statusText:"Bad Request",headers:{"Content-Type":"application/json","x-amzn-ErrorType":"BadRequestException"},body:e})}},E=class extends w{constructor(){super({statusCode:403,statusText:"Forbidden",headers:{"Content-Type":"application/json","x-amzn-ErrorType":"ForbiddenException"},body:'{"message": "Forbidden"}'})}},P=class extends w{constructor(){super({statusCode:403,statusText:"Forbidden",headers:{"Content-Type":"application/json","x-amzn-ErrorType":"MissingAuthenticationTokenException"},body:'{"message": "Missing Authentication Token"}'})}},m=class extends w{constructor(e=502){super({statusCode:e,statusText:"BadGateway",headers:{"Content-Type":"application/json","x-amzn-ErrorType":"InternalServerErrorException"},body:'{"message": "Internal server error"}'})}};function N(c,e,t){let n=e.split("/").filter(Boolean),o={};if(!n.length){let i;return t[c]?i=c:t.ANY&&(i="ANY"),i?{matchedMethod:i,pathParams:o,resource:t,resourcePath:"/"}:void 0}let a=q(c,n,t,o,"");if(a?.resource)return{matchedMethod:a.matchedMethod,pathParams:o,resource:a.resource,resourcePath:a?.resourcePath}}function q(c,e,t,n,o){if(!e.length)return;let a=`/${e[0]}`;if(a in t){let r=t[a],d=`${o}${a}`;if(e.length===1){let u=r[c]?c:r.ANY?"ANY":null;if(u)return{matchedMethod:u,resource:r,resourcePath:d}}return q(c,e.slice(1),r,n,d)}let i=Object.keys(t).find(r=>r.startsWith("/{")&&!r.endsWith("+}"));if(i){let r=i.slice(2,-1);n[r]=encodeURIComponent(e[0]);let d=t[i],u=`${o}${i}`;if(e.length===1){let g=d[c]?c:d.ANY?"ANY":void 0;if(g)return{matchedMethod:g,resource:d,resourcePath:u}}return q(c,e.slice(1),d,n,u)}let s=Object.keys(t).find(r=>r.startsWith("/{")&&r.endsWith("+}"));if(s){let r=s.match(/\{(.+?)\+\}/)?.[1];r&&(n[r]=e.map(encodeURIComponent).join("/"));let d=t[s],u=`${o}${s}`;if(d.ANY)return{matchedMethod:"ANY",resource:d,resourcePath:u}}}import{getRandomValues as k}from"node:crypto";import{networkInterfaces as B}from"node:os";var C="abcdefghijklmnopqrstuvwxyz0123456789",H=`ABCDEFGHIJKLMNOPQRSTUVWXYZ${C}`,J=40;function O(){let c="",e=new Uint8Array(45);k(e);for(let t=0;t<J;t++)c+=H[e[t]%H.length];return c}var X=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function j(){let c=new Date,e=String(c.getUTCDate()).padStart(2,"0"),t=X[c.getUTCMonth()],n=c.getUTCFullYear(),o=String(c.getUTCHours()).padStart(2,"0"),a=String(c.getUTCMinutes()).padStart(2,"0"),i=String(c.getUTCSeconds()).padStart(2,"0");return{requestTime:`${e}/${t}/${n}:${o}:${a}:${i} +0000`,requestTimeEpoch:c.getTime()}}function D(){let c="127.0.0.1";if(B){let e=Object.values(B()).reduce((t,n)=>(t.push(...n),t),[])?.filter(t=>!t.internal&&t.family==="IPv4").find(Boolean)?.address;e&&(c=e)}return c}function L(){let c=Math.floor(Date.now()/1e3).toString(16),e=k(new Uint8Array(12)).reduce((t,n)=>t+n.toString(16).padStart(2,"0"),"");return`1-${c}-${e}`}function Z(){return k(new Uint8Array(8)).reduce((c,e)=>c+e.toString(16).padStart(2,"0"),"")}function ee(c){let e=c.split("-");if(e.length===3){let t=(BigInt(`0x${e[2]}`)+BigInt(2)).toString(16).padStart(24,"0");return`${e[0]}-${e[1]}-${t}`}return c}function U(c){if(!c)return`Root=${L()}`;let e=c.match(/Root=([^\s;]+)/),t=e?e[1]:L(),n=ee(t);return`Self=1-${Z()};Root=${n}`}function Q(){let c="",e=new Uint8Array(6);crypto.getRandomValues(e);for(let t=0;t<6;t++)c+=C[e[t]%C.length];return c}function V(){let c=new Uint8Array(8);return crypto.getRandomValues(c),Buffer.from(String.fromCharCode(...c),"utf-8").toString("base64url")}var se=["connection","content-md5","content-length","expect","max-forwards","proxy-authenticate","server","te","host","trailer","transfer-encoding","upgrade","www-authenticate","x-forwarded-port","x-forwarded-proto"],re=["AWS4-HMAC-SHA256","Credential","SignedHeaders","Signature"],F=["DELETE","GET","HEAD","OPTIONS","PATCH","POST","PUT"],G=["authorization","connection","content-md5","max-forwards","user-agent","www-authenticate","date","server"],z=["expect","host","proxy-authenticate","te","transfer-encoding","trailer","upgrade","via"],ne=/^[a-z0-9-.+#!{}_'`]+\/([a-z0-9-.+#!{}_'`]+|\*{1})$/,v=class c{constructor({id:e,ip:t,getLambdas:n,port:o,stage:a,resources:i,requireStagePrefixInRequestPath:s,models:r,binaryMediaTypes:d,resolveLambdaNameFromArn:u},g){this.logger=g;if(e)this.id=e;else{let l=$();this.id=l.slice(0,l.indexOf("-"))}this.ip=t,this.port=o,this.stage=a??"dev",this.getLambdas=n,this.resources=i,this.resolveLambdaNameFromArn=u,this.deploymentId=Q(),r&&typeof r=="object"?this.models=r:this.models={},typeof s=="boolean"&&(this.requireStagePrefixInRequestPath=s),Array.isArray(d)&&this.compileBinaryTypes(d),this.compileResources(this.resources)}static apiKeys=[];static servers=[];server;id;ip;port;stage;requireStagePrefixInRequestPath=!0;deploymentId;resolveLambdaNameFromArn;binaryMediaTypes=[];getLambdas;resources;compiledResources={};sockets=[];models;compileBinaryTypes(e){for(let t of e){let n=t.toLowerCase();if(n=="*/*"){this.binaryMediaTypes.push(/^.*$/);continue}if(ne.test(n))if(n.endsWith("/*")){let o=new RegExp(`^${n.slice(0,-1)}[a-z0-9-_.$~+#'{}\`!*]+$`);this.binaryMediaTypes.push(o)}else{let o=new RegExp(`^${n}$`);this.binaryMediaTypes.push(o)}}}compileResources(e){for(let[t,n]of Object.entries(e))t.startsWith("/")&&this.compileResources(n);if(!e.resourceId){let t=$();e.resourceId=t.slice(0,t.indexOf("-"))}this.compiledResources[e.resourceId]={};for(let t of F){let n=e[t];if(!n)continue;let o=[],a=[],i={};if(n.request){if(n.request.queryStringParameters)for(let[s,r]of Object.entries(n.request.queryStringParameters))r.required&&o.push(s);if(n.request.headers)for(let[s,r]of Object.entries(n.request.headers))r.required&&a.push(s);if(n.request.body)for(let[s,r]of Object.entries(n.request.body)){let d=this.models[r];i[s]=K(d)}}this.compiledResources[e.resourceId][t]={requiredQueryParams:o,requiredHeaders:a,body:i}}}async start(){this.server=te((t,n)=>{this.requestHandler(t,n)}),await new Promise(t=>{this.server.listen(this.port,t)}),c.servers.push(this),this.port=this.server.address().port,this.server.on("connection",t=>{t.on("close",()=>{let n=this.sockets.findIndex(o=>o==t);n!=-1&&this.sockets.splice(n,1)}),this.sockets.push(t)});let e=this.requireStagePrefixInRequestPath?`/${this.stage}`:"";this.printPaths(this.resources,e)}printPaths(e,t){let n=Object.keys(e);for(let o of n){let a=e[o];if(!o.startsWith("/"))continue;let i=Object.keys(a).filter(r=>F.includes(r)),s=`${t}${o}`;i.length&&this.logger.CYAN(`${i.join(", ")} http://localhost:${this.port}${s}`),this.printPaths(a,s)}}dropConnections(){for(let e of this.sockets)e.writable&&e.destroy()}stop(){this.server?.close()}findResourceFromRequest(e){let{method:t,url:n}=e,o=n.indexOf("?");o==-1&&(o=void 0);let a=n.slice(0,o),i=a;for(;i!="/"&&i.endsWith("/");)i=i.slice(0,-1);let s;o&&(s=n.slice(o));let r=i;if(this.requireStagePrefixInRequestPath){if(!i.startsWith(`/${this.stage}`))return;r=i.slice(`/${this.stage}`.length)}let d=N(t,r,this.resources);if(d)return{resource:d.resource,pathname:i,requestPath:a,rawQueryStringParameters:s,matchedMethod:d.matchedMethod,pathParams:d.pathParams,resourcePath:d.resourcePath}}static async collectBody(e,t){let n=Buffer.alloc(0);return e.on("data",o=>{n=Buffer.concat([n,o])}),new Promise(o=>{e.on("end",async()=>{o(n?n.toString(t?"base64":"utf-8"):null)})})}static getQueryStrings(e){let t=null,n=null;if(!e)return{queryStringParameters:n,multiValueQueryStringParameters:t};let o=e.slice(1).split("&"),a={};for(let s of o){let[r,d]=s.split("="),u=r.split(";"),g=d?.split(";")??[""];if(u.length==1&&g.length==1){let R=decodeURIComponent(u[0]),b=decodeURIComponent(g[0]);R in a?a[R].push(b):a[R]=[b];continue}let l=u.slice(0,-1),p=u[u.length-1],f=decodeURIComponent(p),y=decodeURIComponent(g[0]);if(f in a?a[f].push(y):a[f]=[y],g.length>1){let R=g.slice(1);for(let b of R)l.push(b)}for(let R of l){let b=decodeURIComponent(R);b in a?a[b].push(""):a[b]=[""]}}let i=Object.keys(a);if(i.length){n={},t={};for(let s of i.sort()){let r=a[s];t[s]=r,n[s]=r[r.length-1]}}return{queryStringParameters:n,multiValueQueryStringParameters:t}}static shouldDropHeader(e){return!!se.includes(e)}static parseMultiValueHeaders(e){let t={},n={},o={};for(let i=0;i<e.length;i=i+2){let s=e[i],r=s.toLowerCase(),d=e[i+1]?.trim()??"";if(d=Buffer.from(d,"utf-8").toString("latin1"),r=="x-amzn-trace-id"){t["X-Amzn-Trace-Id"]=[d];continue}if(r=="user-agent"){t["User-Agent"]=[d];continue}if(r=="x-forwarded-for"){o[s]||(o[s]=[]),o[s].push(d);continue}if(c.shouldDropHeader(r))continue;let u=n[r];u&&u!=s&&delete t[u],s in t||(t[s]=[]),t[s].push(d),n[r]=s}let a=Object.keys(o);if(a.length){let i=a[a.length-1];t["X-Forwarded-For"]=o[i]}return t}getHeaders(e){let t=c.parseMultiValueHeaders(e),n=t["X-Amzn-Trace-Id"]?t["X-Amzn-Trace-Id"][0]:void 0;t.Host=[`localhost:${this.port}`],t["X-Amzn-Trace-Id"]=[U(n)],t["X-Forwarded-Proto"]=["http"],t["X-Forwarded-Port"]=[String(this.port)],t["X-Forwarded-For"]||(t["X-Forwarded-For"]=[]),t["X-Forwarded-For"].push(this.ip);let o={},a={},i=Object.keys(t).sort((l,p)=>l.toLowerCase().localeCompare(p.toLowerCase())),s,r,d,u="*/*",g;for(let l of i){let p=t[l],f=l.toLowerCase();if(f=="x-http-method-override"){s=p[p.length-1];continue}if(f=="x-api-key")r=p[p.length-1];else if(f=="authorization"){if(g=p[p.length-1],g.startsWith("AWS4-HMAC-SHA256 Credential=")&&re.every(y=>g.includes(y)))continue}else if(f=="content-type")d=p[p.length-1].toLowerCase();else if(f=="accept")u=p[p.length-1].toLowerCase().split(",")[0];else if(l=="X-Forwarded-For"){let y=p.join(", ");o[l]=[y],a[l]=y;continue}o[l]=p,a[l]=p[p.length-1]}return{headers:a,multiValueHeaders:o,overrideMethod:s,apiKey:r,contentType:d,accept:u,authorization:g}}createRequestContext({foundRequest:e,requestId:t,httpMethod:n,req:o,headers:a,apiKey:i}){let s,r;if(i){s={apiKey:i};let f=c.apiKeys.find(y=>y.value==i)?.id;f&&(r={apiKeyId:f})}let d={cognitoIdentityPoolId:null,accountId:null,cognitoIdentityId:null,...s,caller:null,sourceIp:o.socket.remoteAddress?.includes(":")?this.ip:o.socket.remoteAddress,principalOrgId:null,accessKey:null,cognitoAuthenticationType:null,cognitoAuthenticationProvider:null,userArn:null,...r,userAgent:a["User-Agent"]??null,user:null},{requestTime:u,requestTimeEpoch:g}=j(),l=e.requestPath;return this.requireStagePrefixInRequestPath||(l=`/${this.stage}${e.requestPath}`),{resourceId:e.resource.resourceId,resourcePath:e.resourcePath,httpMethod:n,extendedRequestId:V(),requestTime:u,path:l,accountId:"123456789012",protocol:"HTTP/1.1",stage:this.stage,domainPrefix:"localhost",requestTimeEpoch:g,requestId:t,identity:d,domainName:`http://localhost:${this.port}`,deploymentId:this.deploymentId,apiId:this.id}}async createPayloadFromRequest(e,t,n){let{rawHeaders:o,method:a}=e,{headers:i,multiValueHeaders:s,overrideMethod:r,apiKey:d,contentType:u,accept:g}=this.getHeaders(o),l=!1;u&&this.binaryMediaTypes.find(Y=>Y.test(u))&&(l=!0);let p=await c.collectBody(e,l)||null,{queryStringParameters:f,multiValueQueryStringParameters:y}=c.getQueryStrings(t.rawQueryStringParameters),R=null;Object.keys(t.pathParams).length&&(R=t.pathParams);let b=r??a,W=`/${this.stage}`,x=t.requestPath;return this.requireStagePrefixInRequestPath&&(x=x.slice(W.length),x||(x="/")),{payload:{resource:t.resourcePath,path:x,httpMethod:b,headers:i,multiValueHeaders:s,queryStringParameters:f,multiValueQueryStringParameters:y,pathParameters:R,stageVariables:null,requestContext:this.createRequestContext({foundRequest:t,requestId:n,apiKey:d,req:e,headers:i,httpMethod:b}),isBase64Encoded:l,body:p},contentType:u,accept:g}}validateRequest(e,t,n,o){let{payload:a,contentType:i}=e;if(!F.includes(a.httpMethod))throw new T;if(t.requiresApiKey&&!a.requestContext.identity.apiKeyId)throw new E;let s=i??"application/json";if(s.startsWith("application/json;")){let u=s.replaceAll(" ","").split(";").find(g=>g.startsWith("charset="));if(u&&u.replaceAll(",","")!="charset=utf-8")throw new M;s="application/json"}let r=this.compiledResources[n]?.[o];if(t.validate&&r){if(t.validate.query&&r.requiredQueryParams.length){if(!a.queryStringParameters)throw new I(`{"message": "Missing required request parameters: [${r.requiredQueryParams.join(", ")}]"}`);let l=r.requiredQueryParams.filter(p=>!a.queryStringParameters[p]);if(l.length)throw new I(`{"message": "Missing required request parameters: [${l.join(", ")}]"}`)}if(t.validate.headers&&r.requiredHeaders.length){let l=r.requiredHeaders.filter(p=>!a.headers[p]);if(l.length)throw new I(`{"message": "Missing required request parameters: [${l.join(", ")}]"}`)}if(!t.validate.body||a.isBase64Encoded||this.binaryMediaTypes.find(l=>l.test("anything")))return;let d=r.body[s];if(typeof d!="function")return;if(!a.body)throw new I('{"message":[Unknown error parsing request body]}');let u;try{u=JSON.parse(a.body)}catch{throw new I('{"message":[Unknown error parsing request body]}')}if(!d(u)){this.logger.getDebug()&&console.warn(d.errors);let l=d.errors.map(p=>`instancePath '${p.instancePath}' ${p.message}`).join(", ");throw new I(JSON.stringify({message:`[${l}]`}))}}}async invokeProxyLambda(e,t){let a=e;if(a.startsWith("arn:aws:lambda")){let d=a.split(":");(d.length==7||d.length==8)&&(a=d[6])}let i=this.getLambdas(),s=i.find(d=>d.name==a);if(!s&&typeof this.resolveLambdaNameFromArn=="function"){let d=this.resolveLambdaNameFromArn(e);s=i.find(u=>u.name==d)}if(!s)throw this.logger.RED(`REST APiG can not find Lambda ${e}`),new m;return await s.invoke(t)}async invokeIntegration(e,t,n,o){let a=e.matchedMethod,i=e.resource[a];try{let s=await this.createPayloadFromRequest(t,e,o),{payload:r,accept:d}=s;if(this.validateRequest(s,i,e.resource.resourceId,a),i.integration.lambda?.arn){let u=await this.invokeProxyLambda(i.integration.lambda.arn,r);this.responseFromIntegration(n,u,"lambda-proxy",o,d,a)}else if(typeof i.integration.mock=="function"){let u=await i.integration.mock(r);this.responseFromIntegration(n,u,"lambda-proxy",o,d,a)}else this.logger.RED("REST APiG must have integration"),n.statusCode=500,n.end("No resource integration found")}catch(s){if(s instanceof w){s.completeRequest(n,o);return}console.error(s),new m().completeRequest(n,o)}}async requestHandler(e,t){let n=this.findResourceFromRequest(e),o=$();n?await this.invokeIntegration(n,e,t,o):new P().completeRequest(t,o)}parseIntegrationResponseHeaders(e){let t={},n=typeof e.multiValueHeaders;if(S(e.multiValueHeaders))for(let[i,s]of Object.entries(e.multiValueHeaders)){let r=i,d=i.toLowerCase();if(d=="content-type")r="Content-Type";else if(G.includes(d))r=`x-amzn-Remapped-${r}`;else if(z.includes(d))continue;t[r]=[];for(let u of s)if(typeof u=="string")t[r].push(u);else if(typeof u=="number"||typeof u=="boolean")t[r].push(String(u));else if(u===null)t[r].includes("")||t[r].push("");else throw this.logger.RED(`Invalid integration response headers. MultiValueHeader '${r}' values must be string, number, boolean or null.`),new m}else if(n!="undefined"&&n!==null)throw this.logger.RED("Invalid integration response headers. multiValueHeaders must be an object of with string[] as value type."),new m;if(typeof e.headers=="undefined")return t;if(S(e.headers))for(let[i,s]of Object.entries(e.headers)){let r=i,d=i.toLowerCase();if(d=="content-type")r="Content-Type";else if(G.includes(d))r=`x-amzn-Remapped-${r}`;else if(z.includes(d))continue;if(t[r]||(t[r]=[]),typeof s=="string")t[r].includes(s)||t[r].push(s);else if(typeof s=="number"||typeof s=="boolean"){let u=String(s);t[r].includes(u)||t[r].push(u)}else if(s===null)t[r].includes("")||t[r].push("");else throw this.logger.RED(`Invalid integration response headers. Header '${r}' must be string, number, boolean or null.`),new m}else if(e.headers!==null)throw this.logger.RED("Invalid integration response headers. Headers must be an object or null."),new m;return t}parseIntegrationResponse(e,t){if(!S(e))throw this.logger.RED("Invalid integration response."),new m;let n=["statusCode","body","headers","isBase64Encoded","multiValueHeaders"],o=Object.keys(e).find(d=>!n.includes(d));if(o)throw this.logger.RED(`Invalid integration response. Field '${o}' is not supported.`),new m;let a=200,i;if(e.statusCode){if(Number.isNaN(e.statusCode))throw this.logger.RED("Invalid integration response statusCode"),new m;let d=Number(e.statusCode);if(!(d>99&&d<600))throw this.logger.RED("Invalid integration response statusCode"),new m;a=d}let s=typeof e.body;if(s=="string")i=e.body;else if(s=="number")Number.isNaN(e.body)||(i=String(e.body));else if(s=="boolean")i=String(e.body);else if(s!="undefined"&&e.body!==null)throw this.logger.RED("Invalid integration response body"),new m;if(i&&e.isBase64Encoded&&this.binaryMediaTypes.find(d=>d.test(t))){let d=Buffer.from(i,"base64");if(d.toString("base64")!=i)throw this.logger.RED("Invalid integration response body. Incorrect body base64 encoding"),new m;i=d}let r=this.parseIntegrationResponseHeaders(e);return{statusCode:a,body:i,headers:r}}responseFromIntegration(e,t,n,o,a,i){try{let s=this.parseIntegrationResponse(t,a);e.shouldKeepAlive=!1,s.headers.Connection=["keep-alive"],s.headers["x-amzn-RequestId"]=[o],s.headers["Content-Length"]=["0"],s.body&&s.statusCode!=204&&(s.headers["Content-Length"]=[Buffer.byteLength(s.body,typeof s.body=="string"?"utf-8":"base64").toString()]),s.headers["Content-Type"]?s.headers["Content-Type"]=[s.headers["Content-Type"][0]]:s.headers["Content-Type"]=["application/json"],i=="HEAD"&&s.headers["Content-Length"][0]!="0"&&(s.headers["x-amzn-Remapped-Content-Length"]=s.headers["Content-Length"]),e.writeHead(s.statusCode,s.headers),i=="HEAD"?e.end():e.end(s.body)}catch(s){if(s instanceof w){s.completeRequest(e,o);return}console.error(s),new m().completeRequest(e,o)}}};var ie=D(),Ge=c=>{let e=c.gateways,t=c.apiKeys??[],n={name:"rest-api-plugin",onKill(){for(let o of v.servers)o.stop()},shared:{gateways:e},server:{async onReady(){for(let o of t){if(!o.id){let a=oe();o.id=a.slice(0,a.indexOf("-"))}o.value||(o.value=O(),console.log("API Key",o.name,":",o.value)),v.apiKeys.push(o)}for(let o of e){let a=new v({ip:ie,...o,getLambdas:()=>this.lambdas},this.log);await a.start();let i=n.shared.gateways.find(s=>s.id==o.id);i&&(i.id=a.id,i.port=a.port,i.stage=a.stage),console.log(`REST API [${a.id}]`,`http://localhost:${a.port}`),a.server?.unref()}}},buildCallback(o,a){if(a)for(let i of v.servers)i.dropConnections()}};return n};export{Ge as restApiPlugin};
@@ -0,0 +1,4 @@
1
+ /**
2
+ * @deprecated Not supported yet
3
+ */
4
+ export declare const getResourcesFromOpenApi: (document: Record<string, any>, overwriteIntegrationUri?: (uri: string) => string) => void;
@@ -0,0 +1,265 @@
1
+ import { type IncomingMessage, type Server } from "node:http";
2
+ import type { ILambda } from "../../defineConfig";
3
+ import type { log } from "../../lib/utils/colorize";
4
+ export interface RestApiKey {
5
+ name: string;
6
+ id?: string;
7
+ value?: string;
8
+ }
9
+ interface IIntegrationResponse {
10
+ statusCode: number;
11
+ headers?: Record<string, string>;
12
+ multiValueHeaders?: Record<string, string[]>;
13
+ body?: string | null;
14
+ isBase64Encoded?: boolean;
15
+ }
16
+ interface ILambdaIntegration {
17
+ lambda: {
18
+ /**
19
+ * Function name or function (un)qualified arn
20
+ */
21
+ arn: string;
22
+ proxy?: true;
23
+ };
24
+ mock?: never;
25
+ }
26
+ interface IMockIntegration {
27
+ lambda?: never;
28
+ mock: (request: any) => Promise<IIntegrationResponse> | IIntegrationResponse;
29
+ }
30
+ type IMethodIntegration = ILambdaIntegration | IMockIntegration;
31
+ interface IMethodExecution {
32
+ integration: IMethodIntegration;
33
+ requiresApiKey?: boolean;
34
+ request?: {
35
+ queryStringParameters?: Record<string, {
36
+ required?: boolean;
37
+ cache?: boolean;
38
+ }>;
39
+ headers?: Record<string, {
40
+ required?: boolean;
41
+ cache?: boolean;
42
+ }>;
43
+ /** @example {"application/json": "CreateUserModel"} */
44
+ body?: {
45
+ [contentType: string]: string;
46
+ };
47
+ };
48
+ validate?: {
49
+ query?: boolean;
50
+ headers?: boolean;
51
+ body?: boolean;
52
+ };
53
+ }
54
+ export interface EndpointMethods {
55
+ ANY?: IMethodExecution;
56
+ DELETE?: IMethodExecution;
57
+ GET?: IMethodExecution;
58
+ HEAD?: IMethodExecution;
59
+ OPTIONS?: IMethodExecution;
60
+ PATCH?: IMethodExecution;
61
+ POST?: IMethodExecution;
62
+ PUT?: IMethodExecution;
63
+ resourceId?: string;
64
+ }
65
+ export type IRestApiGatewayResource = {
66
+ "/"?: "❌ Resource path can not be /";
67
+ } & {
68
+ [key in `/${string}+}` | `/${string}}` | `/${string}` | `/${string}/` | `/${string}/${string}`]: key extends `/${string}/${string}` ? "❌ Resource path can not include multiple /" : key extends `${string}/` ? "❌ Resource path can not end with /" : key extends `/${string}+}` ? EndpointMethods : IRestApiGatewayResource & EndpointMethods;
69
+ } & EndpointMethods;
70
+ interface IRequestResourceFound {
71
+ resource: IRestApiGatewayResource;
72
+ pathname: string;
73
+ requestPath: string;
74
+ rawQueryStringParameters?: string;
75
+ matchedMethod: string;
76
+ pathParams: Record<string, string>;
77
+ resourcePath: string;
78
+ }
79
+ export interface IRestApiServer {
80
+ id?: string;
81
+ ip: string;
82
+ getLambdas: () => ILambda[];
83
+ port?: number;
84
+ /** @default "dev" */
85
+ stage?: string;
86
+ resources: IRestApiGatewayResource;
87
+ /**
88
+ * Should all the request against the API start with stage prefix ?
89
+ * @default true
90
+ */
91
+ requireStagePrefixInRequestPath?: boolean;
92
+ /**
93
+ * AWS REST API Gateway compatible JSON Schemas
94
+ *
95
+ * @example
96
+ * ```js
97
+ * {
98
+ * CreateUserModel: {
99
+ * type: "object",
100
+ * required: ["firstname"],
101
+ * properties: {
102
+ * firstname: {
103
+ * type: "string"
104
+ * },
105
+ * lastname: {
106
+ * type: "string"
107
+ * }
108
+ * }
109
+ * }
110
+ * }
111
+ * ```
112
+ */
113
+ models?: {
114
+ [modelName: string]: Record<string, any>;
115
+ };
116
+ /** @example ["image/*", "video/*"] */
117
+ binaryMediaTypes?: string[];
118
+ resolveLambdaNameFromArn?: (lambdaArn: string) => string | Promise<string>;
119
+ }
120
+ type httpMethod = keyof Omit<EndpointMethods, "resourceId">;
121
+ export declare class RestApiServer {
122
+ logger: typeof log;
123
+ static apiKeys: RestApiKey[];
124
+ static servers: RestApiServer[];
125
+ server?: Server;
126
+ id: string;
127
+ ip: string;
128
+ port?: number;
129
+ stage: string;
130
+ requireStagePrefixInRequestPath: boolean;
131
+ deploymentId: string;
132
+ private resolveLambdaNameFromArn?;
133
+ private binaryMediaTypes;
134
+ private getLambdas;
135
+ private resources;
136
+ private compiledResources;
137
+ private sockets;
138
+ private models;
139
+ constructor({ id, ip, getLambdas, port, stage, resources, requireStagePrefixInRequestPath, models, binaryMediaTypes, resolveLambdaNameFromArn, }: IRestApiServer, logger: typeof log);
140
+ private compileBinaryTypes;
141
+ private compileResources;
142
+ start(): Promise<void>;
143
+ private printPaths;
144
+ dropConnections(): void;
145
+ stop(): void;
146
+ private findResourceFromRequest;
147
+ private static collectBody;
148
+ static getQueryStrings(rawQueryStringParameters?: string): {
149
+ multiValueQueryStringParameters: Record<string, string[]> | null;
150
+ queryStringParameters: Record<string, string> | null;
151
+ };
152
+ private static shouldDropHeader;
153
+ static parseMultiValueHeaders(rawHeaders: string[]): Record<string, string[]>;
154
+ getHeaders(rawHeaders: string[]): {
155
+ headers: Record<string, string>;
156
+ multiValueHeaders: Record<string, string[]>;
157
+ overrideMethod: string | undefined;
158
+ apiKey: string | undefined;
159
+ contentType: string | undefined;
160
+ accept: string;
161
+ authorization: string | undefined;
162
+ };
163
+ createRequestContext({ foundRequest, requestId, httpMethod, req, headers, apiKey, }: {
164
+ foundRequest: IRequestResourceFound;
165
+ requestId: string;
166
+ httpMethod: string;
167
+ req: IncomingMessage;
168
+ headers: Record<string, string>;
169
+ apiKey?: string;
170
+ }): {
171
+ resourceId: string | undefined;
172
+ resourcePath: string;
173
+ httpMethod: string;
174
+ extendedRequestId: string;
175
+ requestTime: string;
176
+ path: string;
177
+ accountId: string;
178
+ protocol: string;
179
+ stage: string;
180
+ domainPrefix: string;
181
+ requestTimeEpoch: number;
182
+ requestId: string;
183
+ identity: {
184
+ userAgent: string;
185
+ user: null;
186
+ apiKeyId?: string | undefined;
187
+ caller: null;
188
+ sourceIp: string | undefined;
189
+ principalOrgId: null;
190
+ accessKey: null;
191
+ cognitoAuthenticationType: null;
192
+ cognitoAuthenticationProvider: null;
193
+ userArn: null;
194
+ apiKey?: string | undefined;
195
+ cognitoIdentityPoolId: null;
196
+ accountId: null;
197
+ cognitoIdentityId: null;
198
+ };
199
+ domainName: string;
200
+ deploymentId: string;
201
+ apiId: string;
202
+ };
203
+ createPayloadFromRequest(req: IncomingMessage, foundRequest: IRequestResourceFound, requestId: string): Promise<{
204
+ payload: {
205
+ resource: string;
206
+ path: string;
207
+ httpMethod: string | undefined;
208
+ headers: Record<string, string>;
209
+ multiValueHeaders: Record<string, string[]>;
210
+ queryStringParameters: Record<string, string> | null;
211
+ multiValueQueryStringParameters: Record<string, string[]> | null;
212
+ pathParameters: Record<string, string> | null;
213
+ stageVariables: null;
214
+ requestContext: {
215
+ resourceId: string | undefined;
216
+ resourcePath: string;
217
+ httpMethod: string;
218
+ extendedRequestId: string;
219
+ requestTime: string;
220
+ path: string;
221
+ accountId: string;
222
+ protocol: string;
223
+ stage: string;
224
+ domainPrefix: string;
225
+ requestTimeEpoch: number;
226
+ requestId: string;
227
+ identity: {
228
+ userAgent: string;
229
+ user: null;
230
+ apiKeyId?: string | undefined;
231
+ caller: null;
232
+ sourceIp: string | undefined;
233
+ principalOrgId: null;
234
+ accessKey: null;
235
+ cognitoAuthenticationType: null;
236
+ cognitoAuthenticationProvider: null;
237
+ userArn: null;
238
+ apiKey?: string | undefined;
239
+ cognitoIdentityPoolId: null;
240
+ accountId: null;
241
+ cognitoIdentityId: null;
242
+ };
243
+ domainName: string;
244
+ deploymentId: string;
245
+ apiId: string;
246
+ };
247
+ isBase64Encoded: boolean;
248
+ body: string | null;
249
+ };
250
+ contentType: string | undefined;
251
+ accept: string;
252
+ }>;
253
+ validateRequest(request: Awaited<ReturnType<RestApiServer["createPayloadFromRequest"]>>, method: IMethodExecution, resourceId: string, methodName: httpMethod): void;
254
+ private invokeProxyLambda;
255
+ private invokeIntegration;
256
+ private requestHandler;
257
+ parseIntegrationResponseHeaders(payload: any): Record<string, string[]>;
258
+ parseIntegrationResponse(payload: any, accept: string): {
259
+ statusCode: number;
260
+ body: string | Buffer<ArrayBufferLike> | undefined;
261
+ headers: Record<string, string[]>;
262
+ };
263
+ private responseFromIntegration;
264
+ }
265
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,9 @@
1
+ export declare function generateApiKey(): string;
2
+ export declare function generateRequestTime(): {
3
+ requestTime: string;
4
+ requestTimeEpoch: number;
5
+ };
6
+ export declare function getLocalIp(): string;
7
+ export declare function generateApiGatewayTraceId(originalTraceId?: string): string;
8
+ export declare function generateDeploymentId(): string;
9
+ export declare function generateExtendedRequestId(): string;
@@ -0,0 +1,10 @@
1
+ import { S3GenericAction, type S3LocalService } from "./localAction";
2
+ import type { IncomingHttpHeaders, IncomingMessage, ServerResponse } from "node:http";
3
+ export declare class AbortMultipartUploadAction extends S3GenericAction {
4
+ localService: S3LocalService;
5
+ bucket: string;
6
+ key: string;
7
+ uploadId: string;
8
+ constructor(url: URL, headers: IncomingHttpHeaders, localService: S3LocalService);
9
+ exec(res: ServerResponse, req: IncomingMessage): Promise<void>;
10
+ }
@@ -0,0 +1,15 @@
1
+ import { S3GenericAction, S3LocalService } from "./localAction";
2
+ import type { IncomingHttpHeaders, IncomingMessage, ServerResponse } from "http";
3
+ export declare class CompleteMultipartUploadAction extends S3GenericAction {
4
+ localService: S3LocalService;
5
+ bucket: string;
6
+ key: string;
7
+ uploadId: string | null;
8
+ constructor(url: URL, headers: IncomingHttpHeaders, localService: S3LocalService);
9
+ private validateRequest;
10
+ private collectBody;
11
+ private getRequestBody;
12
+ private verifyCompleteMultiPartUploadParts;
13
+ private safeCreateObject;
14
+ exec(res: ServerResponse, req: IncomingMessage): Promise<void>;
15
+ }
@@ -0,0 +1,24 @@
1
+ import type { IncomingHttpHeaders, IncomingMessage, ServerResponse } from "node:http";
2
+ import { type LocalS3Object, S3GenericAction, S3LocalService } from "./localAction";
3
+ export declare class CopyObjectAction extends S3GenericAction {
4
+ localService: S3LocalService;
5
+ bucket: string;
6
+ key: string;
7
+ sourceBucket: string;
8
+ sourceKey: string;
9
+ contentType: string;
10
+ cacheControl?: string;
11
+ contentDisposition?: string;
12
+ contentEncoding?: string;
13
+ contentLanguage?: string;
14
+ websiteRedirectLocation?: string;
15
+ expires?: number;
16
+ storageClass: LocalS3Object["StorageClass"];
17
+ metadataDirective?: string;
18
+ ifMatch?: string;
19
+ ifNoneMatch?: string;
20
+ ifModifiedSince?: number;
21
+ ifUnmodifiedSince?: number;
22
+ constructor(url: URL, headers: IncomingHttpHeaders, localService: S3LocalService);
23
+ exec(res: ServerResponse, req: IncomingMessage): Promise<void>;
24
+ }