@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.
- package/dist/app.json +1 -1
- package/dist/app.stage.json +1 -1
- package/dist/bin.js +254 -50
- package/dist/build-json-schema.js +16 -0
- package/dist/handlers/bundle.mjs +2 -138
- package/dist/handlers/on-failure.mjs +86 -8
- package/package.json +8 -8
package/dist/handlers/bundle.mjs
CHANGED
|
@@ -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
|
-
|
|
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:
|
|
110
|
+
payload: body,
|
|
111
|
+
source: queueName ? { resource: logicalResourceName(queueName), event: body } : undefined,
|
|
36
112
|
queue: {
|
|
37
|
-
name:
|
|
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
|
|
185
|
+
payload,
|
|
186
|
+
source: table ? { resource: logicalResourceName(table) } : getFailureSource(payload)
|
|
109
187
|
};
|
|
110
188
|
};
|
|
111
189
|
var parsePayload = (payload) => {
|
|
112
190
|
try {
|
|
113
|
-
return
|
|
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.
|
|
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/
|
|
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
|
-
"
|
|
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",
|