@awsless/cli 0.0.46-next.1 → 0.0.46-next.2

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/bin.js CHANGED
@@ -528,6 +528,8 @@ import {
528
528
  CreateAliasCommand as CreateAliasCommand2,
529
529
  CreateFunctionUrlConfigCommand,
530
530
  GetFunctionUrlConfigCommand,
531
+ RemovePermissionCommand,
532
+ UpdateFunctionUrlConfigCommand,
531
533
  LambdaClient as LambdaClient2,
532
534
  PutFunctionEventInvokeConfigCommand
533
535
  } from "@aws-sdk/client-lambda";
@@ -559,7 +561,8 @@ var createLambdaProvider = ({ credentials, region }) => {
559
561
  deploymentId: z2.string(),
560
562
  functionName: z2.string(),
561
563
  functionVersion: z2.string(),
562
- onFailureArn: z2.string()
564
+ onFailureArn: z2.string(),
565
+ sourceAccount: z2.string().optional()
563
566
  });
564
567
  const bundleDeploymentStateSchema = bundleDeploymentInputSchema.extend({
565
568
  deploymentAlias: z2.string(),
@@ -596,14 +599,15 @@ var createLambdaProvider = ({ credentials, region }) => {
596
599
  })
597
600
  );
598
601
  };
599
- const createPublicUrl = async (functionName, alias) => {
602
+ const createDeploymentUrl = async (functionName, alias, sourceAccount) => {
603
+ const authType = sourceAccount ? "AWS_IAM" : "NONE";
600
604
  let url;
601
605
  try {
602
606
  const result = await lambda.send(
603
607
  new CreateFunctionUrlConfigCommand({
604
608
  FunctionName: functionName,
605
609
  Qualifier: alias,
606
- AuthType: "NONE"
610
+ AuthType: authType
607
611
  })
608
612
  );
609
613
  url = result.FunctionUrl;
@@ -612,21 +616,39 @@ var createLambdaProvider = ({ credentials, region }) => {
612
616
  throw error;
613
617
  }
614
618
  const result = await lambda.send(
615
- new GetFunctionUrlConfigCommand({
619
+ new UpdateFunctionUrlConfigCommand({
616
620
  FunctionName: functionName,
617
- Qualifier: alias
621
+ Qualifier: alias,
622
+ AuthType: authType
618
623
  })
619
624
  );
620
625
  url = result.FunctionUrl;
621
626
  }
622
- const permissions = [
627
+ const permissions = sourceAccount ? [
628
+ {
629
+ StatementId: "cloudfront-url",
630
+ Principal: "cloudfront.amazonaws.com",
631
+ SourceAccount: sourceAccount,
632
+ Action: "lambda:InvokeFunctionUrl",
633
+ FunctionUrlAuthType: "AWS_IAM"
634
+ },
635
+ {
636
+ StatementId: "cloudfront-invoke",
637
+ Principal: "cloudfront.amazonaws.com",
638
+ SourceAccount: sourceAccount,
639
+ Action: "lambda:InvokeFunction",
640
+ InvokedViaFunctionUrl: true
641
+ }
642
+ ] : [
623
643
  {
624
644
  StatementId: "public-url",
645
+ Principal: "*",
625
646
  Action: "lambda:InvokeFunctionUrl",
626
647
  FunctionUrlAuthType: "NONE"
627
648
  },
628
649
  {
629
650
  StatementId: "public-invoke",
651
+ Principal: "*",
630
652
  Action: "lambda:InvokeFunction",
631
653
  InvokedViaFunctionUrl: true
632
654
  }
@@ -637,7 +659,6 @@ var createLambdaProvider = ({ credentials, region }) => {
637
659
  new AddPermissionCommand({
638
660
  FunctionName: functionName,
639
661
  Qualifier: alias,
640
- Principal: "*",
641
662
  ...permission
642
663
  })
643
664
  );
@@ -647,6 +668,23 @@ var createLambdaProvider = ({ credentials, region }) => {
647
668
  }
648
669
  }
649
670
  }
671
+ if (sourceAccount) {
672
+ for (const statementId of ["public-url", "public-invoke"]) {
673
+ try {
674
+ await lambda.send(
675
+ new RemovePermissionCommand({
676
+ FunctionName: functionName,
677
+ Qualifier: alias,
678
+ StatementId: statementId
679
+ })
680
+ );
681
+ } catch (error) {
682
+ if (!isError(error, "ResourceNotFoundException")) {
683
+ throw error;
684
+ }
685
+ }
686
+ }
687
+ }
650
688
  return url;
651
689
  };
652
690
  const createBundleDeployment = async (state2) => {
@@ -658,7 +696,7 @@ var createLambdaProvider = ({ credentials, region }) => {
658
696
  name: deploymentAlias
659
697
  });
660
698
  await configureVersion(state2);
661
- const url = await createPublicUrl(state2.functionName, deploymentAlias);
699
+ const url = await createDeploymentUrl(state2.functionName, deploymentAlias, state2.sourceAccount);
662
700
  return {
663
701
  ...state2,
664
702
  deploymentAlias,
@@ -769,7 +807,20 @@ var createLambdaProvider = ({ credentials, region }) => {
769
807
  deploymentAliases.push(deploymentAlias);
770
808
  }
771
809
  await configureVersion(proposed);
772
- const url = await createPublicUrl(proposed.functionName, deploymentAlias);
810
+ const url = await createDeploymentUrl(proposed.functionName, deploymentAlias, proposed.sourceAccount);
811
+ if (proposed.sourceAccount && prior.sourceAccount !== proposed.sourceAccount) {
812
+ await Promise.all(
813
+ deploymentAliases.filter((name) => name !== deploymentAlias).map(
814
+ (name) => createDeploymentUrl(proposed.functionName, name, proposed.sourceAccount).catch(
815
+ (error) => {
816
+ if (!isError(error, "ResourceNotFoundException")) {
817
+ throw error;
818
+ }
819
+ }
820
+ )
821
+ )
822
+ );
823
+ }
773
824
  return {
774
825
  ...proposed,
775
826
  deploymentAlias,
@@ -1276,20 +1327,16 @@ var readDeployedFunctionVersion = (state2) => {
1276
1327
  };
1277
1328
  var formatDeploymentSummary = (props) => {
1278
1329
  let previewUrl;
1279
- let lambdaUrl;
1280
1330
  for (const [urn, node] of readStateNodes(props.state)) {
1281
1331
  if (node.type === "aws_cloudfront_distribution" && urn.endsWith(":{preview}")) {
1282
1332
  previewUrl = `https://${node.output.domainName}`;
1283
1333
  }
1284
- if (node.type === "bundle-deployment") {
1285
- lambdaUrl = node.output.url;
1286
- }
1287
1334
  }
1288
1335
  return Object.keys(props.appConfig.defaults.router ?? {}).map((routerId, index) => {
1289
1336
  return [
1290
1337
  `${routerId}: deployment #${props.id}`,
1291
1338
  index === 0 ? previewUrl : void 0,
1292
- index === 0 ? lambdaUrl : void 0
1339
+ index === 0 && previewUrl ? `${previewUrl}/?awsless-deployment=${props.id}` : void 0
1293
1340
  ].filter(Boolean).join("\n");
1294
1341
  });
1295
1342
  };
@@ -3843,7 +3890,6 @@ var bundleTypeScriptWithRolldown = async ({
3843
3890
  format: format3 = "esm",
3844
3891
  minify = true,
3845
3892
  file,
3846
- nativeDir,
3847
3893
  external,
3848
3894
  importAsString: importAsStringList
3849
3895
  }) => {
@@ -3854,7 +3900,25 @@ var bundleTypeScriptWithRolldown = async ({
3854
3900
  return importee.startsWith("@aws-sdk") || importee.startsWith("aws-sdk") || external?.includes(importee);
3855
3901
  },
3856
3902
  treeshake: {
3857
- moduleSideEffects: (id, isExternal) => isExternal ? external?.includes(id) === true : id.startsWith(`${directories.root}/`)
3903
+ // The @awsless packages are pure clients, but their entry points
3904
+ // also export test helpers that pull in local server
3905
+ // implementations like dynamo-db-local, which crash the ESM
3906
+ // runtime with CJS globals like __dirname. Treating the scope as
3907
+ // side-effect free prunes those unused chains from production
3908
+ // bundles, while every other dependency keeps its import side
3909
+ // effects, like the fs patching of graceful-fs.
3910
+ moduleSideEffects: (id, isExternal) => {
3911
+ if (isExternal) {
3912
+ return external?.includes(id) === true;
3913
+ }
3914
+ if (id.includes("/node_modules/@awsless/")) {
3915
+ return false;
3916
+ }
3917
+ if (id.includes("/node_modules/")) {
3918
+ return true;
3919
+ }
3920
+ return id.startsWith(`${directories.root}/`);
3921
+ }
3858
3922
  },
3859
3923
  onwarn: (error) => {
3860
3924
  debugError(error.message);
@@ -3901,6 +3965,7 @@ var bundleTypeScriptWithRolldown = async ({
3901
3965
  chunkFileNames: `[name].${ext}`,
3902
3966
  minify
3903
3967
  });
3968
+ assertNoTestOnlyModules(result.output);
3904
3969
  const hash = createHash4("sha1");
3905
3970
  const files = [];
3906
3971
  for (const item of result.output) {
@@ -3922,6 +3987,22 @@ var bundleTypeScriptWithRolldown = async ({
3922
3987
  files
3923
3988
  };
3924
3989
  };
3990
+ var TEST_ONLY_MODULES = ["dynamo-db-local", "@awsless/dynamodb-server", "redis-memory-server"];
3991
+ var assertNoTestOnlyModules = (output) => {
3992
+ for (const item of output) {
3993
+ if (item.type !== "chunk") {
3994
+ continue;
3995
+ }
3996
+ for (const id of item.moduleIds ?? []) {
3997
+ const found = TEST_ONLY_MODULES.find((name) => id.includes(`/node_modules/${name}/`));
3998
+ if (found) {
3999
+ throw new Error(
4000
+ `The test-only package "${found}" was bundled into a production build through "${id}". Remove the import from the handler, or keep the package tree-shakeable.`
4001
+ );
4002
+ }
4003
+ }
4004
+ }
4005
+ };
3925
4006
 
3926
4007
  // src/feature/bundle/util.ts
3927
4008
  var ROUTE_HEADER = "x-awsless-route";
@@ -4207,7 +4288,8 @@ var bundleFeature = defineFeature({
4207
4288
  deploymentId: ctx.deploymentId ?? "local-0",
4208
4289
  functionName: lambda.functionName,
4209
4290
  functionVersion: lambda.version,
4210
- onFailureArn: onFailure
4291
+ onFailureArn: onFailure,
4292
+ sourceAccount: ctx.accountId
4211
4293
  },
4212
4294
  {
4213
4295
  // Make sure the permissions are in place before any event source is wired up.
@@ -9117,7 +9199,7 @@ var getViewerRequestFunctionCode = (props) => {
9117
9199
  ].join("\n")
9118
9200
  ) : ""
9119
9201
  ],
9120
- ACTIVE_PREFIX(props.router)
9202
+ props.preview ? PREVIEW_PREFIX(props.router) : ACTIVE_PREFIX(props.router)
9121
9203
  );
9122
9204
  };
9123
9205
  var BLOCK_DIRECT_ACCESS_TO_CLOUDFRONT = `
@@ -9177,6 +9259,58 @@ if(!isAuthorized) {
9177
9259
  }
9178
9260
  }
9179
9261
  `;
9262
+ var PREVIEW_PREFIX = (router) => `
9263
+ const router = ${JSON.stringify(router)};
9264
+ let deployment;
9265
+
9266
+ if (request.querystring['awsless-deployment'] && request.querystring['awsless-deployment'].value) {
9267
+ deployment = request.querystring['awsless-deployment'].value;
9268
+ } else if (request.cookies && request.cookies['awsless-deployment'] && request.cookies['awsless-deployment'].value) {
9269
+ deployment = request.cookies['awsless-deployment'].value;
9270
+ }
9271
+
9272
+ let prefix;
9273
+
9274
+ try {
9275
+ const pointer = deployment ? '$deploy:' + deployment : '$active';
9276
+ prefix = (await cf.kvs().get(pointer)).split(':')[0] + ':' + router + ':';
9277
+ } catch (e) {
9278
+ return deployment
9279
+ ? { statusCode: 404, statusDescription: 'Unknown Deployment' }
9280
+ : { statusCode: 503, statusDescription: 'Service Unavailable' };
9281
+ }
9282
+
9283
+ if (request.querystring['awsless-deployment']) {
9284
+ delete request.querystring['awsless-deployment'];
9285
+
9286
+ const query = [];
9287
+
9288
+ for (const key in request.querystring) {
9289
+ const entry = request.querystring[key];
9290
+
9291
+ if (entry.multiValue) {
9292
+ for (const item of entry.multiValue) {
9293
+ query.push(key + '=' + item.value);
9294
+ }
9295
+ } else {
9296
+ query.push(key + '=' + entry.value);
9297
+ }
9298
+ }
9299
+
9300
+ return {
9301
+ statusCode: 302,
9302
+ statusDescription: 'Found',
9303
+ headers: {
9304
+ location: { value: request.uri + (query.length ? '?' + query.join('&') : '') }
9305
+ },
9306
+ cookies: {
9307
+ 'awsless-deployment': {
9308
+ value: deployment,
9309
+ attributes: 'Path=/; Secure; SameSite=Lax'
9310
+ }
9311
+ }
9312
+ };
9313
+ }`;
9180
9314
  var ACTIVE_PREFIX = (router) => `
9181
9315
  const router = ${JSON.stringify(router)};
9182
9316
  let prefix;
@@ -9793,6 +9927,7 @@ var routerFeature = defineFeature({
9793
9927
  runtime: "cloudfront-js-2.0",
9794
9928
  code: getViewerRequestFunctionCode({
9795
9929
  router: id,
9930
+ preview: true,
9796
9931
  basicAuth: props.basicAuth,
9797
9932
  passwordAuth: props.passwordAuth
9798
9933
  }),
@@ -9901,22 +10036,6 @@ var routerFeature = defineFeature({
9901
10036
  dependsOn: Array.from(routeDependencies)
9902
10037
  }
9903
10038
  );
9904
- if (!(props.basicAuth ?? props.passwordAuth)) {
9905
- bundle.addEnv(
9906
- "AWSLESS_PREVIEW",
9907
- $resolve(
9908
- [routes],
9909
- (routes2) => JSON.stringify({
9910
- router: id,
9911
- routes: Object.fromEntries(
9912
- Object.entries(routes2).filter(
9913
- ([key, route]) => key.startsWith(`${id}:`) && route.type !== "url"
9914
- )
9915
- )
9916
- })
9917
- )
9918
- );
9919
- }
9920
10039
  });
9921
10040
  }
9922
10041
  ctx.shared.add("router", "id", id, distribution.id);
@@ -3,128 +3,6 @@ import { patch, unpatch } from "@awsless/json";
3
3
  import { ExpectedError, invoke, isErrorResponse } from "@awsless/lambda";
4
4
  import { formatRoutePayload, getCurrentRoute, withRoute } from "awsless";
5
5
 
6
- // src/feature/bundle/server/preview.ts
7
- import { GetObjectCommand, NoSuchKey } from "@aws-sdk/client-s3";
8
- import { s3Client } from "@awsless/s3";
9
- var getPossibleRouteKeys = (path) => {
10
- if (path === "" || path === "/") {
11
- return ["/", "/*"];
12
- }
13
- const parts = path.split("/");
14
- const root = path.startsWith("/") ? parts[1] : parts[0];
15
- const file = parts[parts.length - 1].includes(".");
16
- if (root.includes(".")) {
17
- return [path, "/*.", "/*"];
18
- }
19
- if (file) {
20
- return [path, "/" + root + "/*.", "/" + root + "/*", "/*.", "/*"];
21
- }
22
- return [path, "/" + root + "/*", "/*"];
23
- };
24
- var findRoute = (props, path, method) => {
25
- for (const key of getPossibleRouteKeys(path)) {
26
- const route = props.routes[`${props.router}:${key}`];
27
- if (!route) {
28
- continue;
29
- }
30
- if (route.type === "s3" && method !== "GET" && method !== "HEAD") {
31
- continue;
32
- }
33
- return route;
34
- }
35
- return;
36
- };
37
- var rewritePath = (route, path) => {
38
- if (!route.rewrite) {
39
- return path;
40
- }
41
- if (route.rewrite.regex) {
42
- return path.replace(new RegExp(route.rewrite.regex), route.rewrite.to);
43
- }
44
- return route.rewrite.to;
45
- };
46
- var serveObject = async (route, path, method) => {
47
- const bucket = route.domainName.split(".s3")[0];
48
- const key = rewritePath(route, path).replace(/^\//, "");
49
- let result;
50
- try {
51
- result = await s3Client().send(new GetObjectCommand({
52
- Bucket: bucket,
53
- Key: key
54
- }));
55
- } catch (error) {
56
- if (error instanceof NoSuchKey) {
57
- return {
58
- statusCode: 404
59
- };
60
- }
61
- throw error;
62
- }
63
- const headers = {};
64
- if (result.ContentType) {
65
- headers["content-type"] = result.ContentType;
66
- }
67
- if (result.CacheControl) {
68
- headers["cache-control"] = result.CacheControl;
69
- }
70
- if (result.ETag) {
71
- headers["etag"] = result.ETag;
72
- }
73
- if (method === "HEAD") {
74
- return { statusCode: 200, headers };
75
- }
76
- return {
77
- statusCode: 200,
78
- headers,
79
- body: await result.Body.transformToString("base64"),
80
- isBase64Encoded: true
81
- };
82
- };
83
- var createPreviewHandler = (props) => {
84
- return async (event) => {
85
- const method = event.requestContext.http.method;
86
- const headers = event.headers ?? {};
87
- let path = event.rawPath;
88
- try {
89
- path = decodeURIComponent(path);
90
- } catch {}
91
- if (method === "OPTIONS") {
92
- return {
93
- statusCode: 204,
94
- headers: {
95
- "access-control-allow-origin": "*",
96
- "access-control-allow-methods": "GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS",
97
- "access-control-allow-headers": "*",
98
- "access-control-max-age": "86400"
99
- }
100
- };
101
- }
102
- const route = findRoute(props, path, method);
103
- if (!route) {
104
- return {
105
- statusCode: 404
106
- };
107
- }
108
- if (route.type === "s3") {
109
- return serveObject(route, path, method);
110
- }
111
- for (const [name, value] of Object.entries(route.requestHeaders ?? {})) {
112
- headers[name] = value;
113
- }
114
- if (headers.authorization) {
115
- headers["x-awsless-authorization"] = headers.authorization;
116
- } else {
117
- delete headers["x-awsless-authorization"];
118
- }
119
- if (route.forwardHost && headers.host) {
120
- headers["x-forwarded-host"] = headers.host;
121
- }
122
- event.headers = headers;
123
- event.rawPath = rewritePath(route, path);
124
- return props.dispatch(event);
125
- };
126
- };
127
-
128
6
  // src/feature/bundle/server/resource/util.ts
129
7
  var asyncRoute = (key, payload) => {
130
8
  process.env.THROW_EXPECTED_ERRORS = "1";
@@ -434,7 +312,6 @@ var topicHandler = (event, routes) => {
434
312
  // src/feature/bundle/server/handle.ts
435
313
  var createBundle = (handlers) => {
436
314
  const routes = Object.keys(handlers);
437
- let previewConfig;
438
315
  const matchers = [
439
316
  functionHandler,
440
317
  cronHandler,
@@ -473,7 +350,8 @@ var createBundle = (handlers) => {
473
350
  process.env.AWSLESS_ROUTE = match2.key;
474
351
  return withRoute(match2.key, invokeRoute, async () => {
475
352
  const handle = await load();
476
- return handle(match2.payload ?? {}, context);
353
+ const routedContext = { ...context, route: match2.key };
354
+ return handle(match2.payload ?? {}, routedContext);
477
355
  });
478
356
  };
479
357
  const invokeRoute = async (key, payload) => {
@@ -502,20 +380,6 @@ var createBundle = (handlers) => {
502
380
  }
503
381
  return response;
504
382
  };
505
- const raw = event;
506
- if (process.env.AWSLESS_PREVIEW && raw?.requestContext?.http && !event?.headers?.["x-awsless-route"]) {
507
- previewConfig ??= JSON.parse(process.env.AWSLESS_PREVIEW);
508
- return createPreviewHandler({
509
- ...previewConfig,
510
- dispatch: async (event2) => {
511
- const match2 = matchRoute(event2);
512
- if (Array.isArray(match2)) {
513
- throw new Error("Unknown bundle route");
514
- }
515
- return handleRoute(match2);
516
- }
517
- })(event);
518
- }
519
383
  const match = matchRoute(event);
520
384
  if (Array.isArray(match)) {
521
385
  const name = `${process.env.AWS_LAMBDA_FUNCTION_NAME}:${process.env.AWS_LAMBDA_FUNCTION_VERSION}`;
@@ -1,8 +1,81 @@
1
1
  // src/feature/on-failure/server/handle.ts
2
- import { parse, patch } from "@awsless/json";
2
+ import { parse as parse2, patch } from "@awsless/json";
3
3
  import { invoke } from "@awsless/lambda";
4
4
  import { deleteObject, getObject } from "@awsless/s3";
5
5
  import { formatRoutePayload, getRouteEnv } from "awsless";
6
+
7
+ // src/feature/on-failure/server/util.ts
8
+ import { parse } from "@awsless/json";
9
+ var isDynamoDBFailureEvent = (event) => {
10
+ return "DDBStreamBatchInfo" in event;
11
+ };
12
+ var logicalResourceName = (physical) => {
13
+ const segments = physical.replace(/\.fifo$/, "").split("--");
14
+ if (segments.length === 4) {
15
+ return `${segments[1]}:${segments[2]}:${segments[3]}`;
16
+ }
17
+ if (segments.length === 3) {
18
+ return `${segments[1]}:${segments[2]}`;
19
+ }
20
+ return physical;
21
+ };
22
+ var getFailureSource = (payload) => {
23
+ const record = getDeliveryRecord(payload);
24
+ if (!record) {
25
+ return;
26
+ }
27
+ if (isTopicRecord(record)) {
28
+ return {
29
+ resource: record.Sns.TopicArn ? logicalResourceName(lastArnSegment(record.Sns.TopicArn)) : "topic",
30
+ event: parseEvent(record.Sns.Message)
31
+ };
32
+ }
33
+ if (isStreamRecord(record)) {
34
+ const table = record.eventSourceARN.split("/")[1];
35
+ return {
36
+ resource: table ? logicalResourceName(table) : "table-stream"
37
+ };
38
+ }
39
+ if (isQueueRecord(record)) {
40
+ return {
41
+ resource: logicalResourceName(lastArnSegment(record.eventSourceARN)),
42
+ event: parseEvent(record.body)
43
+ };
44
+ }
45
+ return;
46
+ };
47
+ var getDeliveryRecord = (payload) => {
48
+ if (!payload || typeof payload !== "object") {
49
+ return;
50
+ }
51
+ const records = payload.Records;
52
+ const record = Array.isArray(records) ? records[0] : undefined;
53
+ return record && typeof record === "object" ? record : undefined;
54
+ };
55
+ var isTopicRecord = (record) => {
56
+ return "Sns" in record && typeof record.Sns === "object" && record.Sns !== null;
57
+ };
58
+ var isStreamRecord = (record) => {
59
+ return "eventSource" in record && record.eventSource === "aws:dynamodb" && "eventSourceARN" in record;
60
+ };
61
+ var isQueueRecord = (record) => {
62
+ return "eventSource" in record && record.eventSource === "aws:sqs" && "eventSourceARN" in record;
63
+ };
64
+ var lastArnSegment = (arn) => {
65
+ return arn.split(":").at(-1);
66
+ };
67
+ var parseEvent = (value) => {
68
+ if (typeof value !== "string") {
69
+ return value;
70
+ }
71
+ try {
72
+ return parse(value);
73
+ } catch {
74
+ return value;
75
+ }
76
+ };
77
+
78
+ // src/feature/on-failure/server/handle.ts
6
79
  var handle_default = async (event, context) => {
7
80
  if (!Array.isArray(event.Records)) {
8
81
  throw new TypeError(`Unknown Event Type: ${JSON.stringify(event)}`);
@@ -28,13 +101,16 @@ var sqsRecord = async (record, context) => {
28
101
  await Promise.all(s3Records.map((record2) => s3Record(record2, context)));
29
102
  return;
30
103
  }
104
+ const queueName = record.messageAttributes.queueName?.stringValue;
105
+ const body = parsePayload(record.body);
31
106
  const payload = {
32
107
  type: "queue",
33
108
  id: record.messageId,
34
109
  date: new Date(Number(record.attributes.SentTimestamp)),
35
- payload: parsePayload(record.body),
110
+ payload: body,
111
+ source: queueName ? { resource: logicalResourceName(queueName), event: body } : undefined,
36
112
  queue: {
37
- name: record.messageAttributes.queueName?.stringValue,
113
+ name: queueName,
38
114
  url: record.messageAttributes.queueUrl?.stringValue
39
115
  }
40
116
  };
@@ -70,9 +146,6 @@ var s3Record = async (record, context) => {
70
146
  key
71
147
  });
72
148
  };
73
- var isDynamoDBFailureEvent = (event) => {
74
- return "DDBStreamBatchInfo" in event;
75
- };
76
149
  var formatUnknownFailureEvent = (event) => {
77
150
  if (isDynamoDBFailureEvent(event)) {
78
151
  return formatDynamoDBStreamFailureEvent(event);
@@ -90,6 +163,7 @@ var formatAsyncLambdaFailureEvent = (event) => {
90
163
  name: typeof route === "string" ? route : event.requestContext.functionArn.split(":")[6]
91
164
  },
92
165
  payload: typeof route === "string" ? payload.event ?? {} : payload,
166
+ source: typeof route === "string" ? { resource: route, event: payload.event ?? {} } : getFailureSource(payload),
93
167
  error: {
94
168
  type: event.responsePayload.errorType,
95
169
  message: event.responsePayload.errorMessage,
@@ -98,6 +172,9 @@ var formatAsyncLambdaFailureEvent = (event) => {
98
172
  };
99
173
  };
100
174
  var formatDynamoDBStreamFailureEvent = (event) => {
175
+ const payload = parsePayload(event.payload);
176
+ const streamArn = event.DDBStreamBatchInfo?.streamArn;
177
+ const table = streamArn?.split("/")[1];
101
178
  return {
102
179
  type: "dynamodb-stream",
103
180
  date: new Date(event.timestamp),
@@ -105,12 +182,13 @@ var formatDynamoDBStreamFailureEvent = (event) => {
105
182
  function: {
106
183
  name: event.requestContext.functionArn.split(":")[6]
107
184
  },
108
- payload: parsePayload(event.payload)
185
+ payload,
186
+ source: table ? { resource: logicalResourceName(table) } : getFailureSource(payload)
109
187
  };
110
188
  };
111
189
  var parsePayload = (payload) => {
112
190
  try {
113
- return parse(payload);
191
+ return parse2(payload);
114
192
  } catch {
115
193
  return payload;
116
194
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@awsless/cli",
3
- "version": "0.0.46-next.1",
3
+ "version": "0.0.46-next.2",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -83,23 +83,23 @@
83
83
  "zod": "^3.24.2",
84
84
  "zod-to-json-schema": "^3.24.3",
85
85
  "@awsless/big-float": "^0.1.7",
86
- "@awsless/clui": "^0.0.8",
87
86
  "@awsless/cloudwatch": "^0.0.1",
88
87
  "@awsless/duration": "^0.0.4",
88
+ "@awsless/clui": "^0.0.8",
89
89
  "@awsless/dynamodb": "^0.3.21",
90
90
  "@awsless/iot": "^0.0.5",
91
91
  "@awsless/json": "^0.0.11",
92
- "@awsless/lambda": "^0.0.44",
93
92
  "@awsless/s3": "^0.0.21",
93
+ "@awsless/lambda": "^0.0.45",
94
94
  "@awsless/redis": "^0.1.13",
95
- "@awsless/size": "^0.0.2",
95
+ "@awsless/scheduler": "^0.0.4",
96
96
  "@awsless/sns": "^0.0.10",
97
97
  "@awsless/sqs": "^0.0.24",
98
98
  "@awsless/ts-file-cache": "^0.0.16",
99
- "@awsless/weak-cache": "^0.0.1",
100
99
  "@awsless/validate": "^0.1.7",
100
+ "@awsless/weak-cache": "^0.0.1",
101
101
  "awsless": "^0.0.15-next.0",
102
- "@awsless/scheduler": "^0.0.4"
102
+ "@awsless/size": "^0.0.2"
103
103
  },
104
104
  "devDependencies": {
105
105
  "@hono/node-server": "1.19.9",