@stacksjs/ts-cloud 0.5.5 → 0.5.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/bin/cli.js +460 -460
- package/dist/deploy/serverless-app.d.ts +6 -0
- package/dist/index.js +36 -12
- package/package.json +3 -3
|
@@ -45,6 +45,12 @@ export type CodeSource = {
|
|
|
45
45
|
kind: 'image';
|
|
46
46
|
imageUri: string;
|
|
47
47
|
};
|
|
48
|
+
/**
|
|
49
|
+
* AWS caps the aggregate size of a function's environment variables at 4 KB.
|
|
50
|
+
* Check before the API call so we fail with an actionable message (which vars,
|
|
51
|
+
* how far over) instead of a cryptic `InvalidParameterValueException` mid-deploy.
|
|
52
|
+
*/
|
|
53
|
+
export declare function assertEnvWithinLimit(name: string, env: Record<string, string>): void;
|
|
48
54
|
export declare function deployServerlessApp(config: CloudConfig, environment: EnvironmentType, opts?: DeployServerlessOptions): Promise<void>;
|
|
49
55
|
export declare function redeployServerlessApp(config: CloudConfig, environment: EnvironmentType): Promise<void>;
|
|
50
56
|
export declare function rollbackServerlessApp(config: CloudConfig, environment: EnvironmentType): Promise<void>;
|
package/dist/index.js
CHANGED
|
@@ -25845,16 +25845,21 @@ function resolveServerlessRuntime(app) {
|
|
|
25845
25845
|
layerEnvVar: "TSCLOUD_NODE_LAYER_ARN"
|
|
25846
25846
|
};
|
|
25847
25847
|
}
|
|
25848
|
-
function
|
|
25848
|
+
function resolveQueues(app, slug, env) {
|
|
25849
25849
|
if (app.queues === false)
|
|
25850
25850
|
return [];
|
|
25851
25851
|
if (app.queues === undefined || app.queues === true)
|
|
25852
|
-
return [`${slug}-${env}-default`];
|
|
25852
|
+
return [{ name: `${slug}-${env}-default` }];
|
|
25853
25853
|
return app.queues.map((q) => {
|
|
25854
|
-
|
|
25855
|
-
|
|
25854
|
+
if (typeof q === "string")
|
|
25855
|
+
return { name: `${slug}-${env}-${q}` };
|
|
25856
|
+
const [name, concurrency] = Object.entries(q)[0];
|
|
25857
|
+
return { name: `${slug}-${env}-${name}`, concurrency };
|
|
25856
25858
|
});
|
|
25857
25859
|
}
|
|
25860
|
+
function resolveQueueNames(app, slug, env) {
|
|
25861
|
+
return resolveQueues(app, slug, env).map((q) => q.name);
|
|
25862
|
+
}
|
|
25858
25863
|
function composeServerlessAppTemplate(opts) {
|
|
25859
25864
|
const { app, environment, handlers } = opts;
|
|
25860
25865
|
const slug = opts.config.project.slug;
|
|
@@ -25866,8 +25871,12 @@ function composeServerlessAppTemplate(opts) {
|
|
|
25866
25871
|
queue: `${slug}-${environment}-queue`,
|
|
25867
25872
|
cli: `${slug}-${environment}-cli`
|
|
25868
25873
|
};
|
|
25869
|
-
|
|
25874
|
+
if (app.gatewayVersion === 1)
|
|
25875
|
+
throw new Error("serverless app: `gatewayVersion: 1` (REST API) is not supported — ts-cloud uses API Gateway HTTP API (v2). Remove `gatewayVersion` or set it to 2.");
|
|
25876
|
+
const queues = resolveQueues(app, slug, environment);
|
|
25877
|
+
const queueNames = queues.map((q) => q.name);
|
|
25870
25878
|
const hasQueue = queueNames.length > 0;
|
|
25879
|
+
const logRetention = app.logRetention ?? 14;
|
|
25871
25880
|
const imageMode = app.packaging === "image";
|
|
25872
25881
|
const schedulerEnabled = (app.scheduler ?? "on") !== "off";
|
|
25873
25882
|
const cacheEnabled = (app.cache?.driver ?? "dynamodb") === "dynamodb";
|
|
@@ -25983,7 +25992,7 @@ function composeServerlessAppTemplate(opts) {
|
|
|
25983
25992
|
function addFunction(logicalId, name, handler8, mode, memory, timeout, reservedConcurrency, tmp = tmpStorage) {
|
|
25984
25993
|
resources[`${logicalId}LogGroup`] = {
|
|
25985
25994
|
Type: "AWS::Logs::LogGroup",
|
|
25986
|
-
Properties: { LogGroupName: `/aws/lambda/${name}`, RetentionInDays:
|
|
25995
|
+
Properties: { LogGroupName: `/aws/lambda/${name}`, RetentionInDays: logRetention }
|
|
25987
25996
|
};
|
|
25988
25997
|
const codeProps = imageMode ? {
|
|
25989
25998
|
PackageType: "Image",
|
|
@@ -26124,19 +26133,21 @@ function composeServerlessAppTemplate(opts) {
|
|
|
26124
26133
|
MessageRetentionPeriod: 1209600
|
|
26125
26134
|
}
|
|
26126
26135
|
};
|
|
26127
|
-
|
|
26136
|
+
queues.forEach((q, i) => {
|
|
26128
26137
|
const qId = `AppQueue${i}`;
|
|
26138
|
+
const fnTimeout = app.queueTimeout ?? 120;
|
|
26129
26139
|
resources[qId] = {
|
|
26130
26140
|
Type: "AWS::SQS::Queue",
|
|
26131
26141
|
Properties: {
|
|
26132
|
-
QueueName:
|
|
26133
|
-
VisibilityTimeout: Math.
|
|
26142
|
+
QueueName: q.name,
|
|
26143
|
+
VisibilityTimeout: Math.min(43200, fnTimeout * 6),
|
|
26134
26144
|
RedrivePolicy: {
|
|
26135
26145
|
deadLetterTargetArn: Fn2.getAtt("AppQueueDlq", "Arn"),
|
|
26136
26146
|
maxReceiveCount: app.queueTries ?? 3
|
|
26137
26147
|
}
|
|
26138
26148
|
}
|
|
26139
26149
|
};
|
|
26150
|
+
const concurrency = q.concurrency ?? app.queueConcurrency;
|
|
26140
26151
|
resources[`${qId}Mapping`] = {
|
|
26141
26152
|
Type: "AWS::Lambda::EventSourceMapping",
|
|
26142
26153
|
Properties: {
|
|
@@ -26144,10 +26155,10 @@ function composeServerlessAppTemplate(opts) {
|
|
|
26144
26155
|
FunctionName: Fn2.ref("QueueFunction"),
|
|
26145
26156
|
BatchSize: 1,
|
|
26146
26157
|
FunctionResponseTypes: ["ReportBatchItemFailures"],
|
|
26147
|
-
...
|
|
26158
|
+
...concurrency ? { ScalingConfig: { MaximumConcurrency: Math.max(2, concurrency) } } : {}
|
|
26148
26159
|
}
|
|
26149
26160
|
};
|
|
26150
|
-
outputs[`QueueUrl${i}`] = { Description: `Queue URL: ${
|
|
26161
|
+
outputs[`QueueUrl${i}`] = { Description: `Queue URL: ${q.name}`, Value: Fn2.ref(qId) };
|
|
26151
26162
|
});
|
|
26152
26163
|
}
|
|
26153
26164
|
if (schedulerEnabled) {
|
|
@@ -83294,7 +83305,15 @@ async function uploadAssets(s32, bucket, dir, prefix, includeDotfiles = false) {
|
|
|
83294
83305
|
}
|
|
83295
83306
|
return count;
|
|
83296
83307
|
}
|
|
83308
|
+
function assertEnvWithinLimit(name, env2) {
|
|
83309
|
+
const bytes = Object.entries(env2).reduce((n, [k, v]) => n + Buffer.byteLength(`${k}=${v}`, "utf8"), 0);
|
|
83310
|
+
if (bytes > 4096) {
|
|
83311
|
+
const biggest = Object.entries(env2).map(([k, v]) => [k, Buffer.byteLength(`${k}=${v}`, "utf8")]).sort((a, b) => b[1] - a[1]).slice(0, 5).map(([k, n]) => `${k} (${n}B)`).join(", ");
|
|
83312
|
+
throw new Error(`${name}: environment variables total ${bytes}B, over AWS's 4096B limit (${bytes - 4096}B too large). ` + `Largest: ${biggest}. Move large/secret values out of env — store them in Secrets Manager and fetch at cold start.`);
|
|
83313
|
+
}
|
|
83314
|
+
}
|
|
83297
83315
|
async function applyFunction(lambda2, name, env2, code) {
|
|
83316
|
+
assertEnvWithinLimit(name, env2);
|
|
83298
83317
|
await withConflictRetry(() => lambda2.updateFunctionConfiguration({ FunctionName: name, Environment: { Variables: env2 } }));
|
|
83299
83318
|
await lambda2.waitForFunctionActive(name, 120);
|
|
83300
83319
|
const codeParams = code.kind === "image" ? { FunctionName: name, ImageUri: code.imageUri } : { FunctionName: name, S3Bucket: code.bucket, S3Key: code.key };
|
|
@@ -83449,6 +83468,7 @@ async function deployServerlessApp(config6, environment, opts = {}) {
|
|
|
83449
83468
|
code: codeSource,
|
|
83450
83469
|
previousSha: prior?.sha,
|
|
83451
83470
|
previousCode: prior?.code,
|
|
83471
|
+
previousFunctionEnv: prior?.functionEnv,
|
|
83452
83472
|
functionEnv,
|
|
83453
83473
|
functionNames: {
|
|
83454
83474
|
http: composed.functionNames.http,
|
|
@@ -83520,14 +83540,17 @@ async function rollbackServerlessApp(config6, environment) {
|
|
|
83520
83540
|
if (!name)
|
|
83521
83541
|
continue;
|
|
83522
83542
|
step(`Restoring ${mode} (${name})`);
|
|
83523
|
-
|
|
83543
|
+
const env2 = release.previousFunctionEnv?.[mode] ?? release.functionEnv[mode] ?? {};
|
|
83544
|
+
await applyFunction(lambda2, name, env2, release.previousCode);
|
|
83524
83545
|
}
|
|
83525
83546
|
await writeRelease(s32, ctx.artifactBucket, ctx.slug, environment, {
|
|
83526
83547
|
...release,
|
|
83527
83548
|
sha: release.previousSha ?? release.sha,
|
|
83528
83549
|
code: release.previousCode,
|
|
83550
|
+
functionEnv: release.previousFunctionEnv ?? release.functionEnv,
|
|
83529
83551
|
previousSha: undefined,
|
|
83530
83552
|
previousCode: undefined,
|
|
83553
|
+
previousFunctionEnv: undefined,
|
|
83531
83554
|
timestamp: new Date().toISOString()
|
|
83532
83555
|
});
|
|
83533
83556
|
success("Rollback complete");
|
|
@@ -86732,6 +86755,7 @@ export {
|
|
|
86732
86755
|
resolveServerlessArtifactBucketName,
|
|
86733
86756
|
resolveServerlessAppStackName,
|
|
86734
86757
|
resolveRegion,
|
|
86758
|
+
resolveQueues,
|
|
86735
86759
|
resolveQueueNames,
|
|
86736
86760
|
resolveProjectStackName,
|
|
86737
86761
|
resolveObjectStorage,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stacksjs/ts-cloud",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.5.
|
|
4
|
+
"version": "0.5.6",
|
|
5
5
|
"description": "A lightweight, performant infrastructure-as-code library and CLI for deploying both server-based (EC2) and serverless applications.",
|
|
6
6
|
"author": "Chris Breuer <chris@stacksjs.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -89,8 +89,8 @@
|
|
|
89
89
|
"test": "bun test"
|
|
90
90
|
},
|
|
91
91
|
"dependencies": {
|
|
92
|
-
"@ts-cloud/aws-types": "0.5.
|
|
93
|
-
"@ts-cloud/core": "0.5.
|
|
92
|
+
"@ts-cloud/aws-types": "0.5.6",
|
|
93
|
+
"@ts-cloud/core": "0.5.6",
|
|
94
94
|
"@stacksjs/ts-xml": "^0.1.0"
|
|
95
95
|
},
|
|
96
96
|
"devDependencies": {
|