@hyperdrive.bot/cli 1.0.12 → 1.0.16
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/README.md +1495 -474
- package/dist/commands/deploy.d.ts +18 -0
- package/dist/commands/deploy.js +239 -0
- package/dist/commands/deployment/create.js +10 -2
- package/dist/commands/domain/{switch.d.ts → set-production.d.ts} +1 -1
- package/dist/commands/domain/set-production.js +27 -0
- package/dist/commands/git/list-open-prs.d.ts +12 -0
- package/dist/commands/git/list-open-prs.js +87 -0
- package/dist/commands/hook/add.d.ts +22 -0
- package/dist/commands/hook/add.js +299 -0
- package/dist/commands/hook/list.d.ts +11 -0
- package/dist/commands/hook/list.js +111 -0
- package/dist/commands/hook/logs.d.ts +13 -0
- package/dist/commands/hook/logs.js +124 -0
- package/dist/commands/hook/remove.d.ts +12 -0
- package/dist/commands/hook/remove.js +115 -0
- package/dist/commands/hook/toggle.d.ts +12 -0
- package/dist/commands/hook/toggle.js +125 -0
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.js +49 -9
- package/dist/commands/module/bindings.d.ts +14 -0
- package/dist/commands/module/bindings.js +125 -0
- package/dist/commands/module/create.d.ts +3 -0
- package/dist/commands/module/create.js +156 -78
- package/dist/commands/module/list.d.ts +1 -0
- package/dist/commands/module/list.js +22 -1
- package/dist/commands/module/sync.d.ts +29 -0
- package/dist/commands/module/sync.js +409 -0
- package/dist/commands/module/unlink.d.ts +11 -0
- package/dist/commands/module/unlink.js +77 -0
- package/dist/commands/module/update.d.ts +10 -0
- package/dist/commands/module/update.js +168 -5
- package/dist/commands/network/discover.d.ts +12 -0
- package/dist/commands/network/discover.js +210 -0
- package/dist/commands/network/get.d.ts +13 -0
- package/dist/commands/network/get.js +90 -0
- package/dist/commands/{auth/logout.d.ts → network/list.d.ts} +2 -9
- package/dist/commands/network/list.js +71 -0
- package/dist/commands/network/register.d.ts +16 -0
- package/dist/commands/network/register.js +144 -0
- package/dist/commands/parameter/sync.d.ts +13 -0
- package/dist/commands/parameter/sync.js +69 -1
- package/dist/commands/project/sync.d.ts +5 -11
- package/dist/commands/project/sync.js +12 -381
- package/dist/commands/seed.d.ts +93 -0
- package/dist/commands/seed.js +324 -0
- package/dist/commands/service/backup.d.ts +17 -0
- package/dist/commands/service/backup.js +156 -0
- package/dist/commands/service/backups.d.ts +14 -0
- package/dist/commands/service/backups.js +110 -0
- package/dist/commands/service/bind.d.ts +16 -0
- package/dist/commands/service/bind.js +106 -0
- package/dist/commands/service/bindings.d.ts +13 -0
- package/dist/commands/service/bindings.js +78 -0
- package/dist/commands/service/clone.d.ts +19 -0
- package/dist/commands/service/clone.js +153 -0
- package/dist/commands/service/create.d.ts +16 -0
- package/dist/commands/service/create.js +212 -0
- package/dist/commands/service/get.d.ts +13 -0
- package/dist/commands/service/get.js +97 -0
- package/dist/commands/service/list.d.ts +12 -0
- package/dist/commands/service/list.js +86 -0
- package/dist/commands/service/register.d.ts +21 -0
- package/dist/commands/service/register.js +215 -0
- package/dist/commands/service/restore.d.ts +19 -0
- package/dist/commands/service/restore.js +158 -0
- package/dist/commands/service/seed.d.ts +17 -0
- package/dist/commands/service/seed.js +173 -0
- package/dist/commands/service/templates.d.ts +10 -0
- package/dist/commands/service/templates.js +66 -0
- package/dist/commands/service/unbind.d.ts +15 -0
- package/dist/commands/service/unbind.js +74 -0
- package/dist/commands/stage/create.d.ts +23 -0
- package/dist/commands/stage/create.js +145 -6
- package/dist/commands/stage/delete.d.ts +11 -0
- package/dist/commands/stage/delete.js +85 -0
- package/dist/commands/stage/deploy.d.ts +34 -0
- package/dist/commands/stage/deploy.js +294 -0
- package/dist/commands/stage/ensure-branches.d.ts +23 -0
- package/dist/commands/stage/ensure-branches.js +101 -0
- package/dist/commands/stage/list.js +4 -0
- package/dist/commands/stage/status.d.ts +14 -0
- package/dist/commands/stage/status.js +100 -0
- package/dist/commands/{jira → tracker}/connect.js +32 -23
- package/dist/commands/tracker/hook/add.d.ts +25 -0
- package/dist/commands/tracker/hook/add.js +284 -0
- package/dist/commands/{jira → tracker}/hook/list.js +20 -11
- package/dist/commands/{jira/hook/add.d.ts → tracker/hook/logs.d.ts} +2 -3
- package/dist/commands/tracker/hook/logs.js +126 -0
- package/dist/commands/{jira → tracker}/hook/remove.js +9 -8
- package/dist/commands/{jira → tracker}/hook/toggle.js +14 -12
- package/dist/commands/tracker/project/init.d.ts +17 -0
- package/dist/commands/tracker/project/init.js +178 -0
- package/dist/commands/tracker/project/link-module.d.ts +17 -0
- package/dist/commands/tracker/project/link-module.js +287 -0
- package/dist/commands/tracker/project/list-modules.d.ts +11 -0
- package/dist/commands/tracker/project/list-modules.js +117 -0
- package/dist/commands/tracker/project/list.d.ts +10 -0
- package/dist/commands/tracker/project/list.js +90 -0
- package/dist/commands/tracker/project/status.d.ts +13 -0
- package/dist/commands/tracker/project/status.js +168 -0
- package/dist/commands/tracker/project/unlink-module.d.ts +13 -0
- package/dist/commands/tracker/project/unlink-module.js +251 -0
- package/dist/commands/{jira → tracker}/status.js +3 -3
- package/dist/lib/ensure-branches.d.ts +53 -0
- package/dist/lib/ensure-branches.js +149 -0
- package/dist/lib/git-providers/github.d.ts +16 -0
- package/dist/lib/git-providers/github.js +157 -0
- package/dist/lib/git-providers/gitlab.d.ts +16 -0
- package/dist/lib/git-providers/gitlab.js +148 -0
- package/dist/lib/git-providers/index.d.ts +67 -0
- package/dist/lib/git-providers/index.js +39 -0
- package/dist/lib/lambda-warmer.d.ts +106 -0
- package/dist/lib/lambda-warmer.js +189 -0
- package/dist/services/hyperdrive-sigv4.d.ts +360 -5
- package/dist/services/hyperdrive-sigv4.js +192 -24
- package/dist/utils/hook-flow.d.ts +60 -3
- package/dist/utils/hook-flow.js +437 -2
- package/dist/utils/hook-normalize.d.ts +6 -0
- package/dist/utils/hook-normalize.js +33 -0
- package/dist/utils/lifecycle-poller.d.ts +32 -0
- package/dist/utils/lifecycle-poller.js +72 -0
- package/dist/utils/retry.d.ts +43 -0
- package/dist/utils/retry.js +88 -0
- package/dist/utils/summary-display.js +1 -1
- package/dist/utils/tracker-project-flow.d.ts +84 -0
- package/dist/utils/tracker-project-flow.js +564 -0
- package/package.json +35 -7
- package/dist/commands/auth/login.d.ts +0 -16
- package/dist/commands/auth/login.js +0 -179
- package/dist/commands/auth/logout.js +0 -116
- package/dist/commands/auth/refresh.d.ts +0 -6
- package/dist/commands/auth/refresh.js +0 -66
- package/dist/commands/auth/status.d.ts +0 -6
- package/dist/commands/auth/status.js +0 -63
- package/dist/commands/config/get.d.ts +0 -9
- package/dist/commands/config/get.js +0 -37
- package/dist/commands/config/set.d.ts +0 -10
- package/dist/commands/config/set.js +0 -48
- package/dist/commands/config/show.d.ts +0 -6
- package/dist/commands/config/show.js +0 -10
- package/dist/commands/domain/current.d.ts +0 -6
- package/dist/commands/domain/current.js +0 -18
- package/dist/commands/domain/list.d.ts +0 -6
- package/dist/commands/domain/list.js +0 -42
- package/dist/commands/domain/switch.js +0 -40
- package/dist/commands/jira/hook/add.js +0 -147
- package/dist/services/tenant-service.d.ts +0 -127
- package/dist/services/tenant-service.js +0 -396
- package/dist/utils/auth-flow.d.ts +0 -147
- package/dist/utils/auth-flow.js +0 -479
- package/oclif.manifest.json +0 -3519
- /package/dist/commands/{jira → tracker}/connect.d.ts +0 -0
- /package/dist/commands/{jira → tracker}/hook/list.d.ts +0 -0
- /package/dist/commands/{jira → tracker}/hook/remove.d.ts +0 -0
- /package/dist/commands/{jira → tracker}/hook/toggle.d.ts +0 -0
- /package/dist/commands/{jira → tracker}/status.d.ts +0 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lambda Warmer
|
|
3
|
+
*
|
|
4
|
+
* Pre-warms Lambdas after a stage deploy by invoking each function once.
|
|
5
|
+
* Mitigates the cold-start cliff users hit on the first request after deploy.
|
|
6
|
+
*
|
|
7
|
+
* AC contract (API-120):
|
|
8
|
+
* - AC2: After all module Lambdas are launched, invoke each one once with a
|
|
9
|
+
* synthetic warmup payload (e.g., `{"warmup": true}`).
|
|
10
|
+
* - AC3: Lambda handlers do NOT need to recognize the warmup payload — a
|
|
11
|
+
* vanilla invoke that returns any response counts as warmed.
|
|
12
|
+
* - AC4: Concurrency-aware: never fire all warmups at once. Default cap = 10.
|
|
13
|
+
* - AC5: Failures are reported but never fatal — warming is best-effort.
|
|
14
|
+
*
|
|
15
|
+
* Discovery
|
|
16
|
+
* ---------
|
|
17
|
+
* Lambdas are discovered via `ListFunctionsCommand` on each region, filtered
|
|
18
|
+
* by names that contain the stage slug as a hyphen-bounded segment
|
|
19
|
+
* (e.g. `api-foo-ss-12-handler` matches stage `ss-12`). This matches the
|
|
20
|
+
* naming convention used by `serverless-plugin-composer`-built modules
|
|
21
|
+
* across the workspace.
|
|
22
|
+
*
|
|
23
|
+
* Credentials
|
|
24
|
+
* -----------
|
|
25
|
+
* Uses the standard AWS SDK default credential provider chain. The user is
|
|
26
|
+
* expected to have credentials configured for the target account (via
|
|
27
|
+
* `AWS_PROFILE`, environment variables, or instance role) — the same way
|
|
28
|
+
* they would for any other CLI tool that hits AWS directly.
|
|
29
|
+
*
|
|
30
|
+
* If credentials are missing or the principal lacks `lambda:ListFunctions`
|
|
31
|
+
* / `lambda:InvokeFunction` on the discovered functions, warming is skipped
|
|
32
|
+
* with a warning. The stage-create flow is NEVER blocked.
|
|
33
|
+
*/
|
|
34
|
+
import { type LambdaClient } from '@aws-sdk/client-lambda';
|
|
35
|
+
/** Default in-flight invocation cap (AC4) */
|
|
36
|
+
export declare const DEFAULT_WARMUP_CONCURRENCY = 10;
|
|
37
|
+
/** Default per-invocation timeout. Lambda invocations should warm in <30s. */
|
|
38
|
+
export declare const DEFAULT_WARMUP_TIMEOUT_MS = 30000;
|
|
39
|
+
/**
|
|
40
|
+
* Result of warming a single Lambda function.
|
|
41
|
+
*/
|
|
42
|
+
export interface WarmupResult {
|
|
43
|
+
durationMs: number;
|
|
44
|
+
error?: string;
|
|
45
|
+
functionName: string;
|
|
46
|
+
region: string;
|
|
47
|
+
/** HTTP status returned by the Invoke API (200 = OK, 4xx/5xx = error) */
|
|
48
|
+
statusCode?: number;
|
|
49
|
+
success: boolean;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Aggregate summary returned by `warmStage()`.
|
|
53
|
+
*/
|
|
54
|
+
export interface WarmupSummary {
|
|
55
|
+
failed: number;
|
|
56
|
+
/** Per-function results, in completion order. */
|
|
57
|
+
results: WarmupResult[];
|
|
58
|
+
skipped: number;
|
|
59
|
+
succeeded: number;
|
|
60
|
+
total: number;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Factory for `LambdaClient` instances. Injectable for tests.
|
|
64
|
+
*/
|
|
65
|
+
export type LambdaClientFactory = (region: string) => LambdaClient;
|
|
66
|
+
/**
|
|
67
|
+
* Options for `warmStage()`.
|
|
68
|
+
*/
|
|
69
|
+
export interface WarmStageOptions {
|
|
70
|
+
/** Override the default in-flight cap (AC4). */
|
|
71
|
+
concurrency?: number;
|
|
72
|
+
/** Inject a custom Lambda client factory (used in tests). */
|
|
73
|
+
lambdaClientFactory?: LambdaClientFactory;
|
|
74
|
+
/** Optional logger (defaults to silent). */
|
|
75
|
+
logger?: (message: string) => void;
|
|
76
|
+
/** AWS regions to scan for Lambdas owned by this stage. */
|
|
77
|
+
regions: string[];
|
|
78
|
+
/** Stage slug (e.g. `ss-12`) — used to filter discovered functions. */
|
|
79
|
+
stageName: string;
|
|
80
|
+
/** Per-invocation timeout in ms. */
|
|
81
|
+
timeoutMs?: number;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Returns true when `functionName` belongs to `stageName`.
|
|
85
|
+
*
|
|
86
|
+
* Stage slugs appear as a hyphen-delimited segment in the deployed function
|
|
87
|
+
* name (e.g. `api-grants-ss-12-handler` belongs to `ss-12`). We require the
|
|
88
|
+
* slug to be hyphen-bounded so `ss-1` does NOT match `ss-12`.
|
|
89
|
+
*/
|
|
90
|
+
export declare function functionBelongsToStage(functionName: string, stageName: string): boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Lists all Lambda function names in `region` that belong to `stageName`.
|
|
93
|
+
* Paginates through `ListFunctionsCommand`.
|
|
94
|
+
*/
|
|
95
|
+
export declare function discoverStageFunctions(client: LambdaClient, stageName: string): Promise<string[]>;
|
|
96
|
+
/**
|
|
97
|
+
* Invoke a single Lambda once with the warmup payload.
|
|
98
|
+
* Never throws — failures are encoded in the returned `WarmupResult`.
|
|
99
|
+
*/
|
|
100
|
+
export declare function warmFunction(client: LambdaClient, region: string, functionName: string, timeoutMs: number): Promise<WarmupResult>;
|
|
101
|
+
/**
|
|
102
|
+
* Discover and warm every Lambda owned by `stageName` across `regions`.
|
|
103
|
+
*
|
|
104
|
+
* Best-effort — never throws. Returns a summary the caller can render.
|
|
105
|
+
*/
|
|
106
|
+
export declare function warmStage(opts: WarmStageOptions): Promise<WarmupSummary>;
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lambda Warmer
|
|
3
|
+
*
|
|
4
|
+
* Pre-warms Lambdas after a stage deploy by invoking each function once.
|
|
5
|
+
* Mitigates the cold-start cliff users hit on the first request after deploy.
|
|
6
|
+
*
|
|
7
|
+
* AC contract (API-120):
|
|
8
|
+
* - AC2: After all module Lambdas are launched, invoke each one once with a
|
|
9
|
+
* synthetic warmup payload (e.g., `{"warmup": true}`).
|
|
10
|
+
* - AC3: Lambda handlers do NOT need to recognize the warmup payload — a
|
|
11
|
+
* vanilla invoke that returns any response counts as warmed.
|
|
12
|
+
* - AC4: Concurrency-aware: never fire all warmups at once. Default cap = 10.
|
|
13
|
+
* - AC5: Failures are reported but never fatal — warming is best-effort.
|
|
14
|
+
*
|
|
15
|
+
* Discovery
|
|
16
|
+
* ---------
|
|
17
|
+
* Lambdas are discovered via `ListFunctionsCommand` on each region, filtered
|
|
18
|
+
* by names that contain the stage slug as a hyphen-bounded segment
|
|
19
|
+
* (e.g. `api-foo-ss-12-handler` matches stage `ss-12`). This matches the
|
|
20
|
+
* naming convention used by `serverless-plugin-composer`-built modules
|
|
21
|
+
* across the workspace.
|
|
22
|
+
*
|
|
23
|
+
* Credentials
|
|
24
|
+
* -----------
|
|
25
|
+
* Uses the standard AWS SDK default credential provider chain. The user is
|
|
26
|
+
* expected to have credentials configured for the target account (via
|
|
27
|
+
* `AWS_PROFILE`, environment variables, or instance role) — the same way
|
|
28
|
+
* they would for any other CLI tool that hits AWS directly.
|
|
29
|
+
*
|
|
30
|
+
* If credentials are missing or the principal lacks `lambda:ListFunctions`
|
|
31
|
+
* / `lambda:InvokeFunction` on the discovered functions, warming is skipped
|
|
32
|
+
* with a warning. The stage-create flow is NEVER blocked.
|
|
33
|
+
*/
|
|
34
|
+
import { InvokeCommand, LambdaClient as DefaultLambdaClient, ListFunctionsCommand, } from '@aws-sdk/client-lambda';
|
|
35
|
+
/** Default in-flight invocation cap (AC4) */
|
|
36
|
+
export const DEFAULT_WARMUP_CONCURRENCY = 10;
|
|
37
|
+
/** Default per-invocation timeout. Lambda invocations should warm in <30s. */
|
|
38
|
+
export const DEFAULT_WARMUP_TIMEOUT_MS = 30_000;
|
|
39
|
+
/** Default factory uses the SDK default credential provider chain. */
|
|
40
|
+
const defaultFactory = (region) => new DefaultLambdaClient({ region });
|
|
41
|
+
/**
|
|
42
|
+
* Returns true when `functionName` belongs to `stageName`.
|
|
43
|
+
*
|
|
44
|
+
* Stage slugs appear as a hyphen-delimited segment in the deployed function
|
|
45
|
+
* name (e.g. `api-grants-ss-12-handler` belongs to `ss-12`). We require the
|
|
46
|
+
* slug to be hyphen-bounded so `ss-1` does NOT match `ss-12`.
|
|
47
|
+
*/
|
|
48
|
+
export function functionBelongsToStage(functionName, stageName) {
|
|
49
|
+
if (!functionName || !stageName)
|
|
50
|
+
return false;
|
|
51
|
+
// Anchor on hyphen boundaries so `ss-1` does not collide with `ss-12`.
|
|
52
|
+
// Matches: `...-<stageName>-...` or `...-<stageName>` (suffix).
|
|
53
|
+
const escaped = stageName.replaceAll(/[$()*+.?[\\\]^{|}]/g, '\\$&');
|
|
54
|
+
const re = new RegExp(`(^|-)${escaped}(-|$)`);
|
|
55
|
+
return re.test(functionName);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Lists all Lambda function names in `region` that belong to `stageName`.
|
|
59
|
+
* Paginates through `ListFunctionsCommand`.
|
|
60
|
+
*/
|
|
61
|
+
export async function discoverStageFunctions(client, stageName) {
|
|
62
|
+
const names = [];
|
|
63
|
+
let marker;
|
|
64
|
+
do {
|
|
65
|
+
const out = await client.send(new ListFunctionsCommand({ Marker: marker, MaxItems: 50 }));
|
|
66
|
+
for (const fn of out.Functions ?? []) {
|
|
67
|
+
const name = fn.FunctionName;
|
|
68
|
+
if (name && functionBelongsToStage(name, stageName)) {
|
|
69
|
+
names.push(name);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
marker = out.NextMarker;
|
|
73
|
+
} while (marker);
|
|
74
|
+
return names;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Concurrency-bounded `Promise.all` — runs at most `limit` workers in parallel.
|
|
78
|
+
* Avoids pulling in a `p-limit` dependency for one use site.
|
|
79
|
+
*/
|
|
80
|
+
async function runWithConcurrency(items, limit, worker) {
|
|
81
|
+
const results = Array.from({ length: items.length });
|
|
82
|
+
let nextIndex = 0;
|
|
83
|
+
const lanes = Array.from({ length: Math.min(limit, items.length) }, async () => {
|
|
84
|
+
while (true) {
|
|
85
|
+
const i = nextIndex++;
|
|
86
|
+
if (i >= items.length)
|
|
87
|
+
return;
|
|
88
|
+
results[i] = await worker(items[i]);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
await Promise.all(lanes);
|
|
92
|
+
return results;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Invoke a single Lambda once with the warmup payload.
|
|
96
|
+
* Never throws — failures are encoded in the returned `WarmupResult`.
|
|
97
|
+
*/
|
|
98
|
+
export async function warmFunction(client, region, functionName, timeoutMs) {
|
|
99
|
+
const startedAt = Date.now();
|
|
100
|
+
try {
|
|
101
|
+
const cmd = new InvokeCommand({
|
|
102
|
+
FunctionName: functionName,
|
|
103
|
+
InvocationType: 'RequestResponse',
|
|
104
|
+
Payload: new TextEncoder().encode(JSON.stringify({ warmup: true })),
|
|
105
|
+
});
|
|
106
|
+
const out = await client.send(cmd, {
|
|
107
|
+
// The AWS SDK respects AbortSignal for command-level timeouts.
|
|
108
|
+
abortSignal: AbortSignal.timeout(timeoutMs),
|
|
109
|
+
});
|
|
110
|
+
const durationMs = Date.now() - startedAt;
|
|
111
|
+
// AC3: any response counts as warmed. The Lambda may have returned a
|
|
112
|
+
// FunctionError (`Unhandled` / `Handled`) — that's fine, the runtime is
|
|
113
|
+
// now hot. We only flag transport-level failures as `success: false`.
|
|
114
|
+
return {
|
|
115
|
+
durationMs,
|
|
116
|
+
functionName,
|
|
117
|
+
region,
|
|
118
|
+
statusCode: out.StatusCode,
|
|
119
|
+
success: true,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
return {
|
|
124
|
+
durationMs: Date.now() - startedAt,
|
|
125
|
+
error: error.message ?? String(error),
|
|
126
|
+
functionName,
|
|
127
|
+
region,
|
|
128
|
+
success: false,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Discover and warm every Lambda owned by `stageName` across `regions`.
|
|
134
|
+
*
|
|
135
|
+
* Best-effort — never throws. Returns a summary the caller can render.
|
|
136
|
+
*/
|
|
137
|
+
export async function warmStage(opts) {
|
|
138
|
+
const concurrency = Math.max(1, opts.concurrency ?? DEFAULT_WARMUP_CONCURRENCY);
|
|
139
|
+
const timeoutMs = Math.max(1000, opts.timeoutMs ?? DEFAULT_WARMUP_TIMEOUT_MS);
|
|
140
|
+
const log = opts.logger ?? (() => { });
|
|
141
|
+
const factory = opts.lambdaClientFactory ?? defaultFactory;
|
|
142
|
+
const summary = {
|
|
143
|
+
failed: 0,
|
|
144
|
+
results: [],
|
|
145
|
+
skipped: 0,
|
|
146
|
+
succeeded: 0,
|
|
147
|
+
total: 0,
|
|
148
|
+
};
|
|
149
|
+
// Discover functions per region in parallel (cheap network calls).
|
|
150
|
+
const discoveries = await Promise.all(opts.regions.map(async (region) => {
|
|
151
|
+
const client = factory(region);
|
|
152
|
+
try {
|
|
153
|
+
const names = await discoverStageFunctions(client, opts.stageName);
|
|
154
|
+
return { client, names, region };
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
log(`⚠️ Warm-up discovery failed in ${region}: ${error.message ?? String(error)}`);
|
|
158
|
+
// AC5: never fatal. Surface as `skipped`.
|
|
159
|
+
return { client, error: error, names: [], region };
|
|
160
|
+
}
|
|
161
|
+
}));
|
|
162
|
+
const tasks = [];
|
|
163
|
+
for (const d of discoveries) {
|
|
164
|
+
if ('error' in d && d.error) {
|
|
165
|
+
summary.skipped += 1;
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
for (const name of d.names) {
|
|
169
|
+
tasks.push({ client: d.client, functionName: name, region: d.region });
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
summary.total = tasks.length;
|
|
173
|
+
if (tasks.length === 0) {
|
|
174
|
+
log(`ℹ️ No Lambdas matched stage '${opts.stageName}' in any of: ${opts.regions.join(', ')}`);
|
|
175
|
+
return summary;
|
|
176
|
+
}
|
|
177
|
+
log(`🔥 Warming ${tasks.length} Lambda(s) (concurrency=${concurrency})...`);
|
|
178
|
+
const results = await runWithConcurrency(tasks, concurrency, async (task) => warmFunction(task.client, task.region, task.functionName, timeoutMs));
|
|
179
|
+
for (const r of results) {
|
|
180
|
+
summary.results.push(r);
|
|
181
|
+
if (r.success) {
|
|
182
|
+
summary.succeeded += 1;
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
summary.failed += 1;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return summary;
|
|
189
|
+
}
|