@awsless/cli 0.0.46-next.0 → 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.
@@ -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.0",
3
+ "version": "0.0.46-next.2",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -82,24 +82,24 @@
82
82
  "zip-a-folder": "^3.1.6",
83
83
  "zod": "^3.24.2",
84
84
  "zod-to-json-schema": "^3.24.3",
85
- "@awsless/cloudwatch": "^0.0.1",
86
85
  "@awsless/big-float": "^0.1.7",
86
+ "@awsless/cloudwatch": "^0.0.1",
87
87
  "@awsless/duration": "^0.0.4",
88
+ "@awsless/clui": "^0.0.8",
88
89
  "@awsless/dynamodb": "^0.3.21",
89
90
  "@awsless/iot": "^0.0.5",
90
91
  "@awsless/json": "^0.0.11",
91
- "@awsless/lambda": "^0.0.44",
92
+ "@awsless/s3": "^0.0.21",
93
+ "@awsless/lambda": "^0.0.45",
92
94
  "@awsless/redis": "^0.1.13",
93
95
  "@awsless/scheduler": "^0.0.4",
94
- "@awsless/s3": "^0.0.21",
95
- "@awsless/size": "^0.0.2",
96
96
  "@awsless/sns": "^0.0.10",
97
+ "@awsless/sqs": "^0.0.24",
97
98
  "@awsless/ts-file-cache": "^0.0.16",
98
- "@awsless/clui": "^0.0.8",
99
99
  "@awsless/validate": "^0.1.7",
100
- "awsless": "^0.0.15-next.0",
101
100
  "@awsless/weak-cache": "^0.0.1",
102
- "@awsless/sqs": "^0.0.24"
101
+ "awsless": "^0.0.15-next.0",
102
+ "@awsless/size": "^0.0.2"
103
103
  },
104
104
  "devDependencies": {
105
105
  "@hono/node-server": "1.19.9",