@awsless/cli 0.0.46-next.4 → 0.0.46-next.6
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 +174 -86
- package/dist/build-json-schema.js +6 -6
- package/dist/handlers/{pubsub-server.mjs → pubsub-server.js} +31410 -37611
- package/dist/handlers/{rpc.mjs → rpc.js} +0 -7
- package/dist/stack.json +1 -1
- package/dist/stack.stage.json +1 -1
- package/package.json +11 -11
- /package/dist/handlers/{bundle.mjs → bundle.js} +0 -0
- /package/dist/handlers/{icon.mjs → icon.js} +0 -0
- /package/dist/handlers/{image.mjs → image.js} +0 -0
- /package/dist/handlers/{on-error-log.mjs → on-error-log.js} +0 -0
- /package/dist/handlers/{on-failure.mjs → on-failure.js} +0 -0
- /package/dist/handlers/{pubsub-publisher.mjs → pubsub-publisher.js} +0 -0
package/dist/bin.js
CHANGED
|
@@ -187,7 +187,7 @@ import {
|
|
|
187
187
|
string,
|
|
188
188
|
updateItem
|
|
189
189
|
} from "@awsless/dynamodb";
|
|
190
|
-
import {
|
|
190
|
+
import { isAfter, subHours } from "date-fns";
|
|
191
191
|
import { userInfo as userInfo2 } from "os";
|
|
192
192
|
|
|
193
193
|
// src/formation/cloudfront-kvs.ts
|
|
@@ -290,17 +290,16 @@ var getRouteStoreArn = async (cloudfront, name) => {
|
|
|
290
290
|
return;
|
|
291
291
|
}
|
|
292
292
|
};
|
|
293
|
-
var stageRoutes = async (kvs, state2
|
|
293
|
+
var stageRoutes = async (kvs, state2) => {
|
|
294
294
|
const routes = sortRoutes(state2.routes);
|
|
295
295
|
const table2 = getRouteTableId(routes);
|
|
296
|
-
const priorTable = prior ? getRouteTableId(sortRoutes(prior.routes)) : void 0;
|
|
297
296
|
const deployment = {
|
|
298
297
|
id: state2.deploymentId,
|
|
299
298
|
table: table2,
|
|
300
299
|
functionVersion: state2.functionVersion
|
|
301
300
|
};
|
|
302
301
|
const mutations = [
|
|
303
|
-
...
|
|
302
|
+
...getTableMutations(table2, routes),
|
|
304
303
|
{
|
|
305
304
|
type: "put",
|
|
306
305
|
key: `${DEPLOY_KEY_PREFIX}${deployment.id}`,
|
|
@@ -324,9 +323,7 @@ var createCloudFrontKvsProvider = ({ credentials, region }) => {
|
|
|
324
323
|
return stageRoutes(kvs, routeDeploymentInputSchema.parse(props.state));
|
|
325
324
|
},
|
|
326
325
|
async updateResource(props) {
|
|
327
|
-
|
|
328
|
-
const prior = routeDeploymentInputSchema.parse(props.priorState);
|
|
329
|
-
return stageRoutes(kvs, state2, prior.storeArn === state2.storeArn ? prior : void 0);
|
|
326
|
+
return stageRoutes(kvs, routeDeploymentInputSchema.parse(props.proposedState));
|
|
330
327
|
}
|
|
331
328
|
}
|
|
332
329
|
});
|
|
@@ -359,6 +356,42 @@ var pruneStoreDeployments = async (kvs, storeArn, deploymentIds) => {
|
|
|
359
356
|
});
|
|
360
357
|
};
|
|
361
358
|
|
|
359
|
+
// src/util/git.ts
|
|
360
|
+
import { execFileSync, execSync } from "child_process";
|
|
361
|
+
var git = (command) => {
|
|
362
|
+
try {
|
|
363
|
+
return execSync(`git ${command}`, { stdio: ["ignore", "pipe", "ignore"], encoding: "utf8" }).trim();
|
|
364
|
+
} catch {
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
var checkedOutBranch = () => {
|
|
369
|
+
return git("rev-parse --abbrev-ref HEAD");
|
|
370
|
+
};
|
|
371
|
+
var currentBranch = () => {
|
|
372
|
+
const branch = checkedOutBranch();
|
|
373
|
+
if (branch && branch !== "HEAD") {
|
|
374
|
+
return branch;
|
|
375
|
+
}
|
|
376
|
+
return process.env.GITHUB_HEAD_REF || process.env.GITHUB_REF_NAME || process.env.CI_COMMIT_REF_NAME || process.env.BRANCH_NAME || branch;
|
|
377
|
+
};
|
|
378
|
+
var currentCommit = () => {
|
|
379
|
+
return git("rev-parse HEAD");
|
|
380
|
+
};
|
|
381
|
+
var currentCommitMessage = () => {
|
|
382
|
+
return git("log -1 --pretty=%s");
|
|
383
|
+
};
|
|
384
|
+
var isCommitMerged = (commit, branch) => {
|
|
385
|
+
try {
|
|
386
|
+
execFileSync("git", ["merge-base", "--is-ancestor", commit, branch], {
|
|
387
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
388
|
+
});
|
|
389
|
+
return true;
|
|
390
|
+
} catch {
|
|
391
|
+
return false;
|
|
392
|
+
}
|
|
393
|
+
};
|
|
394
|
+
|
|
362
395
|
// src/util/lambda.ts
|
|
363
396
|
import {
|
|
364
397
|
CreateAliasCommand,
|
|
@@ -1203,7 +1236,7 @@ var pullRemoteState = async (app, stateBackend) => {
|
|
|
1203
1236
|
await rm(file);
|
|
1204
1237
|
}
|
|
1205
1238
|
} else {
|
|
1206
|
-
await writeFile(file, JSON.stringify(state2, void 0, 2));
|
|
1239
|
+
await writeFile(file, JSON.stringify(state2, void 0, 2), { mode: 384 });
|
|
1207
1240
|
}
|
|
1208
1241
|
};
|
|
1209
1242
|
var pushRemoteState = async (app, stateBackend) => {
|
|
@@ -1217,16 +1250,6 @@ var pushRemoteState = async (app, stateBackend) => {
|
|
|
1217
1250
|
var slugifyBranch = (branch) => {
|
|
1218
1251
|
return (branch ?? "").replace(/[^a-zA-Z0-9_-]+/g, "-").replace(/^-+|-+$/g, "") || "local";
|
|
1219
1252
|
};
|
|
1220
|
-
var git = (command) => {
|
|
1221
|
-
try {
|
|
1222
|
-
return execSync(`git ${command}`, { stdio: ["ignore", "pipe", "ignore"], encoding: "utf8" }).trim();
|
|
1223
|
-
} catch {
|
|
1224
|
-
return;
|
|
1225
|
-
}
|
|
1226
|
-
};
|
|
1227
|
-
var isCommitMerged = (commit, branch) => {
|
|
1228
|
-
return git(`merge-base --is-ancestor ${JSON.stringify(commit)} ${JSON.stringify(branch)}`) !== void 0;
|
|
1229
|
-
};
|
|
1230
1253
|
var table = define("awsless-deployments", {
|
|
1231
1254
|
hash: "appId",
|
|
1232
1255
|
sort: "id",
|
|
@@ -1246,10 +1269,13 @@ var table = define("awsless-deployments", {
|
|
|
1246
1269
|
var deploymentsTable = table;
|
|
1247
1270
|
var latestBranchDeployment = async (client, appId, branch) => {
|
|
1248
1271
|
const items = await listDeployments(client, appId, branch);
|
|
1249
|
-
return items.reduce(
|
|
1272
|
+
return items.reduce(
|
|
1273
|
+
(latest, item) => (latest?.seq ?? 0) >= item.seq ? latest : item,
|
|
1274
|
+
void 0
|
|
1275
|
+
);
|
|
1250
1276
|
};
|
|
1251
1277
|
var claimDeployment = async (props) => {
|
|
1252
|
-
const branch = slugifyBranch(
|
|
1278
|
+
const branch = slugifyBranch(currentBranch());
|
|
1253
1279
|
while (true) {
|
|
1254
1280
|
const latest = await latestBranchDeployment(props.client, props.appId, branch);
|
|
1255
1281
|
const seq = (latest?.seq ?? 0) + 1;
|
|
@@ -1260,8 +1286,8 @@ var claimDeployment = async (props) => {
|
|
|
1260
1286
|
seq,
|
|
1261
1287
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1262
1288
|
user: userInfo2().username,
|
|
1263
|
-
commit:
|
|
1264
|
-
message:
|
|
1289
|
+
commit: currentCommit(),
|
|
1290
|
+
message: currentCommitMessage()
|
|
1265
1291
|
};
|
|
1266
1292
|
try {
|
|
1267
1293
|
await putItem(table, deployment, {
|
|
@@ -1278,7 +1304,7 @@ var claimDeployment = async (props) => {
|
|
|
1278
1304
|
}
|
|
1279
1305
|
};
|
|
1280
1306
|
var currentDeployment = async (client, appId) => {
|
|
1281
|
-
return latestBranchDeployment(client, appId, slugifyBranch(
|
|
1307
|
+
return latestBranchDeployment(client, appId, slugifyBranch(currentBranch()));
|
|
1282
1308
|
};
|
|
1283
1309
|
var getDeployment = async (client, appId, id) => {
|
|
1284
1310
|
return getItem(table, { appId, id }, { client });
|
|
@@ -1328,6 +1354,10 @@ var markPromoted = async (client, appId, id) => {
|
|
|
1328
1354
|
var removeDeployment = async (client, appId, id) => {
|
|
1329
1355
|
await deleteItem(table, { appId, id }, { client });
|
|
1330
1356
|
};
|
|
1357
|
+
var BUSY_WINDOW_HOURS = 24;
|
|
1358
|
+
var isDeploymentBusy = (item, now = /* @__PURE__ */ new Date()) => {
|
|
1359
|
+
return !item.functionVersion && isAfter(new Date(item.createdAt), subHours(now, BUSY_WINDOW_HOURS));
|
|
1360
|
+
};
|
|
1331
1361
|
var selectPrunableDeployments = (items, liveId, options) => {
|
|
1332
1362
|
const rollbackTarget = items.filter((item) => item.promotedAt && item.id !== liveId).sort((a, b) => b.promotedAt.localeCompare(a.promotedAt))[0];
|
|
1333
1363
|
const keep = Math.max(1, Number(options.keep) || 10);
|
|
@@ -1335,16 +1365,15 @@ var selectPrunableDeployments = (items, liveId, options) => {
|
|
|
1335
1365
|
const keptMain = new Set(
|
|
1336
1366
|
items.filter((item) => item.branch === mainSlug && item.functionVersion).map((item) => item.seq).sort((a, b) => b - a).slice(0, keep)
|
|
1337
1367
|
);
|
|
1338
|
-
const dayAgo = new Date(Date.now() - 24 * 60 * 60 * 1e3).toISOString();
|
|
1339
1368
|
return items.filter((item) => {
|
|
1340
|
-
if (item.id === liveId || item.id === rollbackTarget?.id) {
|
|
1369
|
+
if (item.id === liveId || item.id === rollbackTarget?.id || isDeploymentBusy(item)) {
|
|
1341
1370
|
return false;
|
|
1342
1371
|
}
|
|
1343
1372
|
if (options.branch) {
|
|
1344
1373
|
return item.branch === slugifyBranch(options.branch);
|
|
1345
1374
|
}
|
|
1346
1375
|
if (!item.functionVersion) {
|
|
1347
|
-
return
|
|
1376
|
+
return true;
|
|
1348
1377
|
}
|
|
1349
1378
|
if (item.branch === mainSlug) {
|
|
1350
1379
|
return !keptMain.has(item.seq);
|
|
@@ -1494,7 +1523,10 @@ var promoteDeployment = async (props) => {
|
|
|
1494
1523
|
];
|
|
1495
1524
|
const failures = (await Promise.allSettled(rollback2)).filter((result) => result.status === "rejected").map((result) => result.reason);
|
|
1496
1525
|
if (failures.length > 0) {
|
|
1497
|
-
throw new AggregateError(
|
|
1526
|
+
throw new AggregateError(
|
|
1527
|
+
[error, ...failures],
|
|
1528
|
+
`Deployment promotion failed and couldn't be fully reverted.`
|
|
1529
|
+
);
|
|
1498
1530
|
}
|
|
1499
1531
|
throw error;
|
|
1500
1532
|
}
|
|
@@ -1956,7 +1988,7 @@ var CodeSchema = z14.union([
|
|
|
1956
1988
|
var FnSchema = z14.object({
|
|
1957
1989
|
code: CodeSchema,
|
|
1958
1990
|
handler: HandlerSchema.optional()
|
|
1959
|
-
});
|
|
1991
|
+
}).strict();
|
|
1960
1992
|
var FunctionSchema = z14.union([
|
|
1961
1993
|
LocalFileSchema.transform((code) => ({
|
|
1962
1994
|
code
|
|
@@ -2230,7 +2262,7 @@ var ErrorResponseSchema = z20.union([
|
|
|
2230
2262
|
minTTL: MinTTLSchema.optional()
|
|
2231
2263
|
})
|
|
2232
2264
|
]).optional();
|
|
2233
|
-
var RouteSchema = z20.string().regex(/^\//, "Route must start with a slash (/)");
|
|
2265
|
+
var RouteSchema = z20.string().regex(/^\//, "Route must start with a slash (/)").regex(/^\/([^/*.]+)?$/, 'Router paths mount a single segment without dots, like "/api".');
|
|
2234
2266
|
var VisibilitySchema = z20.boolean().default(false).describe("Whether to enable CloudWatch metrics for the WAF rule.");
|
|
2235
2267
|
var WafSettingsSchema = z20.object({
|
|
2236
2268
|
rateLimiter: z20.object({
|
|
@@ -2729,8 +2761,8 @@ var AppSchema = z29.object({
|
|
|
2729
2761
|
layers: LayerSchema,
|
|
2730
2762
|
router: RouterDefaultSchema
|
|
2731
2763
|
// dataRetention: z.boolean().describe('Configure how your resources are handled on delete.').default(false),
|
|
2732
|
-
}).default({}).describe("Default properties")
|
|
2733
|
-
});
|
|
2764
|
+
}).strict().default({}).describe("Default properties")
|
|
2765
|
+
}).strict();
|
|
2734
2766
|
|
|
2735
2767
|
// src/config/stack.ts
|
|
2736
2768
|
import { z as z45 } from "zod";
|
|
@@ -2786,7 +2818,7 @@ var CommandsSchema = z31.record(ResourceIdSchema, CommandSchema).optional().desc
|
|
|
2786
2818
|
|
|
2787
2819
|
// src/feature/config/schema.ts
|
|
2788
2820
|
import { z as z32 } from "zod";
|
|
2789
|
-
var ConfigNameSchema = z32.string().regex(
|
|
2821
|
+
var ConfigNameSchema = z32.string().regex(/^[a-z0-9-]+$/, "Invalid config name");
|
|
2790
2822
|
var ConfigsSchema = z32.array(ConfigNameSchema).optional().describe("Define the config values for your stack.");
|
|
2791
2823
|
|
|
2792
2824
|
// src/feature/cron/schema/index.ts
|
|
@@ -3372,7 +3404,7 @@ var StackSchema = z45.object({
|
|
|
3372
3404
|
images: ImagesSchema,
|
|
3373
3405
|
icons: IconsSchema,
|
|
3374
3406
|
metrics: MetricsSchema
|
|
3375
|
-
});
|
|
3407
|
+
}).strict();
|
|
3376
3408
|
|
|
3377
3409
|
// src/config/load/read.ts
|
|
3378
3410
|
import { readFile as readFile3 } from "fs/promises";
|
|
@@ -3831,7 +3863,7 @@ import { readdir as readdir2, readFile as readFile7, writeFile as writeFile4 } f
|
|
|
3831
3863
|
import { join as join10 } from "path";
|
|
3832
3864
|
|
|
3833
3865
|
// src/build/index.ts
|
|
3834
|
-
import { mkdir as mkdir2, readFile as readFile4, writeFile as writeFile2 } from "fs/promises";
|
|
3866
|
+
import { mkdir as mkdir2, readFile as readFile4, rm as rm2, writeFile as writeFile2 } from "fs/promises";
|
|
3835
3867
|
import { dirname as dirname4, join as join7 } from "path";
|
|
3836
3868
|
|
|
3837
3869
|
// src/util/timer.ts
|
|
@@ -3873,6 +3905,7 @@ var build = (type, name, builder, props) => {
|
|
|
3873
3905
|
cached: true
|
|
3874
3906
|
};
|
|
3875
3907
|
}
|
|
3908
|
+
await rm2(cacheFile, { force: true });
|
|
3876
3909
|
const time = createTimer();
|
|
3877
3910
|
const meta = await callback(async (file, data2) => {
|
|
3878
3911
|
const path = getBuildPath(type, name, file);
|
|
@@ -3925,7 +3958,7 @@ var zipFiles = (files) => {
|
|
|
3925
3958
|
import { generateFileHash } from "@awsless/ts-file-cache";
|
|
3926
3959
|
import { kebabCase as kebabCase5 } from "change-case";
|
|
3927
3960
|
import { createHash as createHash5 } from "crypto";
|
|
3928
|
-
import { readFile as readFile6, rm as
|
|
3961
|
+
import { readFile as readFile6, rm as rm4, writeFile as writeFile3 } from "fs/promises";
|
|
3929
3962
|
import { dirname as dirname5, join as join9 } from "path";
|
|
3930
3963
|
import { fileURLToPath } from "url";
|
|
3931
3964
|
|
|
@@ -3937,13 +3970,13 @@ var formatByteSize = (size) => {
|
|
|
3937
3970
|
};
|
|
3938
3971
|
|
|
3939
3972
|
// src/util/temp.ts
|
|
3940
|
-
import { mkdir as mkdir3, readdir, rm as
|
|
3973
|
+
import { mkdir as mkdir3, readdir, rm as rm3 } from "fs/promises";
|
|
3941
3974
|
import { join as join8 } from "path";
|
|
3942
3975
|
var createTempFolder = async (name) => {
|
|
3943
3976
|
const path = join8(directories.temp, name);
|
|
3944
3977
|
await mkdir3(join8(directories.temp, name), { recursive: true });
|
|
3945
3978
|
process.on("SIGTERM", async () => {
|
|
3946
|
-
await
|
|
3979
|
+
await rm3(path, { recursive: true });
|
|
3947
3980
|
});
|
|
3948
3981
|
return {
|
|
3949
3982
|
path,
|
|
@@ -3951,7 +3984,7 @@ var createTempFolder = async (name) => {
|
|
|
3951
3984
|
return readdir(path, { recursive: true });
|
|
3952
3985
|
},
|
|
3953
3986
|
async delete() {
|
|
3954
|
-
await
|
|
3987
|
+
await rm3(path, { recursive: true });
|
|
3955
3988
|
}
|
|
3956
3989
|
};
|
|
3957
3990
|
};
|
|
@@ -3982,6 +4015,9 @@ var bundleTypeScriptWithRolldown = async ({
|
|
|
3982
4015
|
moduleSideEffects: (id, isExternal) => isExternal ? external?.includes(id) === true : id.startsWith(`${directories.root}/`) && !id.includes("/node_modules/")
|
|
3983
4016
|
},
|
|
3984
4017
|
onwarn: (error) => {
|
|
4018
|
+
if (error.code === "UNRESOLVED_IMPORT") {
|
|
4019
|
+
throw new ExpectedError(error.message);
|
|
4020
|
+
}
|
|
3985
4021
|
debugError(error.message);
|
|
3986
4022
|
},
|
|
3987
4023
|
plugins: [
|
|
@@ -4048,14 +4084,17 @@ var bundleTypeScriptWithRolldown = async ({
|
|
|
4048
4084
|
files
|
|
4049
4085
|
};
|
|
4050
4086
|
};
|
|
4051
|
-
var TEST_ONLY_MODULES = ["dynamo-db-local", "@awsless/dynamodb-server", "redis-memory-server"];
|
|
4087
|
+
var TEST_ONLY_MODULES = ["dynamo-db-local", "@awsless/dynamodb-server", "redis-memory-server", "aws-sdk-vitest-mock"];
|
|
4088
|
+
var findPackage = (id, names) => {
|
|
4089
|
+
return names.find((name) => id.includes(`/${name.replace(/^@[^/]+\//, "")}/`));
|
|
4090
|
+
};
|
|
4052
4091
|
var assertNoTestOnlyModules = (output) => {
|
|
4053
4092
|
for (const item of output) {
|
|
4054
4093
|
if (item.type !== "chunk") {
|
|
4055
4094
|
continue;
|
|
4056
4095
|
}
|
|
4057
4096
|
for (const id of item.moduleIds ?? []) {
|
|
4058
|
-
const found =
|
|
4097
|
+
const found = findPackage(id, TEST_ONLY_MODULES);
|
|
4059
4098
|
if (found) {
|
|
4060
4099
|
throw new Error(
|
|
4061
4100
|
`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.`
|
|
@@ -4086,7 +4125,7 @@ var registerBundleFunction = (ctx, routeKey, props) => {
|
|
|
4086
4125
|
};
|
|
4087
4126
|
var buildBundle = (props) => {
|
|
4088
4127
|
return async (build3, { workspace }) => {
|
|
4089
|
-
const runtime = props.runtime ?? join9(dirname5(fileURLToPath(import.meta.url)), "/handlers/bundle.
|
|
4128
|
+
const runtime = props.runtime ?? join9(dirname5(fileURLToPath(import.meta.url)), "/handlers/bundle.js");
|
|
4090
4129
|
const handlers = [...props.handlers].sort((a, b) => a.routeKey.localeCompare(b.routeKey));
|
|
4091
4130
|
const entries = handlers.map(({ routeKey, file, exportName }) => {
|
|
4092
4131
|
const virtualFile = JSON.stringify(`${file}?awsless-route=${encodeURIComponent(routeKey)}`);
|
|
@@ -4135,7 +4174,7 @@ ${entries.join("\n")}
|
|
|
4135
4174
|
importAsString: importAsString2.length > 0 ? importAsString2 : void 0
|
|
4136
4175
|
});
|
|
4137
4176
|
await temp.delete();
|
|
4138
|
-
await
|
|
4177
|
+
await rm4(getBuildPath("bundle", props.name, "files"), { recursive: true, force: true });
|
|
4139
4178
|
await Promise.all([
|
|
4140
4179
|
write("HASH", bundle.hash),
|
|
4141
4180
|
...bundle.files.map((file) => write(`files/${file.name}`, file.code)),
|
|
@@ -4657,7 +4696,7 @@ var SsmStore = class {
|
|
|
4657
4696
|
debug("Value:", color.info(value));
|
|
4658
4697
|
await this.client.send(
|
|
4659
4698
|
new PutParameterCommand({
|
|
4660
|
-
Type: ParameterType.
|
|
4699
|
+
Type: ParameterType.SECURE_STRING,
|
|
4661
4700
|
Name: this.getName(name),
|
|
4662
4701
|
Value: value,
|
|
4663
4702
|
Overwrite: true
|
|
@@ -5093,10 +5132,12 @@ var domainFeature = defineFeature({
|
|
|
5093
5132
|
}
|
|
5094
5133
|
}
|
|
5095
5134
|
ctx.addGlobalPermission({
|
|
5096
|
-
actions: ["ses
|
|
5135
|
+
actions: ["ses:SendEmail", "ses:SendRawEmail"],
|
|
5097
5136
|
resources: [
|
|
5098
|
-
|
|
5099
|
-
|
|
5137
|
+
`arn:aws:ses:${ctx.appConfig.region}:${ctx.accountId}:identity/*`,
|
|
5138
|
+
// Sending through the app configuration set is authorized against
|
|
5139
|
+
// its own ARN, not just the identity.
|
|
5140
|
+
`arn:aws:ses:${ctx.appConfig.region}:${ctx.accountId}:configuration-set/${ctx.app.name}`
|
|
5100
5141
|
]
|
|
5101
5142
|
});
|
|
5102
5143
|
}
|
|
@@ -5186,7 +5227,9 @@ var functionFeature = defineFeature({
|
|
|
5186
5227
|
// 'lambda:ListFunctions',
|
|
5187
5228
|
// 'lambda:GetFunction',
|
|
5188
5229
|
],
|
|
5189
|
-
resources: [
|
|
5230
|
+
resources: [
|
|
5231
|
+
`arn:aws:lambda:${ctx.appConfig.region}:${ctx.accountId}:function:${ctx.appConfig.name}--*`
|
|
5232
|
+
]
|
|
5190
5233
|
});
|
|
5191
5234
|
},
|
|
5192
5235
|
onStack(ctx) {
|
|
@@ -5228,7 +5271,7 @@ var onErrorLogFeature = defineFeature({
|
|
|
5228
5271
|
const consumerRoute = formatRouteKey(ctx.app.name, "on-error-log", "consumer");
|
|
5229
5272
|
bundle.addHandler({
|
|
5230
5273
|
routeKey: handlerRoute,
|
|
5231
|
-
file: join11(dirname6(fileURLToPath2(import.meta.url)), "/handlers/on-error-log.
|
|
5274
|
+
file: join11(dirname6(fileURLToPath2(import.meta.url)), "/handlers/on-error-log.js"),
|
|
5232
5275
|
exportName: "default"
|
|
5233
5276
|
});
|
|
5234
5277
|
bundle.addEnv(formatRouteEnvName(handlerRoute, "CONSUMER"), consumerRoute);
|
|
@@ -5453,7 +5496,7 @@ var onFailureFeature = defineFeature({
|
|
|
5453
5496
|
const consumer = props.consumer;
|
|
5454
5497
|
bundle.addHandler({
|
|
5455
5498
|
routeKey: normalizerRoute,
|
|
5456
|
-
file: join12(dirname7(fileURLToPath3(import.meta.url)), "/handlers/on-failure.
|
|
5499
|
+
file: join12(dirname7(fileURLToPath3(import.meta.url)), "/handlers/on-failure.js"),
|
|
5457
5500
|
exportName: "default"
|
|
5458
5501
|
});
|
|
5459
5502
|
registerBundleFunction(ctx, consumerRoute, consumer);
|
|
@@ -5608,7 +5651,7 @@ var createPubSubService = (parentGroup, ctx, id, props, inputs) => {
|
|
|
5608
5651
|
});
|
|
5609
5652
|
const shortName = shortId(`${ctx.app.name}:pubsub:${id}:${ctx.appId}`);
|
|
5610
5653
|
const image2 = "public.ecr.aws/aws-cli/aws-cli:arm64";
|
|
5611
|
-
const bundleFile = join14(__dirname, "handlers/pubsub-server.
|
|
5654
|
+
const bundleFile = join14(__dirname, "handlers/pubsub-server.js");
|
|
5612
5655
|
ctx.registerBuild("pubsub", name, async (build3) => {
|
|
5613
5656
|
const hash = createHash8("sha1").update(await readFile9(bundleFile)).digest("hex");
|
|
5614
5657
|
const fingerprint = `${hash}-${ARCHITECTURE}`;
|
|
@@ -5709,7 +5752,8 @@ var createPubSubService = (parentGroup, ctx, id, props, inputs) => {
|
|
|
5709
5752
|
Statement: list3.map((statement) => ({
|
|
5710
5753
|
Effect: pascalCase2(statement.effect ?? "allow"),
|
|
5711
5754
|
Action: statement.actions,
|
|
5712
|
-
Resource: statement.resources
|
|
5755
|
+
Resource: statement.resources,
|
|
5756
|
+
Condition: statement.conditions
|
|
5713
5757
|
}))
|
|
5714
5758
|
})
|
|
5715
5759
|
);
|
|
@@ -6200,7 +6244,7 @@ var pubsubFeature = defineFeature({
|
|
|
6200
6244
|
const publisherRouteKey = formatRouteKey(ctx.app.name, "pubsub", `${id}-publisher`);
|
|
6201
6245
|
bundle.addHandler({
|
|
6202
6246
|
routeKey: publisherRouteKey,
|
|
6203
|
-
file: join15(__dirname2, "/handlers/pubsub-publisher.
|
|
6247
|
+
file: join15(__dirname2, "/handlers/pubsub-publisher.js"),
|
|
6204
6248
|
exportName: "default"
|
|
6205
6249
|
});
|
|
6206
6250
|
bundle.addEnv(formatRouteEnvName3(publisherRouteKey, "REDIS_HOST"), redisHost);
|
|
@@ -6549,7 +6593,7 @@ var rpcFeature = defineFeature({
|
|
|
6549
6593
|
const serverRouteKey = formatRouteKey(ctx.app.name, "rpc", id);
|
|
6550
6594
|
bundle.addHandler({
|
|
6551
6595
|
routeKey: serverRouteKey,
|
|
6552
|
-
file: join16(dirname10(fileURLToPath6(import.meta.url)), "/handlers/rpc.
|
|
6596
|
+
file: join16(dirname10(fileURLToPath6(import.meta.url)), "/handlers/rpc.js"),
|
|
6553
6597
|
exportName: "default"
|
|
6554
6598
|
});
|
|
6555
6599
|
bundle.addEnv(
|
|
@@ -7076,9 +7120,12 @@ var siteFeature = defineFeature({
|
|
|
7076
7120
|
new Response(instance.stderr).text(),
|
|
7077
7121
|
instance.exited
|
|
7078
7122
|
]);
|
|
7079
|
-
if (instance.exitCode !==
|
|
7080
|
-
|
|
7081
|
-
|
|
7123
|
+
if (instance.exitCode !== 0) {
|
|
7124
|
+
const reason = instance.signalCode ? ` (${instance.signalCode})` : "";
|
|
7125
|
+
throw new ExpectedError(
|
|
7126
|
+
`Site build failed${reason}:
|
|
7127
|
+
${(errors.trim() || output.trim()).slice(-2e3)}`
|
|
7128
|
+
);
|
|
7082
7129
|
}
|
|
7083
7130
|
await write("HASH", fingerprint);
|
|
7084
7131
|
return {
|
|
@@ -7919,7 +7966,7 @@ var imageFeature = defineFeature({
|
|
|
7919
7966
|
const serverRouteKey = formatRouteKey(ctx.stack.name, "image", id);
|
|
7920
7967
|
bundle.addHandler({
|
|
7921
7968
|
routeKey: serverRouteKey,
|
|
7922
|
-
file: join20(dirname12(fileURLToPath7(import.meta.url)), "/handlers/image.
|
|
7969
|
+
file: join20(dirname12(fileURLToPath7(import.meta.url)), "/handlers/image.js"),
|
|
7923
7970
|
exportName: "default",
|
|
7924
7971
|
external: ["sharp"]
|
|
7925
7972
|
});
|
|
@@ -8018,7 +8065,7 @@ var iconFeature = defineFeature({
|
|
|
8018
8065
|
const serverRouteKey = formatRouteKey(ctx.stack.name, "icon", id);
|
|
8019
8066
|
bundle.addHandler({
|
|
8020
8067
|
routeKey: serverRouteKey,
|
|
8021
|
-
file: join21(dirname13(fileURLToPath8(import.meta.url)), "/handlers/icon.
|
|
8068
|
+
file: join21(dirname13(fileURLToPath8(import.meta.url)), "/handlers/icon.js"),
|
|
8022
8069
|
exportName: "default"
|
|
8023
8070
|
});
|
|
8024
8071
|
addRoutes({
|
|
@@ -8277,7 +8324,8 @@ var createFargateJob = (parentGroup, ctx, ns, id, local) => {
|
|
|
8277
8324
|
Statement: list3.map((statement) => ({
|
|
8278
8325
|
Effect: pascalCase3(statement.effect ?? "allow"),
|
|
8279
8326
|
Action: statement.actions,
|
|
8280
|
-
Resource: statement.resources
|
|
8327
|
+
Resource: statement.resources,
|
|
8328
|
+
Condition: statement.conditions
|
|
8281
8329
|
}))
|
|
8282
8330
|
})
|
|
8283
8331
|
);
|
|
@@ -8775,7 +8823,8 @@ var createFargateTask = (parentGroup, ctx, ns, id, local) => {
|
|
|
8775
8823
|
Statement: list3.map((statement) => ({
|
|
8776
8824
|
Effect: pascalCase4(statement.effect ?? "allow"),
|
|
8777
8825
|
Action: statement.actions,
|
|
8778
|
-
Resource: statement.resources
|
|
8826
|
+
Resource: statement.resources,
|
|
8827
|
+
Condition: statement.conditions
|
|
8779
8828
|
}))
|
|
8780
8829
|
})
|
|
8781
8830
|
);
|
|
@@ -9247,12 +9296,15 @@ var metricFeature = defineFeature({
|
|
|
9247
9296
|
});
|
|
9248
9297
|
|
|
9249
9298
|
// src/feature/router/index.ts
|
|
9250
|
-
import { days as days10, seconds as
|
|
9299
|
+
import { days as days10, seconds as seconds7, toSeconds as toSeconds13, years } from "@awsless/duration";
|
|
9251
9300
|
import { Group as Group29 } from "@terraforge/core";
|
|
9252
9301
|
import { aws as aws30 } from "@terraforge/aws";
|
|
9253
9302
|
import { camelCase as camelCase9, constantCase as constantCase15 } from "change-case";
|
|
9254
9303
|
|
|
9255
9304
|
// src/feature/router/router-code.ts
|
|
9305
|
+
import { minutes as minutes8, seconds as seconds6, toSeconds as toSeconds12 } from "@awsless/duration";
|
|
9306
|
+
var ORIGIN_READ_TIMEOUT = toSeconds12(minutes8(2));
|
|
9307
|
+
var ORIGIN_CONNECTION_TIMEOUT = toSeconds12(seconds6(10));
|
|
9256
9308
|
var getViewerRequestFunctionCode = (props) => {
|
|
9257
9309
|
return CODE(
|
|
9258
9310
|
[
|
|
@@ -9447,6 +9499,11 @@ function isValidRoute(route, method) {
|
|
|
9447
9499
|
}
|
|
9448
9500
|
|
|
9449
9501
|
async function findRoute(path, method, prefix) {
|
|
9502
|
+
// only route selection is normalized, the forwarded uri stays untouched
|
|
9503
|
+
if (path.length > 1 && path.slice(-1) === '/') {
|
|
9504
|
+
path = path.slice(0, -1);
|
|
9505
|
+
}
|
|
9506
|
+
|
|
9450
9507
|
const store = cf.kvs();
|
|
9451
9508
|
const keys = getPossibleRouteKeys(path);
|
|
9452
9509
|
|
|
@@ -9528,13 +9585,12 @@ function setS3Origin(route) {
|
|
|
9528
9585
|
function setLambdaOrigin(route) {
|
|
9529
9586
|
const config = getRequestOriginConfig(route);
|
|
9530
9587
|
|
|
9531
|
-
// CloudFront caps the origin response timeout at 60s without a quota increase.
|
|
9532
9588
|
if(typeof config.timeouts.readTimeout !== 'number') {
|
|
9533
|
-
config.timeouts.readTimeout =
|
|
9589
|
+
config.timeouts.readTimeout = ${ORIGIN_READ_TIMEOUT};
|
|
9534
9590
|
}
|
|
9535
9591
|
|
|
9536
9592
|
if(typeof config.timeouts.connectionTimeout !== 'number') {
|
|
9537
|
-
config.timeouts.connectionTimeout =
|
|
9593
|
+
config.timeouts.connectionTimeout = ${ORIGIN_CONNECTION_TIMEOUT};
|
|
9538
9594
|
}
|
|
9539
9595
|
|
|
9540
9596
|
cf.updateRequestOrigin(Object.assign(config, {
|
|
@@ -9610,6 +9666,8 @@ async function handler(event) {
|
|
|
9610
9666
|
|
|
9611
9667
|
if(route.forwardHost && headers.host && headers.host.value) {
|
|
9612
9668
|
headers['x-forwarded-host'] = { value: headers.host.value };
|
|
9669
|
+
} else {
|
|
9670
|
+
delete headers['x-forwarded-host'];
|
|
9613
9671
|
}
|
|
9614
9672
|
|
|
9615
9673
|
headers['x-origin'] = { value: route.domainName };
|
|
@@ -9698,9 +9756,9 @@ var routerFeature = defineFeature({
|
|
|
9698
9756
|
});
|
|
9699
9757
|
const cache = new aws30.cloudfront.CachePolicy(group, "cache", {
|
|
9700
9758
|
name,
|
|
9701
|
-
minTtl:
|
|
9702
|
-
maxTtl:
|
|
9703
|
-
defaultTtl:
|
|
9759
|
+
minTtl: toSeconds13(seconds7(0)),
|
|
9760
|
+
maxTtl: toSeconds13(days10(365)),
|
|
9761
|
+
defaultTtl: toSeconds13(days10(0)),
|
|
9704
9762
|
parametersInCacheKeyAndForwardedToOrigin: {
|
|
9705
9763
|
enableAcceptEncodingBrotli: true,
|
|
9706
9764
|
enableAcceptEncodingGzip: true,
|
|
@@ -9753,7 +9811,7 @@ var routerFeature = defineFeature({
|
|
|
9753
9811
|
name,
|
|
9754
9812
|
corsConfig: {
|
|
9755
9813
|
originOverride: props.cors?.override ?? true,
|
|
9756
|
-
accessControlMaxAgeSec:
|
|
9814
|
+
accessControlMaxAgeSec: toSeconds13(props.cors?.maxAge ?? years(1)),
|
|
9757
9815
|
accessControlAllowHeaders: { items: props.cors?.headers ?? ["*"] },
|
|
9758
9816
|
accessControlAllowMethods: { items: props.cors?.methods ?? ["ALL"] },
|
|
9759
9817
|
accessControlAllowOrigins: { items: props.cors?.origins ?? ["*"] },
|
|
@@ -9778,7 +9836,7 @@ var routerFeature = defineFeature({
|
|
|
9778
9836
|
strictTransportSecurity: {
|
|
9779
9837
|
override: true,
|
|
9780
9838
|
preload: true,
|
|
9781
|
-
accessControlMaxAgeSec:
|
|
9839
|
+
accessControlMaxAgeSec: toSeconds13(years(1)),
|
|
9782
9840
|
includeSubdomains: true
|
|
9783
9841
|
},
|
|
9784
9842
|
xssProtection: {
|
|
@@ -9798,7 +9856,7 @@ var routerFeature = defineFeature({
|
|
|
9798
9856
|
rateBasedStatement: {
|
|
9799
9857
|
limit: wafSettingsConfig.rateLimiter.limit,
|
|
9800
9858
|
aggregateKeyType: "IP",
|
|
9801
|
-
evaluationWindowSec:
|
|
9859
|
+
evaluationWindowSec: toSeconds13(wafSettingsConfig.rateLimiter.window)
|
|
9802
9860
|
}
|
|
9803
9861
|
},
|
|
9804
9862
|
action: {
|
|
@@ -9888,12 +9946,12 @@ var routerFeature = defineFeature({
|
|
|
9888
9946
|
rule: wafRules,
|
|
9889
9947
|
captchaConfig: {
|
|
9890
9948
|
immunityTimeProperty: {
|
|
9891
|
-
immunityTime:
|
|
9949
|
+
immunityTime: toSeconds13(wafSettingsConfig.captchaImmunityTime)
|
|
9892
9950
|
}
|
|
9893
9951
|
},
|
|
9894
9952
|
challengeConfig: {
|
|
9895
9953
|
immunityTimeProperty: {
|
|
9896
|
-
immunityTime:
|
|
9954
|
+
immunityTime: toSeconds13(wafSettingsConfig.challengeImmunityTime)
|
|
9897
9955
|
}
|
|
9898
9956
|
},
|
|
9899
9957
|
visibilityConfig: {
|
|
@@ -9949,7 +10007,7 @@ var routerFeature = defineFeature({
|
|
|
9949
10007
|
}
|
|
9950
10008
|
return {
|
|
9951
10009
|
errorCode: Number(errorCode),
|
|
9952
|
-
errorCachingMinTtl: item.minTTL ?
|
|
10010
|
+
errorCachingMinTtl: item.minTTL ? toSeconds13(item.minTTL) : void 0,
|
|
9953
10011
|
responseCode: item.statusCode?.toString() ?? errorCode,
|
|
9954
10012
|
responsePagePath: item.path
|
|
9955
10013
|
};
|
|
@@ -10032,7 +10090,7 @@ var routerFeature = defineFeature({
|
|
|
10032
10090
|
}
|
|
10033
10091
|
return {
|
|
10034
10092
|
errorCode: Number(errorCode),
|
|
10035
|
-
errorCachingMinTtl: item.minTTL ?
|
|
10093
|
+
errorCachingMinTtl: item.minTTL ? toSeconds13(item.minTTL) : void 0,
|
|
10036
10094
|
responseCode: item.statusCode ?? Number(errorCode),
|
|
10037
10095
|
responsePagePath: item.path
|
|
10038
10096
|
};
|
|
@@ -10452,6 +10510,12 @@ var logo = () => {
|
|
|
10452
10510
|
var layout = async (command, cb) => {
|
|
10453
10511
|
console.log();
|
|
10454
10512
|
log9.intro(`${logo()} ${color.line(command)}`);
|
|
10513
|
+
let completed = false;
|
|
10514
|
+
process.on("exit", (code) => {
|
|
10515
|
+
if (code === 0 && !completed) {
|
|
10516
|
+
process.exitCode = 130;
|
|
10517
|
+
}
|
|
10518
|
+
});
|
|
10455
10519
|
try {
|
|
10456
10520
|
const options = program.optsWithGlobals();
|
|
10457
10521
|
const appConfig = await loadAppConfig(options);
|
|
@@ -10466,9 +10530,11 @@ var layout = async (command, cb) => {
|
|
|
10466
10530
|
appConfig,
|
|
10467
10531
|
stackConfigs
|
|
10468
10532
|
});
|
|
10533
|
+
completed = true;
|
|
10469
10534
|
log9.outro(result ?? void 0);
|
|
10470
10535
|
process.exit(0);
|
|
10471
10536
|
} catch (error) {
|
|
10537
|
+
completed = true;
|
|
10472
10538
|
playErrorSound();
|
|
10473
10539
|
logError(error);
|
|
10474
10540
|
log9.outro();
|
|
@@ -12555,9 +12621,12 @@ var test = (program2) => {
|
|
|
12555
12621
|
if (tests.length === 0) {
|
|
12556
12622
|
return "No tests found.";
|
|
12557
12623
|
}
|
|
12558
|
-
await runTests(tests, stacks, options?.filters, {
|
|
12624
|
+
const passed = await runTests(tests, stacks, options?.filters, {
|
|
12559
12625
|
showLogs: true
|
|
12560
12626
|
});
|
|
12627
|
+
if (!passed) {
|
|
12628
|
+
throw new Cancelled();
|
|
12629
|
+
}
|
|
12561
12630
|
return "All tests finished.";
|
|
12562
12631
|
});
|
|
12563
12632
|
});
|
|
@@ -12782,14 +12851,14 @@ var parseJsonLog = (message) => {
|
|
|
12782
12851
|
json = JSON.parse(message);
|
|
12783
12852
|
} catch (error) {
|
|
12784
12853
|
}
|
|
12785
|
-
if ("level" in json && typeof json.level === "string" && "timestamp" in json && typeof json.timestamp === "string" && "message" in json) {
|
|
12854
|
+
if (typeof json === "object" && json !== null && "level" in json && typeof json.level === "string" && "timestamp" in json && typeof json.timestamp === "string" && "message" in json) {
|
|
12786
12855
|
return {
|
|
12787
12856
|
level: json.level,
|
|
12788
12857
|
message: typeof json.message === "string" ? json.message : JSON.stringify(json.message, void 0, 2),
|
|
12789
12858
|
date: new Date(json.timestamp)
|
|
12790
12859
|
};
|
|
12791
12860
|
}
|
|
12792
|
-
if ("type" in json && typeof json.type === "string" && json.type.startsWith("platform") && "time" in json && typeof json.time === "string" && "record" in json) {
|
|
12861
|
+
if (typeof json === "object" && json !== null && "type" in json && typeof json.type === "string" && json.type.startsWith("platform") && "time" in json && typeof json.time === "string" && "record" in json) {
|
|
12793
12862
|
return {
|
|
12794
12863
|
level: "SYSTEM",
|
|
12795
12864
|
message: JSON.stringify(json.record, void 0, 2),
|
|
@@ -13254,11 +13323,11 @@ var createClients = async (appConfig) => {
|
|
|
13254
13323
|
};
|
|
13255
13324
|
};
|
|
13256
13325
|
var formatAge = (iso) => {
|
|
13257
|
-
const
|
|
13258
|
-
if (
|
|
13259
|
-
if (
|
|
13260
|
-
if (
|
|
13261
|
-
return `${Math.floor(
|
|
13326
|
+
const minutes9 = Math.floor((Date.now() - Date.parse(iso)) / 6e4);
|
|
13327
|
+
if (minutes9 < 1) return "just now";
|
|
13328
|
+
if (minutes9 < 60) return `${minutes9}m ago`;
|
|
13329
|
+
if (minutes9 < 60 * 24) return `${Math.floor(minutes9 / 60)}h ago`;
|
|
13330
|
+
return `${Math.floor(minutes9 / (60 * 24))}d ago`;
|
|
13262
13331
|
};
|
|
13263
13332
|
var formatStatus = (item, liveId) => {
|
|
13264
13333
|
if (item.id === liveId) return color.success("live ");
|
|
@@ -13319,10 +13388,23 @@ var prune = (program2) => {
|
|
|
13319
13388
|
initialMessage: "Pruning the deployments",
|
|
13320
13389
|
successMessage: "Done pruning the deployments.",
|
|
13321
13390
|
task: () => withAppReleaseLock(appConfig, async () => {
|
|
13322
|
-
|
|
13391
|
+
const [freshItems, freshLiveId] = await Promise.all([
|
|
13392
|
+
listDeployments(dynamo, appId),
|
|
13393
|
+
readLiveDeploymentId(lambda, functionName)
|
|
13394
|
+
]);
|
|
13395
|
+
const confirmed = new Set(prunable.map((item) => item.id));
|
|
13396
|
+
const prune2 = selectPrunableDeployments(freshItems, freshLiveId, options).filter(
|
|
13397
|
+
(item) => confirmed.has(item.id)
|
|
13398
|
+
);
|
|
13399
|
+
for (const item of prune2) {
|
|
13323
13400
|
await deleteLambdaAlias(lambda, functionName, getDeploymentLambdaAliasName(item.id));
|
|
13324
13401
|
}
|
|
13325
|
-
const versions = await selectPrunableVersions({
|
|
13402
|
+
const versions = await selectPrunableVersions({
|
|
13403
|
+
lambda,
|
|
13404
|
+
functionName,
|
|
13405
|
+
items: freshItems,
|
|
13406
|
+
prunable: prune2
|
|
13407
|
+
});
|
|
13326
13408
|
for (const version of versions) {
|
|
13327
13409
|
await pruneFunctionVersion(lambda, functionName, version);
|
|
13328
13410
|
}
|
|
@@ -13338,10 +13420,10 @@ var prune = (program2) => {
|
|
|
13338
13420
|
await pruneStoreDeployments(
|
|
13339
13421
|
kvs,
|
|
13340
13422
|
storeArn,
|
|
13341
|
-
|
|
13423
|
+
prune2.map((item) => item.id)
|
|
13342
13424
|
);
|
|
13343
13425
|
}
|
|
13344
|
-
for (const item of
|
|
13426
|
+
for (const item of prune2) {
|
|
13345
13427
|
await removeDeployment(dynamo, appId, item.id);
|
|
13346
13428
|
}
|
|
13347
13429
|
})
|
|
@@ -13425,4 +13507,10 @@ program.on("option:no-cache", () => {
|
|
|
13425
13507
|
commands10.forEach((fn) => fn(program));
|
|
13426
13508
|
|
|
13427
13509
|
// src/bin.ts
|
|
13510
|
+
var interrupt = (code) => () => {
|
|
13511
|
+
process.stdout.write("\x1B[?25h");
|
|
13512
|
+
process.exit(code);
|
|
13513
|
+
};
|
|
13514
|
+
process.on("SIGINT", interrupt(130));
|
|
13515
|
+
process.on("SIGTERM", interrupt(143));
|
|
13428
13516
|
program.parse(process.argv);
|