cdk-local 0.107.1 → 0.109.0
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/cli.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/internal.d.ts +10 -2
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +2 -2
- package/dist/{local-studio-BWrmJblg.js → local-studio-CxVVLdJw.js} +342 -137
- package/dist/{local-studio-BWrmJblg.js.map → local-studio-CxVVLdJw.js.map} +1 -1
- package/dist/{local-studio-xR0_WFBL.d.ts → local-studio-DWnKL8m1.d.ts} +3 -1
- package/dist/{local-studio-xR0_WFBL.d.ts.map → local-studio-DWnKL8m1.d.ts.map} +1 -1
- package/package.json +1 -1
|
@@ -17201,123 +17201,14 @@ async function localInvokeCommand(target, options, extraStateProviders) {
|
|
|
17201
17201
|
const targetLabel = lambda.kind === "zip" ? lambda.runtime : "container image";
|
|
17202
17202
|
logger.info(`Target: ${lambda.stack.stackName}/${lambda.logicalId} (${targetLabel})`);
|
|
17203
17203
|
imagePlan = await resolveImagePlan(lambda, options);
|
|
17204
|
-
|
|
17205
|
-
|
|
17206
|
-
|
|
17207
|
-
|
|
17208
|
-
|
|
17209
|
-
|
|
17210
|
-
if (loaded) {
|
|
17211
|
-
stateForRoleHint = {
|
|
17212
|
-
version: 1,
|
|
17213
|
-
stackName: lambda.stack.stackName,
|
|
17214
|
-
resources: loaded.resources,
|
|
17215
|
-
outputs: loaded.outputs,
|
|
17216
|
-
lastModified: 0
|
|
17217
|
-
};
|
|
17218
|
-
const subContext = {
|
|
17219
|
-
resources: loaded.resources,
|
|
17220
|
-
consumerRegion: loaded.region
|
|
17221
|
-
};
|
|
17222
|
-
if (envHasIntrinsicValue(templateEnv)) {
|
|
17223
|
-
const pseudo = await resolvePseudoParametersForInvoke(lambda.stack.region, options);
|
|
17224
|
-
if (pseudo) subContext.pseudoParameters = pseudo;
|
|
17225
|
-
}
|
|
17226
|
-
if (envHasIntrinsicValue(templateEnv) && stateProvider.resolveTemplateSsmParameters) {
|
|
17227
|
-
const ssmParams = await stateProvider.resolveTemplateSsmParameters(lambda.stack.template);
|
|
17228
|
-
if (Object.keys(ssmParams.values).length > 0) subContext.parameters = ssmParams.values;
|
|
17229
|
-
if (ssmParams.secureStringLogicalIds.length > 0) subContext.sensitiveParameters = new Set(ssmParams.secureStringLogicalIds);
|
|
17230
|
-
}
|
|
17231
|
-
if (envHasCrossStackIntrinsic(templateEnv)) {
|
|
17232
|
-
const resolver = await stateProvider.buildCrossStackResolver(loaded.region);
|
|
17233
|
-
if (resolver) subContext.crossStackResolver = resolver;
|
|
17234
|
-
}
|
|
17235
|
-
const { env, audit } = await substituteEnvVarsFromStateAsync(templateEnv, subContext);
|
|
17236
|
-
templateEnv = env;
|
|
17237
|
-
const label = stateProvider.label;
|
|
17238
|
-
for (const key of audit.resolvedKeys) logger.debug(`${label}: substituted env var ${key}`);
|
|
17239
|
-
let unresolved = audit.unresolved;
|
|
17240
|
-
const resolvedKeys = [...audit.resolvedKeys];
|
|
17241
|
-
if (unresolved.length > 0 && stateProvider.resolveDeployedFunctionEnv) {
|
|
17242
|
-
const physicalId = loaded.resources[lambda.logicalId]?.physicalId;
|
|
17243
|
-
if (physicalId) {
|
|
17244
|
-
const deployedEnv = await stateProvider.resolveDeployedFunctionEnv(physicalId);
|
|
17245
|
-
const fb = applyDeployedEnvFallback(templateEnv, unresolved, deployedEnv);
|
|
17246
|
-
templateEnv = fb.env;
|
|
17247
|
-
unresolved = fb.stillUnresolved;
|
|
17248
|
-
for (const key of fb.filled) {
|
|
17249
|
-
resolvedKeys.push(key);
|
|
17250
|
-
logger.debug(`${label}: filled env var ${key} from deployed function config`);
|
|
17251
|
-
}
|
|
17252
|
-
}
|
|
17253
|
-
}
|
|
17254
|
-
stateAudit = {
|
|
17255
|
-
resolvedKeys,
|
|
17256
|
-
unresolved,
|
|
17257
|
-
sensitiveKeys: audit.sensitiveKeys
|
|
17258
|
-
};
|
|
17259
|
-
for (const { key, reason } of unresolved) logger.warn(`${label}: could not substitute env var ${key} (${reason}). Override it via --env-vars or it will be dropped.`);
|
|
17260
|
-
}
|
|
17261
|
-
} catch (err) {
|
|
17262
|
-
stateProvider.dispose();
|
|
17263
|
-
throw err;
|
|
17264
|
-
}
|
|
17265
|
-
const overrides = readEnvOverridesFile$3(options.envVars);
|
|
17266
|
-
const lambdaCdkPath = readCdkPathOrUndefined(lambda.resource);
|
|
17267
|
-
const envResult = resolveEnvVars$1(lambda.logicalId, lambdaCdkPath, templateEnv, overrides);
|
|
17268
|
-
for (const key of envResult.unresolved) {
|
|
17269
|
-
if (stateAudit && stateAudit.unresolved.some((u) => u.key === key)) continue;
|
|
17270
|
-
const overrideKeyExample = lambdaCdkPath?.replace(/\/Resource$/, "") ?? lambda.logicalId;
|
|
17271
|
-
logger.warn(`Environment variable ${key} contains a CloudFormation intrinsic and was dropped. Override it with --env-vars (e.g. {"${overrideKeyExample}":{"${key}":"<literal>"}}), or pass a state-source flag (e.g. --from-cfn-stack or a host-provided extension) to recover deployed values.`);
|
|
17272
|
-
}
|
|
17273
|
-
let resolvedAssumeRoleArn;
|
|
17274
|
-
try {
|
|
17275
|
-
resolvedAssumeRoleArn = await resolveAssumeRoleArnForLambda(options.assumeRole, stateForRoleHint, stateProvider, lambda.logicalId);
|
|
17276
|
-
} finally {
|
|
17277
|
-
stateProvider?.dispose();
|
|
17204
|
+
const containerEnv = await resolveLambdaContainerEnv(lambda, options, profileCredentials, extraStateProviders);
|
|
17205
|
+
const dockerEnv = containerEnv.env;
|
|
17206
|
+
if (options.assumeRole === void 0 && containerEnv.stateForRoleHint) suggestAssumeRoleFromState(containerEnv.stateForRoleHint, lambda.logicalId);
|
|
17207
|
+
if (!containerEnv.assumeRoleApplied && profileCredsFile) {
|
|
17208
|
+
dockerEnv["AWS_SHARED_CREDENTIALS_FILE"] = profileCredsFile.containerPath;
|
|
17209
|
+
dockerEnv["AWS_PROFILE"] = profileCredsFile.profileName;
|
|
17278
17210
|
}
|
|
17279
|
-
if (options.assumeRole === void 0 && stateForRoleHint) suggestAssumeRoleFromState(stateForRoleHint, lambda.logicalId);
|
|
17280
17211
|
const event = await readEvent$1(options);
|
|
17281
|
-
const dockerEnv = {
|
|
17282
|
-
AWS_LAMBDA_FUNCTION_NAME: lambda.logicalId,
|
|
17283
|
-
AWS_LAMBDA_FUNCTION_MEMORY_SIZE: String(lambda.memoryMb),
|
|
17284
|
-
AWS_LAMBDA_FUNCTION_TIMEOUT: String(lambda.timeoutSec),
|
|
17285
|
-
AWS_LAMBDA_FUNCTION_VERSION: "$LATEST",
|
|
17286
|
-
AWS_LAMBDA_LOG_GROUP_NAME: `/aws/lambda/${lambda.logicalId}`,
|
|
17287
|
-
AWS_LAMBDA_LOG_STREAM_NAME: "local",
|
|
17288
|
-
...envResult.resolved
|
|
17289
|
-
};
|
|
17290
|
-
let assumeSucceeded = false;
|
|
17291
|
-
if (resolvedAssumeRoleArn) {
|
|
17292
|
-
const stsRegion = options.region ?? process.env["AWS_REGION"] ?? process.env["AWS_DEFAULT_REGION"];
|
|
17293
|
-
try {
|
|
17294
|
-
const creds = await assumeLambdaExecutionRole(resolvedAssumeRoleArn, stsRegion, options.profile);
|
|
17295
|
-
dockerEnv["AWS_ACCESS_KEY_ID"] = creds.accessKeyId;
|
|
17296
|
-
dockerEnv["AWS_SECRET_ACCESS_KEY"] = creds.secretAccessKey;
|
|
17297
|
-
dockerEnv["AWS_SESSION_TOKEN"] = creds.sessionToken;
|
|
17298
|
-
if (stsRegion) dockerEnv["AWS_REGION"] = stsRegion;
|
|
17299
|
-
assumeSucceeded = true;
|
|
17300
|
-
} catch (err) {
|
|
17301
|
-
const reason = err instanceof Error ? err.message : String(err);
|
|
17302
|
-
logger.warn(`--assume-role: STS AssumeRole(${resolvedAssumeRoleArn}) failed: ${reason}. Falling back to the developer's shell credentials.`);
|
|
17303
|
-
}
|
|
17304
|
-
}
|
|
17305
|
-
if (!assumeSucceeded) {
|
|
17306
|
-
forwardAwsEnv$2(dockerEnv);
|
|
17307
|
-
applyProfileCredentialsOverlay(dockerEnv, profileCredentials, false);
|
|
17308
|
-
if (profileCredsFile) {
|
|
17309
|
-
dockerEnv["AWS_SHARED_CREDENTIALS_FILE"] = profileCredsFile.containerPath;
|
|
17310
|
-
dockerEnv["AWS_PROFILE"] = profileCredsFile.profileName;
|
|
17311
|
-
}
|
|
17312
|
-
}
|
|
17313
|
-
if (!dockerEnv["AWS_REGION"] && !dockerEnv["AWS_DEFAULT_REGION"]) {
|
|
17314
|
-
const fallbackRegion = resolveContainerFallbackRegion({
|
|
17315
|
-
stackRegionOverride: options.region,
|
|
17316
|
-
synthRegion: lambda.stack.region,
|
|
17317
|
-
profileRegion: profileCredentials?.region
|
|
17318
|
-
});
|
|
17319
|
-
if (fallbackRegion) dockerEnv["AWS_REGION"] = fallbackRegion;
|
|
17320
|
-
}
|
|
17321
17212
|
let debugPort;
|
|
17322
17213
|
if (options.debugPort) {
|
|
17323
17214
|
debugPort = Number(options.debugPort);
|
|
@@ -17339,7 +17230,7 @@ async function localInvokeCommand(target, options, extraStateProviders) {
|
|
|
17339
17230
|
mounts: imagePlan.mounts,
|
|
17340
17231
|
extraMounts: extraMountsWithProfile,
|
|
17341
17232
|
env: dockerEnv,
|
|
17342
|
-
...
|
|
17233
|
+
...containerEnv.sensitiveEnvKeys.length > 0 && { sensitiveEnvKeys: new Set(containerEnv.sensitiveEnvKeys) },
|
|
17343
17234
|
cmd: imagePlan.cmd,
|
|
17344
17235
|
hostPort,
|
|
17345
17236
|
host: containerHost,
|
|
@@ -17627,6 +17518,141 @@ function applyProfileCredentialsOverlay(env, profileCreds, assumeRoleActive) {
|
|
|
17627
17518
|
if (profileCreds.sessionToken) env["AWS_SESSION_TOKEN"] = profileCreds.sessionToken;
|
|
17628
17519
|
else delete env["AWS_SESSION_TOKEN"];
|
|
17629
17520
|
}
|
|
17521
|
+
/**
|
|
17522
|
+
* Resolve the full container environment for a Lambda: its declared env vars
|
|
17523
|
+
* (literal + `--env-vars` overrides + intrinsic values substituted against a
|
|
17524
|
+
* `--from-cfn-stack` deployed stack — SSM / cross-stack / deployed-env
|
|
17525
|
+
* fallback included), the `AWS_LAMBDA_*` runtime vars, and AWS credentials
|
|
17526
|
+
* (an `--assume-role` STS assume, else the dev shell's forwarded creds + a
|
|
17527
|
+
* `--profile` overlay), plus a fallback `AWS_REGION`.
|
|
17528
|
+
*
|
|
17529
|
+
* This is the single source of truth shared by `cdkl invoke` AND the
|
|
17530
|
+
* front-door Lambda boot path (`start-cloudfront`'s Function URL origin,
|
|
17531
|
+
* `start-alb`'s Lambda targets — issue #380), so a CDN- / ALB-fronted Lambda
|
|
17532
|
+
* reaches the same deployed resources as a direct `cdkl invoke`. The caller
|
|
17533
|
+
* layers any command-specific concerns (a `--profile` credentials-file
|
|
17534
|
+
* bind-mount, `--debug-port`) on top of `env`.
|
|
17535
|
+
*/
|
|
17536
|
+
async function resolveLambdaContainerEnv(lambda, options, profileCredentials, extraStateProviders) {
|
|
17537
|
+
const logger = getLogger();
|
|
17538
|
+
let stateAudit;
|
|
17539
|
+
let templateEnv = getTemplateEnv(lambda.resource);
|
|
17540
|
+
let stateForRoleHint;
|
|
17541
|
+
const stateProvider = createLocalStateProvider(options, lambda.stack.stackName, await resolveCfnFallbackRegion(options, lambda.stack.region), extraStateProviders);
|
|
17542
|
+
if (stateProvider) try {
|
|
17543
|
+
const loaded = await stateProvider.load(lambda.stack.stackName, lambda.stack.region);
|
|
17544
|
+
if (loaded) {
|
|
17545
|
+
stateForRoleHint = {
|
|
17546
|
+
version: 1,
|
|
17547
|
+
stackName: lambda.stack.stackName,
|
|
17548
|
+
resources: loaded.resources,
|
|
17549
|
+
outputs: loaded.outputs,
|
|
17550
|
+
lastModified: 0
|
|
17551
|
+
};
|
|
17552
|
+
const subContext = {
|
|
17553
|
+
resources: loaded.resources,
|
|
17554
|
+
consumerRegion: loaded.region
|
|
17555
|
+
};
|
|
17556
|
+
if (envHasIntrinsicValue(templateEnv)) {
|
|
17557
|
+
const pseudo = await resolvePseudoParametersForInvoke(lambda.stack.region, options);
|
|
17558
|
+
if (pseudo) subContext.pseudoParameters = pseudo;
|
|
17559
|
+
}
|
|
17560
|
+
if (envHasIntrinsicValue(templateEnv) && stateProvider.resolveTemplateSsmParameters) {
|
|
17561
|
+
const ssmParams = await stateProvider.resolveTemplateSsmParameters(lambda.stack.template);
|
|
17562
|
+
if (Object.keys(ssmParams.values).length > 0) subContext.parameters = ssmParams.values;
|
|
17563
|
+
if (ssmParams.secureStringLogicalIds.length > 0) subContext.sensitiveParameters = new Set(ssmParams.secureStringLogicalIds);
|
|
17564
|
+
}
|
|
17565
|
+
if (envHasCrossStackIntrinsic(templateEnv)) {
|
|
17566
|
+
const resolver = await stateProvider.buildCrossStackResolver(loaded.region);
|
|
17567
|
+
if (resolver) subContext.crossStackResolver = resolver;
|
|
17568
|
+
}
|
|
17569
|
+
const { env, audit } = await substituteEnvVarsFromStateAsync(templateEnv, subContext);
|
|
17570
|
+
templateEnv = env;
|
|
17571
|
+
const label = stateProvider.label;
|
|
17572
|
+
for (const key of audit.resolvedKeys) logger.debug(`${label}: substituted env var ${key}`);
|
|
17573
|
+
let unresolved = audit.unresolved;
|
|
17574
|
+
const resolvedKeys = [...audit.resolvedKeys];
|
|
17575
|
+
if (unresolved.length > 0 && stateProvider.resolveDeployedFunctionEnv) {
|
|
17576
|
+
const physicalId = loaded.resources[lambda.logicalId]?.physicalId;
|
|
17577
|
+
if (physicalId) {
|
|
17578
|
+
const deployedEnv = await stateProvider.resolveDeployedFunctionEnv(physicalId);
|
|
17579
|
+
const fb = applyDeployedEnvFallback(templateEnv, unresolved, deployedEnv);
|
|
17580
|
+
templateEnv = fb.env;
|
|
17581
|
+
unresolved = fb.stillUnresolved;
|
|
17582
|
+
for (const key of fb.filled) {
|
|
17583
|
+
resolvedKeys.push(key);
|
|
17584
|
+
logger.debug(`${label}: filled env var ${key} from deployed function config`);
|
|
17585
|
+
}
|
|
17586
|
+
}
|
|
17587
|
+
}
|
|
17588
|
+
stateAudit = {
|
|
17589
|
+
resolvedKeys,
|
|
17590
|
+
unresolved,
|
|
17591
|
+
sensitiveKeys: audit.sensitiveKeys
|
|
17592
|
+
};
|
|
17593
|
+
for (const { key, reason } of unresolved) logger.warn(`${label}: could not substitute env var ${key} (${reason}). Override it via --env-vars or it will be dropped.`);
|
|
17594
|
+
}
|
|
17595
|
+
} catch (err) {
|
|
17596
|
+
stateProvider.dispose();
|
|
17597
|
+
throw err;
|
|
17598
|
+
}
|
|
17599
|
+
const overrides = readEnvOverridesFile$3(options.envVars);
|
|
17600
|
+
const lambdaCdkPath = readCdkPathOrUndefined(lambda.resource);
|
|
17601
|
+
const envResult = resolveEnvVars$1(lambda.logicalId, lambdaCdkPath, templateEnv, overrides);
|
|
17602
|
+
for (const key of envResult.unresolved) {
|
|
17603
|
+
if (stateAudit && stateAudit.unresolved.some((u) => u.key === key)) continue;
|
|
17604
|
+
const overrideKeyExample = lambdaCdkPath?.replace(/\/Resource$/, "") ?? lambda.logicalId;
|
|
17605
|
+
logger.warn(`Environment variable ${key} contains a CloudFormation intrinsic and was dropped. Override it with --env-vars (e.g. {"${overrideKeyExample}":{"${key}":"<literal>"}}), or pass a state-source flag (e.g. --from-cfn-stack or a host-provided extension) to recover deployed values.`);
|
|
17606
|
+
}
|
|
17607
|
+
let resolvedAssumeRoleArn;
|
|
17608
|
+
try {
|
|
17609
|
+
resolvedAssumeRoleArn = await resolveAssumeRoleArnForLambda(options.assumeRole, stateForRoleHint, stateProvider, lambda.logicalId);
|
|
17610
|
+
} finally {
|
|
17611
|
+
stateProvider?.dispose();
|
|
17612
|
+
}
|
|
17613
|
+
const dockerEnv = {
|
|
17614
|
+
AWS_LAMBDA_FUNCTION_NAME: lambda.logicalId,
|
|
17615
|
+
AWS_LAMBDA_FUNCTION_MEMORY_SIZE: String(lambda.memoryMb),
|
|
17616
|
+
AWS_LAMBDA_FUNCTION_TIMEOUT: String(lambda.timeoutSec),
|
|
17617
|
+
AWS_LAMBDA_FUNCTION_VERSION: "$LATEST",
|
|
17618
|
+
AWS_LAMBDA_LOG_GROUP_NAME: `/aws/lambda/${lambda.logicalId}`,
|
|
17619
|
+
AWS_LAMBDA_LOG_STREAM_NAME: "local",
|
|
17620
|
+
...envResult.resolved
|
|
17621
|
+
};
|
|
17622
|
+
let assumeSucceeded = false;
|
|
17623
|
+
if (resolvedAssumeRoleArn) {
|
|
17624
|
+
const stsRegion = options.region ?? process.env["AWS_REGION"] ?? process.env["AWS_DEFAULT_REGION"];
|
|
17625
|
+
try {
|
|
17626
|
+
const creds = await assumeLambdaExecutionRole(resolvedAssumeRoleArn, stsRegion, options.profile);
|
|
17627
|
+
dockerEnv["AWS_ACCESS_KEY_ID"] = creds.accessKeyId;
|
|
17628
|
+
dockerEnv["AWS_SECRET_ACCESS_KEY"] = creds.secretAccessKey;
|
|
17629
|
+
dockerEnv["AWS_SESSION_TOKEN"] = creds.sessionToken;
|
|
17630
|
+
if (stsRegion) dockerEnv["AWS_REGION"] = stsRegion;
|
|
17631
|
+
assumeSucceeded = true;
|
|
17632
|
+
} catch (err) {
|
|
17633
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
17634
|
+
logger.warn(`--assume-role: STS AssumeRole(${resolvedAssumeRoleArn}) failed: ${reason}. Falling back to the developer's shell credentials.`);
|
|
17635
|
+
}
|
|
17636
|
+
}
|
|
17637
|
+
if (!assumeSucceeded) {
|
|
17638
|
+
forwardAwsEnv$2(dockerEnv);
|
|
17639
|
+
applyProfileCredentialsOverlay(dockerEnv, profileCredentials, false);
|
|
17640
|
+
}
|
|
17641
|
+
if (!dockerEnv["AWS_REGION"] && !dockerEnv["AWS_DEFAULT_REGION"]) {
|
|
17642
|
+
const fallbackRegion = resolveContainerFallbackRegion({
|
|
17643
|
+
stackRegionOverride: options.region,
|
|
17644
|
+
synthRegion: lambda.stack.region,
|
|
17645
|
+
profileRegion: profileCredentials?.region
|
|
17646
|
+
});
|
|
17647
|
+
if (fallbackRegion) dockerEnv["AWS_REGION"] = fallbackRegion;
|
|
17648
|
+
}
|
|
17649
|
+
return {
|
|
17650
|
+
env: dockerEnv,
|
|
17651
|
+
sensitiveEnvKeys: stateAudit?.sensitiveKeys ?? [],
|
|
17652
|
+
...stateForRoleHint !== void 0 && { stateForRoleHint },
|
|
17653
|
+
assumeRoleApplied: assumeSucceeded
|
|
17654
|
+
};
|
|
17655
|
+
}
|
|
17630
17656
|
function materializeInlineCode$1(handler, source, fileExtension) {
|
|
17631
17657
|
const lastDot = handler.lastIndexOf(".");
|
|
17632
17658
|
if (lastDot <= 0) throw new Error(`Handler '${handler}' is malformed: expected '<modulePath>.<exportName>'.`);
|
|
@@ -24435,7 +24461,7 @@ function createFrontDoorLambdaRunner(lambda, opts) {
|
|
|
24435
24461
|
const port = await pickFreePort();
|
|
24436
24462
|
hostPort = port;
|
|
24437
24463
|
const name = `${getEmbedConfig().resourceNamePrefix}-alblambda-${lambda.logicalId}-${process.pid}-${Math.floor(Math.random() * 1e6)}`;
|
|
24438
|
-
const env = {
|
|
24464
|
+
const env = opts.containerEnv ? { ...opts.containerEnv } : {
|
|
24439
24465
|
AWS_LAMBDA_FUNCTION_NAME: lambda.logicalId,
|
|
24440
24466
|
AWS_LAMBDA_FUNCTION_MEMORY_SIZE: String(lambda.memoryMb),
|
|
24441
24467
|
AWS_LAMBDA_FUNCTION_TIMEOUT: String(lambda.timeoutSec),
|
|
@@ -24449,6 +24475,7 @@ function createFrontDoorLambdaRunner(lambda, opts) {
|
|
|
24449
24475
|
image: plan.image,
|
|
24450
24476
|
mounts: plan.mounts,
|
|
24451
24477
|
env,
|
|
24478
|
+
...opts.sensitiveEnvKeys && opts.sensitiveEnvKeys.size > 0 && { sensitiveEnvKeys: opts.sensitiveEnvKeys },
|
|
24452
24479
|
cmd: plan.cmd,
|
|
24453
24480
|
hostPort: port,
|
|
24454
24481
|
host: opts.containerHost,
|
|
@@ -28959,10 +28986,14 @@ async function bootLambdaUrlOrigins(distribution, stacks, opts) {
|
|
|
28959
28986
|
for (const functionLogicalId of functionLogicalIds) {
|
|
28960
28987
|
let runner;
|
|
28961
28988
|
try {
|
|
28962
|
-
|
|
28989
|
+
const lambda = resolveLambdaTarget(functionLogicalId, stacks);
|
|
28990
|
+
const containerEnv = await resolveLambdaContainerEnv(lambda, opts.envOptions, opts.profileCredentials);
|
|
28991
|
+
runner = createFrontDoorLambdaRunner(lambda, {
|
|
28963
28992
|
containerHost: opts.containerHost,
|
|
28964
28993
|
skipPull: opts.skipPull,
|
|
28965
|
-
...opts.region !== void 0 && { region: opts.region }
|
|
28994
|
+
...opts.envOptions.region !== void 0 && { region: opts.envOptions.region },
|
|
28995
|
+
containerEnv: containerEnv.env,
|
|
28996
|
+
...containerEnv.sensitiveEnvKeys.length > 0 && { sensitiveEnvKeys: new Set(containerEnv.sensitiveEnvKeys) }
|
|
28966
28997
|
});
|
|
28967
28998
|
logger.info(`Booting Lambda Function URL origin container for ${functionLogicalId} (the backing Lambda runs locally via RIE)...`);
|
|
28968
28999
|
await runner.start();
|
|
@@ -29030,10 +29061,19 @@ async function localStartCloudFrontCommand(target, options) {
|
|
|
29030
29061
|
};
|
|
29031
29062
|
const initial = await synthAndResolve();
|
|
29032
29063
|
warnUnsupported(initial.distribution);
|
|
29064
|
+
const profileCredentials = options.profile ? await resolveProfileCredentials(options.profile) : void 0;
|
|
29065
|
+
const envOptions = {
|
|
29066
|
+
...options.fromCfnStack !== void 0 && { fromCfnStack: options.fromCfnStack },
|
|
29067
|
+
...options.assumeRole !== void 0 && { assumeRole: options.assumeRole },
|
|
29068
|
+
...options.region !== void 0 && { region: options.region },
|
|
29069
|
+
...options.profile !== void 0 && { profile: options.profile },
|
|
29070
|
+
...options.stackRegion !== void 0 && { stackRegion: options.stackRegion }
|
|
29071
|
+
};
|
|
29033
29072
|
const { invokers: lambdaInvokers, runners: lambdaRunners } = await bootLambdaUrlOrigins(initial.distribution, initial.stacks, {
|
|
29034
29073
|
containerHost: options.host,
|
|
29035
29074
|
skipPull: options.pull === false,
|
|
29036
|
-
|
|
29075
|
+
envOptions,
|
|
29076
|
+
...profileCredentials !== void 0 && { profileCredentials }
|
|
29037
29077
|
});
|
|
29038
29078
|
let tls;
|
|
29039
29079
|
if (tlsRequested) tls = await resolveFrontDoorTlsMaterials({
|
|
@@ -29121,7 +29161,7 @@ function createLocalStartCloudFrontCommand(opts = {}) {
|
|
|
29121
29161
|
* `cmd`.
|
|
29122
29162
|
*/
|
|
29123
29163
|
function addStartCloudFrontSpecificOptions(cmd) {
|
|
29124
|
-
return cmd.addOption(new Option("--port <port>", "HTTP server port (default: auto-allocate)").default("0")).addOption(new Option("--host <host>", "Bind address").default("127.0.0.1")).addOption(new Option("--origin <originId=dir>", "Point a distribution origin at a local directory (repeatable). Use when cdk-local cannot resolve the origin's BucketDeployment source automatically (content uploaded out of band, or a non-CDK bucket).").argParser((value, prev) => [...prev ?? [], value])).addOption(new Option("--tls", "Terminate real TLS (HTTPS). Uses --tls-cert / --tls-key when supplied, else an auto-generated self-signed cert.").default(false)).addOption(new Option("--tls-cert <path>", "PEM server certificate for --tls (implies --tls).")).addOption(new Option("--tls-key <path>", "PEM server private key for --tls (implies --tls).")).addOption(new Option("--no-pull", "Skip 'docker pull' for a Lambda Function URL origin's base image (use the locally cached image).")).addOption(new Option("--watch", "Hot-reload: re-synth + re-resolve the distribution when the CDK app's source changes (honors cdk.json watch.include/exclude; cdk.out, node_modules, .git are always excluded). The server keeps the previous version serving when synth fails mid-reload.").default(false));
|
|
29164
|
+
return cmd.addOption(new Option("--port <port>", "HTTP server port (default: auto-allocate)").default("0")).addOption(new Option("--host <host>", "Bind address").default("127.0.0.1")).addOption(new Option("--origin <originId=dir>", "Point a distribution origin at a local directory (repeatable). Use when cdk-local cannot resolve the origin's BucketDeployment source automatically (content uploaded out of band, or a non-CDK bucket).").argParser((value, prev) => [...prev ?? [], value])).addOption(new Option("--tls", "Terminate real TLS (HTTPS). Uses --tls-cert / --tls-key when supplied, else an auto-generated self-signed cert.").default(false)).addOption(new Option("--tls-cert <path>", "PEM server certificate for --tls (implies --tls).")).addOption(new Option("--tls-key <path>", "PEM server private key for --tls (implies --tls).")).addOption(new Option("--no-pull", "Skip 'docker pull' for a Lambda Function URL origin's base image (use the locally cached image).")).addOption(new Option("--from-cfn-stack [cfn-stack-name]", "Bind a Lambda Function URL origin's backing Lambda to a deployed CloudFormation stack so its env vars resolve to the deployed physical IDs / exports (ListStackResources). Use for CDK apps deployed via the upstream CDK CLI (`cdk deploy`). Bare form uses the resolved stack name; pass a value when the CFn stack name differs. No effect on a pure-S3 distribution.")).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-cfn-stack as the CFn client region.")).addOption(new Option("--assume-role [arn]", "Assume a Lambda Function URL origin's deployed execution role and forward STS-issued temp credentials into its container so the handler runs with the deployed permissions. Three forms: `--assume-role <arn>` (explicit ARN); `--assume-role` (bare, auto-resolves from state — requires --from-cfn-stack); `--no-assume-role` (opt out). Off by default (the dev shell credentials are forwarded).")).addOption(new Option("--watch", "Hot-reload: re-synth + re-resolve the distribution when the CDK app's source changes (honors cdk.json watch.include/exclude; cdk.out, node_modules, .git are always excluded). The server keeps the previous version serving when synth fails mid-reload.").default(false));
|
|
29125
29165
|
}
|
|
29126
29166
|
|
|
29127
29167
|
//#endregion
|
|
@@ -30236,11 +30276,12 @@ const STUDIO_SCRIPT = `
|
|
|
30236
30276
|
// --image-override flag to start-service so the deployed-registry-pinned
|
|
30237
30277
|
// image is rebuilt from local source. Default "(keep pinned image)" => no
|
|
30238
30278
|
// override.
|
|
30239
|
-
|
|
30240
|
-
|
|
30241
|
-
|
|
30279
|
+
// One labeled Dockerfile <select> row (the discovered Dockerfiles + a
|
|
30280
|
+
// "(keep pinned image)" default). Shared by the ecs single picker and the
|
|
30281
|
+
// alb per-backing-service pickers.
|
|
30282
|
+
function buildImageOverrideRow(labelText) {
|
|
30242
30283
|
const row = el('div', 'opt-row');
|
|
30243
|
-
row.appendChild(el('span', 'opt-label',
|
|
30284
|
+
row.appendChild(el('span', 'opt-label', labelText));
|
|
30244
30285
|
const sel = el('select', 'image-override-select');
|
|
30245
30286
|
const none = el('option', null, '(keep pinned image)');
|
|
30246
30287
|
none.value = '';
|
|
@@ -30251,7 +30292,19 @@ const STUDIO_SCRIPT = `
|
|
|
30251
30292
|
sel.appendChild(o);
|
|
30252
30293
|
});
|
|
30253
30294
|
row.appendChild(sel);
|
|
30254
|
-
|
|
30295
|
+
return {
|
|
30296
|
+
row: row,
|
|
30297
|
+
getValue: function () {
|
|
30298
|
+
return sel.value.trim();
|
|
30299
|
+
},
|
|
30300
|
+
};
|
|
30301
|
+
}
|
|
30302
|
+
|
|
30303
|
+
function buildImageOverridePicker() {
|
|
30304
|
+
const sec = el('div', 'section options');
|
|
30305
|
+
sec.appendChild(el('h3', null, 'Image override'));
|
|
30306
|
+
const r = buildImageOverrideRow('Local Dockerfile');
|
|
30307
|
+
sec.appendChild(r.row);
|
|
30255
30308
|
const hint = studioDockerfiles.length
|
|
30256
30309
|
? 'This image is pinned to a deployed registry — local edits do not take effect. Pick a Dockerfile to rebuild it locally.'
|
|
30257
30310
|
: 'This image is pinned to a deployed registry, but no Dockerfile was found under the app directory.';
|
|
@@ -30259,12 +30312,41 @@ const STUDIO_SCRIPT = `
|
|
|
30259
30312
|
return {
|
|
30260
30313
|
node: sec,
|
|
30261
30314
|
collect: function () {
|
|
30262
|
-
const v =
|
|
30315
|
+
const v = r.getValue();
|
|
30263
30316
|
return v === '' ? undefined : v;
|
|
30264
30317
|
},
|
|
30265
30318
|
};
|
|
30266
30319
|
}
|
|
30267
30320
|
|
|
30321
|
+
// Per-backing-service image-override pickers for a pinned ALB (issue #382):
|
|
30322
|
+
// one Dockerfile select per deployed-registry-pinned service the ALB fronts.
|
|
30323
|
+
// collect() returns a { [serviceId]: dockerfile } map threaded as
|
|
30324
|
+
// imageOverrides (one --image-override service=df per entry).
|
|
30325
|
+
function buildAlbImageOverridePicker(services) {
|
|
30326
|
+
const sec = el('div', 'section options');
|
|
30327
|
+
sec.appendChild(el('h3', null, 'Image override (pinned backing services)'));
|
|
30328
|
+
const rows = services.map(function (svc) {
|
|
30329
|
+
const r = buildImageOverrideRow(svc.label);
|
|
30330
|
+
sec.appendChild(r.row);
|
|
30331
|
+
return { id: svc.id, getValue: r.getValue };
|
|
30332
|
+
});
|
|
30333
|
+
const hint = studioDockerfiles.length
|
|
30334
|
+
? 'These services behind the ALB are pinned to a deployed registry — local edits do not take effect. Pick a Dockerfile to rebuild one from local source.'
|
|
30335
|
+
: 'These services behind the ALB are pinned to a deployed registry, but no Dockerfile was found under the app directory.';
|
|
30336
|
+
sec.appendChild(el('div', 'opt-hint', hint));
|
|
30337
|
+
return {
|
|
30338
|
+
node: sec,
|
|
30339
|
+
collect: function () {
|
|
30340
|
+
const map = {};
|
|
30341
|
+
rows.forEach(function (r) {
|
|
30342
|
+
const v = r.getValue();
|
|
30343
|
+
if (v !== '') map[r.id] = v;
|
|
30344
|
+
});
|
|
30345
|
+
return Object.keys(map).length ? map : undefined;
|
|
30346
|
+
},
|
|
30347
|
+
};
|
|
30348
|
+
}
|
|
30349
|
+
|
|
30268
30350
|
// Toggle one target group's body open/closed (groups are collapsed by
|
|
30269
30351
|
// default so a big Lambda list does not push the APIs below the fold).
|
|
30270
30352
|
function toggleGroup(titleEl, bodyEl) {
|
|
@@ -30350,7 +30432,13 @@ const STUDIO_SCRIPT = `
|
|
|
30350
30432
|
t.appendChild(btnSlot);
|
|
30351
30433
|
t.onclick = () => selectTarget(entry.id, group.kind);
|
|
30352
30434
|
targetEls.set(entry.id, t);
|
|
30353
|
-
serveMeta.set(entry.id, {
|
|
30435
|
+
serveMeta.set(entry.id, {
|
|
30436
|
+
dot,
|
|
30437
|
+
btnSlot,
|
|
30438
|
+
kind: group.kind,
|
|
30439
|
+
pinned: entry.pinned === true,
|
|
30440
|
+
backingPinnedServices: entry.backingPinnedServices || [],
|
|
30441
|
+
});
|
|
30354
30442
|
updateServeRow(entry.id);
|
|
30355
30443
|
}
|
|
30356
30444
|
body.appendChild(t);
|
|
@@ -30487,6 +30575,14 @@ const STUDIO_SCRIPT = `
|
|
|
30487
30575
|
if (applied && applied.imageOverride) {
|
|
30488
30576
|
lines.push('--image-override ' + applied.imageOverride);
|
|
30489
30577
|
}
|
|
30578
|
+
// An alb serve threads a per-backing-service imageOverrides map (issue
|
|
30579
|
+
// #382); surface one --image-override line each so the picks do not
|
|
30580
|
+
// silently vanish from the running view (the issue #356 contract).
|
|
30581
|
+
if (applied && applied.imageOverrides) {
|
|
30582
|
+
Object.keys(applied.imageOverrides).forEach(function (svc) {
|
|
30583
|
+
lines.push('--image-override ' + svc + '=' + applied.imageOverrides[svc]);
|
|
30584
|
+
});
|
|
30585
|
+
}
|
|
30490
30586
|
if (applied && applied.rawArgs) {
|
|
30491
30587
|
const raw = String(applied.rawArgs).trim();
|
|
30492
30588
|
if (raw !== '') lines.push(raw);
|
|
@@ -30494,7 +30590,7 @@ const STUDIO_SCRIPT = `
|
|
|
30494
30590
|
return lines;
|
|
30495
30591
|
}
|
|
30496
30592
|
|
|
30497
|
-
async function startServe(id, options, rawArgs, imageOverride) {
|
|
30593
|
+
async function startServe(id, options, rawArgs, imageOverride, imageOverrides) {
|
|
30498
30594
|
// The serve kind (api / alb / ecs) drives which headless command the
|
|
30499
30595
|
// server spawns; it is recorded on the row when the target list loads.
|
|
30500
30596
|
const meta = serveMeta.get(id);
|
|
@@ -30502,7 +30598,12 @@ const STUDIO_SCRIPT = `
|
|
|
30502
30598
|
// Remember what this serve was Started with so the running workspace can
|
|
30503
30599
|
// show a read-only "Started with" summary (issue #356) — the per-run
|
|
30504
30600
|
// option inputs are gone once the composer is replaced by the running view.
|
|
30505
|
-
serveApplied.set(id, {
|
|
30601
|
+
serveApplied.set(id, {
|
|
30602
|
+
options: options,
|
|
30603
|
+
rawArgs: rawArgs,
|
|
30604
|
+
imageOverride: imageOverride,
|
|
30605
|
+
imageOverrides: imageOverrides,
|
|
30606
|
+
});
|
|
30506
30607
|
serveState.set(id, { status: 'starting', endpoints: [] });
|
|
30507
30608
|
updateServeRow(id);
|
|
30508
30609
|
try {
|
|
@@ -30510,6 +30611,7 @@ const STUDIO_SCRIPT = `
|
|
|
30510
30611
|
if (options) body.options = options;
|
|
30511
30612
|
if (rawArgs) body.rawArgs = rawArgs;
|
|
30512
30613
|
if (imageOverride) body.imageOverride = imageOverride;
|
|
30614
|
+
if (imageOverrides) body.imageOverrides = imageOverrides;
|
|
30513
30615
|
const res = await fetch('/api/run', {
|
|
30514
30616
|
method: 'POST',
|
|
30515
30617
|
headers: { 'content-type': 'application/json' },
|
|
@@ -30585,6 +30687,7 @@ const STUDIO_SCRIPT = `
|
|
|
30585
30687
|
let collectOpts = function () { return undefined; };
|
|
30586
30688
|
let collectRaw = function () { return undefined; };
|
|
30587
30689
|
let collectImageOverride = function () { return undefined; };
|
|
30690
|
+
let collectImageOverrides = function () { return undefined; };
|
|
30588
30691
|
btn.onclick = () => {
|
|
30589
30692
|
if (running || starting) {
|
|
30590
30693
|
stopServe(id);
|
|
@@ -30595,7 +30698,7 @@ const STUDIO_SCRIPT = `
|
|
|
30595
30698
|
serveState.set(id, { status: 'stopped', endpoints: [] });
|
|
30596
30699
|
renderServeWorkspace(id);
|
|
30597
30700
|
} else {
|
|
30598
|
-
startServe(id, collectOpts(), collectRaw(), collectImageOverride());
|
|
30701
|
+
startServe(id, collectOpts(), collectRaw(), collectImageOverride(), collectImageOverrides());
|
|
30599
30702
|
}
|
|
30600
30703
|
};
|
|
30601
30704
|
head.appendChild(btn);
|
|
@@ -30615,6 +30718,15 @@ const STUDIO_SCRIPT = `
|
|
|
30615
30718
|
ws.appendChild(io.node);
|
|
30616
30719
|
collectImageOverride = io.collect;
|
|
30617
30720
|
}
|
|
30721
|
+
// An ALB boots its backing ECS services (issue #382); a pinned backing
|
|
30722
|
+
// service has the same "local edits do not take effect" problem, so offer
|
|
30723
|
+
// a per-service Dockerfile picker that threads
|
|
30724
|
+
// --image-override service=dockerfile to start-alb.
|
|
30725
|
+
if (meta && meta.kind === 'alb' && meta.backingPinnedServices && meta.backingPinnedServices.length) {
|
|
30726
|
+
const io = buildAlbImageOverridePicker(meta.backingPinnedServices);
|
|
30727
|
+
ws.appendChild(io.node);
|
|
30728
|
+
collectImageOverrides = io.collect;
|
|
30729
|
+
}
|
|
30618
30730
|
const opt = buildOptions(kind);
|
|
30619
30731
|
if (opt.node) ws.appendChild(opt.node);
|
|
30620
30732
|
collectOpts = opt.collect;
|
|
@@ -31798,6 +31910,34 @@ function annotatePinnedEcsTargets(groups, classify) {
|
|
|
31798
31910
|
}
|
|
31799
31911
|
return anyPinned;
|
|
31800
31912
|
}
|
|
31913
|
+
/**
|
|
31914
|
+
* Annotate each `alb` entry of `groups` with the deployed-registry-pinned ECS
|
|
31915
|
+
* services that ALB fronts (issue #382), so the alb composer can offer a
|
|
31916
|
+
* per-service image-override Dockerfile picker. `resolveBackingPinned` maps one
|
|
31917
|
+
* ALB entry to its pinned backing services (`{ id, label }`, where `id` is the
|
|
31918
|
+
* `--image-override` key — `start-alb`'s `Stack:LogicalId` service-boot
|
|
31919
|
+
* target); the caller supplies it (studio's boot resolves the ALB via
|
|
31920
|
+
* `resolveAlbFrontDoor` and intersects the backing services with the already-
|
|
31921
|
+
* classified pinned `ecs` set). Mutates the entries in place and returns whether
|
|
31922
|
+
* ANY ALB fronts a pinned service, so the caller can include the Dockerfile
|
|
31923
|
+
* scan even when no standalone `ecs` service was pinned. Non-alb groups are
|
|
31924
|
+
* left untouched. Exported so a host CLI can reuse it + so the boot logic is
|
|
31925
|
+
* unit-testable without a real synth.
|
|
31926
|
+
*/
|
|
31927
|
+
function annotateAlbPinnedBackingServices(groups, resolveBackingPinned) {
|
|
31928
|
+
let any = false;
|
|
31929
|
+
for (const group of groups) {
|
|
31930
|
+
if (group.kind !== "alb") continue;
|
|
31931
|
+
for (const entry of group.entries) {
|
|
31932
|
+
const pinned = resolveBackingPinned(entry);
|
|
31933
|
+
if (pinned.length > 0) {
|
|
31934
|
+
entry.backingPinnedServices = pinned;
|
|
31935
|
+
any = true;
|
|
31936
|
+
}
|
|
31937
|
+
}
|
|
31938
|
+
}
|
|
31939
|
+
return any;
|
|
31940
|
+
}
|
|
31801
31941
|
/** Compile a `*` / `?` glob to an anchored RegExp matched against a target id. */
|
|
31802
31942
|
function globToRegExp(glob) {
|
|
31803
31943
|
const escaped = glob.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
@@ -32911,6 +33051,7 @@ function createStudioServeManager(config) {
|
|
|
32911
33051
|
...buildPerRunArgs(req.kind, req.options),
|
|
32912
33052
|
...envFile ? ["--env-vars", envFile] : [],
|
|
32913
33053
|
...req.imageOverride && req.imageOverride.trim() !== "" ? ["--image-override", req.targetId + "=" + req.imageOverride.trim()] : [],
|
|
33054
|
+
...Object.entries(req.imageOverrides ?? {}).flatMap(([svc, df]) => df && df.trim() !== "" ? ["--image-override", svc + "=" + df.trim()] : []),
|
|
32914
33055
|
...config.watch === true ? ["--watch"] : [],
|
|
32915
33056
|
...tokenizeRawArgs(req.rawArgs)
|
|
32916
33057
|
];
|
|
@@ -33156,7 +33297,7 @@ const STUDIO_TARGET_KINDS = [
|
|
|
33156
33297
|
*/
|
|
33157
33298
|
function coerceRunRequest(body) {
|
|
33158
33299
|
if (typeof body !== "object" || body === null) throw new Error("Request body must be a JSON object.");
|
|
33159
|
-
const { targetId, kind, event, options, rawArgs, imageOverride } = body;
|
|
33300
|
+
const { targetId, kind, event, options, rawArgs, imageOverride, imageOverrides } = body;
|
|
33160
33301
|
if (typeof targetId !== "string" || targetId.trim() === "") throw new Error("Request body must include a non-empty \"targetId\" string.");
|
|
33161
33302
|
if (typeof kind !== "string" || !STUDIO_TARGET_KINDS.includes(kind)) throw new Error(`Request body "kind" must be one of: ${STUDIO_TARGET_KINDS.join(", ")}.`);
|
|
33162
33303
|
let runOptions;
|
|
@@ -33177,13 +33318,24 @@ function coerceRunRequest(body) {
|
|
|
33177
33318
|
if (typeof imageOverride !== "string") throw new Error("Request body \"imageOverride\" must be a string.");
|
|
33178
33319
|
if (imageOverride.trim() !== "") runImageOverride = imageOverride;
|
|
33179
33320
|
}
|
|
33321
|
+
let runImageOverrides;
|
|
33322
|
+
if (imageOverrides !== void 0) {
|
|
33323
|
+
if (typeof imageOverrides !== "object" || imageOverrides === null || Array.isArray(imageOverrides)) throw new Error("Request body \"imageOverrides\" must be a JSON object keyed by service id.");
|
|
33324
|
+
const collected = {};
|
|
33325
|
+
for (const [svc, df] of Object.entries(imageOverrides)) {
|
|
33326
|
+
if (typeof df !== "string") throw new Error(`Request body "imageOverrides.${svc}" must be a string.`);
|
|
33327
|
+
if (df.trim() !== "") collected[svc] = df.trim();
|
|
33328
|
+
}
|
|
33329
|
+
if (Object.keys(collected).length > 0) runImageOverrides = collected;
|
|
33330
|
+
}
|
|
33180
33331
|
return {
|
|
33181
33332
|
targetId,
|
|
33182
33333
|
kind,
|
|
33183
33334
|
event,
|
|
33184
33335
|
...runOptions !== void 0 ? { options: runOptions } : {},
|
|
33185
33336
|
...runRawArgs !== void 0 ? { rawArgs: runRawArgs } : {},
|
|
33186
|
-
...runImageOverride !== void 0 ? { imageOverride: runImageOverride } : {}
|
|
33337
|
+
...runImageOverride !== void 0 ? { imageOverride: runImageOverride } : {},
|
|
33338
|
+
...runImageOverrides !== void 0 ? { imageOverrides: runImageOverrides } : {}
|
|
33187
33339
|
};
|
|
33188
33340
|
}
|
|
33189
33341
|
/**
|
|
@@ -33463,6 +33615,48 @@ function makePinClassifier(args) {
|
|
|
33463
33615
|
}
|
|
33464
33616
|
};
|
|
33465
33617
|
}
|
|
33618
|
+
/**
|
|
33619
|
+
* Build the boot-time resolver `annotateAlbPinnedBackingServices` calls per
|
|
33620
|
+
* `alb` entry (issue #382). It resolves the ALB to its backing ECS services
|
|
33621
|
+
* (`resolveAlbFrontDoor`, template-only) and returns the subset that is in
|
|
33622
|
+
* `pinnedEcsByQualifiedId` — the `ecs` services already classified as a
|
|
33623
|
+
* deployed-registry pin by {@link makePinClassifier}. Each returned `id` is the
|
|
33624
|
+
* service's `Stack:LogicalId` (the `--image-override` key `start-alb` matches
|
|
33625
|
+
* against its own service-boot target); `label` is the pinned service's display
|
|
33626
|
+
* id. An ALB that cannot be resolved is WARN-logged + contributes no pickers
|
|
33627
|
+
* (the start-alb run still works; only the picker is absent). Exported for
|
|
33628
|
+
* testing.
|
|
33629
|
+
*/
|
|
33630
|
+
function makeAlbBackingPinnedResolver(args) {
|
|
33631
|
+
const { stacks, pinnedEcsByQualifiedId, logger } = args;
|
|
33632
|
+
return (albEntry) => {
|
|
33633
|
+
if (pinnedEcsByQualifiedId.size === 0) return [];
|
|
33634
|
+
try {
|
|
33635
|
+
const { stack, albLogicalId } = resolveAlbTarget(albEntry.id, stacks);
|
|
33636
|
+
const resolution = resolveAlbFrontDoor(stack, albLogicalId);
|
|
33637
|
+
const serviceQualifiedIds = /* @__PURE__ */ new Set();
|
|
33638
|
+
for (const listener of resolution.listeners) {
|
|
33639
|
+
const actions = [...listener.defaultAction ? [listener.defaultAction] : [], ...listener.rules.map((r) => r.action)];
|
|
33640
|
+
for (const action of actions) {
|
|
33641
|
+
if (action.kind !== "forward") continue;
|
|
33642
|
+
for (const t of action.targets) if (t.kind === "ecs") serviceQualifiedIds.add(`${stack.stackName}:${t.serviceLogicalId}`);
|
|
33643
|
+
}
|
|
33644
|
+
}
|
|
33645
|
+
const out = [];
|
|
33646
|
+
for (const qid of serviceQualifiedIds) {
|
|
33647
|
+
const label = pinnedEcsByQualifiedId.get(qid);
|
|
33648
|
+
if (label !== void 0) out.push({
|
|
33649
|
+
id: qid,
|
|
33650
|
+
label
|
|
33651
|
+
});
|
|
33652
|
+
}
|
|
33653
|
+
return out;
|
|
33654
|
+
} catch (err) {
|
|
33655
|
+
logger.warn(`studio: could not resolve ALB '${albEntry.id}' backing services for the image-override picker; the alb composer will not offer one. ${err instanceof Error ? err.message : String(err)}`);
|
|
33656
|
+
return [];
|
|
33657
|
+
}
|
|
33658
|
+
};
|
|
33659
|
+
}
|
|
33466
33660
|
async function localStudioCommand(options) {
|
|
33467
33661
|
const logger = getLogger();
|
|
33468
33662
|
if (options.verbose) logger.setLevel("debug");
|
|
@@ -33499,7 +33693,7 @@ async function localStudioCommand(options) {
|
|
|
33499
33693
|
}
|
|
33500
33694
|
const appLabel = stacks.map((s) => s.stackName).join(", ") || appCmd;
|
|
33501
33695
|
const servableEcs = new Set(targetGroups.filter((g) => g.kind === "ecs").flatMap((g) => g.entries.filter((e) => e.servable).map((e) => e.id)));
|
|
33502
|
-
const
|
|
33696
|
+
const anyPinned = annotatePinnedEcsTargets(targetGroups, makePinClassifier({
|
|
33503
33697
|
stacks,
|
|
33504
33698
|
contextByStack: await prepareEcsImageContexts({
|
|
33505
33699
|
serviceIds: [...servableEcs],
|
|
@@ -33508,7 +33702,18 @@ async function localStudioCommand(options) {
|
|
|
33508
33702
|
logger
|
|
33509
33703
|
}),
|
|
33510
33704
|
logger
|
|
33511
|
-
}))
|
|
33705
|
+
}));
|
|
33706
|
+
const pinnedEcsByQualifiedId = /* @__PURE__ */ new Map();
|
|
33707
|
+
for (const g of targetGroups) {
|
|
33708
|
+
if (g.kind !== "ecs") continue;
|
|
33709
|
+
for (const e of g.entries) if (e.pinned) pinnedEcsByQualifiedId.set(e.qualifiedId, e.id);
|
|
33710
|
+
}
|
|
33711
|
+
const anyAlbBackingPinned = annotateAlbPinnedBackingServices(targetGroups, makeAlbBackingPinnedResolver({
|
|
33712
|
+
stacks,
|
|
33713
|
+
pinnedEcsByQualifiedId,
|
|
33714
|
+
logger
|
|
33715
|
+
}));
|
|
33716
|
+
const dockerfiles = anyPinned || anyAlbBackingPinned ? discoverDockerfiles(process.cwd()) : [];
|
|
33512
33717
|
const bus = new StudioEventBus();
|
|
33513
33718
|
const childConfig = {
|
|
33514
33719
|
cliEntry: process.argv[1] ?? "",
|
|
@@ -33690,5 +33895,5 @@ function addStudioSpecificOptions(cmd) {
|
|
|
33690
33895
|
}
|
|
33691
33896
|
|
|
33692
33897
|
//#endregion
|
|
33693
|
-
export {
|
|
33694
|
-
//# sourceMappingURL=local-studio-
|
|
33898
|
+
export { createLocalRunTaskCommand as $, buildDisconnectEvent as $n, addStartApiSpecificOptions as $t, matchBehavior as A, applyCorsResponseHeaders as An, webSocketApiMatchesIdentifier as Ar, invokeAgentCoreWs as At, runViewerRequest as B, evaluateResponseParameters as Bn, pickAgentCoreCandidateStack as Br, signAgentCoreInvocation as Bt, createLocalListCommand as C, verifyJwtViaDiscovery as Cn, countTargets as Cr, DEFAULT_SHADOW_READY_TIMEOUT_MS as Ct, createLocalStartCloudFrontCommand as D, invokeRequestAuthorizer as Dn, discoverWebSocketApisOrThrow as Dr, attachContainerLogStreamer as Dt, addStartCloudFrontSpecificOptions as E, evaluateCachedLambdaPolicy as En, discoverWebSocketApis as Er, getContainerNetworkIp as Et, isCloudFrontDistribution as F, matchRoute as Fn, AGENTCORE_AGUI_PROTOCOL as Fr, MCP_PATH as Ft, parseLbPortOverrides as G, HOST_GATEWAY_MIN_VERSION as Gn, tryResolveImageFnJoin as Gr, SUPPORTED_CODE_RUNTIMES as Gt, addAlbSpecificOptions as H, selectIntegrationResponse as Hn, derivePseudoParametersFromRegion as Hr, invokeAgentCore as Ht, pickFunctionUrlLogicalIdFromOrigin as I, translateLambdaResponse as In, AGENTCORE_HTTP_PROTOCOL as Ir, MCP_PROTOCOL_VERSION as It, resolveAlbFrontDoor as J, ConnectionRegistry as Jn, resolveProfileCredentials as Jr, renderCodeDockerfile as Jt, resolveAlbTarget as K, probeHostGatewaySupport as Kn, LocalInvokeBuildError as Kr, buildAgentCoreCodeImage as Kt, pickTargetFunctionLogicalId as L, applyAuthorizerOverlay as Ln, AGENTCORE_MCP_PROTOCOL as Lr, mcpInvokeOnce as Lt, serveFromStaticOrigin as M, buildCorsConfigFromCloudFrontChain as Mn, pickRefLogicalId as Mr, A2A_PATH as Mt, serveLambdaUrlOrigin as N, isFunctionUrlOacFronted as Nn, resolveLambdaArnIntrinsic as Nr, a2aInvokeOnce as Nt, parseOriginOverrides as O, invokeTokenAuthorizer as On, filterWebSocketApisByIdentifiers as Or, addInvokeAgentCoreSpecificOptions as Ot, CLOUDFRONT_DISTRIBUTION_TYPE as P, matchPreflight as Pn, AGENTCORE_A2A_PROTOCOL as Pr, MCP_CONTAINER_PORT as Pt, addRunTaskSpecificOptions as Q, buildConnectEvent as Qn, createLocalInvokeCommand as Qt, resolveCloudFrontDistribution as R, buildHttpApiV2Event as Rn, AGENTCORE_RUNTIME_TYPE as Rr, parseSseForJsonRpc as Rt, addListSpecificOptions as S, verifyJwtAuthorizer as Sn, resolveSingleTarget as Sr, CloudMapRegistry as St, LocalStartCloudFrontError as T, computeRequestIdentityHash as Tn, availableWebSocketApiIdentifiers as Tr, setShadowReadyTimeoutMs as Tt, albStrategy as U, tryParseStatus as Un, formatStateRemedy as Ur, waitForAgentCorePing as Ut, runViewerResponse as V, pickResponseTemplate as Vn, resolveAgentCoreTarget as Vr, AGENTCORE_SESSION_ID_HEADER as Vt, createLocalStartAlbCommand as W, VtlEvaluationError as Wn, substituteImagePlaceholders as Wr, downloadAndExtractS3Bundle as Wt, createLocalStartServiceCommand as X, handleConnectionsRequest as Xn, classifySourceChange as Xt, addStartServiceSpecificOptions as Y, buildMgmtEndpointEnvUrl as Yn, toCmdArgv as Yt, serviceStrategy as Z, parseConnectionsPath as Zn, addInvokeSpecificOptions as Zt, startStudioServer as _, defaultCredentialsLoader as _n, resolveCfnStackName as _r, runImageOverrideBuilds as _t, createLocalStudioCommand as a, attachStageContext as an, resolveRuntimeImage as ar, ecsClusterOption as at, createStudioStore as b, createJwksCache as bn, resolveSsmParameters as br, listPinnedTargets as bt, startStudioProxy as c, resolveEnvVars$1 as cn, substituteAgainstStateAsync as cr, resolveEcsAssumeRoleOption as ct, createStudioDispatcher as d, filterRoutesByApiIdentifiers as dn, LocalStateSourceError as dr, ImageOverrideError as dt, createLocalStartApiCommand as en, buildMessageEvent as er, MAX_TASKS_SUBNET_RANGE_CAP as et, filterStudioCustomResources as f, groupRoutesByServer as fn, createLocalStateProvider as fr, buildImageOverrideTag as ft, filterStudioTargetGroups as g, resolveServiceIntegrationParameters as gn, resolveCfnRegion as gr, resolveImageOverrides as gt, annotatePinnedEcsTargets as h, resolveSelectionExpression as hn, resolveCfnFallbackRegion as hr, parseImageOverrideFlags as ht, coerceStopRequest as i, createFileWatcher as in, resolveRuntimeFileExtension as ir, buildEcsImageResolutionContext$1 as it, startCloudFrontServer as j, buildCorsConfigByApiId as jn, discoverRoutes as jr, A2A_CONTAINER_PORT as jt, resolveCloudFrontTarget as k, attachAuthorizers as kn, parseSelectionExpressionPath as kr, createLocalInvokeAgentCoreCommand as kt, relayServeRequest as l, availableApiIdentifiers as ln, substituteEnvVarsFromState as lr, resolveSharedSidecarCredentials as lt, annotateAlbPinnedBackingServices as m, startApiServer as mn, rejectExplicitCfnStackWithMultipleStacks as mr, mergeForService as mt, coerceRunRequest as n, resolveApiTargetSubset as nn, buildContainerImage as nr, addEcsAssumeRoleOptions as nt, resolveServeBaseUrl as o, buildStageMap as on, EcsTaskResolutionError as or, parseMaxTasks as ot, isCustomResourceLambdaTarget as p, readMtlsMaterialsFromDisk as pn, isCfnFlagPresent as pr, enforceImageOverrideOrphans as pt, isApplicationLoadBalancer as q, bufferToBody as qn, buildStsClientConfig as qr, computeCodeImageTag as qt, coerceServeRequest as r, createAuthorizerCache as rn, resolveRuntimeCodeMountPath as rr, addImageOverrideOptions as rt, createStudioServeManager as s, materializeLayerFromArn as sn, substituteAgainstState as sr, parseRestartPolicy as st, addStudioSpecificOptions as t, createWatchPredicates as tn, architectureToPlatform as tr, addCommonEcsServiceOptions as tt, reinvoke as u, filterRoutesByApiIdentifier as un, substituteEnvVarsFromStateAsync as ur, runEcsServiceEmulator as ut, toStudioTargetGroups as v, buildCognitoJwksUrl as vn, CfnLocalStateProvider as vr, describePinnedImageUri as vt, formatTargetListing as w, buildMethodArn as wn, listTargets as wr, SOFT_RELOAD_COMPLETION_LOG_SUFFIX as wt, StudioEventBus as x, verifyCognitoJwt as xn, resolveWatchConfig as xr, buildCloudMapIndex as xt, renderStudioHtml as y, buildJwksUrlFromIssuer as yn, collectSsmParameterRefs as yr, isLocalCdkAssetImage as yt, compileCloudFrontFunction as z, buildRestV1Event as zn, AgentCoreResolutionError as zr, AGENTCORE_SIGV4_SERVICE as zt };
|
|
33899
|
+
//# sourceMappingURL=local-studio-CxVVLdJw.js.map
|