exlo 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.mjs +5 -5
- package/dist/defineConfig.mjs +1 -1
- package/dist/plugins/dynamodb/src/batch.d.ts +24 -0
- package/dist/plugins/dynamodb/src/failure/getBatchItemFailures.d.ts +4 -0
- package/dist/plugins/dynamodb/src/failure/index.d.ts +28 -0
- package/dist/plugins/dynamodb/src/failure/s3.d.ts +13 -0
- package/dist/plugins/dynamodb/src/failure/sns.d.ts +11 -0
- package/dist/plugins/dynamodb/src/failure/sqs.d.ts +12 -0
- package/dist/plugins/dynamodb/src/index.d.ts +48 -0
- package/dist/plugins/dynamodb/src/index.mjs +1 -0
- package/dist/plugins/dynamodb/src/proxy/calculateItemSizeInBytes.d.ts +1 -0
- package/dist/plugins/dynamodb/src/proxy/dynamoDbDateTime.d.ts +13 -0
- package/dist/plugins/dynamodb/src/proxy/index.d.ts +17 -0
- package/dist/plugins/dynamodb/src/proxy/index.mjs +1 -0
- package/dist/plugins/dynamodb/src/proxy/proxy.d.ts +56 -0
- package/dist/plugins/dynamodb/src/proxy/proxy.test.d.ts +1 -0
- package/dist/plugins/dynamodb/src/proxy/proxyDynamoStream.d.ts +76 -0
- package/dist/plugins/dynamodb/src/proxy/sequenceNumber.d.ts +16 -0
- package/dist/plugins/dynamodb/src/proxy/worker.d.ts +1 -0
- package/dist/plugins/dynamodb/src/proxy/worker.mjs +1 -0
- package/dist/plugins/dynamodb/src/stream.d.ts +24 -0
- package/dist/plugins/dynamodb/src/streamhandler.d.ts +28 -0
- package/dist/plugins/dynamodb/src/subscriber.d.ts +57 -0
- package/dist/plugins/dynamodb/src/tumbling.d.ts +30 -0
- package/dist/plugins/dynamodb/src/worker.d.ts +1 -0
- package/dist/plugins/dynamodb/src/worker.mjs +1 -0
- package/dist/standalone.js +1 -1
- package/dist/standalone.mjs +1 -1
- package/package.json +2 -2
package/dist/cli/index.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{readFile as
|
|
3
|
-
`),
|
|
2
|
+
import{readFile as D}from"node:fs/promises";import p from"node:path";import{pathToFileURL as I}from"node:url";import{parseArgs as O}from"node:util";import{run as Y}from"exlo";var j="exlo",b="0.0.4";var g=!1,N=e=>{g=e},R=()=>g,a=(e,t)=>{g&&console.log(`\x1B[${e}m${t}\x1B[0m`)},A=e=>console.log(`\x1B[31m${e}\x1B[0m`),$=e=>a("32",e),q=e=>a("33",e),L=e=>a("36",e),S=e=>a("90",e),C=e=>a("94",e),F=e=>a("95",e),_=e=>g?console.log(e):void 0,i={GREEN:$,YELLOW:q,CYAN:L,BR_BLUE:C,RED:A,GREY:S,PINK:F,setDebug:N,getDebug:R,info:_};var x={port:{type:"string",short:"p",default:"0",description:"Lambda server port."},debug:{type:"boolean",default:!1,description:"Enable debug mode. When enabled exlo will print usefull informations."},config:{type:"string",short:"c",description:"Path to exlo 'defineConfig' file."},runtime:{type:"string",short:"r",description:"Lambda default runtime (ex: nodejs22.x, python3.7, ruby2.7 etc.)."},timeout:{type:"string",short:"t",default:"3",description:"Lambda default timeout."},definitions:{type:"string",short:"d",description:"Path to .json, .mjs, .cjs file with Lambda function definitions."},functions:{type:"string",short:"f",multiple:!0,description:"Glob pattern to automatically find and define Lambda handlers."},exclude:{type:"string",short:"X",multiple:!0,default:[".(test|spec)."],description:"RegExp string to exclude found enteries from --functions."},handlerName:{type:"string",default:"handler",description:"Handler function name. To be used with --functions."},env:{type:"string",short:"e",multiple:!0,default:[],description:"Environment variables to be injected into Lambdas. All existing AWS_* are automatically injected.",example:"-e API_KEY=supersecret -e API_URL=https://website.com"},"optimize-build":{type:"boolean",default:!1,description:"externalize dependencies and other stuff"},"shim-require":{type:"boolean",default:!1,description:"shim 'require()', '__dirname' and '__filename' when bundeling Lambdas with ESM format"},help:{type:"boolean",short:"h",skipFullPrint:!0},version:{type:"boolean",short:"v",skipFullPrint:!0},"esbuild-external":{type:"string",multiple:!0,skip:!0},"esbuild-resolveExtensions":{type:"string",multiple:!0,skip:!0},"esbuild-mainFields":{type:"string",multiple:!0,skip:!0},"esbuild-conditions":{type:"string",multiple:!0,skip:!0},"esbuild-entryPoints":{type:"string",multiple:!0,skip:!0},"esbuild-inject":{type:"string",multiple:!0,skip:!0},"esbuild-nodePaths":{type:"string",multiple:!0,skip:!0}};function M(){i.setDebug(!0),i.GREY("Usage examples:"),console.log("exlo -c exlo.config.ts"),console.log(`exlo -p 3000 --debug --functions "src/lambdas/**/*.ts"
|
|
3
|
+
`),i.BR_BLUE("Options:");for(let[e,t]of Object.entries(x)){let n=e;if(t.skip)continue;if(t.short&&(n+=`, -${t.short}`),t.skipFullPrint){i.CYAN(` --${n}
|
|
4
4
|
`);continue}let s=` type: ${t.type}`;t.description&&(s+=`
|
|
5
5
|
description: ${t.description}`),"default"in t&&(s+=`
|
|
6
6
|
default: ${t.default}`),t.example&&(s+=`
|
|
7
7
|
example: ${t.example}`),s+=`
|
|
8
|
-
`,
|
|
9
|
-
description: where 'options' is one of esbuild build options`),
|
|
8
|
+
`,i.CYAN(` --${n}`),i.GREY(s)}i.CYAN(" --esbuild-[option]"),i.GREY(`
|
|
9
|
+
description: where 'options' is one of esbuild build options`),i.GREY(`
|
|
10
10
|
example: exlo --esbuild-external="@aws-sdk/*" --esbuild-external=react --esbuild-format=esm --esbuild-outExtension..js=.mjs --esbuild-outExtension..css=.CSS`),console.log(`
|
|
11
|
-
${j} v${b}`),process.exit(0)}function v(e,t){return!e||Number.isNaN(e)?t:Number(e)}async function P(e){if(e){if(e.endsWith(".js"))throw new Error("Only .json, .mjs and .cjs are supported for --definitions option.");if(e.endsWith(".json"))return JSON.parse(await
|
|
11
|
+
${j} v${b}`),process.exit(0)}function v(e,t){return!e||Number.isNaN(e)?t:Number(e)}async function P(e){if(e){if(e.endsWith(".js"))throw new Error("Only .json, .mjs and .cjs are supported for --definitions option.");if(e.endsWith(".json"))return JSON.parse(await D(e,"utf-8")).functions;if(e.endsWith(".mjs")||e.endsWith(".cjs"))return(await import(I(p.resolve(process.cwd(),e)).href)).functions}}async function G(e,t,n){if(!n)return;let s=Number(process.versions.node.slice(0,process.versions.node.indexOf(".")));if(s<22)throw new Error("--functions option is only supported on Node22 and higher.");let{glob:u}=await import("node:fs/promises"),m={};for await(let l of u(n)){if(e.some(k=>l.match(k)))continue;let f=p.basename(p.dirname(l)),o=p.parse(l),r;o.name=="index"?m[f]?r=l.replaceAll(p.sep,"_"):r=f:m[o.name]?m[`${f}_${o.name}`]?r=l.replaceAll(p.sep,"_"):r=`${f}_${o.name}`:r=o.name,m[r]={name:r,handler:l.replace(o.ext,`.${t}`),runtime:o.ext==".py"?"python3.7":o.ext==".rb"?"ruby2.7":`nodejs${s}.x`}}return m}function W(e){let t={};for(let n of e){let[s,...u]=n.split("=");t[s]=u.join("=")}return t}var{values:d}=O({strict:!1,options:x}),{port:B,config:U,debug:z,help:T,runtime:V,definitions:E,timeout:H,functions:y,handlerName:K,exclude:w,env:J}=d;d.version?(console.log(b),process.exit(0)):T&&M();if(E&&y)throw new Error("Can not use --definitions (-d) and --functions (-f) together.");var Q=Array.isArray(w)?w.filter(e=>typeof e=="string").map(e=>new RegExp(e)):[],X=y?await G(Q,K,y):await P(E),c={};for(let e of Object.keys(d).filter(t=>t.startsWith("esbuild-"))){let t=e.split("esbuild-")[1];if(t.includes(".")){let n=t.indexOf("."),s=t.slice(0,n),u=t.slice(n+1);c[s]||(c[s]={}),c[s][u]=d[e]}else c[t]=d[e]}var Z=d["optimize-build"],ee=d["shim-require"],te={debug:z,config:U,port:v(B,0),functions:X,build:{esbuild:c,optimizeBuild:Z,shimRequire:ee},defaults:{environment:W(J),runtime:V,timeout:v(H,3)}};Y(te);
|
package/dist/defineConfig.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var h="0.0.
|
|
1
|
+
var h="0.0.4";function k(e){let c=new Set;e.plugins&&(e.plugins=e.plugins.filter((i,a)=>typeof i!="object"||!i||!("name"in i)?!1:((!i.name||!i.name.length||typeof i.name!="string")&&(i.name=`plugin-${a}`,console.warn(`No Plugin name provided at index ${a}`)),c.has(i.name)?i.name=i.name+a:c.add(i.name),!0)));async function f({stop:i,lambdas:a,region:g,esbuild:y,getServices:b,setService:d,addLambda:p,log:l,setEndpoint:v,getEndpoint:x,getAwsProviderDefaults:C,setAwsProviderDefaults:S}){let r={build:{esbuild:e?.build?.esbuild??{},shimRequire:e?.build?.shimRequire,optimizeBuild:e?.build?.optimizeBuild},server:{port:e.server?.port},onKill:[]};if(e.defaults&&typeof e.defaults=="object"&&!Array.isArray(e.defaults)&&S(e.defaults),e.functions&&typeof e.functions=="object"&&!Array.isArray(e.functions))for(let[m,s]of Object.entries(e.functions))p(m,s);e.services&&(e.services.sqs&&d("sqs",e.services.sqs),e.services.sns&&d("sns",e.services.sns),e.services.dynamodb&&d("dynamodb",e.services.dynamodb));let o={stop:i,lambdas:a,region:g,esbuild:y,options:e,config:r,getServices:b,setService:d,addLambda:p,log:l,setEndpoint:v,getEndpoint:x,getAwsProviderDefaults:C};if(e.plugins){r.server.onReady=async(s,n)=>{for(let t of e.plugins)if(t.server?.onReady)try{await t.server.onReady.call(o,s,n)}catch(u){l.RED(t.name),console.error(u)}},r.buildCallback=async(s,n)=>{for(let t of e.plugins)if(t.buildCallback)try{await t.buildCallback.call(o,s,n)}catch(u){l.RED(t.name),console.error(u),n||process.exit(1)}};let m=e.plugins.reduce((s,n)=>(n.server?.request?.length&&s.push(...n.server.request),s),[]);m?.length&&(r.server.request=m.map(s=>(s.callback=s.callback.bind(o),s)));for(let s of e.plugins)if(s.onKill&&r.onKill.push(s.onKill.bind(o)),s.onInit)try{await s.onInit.call(o)}catch(n){throw l.RED(s.name),n}}return r}return f.plugins=e.plugins??[],f}export{k as defineConfig,h as exloVersion};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { TumblingWindow } from "./tumbling";
|
|
2
|
+
interface IBatchConfig {
|
|
3
|
+
batchSize: number;
|
|
4
|
+
maximumBatchingWindow: number;
|
|
5
|
+
maximumRecordAgeInSeconds: number;
|
|
6
|
+
onComplete: (batch: Batch, isFinalInvokeForWindow: boolean) => void;
|
|
7
|
+
onRecordExpire?: (DDBStreamBatchInfo: any) => void;
|
|
8
|
+
tumbling?: TumblingWindow;
|
|
9
|
+
}
|
|
10
|
+
export declare class Batch {
|
|
11
|
+
#private;
|
|
12
|
+
maximumRecordAgeInSeconds: number;
|
|
13
|
+
onComplete: (batch: Batch, isFinalInvokeForWindow: boolean) => void;
|
|
14
|
+
onRecordExpire?: (DDBStreamBatchInfo: any) => void;
|
|
15
|
+
records: any[];
|
|
16
|
+
closed: boolean;
|
|
17
|
+
tumbling?: TumblingWindow;
|
|
18
|
+
getStreamEvent: (records?: any[]) => any;
|
|
19
|
+
constructor({ batchSize, maximumBatchingWindow, onComplete, onRecordExpire, maximumRecordAgeInSeconds, tumbling, }: IBatchConfig);
|
|
20
|
+
setRecord(record: any, DDBStreamBatchInfo: any): boolean;
|
|
21
|
+
removeRecord(id: string): void;
|
|
22
|
+
hasRecord(id: string): any;
|
|
23
|
+
}
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface IOnFailureDestinationHandlerMessage {
|
|
2
|
+
requestContext: {
|
|
3
|
+
requestId: string;
|
|
4
|
+
functionArn: string;
|
|
5
|
+
condition: "RetryAttemptsExhausted" | "RecordAgeExceeded";
|
|
6
|
+
approximateInvokeCount: number;
|
|
7
|
+
};
|
|
8
|
+
responseContext: {
|
|
9
|
+
statusCode: number;
|
|
10
|
+
executedVersion: "$LATEST";
|
|
11
|
+
functionError: "Unhandled";
|
|
12
|
+
};
|
|
13
|
+
version: "1.0";
|
|
14
|
+
timestamp: string;
|
|
15
|
+
DDBStreamBatchInfo: {
|
|
16
|
+
shardId: string;
|
|
17
|
+
startSequenceNumber: string;
|
|
18
|
+
endSequenceNumber: string;
|
|
19
|
+
approximateArrivalOfFirstRecord: string;
|
|
20
|
+
approximateArrivalOfLastRecord: string;
|
|
21
|
+
batchSize: number;
|
|
22
|
+
streamArn: string;
|
|
23
|
+
};
|
|
24
|
+
payload?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface IOnFailureDestinationHandler {
|
|
27
|
+
report(message: IOnFailureDestinationHandlerMessage): Promise<void> | void;
|
|
28
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { S3 } from "@aws-sdk/client-s3";
|
|
2
|
+
import type { IOnFailureDestinationHandler, IOnFailureDestinationHandlerMessage } from ".";
|
|
3
|
+
export declare class OnFailureS3Reporter implements IOnFailureDestinationHandler {
|
|
4
|
+
#private;
|
|
5
|
+
bucketArn: string;
|
|
6
|
+
esmId: string;
|
|
7
|
+
getS3Client: () => S3;
|
|
8
|
+
private get client();
|
|
9
|
+
private get bucketName();
|
|
10
|
+
constructor(bucketArn: string, esmId: string, getS3Client: () => S3);
|
|
11
|
+
private createObjectKey;
|
|
12
|
+
report(message: IOnFailureDestinationHandlerMessage): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { SNS } from "@aws-sdk/client-sns";
|
|
2
|
+
import type { IOnFailureDestinationHandler, IOnFailureDestinationHandlerMessage } from ".";
|
|
3
|
+
export declare class OnFailureSnsReporter implements IOnFailureDestinationHandler {
|
|
4
|
+
#private;
|
|
5
|
+
topicArn: string;
|
|
6
|
+
getSnsClient: () => SNS;
|
|
7
|
+
private get client();
|
|
8
|
+
constructor(topicArn: string, getSnsClient: () => SNS);
|
|
9
|
+
report(message: IOnFailureDestinationHandlerMessage): Promise<void>;
|
|
10
|
+
private send;
|
|
11
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { SQS } from "@aws-sdk/client-sqs";
|
|
2
|
+
import type { IOnFailureDestinationHandler, IOnFailureDestinationHandlerMessage } from ".";
|
|
3
|
+
export declare class OnFailureSqsReporter implements IOnFailureDestinationHandler {
|
|
4
|
+
#private;
|
|
5
|
+
queueArn: string;
|
|
6
|
+
getSqsClient: () => SQS;
|
|
7
|
+
private getQueueUrl;
|
|
8
|
+
private get client();
|
|
9
|
+
constructor(queueArn: string, getSqsClient: () => SQS);
|
|
10
|
+
report(message: IOnFailureDestinationHandlerMessage): Promise<void>;
|
|
11
|
+
private send;
|
|
12
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { DynamoDBClientConfig } from "@aws-sdk/client-dynamodb";
|
|
2
|
+
import type { S3 } from "@aws-sdk/client-s3";
|
|
3
|
+
import type { SNS } from "@aws-sdk/client-sns";
|
|
4
|
+
import type { SQS } from "@aws-sdk/client-sqs";
|
|
5
|
+
import type { ExloPlugin } from "exlo/defineConfig";
|
|
6
|
+
export type DynamoDbPluginInstance = ExloPlugin<{
|
|
7
|
+
isReady: boolean;
|
|
8
|
+
onReady: (cb: Function) => void;
|
|
9
|
+
proxyEndpoint?: string;
|
|
10
|
+
}>;
|
|
11
|
+
export interface IDynamoDbPluginConfig {
|
|
12
|
+
dynamoDbClientConfig?: DynamoDBClientConfig;
|
|
13
|
+
/**
|
|
14
|
+
* Set `AWS_ENDPOINT_URL_DYNAMODB` env variable inside lambdas
|
|
15
|
+
* @default true
|
|
16
|
+
*/
|
|
17
|
+
setEndpointEnvVar?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Create a local proxy server for DynamoDB Local.
|
|
20
|
+
* Strongly Recommended as AWS DynamoDB Local has various issues with Streams.
|
|
21
|
+
* @default false
|
|
22
|
+
*/
|
|
23
|
+
proxy?: {
|
|
24
|
+
/**
|
|
25
|
+
* @default 0 (random port)
|
|
26
|
+
*/
|
|
27
|
+
port?: number;
|
|
28
|
+
/**
|
|
29
|
+
* @default 3
|
|
30
|
+
*/
|
|
31
|
+
maxShards?: number;
|
|
32
|
+
/**
|
|
33
|
+
* Set `AWS_ENDPOINT_URL_DYNAMODB_STREAMS` env variable inside lambdas
|
|
34
|
+
* @default true
|
|
35
|
+
*/
|
|
36
|
+
setEndpointEnvVar?: boolean;
|
|
37
|
+
inheritStreamsFromExistingTables?: boolean;
|
|
38
|
+
} | boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Used by On Failure Destinations
|
|
41
|
+
*/
|
|
42
|
+
services?: {
|
|
43
|
+
sns?: SNS;
|
|
44
|
+
sqs?: SQS;
|
|
45
|
+
s3?: S3;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export declare const dynamoDbPlugin: (config?: IDynamoDbPluginConfig) => DynamoDbPluginInstance;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var N=(n=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(n,{get:(t,e)=>(typeof require<"u"?require:t)[e]}):n)(function(n){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+n+'" is not supported')});import L from"node:path";import{Worker as _}from"node:worker_threads";import k from"node:path";import{createRequire as O}from"node:module";var f=N,g={};function A(n){if(g[n])return g[n];if(typeof f=="function"&&typeof f.resolve=="function"){let e=k.resolve(f.resolve(n),"../../");return g[n]=e,e}f=O(new URL(".",import.meta.url));let t=k.resolve(f.resolve(n),"../../");return g[n]=t,t}import{randomUUID as H}from"node:crypto";import $ from"node:events";import{EventSourceMapping as Q}from"exlo/internal/esm";var y=class{#e;#t;maximumRecordAgeInSeconds;onComplete;onRecordExpire;records=[];closed=!1;tumbling;#n={};#i;getStreamEvent;constructor({batchSize:t,maximumBatchingWindow:e,onComplete:i,onRecordExpire:s,maximumRecordAgeInSeconds:o,tumbling:r}){this.maximumRecordAgeInSeconds=o,this.#e=t,this.#t=e,this.onComplete=i,this.onRecordExpire=s,this.tumbling=r,this.tumbling?(this.getStreamEvent=a=>this.tumbling.getTimeWindowEvent(a??this.records),this.tumbling.onComplete||(this.tumbling.onComplete=()=>{this.onComplete(this,!0)})):this.getStreamEvent=a=>({Records:a??this.records})}#s(){this.records.length==this.#e&&(this.closed=!0,clearTimeout(this.#i),this.onComplete(this,!1))}setRecord(t,e){return this.closed?!1:(this.records.push(t),this.#s(),this.#r(t.eventID,e),this.records.length==1&&(this.#i=setTimeout(()=>{this.closed||(this.closed=!0,this.onComplete(this,!1))},this.#t).unref()),!0)}removeRecord(t){let e=this.records.findIndex(i=>i.eventID==t);e!=-1&&(clearTimeout(this.#n[t]),this.records.splice(e,1))}hasRecord(t){return this.records.find(e=>e.eventID==t)}#r(t,e){this.#n[t]=setTimeout(()=>{let i=this.records.findIndex(s=>s.eventID==t);i!=-1&&(this.records.splice(i,1),this.onRecordExpire&&this.onRecordExpire(e))},this.maximumRecordAgeInSeconds).unref()}};var W=n=>typeof n=="string"&&n.length,C=(n,t)=>{if(!(typeof t>"u"||t===null||typeof t=="object"&&(t.batchItemFailures===null||Array.isArray(t.batchItemFailures)&&!t.batchItemFailures.length))&&typeof t=="object"&&Array.isArray(t.batchItemFailures)){if(t.batchItemFailures.some(s=>!s.itemIdentifier||!W(s.itemIdentifier)||!n.find(o=>o.eventID==s.itemIdentifier)))throw new Error("ReportBatchItemFailures: complete failure.");let e=[],i=[];for(let s of n)t.batchItemFailures.find(r=>r.itemIdentifier==s.eventID)?i.push(s):e.push(s.eventID);return{success:e,failures:i}}};import{randomUUID as M}from"node:crypto";var S=class{constructor(t,e,i){this.bucketArn=t;this.esmId=e;this.getS3Client=i}#e;get client(){return this.#e||(this.#e=this.getS3Client()),this.#e}#t;get bucketName(){return this.#t||(this.#t=this.bucketArn.split(":")[5]),this.#t}createObjectKey(t){let[e,i]=new Date().toISOString().split("T"),[s,o,r]=e.split("-"),[a,c,d]=i.split(":");return`aws/lambda/${this.esmId}/${t}/${s}/${o}/${r}/${e}T${a}.${c}.${d}-${M()}`}async report(t){await this.client.putObject({Bucket:this.bucketName,Key:this.createObjectKey(t.DDBStreamBatchInfo.shardId),Body:JSON.stringify(t)})}};var w=class{constructor(t,e){this.topicArn=t;this.getSnsClient=e}#e;get client(){return this.#e||(this.#e=this.getSnsClient()),this.#e}async report(t){let e={...t,payload:void 0};await this.send(e)}async send(t){return this.client.publish({TopicArn:this.topicArn,Message:JSON.stringify(t)})}};var I=class{constructor(t,e){this.queueArn=t;this.getSqsClient=e}#e;#t;async getQueueUrl(){if(!this.#e){let e=this.queueArn.split(":")[5],i=await this.client.getQueueUrl({QueueName:e});this.#e=i.QueueUrl}return this.#e}get client(){return this.#t||(this.#t=this.getSqsClient()),this.#t}async report(t){let e={...t,payload:void 0};await this.send(e)}async send(t){return this.client.sendMessage({QueueUrl:await this.getQueueUrl(),MessageBody:JSON.stringify(t)})}};var q=n=>n&&!Array.isArray(n)&&Object.keys(n).length,x=class{shardId;eventSourceARN;window={start:"",end:""};state={};isFinalInvokeForWindow=!1;isWindowTerminatedEarly=!1;onComplete;constructor({shardId:t,eventSourceARN:e,tumblingWindowInSeconds:i}){this.shardId=t,this.eventSourceARN=e;let s=new Date;this.window.start=s.toISOString(),s.setSeconds(s.getSeconds()+i),this.window.end=s.toISOString(),setTimeout(()=>{this.isFinalInvokeForWindow=!0,this.onComplete?.()},i*1e3).unref()}setState(t){if(q(t))return this.isFinalInvokeForWindow||(this.state=t),this;throw new Error("Invalide state object")}getTimeWindowEvent(t){return{Records:t,window:this.window,state:this.state,shardId:this.shardId,eventSourceARN:this.eventSourceARN,isFinalInvokeForWindow:this.isFinalInvokeForWindow,isWindowTerminatedEarly:this.isWindowTerminatedEarly}}};var B=n=>new Promise(t=>setTimeout(t,n*1e3).unref()),U=86400*1e3,F=class extends Q{init(){}enable(){}disable(){}},v=class n extends ${constructor(e,i,s,o,r,a){super();this.getAwsServices=o;this.region=r;this.accountId=a;this.event=e,this.lambdaName=s,this.TableName=e.TableName,this.enabled=e.enabled,this.startingPosition=e.startingPosition,this.invoke=i,this.batchSize=e.batchSize,this.functionResponseType=e.functionResponseType,this.filterPatterns=e.filterPatterns,this.bisectBatchOnFunctionError=e.bisectBatchOnFunctionError,this.tumblingWindowInSeconds=e.tumblingWindowInSeconds,this.maximumRetryAttempts=e.maximumRetryAttempts,e.maximumRecordAgeInSeconds&&(this.maximumRecordAgeInSeconds=e.maximumRecordAgeInSeconds*1e3),!e.maximumBatchingWindow||Number.isNaN(e.maximumBatchingWindow)||e.maximumBatchingWindow==-1?this.maximumBatchingWindow=0:this.maximumBatchingWindow=e.maximumBatchingWindow*1e3;let c;if(Array.isArray(this.filterPatterns)){c=[];for(let d of this.filterPatterns)c.push({Pattern:JSON.stringify(d)});c.length||(c=void 0)}this.#n=new F({BatchSize:this.batchSize,Enabled:this.enabled,EventSourceArn:"",FunctionName:this.lambdaName,FilterCriteria:c?{Filters:c}:void 0}),typeof e.onFailureDestination=="string"&&(this.setFailureHandler(e.onFailureDestination),this.#n.config.DestinationConfig={OnFailure:{Destination:e.onFailureDestination}}),this.on("invoke",(d,m)=>{let p=this.#e.find(l=>!l.closed),R=p?.setRecord(d,m);if(!p||!R){let l=new y({batchSize:this.batchSize,maximumBatchingWindow:this.maximumBatchingWindow,maximumRecordAgeInSeconds:this.maximumRecordAgeInSeconds,tumbling:this.#a(m),onComplete:async(u,T)=>{n.invokationLog(this.TableName,this.lambdaName);let{error:h}=await this.callLambda(u);if(h&&await this.#i(u,m),T){let E=this.#e.findIndex(b=>b==u);if(E!=-1){let b=this.#t.findIndex(P=>P==this.#e[E].tumbling);b!=-1&&this.#t.splice(b,1),this.#e.splice(E,1)}}},onRecordExpire:this.failure?()=>{this.failure.report(this.createFailureMessage({totalRetry:1,condition:"RecordAgeExceeded",DDBStreamBatchInfo:m}))}:void 0});this.#e.push(l),l.setRecord(d,m)}})}lambdaName;TableName;enabled;startingPosition;invoke;batchSize;maximumBatchingWindow;maximumRetryAttempts;maximumRecordAgeInSeconds=U;bisectBatchOnFunctionError;tumblingWindowInSeconds;functionResponseType;filterPatterns;failure;event;#e=[];#t=[];#n;static invokationLog=process.env.SLS_DEGUG=="*"?(e,i)=>console.log(`\x1B[35mDynamoDB Stream:\x1B[0m \x1B[94m${e}\x1B[0m \x1B[35m|||/\x1B[0m \x1B[33m${i}\x1B[0m`):(e,i)=>{};setFailureHandler(e){let i=this,[s,o,r]=e.split(":");switch(r){case"sns":this.failure=new w(e,()=>{let a=i.getAwsServices().sns;if(!a)throw new Error("Dont know how to send SNS message without SNS client. Use SNS Plugin or provide SNS client in DynamoDB Plugin options. Make sure target SNS Topic exists.");return a});break;case"sqs":this.failure=new I(e,()=>{let a=i.getAwsServices().sqs;if(!a)throw new Error("Dont know how to send SQS message without SQS client. Use SQS Plugin or provide SQS client in DynamoDB Plugin options. Make sure target SQS Queue exists.");return a});break;case"s3":this.failure=new S(e,this.#n.UUID,()=>{let a=i.getAwsServices().s3;if(!a)throw new Error("Dont know how to store S3 Object without S3 client. Use S3 Plugin or provide S3 client in DynamoDB Plugin options. Make sure target S3 Bucket exists.");return a});break;default:throw new Error(`Invalid onFailureDestination ARN: ${e}. Service must be sns, sqs or s3`)}}setRecords=async(e,i)=>{let[s,o]=this.#n.filterRecords(e);for(let r of s)this.emit("invoke",r,i)};async callLambda(e,i){let s={},o=e.getStreamEvent(i);try{let r=await this.invoke(o,{kind:"ddb",event:this.event});if(this.tumblingWindowInSeconds&&e.tumbling.setState(r.state),this.functionResponseType=="ReportBatchItemFailures"){let a=C(e.records,r);if(a){let{success:c,failures:d}=a;for(let m of c)e.removeRecord(m);d.length&&(s.error=new Error("has failed items"))}else for(let c of e.records)e.removeRecord(c.eventID)}else for(let a of e.records)e.removeRecord(a.eventID)}catch(r){s.error=r}return s}async#i(e,i){if(this.maximumRetryAttempts)return this.#r(e,i);this.#s(e)}async#s(e){for(;e.records.length;)console.log(`\x1B[35mDynamoDB Stream retry until record expires!: ${this.TableName} |||/ ${this.lambdaName}\x1B[0m`),await this.callLambda(e),await B(.6)}async#r(e,i){let s=0;for(;s<=this.maximumRetryAttempts-1;){s++;let o=[e.records];if(this.bisectBatchOnFunctionError){let r=Math.ceil(e.records.length/2);o=this.#o(e.records,r)}console.log(`\x1B[35mDynamoDB Stream retry n\xB0${s}: ${this.TableName} |||/ ${this.lambdaName}\x1B[0m`);for(let r of o)await this.callLambda(e,r);if(!e.records.length)break;await B(.6)}if(this.failure&&e.records.length){let o={Records:e.records.slice()};for(let r of e.records)e.removeRecord(r.eventID);await this.failure.report(this.createFailureMessage({totalRetry:s,condition:"RetryAttemptsExhausted",DDBStreamBatchInfo:i,payload:o}))}}createFailureMessage({totalRetry:e,payload:i,DDBStreamBatchInfo:s,condition:o}){return{requestContext:{approximateInvokeCount:e,condition:o,functionArn:`arn:aws:lambda:${this.region}:${this.accountId}:function:${this.lambdaName}`,requestId:H()},timestamp:new Date().toISOString(),version:"1.0",responseContext:{executedVersion:"$LATEST",functionError:"Unhandled",statusCode:200},DDBStreamBatchInfo:s,payload:i?JSON.stringify(i):void 0}}#o(e,i){let s=[];for(let o=0;o<e.length;o+=i){let r=e.slice(o,o+i);s.push(r)}return s}#a=({shardId:e,streamArn:i})=>{if(this.tumblingWindowInSeconds){let s=this.#t.find(r=>!r.isFinalInvokeForWindow&&r.shardId==e);if(s)return s;let o=new x({shardId:e,eventSourceARN:i,tumblingWindowInSeconds:this.tumblingWindowInSeconds});return this.#t.push(o),o}}};var D=class{constructor(t,e,i,s){this.getAwsServices=e;this.region=i;this.accountId=s;this.#e=t,this.getSlsDeclarations(),this.getListenableTables()}subscribers=[];#e=[];listenableTables=[];getSlsDeclarations=()=>{for(let t of this.#e){let e=t.ddb;if(e.length)for(let i of e){let s=new v(i,t.invoke,t.name,this.getAwsServices,this.region,this.accountId);this.subscribers.push(s)}}};getListenableTables=()=>{for(let t of this.subscribers){let{TableName:e,enabled:i,startingPosition:s}=t,o=this.listenableTables.findIndex(r=>r.TableName==e);if(i){let r={TableName:e,startingPosition:s};s&&(r.startingPosition=s),o==-1?this.listenableTables.push(r):this.listenableTables[o]={...this.listenableTables[o],...r}}}};setRecords=({records:t,TableName:e,DDBStreamBatchInfo:i})=>{for(let s of this.subscribers)s.TableName==e&&s.setRecords(t,i)}};async function V(n){let{startProxy:t}=await import("exlo/dynamodbProxy"),[e,i]=await t(n);return e.unref(),i}var we=n=>{let t,e,i=[],s=async()=>{o.shared.isReady=!0;for(let r of i)await r()},o={name:"ddblocal-stream",shared:{isReady:!1,onReady:r=>{typeof r=="function"?i.push(r):console.warn("onReady callback must be a function")}},onInit:async function(){let{region:r,accountId:a}=this.getAwsProviderDefaults(),c={endpoint:"http://localhost:8000",region:r,credentials:{accessKeyId:"test",secretAccessKey:"test"}},d=n?.dynamoDbClientConfig??c,m;if(n?.proxy){let l={dynamoDbLocalClientConfig:d,region:r,accountId:a},u=!0;typeof n?.proxy=="object"&&(typeof n.proxy.setEndpointEnvVar=="boolean"&&(u=n.proxy.setEndpointEnvVar),typeof n.proxy.port=="number"&&(l.proxyPort=n.proxy.port),typeof n.proxy.maxShards=="number"&&(l.maxShards=n.proxy.maxShards),typeof n.proxy.inheritStreamsFromExistingTables=="boolean"&&(l.inheritStreamsFromExistingTables=n.proxy.inheritStreamsFromExistingTables));let h=`http://localhost:${await V(l)}`;this.setEndpoint("dynamodb_streams",h,u?"AWS_ENDPOINT_URL_DYNAMODB_STREAMS":void 0),o.shared.proxyEndpoint=h,m=h}else m=d.endpoint;let p=this;t=new D(this.lambdas,()=>{let l={...p.getServices()};return n?.services&&(n.services.s3&&(l.s3=n.services.s3),n.services.sns&&(l.sns=n.services.sns),n.services.sqs&&(l.sqs=n.services.sqs)),l},r,a);let R=L.join(A("exlo"),"dist/plugins/dynamodb/src/worker.mjs");if(e=new _(R,{name:"dynamodb-streams",workerData:{clientConfig:{...d,endpoint:m}}}),e.unref(),e.on("message",async l=>{l.channel=="ready"?await s():t.setRecords(l)}),typeof m=="string"){let l=typeof n?.setEndpointEnvVar=="boolean"?n.setEndpointEnvVar:!0;this.setEndpoint("dynamodb",m,l?"AWS_ENDPOINT_URL_DYNAMODB":void 0)}},onKill(){e?.terminate()},server:{async onReady(r){return e?.postMessage({channel:"init",tables:t.listenableTables}),new Promise(a=>{i.unshift(a)})}}};return o};export{we as dynamoDbPlugin};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function calculateItemSizeInBytes(item: any): number;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare class DynamoDbDateTime {
|
|
2
|
+
#private;
|
|
3
|
+
constructor(fromDate?: Date);
|
|
4
|
+
getRawValue(): Date;
|
|
5
|
+
eq(other: DynamoDbDateTime): boolean;
|
|
6
|
+
gt(other: DynamoDbDateTime): boolean;
|
|
7
|
+
gte(other: DynamoDbDateTime): boolean;
|
|
8
|
+
lt(other: DynamoDbDateTime): boolean;
|
|
9
|
+
lte(other: DynamoDbDateTime): boolean;
|
|
10
|
+
toISOString(): string;
|
|
11
|
+
getTime(): number;
|
|
12
|
+
toJSON(): number;
|
|
13
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Worker } from "node:worker_threads";
|
|
2
|
+
import type { DynamoDBClientConfig } from "@aws-sdk/client-dynamodb";
|
|
3
|
+
export interface IDynamoDbProxyServerConfig {
|
|
4
|
+
dynamoDbLocalClientConfig: DynamoDBClientConfig;
|
|
5
|
+
/**
|
|
6
|
+
* @default 0 (random port)
|
|
7
|
+
*/
|
|
8
|
+
proxyPort?: number;
|
|
9
|
+
/**
|
|
10
|
+
* @default 3
|
|
11
|
+
*/
|
|
12
|
+
maxShards?: number;
|
|
13
|
+
region?: string;
|
|
14
|
+
accountId?: string;
|
|
15
|
+
inheritStreamsFromExistingTables?: boolean;
|
|
16
|
+
}
|
|
17
|
+
export declare function startProxy(config: IDynamoDbProxyServerConfig): Promise<[Worker, number]>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var i=(r=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(r,{get:(e,o)=>(typeof require<"u"?require:e)[o]}):r)(function(r){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+r+'" is not supported')});import f from"node:path";import{Worker as y}from"node:worker_threads";import s from"node:path";import{createRequire as l}from"node:module";var n=i,t={};function m(r){if(t[r])return t[r];if(typeof n=="function"&&typeof n.resolve=="function"){let o=s.resolve(n.resolve(r),"../../");return t[r]=o,o}n=l(new URL(".",import.meta.url));let e=s.resolve(n.resolve(r),"../../");return t[r]=e,e}var d=f.join(m("exlo"),"dist/plugins/dynamodb/src/proxy/worker.mjs");async function h(r){return new Promise(e=>{let o=new y(d,{name:"dynamodb-proxy",workerData:r});o.on("message",({proxyPort:a})=>{e([o,a])})})}export{h as startProxy};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { type IncomingMessage, type Server, type ServerResponse } from "node:http";
|
|
2
|
+
import type { DynamoDB } from "@aws-sdk/client-dynamodb";
|
|
3
|
+
import { type IStreamDescription, ProxyDynamoStream } from "./proxyDynamoStream";
|
|
4
|
+
export declare class ProxyDynamoDbServer {
|
|
5
|
+
client: DynamoDB;
|
|
6
|
+
proxyPort: number;
|
|
7
|
+
maxShards: number;
|
|
8
|
+
inheritStreamsFromExistingTables: boolean;
|
|
9
|
+
accountId: string;
|
|
10
|
+
region: string;
|
|
11
|
+
private static collectBuffer;
|
|
12
|
+
private static collectBody;
|
|
13
|
+
private static collectJsonObjectOrReturnError;
|
|
14
|
+
private redirect;
|
|
15
|
+
private safeReturnThrownError;
|
|
16
|
+
private dynamoDbLocalEndpoint;
|
|
17
|
+
server?: Server;
|
|
18
|
+
streams: ProxyDynamoStream[];
|
|
19
|
+
itemsWithTTL: Record<string, {
|
|
20
|
+
keySchema: IStreamDescription["KeySchema"];
|
|
21
|
+
ttlFieldName: string;
|
|
22
|
+
enabled: boolean;
|
|
23
|
+
items: Map<string, {
|
|
24
|
+
ttl: number;
|
|
25
|
+
oldImage: any;
|
|
26
|
+
key: any;
|
|
27
|
+
}>;
|
|
28
|
+
}>;
|
|
29
|
+
getStreamByTableName(TableName: string): ProxyDynamoStream | undefined;
|
|
30
|
+
private getTableKeySchemaAttributeNames;
|
|
31
|
+
getStreamByArn(StreamArn: string): ProxyDynamoStream | undefined;
|
|
32
|
+
private trackTTLRecord;
|
|
33
|
+
setRecord(TableName: string, NewImage: any, OldImage: any, isTTL?: boolean): void;
|
|
34
|
+
private getBodyIfJsonObject;
|
|
35
|
+
private static isValidStreamArn;
|
|
36
|
+
private static isValidShardIteratorType;
|
|
37
|
+
constructor(client: DynamoDB, proxyPort?: number, maxShards?: number, inheritStreamsFromExistingTables?: boolean, accountId?: string, region?: string);
|
|
38
|
+
GetRecords(req: IncomingMessage, res: ServerResponse): Promise<void>;
|
|
39
|
+
GetShardIterator(req: IncomingMessage, res: ServerResponse): Promise<void>;
|
|
40
|
+
ListStreams(req: IncomingMessage, res: ServerResponse): Promise<void>;
|
|
41
|
+
DescribeStream(req: IncomingMessage, res: ServerResponse): Promise<void>;
|
|
42
|
+
CreateTable(req: IncomingMessage, res: ServerResponse): Promise<void>;
|
|
43
|
+
DeleteTable(req: IncomingMessage, res: ServerResponse): Promise<void>;
|
|
44
|
+
UpdateTable(req: IncomingMessage, res: ServerResponse): Promise<void>;
|
|
45
|
+
UpdateTimeToLive(req: IncomingMessage, res: ServerResponse): Promise<void>;
|
|
46
|
+
PutItem(req: IncomingMessage, res: ServerResponse): Promise<void>;
|
|
47
|
+
DeleteItem(req: IncomingMessage, res: ServerResponse): Promise<void>;
|
|
48
|
+
UpdateItem(req: IncomingMessage, res: ServerResponse): Promise<void>;
|
|
49
|
+
private safeBatchGetItems;
|
|
50
|
+
BatchWriteItem(req: IncomingMessage, res: ServerResponse): Promise<void>;
|
|
51
|
+
TransactWriteItems(req: IncomingMessage, res: ServerResponse): Promise<void>;
|
|
52
|
+
private setDynamoDbLocalEndpoint;
|
|
53
|
+
private inheritStreams;
|
|
54
|
+
private watchTTL;
|
|
55
|
+
init(): Promise<number>;
|
|
56
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { DynamoDbDateTime } from "./dynamoDbDateTime";
|
|
2
|
+
import { SequenceNumber } from "./sequenceNumber";
|
|
3
|
+
interface IProxyRecord {
|
|
4
|
+
awsRegion: string;
|
|
5
|
+
dynamodb: {
|
|
6
|
+
ApproximateCreationDateTime: DynamoDbDateTime;
|
|
7
|
+
Keys: Record<string, any>;
|
|
8
|
+
NewImage: any;
|
|
9
|
+
OldImage: any;
|
|
10
|
+
SequenceNumber: SequenceNumber;
|
|
11
|
+
SizeBytes: number;
|
|
12
|
+
StreamViewType: "NEW_IMAGE" | "OLD_IMAGE" | "NEW_AND_OLD_IMAGES" | "KEYS_ONLY";
|
|
13
|
+
};
|
|
14
|
+
eventID: string;
|
|
15
|
+
eventName: "INSERT" | "MODIFY" | "REMOVE";
|
|
16
|
+
eventSource: string;
|
|
17
|
+
eventVersion: string;
|
|
18
|
+
userIdentity?: {
|
|
19
|
+
type: "Service";
|
|
20
|
+
principalId: "dynamodb.amazonaws.com";
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export declare class ProxyShardIterator {
|
|
24
|
+
shardId: string;
|
|
25
|
+
iteratorType: "TRIM_HORIZON" | "LATEST" | "AT_SEQUENCE_NUMBER" | "AFTER_SEQUENCE_NUMBER";
|
|
26
|
+
position: number;
|
|
27
|
+
expires: Date;
|
|
28
|
+
constructor(shardId: string, iteratorType: "TRIM_HORIZON" | "LATEST" | "AT_SEQUENCE_NUMBER" | "AFTER_SEQUENCE_NUMBER", position: number, expires: Date);
|
|
29
|
+
static fromString(stringValue: string): ProxyShardIterator;
|
|
30
|
+
isExpired(): boolean;
|
|
31
|
+
toString(): string;
|
|
32
|
+
}
|
|
33
|
+
export declare class ProxyDynamoShard {
|
|
34
|
+
#private;
|
|
35
|
+
ParentShardId?: string;
|
|
36
|
+
SequenceNumberRange: {
|
|
37
|
+
EndingSequenceNumber?: string;
|
|
38
|
+
StartingSequenceNumber?: SequenceNumber;
|
|
39
|
+
};
|
|
40
|
+
ShardId: string;
|
|
41
|
+
constructor(id: number);
|
|
42
|
+
getId(): number;
|
|
43
|
+
setRecord(record: IProxyRecord): void;
|
|
44
|
+
get records(): IProxyRecord[];
|
|
45
|
+
getRecords(iterator: ProxyShardIterator, limit?: number): {
|
|
46
|
+
Records: IProxyRecord[];
|
|
47
|
+
nextIterator: ProxyShardIterator | null;
|
|
48
|
+
};
|
|
49
|
+
getIterator(shardIteratorType: "TRIM_HORIZON" | "LATEST" | "AT_SEQUENCE_NUMBER" | "AFTER_SEQUENCE_NUMBER", sequenceNumber?: SequenceNumber): ProxyShardIterator;
|
|
50
|
+
}
|
|
51
|
+
export interface IStreamDescription {
|
|
52
|
+
CreationRequestDateTime: DynamoDbDateTime;
|
|
53
|
+
KeySchema: {
|
|
54
|
+
AttributeName: string;
|
|
55
|
+
KeyType: "HASH" | "RANGE";
|
|
56
|
+
}[];
|
|
57
|
+
LastEvaluatedShardId?: string;
|
|
58
|
+
Shards: ProxyDynamoShard[];
|
|
59
|
+
StreamArn: string;
|
|
60
|
+
StreamLabel: string;
|
|
61
|
+
StreamStatus: "ENABLING" | "ENABLED" | "DISABLING" | "DISABLED";
|
|
62
|
+
StreamViewType: "NEW_IMAGE" | "OLD_IMAGE" | "NEW_AND_OLD_IMAGES" | "KEYS_ONLY";
|
|
63
|
+
TableName: string;
|
|
64
|
+
}
|
|
65
|
+
export declare class ProxyDynamoStream {
|
|
66
|
+
#private;
|
|
67
|
+
TableName: string;
|
|
68
|
+
StreamDescription: IStreamDescription;
|
|
69
|
+
TableArn: string;
|
|
70
|
+
get maxShards(): number;
|
|
71
|
+
constructor(TableName: string, StreamViewType: IStreamDescription["StreamViewType"], KeySchema: IStreamDescription["KeySchema"], maxShards: number, accountId?: string, region?: string);
|
|
72
|
+
findShardByHashId(id: number): ProxyDynamoShard;
|
|
73
|
+
setRecord(newImage: any, oldImage: any, isTTL: boolean): void;
|
|
74
|
+
getShardById(ShardId: string): ProxyDynamoShard | undefined;
|
|
75
|
+
}
|
|
76
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare class SequenceNumber {
|
|
2
|
+
#private;
|
|
3
|
+
static create(): SequenceNumber;
|
|
4
|
+
static createFromString(stringValue: string): SequenceNumber;
|
|
5
|
+
constructor(v: bigint);
|
|
6
|
+
getRawValue(): bigint;
|
|
7
|
+
plusplus(): void;
|
|
8
|
+
dup(): SequenceNumber;
|
|
9
|
+
eq(other: SequenceNumber): boolean;
|
|
10
|
+
gt(other: SequenceNumber): boolean;
|
|
11
|
+
gte(other: SequenceNumber): boolean;
|
|
12
|
+
lt(other: SequenceNumber): boolean;
|
|
13
|
+
lte(other: SequenceNumber): boolean;
|
|
14
|
+
toJSON(): string;
|
|
15
|
+
toString(): string;
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{parentPort as H,workerData as b}from"node:worker_threads";import{DynamoDB as Q}from"@aws-sdk/client-dynamodb";import D,{createServer as W}from"node:http";import{isDeepStrictEqual as w}from"node:util";import{EventSourceMapping as he}from"exlo/internal/esm";import{EventSourceMapping as ae}from"exlo/internal/esm";var g=c=>Object.prototype.toString.call(c)=="[object Object]";import{randomUUID as q}from"node:crypto";var A=new TextEncoder;function O(c){if(!c)return 0;let t=0,e={};for(let a in c){if(!c.hasOwnProperty(a))continue;let n={sizeOfName:A.encode(a).length,attributeSize:_(c[a])};n.total=n.sizeOfName+n.attributeSize,t+=n.total,e[a]=n}return t}function _(c){if(!c)return 0;if(c.hasOwnProperty("B"))return atob(c.B).length;if(c.hasOwnProperty("S"))return A.encode(c.S).length;if(c.hasOwnProperty("N"))return C(c.N);if(c.hasOwnProperty("BS")){let t=0;for(let e=0;e<c.BS.length;e++)t+=atob(c.BS[e]).length;return t}if(c.hasOwnProperty("SS")){let t=0;for(let e=0;e<c.SS.length;e++)t+=A.encode(c.SS[e]).length;return t}if(c.hasOwnProperty("NS")){let t=0;for(let e=0;e<c.NS.length;e++)t+=C(c.NS[e]);return t}if(c.hasOwnProperty("BOOL")||c.hasOwnProperty("NULL"))return 1;if(c.hasOwnProperty("M")){let t=3;for(let e in c.M)c.M.hasOwnProperty(e)&&(t+=A.encode(e).length,t+=_(c.M[e]),t+=1);return t}if(c.hasOwnProperty("L")){let t=3;for(let e=0;e<c.L.length;e++)t+=_(c.L[e]),t+=1;return t}throw`unknown data type in ${JSON.stringify(c)}`}var x=class{value=0;rawValue;constructor(t){this.rawValue=t,this.value=Number(t)}toFixed(){return this.rawValue.split(".")[0]}};function C(c){let t=new x(c);if(t.value==0)return 1;let e=t.toFixed(),a=U(e.replace("-",""))+1;return e.startsWith("-")&&a++,a>21&&(a=21),a}function U(c){if(c.indexOf(".")!==-1){let t=c.split("."),e=t[0],a=t[1];return e==="0"&&(e="",a=V(a,!0)),e.length%2!==0&&(e=`Z${e}`),a.length%2!==0&&(a=`${a}Z`),U(e+a)}return c=V(c,!0,!0),Math.ceil(c.length/2)}function V(c,t,e){for(;t;){let a=c.replace(/^(0{2})/,"");if(a.length==c.length)break;c=a}for(;e;){let a=c.replace(/(0{2})$/,"");if(a.length==c.length)break;c=a}return c}var R=class{#e;constructor(t=new Date){this.#e=t}getRawValue(){return this.#e}eq(t){return this.#e==t.getRawValue()}gt(t){return this.#e>t.getRawValue()}gte(t){return this.#e>=t.getRawValue()}lt(t){return this.#e<t.getRawValue()}lte(t){return this.#e<=t.getRawValue()}toISOString(){return this.#e.toISOString()}getTime(){return this.#e.getTime()}toJSON(){return this.#e.getTime()/1e3}};var T=class c{static create(){return new c(BigInt("100000000000000000000000"))}static createFromString(t){return new c(BigInt(t))}#e;constructor(t){this.#e=t}getRawValue(){return this.#e}plusplus(){this.#e++}dup(){return new c(this.#e)}eq(t){return this.#e==t.getRawValue()}gt(t){return this.#e>t.getRawValue()}gte(t){return this.#e>=t.getRawValue()}lt(t){return this.#e<t.getRawValue()}lte(t){return this.#e<=t.getRawValue()}toJSON(){return this.#e.toString()}toString(){return this.#e.toString()}};var v=class c{constructor(t,e,a,n){this.shardId=t;this.iteratorType=e;this.position=a;this.expires=n}static fromString(t){let e=JSON.parse(Buffer.from(t,"base64").toString("utf-8")),{shardId:a,position:n,expires:i,iteratorType:r}=e;return new c(a,r,n,new Date(i))}isExpired(){return new Date>this.expires}toString(){let t=JSON.stringify({shardId:this.shardId,iteratorType:this.iteratorType,position:this.position,expires:this.expires});return Buffer.from(t,"utf-8").toString("base64")}},B=class{ParentShardId;SequenceNumberRange;ShardId;#e=[];#t;constructor(t){this.#t=t,this.ShardId=`shardId-${q()}`,this.SequenceNumberRange={}}getId(){return this.#t}setRecord(t){this.SequenceNumberRange.StartingSequenceNumber||(this.SequenceNumberRange.StartingSequenceNumber=t.dynamodb.SequenceNumber),this.#e.push(t)}get records(){return this.#e}getRecords(t,e=1e3){let a=this.#e.slice(t.position,t.position+e),n=null,i=t.position+a.length;return n=this.getIterator("LATEST"),n.iteratorType=t.iteratorType,n.position=i,this.SequenceNumberRange.EndingSequenceNumber&&!this.#e[i]&&(n=null),{Records:a,nextIterator:n}}getIterator(t,e){let a;if(t=="TRIM_HORIZON")a=0;else if(t=="LATEST")a=this.#e.length;else if(e){let n=this.#e.findIndex(i=>i.dynamodb.SequenceNumber.eq(e));n==-1?a=this.#e.length+1:t=="AT_SEQUENCE_NUMBER"?a=n:a=n+1}else throw new Error("SequenceNumber is requied for this shardIteratorType");return new v(this.ShardId,t,a,new Date)}},E=class{constructor(t,e,a,n,i="123456789012",r="us-east-1"){this.TableName=t;this.#t=n,this.#n=i,this.#a=r;let o=new R,s=o.toISOString();s=s.split("Z")[0],this.#e=T.create(),this.TableArn=`arn:aws:dynamodb:${r}:${i}:table/${t}`,this.StreamDescription={CreationRequestDateTime:o,KeySchema:a,Shards:[],StreamArn:`${this.TableArn}/stream/${s}`,StreamStatus:"ENABLED",StreamViewType:e,StreamLabel:s,TableName:t};for(let d=1;d<=n;d++)this.StreamDescription.Shards.push(new B(d))}StreamDescription;TableArn;#e;#t;#a;#n;get maxShards(){return this.#t}findShardByHashId(t){let e=this.StreamDescription.Shards.find(n=>n.getId()==t);if(e)return e;let a=new B(t);return this.StreamDescription.Shards.push(a),a}setRecord(t,e,a){let n=this.#a,i=q().replaceAll("-",""),r="1.1",o="aws:dynamodb",s;t&&e?s="MODIFY":t?s="INSERT":s="REMOVE";let d=t??e,u={},m={};for(let{AttributeName:M,KeyType:J}of this.StreamDescription.KeySchema)u[M]=d[M],J=="HASH"&&(m=u[M]);this.#e.plusplus();let h=this.#e.dup(),l=["NEW_IMAGE","NEW_AND_OLD_IMAGES"].includes(this.StreamDescription.StreamViewType)?t:void 0,f=["OLD_IMAGE","NEW_AND_OLD_IMAGES"].includes(this.StreamDescription.StreamViewType)?e:void 0,y=O(l)+O(f)+O(u),I={ApproximateCreationDateTime:new R,Keys:u,NewImage:l,OldImage:f,SequenceNumber:h,SizeBytes:y,StreamViewType:this.StreamDescription.StreamViewType},N={awsRegion:n,dynamodb:I,eventID:i,eventName:s,eventSource:o,eventVersion:r};a&&(N.userIdentity={type:"Service",principalId:"dynamodb.amazonaws.com"});let S=m.S??m.N??m.B,p=k(S,this.maxShards);this.findShardByHashId(p).setRecord(N)}getShardById(t){return this.StreamDescription.Shards.find(e=>e.ShardId==t)}};function $(c){let t=0;for(let e=0;e<c.length;e++)t=t*31+c.charCodeAt(e)>>>0;return t}function k(c,t=3){let a=$(c)%t;return a==0?1:a}var L=class c{constructor(t,e=0,a=3,n=!1,i="123456789012",r="us-east-1"){this.client=t;this.proxyPort=e;this.maxShards=a;this.inheritStreamsFromExistingTables=n;this.accountId=i;this.region=r}static async collectBuffer(t){let e=Buffer.alloc(0);return t.on("data",a=>{e=Buffer.concat([e,a])}),new Promise(a=>{t.on("end",async()=>{a(e)})})}static async collectBody(t){return(await this.collectBuffer(t)).toString("utf-8")}static async collectJsonObjectOrReturnError(t,e){try{let a=JSON.parse(await this.collectBody(t));if(!a||Array.isArray(a)||typeof a!="object")throw new Error("Invalid request");return a}catch{e.statusCode=400,e.end(JSON.stringify({__type:"com.amazon.coral.validate#ValidationException",Message:"Invalid Request Body"}));return}}redirect(t,e,a){let n=D.request(new URL(t.url,this.dynamoDbLocalEndpoint),{headers:t.headers,method:t.method},i=>{e.writeHead(i.statusCode,i.statusMessage,i.headers),i.pipe(e)});a&&n.write(a)}safeReturnThrownError(t,e,a,n){if(a?.$response?.body){let i=a.$response.body,r={};for(let d of Object.keys(a))d.startsWith("$")||(r[d]=a[d]);let o={};typeof i.headers.server=="string"&&(o.server=i.headers.server),typeof i.headers.date=="string"&&(o.date=i.headers.date),typeof i.headers["x-amzn-requestid"]=="string"&&(o["x-amzn-requestid"]=i.headers["x-amzn-requestid"]),o["content-type"]="application/x-amz-json-1.0";let s=JSON.stringify(r);o["content-length"]=Buffer.from(s).byteLength,e.writeHead(i.statusCode,i.statusMessage,o),e.end(s)}else return this.redirect(t,e,n)}dynamoDbLocalEndpoint="http://localhost:8000";server;streams=[];itemsWithTTL={};getStreamByTableName(t){return this.streams.find(e=>(e.TableName==t||e.TableArn==t)&&e.StreamDescription.StreamStatus=="ENABLED")}getTableKeySchemaAttributeNames(t){let e=this.streams.find(a=>a.TableName==t||a.TableArn==t);if(e)return e.StreamDescription.KeySchema.map(a=>a.AttributeName)}getStreamByArn(t){return this.streams.find(e=>e.StreamDescription.StreamArn==t)}trackTTLRecord(t,e){if(!e)return;let a=this.itemsWithTTL[t];if(a)try{let n={};for(let o of a.keySchema)n[o.AttributeName]=e[o.AttributeName];let i=JSON.stringify(n);if(!e[a.ttlFieldName]){a.items.delete(i);return}let r=new Date(Number(e[a.ttlFieldName].N)*1e3);a.items.set(i,{oldImage:e,ttl:r.getTime(),key:n})}catch(n){console.error(n)}}setRecord(t,e,a,n=!1){let i=this.getStreamByTableName(t);if(i&&i.setRecord(e,a,n),!n&&!e&&a){let r=this.itemsWithTTL[t];if(!r)return;let o={};for(let d of r.keySchema)o[d.AttributeName]=a[d.AttributeName];let s=JSON.stringify(o);r.items.delete(s);return}this.trackTTLRecord(t,e)}async getBodyIfJsonObject(t,e){let a=await c.collectBuffer(t),n=a.toString("utf-8"),i;try{if(i=JSON.parse(n),!i||Array.isArray(i)||typeof i!="object")throw new Error("");return{buf:a,rawBody:n,parsedBody:i}}catch{return this.redirect(t,e,a)}}static isValidStreamArn(t){if(!t||typeof t!="string")return!1;let e=t.split("/");if(e.length!=4)return!1;let[a,n,i,r]=e;if(i!="stream"||!new Date(r).getTime())return!1;let o=a.split(":");if(o.length!=6)return!1;let[s,d,u,m,h,l]=o;return!(!(s=="arn"&&u=="dynamodb"&&l=="table")||!["aws","aws-cn","aws-us-gov"].includes(d))}static isValidShardIteratorType(t){return!t||typeof t!="string"?!1:["AFTER_SEQUENCE_NUMBER","LATEST","AT_SEQUENCE_NUMBER","TRIM_HORIZON"].includes(t)}async GetRecords(t,e){let a=await c.collectJsonObjectOrReturnError(t,e);if(!a)return;let{ShardIterator:n,Limit:i}=a,r=typeof n=="string"?n:"",[o,s,d]=r.split("|"),u=this.getStreamByArn(o);if(!u){e.statusCode=400,e.end(JSON.stringify({__type:"com.amazon.coral.validate#ValidationException",Message:"Invalid ShardIterator"}));return}let m;try{m=v.fromString(d)}catch{e.statusCode=400,e.end(JSON.stringify({__type:"com.amazon.coral.validate#ValidationException",Message:"Invalid ShardIterator"}));return}let h=u.getShardById(m.shardId);if(!h){e.statusCode=400,e.end(JSON.stringify({__type:"com.amazon.coral.validate#ValidationException",Message:"Invalid ShardIterator"}));return}let{Records:l,nextIterator:f}=h.getRecords(m,i?Number(i):void 0),y=null;f&&(y=`${u.StreamDescription.StreamArn}|${h.getId()}|${f.toString()}`),e.end(JSON.stringify({NextShardIterator:y,Records:l}))}async GetShardIterator(t,e){let a=await c.collectJsonObjectOrReturnError(t,e);if(!a)return;let{ShardId:n,ShardIteratorType:i,StreamArn:r,SequenceNumber:o}=a;if(!c.isValidStreamArn(r)){e.statusCode=400,e.end(JSON.stringify({__type:"com.amazon.coral.validate#ValidationException",Message:"Invalid StreamArn"}));return}let s=this.getStreamByArn(r);if(!s){e.statusCode=400,e.end(JSON.stringify({__type:"com.amazonaws.dynamodb.v20120810#ResourceNotFoundException",message:`Requested resource not found: Stream: ${r} not found`}));return}if(!c.isValidShardIteratorType(i)){e.statusCode=400,e.end(JSON.stringify({__type:"com.amazon.coral.validate#ValidationException",message:`1 validation error detected: Value '${i}' at 'shardIteratorType' failed to satisfy constraint: Member must satisfy enum value set: [AFTER_SEQUENCE_NUMBER, LATEST, AT_SEQUENCE_NUMBER, TRIM_HORIZON]`}));return}let d=s.getShardById(n);if(!d){e.statusCode=400,e.end(JSON.stringify({__type:"com.amazonaws.dynamodb.v20120810#ResourceNotFoundException",message:"Requested resource not found: Shard does not exist"}));return}if(["AT_SEQUENCE_NUMBER","AFTER_SEQUENCE_NUMBER"].includes(i)){if(!o){e.statusCode=400,e.end(JSON.stringify({__type:"com.amazon.coral.validate#ValidationException",Message:"One or more parameter values were invalid: SequenceNumber cannot be null"}));return}}else if(o){e.statusCode=400,e.end(JSON.stringify({__type:"com.amazon.coral.validate#ValidationException",Message:"One or more parameter values were invalid: SequenceNumber should not be passed for this iterator type"}));return}let u;if(typeof o<"u")if(typeof o=="string"){let m;if(o.length<21)m=`1 validation error detected: Value '${o}' at 'sequenceNumber' failed to satisfy constraint: Member must have length greater than or equal to 21`;else try{u=T.createFromString(o)}catch{m="Invalid SequenceNumber for the shard"}if(m){e.statusCode=400,e.end(JSON.stringify({__type:"com.amazon.coral.validate#ValidationException",Message:m}));return}}else{let m;if(typeof o=="object"&&o?m="Start of structure or map found where not expected":typeof o=="number"?m="NUMBER_VALUE cannot be converted to String":typeof o=="boolean"&&(m=`${String(o).toUpperCase()}_VALUE cannot be converted to String`),m){e.statusCode=400,e.end(JSON.stringify({__type:"com.amazon.coral.service#SerializationException",Message:m}));return}}if(u){if(!d.SequenceNumberRange.StartingSequenceNumber){e.statusCode=400,e.end(JSON.stringify({__type:"com.amazon.coral.validate#ValidationException",Message:"Invalid SequenceNumber for the shard"}));return}if(u.lt(d.SequenceNumberRange.StartingSequenceNumber)){e.statusCode=400,e.end(JSON.stringify({__type:"com.amazon.coral.validate#ValidationException",Message:"Invalid SequenceNumber for the shard"}));return}if(d.SequenceNumberRange.EndingSequenceNumber&&u.gt(T.createFromString(d.SequenceNumberRange.EndingSequenceNumber))){e.statusCode=400,e.end(JSON.stringify({__type:"com.amazon.coral.validate#ValidationException",Message:"Invalid SequenceNumber for the shard"}));return}}try{let m=d.getIterator(i,u);e.end(JSON.stringify({ShardIterator:`${s.StreamDescription.StreamArn}|${d.getId()}|${m.toString()}`}))}catch(m){console.error(m),e.end()}}async ListStreams(t,e){let a=await c.collectJsonObjectOrReturnError(t,e);if(!a)return;let{ExclusiveStartStreamArn:n,Limit:i,TableName:r}=a,o=i??100,s=r?this.streams.filter(d=>d.TableName==r||d.TableArn==r):this.streams;if(n){let d=s.findIndex(u=>u.StreamDescription.StreamArn==n);d!=-1&&(s=s.slice(d+1,o-1))}e.end(JSON.stringify({Streams:s.map(({TableName:d,StreamDescription:u})=>({StreamArn:u.StreamArn,StreamLabel:u.StreamLabel,TableName:d}))}))}async DescribeStream(t,e){let a=await c.collectJsonObjectOrReturnError(t,e);if(!a)return;let{StreamArn:n,ExclusiveStartShardId:i,Limit:r}=a;if(!c.isValidStreamArn(n)){e.statusCode=400,e.end(JSON.stringify({__type:"com.amazon.coral.validate#ValidationException",Message:"Invalid StreamArn"}));return}let o=this.streams.find(u=>u.StreamDescription.StreamArn==n);if(!o){e.statusCode=400,e.end(JSON.stringify({__type:"com.amazonaws.dynamodb.v20120810#ResourceNotFoundException",message:`Requested resource not found: Stream: ${n} not found`}));return}let s=r??100,d=o.StreamDescription.Shards;if(i){let u=d.findIndex(m=>m.ShardId==i);u!=-1&&(d=d.slice(u+1,s-1))}e.end(JSON.stringify({StreamDescription:{...o.StreamDescription,Shards:d}}))}async CreateTable(t,e){t.pipe(D.request(new URL(t.url,this.dynamoDbLocalEndpoint),{headers:t.headers,method:t.method},async a=>{if(e.writeHead(a.statusCode,a.statusMessage,a.headers),a.statusCode==200){let n=await c.collectBuffer(a),i=JSON.parse(n.toString("utf-8")),{TableName:r,KeySchema:o,TableArn:s,StreamSpecification:d}=i.TableDescription;d?.StreamEnabled&&this.streams.push(new E(r,d.StreamViewType,o,this.maxShards,this.accountId,this.region)),e.end(n)}else a.pipe(e)}))}async DeleteTable(t,e){t.pipe(D.request(new URL(t.url,this.dynamoDbLocalEndpoint),{headers:t.headers,method:t.method},async a=>{if(e.writeHead(a.statusCode,a.statusMessage,a.headers),a.statusCode==200){let n=await c.collectBuffer(a),i=JSON.parse(n.toString("utf-8")),{TableName:r}=i.TableDescription,o=this.streams.findIndex(s=>s.TableName==r||s.TableArn==r);o!=-1&&this.streams.splice(o,1),delete this.itemsWithTTL[r],e.end(n)}else a.pipe(e)}))}async UpdateTable(t,e){t.pipe(D.request(new URL(t.url,this.dynamoDbLocalEndpoint),{headers:t.headers,method:t.method},async a=>{if(e.writeHead(a.statusCode,a.statusMessage,a.headers),a.statusCode!=200){a.pipe(e);return}let n=await c.collectBuffer(a),i=JSON.parse(n.toString("utf-8")),{TableName:r,StreamSpecification:o,KeySchema:s}=i.TableDescription;if(o){let d=this.getStreamByTableName(r);typeof o.StreamEnabled=="boolean"?d?d.StreamDescription.StreamStatus=o.StreamEnabled?"ENABLED":"DISABLED":o.StreamEnabled&&this.streams.push(new E(r,o.StreamViewType,s,this.maxShards)):d?d.StreamDescription.StreamViewType=o.StreamViewType:this.streams.push(new E(r,o.StreamViewType,s,this.maxShards))}else{let d=this.streams.find(u=>u.TableName==r||u.TableArn==r);d&&(d.StreamDescription.StreamStatus="DISABLED")}e.end(n)}))}async UpdateTimeToLive(t,e){let a=await this.getBodyIfJsonObject(t,e);if(!a)return;let{buf:n,parsedBody:i}=a;try{let r=await this.client.updateTimeToLive(i);r.$metadata.httpStatusCode&&(e.statusCode=r.$metadata.httpStatusCode),r.$metadata.requestId&&e.setHeader("x-amzn-RequestId",r.$metadata.requestId);let{TableName:o}=i,s=this.streams.find(d=>d.TableName==o||d.TableArn==o);if(s){let{TimeToLiveSpecification:d}=r,{AttributeName:u,Enabled:m}=d,h=m,l=u;this.itemsWithTTL[o]??={items:new Map,ttlFieldName:l,enabled:h,keySchema:s.StreamDescription.KeySchema},this.itemsWithTTL[o].enabled=h,this.itemsWithTTL[o].ttlFieldName=l}e.end(JSON.stringify(r))}catch(r){this.safeReturnThrownError(t,e,r,n)}}async PutItem(t,e){let a=await this.getBodyIfJsonObject(t,e);if(!a)return;let{buf:n,rawBody:i,parsedBody:r}=a;try{let o=["NONE","ALL_OLD"],s=r.ReturnValues,d="";s?o.includes(s)?d="ALL_OLD":d=s:d="ALL_OLD";let u={...r,ReturnValues:d},m=await this.client.putItem(u);m.$metadata.httpStatusCode&&(e.statusCode=m.$metadata.httpStatusCode),m.$metadata.requestId&&e.setHeader("x-amzn-RequestId",m.$metadata.requestId);let{TableName:h,Item:l}=r,f=l,y=m.Attributes;this.setRecord(h,f,y);let I=JSON.stringify({...m,Attributes:s=="ALL_OLD"?m.Attributes:void 0});e.end(I)}catch(o){this.safeReturnThrownError(t,e,o,n)}}async DeleteItem(t,e){let a=await this.getBodyIfJsonObject(t,e);if(!a)return;let{buf:n,parsedBody:i}=a;try{let r=["NONE","ALL_OLD"],o=i.ReturnValues,s="";o?r.includes(o)?s="ALL_OLD":s=o:s="ALL_OLD";let d={...i,ReturnValues:s},u=await this.client.deleteItem(d);u.$metadata.httpStatusCode&&(e.statusCode=u.$metadata.httpStatusCode),u.$metadata.requestId&&e.setHeader("x-amzn-RequestId",u.$metadata.requestId);let{TableName:m}=i,h=void 0,l=u.Attributes;l&&this.setRecord(m,h,l);let f=JSON.stringify({...u,Attributes:o=="ALL_OLD"?u.Attributes:void 0});e.end(f)}catch(r){this.safeReturnThrownError(t,e,r,n)}}async UpdateItem(t,e){let a=await this.getBodyIfJsonObject(t,e);if(!a)return;let{buf:n,rawBody:i,parsedBody:r}=a;try{let{TableName:o,Key:s}=r,d;try{d=(await this.client.getItem({TableName:o,Key:s,ConsistentRead:!0})).Item}catch{}let u=await this.client.updateItem(r),{Item:m}=await this.client.getItem({TableName:o,Key:s,ConsistentRead:!0});u.$metadata.httpStatusCode&&(e.statusCode=u.$metadata.httpStatusCode),u.$metadata.requestId&&e.setHeader("x-amzn-RequestId",u.$metadata.requestId),this.setRecord(o,m,d);let h=JSON.stringify(u);e.end(h)}catch(o){this.safeReturnThrownError(t,e,o,n)}}async safeBatchGetItems(t){let e={},a=t;do try{let{Responses:n,UnprocessedKeys:i}=await this.client.batchGetItem({RequestItems:a});if(n)for(let[r,o]of Object.entries(n))e[r]?e[r]=e[r].concat(o):e[r]=o;i&&Object.keys(i).length?a=i:a=void 0}catch{a=void 0}while(a);return e}async BatchWriteItem(t,e){let a=await this.getBodyIfJsonObject(t,e);if(!a)return;let{buf:n,parsedBody:i}=a;if(!g(i.RequestItems))return this.redirect(t,e,n);let r={};for(let[s,d]of Object.entries(i.RequestItems)){if(!Array.isArray(d))return this.redirect(t,e,n);let u=this.getTableKeySchemaAttributeNames(s);if(!u)return this.redirect(t,e,n);r[s]={Keys:[],ConsistentRead:!0};for(let m of d){if(!g(m))return this.redirect(t,e,n);if(g(m.DeleteRequest)){if(!g(m.DeleteRequest.Key))return this.redirect(t,e,n);let h={};for(let l of u)h[l]=m.DeleteRequest.Key[l];r[s].Keys.push(h)}else if(g(m.PutRequest)){if(!g(m.PutRequest.Item))return this.redirect(t,e,n);let h={};for(let l of u)h[l]=m.PutRequest.Item[l];r[s].Keys.push(h)}else return this.redirect(t,e,n)}}let o=await this.safeBatchGetItems(r);try{let s=await this.client.batchWriteItem(i),d=await this.safeBatchGetItems(r);for(let[u,m]of Object.entries(r))if(this.getStreamByTableName(u))for(let l of m.Keys){let f=Object.keys(l),y=o[u].find(N=>{let S={};for(let p of f)S[p]=N[p];return w(l,S)}),I=d[u].find(N=>{let S={};for(let p of f)S[p]=N[p];return w(l,S)});(I||y)&&this.setRecord(u,I,y)}s.$metadata.httpStatusCode&&(e.statusCode=s.$metadata.httpStatusCode),s.$metadata.requestId&&e.setHeader("x-amzn-RequestId",s.$metadata.requestId),e.end(JSON.stringify(s))}catch(s){this.safeReturnThrownError(t,e,s,n)}}async TransactWriteItems(t,e){let a=await this.getBodyIfJsonObject(t,e);if(!a)return;let{buf:n,parsedBody:i}=a;if(!Array.isArray(i.TransactItems))return this.redirect(t,e,n);let r={};for(let s of i.TransactItems){if(!g(s))return this.redirect(t,e,n);if(s.Delete){if(!g(s.Delete)||typeof s.Delete.TableName!="string"||!s.Delete.Key)return this.redirect(t,e,n);r[s.Delete.TableName]??={Keys:[],ConsistentRead:!0},r[s.Delete.TableName].Keys.find(u=>w(u,s.Delete.Key))||r[s.Delete.TableName].Keys.push(s.Delete.Key)}else if(s.Update){if(!g(s.Update)||typeof s.Update.TableName!="string"||!s.Update.Key)return this.redirect(t,e,n);r[s.Update.TableName]??={Keys:[],ConsistentRead:!0},r[s.Update.TableName].Keys.find(u=>w(u,s.Update.Key))||r[s.Update.TableName].Keys.push(s.Update.Key)}else if(s.Put){if(!g(s.Put)||typeof s.Put.TableName!="string"||!g(s.Put.Item))return this.redirect(t,e,n);let d=this.getTableKeySchemaAttributeNames(s.Put.TableName);if(!d)return this.redirect(t,e,n);r[s.Put.TableName]??={Keys:[],ConsistentRead:!0};let u={};for(let h of d)u[h]=s.Put.Item[h];r[s.Put.TableName].Keys.find(h=>w(h,u))||r[s.Put.TableName].Keys.push(u)}}let o=await this.safeBatchGetItems(r);try{let s=await this.client.transactWriteItems(i),d=await this.safeBatchGetItems(r);for(let[u,m]of Object.entries(r))if(this.getStreamByTableName(u))for(let l of m.Keys){let f=Object.keys(l),y=o[u].find(N=>{let S={};for(let p of f)S[p]=N[p];return w(l,S)}),I=d[u].find(N=>{let S={};for(let p of f)S[p]=N[p];return w(l,S)});(I||y)&&this.setRecord(u,I,y)}s.$metadata.httpStatusCode&&(e.statusCode=s.$metadata.httpStatusCode),s.$metadata.requestId&&e.setHeader("x-amzn-RequestId",s.$metadata.requestId),e.end(JSON.stringify(s))}catch(s){this.safeReturnThrownError(t,e,s,n)}}async setDynamoDbLocalEndpoint(){try{let t="http://localhost:8000",e=await this.client.config.endpoint?.();e&&(t=`${e.protocol}${e.hostname}`,e.port&&(t+=`:${e.port}`),e.path&&e.path!="/"&&(t+=e.path)),this.dynamoDbLocalEndpoint=t}catch{console.warn("Can not resolve DynamoDB Local endpoint. Using default http://localhost:8000")}}async inheritStreams(){let t;do{let e={ExclusiveStartTableName:t},{TableNames:a,LastEvaluatedTableName:n}=await this.client.listTables(e);for(let i of a){let{Table:r}=await this.client.describeTable({TableName:i});if(r?.StreamSpecification?.StreamEnabled&&r.StreamSpecification.StreamViewType&&r.KeySchema?.every(s=>s.AttributeName&&s.KeyType)){let s=new E(i,r.StreamSpecification.StreamViewType,r.KeySchema,this.maxShards);this.streams.push(s)}let{TimeToLiveDescription:o}=await this.client.describeTimeToLive({TableName:i});o?.TimeToLiveStatus=="ENABLED"&&(this.itemsWithTTL[i]={enabled:!0,ttlFieldName:o.AttributeName,keySchema:r.KeySchema,items:new Map})}t=n}while(t)}watchTTL(){setInterval(async()=>{for(let[t,e]of Object.entries(this.itemsWithTTL)){if(!e.enabled)continue;let a=Date.now();for(let[n,i]of e.items.entries())if(!(i.ttl>a))try{(await this.client.getItem({TableName:t,Key:i.key,ConsistentRead:!0})).Item||(e.items.delete(n),this.setRecord(t,void 0,i.oldImage,!0))}catch(r){console.error(r)}}},1e3).unref()}async init(){let t=this;await this.setDynamoDbLocalEndpoint(),this.inheritStreamsFromExistingTables&&await this.inheritStreams();let e=W(async(a,n)=>{switch(a.headers["x-amz-target"]?.split(".")[1]){case"GetRecords":return t.GetRecords(a,n);case"GetShardIterator":return t.GetShardIterator(a,n);case"ListStreams":return t.ListStreams(a,n);case"DescribeStream":return t.DescribeStream(a,n);case"CreateTable":return t.CreateTable(a,n);case"DeleteTable":return t.DeleteTable(a,n);case"UpdateTable":return t.UpdateTable(a,n);case"PutItem":return t.PutItem(a,n);case"UpdateItem":return t.UpdateItem(a,n);case"DeleteItem":return t.DeleteItem(a,n);case"BatchWriteItem":return t.BatchWriteItem(a,n);case"TransactWriteItems":return t.TransactWriteItems(a,n);case"UpdateTimeToLive":return t.UpdateTimeToLive(a,n);default:a.pipe(D.request(new URL(a.url,this.dynamoDbLocalEndpoint),{headers:a.headers,method:a.method},o=>{n.writeHead(o.statusCode,o.statusMessage,o.headers),o.pipe(n)}))}});return await new Promise(a=>{e.listen(this.proxyPort,()=>{a(void 0)})}),this.server=e,t.watchTTL(),e.address().port}};var F=3,K=!1,P="123456789012",z="us-east-1";b.maxShards&&(typeof b.maxShards=="number"&&b.maxShards>0?F=Math.round(b.maxShards):console.warn("When provided, maxShards must be a positive integer. Using default 3."));typeof b.inheritStreamsFromExistingTables=="boolean"&&(K=b.inheritStreamsFromExistingTables);typeof b.accountId=="string"&&(P=b.accountId);typeof b.region=="string"&&(z=b.region);var G=new Q(b.dynamoDbLocalClientConfig),j=new L(G,b.proxyPort,F,K,P,z),Y=await j.init();H.postMessage({proxyPort:Y});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import EventEmitter from "node:events";
|
|
2
|
+
import { DynamoDBClient, type DynamoDBClientConfig } from "@aws-sdk/client-dynamodb";
|
|
3
|
+
import { DynamoDBStreams, type Shard, type ShardIteratorType } from "@aws-sdk/client-dynamodb-streams";
|
|
4
|
+
export declare class DynamoStream extends EventEmitter {
|
|
5
|
+
#private;
|
|
6
|
+
cli: DynamoDBClient;
|
|
7
|
+
streamCli: DynamoDBStreams;
|
|
8
|
+
TableName: string;
|
|
9
|
+
ShardIteratorType: ShardIteratorType;
|
|
10
|
+
constructor(config: {
|
|
11
|
+
TableName: string;
|
|
12
|
+
startingPosition: ShardIteratorType;
|
|
13
|
+
}, clientConfig: DynamoDBClientConfig);
|
|
14
|
+
private runningShards;
|
|
15
|
+
private completedShards;
|
|
16
|
+
init(): Promise<void>;
|
|
17
|
+
private start;
|
|
18
|
+
getAvailableStream(): Promise<import("@aws-sdk/client-dynamodb-streams").StreamDescription | undefined>;
|
|
19
|
+
describeStream(StreamArn: string): Promise<import("@aws-sdk/client-dynamodb-streams").StreamDescription | undefined>;
|
|
20
|
+
getShardIterator(Shard: Shard, StreamArn: string): Promise<string | undefined>;
|
|
21
|
+
private getNextWatcherTimeout;
|
|
22
|
+
totalConsumedRecords: number;
|
|
23
|
+
watch(Shard: Shard, StreamArn: string): Promise<void>;
|
|
24
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { S3 } from "@aws-sdk/client-s3";
|
|
2
|
+
import type { SNS } from "@aws-sdk/client-sns";
|
|
3
|
+
import type { SQS } from "@aws-sdk/client-sqs";
|
|
4
|
+
import { Subscriber } from "./subscriber";
|
|
5
|
+
export declare class StreamsHandler {
|
|
6
|
+
#private;
|
|
7
|
+
getAwsServices: () => {
|
|
8
|
+
sqs?: SQS;
|
|
9
|
+
sns?: SNS;
|
|
10
|
+
s3?: S3;
|
|
11
|
+
};
|
|
12
|
+
region: string;
|
|
13
|
+
accountId: string;
|
|
14
|
+
subscribers: Subscriber[];
|
|
15
|
+
listenableTables: any[];
|
|
16
|
+
constructor(lambdas: any[], getAwsServices: () => {
|
|
17
|
+
sqs?: SQS;
|
|
18
|
+
sns?: SNS;
|
|
19
|
+
s3?: S3;
|
|
20
|
+
}, region: string, accountId: string);
|
|
21
|
+
getSlsDeclarations: () => void;
|
|
22
|
+
getListenableTables: () => void;
|
|
23
|
+
setRecords: ({ records, TableName, DDBStreamBatchInfo, }: {
|
|
24
|
+
records: any[];
|
|
25
|
+
TableName: string;
|
|
26
|
+
DDBStreamBatchInfo: any;
|
|
27
|
+
}) => void;
|
|
28
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import EventEmitter from "node:events";
|
|
2
|
+
import type { S3 } from "@aws-sdk/client-s3";
|
|
3
|
+
import type { SNS } from "@aws-sdk/client-sns";
|
|
4
|
+
import type { SQS } from "@aws-sdk/client-sqs";
|
|
5
|
+
import { Batch } from "./batch";
|
|
6
|
+
import type { IOnFailureDestinationHandler } from "./failure/index";
|
|
7
|
+
interface Config {
|
|
8
|
+
TableName: string;
|
|
9
|
+
enabled?: boolean;
|
|
10
|
+
startingPosition: "TRIM_HORIZON" | "LATEST";
|
|
11
|
+
batchSize: number;
|
|
12
|
+
maximumBatchingWindow?: number;
|
|
13
|
+
maximumRetryAttempts?: number;
|
|
14
|
+
maximumRecordAgeInSeconds?: number;
|
|
15
|
+
bisectBatchOnFunctionError?: boolean;
|
|
16
|
+
tumblingWindowInSeconds?: number;
|
|
17
|
+
functionResponseType?: string;
|
|
18
|
+
filterPatterns?: any[];
|
|
19
|
+
onFailureDestination?: string;
|
|
20
|
+
}
|
|
21
|
+
type Invoke = (event: any, info?: any) => Promise<void | any>;
|
|
22
|
+
export declare class Subscriber extends EventEmitter {
|
|
23
|
+
#private;
|
|
24
|
+
getAwsServices: () => {
|
|
25
|
+
sqs?: SQS;
|
|
26
|
+
sns?: SNS;
|
|
27
|
+
s3?: S3;
|
|
28
|
+
};
|
|
29
|
+
region: string;
|
|
30
|
+
accountId: string;
|
|
31
|
+
lambdaName: string;
|
|
32
|
+
TableName: string;
|
|
33
|
+
enabled?: boolean;
|
|
34
|
+
startingPosition: "TRIM_HORIZON" | "LATEST";
|
|
35
|
+
invoke: Invoke;
|
|
36
|
+
batchSize: number;
|
|
37
|
+
maximumBatchingWindow: number;
|
|
38
|
+
maximumRetryAttempts?: number;
|
|
39
|
+
maximumRecordAgeInSeconds: number;
|
|
40
|
+
bisectBatchOnFunctionError?: boolean;
|
|
41
|
+
tumblingWindowInSeconds?: number;
|
|
42
|
+
functionResponseType?: string;
|
|
43
|
+
filterPatterns?: any[];
|
|
44
|
+
failure?: IOnFailureDestinationHandler;
|
|
45
|
+
event: any;
|
|
46
|
+
static invokationLog: (TableName: string, lambdaName: string) => void;
|
|
47
|
+
constructor(event: Config, invoke: Invoke, name: string, getAwsServices: () => {
|
|
48
|
+
sqs?: SQS;
|
|
49
|
+
sns?: SNS;
|
|
50
|
+
s3?: S3;
|
|
51
|
+
}, region: string, accountId: string);
|
|
52
|
+
private setFailureHandler;
|
|
53
|
+
setRecords: (records: any[], DDBStreamBatchInfo: any) => Promise<void>;
|
|
54
|
+
callLambda(batch: Batch, Records?: any[]): Promise<any>;
|
|
55
|
+
private createFailureMessage;
|
|
56
|
+
}
|
|
57
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export declare class TumblingWindow {
|
|
2
|
+
shardId: string;
|
|
3
|
+
eventSourceARN: string;
|
|
4
|
+
window: {
|
|
5
|
+
start: string;
|
|
6
|
+
end: string;
|
|
7
|
+
};
|
|
8
|
+
state: any;
|
|
9
|
+
isFinalInvokeForWindow: boolean;
|
|
10
|
+
isWindowTerminatedEarly: boolean;
|
|
11
|
+
onComplete?: Function;
|
|
12
|
+
constructor({ shardId, eventSourceARN, tumblingWindowInSeconds, }: {
|
|
13
|
+
shardId: string;
|
|
14
|
+
eventSourceARN: string;
|
|
15
|
+
tumblingWindowInSeconds: number;
|
|
16
|
+
});
|
|
17
|
+
setState(state: any): this;
|
|
18
|
+
getTimeWindowEvent(records: any[]): {
|
|
19
|
+
Records: any[];
|
|
20
|
+
window: {
|
|
21
|
+
start: string;
|
|
22
|
+
end: string;
|
|
23
|
+
};
|
|
24
|
+
state: any;
|
|
25
|
+
shardId: string;
|
|
26
|
+
eventSourceARN: string;
|
|
27
|
+
isFinalInvokeForWindow: boolean;
|
|
28
|
+
isWindowTerminatedEarly: boolean;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{parentPort as m,workerData as w}from"node:worker_threads";import u from"node:events";import{DynamoDBClient as g,waitUntilTableExists as y}from"@aws-sdk/client-dynamodb";import{DynamoDBStreams as p,ExpiredIteratorException as f,TrimmedDataAccessException as b}from"@aws-sdk/client-dynamodb-streams";var c=class extends u{cli;streamCli;TableName;#e=!0;ShardIteratorType;constructor(t,e){super(),this.cli=new g(e),this.streamCli=new p(e),this.TableName=t.TableName,this.ShardIteratorType=t.startingPosition}runningShards=new Set;completedShards=new Set;async init(){await this.#t(),await this.start();let t=0,e=async()=>{try{let a=await this.getAvailableStream();if(!a?.Shards||!a.StreamArn)return;let r=0;for(let s of a.Shards)this.runningShards.has(s.ShardId)||this.completedShards.has(s.ShardId)||setTimeout(async()=>{try{await this.watch(s,a.StreamArn),this.runningShards.add(s.ShardId),r++}catch(n){console.error(n)}},50);t+=r}catch(a){console.error(a)}setTimeout(e,1e3)};await e()}async#t(){try{await y({client:this.cli,maxWaitTime:25},{TableName:this.TableName}),console.log(`\u2705 Successfully connected to Table "${this.TableName}"`)}catch{console.log(`Could not connect to table ${this.TableName}`)}}async start(){}async getAvailableStream(){let{Streams:t}=await this.streamCli.listStreams({TableName:this.TableName});if(!t)return;let e=await Promise.all(t.filter(r=>r.StreamArn).map(r=>this.describeStream(r.StreamArn)));if(!e)return;let a=e.filter(r=>r?.StreamStatus=="ENABLED"&&r.Shards?.length);if(a?.length)return a[0]}async describeStream(t){let{StreamDescription:e}=await this.streamCli.describeStream({StreamArn:t});return e}async getShardIterator(t,e){return(await this.streamCli.getShardIterator({StreamArn:e,ShardId:t.ShardId,ShardIteratorType:this.ShardIteratorType})).ShardIterator}getNextWatcherTimeout(t){return t<=20?250:t>=60?6e3:t/10*1e3}totalConsumedRecords=0;async watch(t,e){let a=t.SequenceNumberRange?.StartingSequenceNumber,r=t.SequenceNumberRange?.EndingSequenceNumber,s=await this.getShardIterator(t,e),n=0,l=async()=>{try{let{NextShardIterator:i,Records:o}=await this.streamCli.getRecords({ShardIterator:s});if(o?.length){this.totalConsumedRecords+=o.length,n=0;let h=new Date().toISOString(),S={shardId:t.ShardId,startSequenceNumber:a,endSequenceNumber:r,approximateArrivalOfFirstRecord:h,approximateArrivalOfLastRecord:h,batchSize:o.length,streamArn:e};this.emit("records",o,S)}else n++;if(i)s=i;else{console.log("Total consumed in this Shard",this.TableName,this.totalConsumedRecords),this.completedShards.add(t.ShardId),s=void 0,await this.start();return}}catch(i){if(n=0,i instanceof f){await this.start();return}i instanceof b?s=await this.getShardIterator(t,e):console.log(i)}setTimeout(l,this.getNextWatcherTimeout(n))};await l()}};var{clientConfig:T}=w,I={endpoint:"http://127.0.0.1:8000",region:"us-east-1",credentials:{accessKeyId:"test",secretAccessKey:"test"}};m.on("message",async d=>{let{channel:t,tables:e}=d;if(t=="init"){for(let a of e)try{let r=new c(a,T??I);r.on("records",(s,n)=>{m.postMessage({records:s,DDBStreamBatchInfo:n,TableName:r.TableName})}),await r.init()}catch(r){console.log(r)}m.postMessage({channel:"ready"})}});
|
package/dist/standalone.js
CHANGED
|
@@ -6,7 +6,7 @@ Please verify provided SQS Client validity.`),console.error(d)}}},an=/(-|\w+)/g,
|
|
|
6
6
|
`)}else A=I;A.trim()&&console.log(A)}}catch(N){console.log("err",N),h(N)}};this.python.stdout.on("data",u);let S=w=>{let R=w.toString();if(R.includes(t.ERR_RESPONSE))try{R=JSON.parse(R.split(t.ERR_RESPONSE)[1]),R.requestId=p}catch{}finally{this.python.stdout.removeListener("data",u),this.python.stderr.removeListener("data",S),h(R)}else console.log(R)};this.python.stderr.on("data",S),this.python.stdin.write(`${g}
|
|
7
7
|
`)}),this.watcherListener=()=>{this.isMounted&&(this.unmount(!0),this.watchers.forEach(d=>d.close()),this.watchers=[],this.emitRebuild())}}setWatchFiles=async e=>{try{let n=e.split(t.WATCH),s=n[n.length-1].split(t.WATCHEND)[0],i=JSON.parse(s).map(o=>`${o.replace(/\./g,H.default.sep)}.py`);for(let o of i)try{await(0,fe.access)(o),this.watchers.push((0,at.watch)(o,{persistent:!1},this.watcherListener))}catch{}}catch(n){console.log(n)}};findPython(){let[e]=this.runtime.split("."),n=e.split("python")[1];if(ot(`${e} --version`))return e;let r=ot("python --version");if(!r)throw new Error("Can not find python on your OS. Make sure it is installed.");if(n){let s=r.split(" ")[1]?.split(".")[0];s&&s!=n&&b.YELLOW("found python binary but with different version")}return"python"}load=()=>{this.bin||(this.bin=this.findPython()),this.python=(0,ie.spawn)(this.bin,["-u",t.wrapper,this.handlerFileAbsolutePath,this.pyModulePath,this.handlerName,String(this.timeout)],{env:this.environment}),this.python.pid||(console.error(`Can not find ${this.bin} in your PATH`),process.exit(1)),this.isMounted=!0};onComplete=e=>{}};var ct=require("node:child_process"),lt=require("node:fs"),he=require("node:fs/promises"),W=P(require("node:path"));var oe=class t{invoke;mount;unmount;name;timeout;memorySize;environment;handlerPath;modulePath;handlerDir;handlerName;runtime;bin;ruby;isMounted=!1;emitRebuild;watcherListener;watchers=[];static wrapper=W.default.resolve(q("exlo"),"./src/lib/runtime/runners/ruby/index.rb");static DELIMITER="__|response|__";static ERR_RESPONSE="__|error|__";static WATCH="__|watch|__";constructor({name:e,timeout:n,memorySize:r,environment:s,handlerPath:i,handlerName:o,runtime:a},l){this.name=e,this.timeout=n,this.memorySize=r,this.environment=s,this.handlerName=o,this.runtime=a,this.emitRebuild=l;let c=W.default.resolve(i);this.handlerDir=W.default.dirname(c),this.handlerPath=W.default.basename(c,`.${this.handlerName}`),this.modulePath=`${this.handlerDir}/${this.handlerPath}.rb`,this.mount=async()=>{if(!this.ruby)try{await(0,he.access)(this.modulePath),this.load()}catch{console.error(`Can not find ${this.name}'s handler at: "${this.modulePath}"`),process.exit(1)}},this.unmount=d=>{d&&(this.ruby?.kill(),this.ruby=void 0,this.isMounted=!1)},this.invoke=async({event:d,info:m,clientContext:f,awsRequestId:p})=>new Promise((y,h)=>{let g=JSON.stringify({event:d,awsRequestId:p,context:f??""}),x=S=>{let w=null,R=S.toString();try{if(R.includes(t.WATCH))this.setWatchFiles(R);else if(R.includes(t.DELIMITER)){let I=R.split(t.DELIMITER),N=I[I.length-1];if(I.length>1){let A=I.slice(0,-1).join(`
|
|
8
8
|
`);A.trim()&&console.log(A)}N&&(w=JSON.parse(N)),this.ruby.stdout.removeListener("data",x),this.ruby.stderr.removeListener("data",u),y(w)}else R.trim()&&console.log(R)}catch(I){h(I)}};this.ruby.stdout.on("data",x);let u=S=>{let w=S.toString();if(w.includes(t.ERR_RESPONSE))try{w=JSON.parse(w.split(t.ERR_RESPONSE)[1]),w.requestId=p}catch{}finally{this.ruby.stdout.removeListener("data",x),this.ruby.stderr.removeListener("data",u),h(w)}else console.log(w)};this.ruby.stderr.on("data",u),this.ruby.stdin.write(`${g}
|
|
9
|
-
`)}),this.watcherListener=()=>{this.isMounted&&(this.unmount(!0),this.watchers.forEach(d=>d.close()),this.watchers=[],this.emitRebuild())}}setWatchFiles=async e=>{try{let n=e.split(t.WATCH),r=n[n.length-1],s=JSON.parse(r);s.push(this.modulePath);for(let i of s)try{await(0,he.access)(i),this.watchers.push((0,lt.watch)(i,{persistent:!1},this.watcherListener))}catch{}}catch(n){console.log(n)}};load=()=>{this.bin||(this.bin=process.platform==="win32"?"ruby.exe":"ruby"),this.ruby=(0,ct.spawn)(this.bin,[t.wrapper,this.modulePath,this.handlerName,this.name,String(this.timeout)],{env:this.environment,shell:!0}),this.ruby.pid||(console.error(`Can not find ${this.bin} in your PATH`),process.exit(1)),this.isMounted=!0};onComplete=e=>{}};var yn=["@invoke","@url"],k=class t{handlers=[];static ip="127.0.0.1";debug=!1;port=0;constructor(e){this.debug=e.debug}static parseNameFromUrl(e){let n=e.split("/"),r=yn.includes(n[1])?n[2]:n[3];if(r=decodeURIComponent(r),r.includes(":function:")){let s=r.split(":function:");r=s[s.length-1]}if(r.includes(":")){let s=r.split(":");s.length==2&&(r=s[0])}return r}getHandlerByName(e){if(!e)return;let n=t.parseNameFromUrl(e);return this.handlers.find(r=>r.name==n)}addHandler(e){let n=this.handlers.findIndex(r=>r.name==e.name&&r.esOutputPath==e.esOutputPath);n==-1?(this.handlers.push(e),this.#e("POST",`/2015-03-31/functions/${e.name}/invocations`),e.url&&this.#e("ANY",`/@url/${e.name}`,"34")):this.handlers[n].runtime.startsWith("n")&&(this.handlers[n].clear(),this.handlers[n]=e)}#e(e,n,r="90"){let s=`${e} http://localhost:${this.port}${n}`;console.log(`\x1B[${r}m${s}\x1B[0m`)}};var ae;ye.networkInterfaces&&(ae=Object.values((0,ye.networkInterfaces)()).reduce((t,e)=>(t.push(...e),t),[])?.filter(t=>!t.internal&&t.family==="IPv4").find(Boolean)?.address);var gn=mt.default?.url()!=null;gn&&(console.warn("Lambdas timeout are disabled when a Debugger is attached"),$.ENABLE_TIMEOUT=!1);var bn={errors:[],warnings:[],outputFiles:[],metafile:{inputs:{},outputs:{}},mangleCache:{}},ce=class extends k{#e;runtimeConfig={};#t;sco=[];aws;customOfflineRequests=[];customBuildCallback;onReady;stop(e){this.#e.close(e)}constructor(e,n={debug:!1}){super(n),b.setDebug(n.debug),this.aws=e.aws,this.sco=[],this.#e=pt.default.createServer({maxHeaderSize:105536},this.#r.bind(this)),this.#e.on("connection",s=>{s.on("close",()=>{let i=this.sco.findIndex(o=>o==s);i!=-1&&this.sco.splice(i,1)}),this.sco.push(s)});let r=(0,dt.randomUUID)();v.accountId=Buffer.from(r).toString("hex").slice(0,16),v.apiId=Buffer.from(r).toString("ascii").slice(0,10),v.port=this.port}setPort(e){this.port=e,v.port=e}listen(e=0,n){if(isNaN(e))throw Error("port should be a number");this.#e.once("error",async r=>{r.code==="EADDRINUSE"?(b.RED(r.message),process.exit(1)):console.log(r)}),this.#e.listen(e,async()=>{let{port:r,address:s}=this.#e.address();this.setPort(r),ae&&(k.ip=ae),typeof n=="function"&&await n(r,ae);try{await this.onReady?.(r,k.ip),await Ke(this.handlers,this.aws)}catch(i){console.error(i)}})}#n(e,n){n=n.endsWith("/")?n:`${n}/`;let r=this.customOfflineRequests.find(s=>{let i=!1,o=!0;return typeof s.filter=="string"?(s.filter.endsWith("/")||(s.filter+="/"),i=s.filter==n):s.filter instanceof RegExp&&(i=s.filter.test(n)),typeof s.method=="string"&&s.method.toUpperCase()!="ANY"?o=s.method.toUpperCase()==e:Array.isArray(s.method)&&(s.method.findIndex(l=>l.toUpperCase()=="ANY")!==-1||(o=s.method.findIndex(l=>l.toUpperCase()==e)!==-1)),i&&o});if(r)return r.callback}async#r(e,n){let{url:r,method:s}=e,i=new URL(r,v.dummyHost),o=this.#n(s,i.pathname);if(o)try{await o(e,n)}catch{n.writableFinished||n.end("Internal Server Error")}else{e.on("error",l=>{console.error(l.stack)});let a=()=>{n.setHeader("Content-Type","text/html"),n.statusCode=404,n.end(qe)};this.#t?this.#t(e,n,a):a()}}fakeRebuildEmitter=async()=>{if(this.customBuildCallback)try{await this.customBuildCallback(bn,!0)}catch(e){console.log(e)}console.log(`\x1B[32m${new Date().toLocaleString()} \u{1F504}\u2705 Rebuild\x1B[0m`)};async load(e){for(let n of e){let r=n.runtime.charAt(0);n.runner=r=="n"?new re(n):r=="p"?new se(n,this.fakeRebuildEmitter):r=="r"?new oe(n,this.fakeRebuildEmitter):new ne(n.runtime);let s=new $(n);this.addHandler(s)}}};var ht=require("node:fs/promises"),L=P(require("node:path")),yt=require("node:url"),gt=P(require("esbuild"));var ut="0.0.3";function ft(t){let e=new Set;t.plugins&&(t.plugins=t.plugins.filter((r,s)=>typeof r!="object"||!r||!("name"in r)?!1:((!r.name||!r.name.length||typeof r.name!="string")&&(r.name=`plugin-${s}`,console.warn(`No Plugin name provided at index ${s}`)),e.has(r.name)?r.name=r.name+s:e.add(r.name),!0)));async function n({stop:r,lambdas:s,region:i,esbuild:o,getServices:a,setService:l,addLambda:c,log:d,setEndpoint:m,getEndpoint:f,getAwsProviderDefaults:p,setAwsProviderDefaults:y}){let h={build:{esbuild:t?.build?.esbuild??{},shimRequire:t?.build?.shimRequire,optimizeBuild:t?.build?.optimizeBuild},server:{port:t.server?.port},onKill:[]};if(t.defaults&&typeof t.defaults=="object"&&!Array.isArray(t.defaults)&&y(t.defaults),t.functions&&typeof t.functions=="object"&&!Array.isArray(t.functions))for(let[x,u]of Object.entries(t.functions))c(x,u);t.services&&(t.services.sqs&&l("sqs",t.services.sqs),t.services.sns&&l("sns",t.services.sns),t.services.dynamodb&&l("dynamodb",t.services.dynamodb));let g={stop:r,lambdas:s,region:i,esbuild:o,options:t,config:h,getServices:a,setService:l,addLambda:c,log:d,setEndpoint:m,getEndpoint:f,getAwsProviderDefaults:p};if(t.plugins){h.server.onReady=async(u,S)=>{for(let w of t.plugins)if(w.server?.onReady)try{await w.server.onReady.call(g,u,S)}catch(R){d.RED(w.name),console.error(R)}},h.buildCallback=async(u,S)=>{for(let w of t.plugins)if(w.buildCallback)try{await w.buildCallback.call(g,u,S)}catch(R){d.RED(w.name),console.error(R),S||process.exit(1)}};let x=t.plugins.reduce((u,S)=>(S.server?.request?.length&&u.push(...S.server.request),u),[]);x?.length&&(h.server.request=x.map(u=>(u.callback=u.callback.bind(g),u)));for(let u of t.plugins)if(u.onKill&&h.onKill.push(u.onKill.bind(g)),u.onInit)try{await u.onInit.call(g)}catch(S){throw d.RED(u.name),S}}return h}return n.plugins=t.plugins??[],n}var vn=["js","mjs","cjs","ts","cts","mts"],xn=async t=>{let e=L.default.dirname(L.default.toNamespacedPath(t)),n=L.default.basename(t,L.default.extname(t)),r=L.default.join(e,`__${n}.mjs`);await gt.default.build({outfile:r,entryPoints:[t],bundle:!0,packages:"external",platform:"node",format:"esm",target:`node${process.versions.node.split(".")[0]}`,minify:!0,sourcemap:"inline",sourcesContent:!0});try{return await import((0,yt.pathToFileURL)(r).href)}catch(s){throw s}finally{await(0,ht.rm)(r)}},bt=async t=>{if(t){if(typeof t=="string"){let e=L.default.posix.parse(t),n=L.default.posix.join(e.dir,e.name),r=e.ext.slice(1),s=L.default.posix.resolve(n);vn.includes(r)&&(s+=`.${r}`);let i;try{i=await xn(s)}catch(o){b.YELLOW(`Can not read 'defineConfig' from ${t}`),console.error(o),process.exit(1)}return{exportedFunc:i,configObjectName:r,configPath:s}}if(typeof t=="object"&&!Array.isArray(t))return{configObjectName:"__inline_config__",configPath:"inline define config",exportedFunc:ft(t)}}};var wn=t=>{let e=t.split(";");return e.findIndex(r=>r.toLowerCase().startsWith("path="))==-1&&e.push("Path=/"),e.join(";")},ge=(t,e)=>{let n={};if(t&&Object.entries(t).forEach(([r,s])=>{n[r.toLowerCase()]=Array.isArray(s)?`[${s.join(", ")}]`:s}),Array.isArray(e)){if(!e.every(r=>typeof r=="string")){let r=new Error("Wrong 'cookies'. must be string[]",{cause:e}),s={"Content-Type":n["content-type"]??"application/json","x-amzn-ErrorType":"InternalFailure"};throw n["set-cookie"]&&(s["set-cookie"]=n["set-cookie"]),r.headers=s,r}e=e.map(wn),n["set-cookie"]=n["set-cookie"]?[n["set-cookie"],...e]:e}return n};var be=require("node:crypto");var le=class t extends v{res;mockEvent;payload;constructor({res:e,req:n,body:r,mockEvent:s,multiValueHeaders:i,isBase64Encoded:o,lambdaName:a,parsedURL:l,requestId:c}){super(),this.res=e,this.mockEvent=s,this.payload=s.version==1?t.createApgV1Event({req:n,mockEvent:s,parsedURL:l,lambdaName:a,multiValueHeaders:i,isBase64Encoded:o,requestId:c,body:r}):t.createApgV2Event({req:n,mockEvent:s,parsedURL:l,requestId:c,isBase64Encoded:o,body:r})}static skipHeaders=["connection","content"];static createApgV2Event=({req:e,mockEvent:n,parsedURL:r,requestId:s,isBase64Encoded:i,body:o})=>{let{method:a,headers:l}=e,c=t.getPathParameters(n,r),d,m=n.methods.find(S=>S==a)??"ANY",f={},p="";for(let S of Array.from(new Set(r.searchParams.keys()))){let w=r.searchParams.getAll(S);p+=`&${w.map(R=>encodeURI(`${S}=${R}`)).join("&")}`,f[S]=w.join(",")}p&&(p=p.slice(1));let y=n.paths[0]=="/*"?"$default":`${m} ${r.pathname}`,h=new Date,g="127.0.0.1",x=l.host?.startsWith("localhost")?g:l.host?l.host.split(":")[0]:g,u={version:"2.0",routeKey:y,rawPath:r.pathname,rawQueryString:p,headers:t.getCustomHeaders(e,n),requestContext:{accountId:String(t.accountId),apiId:t.apiId,domainName:`localhost:${t.port}`,domainPrefix:"localhost",http:{method:a,path:r.pathname,protocol:"HTTP/1.1",sourceIp:x,userAgent:l["user-agent"]??""},requestId:s,routeKey:y,stage:"$default",time:h.toISOString(),timeEpoch:h.getTime()}};return o?(u.body=o,u.isBase64Encoded=i):u.isBase64Encoded=!1,Object.keys(f).length&&(u.queryStringParameters=f),Object.keys(c).length&&(u.pathParameters=c),l.cookie&&(u.cookies=l.cookie.split("; ")),d=u,d.headers["x-mock-type"]&&delete d.headers["x-mock-type"],d};static createApgV1Event=({req:e,mockEvent:n,parsedURL:r,lambdaName:s,isBase64Encoded:i,requestId:o,body:a})=>{let{method:l}=e,c={};n.proxy=="httpApi"&&(c.version="1.0");let d=n.paths[0];c.resource=d,c.path=r.pathname,c.httpMethod=l;let{headers:m,multiValueHeaders:f,apiKey:p}=t.getApiGV1Headers(e,n);c.headers=m,c.multiValueHeaders=f;let y=String(e.socket.remoteAddress),h=Object.fromEntries(r.searchParams);c.queryStringParameters=Object.keys(h).length?h:null;let g=t.getMultiValueQueryStringParameters(r.searchParams);c.multiValueQueryStringParameters=Object.keys(g).length?g:null;let x=new Date,u={accountId:String(t.accountId),apiId:t.apiId,domainName:`localhost:${t.port}`,domainPrefix:"localhost",extendedRequestId:"fake-id",httpMethod:l,identity:{accessKey:null,accountId:null,caller:null,cognitoAuthenticationProvider:null,cognitoAuthenticationType:null,cognitoIdentityId:null,cognitoIdentityPoolId:null,principalOrgId:null,sourceIp:y,user:null,userAgent:e.headers["user-agent"],userArn:null},path:r.pathname,protocol:"HTTP/1.1",requestId:o,requestTime:x.toISOString(),requestTimeEpoch:x.getTime(),resourceId:"exhmtv",resourcePath:d};n.proxy=="httpApi"?(u.identity.cognitoAmr=null,u.stage="$default"):(u.stage="dev",n.private&&(u.identity.apiKey=p,u.identity.apiKeyId="abcdefghjk")),c.requestContext=u;let S=t.getPathParameters(n,r);return c.pathParameters=Object.keys(S).length?S:null,c.stageVariables=null,c.body=a??null,c.isBase64Encoded=a?i:!1,c};returnError=e=>{if(this.res.writableFinished)return!0;let n=500,r=t.httpErrMsg;e&&t.isEndpointTimeoutError(e.errorMessage)&&(this.mockEvent.proxy=="httpApi"?(n=503,r=t.unavailable):(n=504,r=t.apgTimeoutMsg));let s=[["Date",new Date().toUTCString()],["Content-Type",t.contentType.json],["Content-Length",String(r.length)],t.keepAlive,["Apigw-Requestid","ETuSEj-PiGYEJdQ="]];return this.res.shouldKeepAlive=!1,this.res.writeHead(n,s),this.res.end(r)};#e=e=>{let n="",r=typeof e;if(r=="string"||r=="number"||r=="boolean")n=String(e);else if(e===null)n="";else throw new Error("");return n};sendV1Response=e=>{let n=[["Date",new Date().toUTCString()],["Apigw-Requestid",Buffer.from((0,be.randomUUID)()).toString("base64").slice(0,16)],t.keepAlive],r=200;if(!e||isNaN(e.statusCode))throw b.RED(`Valid 'http' response payload must be an object which includes a valid 'statusCode'.
|
|
9
|
+
`)}),this.watcherListener=()=>{this.isMounted&&(this.unmount(!0),this.watchers.forEach(d=>d.close()),this.watchers=[],this.emitRebuild())}}setWatchFiles=async e=>{try{let n=e.split(t.WATCH),r=n[n.length-1],s=JSON.parse(r);s.push(this.modulePath);for(let i of s)try{await(0,he.access)(i),this.watchers.push((0,lt.watch)(i,{persistent:!1},this.watcherListener))}catch{}}catch(n){console.log(n)}};load=()=>{this.bin||(this.bin=process.platform==="win32"?"ruby.exe":"ruby"),this.ruby=(0,ct.spawn)(this.bin,[t.wrapper,this.modulePath,this.handlerName,this.name,String(this.timeout)],{env:this.environment,shell:!0}),this.ruby.pid||(console.error(`Can not find ${this.bin} in your PATH`),process.exit(1)),this.isMounted=!0};onComplete=e=>{}};var yn=["@invoke","@url"],k=class t{handlers=[];static ip="127.0.0.1";debug=!1;port=0;constructor(e){this.debug=e.debug}static parseNameFromUrl(e){let n=e.split("/"),r=yn.includes(n[1])?n[2]:n[3];if(r=decodeURIComponent(r),r.includes(":function:")){let s=r.split(":function:");r=s[s.length-1]}if(r.includes(":")){let s=r.split(":");s.length==2&&(r=s[0])}return r}getHandlerByName(e){if(!e)return;let n=t.parseNameFromUrl(e);return this.handlers.find(r=>r.name==n)}addHandler(e){let n=this.handlers.findIndex(r=>r.name==e.name&&r.esOutputPath==e.esOutputPath);n==-1?(this.handlers.push(e),this.#e("POST",`/2015-03-31/functions/${e.name}/invocations`),e.url&&this.#e("ANY",`/@url/${e.name}`,"34")):this.handlers[n].runtime.startsWith("n")&&(this.handlers[n].clear(),this.handlers[n]=e)}#e(e,n,r="90"){let s=`${e} http://localhost:${this.port}${n}`;console.log(`\x1B[${r}m${s}\x1B[0m`)}};var ae;ye.networkInterfaces&&(ae=Object.values((0,ye.networkInterfaces)()).reduce((t,e)=>(t.push(...e),t),[])?.filter(t=>!t.internal&&t.family==="IPv4").find(Boolean)?.address);var gn=mt.default?.url()!=null;gn&&(console.warn("Lambdas timeout are disabled when a Debugger is attached"),$.ENABLE_TIMEOUT=!1);var bn={errors:[],warnings:[],outputFiles:[],metafile:{inputs:{},outputs:{}},mangleCache:{}},ce=class extends k{#e;runtimeConfig={};#t;sco=[];aws;customOfflineRequests=[];customBuildCallback;onReady;stop(e){this.#e.close(e)}constructor(e,n={debug:!1}){super(n),b.setDebug(n.debug),this.aws=e.aws,this.sco=[],this.#e=pt.default.createServer({maxHeaderSize:105536},this.#r.bind(this)),this.#e.on("connection",s=>{s.on("close",()=>{let i=this.sco.findIndex(o=>o==s);i!=-1&&this.sco.splice(i,1)}),this.sco.push(s)});let r=(0,dt.randomUUID)();v.accountId=Buffer.from(r).toString("hex").slice(0,16),v.apiId=Buffer.from(r).toString("ascii").slice(0,10),v.port=this.port}setPort(e){this.port=e,v.port=e}listen(e=0,n){if(isNaN(e))throw Error("port should be a number");this.#e.once("error",async r=>{r.code==="EADDRINUSE"?(b.RED(r.message),process.exit(1)):console.log(r)}),this.#e.listen(e,async()=>{let{port:r,address:s}=this.#e.address();this.setPort(r),ae&&(k.ip=ae),typeof n=="function"&&await n(r,ae);try{await this.onReady?.(r,k.ip),await Ke(this.handlers,this.aws)}catch(i){console.error(i)}})}#n(e,n){n=n.endsWith("/")?n:`${n}/`;let r=this.customOfflineRequests.find(s=>{let i=!1,o=!0;return typeof s.filter=="string"?(s.filter.endsWith("/")||(s.filter+="/"),i=s.filter==n):s.filter instanceof RegExp&&(i=s.filter.test(n)),typeof s.method=="string"&&s.method.toUpperCase()!="ANY"?o=s.method.toUpperCase()==e:Array.isArray(s.method)&&(s.method.findIndex(l=>l.toUpperCase()=="ANY")!==-1||(o=s.method.findIndex(l=>l.toUpperCase()==e)!==-1)),i&&o});if(r)return r.callback}async#r(e,n){let{url:r,method:s}=e,i=new URL(r,v.dummyHost),o=this.#n(s,i.pathname);if(o)try{await o(e,n)}catch{n.writableFinished||n.end("Internal Server Error")}else{e.on("error",l=>{console.error(l.stack)});let a=()=>{n.setHeader("Content-Type","text/html"),n.statusCode=404,n.end(qe)};this.#t?this.#t(e,n,a):a()}}fakeRebuildEmitter=async()=>{if(this.customBuildCallback)try{await this.customBuildCallback(bn,!0)}catch(e){console.log(e)}console.log(`\x1B[32m${new Date().toLocaleString()} \u{1F504}\u2705 Rebuild\x1B[0m`)};async load(e){for(let n of e){let r=n.runtime.charAt(0);n.runner=r=="n"?new re(n):r=="p"?new se(n,this.fakeRebuildEmitter):r=="r"?new oe(n,this.fakeRebuildEmitter):new ne(n.runtime);let s=new $(n);this.addHandler(s)}}};var ht=require("node:fs/promises"),L=P(require("node:path")),yt=require("node:url"),gt=P(require("esbuild"));var ut="0.0.4";function ft(t){let e=new Set;t.plugins&&(t.plugins=t.plugins.filter((r,s)=>typeof r!="object"||!r||!("name"in r)?!1:((!r.name||!r.name.length||typeof r.name!="string")&&(r.name=`plugin-${s}`,console.warn(`No Plugin name provided at index ${s}`)),e.has(r.name)?r.name=r.name+s:e.add(r.name),!0)));async function n({stop:r,lambdas:s,region:i,esbuild:o,getServices:a,setService:l,addLambda:c,log:d,setEndpoint:m,getEndpoint:f,getAwsProviderDefaults:p,setAwsProviderDefaults:y}){let h={build:{esbuild:t?.build?.esbuild??{},shimRequire:t?.build?.shimRequire,optimizeBuild:t?.build?.optimizeBuild},server:{port:t.server?.port},onKill:[]};if(t.defaults&&typeof t.defaults=="object"&&!Array.isArray(t.defaults)&&y(t.defaults),t.functions&&typeof t.functions=="object"&&!Array.isArray(t.functions))for(let[x,u]of Object.entries(t.functions))c(x,u);t.services&&(t.services.sqs&&l("sqs",t.services.sqs),t.services.sns&&l("sns",t.services.sns),t.services.dynamodb&&l("dynamodb",t.services.dynamodb));let g={stop:r,lambdas:s,region:i,esbuild:o,options:t,config:h,getServices:a,setService:l,addLambda:c,log:d,setEndpoint:m,getEndpoint:f,getAwsProviderDefaults:p};if(t.plugins){h.server.onReady=async(u,S)=>{for(let w of t.plugins)if(w.server?.onReady)try{await w.server.onReady.call(g,u,S)}catch(R){d.RED(w.name),console.error(R)}},h.buildCallback=async(u,S)=>{for(let w of t.plugins)if(w.buildCallback)try{await w.buildCallback.call(g,u,S)}catch(R){d.RED(w.name),console.error(R),S||process.exit(1)}};let x=t.plugins.reduce((u,S)=>(S.server?.request?.length&&u.push(...S.server.request),u),[]);x?.length&&(h.server.request=x.map(u=>(u.callback=u.callback.bind(g),u)));for(let u of t.plugins)if(u.onKill&&h.onKill.push(u.onKill.bind(g)),u.onInit)try{await u.onInit.call(g)}catch(S){throw d.RED(u.name),S}}return h}return n.plugins=t.plugins??[],n}var vn=["js","mjs","cjs","ts","cts","mts"],xn=async t=>{let e=L.default.dirname(L.default.toNamespacedPath(t)),n=L.default.basename(t,L.default.extname(t)),r=L.default.join(e,`__${n}.mjs`);await gt.default.build({outfile:r,entryPoints:[t],bundle:!0,packages:"external",platform:"node",format:"esm",target:`node${process.versions.node.split(".")[0]}`,minify:!0,sourcemap:"inline",sourcesContent:!0});try{return await import((0,yt.pathToFileURL)(r).href)}catch(s){throw s}finally{await(0,ht.rm)(r)}},bt=async t=>{if(t){if(typeof t=="string"){let e=L.default.posix.parse(t),n=L.default.posix.join(e.dir,e.name),r=e.ext.slice(1),s=L.default.posix.resolve(n);vn.includes(r)&&(s+=`.${r}`);let i;try{i=await xn(s)}catch(o){b.YELLOW(`Can not read 'defineConfig' from ${t}`),console.error(o),process.exit(1)}return{exportedFunc:i,configObjectName:r,configPath:s}}if(typeof t=="object"&&!Array.isArray(t))return{configObjectName:"__inline_config__",configPath:"inline define config",exportedFunc:ft(t)}}};var wn=t=>{let e=t.split(";");return e.findIndex(r=>r.toLowerCase().startsWith("path="))==-1&&e.push("Path=/"),e.join(";")},ge=(t,e)=>{let n={};if(t&&Object.entries(t).forEach(([r,s])=>{n[r.toLowerCase()]=Array.isArray(s)?`[${s.join(", ")}]`:s}),Array.isArray(e)){if(!e.every(r=>typeof r=="string")){let r=new Error("Wrong 'cookies'. must be string[]",{cause:e}),s={"Content-Type":n["content-type"]??"application/json","x-amzn-ErrorType":"InternalFailure"};throw n["set-cookie"]&&(s["set-cookie"]=n["set-cookie"]),r.headers=s,r}e=e.map(wn),n["set-cookie"]=n["set-cookie"]?[n["set-cookie"],...e]:e}return n};var be=require("node:crypto");var le=class t extends v{res;mockEvent;payload;constructor({res:e,req:n,body:r,mockEvent:s,multiValueHeaders:i,isBase64Encoded:o,lambdaName:a,parsedURL:l,requestId:c}){super(),this.res=e,this.mockEvent=s,this.payload=s.version==1?t.createApgV1Event({req:n,mockEvent:s,parsedURL:l,lambdaName:a,multiValueHeaders:i,isBase64Encoded:o,requestId:c,body:r}):t.createApgV2Event({req:n,mockEvent:s,parsedURL:l,requestId:c,isBase64Encoded:o,body:r})}static skipHeaders=["connection","content"];static createApgV2Event=({req:e,mockEvent:n,parsedURL:r,requestId:s,isBase64Encoded:i,body:o})=>{let{method:a,headers:l}=e,c=t.getPathParameters(n,r),d,m=n.methods.find(S=>S==a)??"ANY",f={},p="";for(let S of Array.from(new Set(r.searchParams.keys()))){let w=r.searchParams.getAll(S);p+=`&${w.map(R=>encodeURI(`${S}=${R}`)).join("&")}`,f[S]=w.join(",")}p&&(p=p.slice(1));let y=n.paths[0]=="/*"?"$default":`${m} ${r.pathname}`,h=new Date,g="127.0.0.1",x=l.host?.startsWith("localhost")?g:l.host?l.host.split(":")[0]:g,u={version:"2.0",routeKey:y,rawPath:r.pathname,rawQueryString:p,headers:t.getCustomHeaders(e,n),requestContext:{accountId:String(t.accountId),apiId:t.apiId,domainName:`localhost:${t.port}`,domainPrefix:"localhost",http:{method:a,path:r.pathname,protocol:"HTTP/1.1",sourceIp:x,userAgent:l["user-agent"]??""},requestId:s,routeKey:y,stage:"$default",time:h.toISOString(),timeEpoch:h.getTime()}};return o?(u.body=o,u.isBase64Encoded=i):u.isBase64Encoded=!1,Object.keys(f).length&&(u.queryStringParameters=f),Object.keys(c).length&&(u.pathParameters=c),l.cookie&&(u.cookies=l.cookie.split("; ")),d=u,d.headers["x-mock-type"]&&delete d.headers["x-mock-type"],d};static createApgV1Event=({req:e,mockEvent:n,parsedURL:r,lambdaName:s,isBase64Encoded:i,requestId:o,body:a})=>{let{method:l}=e,c={};n.proxy=="httpApi"&&(c.version="1.0");let d=n.paths[0];c.resource=d,c.path=r.pathname,c.httpMethod=l;let{headers:m,multiValueHeaders:f,apiKey:p}=t.getApiGV1Headers(e,n);c.headers=m,c.multiValueHeaders=f;let y=String(e.socket.remoteAddress),h=Object.fromEntries(r.searchParams);c.queryStringParameters=Object.keys(h).length?h:null;let g=t.getMultiValueQueryStringParameters(r.searchParams);c.multiValueQueryStringParameters=Object.keys(g).length?g:null;let x=new Date,u={accountId:String(t.accountId),apiId:t.apiId,domainName:`localhost:${t.port}`,domainPrefix:"localhost",extendedRequestId:"fake-id",httpMethod:l,identity:{accessKey:null,accountId:null,caller:null,cognitoAuthenticationProvider:null,cognitoAuthenticationType:null,cognitoIdentityId:null,cognitoIdentityPoolId:null,principalOrgId:null,sourceIp:y,user:null,userAgent:e.headers["user-agent"],userArn:null},path:r.pathname,protocol:"HTTP/1.1",requestId:o,requestTime:x.toISOString(),requestTimeEpoch:x.getTime(),resourceId:"exhmtv",resourcePath:d};n.proxy=="httpApi"?(u.identity.cognitoAmr=null,u.stage="$default"):(u.stage="dev",n.private&&(u.identity.apiKey=p,u.identity.apiKeyId="abcdefghjk")),c.requestContext=u;let S=t.getPathParameters(n,r);return c.pathParameters=Object.keys(S).length?S:null,c.stageVariables=null,c.body=a??null,c.isBase64Encoded=a?i:!1,c};returnError=e=>{if(this.res.writableFinished)return!0;let n=500,r=t.httpErrMsg;e&&t.isEndpointTimeoutError(e.errorMessage)&&(this.mockEvent.proxy=="httpApi"?(n=503,r=t.unavailable):(n=504,r=t.apgTimeoutMsg));let s=[["Date",new Date().toUTCString()],["Content-Type",t.contentType.json],["Content-Length",String(r.length)],t.keepAlive,["Apigw-Requestid","ETuSEj-PiGYEJdQ="]];return this.res.shouldKeepAlive=!1,this.res.writeHead(n,s),this.res.end(r)};#e=e=>{let n="",r=typeof e;if(r=="string"||r=="number"||r=="boolean")n=String(e);else if(e===null)n="";else throw new Error("");return n};sendV1Response=e=>{let n=[["Date",new Date().toUTCString()],["Apigw-Requestid",Buffer.from((0,be.randomUUID)()).toString("base64").slice(0,16)],t.keepAlive],r=200;if(!e||isNaN(e.statusCode))throw b.RED(`Valid 'http' response payload must be an object which includes a valid 'statusCode'.
|
|
10
10
|
Received:`),console.log(e),new Error;r=e.statusCode,e.headers&&typeof e.headers=="object"&&!Array.isArray(e.headers)&&Object.entries(e.headers).forEach(([c,d])=>{let m=t.normalizeHeaderKey(c),f=this.#e(d);n.push([m,f])}),e.multiValueHeaders&&typeof e.multiValueHeaders=="object"&&!Array.isArray(e.multiValueHeaders)&&Object.entries(e.multiValueHeaders).forEach(([c,d])=>{let m=t.normalizeHeaderKey(c);if(!Array.isArray(d))throw new Error;d.map(p=>this.#e(p)).forEach(p=>{n.push([m,p])})});let s=e.body;if(e.isBase64Encoded&&s){if(typeof s!="string")throw new Error;let c=Buffer.from(s,"base64").toString();if(Buffer.from(c).toString("base64")!=s)throw b.RED("response body is not properly base64 encoded"),new Error;s=c}n.findIndex(c=>c[0].toLowerCase()=="content-type")==-1&&n.push(["Content-Type",t.contentType.json]);let o=n.findIndex(c=>c[0].toLowerCase()=="content-length");o!=-1&&n.splice(o,1);let a=typeof s;a=="number"||a=="boolean"?s=String(s):s&&a!="string"&&b.YELLOW("API Gateway payload v1 return body must be typeof string, number or boolean ");let l=r==204?"0":s?String(Buffer.from(s).byteLength):"0";n.push(["Content-Length",l]),this.res.shouldKeepAlive=!1,this.res.writeHead(r,n),this.res.end(s)};sendV2Response=e=>{this.res.setHeader("Apigw-Requestid",Buffer.from((0,be.randomUUID)()).toString("base64").slice(0,16)),this.res.setHeader("Date",new Date().toUTCString()),e?(typeof e.headers=="object"&&!Array.isArray(e.headers)&&Object.keys(e.headers).filter(s=>s!=="Apigw-Requestid"&&s!=="Date").forEach(s=>{this.res.setHeader(s,e.headers[s])}),e.statusCode?(this.res.statusCode=e.statusCode,e.cookies?.length&&this.res.setHeader("Set-Cookie",e.cookies)):this.res.statusCode=200):this.res.statusCode=200;let n="";if(!e)return this.res.end();if(typeof e=="object"&&typeof e.body=="string"&&(n=e.body,e.isBase64Encoded)){let r=Buffer.from(n,"base64").toString();if(Buffer.from(r).toString("base64")!=n)throw b.RED("response body is not properly base64 encoded"),new Error;n=r}typeof e=="string"?(this.res.setHeader("Content-Type",t.contentType.json),n=e):typeof e=="object"&&!e.statusCode&&(this.res.setHeader("Content-Type",t.contentType.json),n=JSON.stringify(e)),this.res.end(n)};sendResponse=e=>{if(!this.res.writableFinished)return this.mockEvent.version==1?this.sendV1Response(e):this.sendV2Response(e)}};var Rn=(t,e)=>{let n=e.url.stream?t:void 0;if(n){let r=!1,s=t.write.bind(t),i=t.setHeader.bind(t),o,a,l=m=>{a=a?Buffer.concat([a,m]):m},c=()=>{if(a){let m=_e(a),f=m.statusCode??200;try{let p=ge(m.headers,m.cookies);t.writeHead(f,p)}catch(p){t.writeHead(500,p.headers),t.end?.(v.amzMsgNull),delete p.headers}}else t.writeHead(200)};n.setHeader=(m,f)=>{if(m.toLowerCase()=="content-type"){if(f=="application/vnd.awslambda.http-integration-response")return r=!0,i("Content-Type",v.contentType.json);o=f}return i(m,f)};let d=!1;return n.write=(m,f,p)=>{if(n.headersSent)return s(m,f,p);if(d)try{let y=E.codec.decode(m),h=JSON.parse(y);if(Array.isArray(h))throw new Error("Invalid stream response");return h&&typeof h=="object"?(c(),s(m,f,p)):(t.writeHead(200,{"Content-Type":v.contentType.octet}),t.end())}catch(y){let h=new Error(`When using HttpResponseStream first chunk of .write() must be valid JSON and not be Array. Number and null will respones with 200.
|
|
11
11
|
'${e.name}'`);return h.cause=y.message,console.error(h),Z(t)}else if(r)$e(m)?d=!0:l(m);else{if(o==v.contentType.json)try{let h=E.codec.decode(m),g=JSON.parse(h);if(g===null||typeof g=="number")throw new Error(h)}catch(h){let g=new Error(`When 'Content-Type' is 'application/json' first chunk of .write() must be parsable JSON and not be null or number.
|
|
12
12
|
'${e.name}'`);return g.cause=h.message,console.error(g),Z(t)}let y={"Content-Type":o??v.contentType.octet};return n.writeHead(200,y),s(m,f,p)}},n}},In=(t,e,n)=>{let r=K(t),s=r?t.getParsedResponse():t,i,o=!1;if(s&&typeof s=="object"&&s.statusCode){let a=isNaN(s.statusCode),l=a?500:s.statusCode;if(o=!a&&(s.isBase64Encoded==!0||s.isBase64Encoded=="true"),s.headers||s.cookies)try{let c=ge(s.headers,s.cookies);e.writeHead(l,c)}catch(c){return e.writeHead(500,c.headers),delete c.headers,console.error(c),e.end(v.amzMsgNull)}else e.writeHead(l,{"Content-Type":v.contentType.json});n?i=s:(typeof s.body<"u"&&(i=s.body),e.headersSent||e.setHeader("Content-Type",r?v.contentType.octet:v.contentType.json))}else e.writeHead(200,{"Content-Type":v.contentType.json}),i=s;!e.headersSent&&!n&&r&&e.setHeader("Content-Type",v.contentType.octet),n?i instanceof Uint8Array?e.end(i):e.end(JSON.stringify(i)):((typeof i=="number"||typeof i=="boolean"||i==null||i instanceof Object)&&(i=JSON.stringify(i)),i&&o&&(i=Buffer.from(i,"base64")),e.end(i))},St=t=>({filter:/^\/@url\//,callback:async(e,n)=>{let{url:r,method:s,headers:i}=e;if(He(n,s))return;let o=new URL(r,v.dummyHost),a=F(n),l=k.parseNameFromUrl(o.pathname),c=t.handlers.find(h=>h.name==l);if(!c?.url)return n.statusCode=404,n.end("Not Found");let d=v.getIsBase64Encoded(i),m=await D(e,d),f=le.createApgV2Event({req:e,mockEvent:c.url,parsedURL:o,requestId:a,body:m,isBase64Encoded:d}),p=`/@url/${c.name}`,y=o.pathname.slice(p.length);y||(y="/"),f.requestContext.accountId="anonymous",f.rawPath=y,f.requestContext.http.path=y;try{let h=Rn(n,c),g=await c.invoke(f,c.url,void 0,h);if(!g)return n.end();In(g,n,h)}catch(h){console.error(h),Z(n)}}});var vt=t=>({filter:/(^\/2015-03-31\/functions\/.*\/invocations)|(^\/@invoke\/)/,callback:async(e,n)=>{let{url:r,headers:s}=e,i=new URL(r,"http://localhost:3003"),o=k.parseNameFromUrl(i.pathname),a=t.handlers.find(g=>g.name==o),l=F(n);if(n.setHeader("Content-Type","application/json"),e.on("error",g=>{n.statusCode=502,n.end(JSON.stringify(g))}),!a){let{region:g,accountId:x}=t.aws;return n.statusCode=404,n.setHeader("x-amzn-errortype","ResourceNotFoundException"),n.end(X(o,g,x))}let c=s["x-amz-invocation-type"],d=J(s["x-amz-client-context"]);if(d instanceof Error)return n.setHeader("x-amzn-errortype","InvalidRequestContentException"),n.statusCode=400,n.end(Y);let m=c=="DryRun"?204:c=="Event"?202:200,f=await D(e),p=Q(f);if(n.setHeader("X-Amzn-Trace-Id","root=1-xxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxx;sampled=0"),p instanceof Error)return n.statusCode=400,n.setHeader("x-amzn-errortype","InvalidRequestContentException"),n.end(G(p.message));n.setHeader("X-Amz-Executed-Version","$LATEST");let y=new Date,h={};n.statusCode=m,m!==200&&n.end(),m==202&&(h.kind="async");try{let g=await a.invoke(p,h,d);if(m==200){if(typeof g>"u"){n.end();return}let x=K(g),u=x?g.buffer:g;x?u=E.codec.decode(u):typeof u!="string"&&(u=JSON.stringify(u)),n.end(u)}}catch(g){n.writableFinished||(n.setHeader("X-Amz-Function-Error",g.errorType??g.message??""),n.statusCode=200,n.end(JSON.stringify(g)))}}});var Se=require("node:crypto"),xt=require("node:timers/promises");var wt=t=>({filter:"/2015-03-31/functions",method:"POST",async callback(e,n){let r=await D(e),s=JSON.parse(r),{FunctionName:i,Handler:o,Environment:a,Runtime:l,Timeout:c,MemorySize:d}=s;t.addLambda(i,{handler:o,environment:a?.Variables,runtime:l,timeout:c,memorySize:d}),t.isDynamicBuild=!0,t.setEsBuildConfig(),await t.buildContext.dispose(),await t.buildAndWatch(),await(0,xt.setTimeout)(100),n.statusCode=201,n.end(r)}}),Rt=t=>({filter:/\/2015-03-31\/functions\/*/,method:"GET",async callback(e,n){let{url:r}=e,i=new URL(r,"http://localhost:3003").pathname.slice(22),o=t.getLambdaByName(i);if(!o){n.statusCode=404,n.end();return}let a={Code:{RepositoryType:"S3",Location:"https://s3.com/snapshots/1234543"},Tags:{},Configuration:{Architectures:["arm64"],CodeSha256:"WrLckXVmmfsSPvP/15FqPi9Nt9qQBaspP6RV3T137K4=",SigningJobArn:"",FunctionArn:`arn:aws:lambda:${t.aws.region}:${t.aws.accountId}:function:${i}`,FunctionName:i,Handler:o.handlerPath,Timeout:o.timeout,Runtime:o.runtime,MemorySize:o.memorySize,Environment:{Variables:It(o.environment)},State:"Active",LastUpdateStatus:"Successful",LastModified:new Date().toISOString(),Version:"$LATEST",Role:`arn:aws:iam::${t.aws.accountId}:role/fake-role-name`,RevisionId:(0,Se.randomUUID)(),PackageType:"Zip",Description:"",EphemeralStorage:{Size:512},TracingConfig:{Mode:"PassThrough"},VpcConfig:{Ipv6AllowedForDualStack:!1,VpcId:"",SecurityGroupIds:[],SubnetIds:[]},CodeSize:5867,SnapStart:{OptimizationStatus:"Off",ApplyOn:"None"},LoggingConfig:{LogFormat:"Text",LogGroup:`/aws/lambda/${i}`}}};n.end(JSON.stringify(a))}}),En=["AWS_EXECUTION_ENV","AWS_LAMBDA_FUNCTION_VERSION","AWS_LAMBDA_FUNCTION_NAME","_HANDLER","IS_OFFLINE","IS_LOCAL","AWS_SAM_LOCAL","AWS_LAMBDA_FUNCTION_MEMORY_SIZE"];function It(t){let e={};for(let[n,r]of Object.entries(t))En.includes(n)||(e[n]=String(r));return e}var At=t=>({method:"GET",filter:/\/2015-03-31\/functions\/.*\/versions/,async callback(e,n){let{url:r}=e,i=new URL(r,"http://localhost:3003").pathname.slice(22);i=i.slice(0,i.indexOf("/"));let o=t.getLambdaByName(i);if(!o){n.statusCode=404,n.end();return}let a={Versions:[{Architectures:["arm64"],CodeSha256:"WrLckXVmmfsSPvP/15FqPi9Nt9qQBaspP6RV3T137K4=",SigningJobArn:"",FunctionArn:`arn:aws:lambda:${t.aws.region}:${t.aws.accountId}:function:${i}`,FunctionName:i,Handler:o.handlerPath,Timeout:o.timeout,Runtime:o.runtime,MemorySize:o.memorySize,Environment:{Variables:It(o.environment)},State:"Active",LastUpdateStatus:"Successful",LastModified:new Date().toISOString(),Version:"$LATEST",Role:`arn:aws:iam::${t.aws.accountId}:role/fake-role-name`,RevisionId:(0,Se.randomUUID)(),PackageType:"Zip",Description:"",EphemeralStorage:{Size:512},TracingConfig:{Mode:"PassThrough"},VpcConfig:{Ipv6AllowedForDualStack:!1,VpcId:"",SecurityGroupIds:[],SubnetIds:[]},CodeSize:5867,SnapStart:{OptimizationStatus:"Off",ApplyOn:"None"},LoggingConfig:{LogFormat:"Text",LogGroup:`/aws/lambda/${i}`}}]};n.end(JSON.stringify(a))}}),Et=t=>({method:"GET",filter:/\/2020-06-30\/functions\/.*\/code-signing-config/,async callback(e,n){let{url:r}=e,i=new URL(r,"http://localhost:3003").pathname.slice(22);if(i=i.slice(0,i.indexOf("/")),!t.getLambdaByName(i)){n.statusCode=404,n.end();return}let a={CodeSigningConfigArn:"",FunctionName:i};n.end(JSON.stringify(a))}});var kt=require("@smithy/eventstream-codec");var kn=(t,e)=>{let n=Buffer.from(t,e);return new Uint8Array(n.buffer,n.byteOffset,n.byteLength/Uint8Array.BYTES_PER_ELEMENT)},Pn=t=>Buffer.from(t,t.byteOffset,t.byteLength).toString("utf8"),ve=new kt.EventStreamCodec(Pn,kn),de=class t{res;static complete=Buffer.from([0,0,0,102,0,0,0,84,31,86,200,105,11,58,101,118,101,110,116,45,116,121,112,101,7,0,14,73,110,118,111,107,101,67,111,109,112,108,101,116,101,13,58,99,111,110,116,101,110,116,45,116,121,112,101,7,0,16,97,112,112,108,105,99,97,116,105,111,110,47,106,115,111,110,13,58,109,101,115,115,97,103,101,45,116,121,112,101,7,0,5,101,118,101,110,116,123,125,112,6,212,103]);constructor(e){this.res=e}write(e,n,r){this.res.write(ve.encode({headers:this.#e("PayloadChunk",v.contentType.octet),body:e}),n,r)}end(e){e?this.write(e,"utf8",()=>{this.res.end(t.complete)}):this.res.end(t.complete)}setHeader(e,n){e=="Content-Type"&&this.res.setHeader("Content-Type",n)}destroy(){this.res.destroy()}endWithError(e){let n={ErrorCode:e.errorType,ErrorDetails:JSON.stringify(e)},r=Array.from(Buffer.from(JSON.stringify(n)).values());this.res.end(ve.encode({headers:this.#e("InvokeComplete",v.contentType.json),body:new Uint8Array(r)}))}endWithJson(e){let n=Array.from(Buffer.from(JSON.stringify(e)).values());this.res.write(ve.encode({headers:this.#e("PayloadChunk",v.contentType.octet),body:new Uint8Array(n)}),()=>{this.res.end(t.complete)})}#e(e,n,r="event"){return{":event-type":{type:"string",value:e},":content-type":{type:"string",value:n},":message-type":{type:"string",value:r}}}};var Pt=t=>({filter:/^\/2021-11-15\/functions\//,callback:async(e,n)=>{let{url:r,headers:s}=e,i=new URL(r,"http://localhost:3003"),o=F(n),a=k.parseNameFromUrl(i.pathname),l=t.handlers.find(p=>p.name==a),c=await D(e),d=Q(c);if(n.setHeader("X-Amzn-Trace-Id","root=1-xxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxx;sampled=0"),d instanceof Error)return n.statusCode=400,n.setHeader("x-amzn-errortype","InvalidRequestContentException"),n.end(G(d.message));let m=J(s["x-amz-client-context"]);if(m instanceof Error)return n.setHeader("x-amzn-errortype","InvalidRequestContentException"),n.statusCode=400,n.end(Y);let f=new de(n);if(l){let p=l.url?.stream??{};try{let y=await l.invoke(d,p,m,f);y&&f.endWithJson(y)}catch(y){n.writableFinished||f.endWithError(y)}}else{let{region:p,accountId:y}=t.aws;n.statusCode=404,n.end(X(a,p,y))}}});var Ot=t=>[wt(t),At(t),Et(t),vt(t),Pt(t),St(t),Rt(t)];var we=process.cwd(),On=3,Nn=1024,Ln={IS_OFFLINE:!0,IS_LOCAL:!0,AWS_SAM_LOCAL:!0},Dn=we.split(O.default.sep)[0],Tn=new RegExp(`^.*:${Dn}`),Mn=t=>Tn.test(t);process.title="node (exlo)";var pe=class extends ce{#e;options;config;esBuildConfig;buildContext={};customEsBuildConfig;optimizeBuild=!1;nodeVersion=!1;onKill=[];shimRequire=!1;port=0;onceServerReady=[];isDynamicBuild=!1;endpoints={};constructor(e,n){super(e,{debug:typeof n.debug=="boolean"?n.debug:!1}),this.#e=[],this.options=n,this.options.customEsBuildConfig&&(this.customEsBuildConfig=this.options.customEsBuildConfig),this.options.config&&(typeof this.options.config=="string"||typeof this.options.config=="object"&&!Array.isArray(this.options.config))&&(this.config=this.options.config),typeof this.options.optimizeBuild=="boolean"&&(this.optimizeBuild=this.options.optimizeBuild),typeof this.options.shimRequire=="boolean"&&(this.shimRequire=this.options.shimRequire),this.aws.runtime?.startsWith("node")?this.nodeVersion=this.aws.runtime?.replace(/[^0-9]/g,""):this.nodeVersion="20",b.BR_BLUE("Starting exlo...")}async start(){this.#s(),this.#e=this.#r(),await this.#o(),this.setEsBuildConfig(),await this.buildAndWatch()}setEsBuildConfig(){let n={sourcemap:!0,minify:!1,entryPoints:this.#e.filter(r=>r.runtime.startsWith("n")).map(r=>r.esEntryPoint),outdir:O.default.join(we,".exlo","build"),metafile:!0,bundle:!0,platform:"node",target:"node20",format:"cjs",outbase:"src",plugins:[],external:["esbuild"],dropLabels:[]};if(typeof process.env.NODE_ENV=="string"&&(n.define={"process.env.NODE_ENV":`"${process.env.NODE_ENV}"`}),typeof this.nodeVersion=="string"&&!isNaN(Number(this.nodeVersion))){Number(process.versions.node.slice(0,2))<Number(this.nodeVersion)&&b.RED(`You are running on NodeJS ${process.version} which is lower than defined '${this.nodeVersion}'.`),n.target=`node${this.nodeVersion}`;let r=()=>this.sco;n.plugins?.push(ke({nodeVersion:Number(this.nodeVersion),shimRequire:this.shimRequire,optimizeBuild:this.optimizeBuild,buildCallback:this.buildCallback,getSockets:r}))}this.customEsBuildConfig&&(n=Pe(n,this.customEsBuildConfig)),this.esBuildConfig=n}async buildAndWatch(){this.buildContext=await xe.default.context(this.esBuildConfig),await this.buildContext.watch()}buildCallback=async(e,n)=>{if(n||this.isDynamicBuild)await this.#t(e);else{let{outputs:r}=e.metafile;if(this.#i(r),this.customBuildCallback)try{await this.customBuildCallback(e,!1)}catch(o){console.log(o)}this.#a();let s=this,i=await new Promise(o=>{this.listen(this.port,async(a,l)=>{let c=`http://localhost:${a}`;b.PINK(`Lambda endpoint: ${c}`),this.endpoints.lambda=c,await s.load(s.#e);for(let d of s.#e)d.setEnv("LOCAL_PORT",a),d.setEnv("AWS_LAMBDA_RUNTIME_API",`127.0.0.1:${a}`);o({url:c,port:a})})});this.onceServerReady.forEach(o=>{o(i)})}};async#t(e){if(e?.errors?.length)b.RED("Build failed:"),console.error(e.errors);else{this.#i(e.metafile.outputs);try{await this.load(this.#e),this.customBuildCallback&&await this.customBuildCallback(e,!0)}catch(n){console.error(n)}console.log(`\x1B[32m${new Date().toLocaleString()} \u{1F504}\u2705 Rebuild\x1B[0m`)}}#n(e){let n=this.aws,r=n.runtime,s=this.runtimeConfig.environment.AWS_REGION??this.runtimeConfig.environment.REGION,o=n.functions[e],a=o.handler,l=O.default.extname(a),c=l.slice(1),d=O.default.resolve(a.replace(l,"")),m=n.getFunction(e),f=m.runtime??r,p={name:e,runtime:m.runtime??r,handlerPath:a,handlerName:c,esEntryPoint:d,memorySize:o.memorySize??this.runtimeConfig.memorySize??Nn,timeout:o.timeout??this.runtimeConfig.timeout??On,sqs:[],ddb:[],environment:{AWS_EXECUTION_ENV:`AWS_Lambda_${f}`,AWS_LAMBDA_FUNCTION_VERSION:"$LATEST",AWS_LAMBDA_FUNCTION_NAME:e,_HANDLER:O.default.basename(a),...this.runtimeConfig.environment,...o.environment,...Ln},invoke:async(y,h)=>{let g=this.getHandlerByName(`/@invoke/${e}`);if(g)return await g.invoke(y,h);b.RED(`'${e}' is not mounted yet.
|
package/dist/standalone.mjs
CHANGED
|
@@ -6,7 +6,7 @@ Please verify provided SQS Client validity.`),console.error(d)}}},Nt=/(-|\w+)/g,
|
|
|
6
6
|
`)}else A=I;A.trim()&&console.log(A)}}catch(P){console.log("err",P),h(P)}};this.python.stdout.on("data",u);let S=w=>{let R=w.toString();if(R.includes(t.ERR_RESPONSE))try{R=JSON.parse(R.split(t.ERR_RESPONSE)[1]),R.requestId=p}catch{}finally{this.python.stdout.removeListener("data",u),this.python.stderr.removeListener("data",S),h(R)}else console.log(R)};this.python.stderr.on("data",S),this.python.stdin.write(`${g}
|
|
7
7
|
`)}),this.watcherListener=()=>{this.isMounted&&(this.unmount(!0),this.watchers.forEach(d=>d.close()),this.watchers=[],this.emitRebuild())}}setWatchFiles=async e=>{try{let n=e.split(t.WATCH),s=n[n.length-1].split(t.WATCHEND)[0],i=JSON.parse(s).map(o=>`${o.replace(/\./g,_.sep)}.py`);for(let o of i)try{await Ue(o),this.watchers.push(Vt(o,{persistent:!1},this.watcherListener))}catch{}}catch(n){console.log(n)}};findPython(){let[e]=this.runtime.split("."),n=e.split("python")[1];if(ze(`${e} --version`))return e;let r=ze("python --version");if(!r)throw new Error("Can not find python on your OS. Make sure it is installed.");if(n){let s=r.split(" ")[1]?.split(".")[0];s&&s!=n&&b.YELLOW("found python binary but with different version")}return"python"}load=()=>{this.bin||(this.bin=this.findPython()),this.python=Ct(this.bin,["-u",t.wrapper,this.handlerFileAbsolutePath,this.pyModulePath,this.handlerName,String(this.timeout)],{env:this.environment}),this.python.pid||(console.error(`Can not find ${this.bin} in your PATH`),process.exit(1)),this.isMounted=!0};onComplete=e=>{}};import{spawn as Jt}from"node:child_process";import{watch as Qt}from"node:fs";import{access as Ce}from"node:fs/promises";import ne from"node:path";var re=class t{invoke;mount;unmount;name;timeout;memorySize;environment;handlerPath;modulePath;handlerDir;handlerName;runtime;bin;ruby;isMounted=!1;emitRebuild;watcherListener;watchers=[];static wrapper=ne.resolve(M("exlo"),"./src/lib/runtime/runners/ruby/index.rb");static DELIMITER="__|response|__";static ERR_RESPONSE="__|error|__";static WATCH="__|watch|__";constructor({name:e,timeout:n,memorySize:r,environment:s,handlerPath:i,handlerName:o,runtime:a},l){this.name=e,this.timeout=n,this.memorySize=r,this.environment=s,this.handlerName=o,this.runtime=a,this.emitRebuild=l;let c=ne.resolve(i);this.handlerDir=ne.dirname(c),this.handlerPath=ne.basename(c,`.${this.handlerName}`),this.modulePath=`${this.handlerDir}/${this.handlerPath}.rb`,this.mount=async()=>{if(!this.ruby)try{await Ce(this.modulePath),this.load()}catch{console.error(`Can not find ${this.name}'s handler at: "${this.modulePath}"`),process.exit(1)}},this.unmount=d=>{d&&(this.ruby?.kill(),this.ruby=void 0,this.isMounted=!1)},this.invoke=async({event:d,info:m,clientContext:f,awsRequestId:p})=>new Promise((y,h)=>{let g=JSON.stringify({event:d,awsRequestId:p,context:f??""}),x=S=>{let w=null,R=S.toString();try{if(R.includes(t.WATCH))this.setWatchFiles(R);else if(R.includes(t.DELIMITER)){let I=R.split(t.DELIMITER),P=I[I.length-1];if(I.length>1){let A=I.slice(0,-1).join(`
|
|
8
8
|
`);A.trim()&&console.log(A)}P&&(w=JSON.parse(P)),this.ruby.stdout.removeListener("data",x),this.ruby.stderr.removeListener("data",u),y(w)}else R.trim()&&console.log(R)}catch(I){h(I)}};this.ruby.stdout.on("data",x);let u=S=>{let w=S.toString();if(w.includes(t.ERR_RESPONSE))try{w=JSON.parse(w.split(t.ERR_RESPONSE)[1]),w.requestId=p}catch{}finally{this.ruby.stdout.removeListener("data",x),this.ruby.stderr.removeListener("data",u),h(w)}else console.log(w)};this.ruby.stderr.on("data",u),this.ruby.stdin.write(`${g}
|
|
9
|
-
`)}),this.watcherListener=()=>{this.isMounted&&(this.unmount(!0),this.watchers.forEach(d=>d.close()),this.watchers=[],this.emitRebuild())}}setWatchFiles=async e=>{try{let n=e.split(t.WATCH),r=n[n.length-1],s=JSON.parse(r);s.push(this.modulePath);for(let i of s)try{await Ce(i),this.watchers.push(Qt(i,{persistent:!1},this.watcherListener))}catch{}}catch(n){console.log(n)}};load=()=>{this.bin||(this.bin=process.platform==="win32"?"ruby.exe":"ruby"),this.ruby=Jt(this.bin,[t.wrapper,this.modulePath,this.handlerName,this.name,String(this.timeout)],{env:this.environment,shell:!0}),this.ruby.pid||(console.error(`Can not find ${this.bin} in your PATH`),process.exit(1)),this.isMounted=!0};onComplete=e=>{}};var Kt=["@invoke","@url"],k=class t{handlers=[];static ip="127.0.0.1";debug=!1;port=0;constructor(e){this.debug=e.debug}static parseNameFromUrl(e){let n=e.split("/"),r=Kt.includes(n[1])?n[2]:n[3];if(r=decodeURIComponent(r),r.includes(":function:")){let s=r.split(":function:");r=s[s.length-1]}if(r.includes(":")){let s=r.split(":");s.length==2&&(r=s[0])}return r}getHandlerByName(e){if(!e)return;let n=t.parseNameFromUrl(e);return this.handlers.find(r=>r.name==n)}addHandler(e){let n=this.handlers.findIndex(r=>r.name==e.name&&r.esOutputPath==e.esOutputPath);n==-1?(this.handlers.push(e),this.#e("POST",`/2015-03-31/functions/${e.name}/invocations`),e.url&&this.#e("ANY",`/@url/${e.name}`,"34")):this.handlers[n].runtime.startsWith("n")&&(this.handlers[n].clear(),this.handlers[n]=e)}#e(e,n,r="90"){let s=`${e} http://localhost:${this.port}${n}`;console.log(`\x1B[${r}m${s}\x1B[0m`)}};var se;Ve&&(se=Object.values(Ve()).reduce((t,e)=>(t.push(...e),t),[])?.filter(t=>!t.internal&&t.family==="IPv4").find(Boolean)?.address);var Zt=Xt?.url()!=null;Zt&&(console.warn("Lambdas timeout are disabled when a Debugger is attached"),H.ENABLE_TIMEOUT=!1);var en={errors:[],warnings:[],outputFiles:[],metafile:{inputs:{},outputs:{}},mangleCache:{}},ie=class extends k{#e;runtimeConfig={};#t;sco=[];aws;customOfflineRequests=[];customBuildCallback;onReady;stop(e){this.#e.close(e)}constructor(e,n={debug:!1}){super(n),b.setDebug(n.debug),this.aws=e.aws,this.sco=[],this.#e=Yt.createServer({maxHeaderSize:105536},this.#r.bind(this)),this.#e.on("connection",s=>{s.on("close",()=>{let i=this.sco.findIndex(o=>o==s);i!=-1&&this.sco.splice(i,1)}),this.sco.push(s)});let r=Gt();v.accountId=Buffer.from(r).toString("hex").slice(0,16),v.apiId=Buffer.from(r).toString("ascii").slice(0,10),v.port=this.port}setPort(e){this.port=e,v.port=e}listen(e=0,n){if(isNaN(e))throw Error("port should be a number");this.#e.once("error",async r=>{r.code==="EADDRINUSE"?(b.RED(r.message),process.exit(1)):console.log(r)}),this.#e.listen(e,async()=>{let{port:r,address:s}=this.#e.address();this.setPort(r),se&&(k.ip=se),typeof n=="function"&&await n(r,se);try{await this.onReady?.(r,k.ip),await je(this.handlers,this.aws)}catch(i){console.error(i)}})}#n(e,n){n=n.endsWith("/")?n:`${n}/`;let r=this.customOfflineRequests.find(s=>{let i=!1,o=!0;return typeof s.filter=="string"?(s.filter.endsWith("/")||(s.filter+="/"),i=s.filter==n):s.filter instanceof RegExp&&(i=s.filter.test(n)),typeof s.method=="string"&&s.method.toUpperCase()!="ANY"?o=s.method.toUpperCase()==e:Array.isArray(s.method)&&(s.method.findIndex(l=>l.toUpperCase()=="ANY")!==-1||(o=s.method.findIndex(l=>l.toUpperCase()==e)!==-1)),i&&o});if(r)return r.callback}async#r(e,n){let{url:r,method:s}=e,i=new URL(r,v.dummyHost),o=this.#n(s,i.pathname);if(o)try{await o(e,n)}catch{n.writableFinished||n.end("Internal Server Error")}else{e.on("error",l=>{console.error(l.stack)});let a=()=>{n.setHeader("Content-Type","text/html"),n.statusCode=404,n.end(Ae)};this.#t?this.#t(e,n,a):a()}}fakeRebuildEmitter=async()=>{if(this.customBuildCallback)try{await this.customBuildCallback(en,!0)}catch(e){console.log(e)}console.log(`\x1B[32m${new Date().toLocaleString()} \u{1F504}\u2705 Rebuild\x1B[0m`)};async load(e){for(let n of e){let r=n.runtime.charAt(0);n.runner=r=="n"?new ee(n):r=="p"?new te(n,this.fakeRebuildEmitter):r=="r"?new re(n,this.fakeRebuildEmitter):new Z(n.runtime);let s=new H(n);this.addHandler(s)}}};import{rm as rn}from"node:fs/promises";import L from"node:path";import{pathToFileURL as sn}from"node:url";import on from"esbuild";var nn="0.0.3";function Be(t){let e=new Set;t.plugins&&(t.plugins=t.plugins.filter((r,s)=>typeof r!="object"||!r||!("name"in r)?!1:((!r.name||!r.name.length||typeof r.name!="string")&&(r.name=`plugin-${s}`,console.warn(`No Plugin name provided at index ${s}`)),e.has(r.name)?r.name=r.name+s:e.add(r.name),!0)));async function n({stop:r,lambdas:s,region:i,esbuild:o,getServices:a,setService:l,addLambda:c,log:d,setEndpoint:m,getEndpoint:f,getAwsProviderDefaults:p,setAwsProviderDefaults:y}){let h={build:{esbuild:t?.build?.esbuild??{},shimRequire:t?.build?.shimRequire,optimizeBuild:t?.build?.optimizeBuild},server:{port:t.server?.port},onKill:[]};if(t.defaults&&typeof t.defaults=="object"&&!Array.isArray(t.defaults)&&y(t.defaults),t.functions&&typeof t.functions=="object"&&!Array.isArray(t.functions))for(let[x,u]of Object.entries(t.functions))c(x,u);t.services&&(t.services.sqs&&l("sqs",t.services.sqs),t.services.sns&&l("sns",t.services.sns),t.services.dynamodb&&l("dynamodb",t.services.dynamodb));let g={stop:r,lambdas:s,region:i,esbuild:o,options:t,config:h,getServices:a,setService:l,addLambda:c,log:d,setEndpoint:m,getEndpoint:f,getAwsProviderDefaults:p};if(t.plugins){h.server.onReady=async(u,S)=>{for(let w of t.plugins)if(w.server?.onReady)try{await w.server.onReady.call(g,u,S)}catch(R){d.RED(w.name),console.error(R)}},h.buildCallback=async(u,S)=>{for(let w of t.plugins)if(w.buildCallback)try{await w.buildCallback.call(g,u,S)}catch(R){d.RED(w.name),console.error(R),S||process.exit(1)}};let x=t.plugins.reduce((u,S)=>(S.server?.request?.length&&u.push(...S.server.request),u),[]);x?.length&&(h.server.request=x.map(u=>(u.callback=u.callback.bind(g),u)));for(let u of t.plugins)if(u.onKill&&h.onKill.push(u.onKill.bind(g)),u.onInit)try{await u.onInit.call(g)}catch(S){throw d.RED(u.name),S}}return h}return n.plugins=t.plugins??[],n}var an=["js","mjs","cjs","ts","cts","mts"],cn=async t=>{let e=L.dirname(L.toNamespacedPath(t)),n=L.basename(t,L.extname(t)),r=L.join(e,`__${n}.mjs`);await on.build({outfile:r,entryPoints:[t],bundle:!0,packages:"external",platform:"node",format:"esm",target:`node${process.versions.node.split(".")[0]}`,minify:!0,sourcemap:"inline",sourcesContent:!0});try{return await import(sn(r).href)}catch(s){throw s}finally{await rn(r)}},Je=async t=>{if(t){if(typeof t=="string"){let e=L.posix.parse(t),n=L.posix.join(e.dir,e.name),r=e.ext.slice(1),s=L.posix.resolve(n);an.includes(r)&&(s+=`.${r}`);let i;try{i=await cn(s)}catch(o){b.YELLOW(`Can not read 'defineConfig' from ${t}`),console.error(o),process.exit(1)}return{exportedFunc:i,configObjectName:r,configPath:s}}if(typeof t=="object"&&!Array.isArray(t))return{configObjectName:"__inline_config__",configPath:"inline define config",exportedFunc:Be(t)}}};var ln=t=>{let e=t.split(";");return e.findIndex(r=>r.toLowerCase().startsWith("path="))==-1&&e.push("Path=/"),e.join(";")},de=(t,e)=>{let n={};if(t&&Object.entries(t).forEach(([r,s])=>{n[r.toLowerCase()]=Array.isArray(s)?`[${s.join(", ")}]`:s}),Array.isArray(e)){if(!e.every(r=>typeof r=="string")){let r=new Error("Wrong 'cookies'. must be string[]",{cause:e}),s={"Content-Type":n["content-type"]??"application/json","x-amzn-ErrorType":"InternalFailure"};throw n["set-cookie"]&&(s["set-cookie"]=n["set-cookie"]),r.headers=s,r}e=e.map(ln),n["set-cookie"]=n["set-cookie"]?[n["set-cookie"],...e]:e}return n};import{randomUUID as Qe}from"node:crypto";var oe=class t extends v{res;mockEvent;payload;constructor({res:e,req:n,body:r,mockEvent:s,multiValueHeaders:i,isBase64Encoded:o,lambdaName:a,parsedURL:l,requestId:c}){super(),this.res=e,this.mockEvent=s,this.payload=s.version==1?t.createApgV1Event({req:n,mockEvent:s,parsedURL:l,lambdaName:a,multiValueHeaders:i,isBase64Encoded:o,requestId:c,body:r}):t.createApgV2Event({req:n,mockEvent:s,parsedURL:l,requestId:c,isBase64Encoded:o,body:r})}static skipHeaders=["connection","content"];static createApgV2Event=({req:e,mockEvent:n,parsedURL:r,requestId:s,isBase64Encoded:i,body:o})=>{let{method:a,headers:l}=e,c=t.getPathParameters(n,r),d,m=n.methods.find(S=>S==a)??"ANY",f={},p="";for(let S of Array.from(new Set(r.searchParams.keys()))){let w=r.searchParams.getAll(S);p+=`&${w.map(R=>encodeURI(`${S}=${R}`)).join("&")}`,f[S]=w.join(",")}p&&(p=p.slice(1));let y=n.paths[0]=="/*"?"$default":`${m} ${r.pathname}`,h=new Date,g="127.0.0.1",x=l.host?.startsWith("localhost")?g:l.host?l.host.split(":")[0]:g,u={version:"2.0",routeKey:y,rawPath:r.pathname,rawQueryString:p,headers:t.getCustomHeaders(e,n),requestContext:{accountId:String(t.accountId),apiId:t.apiId,domainName:`localhost:${t.port}`,domainPrefix:"localhost",http:{method:a,path:r.pathname,protocol:"HTTP/1.1",sourceIp:x,userAgent:l["user-agent"]??""},requestId:s,routeKey:y,stage:"$default",time:h.toISOString(),timeEpoch:h.getTime()}};return o?(u.body=o,u.isBase64Encoded=i):u.isBase64Encoded=!1,Object.keys(f).length&&(u.queryStringParameters=f),Object.keys(c).length&&(u.pathParameters=c),l.cookie&&(u.cookies=l.cookie.split("; ")),d=u,d.headers["x-mock-type"]&&delete d.headers["x-mock-type"],d};static createApgV1Event=({req:e,mockEvent:n,parsedURL:r,lambdaName:s,isBase64Encoded:i,requestId:o,body:a})=>{let{method:l}=e,c={};n.proxy=="httpApi"&&(c.version="1.0");let d=n.paths[0];c.resource=d,c.path=r.pathname,c.httpMethod=l;let{headers:m,multiValueHeaders:f,apiKey:p}=t.getApiGV1Headers(e,n);c.headers=m,c.multiValueHeaders=f;let y=String(e.socket.remoteAddress),h=Object.fromEntries(r.searchParams);c.queryStringParameters=Object.keys(h).length?h:null;let g=t.getMultiValueQueryStringParameters(r.searchParams);c.multiValueQueryStringParameters=Object.keys(g).length?g:null;let x=new Date,u={accountId:String(t.accountId),apiId:t.apiId,domainName:`localhost:${t.port}`,domainPrefix:"localhost",extendedRequestId:"fake-id",httpMethod:l,identity:{accessKey:null,accountId:null,caller:null,cognitoAuthenticationProvider:null,cognitoAuthenticationType:null,cognitoIdentityId:null,cognitoIdentityPoolId:null,principalOrgId:null,sourceIp:y,user:null,userAgent:e.headers["user-agent"],userArn:null},path:r.pathname,protocol:"HTTP/1.1",requestId:o,requestTime:x.toISOString(),requestTimeEpoch:x.getTime(),resourceId:"exhmtv",resourcePath:d};n.proxy=="httpApi"?(u.identity.cognitoAmr=null,u.stage="$default"):(u.stage="dev",n.private&&(u.identity.apiKey=p,u.identity.apiKeyId="abcdefghjk")),c.requestContext=u;let S=t.getPathParameters(n,r);return c.pathParameters=Object.keys(S).length?S:null,c.stageVariables=null,c.body=a??null,c.isBase64Encoded=a?i:!1,c};returnError=e=>{if(this.res.writableFinished)return!0;let n=500,r=t.httpErrMsg;e&&t.isEndpointTimeoutError(e.errorMessage)&&(this.mockEvent.proxy=="httpApi"?(n=503,r=t.unavailable):(n=504,r=t.apgTimeoutMsg));let s=[["Date",new Date().toUTCString()],["Content-Type",t.contentType.json],["Content-Length",String(r.length)],t.keepAlive,["Apigw-Requestid","ETuSEj-PiGYEJdQ="]];return this.res.shouldKeepAlive=!1,this.res.writeHead(n,s),this.res.end(r)};#e=e=>{let n="",r=typeof e;if(r=="string"||r=="number"||r=="boolean")n=String(e);else if(e===null)n="";else throw new Error("");return n};sendV1Response=e=>{let n=[["Date",new Date().toUTCString()],["Apigw-Requestid",Buffer.from(Qe()).toString("base64").slice(0,16)],t.keepAlive],r=200;if(!e||isNaN(e.statusCode))throw b.RED(`Valid 'http' response payload must be an object which includes a valid 'statusCode'.
|
|
9
|
+
`)}),this.watcherListener=()=>{this.isMounted&&(this.unmount(!0),this.watchers.forEach(d=>d.close()),this.watchers=[],this.emitRebuild())}}setWatchFiles=async e=>{try{let n=e.split(t.WATCH),r=n[n.length-1],s=JSON.parse(r);s.push(this.modulePath);for(let i of s)try{await Ce(i),this.watchers.push(Qt(i,{persistent:!1},this.watcherListener))}catch{}}catch(n){console.log(n)}};load=()=>{this.bin||(this.bin=process.platform==="win32"?"ruby.exe":"ruby"),this.ruby=Jt(this.bin,[t.wrapper,this.modulePath,this.handlerName,this.name,String(this.timeout)],{env:this.environment,shell:!0}),this.ruby.pid||(console.error(`Can not find ${this.bin} in your PATH`),process.exit(1)),this.isMounted=!0};onComplete=e=>{}};var Kt=["@invoke","@url"],k=class t{handlers=[];static ip="127.0.0.1";debug=!1;port=0;constructor(e){this.debug=e.debug}static parseNameFromUrl(e){let n=e.split("/"),r=Kt.includes(n[1])?n[2]:n[3];if(r=decodeURIComponent(r),r.includes(":function:")){let s=r.split(":function:");r=s[s.length-1]}if(r.includes(":")){let s=r.split(":");s.length==2&&(r=s[0])}return r}getHandlerByName(e){if(!e)return;let n=t.parseNameFromUrl(e);return this.handlers.find(r=>r.name==n)}addHandler(e){let n=this.handlers.findIndex(r=>r.name==e.name&&r.esOutputPath==e.esOutputPath);n==-1?(this.handlers.push(e),this.#e("POST",`/2015-03-31/functions/${e.name}/invocations`),e.url&&this.#e("ANY",`/@url/${e.name}`,"34")):this.handlers[n].runtime.startsWith("n")&&(this.handlers[n].clear(),this.handlers[n]=e)}#e(e,n,r="90"){let s=`${e} http://localhost:${this.port}${n}`;console.log(`\x1B[${r}m${s}\x1B[0m`)}};var se;Ve&&(se=Object.values(Ve()).reduce((t,e)=>(t.push(...e),t),[])?.filter(t=>!t.internal&&t.family==="IPv4").find(Boolean)?.address);var Zt=Xt?.url()!=null;Zt&&(console.warn("Lambdas timeout are disabled when a Debugger is attached"),H.ENABLE_TIMEOUT=!1);var en={errors:[],warnings:[],outputFiles:[],metafile:{inputs:{},outputs:{}},mangleCache:{}},ie=class extends k{#e;runtimeConfig={};#t;sco=[];aws;customOfflineRequests=[];customBuildCallback;onReady;stop(e){this.#e.close(e)}constructor(e,n={debug:!1}){super(n),b.setDebug(n.debug),this.aws=e.aws,this.sco=[],this.#e=Yt.createServer({maxHeaderSize:105536},this.#r.bind(this)),this.#e.on("connection",s=>{s.on("close",()=>{let i=this.sco.findIndex(o=>o==s);i!=-1&&this.sco.splice(i,1)}),this.sco.push(s)});let r=Gt();v.accountId=Buffer.from(r).toString("hex").slice(0,16),v.apiId=Buffer.from(r).toString("ascii").slice(0,10),v.port=this.port}setPort(e){this.port=e,v.port=e}listen(e=0,n){if(isNaN(e))throw Error("port should be a number");this.#e.once("error",async r=>{r.code==="EADDRINUSE"?(b.RED(r.message),process.exit(1)):console.log(r)}),this.#e.listen(e,async()=>{let{port:r,address:s}=this.#e.address();this.setPort(r),se&&(k.ip=se),typeof n=="function"&&await n(r,se);try{await this.onReady?.(r,k.ip),await je(this.handlers,this.aws)}catch(i){console.error(i)}})}#n(e,n){n=n.endsWith("/")?n:`${n}/`;let r=this.customOfflineRequests.find(s=>{let i=!1,o=!0;return typeof s.filter=="string"?(s.filter.endsWith("/")||(s.filter+="/"),i=s.filter==n):s.filter instanceof RegExp&&(i=s.filter.test(n)),typeof s.method=="string"&&s.method.toUpperCase()!="ANY"?o=s.method.toUpperCase()==e:Array.isArray(s.method)&&(s.method.findIndex(l=>l.toUpperCase()=="ANY")!==-1||(o=s.method.findIndex(l=>l.toUpperCase()==e)!==-1)),i&&o});if(r)return r.callback}async#r(e,n){let{url:r,method:s}=e,i=new URL(r,v.dummyHost),o=this.#n(s,i.pathname);if(o)try{await o(e,n)}catch{n.writableFinished||n.end("Internal Server Error")}else{e.on("error",l=>{console.error(l.stack)});let a=()=>{n.setHeader("Content-Type","text/html"),n.statusCode=404,n.end(Ae)};this.#t?this.#t(e,n,a):a()}}fakeRebuildEmitter=async()=>{if(this.customBuildCallback)try{await this.customBuildCallback(en,!0)}catch(e){console.log(e)}console.log(`\x1B[32m${new Date().toLocaleString()} \u{1F504}\u2705 Rebuild\x1B[0m`)};async load(e){for(let n of e){let r=n.runtime.charAt(0);n.runner=r=="n"?new ee(n):r=="p"?new te(n,this.fakeRebuildEmitter):r=="r"?new re(n,this.fakeRebuildEmitter):new Z(n.runtime);let s=new H(n);this.addHandler(s)}}};import{rm as rn}from"node:fs/promises";import L from"node:path";import{pathToFileURL as sn}from"node:url";import on from"esbuild";var nn="0.0.4";function Be(t){let e=new Set;t.plugins&&(t.plugins=t.plugins.filter((r,s)=>typeof r!="object"||!r||!("name"in r)?!1:((!r.name||!r.name.length||typeof r.name!="string")&&(r.name=`plugin-${s}`,console.warn(`No Plugin name provided at index ${s}`)),e.has(r.name)?r.name=r.name+s:e.add(r.name),!0)));async function n({stop:r,lambdas:s,region:i,esbuild:o,getServices:a,setService:l,addLambda:c,log:d,setEndpoint:m,getEndpoint:f,getAwsProviderDefaults:p,setAwsProviderDefaults:y}){let h={build:{esbuild:t?.build?.esbuild??{},shimRequire:t?.build?.shimRequire,optimizeBuild:t?.build?.optimizeBuild},server:{port:t.server?.port},onKill:[]};if(t.defaults&&typeof t.defaults=="object"&&!Array.isArray(t.defaults)&&y(t.defaults),t.functions&&typeof t.functions=="object"&&!Array.isArray(t.functions))for(let[x,u]of Object.entries(t.functions))c(x,u);t.services&&(t.services.sqs&&l("sqs",t.services.sqs),t.services.sns&&l("sns",t.services.sns),t.services.dynamodb&&l("dynamodb",t.services.dynamodb));let g={stop:r,lambdas:s,region:i,esbuild:o,options:t,config:h,getServices:a,setService:l,addLambda:c,log:d,setEndpoint:m,getEndpoint:f,getAwsProviderDefaults:p};if(t.plugins){h.server.onReady=async(u,S)=>{for(let w of t.plugins)if(w.server?.onReady)try{await w.server.onReady.call(g,u,S)}catch(R){d.RED(w.name),console.error(R)}},h.buildCallback=async(u,S)=>{for(let w of t.plugins)if(w.buildCallback)try{await w.buildCallback.call(g,u,S)}catch(R){d.RED(w.name),console.error(R),S||process.exit(1)}};let x=t.plugins.reduce((u,S)=>(S.server?.request?.length&&u.push(...S.server.request),u),[]);x?.length&&(h.server.request=x.map(u=>(u.callback=u.callback.bind(g),u)));for(let u of t.plugins)if(u.onKill&&h.onKill.push(u.onKill.bind(g)),u.onInit)try{await u.onInit.call(g)}catch(S){throw d.RED(u.name),S}}return h}return n.plugins=t.plugins??[],n}var an=["js","mjs","cjs","ts","cts","mts"],cn=async t=>{let e=L.dirname(L.toNamespacedPath(t)),n=L.basename(t,L.extname(t)),r=L.join(e,`__${n}.mjs`);await on.build({outfile:r,entryPoints:[t],bundle:!0,packages:"external",platform:"node",format:"esm",target:`node${process.versions.node.split(".")[0]}`,minify:!0,sourcemap:"inline",sourcesContent:!0});try{return await import(sn(r).href)}catch(s){throw s}finally{await rn(r)}},Je=async t=>{if(t){if(typeof t=="string"){let e=L.posix.parse(t),n=L.posix.join(e.dir,e.name),r=e.ext.slice(1),s=L.posix.resolve(n);an.includes(r)&&(s+=`.${r}`);let i;try{i=await cn(s)}catch(o){b.YELLOW(`Can not read 'defineConfig' from ${t}`),console.error(o),process.exit(1)}return{exportedFunc:i,configObjectName:r,configPath:s}}if(typeof t=="object"&&!Array.isArray(t))return{configObjectName:"__inline_config__",configPath:"inline define config",exportedFunc:Be(t)}}};var ln=t=>{let e=t.split(";");return e.findIndex(r=>r.toLowerCase().startsWith("path="))==-1&&e.push("Path=/"),e.join(";")},de=(t,e)=>{let n={};if(t&&Object.entries(t).forEach(([r,s])=>{n[r.toLowerCase()]=Array.isArray(s)?`[${s.join(", ")}]`:s}),Array.isArray(e)){if(!e.every(r=>typeof r=="string")){let r=new Error("Wrong 'cookies'. must be string[]",{cause:e}),s={"Content-Type":n["content-type"]??"application/json","x-amzn-ErrorType":"InternalFailure"};throw n["set-cookie"]&&(s["set-cookie"]=n["set-cookie"]),r.headers=s,r}e=e.map(ln),n["set-cookie"]=n["set-cookie"]?[n["set-cookie"],...e]:e}return n};import{randomUUID as Qe}from"node:crypto";var oe=class t extends v{res;mockEvent;payload;constructor({res:e,req:n,body:r,mockEvent:s,multiValueHeaders:i,isBase64Encoded:o,lambdaName:a,parsedURL:l,requestId:c}){super(),this.res=e,this.mockEvent=s,this.payload=s.version==1?t.createApgV1Event({req:n,mockEvent:s,parsedURL:l,lambdaName:a,multiValueHeaders:i,isBase64Encoded:o,requestId:c,body:r}):t.createApgV2Event({req:n,mockEvent:s,parsedURL:l,requestId:c,isBase64Encoded:o,body:r})}static skipHeaders=["connection","content"];static createApgV2Event=({req:e,mockEvent:n,parsedURL:r,requestId:s,isBase64Encoded:i,body:o})=>{let{method:a,headers:l}=e,c=t.getPathParameters(n,r),d,m=n.methods.find(S=>S==a)??"ANY",f={},p="";for(let S of Array.from(new Set(r.searchParams.keys()))){let w=r.searchParams.getAll(S);p+=`&${w.map(R=>encodeURI(`${S}=${R}`)).join("&")}`,f[S]=w.join(",")}p&&(p=p.slice(1));let y=n.paths[0]=="/*"?"$default":`${m} ${r.pathname}`,h=new Date,g="127.0.0.1",x=l.host?.startsWith("localhost")?g:l.host?l.host.split(":")[0]:g,u={version:"2.0",routeKey:y,rawPath:r.pathname,rawQueryString:p,headers:t.getCustomHeaders(e,n),requestContext:{accountId:String(t.accountId),apiId:t.apiId,domainName:`localhost:${t.port}`,domainPrefix:"localhost",http:{method:a,path:r.pathname,protocol:"HTTP/1.1",sourceIp:x,userAgent:l["user-agent"]??""},requestId:s,routeKey:y,stage:"$default",time:h.toISOString(),timeEpoch:h.getTime()}};return o?(u.body=o,u.isBase64Encoded=i):u.isBase64Encoded=!1,Object.keys(f).length&&(u.queryStringParameters=f),Object.keys(c).length&&(u.pathParameters=c),l.cookie&&(u.cookies=l.cookie.split("; ")),d=u,d.headers["x-mock-type"]&&delete d.headers["x-mock-type"],d};static createApgV1Event=({req:e,mockEvent:n,parsedURL:r,lambdaName:s,isBase64Encoded:i,requestId:o,body:a})=>{let{method:l}=e,c={};n.proxy=="httpApi"&&(c.version="1.0");let d=n.paths[0];c.resource=d,c.path=r.pathname,c.httpMethod=l;let{headers:m,multiValueHeaders:f,apiKey:p}=t.getApiGV1Headers(e,n);c.headers=m,c.multiValueHeaders=f;let y=String(e.socket.remoteAddress),h=Object.fromEntries(r.searchParams);c.queryStringParameters=Object.keys(h).length?h:null;let g=t.getMultiValueQueryStringParameters(r.searchParams);c.multiValueQueryStringParameters=Object.keys(g).length?g:null;let x=new Date,u={accountId:String(t.accountId),apiId:t.apiId,domainName:`localhost:${t.port}`,domainPrefix:"localhost",extendedRequestId:"fake-id",httpMethod:l,identity:{accessKey:null,accountId:null,caller:null,cognitoAuthenticationProvider:null,cognitoAuthenticationType:null,cognitoIdentityId:null,cognitoIdentityPoolId:null,principalOrgId:null,sourceIp:y,user:null,userAgent:e.headers["user-agent"],userArn:null},path:r.pathname,protocol:"HTTP/1.1",requestId:o,requestTime:x.toISOString(),requestTimeEpoch:x.getTime(),resourceId:"exhmtv",resourcePath:d};n.proxy=="httpApi"?(u.identity.cognitoAmr=null,u.stage="$default"):(u.stage="dev",n.private&&(u.identity.apiKey=p,u.identity.apiKeyId="abcdefghjk")),c.requestContext=u;let S=t.getPathParameters(n,r);return c.pathParameters=Object.keys(S).length?S:null,c.stageVariables=null,c.body=a??null,c.isBase64Encoded=a?i:!1,c};returnError=e=>{if(this.res.writableFinished)return!0;let n=500,r=t.httpErrMsg;e&&t.isEndpointTimeoutError(e.errorMessage)&&(this.mockEvent.proxy=="httpApi"?(n=503,r=t.unavailable):(n=504,r=t.apgTimeoutMsg));let s=[["Date",new Date().toUTCString()],["Content-Type",t.contentType.json],["Content-Length",String(r.length)],t.keepAlive,["Apigw-Requestid","ETuSEj-PiGYEJdQ="]];return this.res.shouldKeepAlive=!1,this.res.writeHead(n,s),this.res.end(r)};#e=e=>{let n="",r=typeof e;if(r=="string"||r=="number"||r=="boolean")n=String(e);else if(e===null)n="";else throw new Error("");return n};sendV1Response=e=>{let n=[["Date",new Date().toUTCString()],["Apigw-Requestid",Buffer.from(Qe()).toString("base64").slice(0,16)],t.keepAlive],r=200;if(!e||isNaN(e.statusCode))throw b.RED(`Valid 'http' response payload must be an object which includes a valid 'statusCode'.
|
|
10
10
|
Received:`),console.log(e),new Error;r=e.statusCode,e.headers&&typeof e.headers=="object"&&!Array.isArray(e.headers)&&Object.entries(e.headers).forEach(([c,d])=>{let m=t.normalizeHeaderKey(c),f=this.#e(d);n.push([m,f])}),e.multiValueHeaders&&typeof e.multiValueHeaders=="object"&&!Array.isArray(e.multiValueHeaders)&&Object.entries(e.multiValueHeaders).forEach(([c,d])=>{let m=t.normalizeHeaderKey(c);if(!Array.isArray(d))throw new Error;d.map(p=>this.#e(p)).forEach(p=>{n.push([m,p])})});let s=e.body;if(e.isBase64Encoded&&s){if(typeof s!="string")throw new Error;let c=Buffer.from(s,"base64").toString();if(Buffer.from(c).toString("base64")!=s)throw b.RED("response body is not properly base64 encoded"),new Error;s=c}n.findIndex(c=>c[0].toLowerCase()=="content-type")==-1&&n.push(["Content-Type",t.contentType.json]);let o=n.findIndex(c=>c[0].toLowerCase()=="content-length");o!=-1&&n.splice(o,1);let a=typeof s;a=="number"||a=="boolean"?s=String(s):s&&a!="string"&&b.YELLOW("API Gateway payload v1 return body must be typeof string, number or boolean ");let l=r==204?"0":s?String(Buffer.from(s).byteLength):"0";n.push(["Content-Length",l]),this.res.shouldKeepAlive=!1,this.res.writeHead(r,n),this.res.end(s)};sendV2Response=e=>{this.res.setHeader("Apigw-Requestid",Buffer.from(Qe()).toString("base64").slice(0,16)),this.res.setHeader("Date",new Date().toUTCString()),e?(typeof e.headers=="object"&&!Array.isArray(e.headers)&&Object.keys(e.headers).filter(s=>s!=="Apigw-Requestid"&&s!=="Date").forEach(s=>{this.res.setHeader(s,e.headers[s])}),e.statusCode?(this.res.statusCode=e.statusCode,e.cookies?.length&&this.res.setHeader("Set-Cookie",e.cookies)):this.res.statusCode=200):this.res.statusCode=200;let n="";if(!e)return this.res.end();if(typeof e=="object"&&typeof e.body=="string"&&(n=e.body,e.isBase64Encoded)){let r=Buffer.from(n,"base64").toString();if(Buffer.from(r).toString("base64")!=n)throw b.RED("response body is not properly base64 encoded"),new Error;n=r}typeof e=="string"?(this.res.setHeader("Content-Type",t.contentType.json),n=e):typeof e=="object"&&!e.statusCode&&(this.res.setHeader("Content-Type",t.contentType.json),n=JSON.stringify(e)),this.res.end(n)};sendResponse=e=>{if(!this.res.writableFinished)return this.mockEvent.version==1?this.sendV1Response(e):this.sendV2Response(e)}};var dn=(t,e)=>{let n=e.url.stream?t:void 0;if(n){let r=!1,s=t.write.bind(t),i=t.setHeader.bind(t),o,a,l=m=>{a=a?Buffer.concat([a,m]):m},c=()=>{if(a){let m=Pe(a),f=m.statusCode??200;try{let p=de(m.headers,m.cookies);t.writeHead(f,p)}catch(p){t.writeHead(500,p.headers),t.end?.(v.amzMsgNull),delete p.headers}}else t.writeHead(200)};n.setHeader=(m,f)=>{if(m.toLowerCase()=="content-type"){if(f=="application/vnd.awslambda.http-integration-response")return r=!0,i("Content-Type",v.contentType.json);o=f}return i(m,f)};let d=!1;return n.write=(m,f,p)=>{if(n.headersSent)return s(m,f,p);if(d)try{let y=E.codec.decode(m),h=JSON.parse(y);if(Array.isArray(h))throw new Error("Invalid stream response");return h&&typeof h=="object"?(c(),s(m,f,p)):(t.writeHead(200,{"Content-Type":v.contentType.octet}),t.end())}catch(y){let h=new Error(`When using HttpResponseStream first chunk of .write() must be valid JSON and not be Array. Number and null will respones with 200.
|
|
11
11
|
'${e.name}'`);return h.cause=y.message,console.error(h),G(t)}else if(r)Oe(m)?d=!0:l(m);else{if(o==v.contentType.json)try{let h=E.codec.decode(m),g=JSON.parse(h);if(g===null||typeof g=="number")throw new Error(h)}catch(h){let g=new Error(`When 'Content-Type' is 'application/json' first chunk of .write() must be parsable JSON and not be null or number.
|
|
12
12
|
'${e.name}'`);return g.cause=h.message,console.error(g),G(t)}let y={"Content-Type":o??v.contentType.octet};return n.writeHead(200,y),s(m,f,p)}},n}},pn=(t,e,n)=>{let r=B(t),s=r?t.getParsedResponse():t,i,o=!1;if(s&&typeof s=="object"&&s.statusCode){let a=isNaN(s.statusCode),l=a?500:s.statusCode;if(o=!a&&(s.isBase64Encoded==!0||s.isBase64Encoded=="true"),s.headers||s.cookies)try{let c=de(s.headers,s.cookies);e.writeHead(l,c)}catch(c){return e.writeHead(500,c.headers),delete c.headers,console.error(c),e.end(v.amzMsgNull)}else e.writeHead(l,{"Content-Type":v.contentType.json});n?i=s:(typeof s.body<"u"&&(i=s.body),e.headersSent||e.setHeader("Content-Type",r?v.contentType.octet:v.contentType.json))}else e.writeHead(200,{"Content-Type":v.contentType.json}),i=s;!e.headersSent&&!n&&r&&e.setHeader("Content-Type",v.contentType.octet),n?i instanceof Uint8Array?e.end(i):e.end(JSON.stringify(i)):((typeof i=="number"||typeof i=="boolean"||i==null||i instanceof Object)&&(i=JSON.stringify(i)),i&&o&&(i=Buffer.from(i,"base64")),e.end(i))},Ke=t=>({filter:/^\/@url\//,callback:async(e,n)=>{let{url:r,method:s,headers:i}=e;if(ke(n,s))return;let o=new URL(r,v.dummyHost),a=j(n),l=k.parseNameFromUrl(o.pathname),c=t.handlers.find(h=>h.name==l);if(!c?.url)return n.statusCode=404,n.end("Not Found");let d=v.getIsBase64Encoded(i),m=await N(e,d),f=oe.createApgV2Event({req:e,mockEvent:c.url,parsedURL:o,requestId:a,body:m,isBase64Encoded:d}),p=`/@url/${c.name}`,y=o.pathname.slice(p.length);y||(y="/"),f.requestContext.accountId="anonymous",f.rawPath=y,f.requestContext.http.path=y;try{let h=dn(n,c),g=await c.invoke(f,c.url,void 0,h);if(!g)return n.end();pn(g,n,h)}catch(h){console.error(h),G(n)}}});var Ge=t=>({filter:/(^\/2015-03-31\/functions\/.*\/invocations)|(^\/@invoke\/)/,callback:async(e,n)=>{let{url:r,headers:s}=e,i=new URL(r,"http://localhost:3003"),o=k.parseNameFromUrl(i.pathname),a=t.handlers.find(g=>g.name==o),l=j(n);if(n.setHeader("Content-Type","application/json"),e.on("error",g=>{n.statusCode=502,n.end(JSON.stringify(g))}),!a){let{region:g,accountId:x}=t.aws;return n.statusCode=404,n.setHeader("x-amzn-errortype","ResourceNotFoundException"),n.end(K(o,g,x))}let c=s["x-amz-invocation-type"],d=C(s["x-amz-client-context"]);if(d instanceof Error)return n.setHeader("x-amzn-errortype","InvalidRequestContentException"),n.statusCode=400,n.end(Q);let m=c=="DryRun"?204:c=="Event"?202:200,f=await N(e),p=V(f);if(n.setHeader("X-Amzn-Trace-Id","root=1-xxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxx;sampled=0"),p instanceof Error)return n.statusCode=400,n.setHeader("x-amzn-errortype","InvalidRequestContentException"),n.end(J(p.message));n.setHeader("X-Amz-Executed-Version","$LATEST");let y=new Date,h={};n.statusCode=m,m!==200&&n.end(),m==202&&(h.kind="async");try{let g=await a.invoke(p,h,d);if(m==200){if(typeof g>"u"){n.end();return}let x=B(g),u=x?g.buffer:g;x?u=E.codec.decode(u):typeof u!="string"&&(u=JSON.stringify(u)),n.end(u)}}catch(g){n.writableFinished||(n.setHeader("X-Amz-Function-Error",g.errorType??g.message??""),n.statusCode=200,n.end(JSON.stringify(g)))}}});import{randomUUID as Ye}from"node:crypto";import{setTimeout as un}from"node:timers/promises";var Xe=t=>({filter:"/2015-03-31/functions",method:"POST",async callback(e,n){let r=await N(e),s=JSON.parse(r),{FunctionName:i,Handler:o,Environment:a,Runtime:l,Timeout:c,MemorySize:d}=s;t.addLambda(i,{handler:o,environment:a?.Variables,runtime:l,timeout:c,memorySize:d}),t.isDynamicBuild=!0,t.setEsBuildConfig(),await t.buildContext.dispose(),await t.buildAndWatch(),await un(100),n.statusCode=201,n.end(r)}}),Ze=t=>({filter:/\/2015-03-31\/functions\/*/,method:"GET",async callback(e,n){let{url:r}=e,i=new URL(r,"http://localhost:3003").pathname.slice(22),o=t.getLambdaByName(i);if(!o){n.statusCode=404,n.end();return}let a={Code:{RepositoryType:"S3",Location:"https://s3.com/snapshots/1234543"},Tags:{},Configuration:{Architectures:["arm64"],CodeSha256:"WrLckXVmmfsSPvP/15FqPi9Nt9qQBaspP6RV3T137K4=",SigningJobArn:"",FunctionArn:`arn:aws:lambda:${t.aws.region}:${t.aws.accountId}:function:${i}`,FunctionName:i,Handler:o.handlerPath,Timeout:o.timeout,Runtime:o.runtime,MemorySize:o.memorySize,Environment:{Variables:et(o.environment)},State:"Active",LastUpdateStatus:"Successful",LastModified:new Date().toISOString(),Version:"$LATEST",Role:`arn:aws:iam::${t.aws.accountId}:role/fake-role-name`,RevisionId:Ye(),PackageType:"Zip",Description:"",EphemeralStorage:{Size:512},TracingConfig:{Mode:"PassThrough"},VpcConfig:{Ipv6AllowedForDualStack:!1,VpcId:"",SecurityGroupIds:[],SubnetIds:[]},CodeSize:5867,SnapStart:{OptimizationStatus:"Off",ApplyOn:"None"},LoggingConfig:{LogFormat:"Text",LogGroup:`/aws/lambda/${i}`}}};n.end(JSON.stringify(a))}}),fn=["AWS_EXECUTION_ENV","AWS_LAMBDA_FUNCTION_VERSION","AWS_LAMBDA_FUNCTION_NAME","_HANDLER","IS_OFFLINE","IS_LOCAL","AWS_SAM_LOCAL","AWS_LAMBDA_FUNCTION_MEMORY_SIZE"];function et(t){let e={};for(let[n,r]of Object.entries(t))fn.includes(n)||(e[n]=String(r));return e}var tt=t=>({method:"GET",filter:/\/2015-03-31\/functions\/.*\/versions/,async callback(e,n){let{url:r}=e,i=new URL(r,"http://localhost:3003").pathname.slice(22);i=i.slice(0,i.indexOf("/"));let o=t.getLambdaByName(i);if(!o){n.statusCode=404,n.end();return}let a={Versions:[{Architectures:["arm64"],CodeSha256:"WrLckXVmmfsSPvP/15FqPi9Nt9qQBaspP6RV3T137K4=",SigningJobArn:"",FunctionArn:`arn:aws:lambda:${t.aws.region}:${t.aws.accountId}:function:${i}`,FunctionName:i,Handler:o.handlerPath,Timeout:o.timeout,Runtime:o.runtime,MemorySize:o.memorySize,Environment:{Variables:et(o.environment)},State:"Active",LastUpdateStatus:"Successful",LastModified:new Date().toISOString(),Version:"$LATEST",Role:`arn:aws:iam::${t.aws.accountId}:role/fake-role-name`,RevisionId:Ye(),PackageType:"Zip",Description:"",EphemeralStorage:{Size:512},TracingConfig:{Mode:"PassThrough"},VpcConfig:{Ipv6AllowedForDualStack:!1,VpcId:"",SecurityGroupIds:[],SubnetIds:[]},CodeSize:5867,SnapStart:{OptimizationStatus:"Off",ApplyOn:"None"},LoggingConfig:{LogFormat:"Text",LogGroup:`/aws/lambda/${i}`}}]};n.end(JSON.stringify(a))}}),nt=t=>({method:"GET",filter:/\/2020-06-30\/functions\/.*\/code-signing-config/,async callback(e,n){let{url:r}=e,i=new URL(r,"http://localhost:3003").pathname.slice(22);if(i=i.slice(0,i.indexOf("/")),!t.getLambdaByName(i)){n.statusCode=404,n.end();return}let a={CodeSigningConfigArn:"",FunctionName:i};n.end(JSON.stringify(a))}});import{EventStreamCodec as hn}from"@smithy/eventstream-codec";var yn=(t,e)=>{let n=Buffer.from(t,e);return new Uint8Array(n.buffer,n.byteOffset,n.byteLength/Uint8Array.BYTES_PER_ELEMENT)},gn=t=>Buffer.from(t,t.byteOffset,t.byteLength).toString("utf8"),pe=new hn(gn,yn),ae=class t{res;static complete=Buffer.from([0,0,0,102,0,0,0,84,31,86,200,105,11,58,101,118,101,110,116,45,116,121,112,101,7,0,14,73,110,118,111,107,101,67,111,109,112,108,101,116,101,13,58,99,111,110,116,101,110,116,45,116,121,112,101,7,0,16,97,112,112,108,105,99,97,116,105,111,110,47,106,115,111,110,13,58,109,101,115,115,97,103,101,45,116,121,112,101,7,0,5,101,118,101,110,116,123,125,112,6,212,103]);constructor(e){this.res=e}write(e,n,r){this.res.write(pe.encode({headers:this.#e("PayloadChunk",v.contentType.octet),body:e}),n,r)}end(e){e?this.write(e,"utf8",()=>{this.res.end(t.complete)}):this.res.end(t.complete)}setHeader(e,n){e=="Content-Type"&&this.res.setHeader("Content-Type",n)}destroy(){this.res.destroy()}endWithError(e){let n={ErrorCode:e.errorType,ErrorDetails:JSON.stringify(e)},r=Array.from(Buffer.from(JSON.stringify(n)).values());this.res.end(pe.encode({headers:this.#e("InvokeComplete",v.contentType.json),body:new Uint8Array(r)}))}endWithJson(e){let n=Array.from(Buffer.from(JSON.stringify(e)).values());this.res.write(pe.encode({headers:this.#e("PayloadChunk",v.contentType.octet),body:new Uint8Array(n)}),()=>{this.res.end(t.complete)})}#e(e,n,r="event"){return{":event-type":{type:"string",value:e},":content-type":{type:"string",value:n},":message-type":{type:"string",value:r}}}};var rt=t=>({filter:/^\/2021-11-15\/functions\//,callback:async(e,n)=>{let{url:r,headers:s}=e,i=new URL(r,"http://localhost:3003"),o=j(n),a=k.parseNameFromUrl(i.pathname),l=t.handlers.find(p=>p.name==a),c=await N(e),d=V(c);if(n.setHeader("X-Amzn-Trace-Id","root=1-xxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxx;sampled=0"),d instanceof Error)return n.statusCode=400,n.setHeader("x-amzn-errortype","InvalidRequestContentException"),n.end(J(d.message));let m=C(s["x-amz-client-context"]);if(m instanceof Error)return n.setHeader("x-amzn-errortype","InvalidRequestContentException"),n.statusCode=400,n.end(Q);let f=new ae(n);if(l){let p=l.url?.stream??{};try{let y=await l.invoke(d,p,m,f);y&&f.endWithJson(y)}catch(y){n.writableFinished||f.endWithError(y)}}else{let{region:p,accountId:y}=t.aws;n.statusCode=404,n.end(K(a,p,y))}}});var st=t=>[Xe(t),tt(t),nt(t),Ge(t),rt(t),Ke(t),Ze(t)];var me=process.cwd(),Sn=3,vn=1024,xn={IS_OFFLINE:!0,IS_LOCAL:!0,AWS_SAM_LOCAL:!0},wn=me.split(O.sep)[0],Rn=new RegExp(`^.*:${wn}`),In=t=>Rn.test(t);process.title="node (exlo)";var ce=class extends ie{#e;options;config;esBuildConfig;buildContext={};customEsBuildConfig;optimizeBuild=!1;nodeVersion=!1;onKill=[];shimRequire=!1;port=0;onceServerReady=[];isDynamicBuild=!1;endpoints={};constructor(e,n){super(e,{debug:typeof n.debug=="boolean"?n.debug:!1}),this.#e=[],this.options=n,this.options.customEsBuildConfig&&(this.customEsBuildConfig=this.options.customEsBuildConfig),this.options.config&&(typeof this.options.config=="string"||typeof this.options.config=="object"&&!Array.isArray(this.options.config))&&(this.config=this.options.config),typeof this.options.optimizeBuild=="boolean"&&(this.optimizeBuild=this.options.optimizeBuild),typeof this.options.shimRequire=="boolean"&&(this.shimRequire=this.options.shimRequire),this.aws.runtime?.startsWith("node")?this.nodeVersion=this.aws.runtime?.replace(/[^0-9]/g,""):this.nodeVersion="20",b.BR_BLUE("Starting exlo...")}async start(){this.#s(),this.#e=this.#r(),await this.#o(),this.setEsBuildConfig(),await this.buildAndWatch()}setEsBuildConfig(){let n={sourcemap:!0,minify:!1,entryPoints:this.#e.filter(r=>r.runtime.startsWith("n")).map(r=>r.esEntryPoint),outdir:O.join(me,".exlo","build"),metafile:!0,bundle:!0,platform:"node",target:"node20",format:"cjs",outbase:"src",plugins:[],external:["esbuild"],dropLabels:[]};if(typeof process.env.NODE_ENV=="string"&&(n.define={"process.env.NODE_ENV":`"${process.env.NODE_ENV}"`}),typeof this.nodeVersion=="string"&&!isNaN(Number(this.nodeVersion))){Number(process.versions.node.slice(0,2))<Number(this.nodeVersion)&&b.RED(`You are running on NodeJS ${process.version} which is lower than defined '${this.nodeVersion}'.`),n.target=`node${this.nodeVersion}`;let r=()=>this.sco;n.plugins?.push(ge({nodeVersion:Number(this.nodeVersion),shimRequire:this.shimRequire,optimizeBuild:this.optimizeBuild,buildCallback:this.buildCallback,getSockets:r}))}this.customEsBuildConfig&&(n=be(n,this.customEsBuildConfig)),this.esBuildConfig=n}async buildAndWatch(){this.buildContext=await it.context(this.esBuildConfig),await this.buildContext.watch()}buildCallback=async(e,n)=>{if(n||this.isDynamicBuild)await this.#t(e);else{let{outputs:r}=e.metafile;if(this.#i(r),this.customBuildCallback)try{await this.customBuildCallback(e,!1)}catch(o){console.log(o)}this.#a();let s=this,i=await new Promise(o=>{this.listen(this.port,async(a,l)=>{let c=`http://localhost:${a}`;b.PINK(`Lambda endpoint: ${c}`),this.endpoints.lambda=c,await s.load(s.#e);for(let d of s.#e)d.setEnv("LOCAL_PORT",a),d.setEnv("AWS_LAMBDA_RUNTIME_API",`127.0.0.1:${a}`);o({url:c,port:a})})});this.onceServerReady.forEach(o=>{o(i)})}};async#t(e){if(e?.errors?.length)b.RED("Build failed:"),console.error(e.errors);else{this.#i(e.metafile.outputs);try{await this.load(this.#e),this.customBuildCallback&&await this.customBuildCallback(e,!0)}catch(n){console.error(n)}console.log(`\x1B[32m${new Date().toLocaleString()} \u{1F504}\u2705 Rebuild\x1B[0m`)}}#n(e){let n=this.aws,r=n.runtime,s=this.runtimeConfig.environment.AWS_REGION??this.runtimeConfig.environment.REGION,o=n.functions[e],a=o.handler,l=O.extname(a),c=l.slice(1),d=O.resolve(a.replace(l,"")),m=n.getFunction(e),f=m.runtime??r,p={name:e,runtime:m.runtime??r,handlerPath:a,handlerName:c,esEntryPoint:d,memorySize:o.memorySize??this.runtimeConfig.memorySize??vn,timeout:o.timeout??this.runtimeConfig.timeout??Sn,sqs:[],ddb:[],environment:{AWS_EXECUTION_ENV:`AWS_Lambda_${f}`,AWS_LAMBDA_FUNCTION_VERSION:"$LATEST",AWS_LAMBDA_FUNCTION_NAME:e,_HANDLER:O.basename(a),...this.runtimeConfig.environment,...o.environment,...xn},invoke:async(y,h)=>{let g=this.getHandlerByName(`/@invoke/${e}`);if(g)return await g.invoke(y,h);b.RED(`'${e}' is not mounted yet.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "exlo",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "A modular toolkit to emulate cloud services locally using high-quality built-in plugins and custom extensions. Includes support for Lambda, S3, SNS, SQS, Secrets Manager, REST API Gateway and more.",
|
|
3
|
+
"version": "0.0.4",
|
|
4
|
+
"description": "A modular toolkit to emulate cloud services locally using high-quality built-in plugins and custom extensions. Includes support for Lambda, S3, SNS, SQS, Secrets Manager, DynamoDB, REST API Gateway and more.",
|
|
5
5
|
"author": "Inqnuam",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://github.com/inqnuam/exlo",
|