@effortless-aws/cli 0.1.1 → 0.2.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/index.js +416 -286
- package/package.json +2 -2
package/dist/cli/index.js
CHANGED
|
@@ -6,15 +6,15 @@ var __export = (target, all) => {
|
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
// src/cli/index.ts
|
|
9
|
-
import { Command as Command7 } from "@effect/cli";
|
|
9
|
+
import { CliConfig, Command as Command7 } from "@effect/cli";
|
|
10
10
|
import { NodeContext, NodeRuntime } from "@effect/platform-node";
|
|
11
|
-
import { Effect as
|
|
11
|
+
import { Effect as Effect45 } from "effect";
|
|
12
12
|
import { createRequire as createRequire2 } from "module";
|
|
13
13
|
|
|
14
14
|
// src/cli/commands/deploy.ts
|
|
15
15
|
import { Args, Command } from "@effect/cli";
|
|
16
|
-
import { Effect as
|
|
17
|
-
import * as
|
|
16
|
+
import { Effect as Effect38, Console as Console3, Logger, LogLevel, Option } from "effect";
|
|
17
|
+
import * as path9 from "path";
|
|
18
18
|
|
|
19
19
|
// src/deploy/deploy.ts
|
|
20
20
|
import { Effect as Effect35, Console as Console2 } from "effect";
|
|
@@ -2628,6 +2628,64 @@ var readProductionDependencies = (projectDir) => Effect18.gen(function* () {
|
|
|
2628
2628
|
const pkg = JSON.parse(content);
|
|
2629
2629
|
return Object.keys(pkg.dependencies ?? {});
|
|
2630
2630
|
});
|
|
2631
|
+
var DEV_ONLY_PACKAGES = /* @__PURE__ */ new Set([
|
|
2632
|
+
"typescript",
|
|
2633
|
+
"ts-node",
|
|
2634
|
+
"tsx",
|
|
2635
|
+
"vitest",
|
|
2636
|
+
"jest",
|
|
2637
|
+
"mocha",
|
|
2638
|
+
"eslint",
|
|
2639
|
+
"prettier",
|
|
2640
|
+
"tsup",
|
|
2641
|
+
"esbuild",
|
|
2642
|
+
"webpack",
|
|
2643
|
+
"rollup",
|
|
2644
|
+
"vite",
|
|
2645
|
+
"turbo",
|
|
2646
|
+
"husky",
|
|
2647
|
+
"lint-staged",
|
|
2648
|
+
"commitlint",
|
|
2649
|
+
"nodemon",
|
|
2650
|
+
"ts-jest",
|
|
2651
|
+
"concurrently",
|
|
2652
|
+
"rimraf"
|
|
2653
|
+
]);
|
|
2654
|
+
var DEV_ONLY_PREFIXES = [
|
|
2655
|
+
"@types/",
|
|
2656
|
+
"@typescript-eslint/",
|
|
2657
|
+
"@eslint/",
|
|
2658
|
+
"eslint-plugin-",
|
|
2659
|
+
"eslint-config-",
|
|
2660
|
+
"@vitest/",
|
|
2661
|
+
"@jest/"
|
|
2662
|
+
];
|
|
2663
|
+
var checkDependencyWarnings = (projectDir) => Effect18.gen(function* () {
|
|
2664
|
+
const pkgPath = path.join(projectDir, "package.json");
|
|
2665
|
+
const content = yield* Effect18.tryPromise({
|
|
2666
|
+
try: () => fs.readFile(pkgPath, "utf-8"),
|
|
2667
|
+
catch: () => Effect18.succeed(null)
|
|
2668
|
+
});
|
|
2669
|
+
if (!content) return [];
|
|
2670
|
+
const pkg = JSON.parse(content);
|
|
2671
|
+
const deps = Object.keys(pkg.dependencies ?? {});
|
|
2672
|
+
const devDeps = Object.keys(pkg.devDependencies ?? {});
|
|
2673
|
+
const warnings = [];
|
|
2674
|
+
const devInProd = deps.filter(
|
|
2675
|
+
(d) => DEV_ONLY_PACKAGES.has(d) || DEV_ONLY_PREFIXES.some((p) => d.startsWith(p))
|
|
2676
|
+
);
|
|
2677
|
+
if (devInProd.length > 0) {
|
|
2678
|
+
warnings.push(
|
|
2679
|
+
`These packages are in "dependencies" but look like dev tools (they will bloat the Lambda layer): ${devInProd.join(", ")}. Consider moving them to "devDependencies".`
|
|
2680
|
+
);
|
|
2681
|
+
}
|
|
2682
|
+
if (deps.length === 0 && devDeps.length > 0) {
|
|
2683
|
+
warnings.push(
|
|
2684
|
+
`"dependencies" is empty but "devDependencies" has ${devDeps.length} package(s). Runtime packages must be in "dependencies" to be included in the Lambda layer.`
|
|
2685
|
+
);
|
|
2686
|
+
}
|
|
2687
|
+
return warnings;
|
|
2688
|
+
});
|
|
2631
2689
|
var getPackageRealPath = (projectDir, pkgName) => {
|
|
2632
2690
|
const pkgPath = path.join(projectDir, "node_modules", pkgName);
|
|
2633
2691
|
if (!fsSync.existsSync(pkgPath)) return null;
|
|
@@ -2816,6 +2874,12 @@ var getExistingLayerByHash = (layerName, expectedHash) => Effect18.gen(function*
|
|
|
2816
2874
|
};
|
|
2817
2875
|
});
|
|
2818
2876
|
var ensureLayer = (config) => Effect18.gen(function* () {
|
|
2877
|
+
const depWarnings = yield* checkDependencyWarnings(config.projectDir).pipe(
|
|
2878
|
+
Effect18.catchAll(() => Effect18.succeed([]))
|
|
2879
|
+
);
|
|
2880
|
+
for (const w of depWarnings) {
|
|
2881
|
+
yield* Effect18.logWarning(`[layer] ${w}`);
|
|
2882
|
+
}
|
|
2819
2883
|
const dependencies = yield* readProductionDependencies(config.projectDir).pipe(
|
|
2820
2884
|
Effect18.catchAll(() => Effect18.succeed([]))
|
|
2821
2885
|
);
|
|
@@ -3524,7 +3588,7 @@ var ensureDistribution = (input) => Effect21.gen(function* () {
|
|
|
3524
3588
|
};
|
|
3525
3589
|
});
|
|
3526
3590
|
var ensureSsrDistribution = (input) => Effect21.gen(function* () {
|
|
3527
|
-
const { project, stage, handlerName, bucketName, bucketRegion, s3OacId, lambdaOriginDomain, lambdaOacId, assetPatterns, tags, aliases, acmCertificateArn } = input;
|
|
3591
|
+
const { project, stage, handlerName, bucketName, bucketRegion, s3OacId, lambdaOriginDomain, lambdaOacId, assetPatterns, tags, aliases, acmCertificateArn, apiOriginDomain, routePatterns } = input;
|
|
3528
3592
|
const comment = makeDistComment(project, stage, handlerName);
|
|
3529
3593
|
const lambdaOriginId = `Lambda-${project}-${stage}-${handlerName}`;
|
|
3530
3594
|
const s3OriginId = `S3-${bucketName}`;
|
|
@@ -3537,6 +3601,8 @@ var ensureSsrDistribution = (input) => Effect21.gen(function* () {
|
|
|
3537
3601
|
} : void 0;
|
|
3538
3602
|
const ALL_METHODS = ["GET", "HEAD", "OPTIONS", "PUT", "POST", "PATCH", "DELETE"];
|
|
3539
3603
|
const CACHED_METHODS = ["GET", "HEAD"];
|
|
3604
|
+
const hasApiRoutes = apiOriginDomain && routePatterns && routePatterns.length > 0;
|
|
3605
|
+
const apiOriginId = hasApiRoutes ? `API-${project}-${stage}` : void 0;
|
|
3540
3606
|
const originsItems = [
|
|
3541
3607
|
{
|
|
3542
3608
|
Id: lambdaOriginId,
|
|
@@ -3560,7 +3626,23 @@ var ensureSsrDistribution = (input) => Effect21.gen(function* () {
|
|
|
3560
3626
|
OriginAccessControlId: s3OacId,
|
|
3561
3627
|
S3OriginConfig: { OriginAccessIdentity: "" },
|
|
3562
3628
|
CustomHeaders: { Quantity: 0, Items: [] }
|
|
3563
|
-
}
|
|
3629
|
+
},
|
|
3630
|
+
...hasApiRoutes ? [{
|
|
3631
|
+
Id: apiOriginId,
|
|
3632
|
+
DomainName: apiOriginDomain,
|
|
3633
|
+
OriginPath: "",
|
|
3634
|
+
ConnectionAttempts: 3,
|
|
3635
|
+
ConnectionTimeout: 10,
|
|
3636
|
+
CustomOriginConfig: {
|
|
3637
|
+
HTTPPort: 80,
|
|
3638
|
+
HTTPSPort: 443,
|
|
3639
|
+
OriginProtocolPolicy: "https-only",
|
|
3640
|
+
OriginSslProtocols: { Quantity: 1, Items: ["TLSv1.2"] },
|
|
3641
|
+
OriginReadTimeout: 30,
|
|
3642
|
+
OriginKeepaliveTimeout: 5
|
|
3643
|
+
},
|
|
3644
|
+
CustomHeaders: { Quantity: 0, Items: [] }
|
|
3645
|
+
}] : []
|
|
3564
3646
|
];
|
|
3565
3647
|
const defaultCacheBehavior = {
|
|
3566
3648
|
TargetOriginId: lambdaOriginId,
|
|
@@ -3579,26 +3661,42 @@ var ensureSsrDistribution = (input) => Effect21.gen(function* () {
|
|
|
3579
3661
|
LambdaFunctionAssociations: { Quantity: 0, Items: [] },
|
|
3580
3662
|
FieldLevelEncryptionId: ""
|
|
3581
3663
|
};
|
|
3582
|
-
const
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3664
|
+
const apiRouteBehaviors = hasApiRoutes ? routePatterns.map((pattern) => ({
|
|
3665
|
+
PathPattern: pattern,
|
|
3666
|
+
TargetOriginId: apiOriginId,
|
|
3667
|
+
ViewerProtocolPolicy: "redirect-to-https",
|
|
3668
|
+
AllowedMethods: {
|
|
3669
|
+
Quantity: 7,
|
|
3670
|
+
Items: [...ALL_METHODS],
|
|
3671
|
+
CachedMethods: { Quantity: 2, Items: [...CACHED_METHODS] }
|
|
3672
|
+
},
|
|
3673
|
+
Compress: true,
|
|
3674
|
+
SmoothStreaming: false,
|
|
3675
|
+
CachePolicyId: CACHING_DISABLED_POLICY_ID,
|
|
3676
|
+
OriginRequestPolicyId: ALL_VIEWER_EXCEPT_HOST_HEADER_POLICY_ID,
|
|
3677
|
+
FunctionAssociations: { Quantity: 0, Items: [] },
|
|
3678
|
+
LambdaFunctionAssociations: { Quantity: 0, Items: [] },
|
|
3679
|
+
FieldLevelEncryptionId: ""
|
|
3680
|
+
})) : [];
|
|
3681
|
+
const assetBehaviors = assetPatterns.map((pattern) => ({
|
|
3682
|
+
PathPattern: pattern,
|
|
3683
|
+
TargetOriginId: s3OriginId,
|
|
3684
|
+
ViewerProtocolPolicy: "redirect-to-https",
|
|
3685
|
+
AllowedMethods: {
|
|
3686
|
+
Quantity: 2,
|
|
3687
|
+
Items: [...CACHED_METHODS],
|
|
3688
|
+
CachedMethods: { Quantity: 2, Items: [...CACHED_METHODS] }
|
|
3689
|
+
},
|
|
3690
|
+
Compress: true,
|
|
3691
|
+
SmoothStreaming: false,
|
|
3692
|
+
CachePolicyId: CACHING_OPTIMIZED_POLICY_ID,
|
|
3693
|
+
ResponseHeadersPolicyId: SECURITY_HEADERS_POLICY_ID,
|
|
3694
|
+
FunctionAssociations: { Quantity: 0, Items: [] },
|
|
3695
|
+
LambdaFunctionAssociations: { Quantity: 0, Items: [] },
|
|
3696
|
+
FieldLevelEncryptionId: ""
|
|
3697
|
+
}));
|
|
3698
|
+
const allBehaviors = [...apiRouteBehaviors, ...assetBehaviors];
|
|
3699
|
+
const cacheBehaviors = allBehaviors.length > 0 ? { Quantity: allBehaviors.length, Items: allBehaviors } : { Quantity: 0, Items: [] };
|
|
3602
3700
|
const existing = yield* findDistributionByTags(project, stage, handlerName);
|
|
3603
3701
|
if (existing) {
|
|
3604
3702
|
const configResult = yield* cloudfront_exports.make("get_distribution_config", {
|
|
@@ -4375,6 +4473,19 @@ var discoverHandlers = (files) => {
|
|
|
4375
4473
|
}
|
|
4376
4474
|
return { httpHandlers, tableHandlers, appHandlers, staticSiteHandlers, fifoQueueHandlers, bucketHandlers, mailerHandlers, apiHandlers };
|
|
4377
4475
|
};
|
|
4476
|
+
var flattenHandlers = (discovered) => {
|
|
4477
|
+
const entries = (type, handlers) => handlers.flatMap((h) => h.exports.map((e) => ({ exportName: e.exportName, file: h.file, type })));
|
|
4478
|
+
return [
|
|
4479
|
+
...entries("http", discovered.httpHandlers),
|
|
4480
|
+
...entries("table", discovered.tableHandlers),
|
|
4481
|
+
...entries("app", discovered.appHandlers),
|
|
4482
|
+
...entries("site", discovered.staticSiteHandlers),
|
|
4483
|
+
...entries("queue", discovered.fifoQueueHandlers),
|
|
4484
|
+
...entries("bucket", discovered.bucketHandlers),
|
|
4485
|
+
...entries("mailer", discovered.mailerHandlers),
|
|
4486
|
+
...entries("api", discovered.apiHandlers)
|
|
4487
|
+
];
|
|
4488
|
+
};
|
|
4378
4489
|
|
|
4379
4490
|
// src/deploy/resolve-config.ts
|
|
4380
4491
|
import { Effect as Effect25 } from "effect";
|
|
@@ -4448,10 +4559,10 @@ var ensureLayerAndExternal = (input) => Effect26.gen(function* () {
|
|
|
4448
4559
|
project: input.project,
|
|
4449
4560
|
stage: input.stage,
|
|
4450
4561
|
region: input.region,
|
|
4451
|
-
projectDir: input.
|
|
4562
|
+
projectDir: input.packageDir
|
|
4452
4563
|
});
|
|
4453
|
-
const prodDeps = layerResult ? yield* readProductionDependencies(input.
|
|
4454
|
-
const { packages: external, warnings: layerWarnings } = prodDeps.length > 0 ? yield* Effect26.sync(() => collectLayerPackages(input.
|
|
4564
|
+
const prodDeps = layerResult ? yield* readProductionDependencies(input.packageDir) : [];
|
|
4565
|
+
const { packages: external, warnings: layerWarnings } = prodDeps.length > 0 ? yield* Effect26.sync(() => collectLayerPackages(input.packageDir, prodDeps)) : { packages: [], warnings: [] };
|
|
4455
4566
|
for (const warning of layerWarnings) {
|
|
4456
4567
|
yield* Effect26.logWarning(`[layer] ${warning}`);
|
|
4457
4568
|
}
|
|
@@ -4566,7 +4677,7 @@ var deploy = (input) => Effect27.gen(function* () {
|
|
|
4566
4677
|
project: input.project,
|
|
4567
4678
|
stage: tagCtx.stage,
|
|
4568
4679
|
region: input.region,
|
|
4569
|
-
|
|
4680
|
+
packageDir: input.packageDir ?? input.projectDir
|
|
4570
4681
|
});
|
|
4571
4682
|
const { functionArn } = yield* deployLambda({
|
|
4572
4683
|
input,
|
|
@@ -4619,7 +4730,7 @@ var deployAll = (input) => Effect27.gen(function* () {
|
|
|
4619
4730
|
project: input.project,
|
|
4620
4731
|
stage: tagCtx.stage,
|
|
4621
4732
|
region: input.region,
|
|
4622
|
-
|
|
4733
|
+
packageDir: input.packageDir ?? input.projectDir
|
|
4623
4734
|
});
|
|
4624
4735
|
yield* Effect27.logDebug("Setting up API Gateway...");
|
|
4625
4736
|
const { apiId } = yield* ensureProjectApi({
|
|
@@ -4731,7 +4842,7 @@ var deployTable = (input) => Effect28.gen(function* () {
|
|
|
4731
4842
|
project: input.project,
|
|
4732
4843
|
stage: resolveStage(input.stage),
|
|
4733
4844
|
region: input.region,
|
|
4734
|
-
|
|
4845
|
+
packageDir: input.packageDir ?? input.projectDir
|
|
4735
4846
|
});
|
|
4736
4847
|
const result = yield* deployTableFunction({
|
|
4737
4848
|
input,
|
|
@@ -4760,7 +4871,7 @@ var deployAllTables = (input) => Effect28.gen(function* () {
|
|
|
4760
4871
|
project: input.project,
|
|
4761
4872
|
stage: resolveStage(input.stage),
|
|
4762
4873
|
region: input.region,
|
|
4763
|
-
|
|
4874
|
+
packageDir: input.packageDir ?? input.projectDir
|
|
4764
4875
|
});
|
|
4765
4876
|
const results = yield* Effect28.forEach(
|
|
4766
4877
|
functions,
|
|
@@ -4793,12 +4904,31 @@ var deployApp = (input) => Effect29.gen(function* () {
|
|
|
4793
4904
|
const stage = resolveStage(input.stage);
|
|
4794
4905
|
const handlerName = exportName;
|
|
4795
4906
|
const tagCtx = { project, stage, handler: handlerName };
|
|
4907
|
+
const routePatterns = fn13.routePatterns;
|
|
4908
|
+
if (routePatterns.length > 0 && !input.apiOriginDomain) {
|
|
4909
|
+
return yield* Effect29.fail(
|
|
4910
|
+
new Error(
|
|
4911
|
+
`App "${exportName}" has routes but no API Gateway exists. Ensure defineHttp() or defineApi() handlers are included in the discovery patterns.`
|
|
4912
|
+
)
|
|
4913
|
+
);
|
|
4914
|
+
}
|
|
4796
4915
|
if (config.build) {
|
|
4797
4916
|
yield* Effect29.logDebug(`Building app: ${config.build}`);
|
|
4917
|
+
const buildStart = Date.now();
|
|
4798
4918
|
yield* Effect29.try({
|
|
4799
|
-
try: () => execSync(config.build, {
|
|
4800
|
-
|
|
4919
|
+
try: () => execSync(config.build, {
|
|
4920
|
+
cwd: projectDir,
|
|
4921
|
+
stdio: input.verbose ? "inherit" : "pipe"
|
|
4922
|
+
}),
|
|
4923
|
+
catch: (error) => {
|
|
4924
|
+
if (!input.verbose && error && typeof error === "object" && "stderr" in error) {
|
|
4925
|
+
const stderr = String(error.stderr);
|
|
4926
|
+
if (stderr) process.stderr.write(stderr);
|
|
4927
|
+
}
|
|
4928
|
+
return new Error(`App build failed: ${config.build}`);
|
|
4929
|
+
}
|
|
4801
4930
|
});
|
|
4931
|
+
yield* Effect29.logDebug(`App built in ${((Date.now() - buildStart) / 1e3).toFixed(1)}s`);
|
|
4802
4932
|
}
|
|
4803
4933
|
const serverDir = path5.resolve(projectDir, config.server);
|
|
4804
4934
|
yield* Effect29.logDebug(`Zipping server directory: ${serverDir}`);
|
|
@@ -4864,7 +4994,8 @@ var deployApp = (input) => Effect29.gen(function* () {
|
|
|
4864
4994
|
assetPatterns,
|
|
4865
4995
|
tags: makeTags(tagCtx, "cloudfront-distribution"),
|
|
4866
4996
|
aliases,
|
|
4867
|
-
acmCertificateArn
|
|
4997
|
+
acmCertificateArn,
|
|
4998
|
+
...input.apiOriginDomain && routePatterns.length > 0 ? { apiOriginDomain: input.apiOriginDomain, routePatterns } : {}
|
|
4868
4999
|
});
|
|
4869
5000
|
yield* addCloudFrontPermission(lambdaName, distributionArn);
|
|
4870
5001
|
yield* putBucketPolicyForOAC(bucketName, distributionArn);
|
|
@@ -4978,10 +5109,21 @@ var deployStaticSite = (input) => Effect30.gen(function* () {
|
|
|
4978
5109
|
}
|
|
4979
5110
|
if (config.build) {
|
|
4980
5111
|
yield* Effect30.logDebug(`Building site: ${config.build}`);
|
|
5112
|
+
const buildStart = Date.now();
|
|
4981
5113
|
yield* Effect30.try({
|
|
4982
|
-
try: () => execSync2(config.build, {
|
|
4983
|
-
|
|
5114
|
+
try: () => execSync2(config.build, {
|
|
5115
|
+
cwd: projectDir,
|
|
5116
|
+
stdio: input.verbose ? "inherit" : "pipe"
|
|
5117
|
+
}),
|
|
5118
|
+
catch: (error) => {
|
|
5119
|
+
if (!input.verbose && error && typeof error === "object" && "stderr" in error) {
|
|
5120
|
+
const stderr = String(error.stderr);
|
|
5121
|
+
if (stderr) process.stderr.write(stderr);
|
|
5122
|
+
}
|
|
5123
|
+
return new Error(`Site build failed: ${config.build}`);
|
|
5124
|
+
}
|
|
4984
5125
|
});
|
|
5126
|
+
yield* Effect30.logDebug(`Site built in ${((Date.now() - buildStart) / 1e3).toFixed(1)}s`);
|
|
4985
5127
|
}
|
|
4986
5128
|
const bucketName = `${project}-${stage}-${handlerName}-site`.toLowerCase();
|
|
4987
5129
|
yield* ensureBucket({
|
|
@@ -5325,7 +5467,7 @@ var prepareLayer = (input) => Effect35.gen(function* () {
|
|
|
5325
5467
|
project: input.project,
|
|
5326
5468
|
stage: input.stage,
|
|
5327
5469
|
region: input.region,
|
|
5328
|
-
projectDir: input.
|
|
5470
|
+
projectDir: input.packageDir
|
|
5329
5471
|
}).pipe(
|
|
5330
5472
|
Effect35.provide(
|
|
5331
5473
|
clients_exports.makeClients({
|
|
@@ -5333,8 +5475,8 @@ var prepareLayer = (input) => Effect35.gen(function* () {
|
|
|
5333
5475
|
})
|
|
5334
5476
|
)
|
|
5335
5477
|
);
|
|
5336
|
-
const prodDeps = layerResult ? yield* readProductionDependencies(input.
|
|
5337
|
-
const { packages: external, warnings: layerWarnings } = prodDeps.length > 0 ? yield* Effect35.sync(() => collectLayerPackages(input.
|
|
5478
|
+
const prodDeps = layerResult ? yield* readProductionDependencies(input.packageDir) : [];
|
|
5479
|
+
const { packages: external, warnings: layerWarnings } = prodDeps.length > 0 ? yield* Effect35.sync(() => collectLayerPackages(input.packageDir, prodDeps)) : { packages: [], warnings: [] };
|
|
5338
5480
|
for (const warning of layerWarnings) {
|
|
5339
5481
|
yield* Effect35.logWarning(`[layer] ${warning}`);
|
|
5340
5482
|
}
|
|
@@ -5523,9 +5665,10 @@ var buildTableTasks = (ctx, handlers, results) => {
|
|
|
5523
5665
|
}
|
|
5524
5666
|
return tasks;
|
|
5525
5667
|
};
|
|
5526
|
-
var buildAppTasks = (ctx, handlers, results) => {
|
|
5668
|
+
var buildAppTasks = (ctx, handlers, results, apiId) => {
|
|
5527
5669
|
const tasks = [];
|
|
5528
5670
|
const { region } = ctx.input;
|
|
5671
|
+
const apiOriginDomain = apiId ? `${apiId}.execute-api.${region}.amazonaws.com` : void 0;
|
|
5529
5672
|
for (const { exports } of handlers) {
|
|
5530
5673
|
for (const fn13 of exports) {
|
|
5531
5674
|
tasks.push(
|
|
@@ -5535,7 +5678,9 @@ var buildAppTasks = (ctx, handlers, results) => {
|
|
|
5535
5678
|
project: ctx.input.project,
|
|
5536
5679
|
stage: ctx.input.stage,
|
|
5537
5680
|
region,
|
|
5538
|
-
fn: fn13
|
|
5681
|
+
fn: fn13,
|
|
5682
|
+
verbose: ctx.input.verbose,
|
|
5683
|
+
...apiOriginDomain ? { apiOriginDomain } : {}
|
|
5539
5684
|
}).pipe(Effect35.provide(clients_exports.makeClients({
|
|
5540
5685
|
lambda: { region },
|
|
5541
5686
|
iam: { region },
|
|
@@ -5566,6 +5711,7 @@ var buildStaticSiteTasks = (ctx, handlers, results, apiId) => {
|
|
|
5566
5711
|
stage: ctx.input.stage,
|
|
5567
5712
|
region,
|
|
5568
5713
|
fn: fn13,
|
|
5714
|
+
verbose: ctx.input.verbose,
|
|
5569
5715
|
...fn13.hasHandler ? { file } : {},
|
|
5570
5716
|
...apiOriginDomain ? { apiOriginDomain } : {}
|
|
5571
5717
|
}).pipe(Effect35.provide(clients_exports.makeClients({
|
|
@@ -5748,7 +5894,7 @@ var deployProject = (input) => Effect35.gen(function* () {
|
|
|
5748
5894
|
project: input.project,
|
|
5749
5895
|
stage,
|
|
5750
5896
|
region: input.region,
|
|
5751
|
-
|
|
5897
|
+
packageDir: input.packageDir ?? input.projectDir
|
|
5752
5898
|
});
|
|
5753
5899
|
if (layerArn && layerStatus) {
|
|
5754
5900
|
const status = layerStatus === "cached" ? c.dim("cached") : c.green("created");
|
|
@@ -5759,7 +5905,10 @@ var deployProject = (input) => Effect35.gen(function* () {
|
|
|
5759
5905
|
const staticSitesNeedApi = !input.noSites && staticSiteHandlers.some(
|
|
5760
5906
|
({ exports }) => exports.some((fn13) => fn13.routePatterns.length > 0)
|
|
5761
5907
|
);
|
|
5762
|
-
|
|
5908
|
+
const appsNeedApi = appHandlers.some(
|
|
5909
|
+
({ exports }) => exports.some((fn13) => fn13.routePatterns.length > 0)
|
|
5910
|
+
);
|
|
5911
|
+
if (totalHttpHandlers > 0 || totalApiHandlers > 0 || staticSitesNeedApi || appsNeedApi) {
|
|
5763
5912
|
const tagCtx = {
|
|
5764
5913
|
project: input.project,
|
|
5765
5914
|
stage,
|
|
@@ -5824,7 +5973,7 @@ var deployProject = (input) => Effect35.gen(function* () {
|
|
|
5824
5973
|
const tasks = [
|
|
5825
5974
|
...apiId ? buildHttpTasks(ctx, httpHandlers, apiId, httpResults) : [],
|
|
5826
5975
|
...buildTableTasks(ctx, tableHandlers, tableResults),
|
|
5827
|
-
...buildAppTasks(ctx, appHandlers, appResults),
|
|
5976
|
+
...buildAppTasks(ctx, appHandlers, appResults, apiId),
|
|
5828
5977
|
...input.noSites ? [] : buildStaticSiteTasks(ctx, staticSiteHandlers, staticSiteResults, apiId),
|
|
5829
5978
|
...buildFifoQueueTasks(ctx, fifoQueueHandlers, fifoQueueResults),
|
|
5830
5979
|
...buildBucketTasks(ctx, bucketHandlers, bucketResults),
|
|
@@ -5876,18 +6025,22 @@ import * as path7 from "path";
|
|
|
5876
6025
|
import * as fs4 from "fs";
|
|
5877
6026
|
import { pathToFileURL } from "url";
|
|
5878
6027
|
import * as esbuild2 from "esbuild";
|
|
5879
|
-
|
|
6028
|
+
import { Effect as Effect36 } from "effect";
|
|
6029
|
+
var loadConfig = Effect36.fn("loadConfig")(function* () {
|
|
5880
6030
|
const configPath = path7.resolve(process.cwd(), "effortless.config.ts");
|
|
5881
6031
|
if (!fs4.existsSync(configPath)) {
|
|
5882
6032
|
return null;
|
|
5883
6033
|
}
|
|
5884
|
-
const result =
|
|
5885
|
-
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
|
|
6034
|
+
const result = yield* Effect36.tryPromise({
|
|
6035
|
+
try: () => esbuild2.build({
|
|
6036
|
+
entryPoints: [configPath],
|
|
6037
|
+
bundle: true,
|
|
6038
|
+
write: false,
|
|
6039
|
+
format: "esm",
|
|
6040
|
+
platform: "node",
|
|
6041
|
+
external: ["effortless-aws"]
|
|
6042
|
+
}),
|
|
6043
|
+
catch: (error) => new Error(`Failed to compile config: ${error}`)
|
|
5891
6044
|
});
|
|
5892
6045
|
const output = result.outputFiles?.[0];
|
|
5893
6046
|
if (!output) {
|
|
@@ -5896,13 +6049,12 @@ var loadConfig = async () => {
|
|
|
5896
6049
|
const code = output.text;
|
|
5897
6050
|
const tempFile = path7.join(process.cwd(), ".effortless-config.mjs");
|
|
5898
6051
|
fs4.writeFileSync(tempFile, code);
|
|
5899
|
-
|
|
5900
|
-
|
|
5901
|
-
|
|
5902
|
-
}
|
|
5903
|
-
|
|
5904
|
-
|
|
5905
|
-
};
|
|
6052
|
+
const mod = yield* Effect36.tryPromise({
|
|
6053
|
+
try: () => import(pathToFileURL(tempFile).href),
|
|
6054
|
+
catch: (error) => new Error(`Failed to load config: ${error}`)
|
|
6055
|
+
}).pipe(Effect36.ensuring(Effect36.sync(() => fs4.unlinkSync(tempFile))));
|
|
6056
|
+
return mod.default;
|
|
6057
|
+
});
|
|
5906
6058
|
var projectOption = Options.text("project").pipe(
|
|
5907
6059
|
Options.withAlias("p"),
|
|
5908
6060
|
Options.withDescription("Project name (or 'name' in effortless.config.ts)"),
|
|
@@ -5910,12 +6062,12 @@ var projectOption = Options.text("project").pipe(
|
|
|
5910
6062
|
);
|
|
5911
6063
|
var stageOption = Options.text("stage").pipe(
|
|
5912
6064
|
Options.withAlias("s"),
|
|
5913
|
-
Options.withDescription("
|
|
6065
|
+
Options.withDescription("Deployment stage (default: dev)"),
|
|
5914
6066
|
Options.withDefault("dev")
|
|
5915
6067
|
);
|
|
5916
6068
|
var regionOption = Options.text("region").pipe(
|
|
5917
6069
|
Options.withAlias("r"),
|
|
5918
|
-
Options.withDescription("AWS region"),
|
|
6070
|
+
Options.withDescription("AWS region (default: eu-central-1)"),
|
|
5919
6071
|
Options.withDefault("eu-central-1")
|
|
5920
6072
|
);
|
|
5921
6073
|
var verboseOption = Options.boolean("verbose").pipe(
|
|
@@ -5948,6 +6100,23 @@ var getPatternsFromConfig = (config) => {
|
|
|
5948
6100
|
});
|
|
5949
6101
|
};
|
|
5950
6102
|
|
|
6103
|
+
// src/cli/project-config.ts
|
|
6104
|
+
import * as Context13 from "effect/Context";
|
|
6105
|
+
import * as Layer14 from "effect/Layer";
|
|
6106
|
+
import * as Effect37 from "effect/Effect";
|
|
6107
|
+
import * as path8 from "path";
|
|
6108
|
+
var ProjectConfig = class _ProjectConfig extends Context13.Tag("ProjectConfig")() {
|
|
6109
|
+
static Live = Layer14.effect(
|
|
6110
|
+
_ProjectConfig,
|
|
6111
|
+
Effect37.gen(function* () {
|
|
6112
|
+
const config = yield* loadConfig();
|
|
6113
|
+
const cwd = process.cwd();
|
|
6114
|
+
const projectDir = config?.root ? path8.resolve(cwd, config.root) : cwd;
|
|
6115
|
+
return { config, cwd, projectDir };
|
|
6116
|
+
})
|
|
6117
|
+
);
|
|
6118
|
+
};
|
|
6119
|
+
|
|
5951
6120
|
// src/cli/commands/deploy.ts
|
|
5952
6121
|
var deployTargetArg = Args.text({ name: "target" }).pipe(
|
|
5953
6122
|
Args.withDescription("Handler name or file path to deploy (optional - uses config patterns if not specified)"),
|
|
@@ -5959,8 +6128,8 @@ var isFilePath = (target) => {
|
|
|
5959
6128
|
var deployCommand = Command.make(
|
|
5960
6129
|
"deploy",
|
|
5961
6130
|
{ target: deployTargetArg, project: projectOption, stage: stageOption, region: regionOption, verbose: verboseOption, noSites: noSitesOption },
|
|
5962
|
-
({ target, project: projectOpt, stage, region, verbose, noSites }) =>
|
|
5963
|
-
const config = yield*
|
|
6131
|
+
({ target, project: projectOpt, stage, region, verbose, noSites }) => Effect38.gen(function* () {
|
|
6132
|
+
const { config, cwd, projectDir } = yield* ProjectConfig;
|
|
5964
6133
|
const project = Option.getOrElse(projectOpt, () => config?.name ?? "");
|
|
5965
6134
|
const finalStage = config?.stage ?? stage;
|
|
5966
6135
|
const finalRegion = config?.region ?? region;
|
|
@@ -5979,9 +6148,8 @@ var deployCommand = Command.make(
|
|
|
5979
6148
|
acm: { region: "us-east-1" }
|
|
5980
6149
|
});
|
|
5981
6150
|
const logLevel = verbose ? LogLevel.Debug : LogLevel.Warning;
|
|
5982
|
-
const projectDir = process.cwd();
|
|
5983
6151
|
yield* Option.match(target, {
|
|
5984
|
-
onNone: () =>
|
|
6152
|
+
onNone: () => Effect38.gen(function* () {
|
|
5985
6153
|
const patterns = getPatternsFromConfig(config);
|
|
5986
6154
|
if (!patterns) {
|
|
5987
6155
|
yield* Console3.error("Error: No target specified and no 'handlers' patterns in config");
|
|
@@ -5989,13 +6157,15 @@ var deployCommand = Command.make(
|
|
|
5989
6157
|
}
|
|
5990
6158
|
const results = yield* deployProject({
|
|
5991
6159
|
projectDir,
|
|
6160
|
+
packageDir: cwd,
|
|
5992
6161
|
patterns,
|
|
5993
6162
|
project,
|
|
5994
6163
|
stage: finalStage,
|
|
5995
6164
|
region: finalRegion,
|
|
5996
|
-
noSites
|
|
6165
|
+
noSites,
|
|
6166
|
+
verbose
|
|
5997
6167
|
});
|
|
5998
|
-
const total = results.httpResults.length + results.tableResults.length + results.appResults.length + results.staticSiteResults.length;
|
|
6168
|
+
const total = results.httpResults.length + results.tableResults.length + results.appResults.length + results.staticSiteResults.length + results.apiResults.length;
|
|
5999
6169
|
yield* Console3.log(`
|
|
6000
6170
|
${c.green(`Deployed ${total} handler(s):`)}`);
|
|
6001
6171
|
if (results.apiUrl) {
|
|
@@ -6014,6 +6184,10 @@ ${c.green(`Deployed ${total} handler(s):`)}`);
|
|
|
6014
6184
|
for (const r of results.tableResults) {
|
|
6015
6185
|
summaryLines.push({ name: r.exportName, line: ` ${c.cyan("[table]")} ${c.bold(r.exportName)}` });
|
|
6016
6186
|
}
|
|
6187
|
+
for (const r of results.apiResults) {
|
|
6188
|
+
const pathPart = results.apiUrl ? r.url.replace(results.apiUrl, "") : r.url;
|
|
6189
|
+
summaryLines.push({ name: r.exportName, line: ` ${c.cyan("[api]")} ${c.bold(r.exportName)} ${c.dim(pathPart)}` });
|
|
6190
|
+
}
|
|
6017
6191
|
for (const r of results.staticSiteResults) {
|
|
6018
6192
|
summaryLines.push({ name: r.exportName, line: ` ${c.cyan("[site]")} ${c.bold(r.exportName)}: ${c.cyan(r.url)}` });
|
|
6019
6193
|
}
|
|
@@ -6022,26 +6196,27 @@ ${c.green(`Deployed ${total} handler(s):`)}`);
|
|
|
6022
6196
|
yield* Console3.log(line);
|
|
6023
6197
|
}
|
|
6024
6198
|
}),
|
|
6025
|
-
onSome: (targetValue) =>
|
|
6199
|
+
onSome: (targetValue) => Effect38.gen(function* () {
|
|
6026
6200
|
if (isFilePath(targetValue)) {
|
|
6027
|
-
const fullPath =
|
|
6201
|
+
const fullPath = path9.isAbsolute(targetValue) ? targetValue : path9.resolve(projectDir, targetValue);
|
|
6028
6202
|
const input = {
|
|
6029
6203
|
projectDir,
|
|
6204
|
+
packageDir: cwd,
|
|
6030
6205
|
file: fullPath,
|
|
6031
6206
|
project,
|
|
6032
6207
|
stage: finalStage,
|
|
6033
6208
|
region: finalRegion
|
|
6034
6209
|
};
|
|
6035
6210
|
const httpResult = yield* deployAll(input).pipe(
|
|
6036
|
-
|
|
6211
|
+
Effect38.catchIf(
|
|
6037
6212
|
(e) => e instanceof Error && e.message.includes("No defineHttp"),
|
|
6038
|
-
() =>
|
|
6213
|
+
() => Effect38.succeed(null)
|
|
6039
6214
|
)
|
|
6040
6215
|
);
|
|
6041
6216
|
const tableResults = yield* deployAllTables(input).pipe(
|
|
6042
|
-
|
|
6217
|
+
Effect38.catchIf(
|
|
6043
6218
|
(e) => e instanceof Error && e.message.includes("No defineTable"),
|
|
6044
|
-
() =>
|
|
6219
|
+
() => Effect38.succeed([])
|
|
6045
6220
|
)
|
|
6046
6221
|
);
|
|
6047
6222
|
if (!httpResult && tableResults.length === 0) {
|
|
@@ -6071,68 +6246,23 @@ Deployed ${tableResults.length} table handler(s):`));
|
|
|
6071
6246
|
}
|
|
6072
6247
|
const files = findHandlerFiles(patterns, projectDir);
|
|
6073
6248
|
const discovered = discoverHandlers(files);
|
|
6074
|
-
|
|
6075
|
-
|
|
6076
|
-
|
|
6077
|
-
for (const { file, exports } of discovered.httpHandlers) {
|
|
6078
|
-
for (const { exportName } of exports) {
|
|
6079
|
-
if (exportName === targetValue) {
|
|
6080
|
-
foundFile = file;
|
|
6081
|
-
foundExport = exportName;
|
|
6082
|
-
break;
|
|
6083
|
-
}
|
|
6084
|
-
}
|
|
6085
|
-
if (foundFile) break;
|
|
6086
|
-
}
|
|
6087
|
-
if (!foundFile) {
|
|
6088
|
-
for (const { file, exports } of discovered.tableHandlers) {
|
|
6089
|
-
for (const { exportName } of exports) {
|
|
6090
|
-
if (exportName === targetValue) {
|
|
6091
|
-
foundFile = file;
|
|
6092
|
-
foundExport = exportName;
|
|
6093
|
-
handlerType = "table";
|
|
6094
|
-
break;
|
|
6095
|
-
}
|
|
6096
|
-
}
|
|
6097
|
-
if (foundFile) break;
|
|
6098
|
-
}
|
|
6099
|
-
}
|
|
6100
|
-
if (!foundFile) {
|
|
6101
|
-
for (const { file, exports } of discovered.appHandlers) {
|
|
6102
|
-
for (const { exportName } of exports) {
|
|
6103
|
-
if (exportName === targetValue) {
|
|
6104
|
-
foundFile = file;
|
|
6105
|
-
foundExport = exportName;
|
|
6106
|
-
handlerType = "app";
|
|
6107
|
-
break;
|
|
6108
|
-
}
|
|
6109
|
-
}
|
|
6110
|
-
if (foundFile) break;
|
|
6111
|
-
}
|
|
6112
|
-
}
|
|
6113
|
-
if (!foundFile || !foundExport) {
|
|
6249
|
+
const allHandlers = flattenHandlers(discovered);
|
|
6250
|
+
const found = allHandlers.find((h) => h.exportName === targetValue);
|
|
6251
|
+
if (!found) {
|
|
6114
6252
|
yield* Console3.error(`Error: Handler "${targetValue}" not found`);
|
|
6115
6253
|
yield* Console3.log("\nAvailable handlers:");
|
|
6116
|
-
for (const
|
|
6117
|
-
|
|
6118
|
-
yield* Console3.log(` ${c.cyan("[http]")} ${exportName}`);
|
|
6119
|
-
}
|
|
6120
|
-
}
|
|
6121
|
-
for (const { exports } of discovered.tableHandlers) {
|
|
6122
|
-
for (const { exportName } of exports) {
|
|
6123
|
-
yield* Console3.log(` ${c.cyan("[table]")} ${exportName}`);
|
|
6124
|
-
}
|
|
6125
|
-
}
|
|
6126
|
-
for (const { exports } of discovered.appHandlers) {
|
|
6127
|
-
for (const { exportName } of exports) {
|
|
6128
|
-
yield* Console3.log(` ${c.cyan("[app]")} ${exportName}`);
|
|
6129
|
-
}
|
|
6254
|
+
for (const h of allHandlers) {
|
|
6255
|
+
yield* Console3.log(` ${c.cyan(`[${h.type}]`.padEnd(9))} ${h.exportName}`);
|
|
6130
6256
|
}
|
|
6131
6257
|
return;
|
|
6132
6258
|
}
|
|
6133
|
-
|
|
6259
|
+
const foundFile = found.file;
|
|
6260
|
+
const foundExport = found.exportName;
|
|
6261
|
+
const handlerType = found.type;
|
|
6262
|
+
yield* Console3.log(`Found handler ${c.bold(targetValue)} in ${c.dim(path9.relative(projectDir, foundFile))}`);
|
|
6134
6263
|
const input = {
|
|
6135
6264
|
projectDir,
|
|
6265
|
+
packageDir: cwd,
|
|
6136
6266
|
file: foundFile,
|
|
6137
6267
|
project,
|
|
6138
6268
|
stage: finalStage,
|
|
@@ -6151,15 +6281,15 @@ ${c.green("Deployed:")} ${c.cyan(result.url)}`);
|
|
|
6151
6281
|
}
|
|
6152
6282
|
})
|
|
6153
6283
|
}).pipe(
|
|
6154
|
-
|
|
6284
|
+
Effect38.provide(clientsLayer),
|
|
6155
6285
|
Logger.withMinimumLogLevel(logLevel)
|
|
6156
6286
|
);
|
|
6157
|
-
})
|
|
6158
|
-
).pipe(Command.withDescription("Deploy handlers
|
|
6287
|
+
}).pipe(Effect38.provide(ProjectConfig.Live))
|
|
6288
|
+
).pipe(Command.withDescription("Deploy handlers to AWS Lambda. Accepts a handler name, file path, or deploys all from config"));
|
|
6159
6289
|
|
|
6160
6290
|
// src/cli/commands/status.ts
|
|
6161
6291
|
import { Command as Command2 } from "@effect/cli";
|
|
6162
|
-
import { Effect as
|
|
6292
|
+
import { Effect as Effect39, Console as Console4, Logger as Logger2, LogLevel as LogLevel2, Option as Option2 } from "effect";
|
|
6163
6293
|
var { lambda, apigatewayv2: apigateway } = clients_exports;
|
|
6164
6294
|
var INTERNAL_HANDLERS = /* @__PURE__ */ new Set(["api", "platform"]);
|
|
6165
6295
|
var extractFunctionName = (arn) => {
|
|
@@ -6184,7 +6314,7 @@ var formatDate = (date) => {
|
|
|
6184
6314
|
if (days < 7) return `${days}d ago`;
|
|
6185
6315
|
return d.toLocaleDateString("en-US", { month: "short", day: "numeric" });
|
|
6186
6316
|
};
|
|
6187
|
-
var getLambdaDetails = (functionName) =>
|
|
6317
|
+
var getLambdaDetails = (functionName) => Effect39.gen(function* () {
|
|
6188
6318
|
const config = yield* lambda.make("get_function_configuration", {
|
|
6189
6319
|
FunctionName: functionName
|
|
6190
6320
|
});
|
|
@@ -6194,62 +6324,21 @@ var getLambdaDetails = (functionName) => Effect37.gen(function* () {
|
|
|
6194
6324
|
timeout: config.Timeout
|
|
6195
6325
|
};
|
|
6196
6326
|
}).pipe(
|
|
6197
|
-
|
|
6327
|
+
Effect39.catchAll(() => Effect39.succeed({}))
|
|
6198
6328
|
);
|
|
6199
|
-
var getApiUrl = (apiId) =>
|
|
6329
|
+
var getApiUrl = (apiId) => Effect39.gen(function* () {
|
|
6200
6330
|
const api = yield* apigateway.make("get_api", { ApiId: apiId });
|
|
6201
6331
|
return api.ApiEndpoint;
|
|
6202
6332
|
}).pipe(
|
|
6203
|
-
|
|
6333
|
+
Effect39.catchAll(() => Effect39.succeed(void 0))
|
|
6204
6334
|
);
|
|
6205
6335
|
var discoverCodeHandlers = (projectDir, patterns) => {
|
|
6206
6336
|
const files = findHandlerFiles(patterns, projectDir);
|
|
6207
6337
|
const discovered = discoverHandlers(files);
|
|
6208
|
-
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
name: fn13.exportName,
|
|
6213
|
-
type: "http",
|
|
6214
|
-
method: fn13.config.method,
|
|
6215
|
-
path: fn13.config.path
|
|
6216
|
-
});
|
|
6217
|
-
}
|
|
6218
|
-
}
|
|
6219
|
-
for (const { exports } of discovered.tableHandlers) {
|
|
6220
|
-
for (const fn13 of exports) {
|
|
6221
|
-
handlers.push({
|
|
6222
|
-
name: fn13.exportName,
|
|
6223
|
-
type: "table"
|
|
6224
|
-
});
|
|
6225
|
-
}
|
|
6226
|
-
}
|
|
6227
|
-
for (const { exports } of discovered.appHandlers) {
|
|
6228
|
-
for (const fn13 of exports) {
|
|
6229
|
-
handlers.push({
|
|
6230
|
-
name: fn13.exportName,
|
|
6231
|
-
type: "app",
|
|
6232
|
-
path: fn13.config.path
|
|
6233
|
-
});
|
|
6234
|
-
}
|
|
6235
|
-
}
|
|
6236
|
-
for (const { exports } of discovered.staticSiteHandlers) {
|
|
6237
|
-
for (const fn13 of exports) {
|
|
6238
|
-
handlers.push({
|
|
6239
|
-
name: fn13.exportName,
|
|
6240
|
-
type: "site"
|
|
6241
|
-
});
|
|
6242
|
-
}
|
|
6243
|
-
}
|
|
6244
|
-
for (const { exports } of discovered.fifoQueueHandlers) {
|
|
6245
|
-
for (const fn13 of exports) {
|
|
6246
|
-
handlers.push({
|
|
6247
|
-
name: fn13.exportName,
|
|
6248
|
-
type: "queue"
|
|
6249
|
-
});
|
|
6250
|
-
}
|
|
6251
|
-
}
|
|
6252
|
-
return handlers;
|
|
6338
|
+
return flattenHandlers(discovered).map((h) => ({
|
|
6339
|
+
name: h.exportName,
|
|
6340
|
+
type: h.type
|
|
6341
|
+
}));
|
|
6253
6342
|
};
|
|
6254
6343
|
var discoverAwsHandlers = (resources) => {
|
|
6255
6344
|
const byHandler = groupResourcesByHandler(resources);
|
|
@@ -6277,6 +6366,7 @@ var TYPE_LABELS = {
|
|
|
6277
6366
|
http: "http",
|
|
6278
6367
|
table: "table",
|
|
6279
6368
|
app: "app",
|
|
6369
|
+
api: "api",
|
|
6280
6370
|
site: "site",
|
|
6281
6371
|
queue: "queue",
|
|
6282
6372
|
lambda: "lambda",
|
|
@@ -6297,9 +6387,9 @@ var STATUS_COLORS = {
|
|
|
6297
6387
|
var formatStatus = (status) => {
|
|
6298
6388
|
return STATUS_COLORS[status](status.padEnd(10));
|
|
6299
6389
|
};
|
|
6300
|
-
var formatRoute = (method,
|
|
6301
|
-
if (method &&
|
|
6302
|
-
if (
|
|
6390
|
+
var formatRoute = (method, path11) => {
|
|
6391
|
+
if (method && path11) return `${method.padEnd(5)} ${path11}`;
|
|
6392
|
+
if (path11) return path11;
|
|
6303
6393
|
return "";
|
|
6304
6394
|
};
|
|
6305
6395
|
var formatEntry = (entry) => {
|
|
@@ -6321,8 +6411,8 @@ var formatEntry = (entry) => {
|
|
|
6321
6411
|
var statusCommand = Command2.make(
|
|
6322
6412
|
"status",
|
|
6323
6413
|
{ project: projectOption, stage: stageOption, region: regionOption, verbose: verboseOption },
|
|
6324
|
-
({ project: projectOpt, stage, region, verbose }) =>
|
|
6325
|
-
const config = yield*
|
|
6414
|
+
({ project: projectOpt, stage, region, verbose }) => Effect39.gen(function* () {
|
|
6415
|
+
const { config, projectDir } = yield* ProjectConfig;
|
|
6326
6416
|
const project = Option2.getOrElse(projectOpt, () => config?.name ?? "");
|
|
6327
6417
|
const finalStage = config?.stage ?? stage;
|
|
6328
6418
|
const finalRegion = config?.region ?? region;
|
|
@@ -6336,11 +6426,10 @@ var statusCommand = Command2.make(
|
|
|
6336
6426
|
resource_groups_tagging_api: { region: finalRegion }
|
|
6337
6427
|
});
|
|
6338
6428
|
const logLevel = verbose ? LogLevel2.Debug : LogLevel2.Info;
|
|
6339
|
-
const projectDir = process.cwd();
|
|
6340
6429
|
const patterns = getPatternsFromConfig(config);
|
|
6341
6430
|
const codeHandlers = patterns ? discoverCodeHandlers(projectDir, patterns) : [];
|
|
6342
6431
|
const codeHandlerNames = new Set(codeHandlers.map((h) => h.name));
|
|
6343
|
-
yield*
|
|
6432
|
+
yield* Effect39.gen(function* () {
|
|
6344
6433
|
yield* Console4.log(`
|
|
6345
6434
|
Status for ${c.bold(project + "/" + finalStage)}:
|
|
6346
6435
|
`);
|
|
@@ -6437,18 +6526,18 @@ API: ${c.cyan(apiUrl)}`);
|
|
|
6437
6526
|
yield* Console4.log(`
|
|
6438
6527
|
Total: ${parts.join(", ")}`);
|
|
6439
6528
|
}).pipe(
|
|
6440
|
-
|
|
6529
|
+
Effect39.provide(clientsLayer),
|
|
6441
6530
|
Logger2.withMinimumLogLevel(logLevel)
|
|
6442
6531
|
);
|
|
6443
|
-
})
|
|
6444
|
-
).pipe(Command2.withDescription("
|
|
6532
|
+
}).pipe(Effect39.provide(ProjectConfig.Live))
|
|
6533
|
+
).pipe(Command2.withDescription("Compare local handlers with deployed AWS resources. Shows new, deployed, and orphaned handlers"));
|
|
6445
6534
|
|
|
6446
6535
|
// src/cli/commands/cleanup.ts
|
|
6447
6536
|
import { Command as Command3, Options as Options2 } from "@effect/cli";
|
|
6448
|
-
import { Effect as
|
|
6537
|
+
import { Effect as Effect41, Console as Console5, Logger as Logger3, LogLevel as LogLevel3, Option as Option3 } from "effect";
|
|
6449
6538
|
|
|
6450
6539
|
// src/deploy/cleanup.ts
|
|
6451
|
-
import { Effect as
|
|
6540
|
+
import { Effect as Effect40 } from "effect";
|
|
6452
6541
|
var extractResourceName = (arn, type) => {
|
|
6453
6542
|
switch (type) {
|
|
6454
6543
|
case "lambda": {
|
|
@@ -6491,7 +6580,7 @@ var extractLayerInfo = (arn) => {
|
|
|
6491
6580
|
version: parseInt(parts[parts.length - 1] ?? "0", 10)
|
|
6492
6581
|
};
|
|
6493
6582
|
};
|
|
6494
|
-
var deleteResource = (resource) =>
|
|
6583
|
+
var deleteResource = (resource) => Effect40.gen(function* () {
|
|
6495
6584
|
const name = extractResourceName(resource.arn, resource.type);
|
|
6496
6585
|
switch (resource.type) {
|
|
6497
6586
|
case "lambda":
|
|
@@ -6524,18 +6613,18 @@ var deleteResource = (resource) => Effect38.gen(function* () {
|
|
|
6524
6613
|
yield* deleteSesIdentity(name);
|
|
6525
6614
|
break;
|
|
6526
6615
|
default:
|
|
6527
|
-
yield*
|
|
6616
|
+
yield* Effect40.logWarning(`Unknown resource type: ${resource.type}, skipping ${resource.arn}`);
|
|
6528
6617
|
}
|
|
6529
6618
|
});
|
|
6530
|
-
var deleteResources = (resources) =>
|
|
6619
|
+
var deleteResources = (resources) => Effect40.gen(function* () {
|
|
6531
6620
|
const orderedTypes = ["lambda", "api-gateway", "cloudfront-distribution", "sqs", "ses", "dynamodb", "s3-bucket", "lambda-layer", "iam-role"];
|
|
6532
6621
|
const iamRolesToDelete = /* @__PURE__ */ new Set();
|
|
6533
6622
|
for (const type of orderedTypes) {
|
|
6534
6623
|
const resourcesOfType = resources.filter((r) => r.type === type);
|
|
6535
6624
|
for (const resource of resourcesOfType) {
|
|
6536
6625
|
yield* deleteResource(resource).pipe(
|
|
6537
|
-
|
|
6538
|
-
(error) =>
|
|
6626
|
+
Effect40.catchAll(
|
|
6627
|
+
(error) => Effect40.logError(`Failed to delete ${resource.type} ${resource.arn}: ${error}`)
|
|
6539
6628
|
)
|
|
6540
6629
|
);
|
|
6541
6630
|
if (resource.type === "lambda") {
|
|
@@ -6547,8 +6636,8 @@ var deleteResources = (resources) => Effect38.gen(function* () {
|
|
|
6547
6636
|
}
|
|
6548
6637
|
for (const roleName of iamRolesToDelete) {
|
|
6549
6638
|
yield* deleteRole(roleName).pipe(
|
|
6550
|
-
|
|
6551
|
-
(error) =>
|
|
6639
|
+
Effect40.catchAll(
|
|
6640
|
+
(error) => Effect40.logError(`Failed to delete IAM role ${roleName}: ${error}`)
|
|
6552
6641
|
)
|
|
6553
6642
|
);
|
|
6554
6643
|
}
|
|
@@ -6569,11 +6658,14 @@ var layerOption = Options2.boolean("layer").pipe(
|
|
|
6569
6658
|
var rolesOption = Options2.boolean("roles").pipe(
|
|
6570
6659
|
Options2.withDescription("Clean up orphaned IAM roles instead of handler resources")
|
|
6571
6660
|
);
|
|
6661
|
+
var orphanedOption = Options2.boolean("orphaned").pipe(
|
|
6662
|
+
Options2.withDescription("Delete only handlers that exist in AWS but not in code")
|
|
6663
|
+
);
|
|
6572
6664
|
var cleanupCommand = Command3.make(
|
|
6573
6665
|
"cleanup",
|
|
6574
|
-
{ project: projectOption, stage: stageOption, region: regionOption, handler: handlerOption, layer: layerOption, roles: rolesOption, all: cleanupAllOption, dryRun: dryRunOption, verbose: verboseOption },
|
|
6575
|
-
({ project: projectOpt, stage, region, handler: handlerOpt, layer: cleanupLayer, roles: cleanupRoles, all: deleteAll, dryRun, verbose }) =>
|
|
6576
|
-
const config = yield*
|
|
6666
|
+
{ project: projectOption, stage: stageOption, region: regionOption, handler: handlerOption, layer: layerOption, roles: rolesOption, orphaned: orphanedOption, all: cleanupAllOption, dryRun: dryRunOption, verbose: verboseOption },
|
|
6667
|
+
({ project: projectOpt, stage, region, handler: handlerOpt, layer: cleanupLayer, roles: cleanupRoles, orphaned: cleanupOrphaned, all: deleteAll, dryRun, verbose }) => Effect41.gen(function* () {
|
|
6668
|
+
const { config, projectDir } = yield* ProjectConfig;
|
|
6577
6669
|
const project = Option3.getOrElse(projectOpt, () => config?.name ?? "");
|
|
6578
6670
|
const finalStage = config?.stage ?? stage;
|
|
6579
6671
|
const finalRegion = config?.region ?? region;
|
|
@@ -6584,14 +6676,14 @@ var cleanupCommand = Command3.make(
|
|
|
6584
6676
|
const logLevel = verbose ? LogLevel3.Debug : LogLevel3.Info;
|
|
6585
6677
|
if (cleanupLayer) {
|
|
6586
6678
|
yield* cleanupLayerVersions({ project, region: finalRegion, deleteAll, dryRun }).pipe(
|
|
6587
|
-
|
|
6679
|
+
Effect41.provide(clients_exports.makeClients({ lambda: { region: finalRegion } })),
|
|
6588
6680
|
Logger3.withMinimumLogLevel(logLevel)
|
|
6589
6681
|
);
|
|
6590
6682
|
return;
|
|
6591
6683
|
}
|
|
6592
6684
|
if (cleanupRoles) {
|
|
6593
6685
|
yield* cleanupIamRoles({ project, stage: finalStage, region: finalRegion, deleteAll, dryRun }).pipe(
|
|
6594
|
-
|
|
6686
|
+
Effect41.provide(clients_exports.makeClients({ iam: { region: finalRegion } })),
|
|
6595
6687
|
Logger3.withMinimumLogLevel(logLevel)
|
|
6596
6688
|
);
|
|
6597
6689
|
return;
|
|
@@ -6606,7 +6698,7 @@ var cleanupCommand = Command3.make(
|
|
|
6606
6698
|
s3: { region: finalRegion },
|
|
6607
6699
|
cloudfront: { region: "us-east-1" }
|
|
6608
6700
|
});
|
|
6609
|
-
yield*
|
|
6701
|
+
yield* Effect41.gen(function* () {
|
|
6610
6702
|
yield* Console5.log(`
|
|
6611
6703
|
Looking for resources in ${c.bold(project + "/" + finalStage)}...
|
|
6612
6704
|
`);
|
|
@@ -6616,14 +6708,34 @@ Looking for resources in ${c.bold(project + "/" + finalStage)}...
|
|
|
6616
6708
|
return;
|
|
6617
6709
|
}
|
|
6618
6710
|
const byHandler = groupResourcesByHandler(resources);
|
|
6619
|
-
|
|
6620
|
-
if (
|
|
6621
|
-
|
|
6622
|
-
|
|
6623
|
-
|
|
6624
|
-
|
|
6711
|
+
let handlersToDelete;
|
|
6712
|
+
if (cleanupOrphaned) {
|
|
6713
|
+
const patterns = getPatternsFromConfig(config);
|
|
6714
|
+
if (!patterns) {
|
|
6715
|
+
yield* Console5.error("Error: No 'handlers' patterns in config \u2014 cannot determine orphaned handlers");
|
|
6716
|
+
return;
|
|
6625
6717
|
}
|
|
6626
|
-
|
|
6718
|
+
const files = findHandlerFiles(patterns, projectDir);
|
|
6719
|
+
const discovered = discoverHandlers(files);
|
|
6720
|
+
const codeNames = new Set(flattenHandlers(discovered).map((h) => h.exportName));
|
|
6721
|
+
const INTERNAL_HANDLERS2 = /* @__PURE__ */ new Set(["api", "platform"]);
|
|
6722
|
+
handlersToDelete = Array.from(byHandler.entries()).filter(([name]) => !codeNames.has(name) && !INTERNAL_HANDLERS2.has(name));
|
|
6723
|
+
if (handlersToDelete.length === 0) {
|
|
6724
|
+
yield* Console5.log("No orphaned handlers found.");
|
|
6725
|
+
return;
|
|
6726
|
+
}
|
|
6727
|
+
} else if (handlerFilter) {
|
|
6728
|
+
if (!byHandler.has(handlerFilter)) {
|
|
6729
|
+
yield* Console5.error(`Handler "${handlerFilter}" not found.`);
|
|
6730
|
+
yield* Console5.log("\nAvailable handlers:");
|
|
6731
|
+
for (const [h] of byHandler) {
|
|
6732
|
+
yield* Console5.log(` - ${h}`);
|
|
6733
|
+
}
|
|
6734
|
+
return;
|
|
6735
|
+
}
|
|
6736
|
+
handlersToDelete = [[handlerFilter, byHandler.get(handlerFilter) ?? []]];
|
|
6737
|
+
} else {
|
|
6738
|
+
handlersToDelete = Array.from(byHandler.entries());
|
|
6627
6739
|
}
|
|
6628
6740
|
const resourcesToDelete = [];
|
|
6629
6741
|
const derivedRoles = [];
|
|
@@ -6654,9 +6766,10 @@ Total: ${totalResources} resource(s) (${derivedRoles.length} derived)`);
|
|
|
6654
6766
|
${c.yellow("[DRY RUN]")} No resources were deleted.`);
|
|
6655
6767
|
return;
|
|
6656
6768
|
}
|
|
6657
|
-
if (!handlerFilter && !deleteAll) {
|
|
6769
|
+
if (!handlerFilter && !cleanupOrphaned && !deleteAll) {
|
|
6658
6770
|
yield* Console5.log("\nTo delete these resources, use one of:");
|
|
6659
6771
|
yield* Console5.log(` ${c.dim("eff cleanup --all")} # Delete all resources`);
|
|
6772
|
+
yield* Console5.log(` ${c.dim("eff cleanup --orphaned")} # Delete orphaned handlers only`);
|
|
6660
6773
|
yield* Console5.log(` ${c.dim("eff cleanup --handler <name>")} # Delete specific handler`);
|
|
6661
6774
|
yield* Console5.log(` ${c.dim("eff cleanup --dry-run")} # Preview without deleting`);
|
|
6662
6775
|
return;
|
|
@@ -6665,12 +6778,12 @@ ${c.yellow("[DRY RUN]")} No resources were deleted.`);
|
|
|
6665
6778
|
yield* deleteResources(resourcesToDelete);
|
|
6666
6779
|
yield* Console5.log(c.green("\nDone!"));
|
|
6667
6780
|
}).pipe(
|
|
6668
|
-
|
|
6781
|
+
Effect41.provide(clientsLayer),
|
|
6669
6782
|
Logger3.withMinimumLogLevel(logLevel)
|
|
6670
6783
|
);
|
|
6671
|
-
})
|
|
6672
|
-
).pipe(Command3.withDescription("Delete deployed resources"));
|
|
6673
|
-
var cleanupLayerVersions = (input) =>
|
|
6784
|
+
}).pipe(Effect41.provide(ProjectConfig.Live))
|
|
6785
|
+
).pipe(Command3.withDescription("Delete deployed resources (Lambda, API Gateway, DynamoDB, IAM roles, layers)"));
|
|
6786
|
+
var cleanupLayerVersions = (input) => Effect41.gen(function* () {
|
|
6674
6787
|
const layerName = `${input.project}-deps`;
|
|
6675
6788
|
yield* Console5.log(`
|
|
6676
6789
|
Searching for layer versions: ${layerName}
|
|
@@ -6702,7 +6815,7 @@ ${c.yellow("[DRY RUN]")} No layers were deleted.`);
|
|
|
6702
6815
|
yield* Console5.log(c.green(`
|
|
6703
6816
|
Deleted ${deleted} layer version(s).`));
|
|
6704
6817
|
});
|
|
6705
|
-
var cleanupIamRoles = (input) =>
|
|
6818
|
+
var cleanupIamRoles = (input) => Effect41.gen(function* () {
|
|
6706
6819
|
yield* Console5.log("\nSearching for effortless IAM roles...\n");
|
|
6707
6820
|
const allRoles = yield* listEffortlessRoles();
|
|
6708
6821
|
if (allRoles.length === 0) {
|
|
@@ -6751,8 +6864,8 @@ ${c.yellow("[DRY RUN]")} No roles were deleted.`);
|
|
|
6751
6864
|
yield* Console5.log(c.red("\nDeleting roles..."));
|
|
6752
6865
|
for (const role of roles) {
|
|
6753
6866
|
yield* deleteRole(role.name).pipe(
|
|
6754
|
-
|
|
6755
|
-
(error) =>
|
|
6867
|
+
Effect41.catchAll(
|
|
6868
|
+
(error) => Effect41.logError(`Failed to delete ${role.name}: ${error}`)
|
|
6756
6869
|
)
|
|
6757
6870
|
);
|
|
6758
6871
|
}
|
|
@@ -6761,7 +6874,7 @@ ${c.yellow("[DRY RUN]")} No roles were deleted.`);
|
|
|
6761
6874
|
|
|
6762
6875
|
// src/cli/commands/logs.ts
|
|
6763
6876
|
import { Args as Args2, Command as Command4, Options as Options3 } from "@effect/cli";
|
|
6764
|
-
import { Effect as
|
|
6877
|
+
import { Effect as Effect42, Console as Console6, Logger as Logger4, LogLevel as LogLevel4, Option as Option4, Schedule as Schedule4 } from "effect";
|
|
6765
6878
|
var { cloudwatch_logs } = clients_exports;
|
|
6766
6879
|
var handlerArg = Args2.text({ name: "handler" }).pipe(
|
|
6767
6880
|
Args2.withDescription("Handler name to show logs for")
|
|
@@ -6832,8 +6945,8 @@ var fetchLogs = (logGroupName, startTime, nextToken) => cloudwatch_logs.make("fi
|
|
|
6832
6945
|
var logsCommand = Command4.make(
|
|
6833
6946
|
"logs",
|
|
6834
6947
|
{ handler: handlerArg, project: projectOption, stage: stageOption, region: regionOption, tail: tailOption, since: sinceOption, verbose: verboseOption },
|
|
6835
|
-
({ handler: handlerName, project: projectOpt, stage, region, tail, since, verbose }) =>
|
|
6836
|
-
const config = yield*
|
|
6948
|
+
({ handler: handlerName, project: projectOpt, stage, region, tail, since, verbose }) => Effect42.gen(function* () {
|
|
6949
|
+
const { config, projectDir } = yield* ProjectConfig;
|
|
6837
6950
|
const project = Option4.getOrElse(projectOpt, () => config?.name ?? "");
|
|
6838
6951
|
const finalStage = config?.stage ?? stage;
|
|
6839
6952
|
const finalRegion = config?.region ?? region;
|
|
@@ -6841,17 +6954,11 @@ var logsCommand = Command4.make(
|
|
|
6841
6954
|
yield* Console6.error("Error: --project is required (or set 'name' in effortless.config.ts)");
|
|
6842
6955
|
return;
|
|
6843
6956
|
}
|
|
6844
|
-
const projectDir = process.cwd();
|
|
6845
6957
|
const patterns = getPatternsFromConfig(config);
|
|
6846
6958
|
if (patterns) {
|
|
6847
6959
|
const files = findHandlerFiles(patterns, projectDir);
|
|
6848
6960
|
const discovered = discoverHandlers(files);
|
|
6849
|
-
const allHandlerNames =
|
|
6850
|
-
...discovered.httpHandlers.flatMap((h) => h.exports.map((e) => e.exportName)),
|
|
6851
|
-
...discovered.tableHandlers.flatMap((h) => h.exports.map((e) => e.exportName)),
|
|
6852
|
-
...discovered.appHandlers.flatMap((h) => h.exports.map((e) => e.exportName)),
|
|
6853
|
-
...discovered.fifoQueueHandlers.flatMap((h) => h.exports.map((e) => e.exportName))
|
|
6854
|
-
];
|
|
6961
|
+
const allHandlerNames = flattenHandlers(discovered).map((h) => h.exportName);
|
|
6855
6962
|
if (!allHandlerNames.includes(handlerName)) {
|
|
6856
6963
|
yield* Console6.error(`Handler "${handlerName}" not found in code.`);
|
|
6857
6964
|
if (allHandlerNames.length > 0) {
|
|
@@ -6869,18 +6976,18 @@ var logsCommand = Command4.make(
|
|
|
6869
6976
|
cloudwatch_logs: { region: finalRegion }
|
|
6870
6977
|
});
|
|
6871
6978
|
const logLevel = verbose ? LogLevel4.Debug : LogLevel4.Info;
|
|
6872
|
-
yield*
|
|
6979
|
+
yield* Effect42.gen(function* () {
|
|
6873
6980
|
const durationMs = parseDuration(since);
|
|
6874
6981
|
let startTime = Date.now() - durationMs;
|
|
6875
6982
|
yield* Console6.log(`Logs for ${c.bold(handlerName)} ${c.dim(`(${logGroupName})`)}:
|
|
6876
6983
|
`);
|
|
6877
6984
|
let hasLogs = false;
|
|
6878
6985
|
const result = yield* fetchLogs(logGroupName, startTime).pipe(
|
|
6879
|
-
|
|
6986
|
+
Effect42.catchAll((error) => {
|
|
6880
6987
|
if (error instanceof clients_exports.cloudwatch_logs.CloudWatchLogsError && error.cause.name === "ResourceNotFoundException") {
|
|
6881
|
-
return
|
|
6988
|
+
return Effect42.succeed({ events: void 0, nextToken: void 0 });
|
|
6882
6989
|
}
|
|
6883
|
-
return
|
|
6990
|
+
return Effect42.fail(error);
|
|
6884
6991
|
})
|
|
6885
6992
|
);
|
|
6886
6993
|
if (result.events && result.events.length > 0) {
|
|
@@ -6904,10 +7011,10 @@ var logsCommand = Command4.make(
|
|
|
6904
7011
|
if (!hasLogs) {
|
|
6905
7012
|
yield* Console6.log("Waiting for logs... (Ctrl+C to stop)\n");
|
|
6906
7013
|
}
|
|
6907
|
-
yield*
|
|
6908
|
-
|
|
7014
|
+
yield* Effect42.repeat(
|
|
7015
|
+
Effect42.gen(function* () {
|
|
6909
7016
|
const result2 = yield* fetchLogs(logGroupName, startTime).pipe(
|
|
6910
|
-
|
|
7017
|
+
Effect42.catchAll(() => Effect42.succeed({ events: void 0, nextToken: void 0 }))
|
|
6911
7018
|
);
|
|
6912
7019
|
if (result2.events && result2.events.length > 0) {
|
|
6913
7020
|
for (const event of result2.events) {
|
|
@@ -6925,16 +7032,16 @@ var logsCommand = Command4.make(
|
|
|
6925
7032
|
Schedule4.spaced("2 seconds")
|
|
6926
7033
|
);
|
|
6927
7034
|
}).pipe(
|
|
6928
|
-
|
|
7035
|
+
Effect42.provide(clientsLayer),
|
|
6929
7036
|
Logger4.withMinimumLogLevel(logLevel)
|
|
6930
7037
|
);
|
|
6931
|
-
})
|
|
6932
|
-
).pipe(Command4.withDescription("
|
|
7038
|
+
}).pipe(Effect42.provide(ProjectConfig.Live))
|
|
7039
|
+
).pipe(Command4.withDescription("Stream CloudWatch logs for a handler. Supports --tail for live tailing and --since for time range"));
|
|
6933
7040
|
|
|
6934
7041
|
// src/cli/commands/layer.ts
|
|
6935
7042
|
import { Command as Command5, Options as Options4 } from "@effect/cli";
|
|
6936
|
-
import { Effect as
|
|
6937
|
-
import * as
|
|
7043
|
+
import { Effect as Effect43, Console as Console7 } from "effect";
|
|
7044
|
+
import * as path10 from "path";
|
|
6938
7045
|
import * as fs5 from "fs";
|
|
6939
7046
|
var buildOption = Options4.boolean("build").pipe(
|
|
6940
7047
|
Options4.withDescription("Build layer directory locally (for debugging)")
|
|
@@ -6942,22 +7049,28 @@ var buildOption = Options4.boolean("build").pipe(
|
|
|
6942
7049
|
var layerCommand = Command5.make(
|
|
6943
7050
|
"layer",
|
|
6944
7051
|
{ build: buildOption, output: outputOption, verbose: verboseOption },
|
|
6945
|
-
({ build: build3, output, verbose }) =>
|
|
6946
|
-
const config = yield*
|
|
6947
|
-
const projectDir = process.cwd();
|
|
7052
|
+
({ build: build3, output, verbose }) => Effect43.gen(function* () {
|
|
7053
|
+
const { config, cwd } = yield* ProjectConfig;
|
|
6948
7054
|
if (build3) {
|
|
6949
|
-
yield* buildLayer(
|
|
7055
|
+
yield* buildLayer(cwd, output, verbose);
|
|
6950
7056
|
} else {
|
|
6951
|
-
yield* showLayerInfo(
|
|
7057
|
+
yield* showLayerInfo(cwd, config?.name, verbose);
|
|
6952
7058
|
}
|
|
6953
|
-
})
|
|
6954
|
-
).pipe(Command5.withDescription("
|
|
6955
|
-
var showLayerInfo = (projectDir, projectName, verbose) =>
|
|
7059
|
+
}).pipe(Effect43.provide(ProjectConfig.Live))
|
|
7060
|
+
).pipe(Command5.withDescription("Inspect or locally build the shared Lambda dependency layer from package.json"));
|
|
7061
|
+
var showLayerInfo = (projectDir, projectName, verbose) => Effect43.gen(function* () {
|
|
6956
7062
|
yield* Console7.log(`
|
|
6957
7063
|
${c.bold("=== Layer Packages Preview ===")}
|
|
6958
7064
|
`);
|
|
7065
|
+
const depWarnings = yield* checkDependencyWarnings(projectDir).pipe(
|
|
7066
|
+
Effect43.catchAll(() => Effect43.succeed([]))
|
|
7067
|
+
);
|
|
7068
|
+
for (const w of depWarnings) {
|
|
7069
|
+
yield* Console7.log(c.yellow(` \u26A0 ${w}`));
|
|
7070
|
+
}
|
|
7071
|
+
if (depWarnings.length > 0) yield* Console7.log("");
|
|
6959
7072
|
const prodDeps = yield* readProductionDependencies(projectDir).pipe(
|
|
6960
|
-
|
|
7073
|
+
Effect43.catchAll(() => Effect43.succeed([]))
|
|
6961
7074
|
);
|
|
6962
7075
|
if (prodDeps.length === 0) {
|
|
6963
7076
|
yield* Console7.log("No production dependencies found in package.json");
|
|
@@ -6969,7 +7082,7 @@ ${c.bold("=== Layer Packages Preview ===")}
|
|
|
6969
7082
|
yield* Console7.log(` ${dep}`);
|
|
6970
7083
|
}
|
|
6971
7084
|
const hash = yield* computeLockfileHash(projectDir).pipe(
|
|
6972
|
-
|
|
7085
|
+
Effect43.catchAll(() => Effect43.succeed(null))
|
|
6973
7086
|
);
|
|
6974
7087
|
if (hash) {
|
|
6975
7088
|
yield* Console7.log(`
|
|
@@ -6977,7 +7090,7 @@ Lockfile hash: ${hash}`);
|
|
|
6977
7090
|
} else {
|
|
6978
7091
|
yield* Console7.log("\nNo lockfile found (package-lock.json, pnpm-lock.yaml, or yarn.lock)");
|
|
6979
7092
|
}
|
|
6980
|
-
const { packages: allPackages, warnings: layerWarnings } = yield*
|
|
7093
|
+
const { packages: allPackages, warnings: layerWarnings } = yield* Effect43.sync(() => collectLayerPackages(projectDir, prodDeps));
|
|
6981
7094
|
if (layerWarnings.length > 0) {
|
|
6982
7095
|
yield* Console7.log(c.yellow(`
|
|
6983
7096
|
Warnings (${layerWarnings.length}):`));
|
|
@@ -7006,10 +7119,10 @@ Total packages for layer ${c.dim(`(${allPackages.length})`)}:`);
|
|
|
7006
7119
|
Layer name: ${projectName}-deps`);
|
|
7007
7120
|
}
|
|
7008
7121
|
});
|
|
7009
|
-
var buildLayer = (projectDir, output, verbose) =>
|
|
7010
|
-
const outputDir =
|
|
7011
|
-
const layerDir =
|
|
7012
|
-
const layerRoot =
|
|
7122
|
+
var buildLayer = (projectDir, output, verbose) => Effect43.gen(function* () {
|
|
7123
|
+
const outputDir = path10.isAbsolute(output) ? output : path10.resolve(projectDir, output);
|
|
7124
|
+
const layerDir = path10.join(outputDir, "nodejs", "node_modules");
|
|
7125
|
+
const layerRoot = path10.join(outputDir, "nodejs");
|
|
7013
7126
|
if (fs5.existsSync(layerRoot)) {
|
|
7014
7127
|
fs5.rmSync(layerRoot, { recursive: true });
|
|
7015
7128
|
}
|
|
@@ -7017,8 +7130,15 @@ var buildLayer = (projectDir, output, verbose) => Effect41.gen(function* () {
|
|
|
7017
7130
|
yield* Console7.log(`
|
|
7018
7131
|
${c.bold("=== Building Layer Locally ===")}
|
|
7019
7132
|
`);
|
|
7133
|
+
const depWarnings = yield* checkDependencyWarnings(projectDir).pipe(
|
|
7134
|
+
Effect43.catchAll(() => Effect43.succeed([]))
|
|
7135
|
+
);
|
|
7136
|
+
for (const w of depWarnings) {
|
|
7137
|
+
yield* Console7.log(c.yellow(` \u26A0 ${w}`));
|
|
7138
|
+
}
|
|
7139
|
+
if (depWarnings.length > 0) yield* Console7.log("");
|
|
7020
7140
|
const prodDeps = yield* readProductionDependencies(projectDir).pipe(
|
|
7021
|
-
|
|
7141
|
+
Effect43.catchAll(() => Effect43.succeed([]))
|
|
7022
7142
|
);
|
|
7023
7143
|
if (prodDeps.length === 0) {
|
|
7024
7144
|
yield* Console7.log("No production dependencies found in package.json");
|
|
@@ -7030,11 +7150,11 @@ ${c.bold("=== Building Layer Locally ===")}
|
|
|
7030
7150
|
yield* Console7.log(` ${dep}`);
|
|
7031
7151
|
}
|
|
7032
7152
|
const hash = yield* computeLockfileHash(projectDir).pipe(
|
|
7033
|
-
|
|
7153
|
+
Effect43.catchAll(() => Effect43.succeed("unknown"))
|
|
7034
7154
|
);
|
|
7035
7155
|
yield* Console7.log(`
|
|
7036
7156
|
Lockfile hash: ${hash}`);
|
|
7037
|
-
const { packages: allPackages, resolvedPaths, warnings: layerWarnings } = yield*
|
|
7157
|
+
const { packages: allPackages, resolvedPaths, warnings: layerWarnings } = yield* Effect43.sync(() => collectLayerPackages(projectDir, prodDeps));
|
|
7038
7158
|
if (layerWarnings.length > 0) {
|
|
7039
7159
|
yield* Console7.log(`
|
|
7040
7160
|
Warnings (${layerWarnings.length}):`);
|
|
@@ -7061,9 +7181,9 @@ Collected ${allPackages.length} packages for layer`);
|
|
|
7061
7181
|
}
|
|
7062
7182
|
continue;
|
|
7063
7183
|
}
|
|
7064
|
-
const destPath =
|
|
7184
|
+
const destPath = path10.join(layerDir, pkgName);
|
|
7065
7185
|
if (pkgName.startsWith("@")) {
|
|
7066
|
-
const scopeDir =
|
|
7186
|
+
const scopeDir = path10.join(layerDir, pkgName.split("/")[0] ?? pkgName);
|
|
7067
7187
|
if (!fs5.existsSync(scopeDir)) {
|
|
7068
7188
|
fs5.mkdirSync(scopeDir, { recursive: true });
|
|
7069
7189
|
}
|
|
@@ -7084,20 +7204,20 @@ To inspect: ls ${layerDir}`);
|
|
|
7084
7204
|
// src/cli/commands/config.ts
|
|
7085
7205
|
import { Args as Args3, Command as Command6 } from "@effect/cli";
|
|
7086
7206
|
import { Prompt } from "@effect/cli";
|
|
7087
|
-
import { Effect as
|
|
7088
|
-
var loadRequiredParams = (projectOpt, stage, region) =>
|
|
7089
|
-
const config = yield*
|
|
7207
|
+
import { Effect as Effect44, Console as Console8, Logger as Logger5, LogLevel as LogLevel5, Option as Option5 } from "effect";
|
|
7208
|
+
var loadRequiredParams = (projectOpt, stage, region) => Effect44.gen(function* () {
|
|
7209
|
+
const { config, projectDir } = yield* ProjectConfig;
|
|
7090
7210
|
const project = Option5.getOrElse(projectOpt, () => config?.name ?? "");
|
|
7091
7211
|
if (!project) {
|
|
7092
7212
|
yield* Console8.error("Error: --project is required (or set 'name' in effortless.config.ts)");
|
|
7093
|
-
return yield*
|
|
7213
|
+
return yield* Effect44.fail(new Error("Missing project name"));
|
|
7094
7214
|
}
|
|
7095
7215
|
const patterns = getPatternsFromConfig(config);
|
|
7096
7216
|
if (!patterns) {
|
|
7097
7217
|
yield* Console8.error("Error: No 'handlers' patterns in config");
|
|
7098
|
-
return yield*
|
|
7218
|
+
return yield* Effect44.fail(new Error("Missing handler patterns"));
|
|
7099
7219
|
}
|
|
7100
|
-
const files = findHandlerFiles(patterns,
|
|
7220
|
+
const files = findHandlerFiles(patterns, projectDir);
|
|
7101
7221
|
const handlers = discoverHandlers(files);
|
|
7102
7222
|
const finalStage = config?.stage ?? stage;
|
|
7103
7223
|
const finalRegion = config?.region ?? region;
|
|
@@ -7107,7 +7227,7 @@ var loadRequiredParams = (projectOpt, stage, region) => Effect42.gen(function* (
|
|
|
7107
7227
|
var listCommand = Command6.make(
|
|
7108
7228
|
"list",
|
|
7109
7229
|
{ project: projectOption, stage: stageOption, region: regionOption, verbose: verboseOption },
|
|
7110
|
-
({ project: projectOpt, stage, region, verbose }) =>
|
|
7230
|
+
({ project: projectOpt, stage, region, verbose }) => Effect44.gen(function* () {
|
|
7111
7231
|
const ctx = yield* loadRequiredParams(projectOpt, stage, region);
|
|
7112
7232
|
const { params } = ctx;
|
|
7113
7233
|
if (params.length === 0) {
|
|
@@ -7115,7 +7235,7 @@ var listCommand = Command6.make(
|
|
|
7115
7235
|
return;
|
|
7116
7236
|
}
|
|
7117
7237
|
const { existing, missing } = yield* checkMissingParams(params).pipe(
|
|
7118
|
-
|
|
7238
|
+
Effect44.provide(clients_exports.makeClients({ ssm: { region: ctx.region } }))
|
|
7119
7239
|
);
|
|
7120
7240
|
yield* Console8.log(`
|
|
7121
7241
|
${c.bold("Config parameters")} ${c.dim(`(${ctx.project} / ${ctx.stage})`)}
|
|
@@ -7138,16 +7258,19 @@ ${c.bold("Config parameters")} ${c.dim(`(${ctx.project} / ${ctx.stage})`)}
|
|
|
7138
7258
|
${c.green("All parameters are set.")}`);
|
|
7139
7259
|
}
|
|
7140
7260
|
yield* Console8.log("");
|
|
7141
|
-
}).pipe(
|
|
7142
|
-
|
|
7261
|
+
}).pipe(
|
|
7262
|
+
Effect44.provide(ProjectConfig.Live),
|
|
7263
|
+
Logger5.withMinimumLogLevel(LogLevel5.Warning)
|
|
7264
|
+
)
|
|
7265
|
+
).pipe(Command6.withDescription("List all declared config parameters and show which are set vs missing"));
|
|
7143
7266
|
var setKeyArg = Args3.text({ name: "key" }).pipe(
|
|
7144
7267
|
Args3.withDescription("SSM parameter key (e.g. stripe/secret-key)")
|
|
7145
7268
|
);
|
|
7146
7269
|
var setCommand = Command6.make(
|
|
7147
7270
|
"set",
|
|
7148
7271
|
{ key: setKeyArg, project: projectOption, stage: stageOption, region: regionOption, verbose: verboseOption },
|
|
7149
|
-
({ key, project: projectOpt, stage, region, verbose }) =>
|
|
7150
|
-
const config = yield*
|
|
7272
|
+
({ key, project: projectOpt, stage, region, verbose }) => Effect44.gen(function* () {
|
|
7273
|
+
const { config } = yield* ProjectConfig;
|
|
7151
7274
|
const project = Option5.getOrElse(projectOpt, () => config?.name ?? "");
|
|
7152
7275
|
if (!project) {
|
|
7153
7276
|
yield* Console8.error("Error: --project is required (or set 'name' in effortless.config.ts)");
|
|
@@ -7164,15 +7287,18 @@ var setCommand = Command6.make(
|
|
|
7164
7287
|
Value: value,
|
|
7165
7288
|
Type: "SecureString",
|
|
7166
7289
|
Overwrite: true
|
|
7167
|
-
}).pipe(
|
|
7290
|
+
}).pipe(Effect44.provide(clients_exports.makeClients({ ssm: { region: finalRegion } })));
|
|
7168
7291
|
yield* Console8.log(`
|
|
7169
7292
|
${c.green("\u2713")} ${c.cyan(ssmPath)} ${c.dim("(SecureString)")}`);
|
|
7170
|
-
}).pipe(
|
|
7171
|
-
|
|
7293
|
+
}).pipe(
|
|
7294
|
+
Effect44.provide(ProjectConfig.Live),
|
|
7295
|
+
Logger5.withMinimumLogLevel(LogLevel5.Warning)
|
|
7296
|
+
)
|
|
7297
|
+
).pipe(Command6.withDescription("Set a config parameter value (stored encrypted in AWS)"));
|
|
7172
7298
|
var configRootCommand = Command6.make(
|
|
7173
7299
|
"config",
|
|
7174
7300
|
{ project: projectOption, stage: stageOption, region: regionOption, verbose: verboseOption },
|
|
7175
|
-
({ project: projectOpt, stage, region, verbose }) =>
|
|
7301
|
+
({ project: projectOpt, stage, region, verbose }) => Effect44.gen(function* () {
|
|
7176
7302
|
const ctx = yield* loadRequiredParams(projectOpt, stage, region);
|
|
7177
7303
|
const { params } = ctx;
|
|
7178
7304
|
if (params.length === 0) {
|
|
@@ -7180,7 +7306,7 @@ var configRootCommand = Command6.make(
|
|
|
7180
7306
|
return;
|
|
7181
7307
|
}
|
|
7182
7308
|
const { missing } = yield* checkMissingParams(params).pipe(
|
|
7183
|
-
|
|
7309
|
+
Effect44.provide(clients_exports.makeClients({ ssm: { region: ctx.region } }))
|
|
7184
7310
|
);
|
|
7185
7311
|
if (missing.length === 0) {
|
|
7186
7312
|
yield* Console8.log(`
|
|
@@ -7205,7 +7331,7 @@ ${c.bold("Missing parameters")} ${c.dim(`(${ctx.project} / ${ctx.stage})`)}
|
|
|
7205
7331
|
Value: value,
|
|
7206
7332
|
Type: "SecureString",
|
|
7207
7333
|
Overwrite: false
|
|
7208
|
-
}).pipe(
|
|
7334
|
+
}).pipe(Effect44.provide(clients_exports.makeClients({ ssm: { region: ctx.region } })));
|
|
7209
7335
|
yield* Console8.log(` ${c.green("\u2713")} created`);
|
|
7210
7336
|
created++;
|
|
7211
7337
|
}
|
|
@@ -7218,9 +7344,12 @@ ${c.bold("Missing parameters")} ${c.dim(`(${ctx.project} / ${ctx.stage})`)}
|
|
|
7218
7344
|
No parameters created.
|
|
7219
7345
|
`);
|
|
7220
7346
|
}
|
|
7221
|
-
}).pipe(
|
|
7347
|
+
}).pipe(
|
|
7348
|
+
Effect44.provide(ProjectConfig.Live),
|
|
7349
|
+
Logger5.withMinimumLogLevel(LogLevel5.Warning)
|
|
7350
|
+
)
|
|
7222
7351
|
).pipe(
|
|
7223
|
-
Command6.withDescription("Manage
|
|
7352
|
+
Command6.withDescription("Manage config values declared via param() in handlers. Run without subcommand to interactively set missing values"),
|
|
7224
7353
|
Command6.withSubcommands([listCommand, setCommand])
|
|
7225
7354
|
);
|
|
7226
7355
|
var configCommand = configRootCommand;
|
|
@@ -7237,6 +7366,7 @@ var cli = Command7.run(mainCommand, {
|
|
|
7237
7366
|
version
|
|
7238
7367
|
});
|
|
7239
7368
|
cli(process.argv).pipe(
|
|
7240
|
-
|
|
7369
|
+
Effect45.provide(NodeContext.layer),
|
|
7370
|
+
Effect45.provide(CliConfig.layer({ showBuiltIns: false, showTypes: false })),
|
|
7241
7371
|
NodeRuntime.runMain
|
|
7242
7372
|
);
|