@stacksjs/ts-cloud 0.5.8 → 0.5.9

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/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: Fn2.getAtt("HttpFunction", "Arn"),
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: Fn2.ref("HttpFunction"),
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: Fn2.ref("QueueFunction"),
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: Fn2.getAtt("CliFunction", "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: Fn2.ref("CliFunction"),
26203
+ FunctionName: invokeName("CliFunction"),
26182
26204
  Action: "lambda:InvokeFunction",
26183
26205
  Principal: "events.amazonaws.com",
26184
26206
  SourceArn: Fn2.getAtt("SchedulerRule", "Arn")
@@ -83439,6 +83461,14 @@ async function applyFunction(lambda2, name, env2, code) {
83439
83461
  await withConflictRetry(() => lambda2.updateFunctionCode(codeParams));
83440
83462
  await lambda2.waitForFunctionActive(name, 120);
83441
83463
  }
83464
+ async function publishAndFlip(lambda2, name) {
83465
+ const published = await withConflictRetry(() => lambda2.publishVersion({ FunctionName: name }));
83466
+ const version2 = published.Version;
83467
+ if (!version2)
83468
+ throw new Error(`publishVersion returned no version for ${name}`);
83469
+ await withConflictRetry(() => lambda2.updateAlias({ FunctionName: name, Name: "live", FunctionVersion: version2 }));
83470
+ return version2;
83471
+ }
83442
83472
  async function deployServerlessApp(config6, environment, opts = {}) {
83443
83473
  const ctx = resolveContext(config6, environment);
83444
83474
  const { app, slug, region, stackName, artifactBucket } = ctx;
@@ -83582,12 +83612,22 @@ async function deployServerlessApp(config6, environment, opts = {}) {
83582
83612
  functionEnv.queue = buildFunctionEnv(app, ctx, environment, "queue", secrets, assetUrl, primaryQueue, infraEnv);
83583
83613
  await applyFunction(lambda2, composed.functionNames.queue, functionEnv.queue, codeSource);
83584
83614
  }
83615
+ const usesProvisionedConcurrency = (app.provisionedConcurrency ?? 0) > 0;
83616
+ const functionVersions = {};
83617
+ if (usesProvisionedConcurrency) {
83618
+ step("Publishing versions + flipping live alias");
83619
+ functionVersions.http = await publishAndFlip(lambda2, composed.functionNames.http);
83620
+ functionVersions.cli = await publishAndFlip(lambda2, composed.functionNames.cli);
83621
+ if (composed.queueNames.length)
83622
+ functionVersions.queue = await publishAndFlip(lambda2, composed.functionNames.queue);
83623
+ }
83585
83624
  await writeRelease(s32, artifactBucket, slug, environment, {
83586
83625
  sha: artifactSha,
83587
83626
  code: codeSource,
83588
83627
  previousSha: prior?.sha,
83589
83628
  previousCode: prior?.code,
83590
83629
  previousFunctionEnv: prior?.functionEnv,
83630
+ ...usesProvisionedConcurrency ? { functionVersions, previousFunctionVersions: prior?.functionVersions } : {},
83591
83631
  functionEnv,
83592
83632
  functionNames: {
83593
83633
  http: composed.functionNames.http,
@@ -83646,6 +83686,9 @@ async function redeployServerlessApp(config6, environment) {
83646
83686
  continue;
83647
83687
  step(`Re-activating ${mode} (${name})`);
83648
83688
  await applyFunction(lambda2, name, release.functionEnv[mode] ?? {}, release.code);
83689
+ const version2 = release.functionVersions?.[mode];
83690
+ if (version2)
83691
+ await withConflictRetry(() => lambda2.updateAlias({ FunctionName: name, Name: "live", FunctionVersion: version2 }));
83649
83692
  }
83650
83693
  success("Redeploy complete");
83651
83694
  }
@@ -83663,15 +83706,20 @@ async function rollbackServerlessApp(config6, environment) {
83663
83706
  step(`Restoring ${mode} (${name})`);
83664
83707
  const env2 = release.previousFunctionEnv?.[mode] ?? release.functionEnv[mode] ?? {};
83665
83708
  await applyFunction(lambda2, name, env2, release.previousCode);
83709
+ const prevVersion = release.previousFunctionVersions?.[mode];
83710
+ if (prevVersion)
83711
+ await withConflictRetry(() => lambda2.updateAlias({ FunctionName: name, Name: "live", FunctionVersion: prevVersion }));
83666
83712
  }
83667
83713
  await writeRelease(s32, ctx.artifactBucket, ctx.slug, environment, {
83668
83714
  ...release,
83669
83715
  sha: release.previousSha ?? release.sha,
83670
83716
  code: release.previousCode,
83671
83717
  functionEnv: release.previousFunctionEnv ?? release.functionEnv,
83718
+ functionVersions: release.previousFunctionVersions ?? release.functionVersions,
83672
83719
  previousSha: undefined,
83673
83720
  previousCode: undefined,
83674
83721
  previousFunctionEnv: undefined,
83722
+ previousFunctionVersions: undefined,
83675
83723
  timestamp: new Date().toISOString()
83676
83724
  });
83677
83725
  success("Rollback complete");
@@ -83688,6 +83736,10 @@ async function setMaintenance(config6, environment, enabled, bypassSecret) {
83688
83736
  if (!enabled)
83689
83737
  delete env2.MAINTENANCE_BYPASS_SECRET;
83690
83738
  await withConflictRetry(() => lambda2.updateFunctionConfiguration({ FunctionName: httpName, Environment: { Variables: env2 } }));
83739
+ if ((ctx.app.provisionedConcurrency ?? 0) > 0) {
83740
+ await lambda2.waitForFunctionActive(httpName, 120);
83741
+ await publishAndFlip(lambda2, httpName);
83742
+ }
83691
83743
  success(enabled ? "Application is now in maintenance mode (503)" : "Application is live");
83692
83744
  }
83693
83745
  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.8",
4
+ "version": "0.5.9",
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.8",
93
- "@ts-cloud/core": "0.5.8",
92
+ "@ts-cloud/aws-types": "0.5.9",
93
+ "@ts-cloud/core": "0.5.9",
94
94
  "@stacksjs/ts-xml": "^0.1.0"
95
95
  },
96
96
  "devDependencies": {