@stacksjs/ts-cloud 0.5.8 → 0.5.10
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/aws/lambda.d.ts +12 -0
- package/dist/bin/cli.js +551 -551
- package/dist/deploy/serverless-app.d.ts +29 -0
- package/dist/index.js +86 -5
- package/package.json +3 -3
|
@@ -99,6 +99,35 @@ export declare function getCommandRecord(config: CloudConfig, environment: Envir
|
|
|
99
99
|
* whitespace argument parsing.
|
|
100
100
|
*/
|
|
101
101
|
export declare function runDbQuery(config: CloudConfig, environment: EnvironmentType, sql: string): Promise<string>;
|
|
102
|
+
export interface ServerlessFunctionInfo {
|
|
103
|
+
mode: 'http' | 'queue' | 'cli';
|
|
104
|
+
name: string;
|
|
105
|
+
/** `live` alias version when provisioned concurrency is on, else '$LATEST'. */
|
|
106
|
+
version: string;
|
|
107
|
+
provisioned?: {
|
|
108
|
+
status: string;
|
|
109
|
+
allocated: number;
|
|
110
|
+
requested: number;
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
export interface ServerlessInfo {
|
|
114
|
+
slug: string;
|
|
115
|
+
environment: string;
|
|
116
|
+
region: string;
|
|
117
|
+
stackStatus: string;
|
|
118
|
+
endpoint?: string;
|
|
119
|
+
assetUrl?: string;
|
|
120
|
+
scheduler: 'on' | 'off' | 'sub-minute';
|
|
121
|
+
queues: string[];
|
|
122
|
+
provisionedConcurrency: number;
|
|
123
|
+
functions: ServerlessFunctionInfo[];
|
|
124
|
+
lastRelease?: {
|
|
125
|
+
sha: string;
|
|
126
|
+
timestamp: string;
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/** Gather an operational summary of a deployed serverless app. */
|
|
130
|
+
export declare function serverlessInfo(config: CloudConfig, environment: EnvironmentType): Promise<ServerlessInfo>;
|
|
102
131
|
/** Rescale the serverless Aurora cluster's min/max ACU capacity. */
|
|
103
132
|
export declare function scaleServerlessDatabase(config: CloudConfig, environment: EnvironmentType, minCapacity: number, maxCapacity: number): Promise<void>;
|
|
104
133
|
/**
|
package/dist/index.js
CHANGED
|
@@ -26026,6 +26026,28 @@ function composeServerlessAppTemplate(opts) {
|
|
|
26026
26026
|
addFunction("CliFunction", functionNames.cli, handlers.cli, "cli", app.cliMemory ?? 1024, app.cliTimeout ?? 900, undefined, app.cliTmpStorage ?? tmpStorage);
|
|
26027
26027
|
if (hasQueue)
|
|
26028
26028
|
addFunction("QueueFunction", functionNames.queue, handlers.queue, "queue", app.queueMemory ?? 1024, app.queueTimeout ?? 120, undefined, app.queueTmpStorage ?? tmpStorage);
|
|
26029
|
+
const pc = (app.provisionedConcurrency ?? 0) > 0 ? app.provisionedConcurrency : 0;
|
|
26030
|
+
const fnLogicalIds = ["HttpFunction", "CliFunction", ...hasQueue ? ["QueueFunction"] : []];
|
|
26031
|
+
if (pc) {
|
|
26032
|
+
for (const L of fnLogicalIds) {
|
|
26033
|
+
resources[`${L}Version`] = {
|
|
26034
|
+
Type: "AWS::Lambda::Version",
|
|
26035
|
+
DeletionPolicy: "Retain",
|
|
26036
|
+
Properties: { FunctionName: Fn2.ref(L) }
|
|
26037
|
+
};
|
|
26038
|
+
resources[`${L}Alias`] = {
|
|
26039
|
+
Type: "AWS::Lambda::Alias",
|
|
26040
|
+
Properties: {
|
|
26041
|
+
FunctionName: Fn2.ref(L),
|
|
26042
|
+
Name: "live",
|
|
26043
|
+
FunctionVersion: Fn2.getAtt(`${L}Version`, "Version"),
|
|
26044
|
+
ProvisionedConcurrencyConfig: { ProvisionedConcurrentExecutions: pc }
|
|
26045
|
+
}
|
|
26046
|
+
};
|
|
26047
|
+
}
|
|
26048
|
+
}
|
|
26049
|
+
const invokeArn = (L) => pc ? Fn2.ref(`${L}Alias`) : Fn2.getAtt(L, "Arn");
|
|
26050
|
+
const invokeName = (L) => pc ? Fn2.ref(`${L}Alias`) : Fn2.ref(L);
|
|
26029
26051
|
resources.HttpApi = {
|
|
26030
26052
|
Type: "AWS::ApiGatewayV2::Api",
|
|
26031
26053
|
Properties: {
|
|
@@ -26038,7 +26060,7 @@ function composeServerlessAppTemplate(opts) {
|
|
|
26038
26060
|
Properties: {
|
|
26039
26061
|
ApiId: Fn2.ref("HttpApi"),
|
|
26040
26062
|
IntegrationType: "AWS_PROXY",
|
|
26041
|
-
IntegrationUri:
|
|
26063
|
+
IntegrationUri: invokeArn("HttpFunction"),
|
|
26042
26064
|
PayloadFormatVersion: "2.0"
|
|
26043
26065
|
}
|
|
26044
26066
|
};
|
|
@@ -26061,7 +26083,7 @@ function composeServerlessAppTemplate(opts) {
|
|
|
26061
26083
|
resources.HttpPermission = {
|
|
26062
26084
|
Type: "AWS::Lambda::Permission",
|
|
26063
26085
|
Properties: {
|
|
26064
|
-
FunctionName:
|
|
26086
|
+
FunctionName: invokeName("HttpFunction"),
|
|
26065
26087
|
Action: "lambda:InvokeFunction",
|
|
26066
26088
|
Principal: "apigateway.amazonaws.com",
|
|
26067
26089
|
SourceArn: Fn2.sub("arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${HttpApi}/*/*")
|
|
@@ -26152,7 +26174,7 @@ function composeServerlessAppTemplate(opts) {
|
|
|
26152
26174
|
Type: "AWS::Lambda::EventSourceMapping",
|
|
26153
26175
|
Properties: {
|
|
26154
26176
|
EventSourceArn: Fn2.getAtt(qId, "Arn"),
|
|
26155
|
-
FunctionName:
|
|
26177
|
+
FunctionName: invokeName("QueueFunction"),
|
|
26156
26178
|
BatchSize: 1,
|
|
26157
26179
|
FunctionResponseTypes: ["ReportBatchItemFailures"],
|
|
26158
26180
|
...concurrency ? { ScalingConfig: { MaximumConcurrency: Math.max(2, concurrency) } } : {}
|
|
@@ -26170,7 +26192,7 @@ function composeServerlessAppTemplate(opts) {
|
|
|
26170
26192
|
State: "ENABLED",
|
|
26171
26193
|
Targets: [{
|
|
26172
26194
|
Id: "cli",
|
|
26173
|
-
Arn:
|
|
26195
|
+
Arn: invokeArn("CliFunction"),
|
|
26174
26196
|
Input: JSON.stringify({ command: "schedule:run" })
|
|
26175
26197
|
}]
|
|
26176
26198
|
}
|
|
@@ -26178,7 +26200,7 @@ function composeServerlessAppTemplate(opts) {
|
|
|
26178
26200
|
resources.SchedulerPermission = {
|
|
26179
26201
|
Type: "AWS::Lambda::Permission",
|
|
26180
26202
|
Properties: {
|
|
26181
|
-
FunctionName:
|
|
26203
|
+
FunctionName: invokeName("CliFunction"),
|
|
26182
26204
|
Action: "lambda:InvokeFunction",
|
|
26183
26205
|
Principal: "events.amazonaws.com",
|
|
26184
26206
|
SourceArn: Fn2.getAtt("SchedulerRule", "Arn")
|
|
@@ -74242,6 +74264,35 @@ class LambdaClient {
|
|
|
74242
74264
|
body: JSON.stringify(rest)
|
|
74243
74265
|
});
|
|
74244
74266
|
}
|
|
74267
|
+
async getAlias(functionName, name) {
|
|
74268
|
+
try {
|
|
74269
|
+
return await this.client.request({
|
|
74270
|
+
service: "lambda",
|
|
74271
|
+
region: this.region,
|
|
74272
|
+
method: "GET",
|
|
74273
|
+
path: `/2015-03-31/functions/${encodeURIComponent(functionName)}/aliases/${encodeURIComponent(name)}`
|
|
74274
|
+
});
|
|
74275
|
+
} catch (err) {
|
|
74276
|
+
if (/ResourceNotFound/i.test(String(err?.message)))
|
|
74277
|
+
return null;
|
|
74278
|
+
throw err;
|
|
74279
|
+
}
|
|
74280
|
+
}
|
|
74281
|
+
async getProvisionedConcurrencyConfig(functionName, qualifier) {
|
|
74282
|
+
try {
|
|
74283
|
+
return await this.client.request({
|
|
74284
|
+
service: "lambda",
|
|
74285
|
+
region: this.region,
|
|
74286
|
+
method: "GET",
|
|
74287
|
+
path: `/2019-09-30/functions/${encodeURIComponent(functionName)}/provisioned-concurrency`,
|
|
74288
|
+
queryParams: { Qualifier: qualifier }
|
|
74289
|
+
});
|
|
74290
|
+
} catch (err) {
|
|
74291
|
+
if (/ProvisionedConcurrencyConfigNotFound|ResourceNotFound/i.test(String(err?.message)))
|
|
74292
|
+
return null;
|
|
74293
|
+
throw err;
|
|
74294
|
+
}
|
|
74295
|
+
}
|
|
74245
74296
|
async putProvisionedConcurrencyConfig(params) {
|
|
74246
74297
|
const { FunctionName, Qualifier, ProvisionedConcurrentExecutions } = params;
|
|
74247
74298
|
return this.client.request({
|
|
@@ -83439,6 +83490,14 @@ async function applyFunction(lambda2, name, env2, code) {
|
|
|
83439
83490
|
await withConflictRetry(() => lambda2.updateFunctionCode(codeParams));
|
|
83440
83491
|
await lambda2.waitForFunctionActive(name, 120);
|
|
83441
83492
|
}
|
|
83493
|
+
async function publishAndFlip(lambda2, name) {
|
|
83494
|
+
const published = await withConflictRetry(() => lambda2.publishVersion({ FunctionName: name }));
|
|
83495
|
+
const version2 = published.Version;
|
|
83496
|
+
if (!version2)
|
|
83497
|
+
throw new Error(`publishVersion returned no version for ${name}`);
|
|
83498
|
+
await withConflictRetry(() => lambda2.updateAlias({ FunctionName: name, Name: "live", FunctionVersion: version2 }));
|
|
83499
|
+
return version2;
|
|
83500
|
+
}
|
|
83442
83501
|
async function deployServerlessApp(config6, environment, opts = {}) {
|
|
83443
83502
|
const ctx = resolveContext(config6, environment);
|
|
83444
83503
|
const { app, slug, region, stackName, artifactBucket } = ctx;
|
|
@@ -83582,12 +83641,22 @@ async function deployServerlessApp(config6, environment, opts = {}) {
|
|
|
83582
83641
|
functionEnv.queue = buildFunctionEnv(app, ctx, environment, "queue", secrets, assetUrl, primaryQueue, infraEnv);
|
|
83583
83642
|
await applyFunction(lambda2, composed.functionNames.queue, functionEnv.queue, codeSource);
|
|
83584
83643
|
}
|
|
83644
|
+
const usesProvisionedConcurrency = (app.provisionedConcurrency ?? 0) > 0;
|
|
83645
|
+
const functionVersions = {};
|
|
83646
|
+
if (usesProvisionedConcurrency) {
|
|
83647
|
+
step("Publishing versions + flipping live alias");
|
|
83648
|
+
functionVersions.http = await publishAndFlip(lambda2, composed.functionNames.http);
|
|
83649
|
+
functionVersions.cli = await publishAndFlip(lambda2, composed.functionNames.cli);
|
|
83650
|
+
if (composed.queueNames.length)
|
|
83651
|
+
functionVersions.queue = await publishAndFlip(lambda2, composed.functionNames.queue);
|
|
83652
|
+
}
|
|
83585
83653
|
await writeRelease(s32, artifactBucket, slug, environment, {
|
|
83586
83654
|
sha: artifactSha,
|
|
83587
83655
|
code: codeSource,
|
|
83588
83656
|
previousSha: prior?.sha,
|
|
83589
83657
|
previousCode: prior?.code,
|
|
83590
83658
|
previousFunctionEnv: prior?.functionEnv,
|
|
83659
|
+
...usesProvisionedConcurrency ? { functionVersions, previousFunctionVersions: prior?.functionVersions } : {},
|
|
83591
83660
|
functionEnv,
|
|
83592
83661
|
functionNames: {
|
|
83593
83662
|
http: composed.functionNames.http,
|
|
@@ -83646,6 +83715,9 @@ async function redeployServerlessApp(config6, environment) {
|
|
|
83646
83715
|
continue;
|
|
83647
83716
|
step(`Re-activating ${mode} (${name})`);
|
|
83648
83717
|
await applyFunction(lambda2, name, release.functionEnv[mode] ?? {}, release.code);
|
|
83718
|
+
const version2 = release.functionVersions?.[mode];
|
|
83719
|
+
if (version2)
|
|
83720
|
+
await withConflictRetry(() => lambda2.updateAlias({ FunctionName: name, Name: "live", FunctionVersion: version2 }));
|
|
83649
83721
|
}
|
|
83650
83722
|
success("Redeploy complete");
|
|
83651
83723
|
}
|
|
@@ -83663,15 +83735,20 @@ async function rollbackServerlessApp(config6, environment) {
|
|
|
83663
83735
|
step(`Restoring ${mode} (${name})`);
|
|
83664
83736
|
const env2 = release.previousFunctionEnv?.[mode] ?? release.functionEnv[mode] ?? {};
|
|
83665
83737
|
await applyFunction(lambda2, name, env2, release.previousCode);
|
|
83738
|
+
const prevVersion = release.previousFunctionVersions?.[mode];
|
|
83739
|
+
if (prevVersion)
|
|
83740
|
+
await withConflictRetry(() => lambda2.updateAlias({ FunctionName: name, Name: "live", FunctionVersion: prevVersion }));
|
|
83666
83741
|
}
|
|
83667
83742
|
await writeRelease(s32, ctx.artifactBucket, ctx.slug, environment, {
|
|
83668
83743
|
...release,
|
|
83669
83744
|
sha: release.previousSha ?? release.sha,
|
|
83670
83745
|
code: release.previousCode,
|
|
83671
83746
|
functionEnv: release.previousFunctionEnv ?? release.functionEnv,
|
|
83747
|
+
functionVersions: release.previousFunctionVersions ?? release.functionVersions,
|
|
83672
83748
|
previousSha: undefined,
|
|
83673
83749
|
previousCode: undefined,
|
|
83674
83750
|
previousFunctionEnv: undefined,
|
|
83751
|
+
previousFunctionVersions: undefined,
|
|
83675
83752
|
timestamp: new Date().toISOString()
|
|
83676
83753
|
});
|
|
83677
83754
|
success("Rollback complete");
|
|
@@ -83688,6 +83765,10 @@ async function setMaintenance(config6, environment, enabled, bypassSecret) {
|
|
|
83688
83765
|
if (!enabled)
|
|
83689
83766
|
delete env2.MAINTENANCE_BYPASS_SECRET;
|
|
83690
83767
|
await withConflictRetry(() => lambda2.updateFunctionConfiguration({ FunctionName: httpName, Environment: { Variables: env2 } }));
|
|
83768
|
+
if ((ctx.app.provisionedConcurrency ?? 0) > 0) {
|
|
83769
|
+
await lambda2.waitForFunctionActive(httpName, 120);
|
|
83770
|
+
await publishAndFlip(lambda2, httpName);
|
|
83771
|
+
}
|
|
83691
83772
|
success(enabled ? "Application is now in maintenance mode (503)" : "Application is live");
|
|
83692
83773
|
}
|
|
83693
83774
|
async function runRemoteCommand(config6, environment, command) {
|
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.10",
|
|
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.10",
|
|
93
|
+
"@ts-cloud/core": "0.5.10",
|
|
94
94
|
"@stacksjs/ts-xml": "^0.1.0"
|
|
95
95
|
},
|
|
96
96
|
"devDependencies": {
|