@ts-cloud/core 0.5.5 → 0.5.7
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
|
@@ -45416,16 +45416,21 @@ function resolveServerlessRuntime(app) {
|
|
|
45416
45416
|
}
|
|
45417
45417
|
|
|
45418
45418
|
// src/serverless/composer.ts
|
|
45419
|
-
function
|
|
45419
|
+
function resolveQueues(app, slug, env) {
|
|
45420
45420
|
if (app.queues === false)
|
|
45421
45421
|
return [];
|
|
45422
45422
|
if (app.queues === undefined || app.queues === true)
|
|
45423
|
-
return [`${slug}-${env}-default`];
|
|
45423
|
+
return [{ name: `${slug}-${env}-default` }];
|
|
45424
45424
|
return app.queues.map((q) => {
|
|
45425
|
-
|
|
45426
|
-
|
|
45425
|
+
if (typeof q === "string")
|
|
45426
|
+
return { name: `${slug}-${env}-${q}` };
|
|
45427
|
+
const [name, concurrency] = Object.entries(q)[0];
|
|
45428
|
+
return { name: `${slug}-${env}-${name}`, concurrency };
|
|
45427
45429
|
});
|
|
45428
45430
|
}
|
|
45431
|
+
function resolveQueueNames(app, slug, env) {
|
|
45432
|
+
return resolveQueues(app, slug, env).map((q) => q.name);
|
|
45433
|
+
}
|
|
45429
45434
|
function composeServerlessAppTemplate(opts) {
|
|
45430
45435
|
const { app, environment, handlers } = opts;
|
|
45431
45436
|
const slug = opts.config.project.slug;
|
|
@@ -45437,8 +45442,12 @@ function composeServerlessAppTemplate(opts) {
|
|
|
45437
45442
|
queue: `${slug}-${environment}-queue`,
|
|
45438
45443
|
cli: `${slug}-${environment}-cli`
|
|
45439
45444
|
};
|
|
45440
|
-
|
|
45445
|
+
if (app.gatewayVersion === 1)
|
|
45446
|
+
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.");
|
|
45447
|
+
const queues = resolveQueues(app, slug, environment);
|
|
45448
|
+
const queueNames = queues.map((q) => q.name);
|
|
45441
45449
|
const hasQueue = queueNames.length > 0;
|
|
45450
|
+
const logRetention = app.logRetention ?? 14;
|
|
45442
45451
|
const imageMode = app.packaging === "image";
|
|
45443
45452
|
const schedulerEnabled = (app.scheduler ?? "on") !== "off";
|
|
45444
45453
|
const cacheEnabled = (app.cache?.driver ?? "dynamodb") === "dynamodb";
|
|
@@ -45554,7 +45563,7 @@ function composeServerlessAppTemplate(opts) {
|
|
|
45554
45563
|
function addFunction(logicalId, name, handler8, mode, memory, timeout, reservedConcurrency, tmp = tmpStorage) {
|
|
45555
45564
|
resources[`${logicalId}LogGroup`] = {
|
|
45556
45565
|
Type: "AWS::Logs::LogGroup",
|
|
45557
|
-
Properties: { LogGroupName: `/aws/lambda/${name}`, RetentionInDays:
|
|
45566
|
+
Properties: { LogGroupName: `/aws/lambda/${name}`, RetentionInDays: logRetention }
|
|
45558
45567
|
};
|
|
45559
45568
|
const codeProps = imageMode ? {
|
|
45560
45569
|
PackageType: "Image",
|
|
@@ -45695,19 +45704,21 @@ function composeServerlessAppTemplate(opts) {
|
|
|
45695
45704
|
MessageRetentionPeriod: 1209600
|
|
45696
45705
|
}
|
|
45697
45706
|
};
|
|
45698
|
-
|
|
45707
|
+
queues.forEach((q, i) => {
|
|
45699
45708
|
const qId = `AppQueue${i}`;
|
|
45709
|
+
const fnTimeout = app.queueTimeout ?? 120;
|
|
45700
45710
|
resources[qId] = {
|
|
45701
45711
|
Type: "AWS::SQS::Queue",
|
|
45702
45712
|
Properties: {
|
|
45703
|
-
QueueName:
|
|
45704
|
-
VisibilityTimeout: Math.
|
|
45713
|
+
QueueName: q.name,
|
|
45714
|
+
VisibilityTimeout: Math.min(43200, fnTimeout * 6),
|
|
45705
45715
|
RedrivePolicy: {
|
|
45706
45716
|
deadLetterTargetArn: Fn2.getAtt("AppQueueDlq", "Arn"),
|
|
45707
45717
|
maxReceiveCount: app.queueTries ?? 3
|
|
45708
45718
|
}
|
|
45709
45719
|
}
|
|
45710
45720
|
};
|
|
45721
|
+
const concurrency = q.concurrency ?? app.queueConcurrency;
|
|
45711
45722
|
resources[`${qId}Mapping`] = {
|
|
45712
45723
|
Type: "AWS::Lambda::EventSourceMapping",
|
|
45713
45724
|
Properties: {
|
|
@@ -45715,10 +45726,10 @@ function composeServerlessAppTemplate(opts) {
|
|
|
45715
45726
|
FunctionName: Fn2.ref("QueueFunction"),
|
|
45716
45727
|
BatchSize: 1,
|
|
45717
45728
|
FunctionResponseTypes: ["ReportBatchItemFailures"],
|
|
45718
|
-
...
|
|
45729
|
+
...concurrency ? { ScalingConfig: { MaximumConcurrency: Math.max(2, concurrency) } } : {}
|
|
45719
45730
|
}
|
|
45720
45731
|
};
|
|
45721
|
-
outputs[`QueueUrl${i}`] = { Description: `Queue URL: ${
|
|
45732
|
+
outputs[`QueueUrl${i}`] = { Description: `Queue URL: ${q.name}`, Value: Fn2.ref(qId) };
|
|
45722
45733
|
});
|
|
45723
45734
|
}
|
|
45724
45735
|
if (schedulerEnabled) {
|
|
@@ -46031,7 +46042,10 @@ function composeServerlessAppTemplate(opts) {
|
|
|
46031
46042
|
DatabaseName: "app",
|
|
46032
46043
|
MasterUsername: Fn2.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:username}}"),
|
|
46033
46044
|
MasterUserPassword: Fn2.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:password}}"),
|
|
46034
|
-
ServerlessV2ScalingConfiguration: {
|
|
46045
|
+
ServerlessV2ScalingConfiguration: {
|
|
46046
|
+
MinCapacity: app.database?.minCapacity ?? 0.5,
|
|
46047
|
+
MaxCapacity: app.database?.maxCapacity ?? 4
|
|
46048
|
+
},
|
|
46035
46049
|
DBSubnetGroupName: Fn2.ref("DbSubnetGroup"),
|
|
46036
46050
|
VpcSecurityGroupIds: [Fn2.getAtt("DataSecurityGroup", "GroupId")]
|
|
46037
46051
|
}
|
|
@@ -47111,6 +47125,7 @@ export {
|
|
|
47111
47125
|
resolveServerlessArtifactBucketName,
|
|
47112
47126
|
resolveServerlessAppStackName,
|
|
47113
47127
|
resolveRegion,
|
|
47128
|
+
resolveQueues,
|
|
47114
47129
|
resolveQueueNames,
|
|
47115
47130
|
resolveProjectStackName,
|
|
47116
47131
|
resolveManagementDashboardSite,
|
|
@@ -17,9 +17,6 @@ require $taskRoot . '/vendor/autoload.php';
|
|
|
17
17
|
$app = require $taskRoot . '/bootstrap/app.php';
|
|
18
18
|
$kernel = $app->make(\Illuminate\Contracts\Http\Kernel::class);
|
|
19
19
|
|
|
20
|
-
$maintenance = getenv('MAINTENANCE_MODE') === '1';
|
|
21
|
-
$bypassSecret = getenv('MAINTENANCE_BYPASS_SECRET') ?: '';
|
|
22
|
-
|
|
23
20
|
while (true) {
|
|
24
21
|
$ctx = nextInvocation($runtimeApi);
|
|
25
22
|
if ($ctx === null) {
|
|
@@ -27,6 +24,11 @@ while (true) {
|
|
|
27
24
|
}
|
|
28
25
|
[$requestId, $event] = $ctx;
|
|
29
26
|
|
|
27
|
+
// Read maintenance state per-invocation so `cloud down`/`up` reaches warm
|
|
28
|
+
// containers (env is flipped via updateFunctionConfiguration).
|
|
29
|
+
$maintenance = getenv('MAINTENANCE_MODE') === '1';
|
|
30
|
+
$bypassSecret = getenv('MAINTENANCE_BYPASS_SECRET') ?: '';
|
|
31
|
+
|
|
30
32
|
try {
|
|
31
33
|
$response = handle($event, $kernel, $maintenance, $bypassSecret);
|
|
32
34
|
postResponse($runtimeApi, $requestId, $response);
|
|
@@ -24,9 +24,6 @@ for ($i = 0; $i < 50 && !file_exists($socketPath); $i++) {
|
|
|
24
24
|
usleep(100000); // 100ms
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
$maintenance = getenv('MAINTENANCE_MODE') === '1';
|
|
28
|
-
$bypassSecret = getenv('MAINTENANCE_BYPASS_SECRET') ?: '';
|
|
29
|
-
|
|
30
27
|
while (true) {
|
|
31
28
|
// 1. Get the next invocation.
|
|
32
29
|
$ctx = nextInvocation($runtimeApi);
|
|
@@ -35,6 +32,12 @@ while (true) {
|
|
|
35
32
|
}
|
|
36
33
|
[$requestId, $event] = $ctx;
|
|
37
34
|
|
|
35
|
+
// Read maintenance state per-invocation: `cloud down`/`up` flips the env via
|
|
36
|
+
// updateFunctionConfiguration, but warm containers would keep a cold-start
|
|
37
|
+
// value if cached outside the loop (the Node adapter reads it per-request too).
|
|
38
|
+
$maintenance = getenv('MAINTENANCE_MODE') === '1';
|
|
39
|
+
$bypassSecret = getenv('MAINTENANCE_BYPASS_SECRET') ?: '';
|
|
40
|
+
|
|
38
41
|
try {
|
|
39
42
|
$response = handle($event, $fpm, $docRoot, $maintenance, $bypassSecret);
|
|
40
43
|
postResponse($runtimeApi, $requestId, $response);
|
|
@@ -38,6 +38,17 @@ export interface ComposedTemplate {
|
|
|
38
38
|
/** Count of resources by CloudFormation type (for deploy summaries). */
|
|
39
39
|
resourceSummary: Record<string, number>;
|
|
40
40
|
}
|
|
41
|
-
/**
|
|
41
|
+
/** A resolved queue: its full name plus an optional per-queue concurrency cap. */
|
|
42
|
+
export interface ResolvedQueue {
|
|
43
|
+
name: string;
|
|
44
|
+
/** Per-queue max concurrency (`queues: [{ emails: 10 }]`), if specified. */
|
|
45
|
+
concurrency?: number;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Resolve the SQS queues from the manifest, preserving any per-queue concurrency
|
|
49
|
+
* (`queues: [{ emails: 10 }]` → `{ name: '…-emails', concurrency: 10 }`).
|
|
50
|
+
*/
|
|
51
|
+
export declare function resolveQueues(app: ServerlessAppConfig, slug: string, env: EnvironmentType): ResolvedQueue[];
|
|
52
|
+
/** Resolve just the SQS queue names from the manifest. */
|
|
42
53
|
export declare function resolveQueueNames(app: ServerlessAppConfig, slug: string, env: EnvironmentType): string[];
|
|
43
54
|
export declare function composeServerlessAppTemplate(opts: ComposeOptions): ComposedTemplate;
|
package/dist/types.d.ts
CHANGED
|
@@ -1579,13 +1579,19 @@ export interface ServerlessAppConfig {
|
|
|
1579
1579
|
timeout?: number;
|
|
1580
1580
|
/** Reserved concurrency for the HTTP function. */
|
|
1581
1581
|
concurrency?: number;
|
|
1582
|
-
/**
|
|
1582
|
+
/**
|
|
1583
|
+
* API Gateway version. Only `2` (HTTP API — cheaper, faster) is supported;
|
|
1584
|
+
* `1` (REST API) throws at compose time. @default 2
|
|
1585
|
+
*/
|
|
1583
1586
|
gatewayVersion?: 1 | 2;
|
|
1584
1587
|
/**
|
|
1585
|
-
* Keep-warm count.
|
|
1586
|
-
*
|
|
1588
|
+
* Keep-warm count. Drives a scheduled EventBridge warmer rule that pings the
|
|
1589
|
+
* HTTP function every few minutes (the runtime short-circuits warmer pings).
|
|
1590
|
+
* 0/undefined disables warming.
|
|
1587
1591
|
*/
|
|
1588
1592
|
warm?: number;
|
|
1593
|
+
/** CloudWatch log retention (days) for all function log groups. @default 14 */
|
|
1594
|
+
logRetention?: number;
|
|
1589
1595
|
/** CLI function memory in MB. @default 1024 */
|
|
1590
1596
|
cliMemory?: number;
|
|
1591
1597
|
/** CLI command timeout in seconds (allow room for migrations). @default 900 */
|
|
@@ -1653,6 +1659,10 @@ export interface ServerlessAppConfig {
|
|
|
1653
1659
|
database?: {
|
|
1654
1660
|
connection?: 'rds-proxy' | 'aurora-serverless' | 'rds';
|
|
1655
1661
|
cluster?: string;
|
|
1662
|
+
/** Aurora Serverless v2 minimum capacity (ACUs). @default 0.5 */
|
|
1663
|
+
minCapacity?: number;
|
|
1664
|
+
/** Aurora Serverless v2 maximum capacity (ACUs). @default 4 */
|
|
1665
|
+
maxCapacity?: number;
|
|
1656
1666
|
};
|
|
1657
1667
|
/** Cache attachment. DynamoDB cache table is the zero-NAT default. */
|
|
1658
1668
|
cache?: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ts-cloud/core",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Core CloudFormation generation library for ts-cloud",
|
|
6
6
|
"author": "Chris Breuer <chris@stacksjs.com>",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"typecheck": "tsc --noEmit"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@ts-cloud/aws-types": "0.5.
|
|
34
|
+
"@ts-cloud/aws-types": "0.5.7"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"typescript": "^5.9.3"
|