@effortless-aws/cli 0.8.0 → 0.9.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 +814 -254
- package/package.json +2 -2
package/dist/cli/index.js
CHANGED
|
@@ -6,9 +6,9 @@ var __export = (target, all) => {
|
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
// src/cli/index.ts
|
|
9
|
-
import { CliConfig, Command as
|
|
9
|
+
import { CliConfig, Command as Command8 } from "@effect/cli";
|
|
10
10
|
import { NodeContext, NodeRuntime } from "@effect/platform-node";
|
|
11
|
-
import { Effect as
|
|
11
|
+
import { Effect as Effect46 } from "effect";
|
|
12
12
|
import { createRequire as createRequire2 } from "module";
|
|
13
13
|
|
|
14
14
|
// src/cli/commands/deploy.ts
|
|
@@ -1933,6 +1933,18 @@ var publishVersion = (functionName) => Effect13.gen(function* () {
|
|
|
1933
1933
|
version: result.Version
|
|
1934
1934
|
};
|
|
1935
1935
|
});
|
|
1936
|
+
var ensureEdgePermission = (functionName) => lambda_exports.make("add_permission", {
|
|
1937
|
+
FunctionName: functionName,
|
|
1938
|
+
StatementId: "replicator",
|
|
1939
|
+
Action: "lambda:GetFunction",
|
|
1940
|
+
Principal: "replicator.lambda.amazonaws.com"
|
|
1941
|
+
}).pipe(
|
|
1942
|
+
Effect13.catchIf(
|
|
1943
|
+
(e) => e._tag === "LambdaError" && e.is("ResourceConflictException"),
|
|
1944
|
+
() => Effect13.logDebug(`Replicator permission already exists for ${functionName}`)
|
|
1945
|
+
),
|
|
1946
|
+
Effect13.asVoid
|
|
1947
|
+
);
|
|
1936
1948
|
var DEFAULT_CORS = {
|
|
1937
1949
|
AllowOrigins: ["*"],
|
|
1938
1950
|
AllowMethods: ["*"],
|
|
@@ -2459,15 +2471,24 @@ var getPackageVersion = (pkgPath) => {
|
|
|
2459
2471
|
return null;
|
|
2460
2472
|
}
|
|
2461
2473
|
};
|
|
2462
|
-
var computeLockfileHash = (projectDir) => Effect18.gen(function* () {
|
|
2474
|
+
var computeLockfileHash = (projectDir, extraNodeModules) => Effect18.gen(function* () {
|
|
2463
2475
|
const prodDeps = yield* readProductionDependencies(projectDir);
|
|
2464
2476
|
if (prodDeps.length === 0) {
|
|
2465
2477
|
return yield* Effect18.fail(new Error("No production dependencies"));
|
|
2466
2478
|
}
|
|
2467
|
-
const { packages: allPackages, resolvedPaths } = collectTransitiveDeps(
|
|
2479
|
+
const { packages: allPackages, resolvedPaths } = collectTransitiveDeps(
|
|
2480
|
+
projectDir,
|
|
2481
|
+
prodDeps,
|
|
2482
|
+
void 0,
|
|
2483
|
+
void 0,
|
|
2484
|
+
void 0,
|
|
2485
|
+
void 0,
|
|
2486
|
+
void 0,
|
|
2487
|
+
extraNodeModules
|
|
2488
|
+
);
|
|
2468
2489
|
const packageVersions = [];
|
|
2469
2490
|
for (const pkgName of Array.from(allPackages).filter((p) => !isAwsRuntime(p)).sort()) {
|
|
2470
|
-
const pkgPath = resolvedPaths.get(pkgName) ?? findInPnpmStore(projectDir, pkgName) ?? getPackageRealPath(projectDir, pkgName);
|
|
2491
|
+
const pkgPath = resolvedPaths.get(pkgName) ?? findInPnpmStore(projectDir, pkgName, extraNodeModules) ?? getPackageRealPath(projectDir, pkgName);
|
|
2471
2492
|
if (pkgPath) {
|
|
2472
2493
|
const version2 = getPackageVersion(pkgPath);
|
|
2473
2494
|
if (version2) {
|
|
@@ -2522,10 +2543,13 @@ var DEV_ONLY_PREFIXES = [
|
|
|
2522
2543
|
"@vitest/",
|
|
2523
2544
|
"@jest/"
|
|
2524
2545
|
];
|
|
2525
|
-
var
|
|
2546
|
+
var RUNTIME_CONDITIONS = /* @__PURE__ */ new Set(["import", "require", "default", "node"]);
|
|
2547
|
+
var isSubpath = (key) => key.startsWith(".");
|
|
2548
|
+
var extractExportPaths = (value, key) => {
|
|
2549
|
+
if (key !== void 0 && !isSubpath(key) && !RUNTIME_CONDITIONS.has(key)) return [];
|
|
2526
2550
|
if (typeof value === "string") return [value];
|
|
2527
2551
|
if (typeof value === "object" && value !== null) {
|
|
2528
|
-
return Object.
|
|
2552
|
+
return Object.entries(value).flatMap(([k, v]) => extractExportPaths(v, k));
|
|
2529
2553
|
}
|
|
2530
2554
|
return [];
|
|
2531
2555
|
};
|
|
@@ -2568,7 +2592,7 @@ var checkDependencyWarnings = (projectDir) => Effect18.gen(function* () {
|
|
|
2568
2592
|
const tsEntries = [...new Set(entryPoints.filter(isRawTypeScript))];
|
|
2569
2593
|
if (tsEntries.length > 0) {
|
|
2570
2594
|
warnings.push(
|
|
2571
|
-
`Package "${dep}" has TypeScript entry points (${tsEntries.join(", ")})
|
|
2595
|
+
`Package "${dep}" has TypeScript entry points (${tsEntries.join(", ")}) \u2014 it will be bundled by esbuild instead of included in the layer.`
|
|
2572
2596
|
);
|
|
2573
2597
|
}
|
|
2574
2598
|
} catch {
|
|
@@ -2601,8 +2625,7 @@ var getPackageDeps = (pkgPath) => {
|
|
|
2601
2625
|
return EMPTY_DEPS;
|
|
2602
2626
|
}
|
|
2603
2627
|
};
|
|
2604
|
-
var
|
|
2605
|
-
const pnpmDir = path.join(projectDir, "node_modules", ".pnpm");
|
|
2628
|
+
var searchPnpmDir = (pnpmDir, pkgName) => {
|
|
2606
2629
|
if (!fsSync.existsSync(pnpmDir)) return null;
|
|
2607
2630
|
const pnpmPkgName = pkgName.replace("/", "+");
|
|
2608
2631
|
try {
|
|
@@ -2622,7 +2645,18 @@ var findInPnpmStore = (projectDir, pkgName) => {
|
|
|
2622
2645
|
}
|
|
2623
2646
|
return null;
|
|
2624
2647
|
};
|
|
2625
|
-
var
|
|
2648
|
+
var findInPnpmStore = (projectDir, pkgName, extraNodeModules) => {
|
|
2649
|
+
const result = searchPnpmDir(path.join(projectDir, "node_modules", ".pnpm"), pkgName);
|
|
2650
|
+
if (result) return result;
|
|
2651
|
+
if (extraNodeModules) {
|
|
2652
|
+
for (const dir of extraNodeModules) {
|
|
2653
|
+
const found = searchPnpmDir(path.join(dir, ".pnpm"), pkgName);
|
|
2654
|
+
if (found) return found;
|
|
2655
|
+
}
|
|
2656
|
+
}
|
|
2657
|
+
return null;
|
|
2658
|
+
};
|
|
2659
|
+
var collectTransitiveDeps = (projectDir, rootDeps, searchPath = path.join(projectDir, "node_modules"), visited = /* @__PURE__ */ new Set(), resolvedPaths = /* @__PURE__ */ new Map(), warnings = [], optionalNames = /* @__PURE__ */ new Set(), extraNodeModules) => {
|
|
2626
2660
|
const rootNodeModules = path.join(projectDir, "node_modules");
|
|
2627
2661
|
for (const dep of rootDeps) {
|
|
2628
2662
|
if (visited.has(dep)) continue;
|
|
@@ -2645,8 +2679,20 @@ var collectTransitiveDeps = (projectDir, rootDeps, searchPath = path.join(projec
|
|
|
2645
2679
|
}
|
|
2646
2680
|
}
|
|
2647
2681
|
}
|
|
2682
|
+
if (!realPath && extraNodeModules) {
|
|
2683
|
+
for (const dir of extraNodeModules) {
|
|
2684
|
+
pkgPath = path.join(dir, dep);
|
|
2685
|
+
if (fsSync.existsSync(pkgPath)) {
|
|
2686
|
+
try {
|
|
2687
|
+
realPath = fsSync.realpathSync(pkgPath);
|
|
2688
|
+
break;
|
|
2689
|
+
} catch {
|
|
2690
|
+
}
|
|
2691
|
+
}
|
|
2692
|
+
}
|
|
2693
|
+
}
|
|
2648
2694
|
if (!realPath) {
|
|
2649
|
-
realPath = findInPnpmStore(projectDir, dep);
|
|
2695
|
+
realPath = findInPnpmStore(projectDir, dep, extraNodeModules);
|
|
2650
2696
|
}
|
|
2651
2697
|
if (!realPath) {
|
|
2652
2698
|
if (!optionalNames.has(dep)) {
|
|
@@ -2662,15 +2708,38 @@ var collectTransitiveDeps = (projectDir, rootDeps, searchPath = path.join(projec
|
|
|
2662
2708
|
const pkgNodeModules = isScoped ? path.dirname(path.dirname(realPath)) : path.dirname(realPath);
|
|
2663
2709
|
const nextOptional = new Set(optionalNames);
|
|
2664
2710
|
for (const name of pkgDeps.optional) nextOptional.add(name);
|
|
2665
|
-
collectTransitiveDeps(projectDir, pkgDeps.all, pkgNodeModules, visited, resolvedPaths, warnings, nextOptional);
|
|
2711
|
+
collectTransitiveDeps(projectDir, pkgDeps.all, pkgNodeModules, visited, resolvedPaths, warnings, nextOptional, extraNodeModules);
|
|
2666
2712
|
}
|
|
2667
2713
|
}
|
|
2668
2714
|
return { packages: visited, resolvedPaths, warnings };
|
|
2669
2715
|
};
|
|
2670
2716
|
var isAwsRuntime = (pkg) => pkg.startsWith("@aws-sdk/") || pkg.startsWith("@smithy/") || pkg.startsWith("@aws-crypto/") || pkg.startsWith("@aws/");
|
|
2671
|
-
var
|
|
2717
|
+
var hasTypeScriptEntryPoints = (pkgPath) => {
|
|
2718
|
+
const pkgJsonPath = path.join(pkgPath, "package.json");
|
|
2719
|
+
if (!fsSync.existsSync(pkgJsonPath)) return false;
|
|
2720
|
+
try {
|
|
2721
|
+
const pkgJson = JSON.parse(fsSync.readFileSync(pkgJsonPath, "utf-8"));
|
|
2722
|
+
const entryPoints = [];
|
|
2723
|
+
if (typeof pkgJson.main === "string") entryPoints.push(pkgJson.main);
|
|
2724
|
+
if (typeof pkgJson.module === "string") entryPoints.push(pkgJson.module);
|
|
2725
|
+
entryPoints.push(...extractExportPaths(pkgJson.exports));
|
|
2726
|
+
return entryPoints.some(isRawTypeScript);
|
|
2727
|
+
} catch {
|
|
2728
|
+
return false;
|
|
2729
|
+
}
|
|
2730
|
+
};
|
|
2731
|
+
var collectLayerPackages = (projectDir, dependencies, extraNodeModules) => {
|
|
2672
2732
|
if (dependencies.length === 0) return { packages: [], resolvedPaths: /* @__PURE__ */ new Map(), warnings: [] };
|
|
2673
|
-
const { packages, resolvedPaths, warnings } = collectTransitiveDeps(
|
|
2733
|
+
const { packages, resolvedPaths, warnings } = collectTransitiveDeps(
|
|
2734
|
+
projectDir,
|
|
2735
|
+
dependencies,
|
|
2736
|
+
void 0,
|
|
2737
|
+
void 0,
|
|
2738
|
+
void 0,
|
|
2739
|
+
void 0,
|
|
2740
|
+
void 0,
|
|
2741
|
+
extraNodeModules
|
|
2742
|
+
);
|
|
2674
2743
|
let changed = true;
|
|
2675
2744
|
while (changed) {
|
|
2676
2745
|
changed = false;
|
|
@@ -2679,7 +2748,7 @@ var collectLayerPackages = (projectDir, dependencies) => {
|
|
|
2679
2748
|
const pkgPaths = /* @__PURE__ */ new Set();
|
|
2680
2749
|
const resolved = resolvedPaths.get(pkg);
|
|
2681
2750
|
if (resolved) pkgPaths.add(resolved);
|
|
2682
|
-
const found = findPackagePath(projectDir, pkg);
|
|
2751
|
+
const found = findPackagePath(projectDir, pkg, extraNodeModules);
|
|
2683
2752
|
if (found) pkgPaths.add(found);
|
|
2684
2753
|
if (pkgPaths.size === 0) continue;
|
|
2685
2754
|
for (const pkgPath of pkgPaths) {
|
|
@@ -2687,7 +2756,7 @@ var collectLayerPackages = (projectDir, dependencies) => {
|
|
|
2687
2756
|
const optionalSet = new Set(pkgDeps.optional);
|
|
2688
2757
|
for (const dep of pkgDeps.all) {
|
|
2689
2758
|
if (!packages.has(dep) && !isAwsRuntime(dep)) {
|
|
2690
|
-
let depPath = findPackagePath(projectDir, dep);
|
|
2759
|
+
let depPath = findPackagePath(projectDir, dep, extraNodeModules);
|
|
2691
2760
|
if (!depPath) {
|
|
2692
2761
|
const isScoped = pkg.startsWith("@");
|
|
2693
2762
|
const parentNodeModules = isScoped ? path.dirname(path.dirname(pkgPath)) : path.dirname(pkgPath);
|
|
@@ -2708,13 +2777,33 @@ var collectLayerPackages = (projectDir, dependencies) => {
|
|
|
2708
2777
|
}
|
|
2709
2778
|
}
|
|
2710
2779
|
}
|
|
2711
|
-
const filtered = Array.from(packages).filter((pkg) =>
|
|
2780
|
+
const filtered = Array.from(packages).filter((pkg) => {
|
|
2781
|
+
if (isAwsRuntime(pkg)) return false;
|
|
2782
|
+
const pkgPath = resolvedPaths.get(pkg) ?? findPackagePath(projectDir, pkg, extraNodeModules);
|
|
2783
|
+
if (!pkgPath) return false;
|
|
2784
|
+
if (hasTypeScriptEntryPoints(pkgPath)) {
|
|
2785
|
+
warnings.push(`Package "${pkg}" has TypeScript entry points \u2014 it will be bundled by esbuild instead of included in the layer`);
|
|
2786
|
+
return false;
|
|
2787
|
+
}
|
|
2788
|
+
return true;
|
|
2789
|
+
});
|
|
2712
2790
|
return { packages: filtered, resolvedPaths, warnings };
|
|
2713
2791
|
};
|
|
2714
|
-
var findPackagePath = (projectDir, pkgName) => {
|
|
2792
|
+
var findPackagePath = (projectDir, pkgName, extraNodeModules) => {
|
|
2715
2793
|
const rootPath = getPackageRealPath(projectDir, pkgName);
|
|
2716
2794
|
if (rootPath) return rootPath;
|
|
2717
|
-
|
|
2795
|
+
if (extraNodeModules) {
|
|
2796
|
+
for (const dir of extraNodeModules) {
|
|
2797
|
+
const pkgPath = path.join(dir, pkgName);
|
|
2798
|
+
if (fsSync.existsSync(pkgPath)) {
|
|
2799
|
+
try {
|
|
2800
|
+
return fsSync.realpathSync(pkgPath);
|
|
2801
|
+
} catch {
|
|
2802
|
+
}
|
|
2803
|
+
}
|
|
2804
|
+
}
|
|
2805
|
+
}
|
|
2806
|
+
return findInPnpmStore(projectDir, pkgName, extraNodeModules);
|
|
2718
2807
|
};
|
|
2719
2808
|
var createLayerZip = (projectDir, packages, resolvedPaths) => Effect18.async((resume) => {
|
|
2720
2809
|
const chunks = [];
|
|
@@ -2778,7 +2867,7 @@ var ensureLayer = (config) => Effect18.gen(function* () {
|
|
|
2778
2867
|
yield* Effect18.logDebug("No production dependencies, skipping layer creation");
|
|
2779
2868
|
return null;
|
|
2780
2869
|
}
|
|
2781
|
-
const hash = yield* computeLockfileHash(config.projectDir).pipe(
|
|
2870
|
+
const hash = yield* computeLockfileHash(config.projectDir, config.extraNodeModules).pipe(
|
|
2782
2871
|
Effect18.catchAll((e) => {
|
|
2783
2872
|
const message = e instanceof Error ? e.message : String(e);
|
|
2784
2873
|
return Effect18.logWarning(`Cannot compute lockfile hash: ${message}, skipping layer`).pipe(
|
|
@@ -2795,7 +2884,7 @@ var ensureLayer = (config) => Effect18.gen(function* () {
|
|
|
2795
2884
|
yield* Effect18.logDebug(`Layer ${layerName} with hash ${hash} already exists (version ${existing.version})`);
|
|
2796
2885
|
return existing;
|
|
2797
2886
|
}
|
|
2798
|
-
const { packages: allPackages, resolvedPaths, warnings: layerWarnings } = yield* Effect18.sync(() => collectLayerPackages(config.projectDir, dependencies));
|
|
2887
|
+
const { packages: allPackages, resolvedPaths, warnings: layerWarnings } = yield* Effect18.sync(() => collectLayerPackages(config.projectDir, dependencies, config.extraNodeModules));
|
|
2799
2888
|
for (const warning of layerWarnings) {
|
|
2800
2889
|
yield* Effect18.logWarning(`[layer] ${warning}`);
|
|
2801
2890
|
}
|
|
@@ -2805,11 +2894,46 @@ var ensureLayer = (config) => Effect18.gen(function* () {
|
|
|
2805
2894
|
if (skippedPackages.length > 0) {
|
|
2806
2895
|
yield* Effect18.logWarning(`Skipped ${skippedPackages.length} packages (not found): ${skippedPackages.slice(0, 10).join(", ")}${skippedPackages.length > 10 ? "..." : ""}`);
|
|
2807
2896
|
}
|
|
2808
|
-
|
|
2897
|
+
const zipSizeMB = layerZip.length / 1024 / 1024;
|
|
2898
|
+
yield* Effect18.logDebug(`Layer zip size: ${zipSizeMB.toFixed(2)} MB (${includedPackages.length} packages)`);
|
|
2899
|
+
const MAX_DIRECT_UPLOAD = 50 * 1024 * 1024;
|
|
2900
|
+
let content;
|
|
2901
|
+
if (layerZip.length > MAX_DIRECT_UPLOAD) {
|
|
2902
|
+
const bucketName = `${config.project}-${config.stage}-deploy-artifacts`;
|
|
2903
|
+
const s3Key = `layers/${layerName}-${hash}.zip`;
|
|
2904
|
+
yield* Effect18.logDebug(`Layer zip too large for direct upload (${zipSizeMB.toFixed(1)} MB), uploading to S3: s3://${bucketName}/${s3Key}`);
|
|
2905
|
+
const bucketExists = yield* s3_exports.make("head_bucket", { Bucket: bucketName }).pipe(
|
|
2906
|
+
Effect18.map(() => true),
|
|
2907
|
+
Effect18.catchIf((e) => e._tag === "S3Error", () => Effect18.succeed(false))
|
|
2908
|
+
);
|
|
2909
|
+
if (!bucketExists) {
|
|
2910
|
+
yield* s3_exports.make("create_bucket", {
|
|
2911
|
+
Bucket: bucketName,
|
|
2912
|
+
...config.region !== "us-east-1" ? { CreateBucketConfiguration: { LocationConstraint: config.region } } : {}
|
|
2913
|
+
});
|
|
2914
|
+
yield* s3_exports.make("put_public_access_block", {
|
|
2915
|
+
Bucket: bucketName,
|
|
2916
|
+
PublicAccessBlockConfiguration: {
|
|
2917
|
+
BlockPublicAcls: true,
|
|
2918
|
+
IgnorePublicAcls: true,
|
|
2919
|
+
BlockPublicPolicy: true,
|
|
2920
|
+
RestrictPublicBuckets: true
|
|
2921
|
+
}
|
|
2922
|
+
});
|
|
2923
|
+
}
|
|
2924
|
+
yield* s3_exports.make("put_object", {
|
|
2925
|
+
Bucket: bucketName,
|
|
2926
|
+
Key: s3Key,
|
|
2927
|
+
Body: layerZip
|
|
2928
|
+
});
|
|
2929
|
+
content = { S3Bucket: bucketName, S3Key: s3Key };
|
|
2930
|
+
} else {
|
|
2931
|
+
content = { ZipFile: layerZip };
|
|
2932
|
+
}
|
|
2809
2933
|
const result = yield* lambda_exports.make("publish_layer_version", {
|
|
2810
2934
|
LayerName: layerName,
|
|
2811
2935
|
Description: `effortless deps layer hash:${hash}`,
|
|
2812
|
-
Content:
|
|
2936
|
+
Content: content,
|
|
2813
2937
|
CompatibleRuntimes: [Runtime2.nodejs24x],
|
|
2814
2938
|
CompatibleArchitectures: [Architecture2.arm64]
|
|
2815
2939
|
});
|
|
@@ -4002,6 +4126,7 @@ import { Effect as Effect24 } from "effect";
|
|
|
4002
4126
|
import * as esbuild from "esbuild";
|
|
4003
4127
|
import * as fsSync2 from "fs";
|
|
4004
4128
|
import * as path3 from "path";
|
|
4129
|
+
import { builtinModules } from "module";
|
|
4005
4130
|
import { createRequire } from "module";
|
|
4006
4131
|
import archiver2 from "archiver";
|
|
4007
4132
|
import { globSync } from "glob";
|
|
@@ -4012,7 +4137,36 @@ var parseSource = (source) => {
|
|
|
4012
4137
|
const project = new Project({ useInMemoryFileSystem: true });
|
|
4013
4138
|
return project.createSourceFile("input.ts", source);
|
|
4014
4139
|
};
|
|
4015
|
-
var
|
|
4140
|
+
var bareName = (expr) => {
|
|
4141
|
+
const dot = expr.lastIndexOf(".");
|
|
4142
|
+
return dot === -1 ? expr : expr.slice(dot + 1);
|
|
4143
|
+
};
|
|
4144
|
+
var getProp = (obj, name) => obj.getProperties().find((p) => p.getKind() === SyntaxKind.PropertyAssignment && p.getName() === name)?.asKindOrThrow(SyntaxKind.PropertyAssignment).getInitializer();
|
|
4145
|
+
var findDefineCalls = (sourceFile, defineFn) => {
|
|
4146
|
+
const results = [];
|
|
4147
|
+
const tryAdd = (callExpr, exportName) => {
|
|
4148
|
+
if (bareName(callExpr.getExpression().getText()) !== defineFn) return;
|
|
4149
|
+
const firstArg = callExpr.getArguments()[0];
|
|
4150
|
+
if (firstArg?.getKind() === SyntaxKind.ObjectLiteralExpression) {
|
|
4151
|
+
results.push({ exportName, args: firstArg });
|
|
4152
|
+
}
|
|
4153
|
+
};
|
|
4154
|
+
const def = sourceFile.getExportAssignment((e) => !e.isExportEquals());
|
|
4155
|
+
if (def?.getExpression().getKind() === SyntaxKind.CallExpression) {
|
|
4156
|
+
tryAdd(def.getExpression().asKindOrThrow(SyntaxKind.CallExpression), "default");
|
|
4157
|
+
}
|
|
4158
|
+
for (const stmt of sourceFile.getVariableStatements()) {
|
|
4159
|
+
if (!stmt.isExported()) continue;
|
|
4160
|
+
for (const decl of stmt.getDeclarations()) {
|
|
4161
|
+
const init = decl.getInitializer();
|
|
4162
|
+
if (init?.getKind() === SyntaxKind.CallExpression) {
|
|
4163
|
+
tryAdd(init.asKindOrThrow(SyntaxKind.CallExpression), decl.getName());
|
|
4164
|
+
}
|
|
4165
|
+
}
|
|
4166
|
+
}
|
|
4167
|
+
return results;
|
|
4168
|
+
};
|
|
4169
|
+
var RUNTIME_PROPS = ["onRecord", "onBatchComplete", "onBatch", "onMessage", "onObjectCreated", "onObjectRemoved", "setup", "schema", "onError", "deps", "config", "static", "middleware", "auth", "routes", "get", "post"];
|
|
4016
4170
|
var evalConfig = (configText, exportName) => {
|
|
4017
4171
|
try {
|
|
4018
4172
|
return new Function(`return ${configText}`)();
|
|
@@ -4027,35 +4181,18 @@ Handler config must use only literal values (no variables, imports, or expressio
|
|
|
4027
4181
|
var buildConfigWithoutRuntime = (obj) => {
|
|
4028
4182
|
const props = obj.getProperties().filter((p) => {
|
|
4029
4183
|
if (p.getKind() === SyntaxKind.PropertyAssignment) {
|
|
4030
|
-
|
|
4031
|
-
|
|
4184
|
+
return !RUNTIME_PROPS.includes(p.getName());
|
|
4185
|
+
}
|
|
4186
|
+
if (p.getKind() === SyntaxKind.ShorthandPropertyAssignment) {
|
|
4187
|
+
return !RUNTIME_PROPS.includes(p.asKindOrThrow(SyntaxKind.ShorthandPropertyAssignment).getName());
|
|
4032
4188
|
}
|
|
4033
4189
|
return true;
|
|
4034
4190
|
}).map((p) => p.getText()).join(", ");
|
|
4035
4191
|
return `{ ${props} }`;
|
|
4036
4192
|
};
|
|
4037
|
-
var
|
|
4038
|
-
const prop = obj.getProperties().find((p) => {
|
|
4039
|
-
if (p.getKind() === SyntaxKind.PropertyAssignment) {
|
|
4040
|
-
return p.getName() === propName;
|
|
4041
|
-
}
|
|
4042
|
-
return false;
|
|
4043
|
-
});
|
|
4044
|
-
if (prop && prop.getKind() === SyntaxKind.PropertyAssignment) {
|
|
4045
|
-
const propAssign = prop;
|
|
4046
|
-
return propAssign.getInitializer()?.getText();
|
|
4047
|
-
}
|
|
4048
|
-
return void 0;
|
|
4049
|
-
};
|
|
4193
|
+
var toKebabCase = (str) => str.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
4050
4194
|
var extractDepsKeys = (obj) => {
|
|
4051
|
-
|
|
4052
|
-
if (p.getKind() === SyntaxKind.PropertyAssignment) {
|
|
4053
|
-
return p.getName() === "deps";
|
|
4054
|
-
}
|
|
4055
|
-
return false;
|
|
4056
|
-
});
|
|
4057
|
-
if (!depsProp || depsProp.getKind() !== SyntaxKind.PropertyAssignment) return [];
|
|
4058
|
-
let init = depsProp.getInitializer();
|
|
4195
|
+
let init = getProp(obj, "deps");
|
|
4059
4196
|
if (!init) return [];
|
|
4060
4197
|
if (init.getKind() === SyntaxKind.ArrowFunction) {
|
|
4061
4198
|
const body = init.getBody();
|
|
@@ -4063,9 +4200,8 @@ var extractDepsKeys = (obj) => {
|
|
|
4063
4200
|
init = body.getExpression();
|
|
4064
4201
|
}
|
|
4065
4202
|
}
|
|
4066
|
-
if (
|
|
4067
|
-
|
|
4068
|
-
return depsObj.getProperties().map((p) => {
|
|
4203
|
+
if (init.getKind() !== SyntaxKind.ObjectLiteralExpression) return [];
|
|
4204
|
+
return init.getProperties().map((p) => {
|
|
4069
4205
|
if (p.getKind() === SyntaxKind.ShorthandPropertyAssignment) {
|
|
4070
4206
|
return p.asKindOrThrow(SyntaxKind.ShorthandPropertyAssignment).getName();
|
|
4071
4207
|
}
|
|
@@ -4075,15 +4211,17 @@ var extractDepsKeys = (obj) => {
|
|
|
4075
4211
|
return "";
|
|
4076
4212
|
}).filter(Boolean);
|
|
4077
4213
|
};
|
|
4078
|
-
var
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
}
|
|
4085
|
-
|
|
4086
|
-
|
|
4214
|
+
var parseGenerateSpec = (text) => {
|
|
4215
|
+
if (!text) return void 0;
|
|
4216
|
+
const hexMatch = text.match(/generateHex\((\d+)\)/);
|
|
4217
|
+
if (hexMatch) return { type: "hex", bytes: Number(hexMatch[1]) };
|
|
4218
|
+
const base64Match = text.match(/generateBase64\((\d+)\)/);
|
|
4219
|
+
if (base64Match) return { type: "base64", bytes: Number(base64Match[1]) };
|
|
4220
|
+
if (text.includes("generateUuid")) return { type: "uuid" };
|
|
4221
|
+
return void 0;
|
|
4222
|
+
};
|
|
4223
|
+
var extractSecretEntries = (obj) => {
|
|
4224
|
+
const init = getProp(obj, "config");
|
|
4087
4225
|
if (!init || init.getKind() !== SyntaxKind.ObjectLiteralExpression) return [];
|
|
4088
4226
|
const configObj = init;
|
|
4089
4227
|
const entries = [];
|
|
@@ -4094,47 +4232,46 @@ var extractParamEntries = (obj) => {
|
|
|
4094
4232
|
const propInit = propAssign.getInitializer();
|
|
4095
4233
|
if (!propInit) continue;
|
|
4096
4234
|
if (propInit.getKind() === SyntaxKind.StringLiteral) {
|
|
4097
|
-
|
|
4098
|
-
entries.push({ propName, ssmKey });
|
|
4235
|
+
entries.push({ propName, ssmKey: propInit.asKindOrThrow(SyntaxKind.StringLiteral).getLiteralValue() });
|
|
4099
4236
|
continue;
|
|
4100
4237
|
}
|
|
4101
4238
|
if (propInit.getKind() !== SyntaxKind.CallExpression) continue;
|
|
4102
4239
|
const callExpr = propInit;
|
|
4103
|
-
const
|
|
4104
|
-
if (
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4240
|
+
const fnName = bareName(callExpr.getExpression().getText());
|
|
4241
|
+
if (fnName === "secret") {
|
|
4242
|
+
const callArgs = callExpr.getArguments();
|
|
4243
|
+
if (callArgs.length === 0) {
|
|
4244
|
+
entries.push({ propName, ssmKey: toKebabCase(propName) });
|
|
4245
|
+
continue;
|
|
4246
|
+
}
|
|
4247
|
+
const firstArg = callArgs[0];
|
|
4248
|
+
if (firstArg.getKind() === SyntaxKind.ObjectLiteralExpression) {
|
|
4249
|
+
const optObj = firstArg;
|
|
4250
|
+
const keyText = getProp(optObj, "key")?.getText();
|
|
4251
|
+
const ssmKey = keyText ? keyText.replace(/^["']|["']$/g, "") : toKebabCase(propName);
|
|
4252
|
+
const generate = parseGenerateSpec(getProp(optObj, "generate")?.getText());
|
|
4253
|
+
entries.push({ propName, ssmKey, ...generate ? { generate } : {} });
|
|
4254
|
+
}
|
|
4255
|
+
continue;
|
|
4256
|
+
}
|
|
4257
|
+
if (fnName === "param") {
|
|
4258
|
+
const firstArg = callExpr.getArguments()[0];
|
|
4259
|
+
if (firstArg?.getKind() === SyntaxKind.StringLiteral) {
|
|
4260
|
+
entries.push({ propName, ssmKey: firstArg.asKindOrThrow(SyntaxKind.StringLiteral).getLiteralValue() });
|
|
4261
|
+
}
|
|
4109
4262
|
}
|
|
4110
4263
|
}
|
|
4111
4264
|
return entries;
|
|
4112
4265
|
};
|
|
4113
4266
|
var extractStaticGlobs = (obj) => {
|
|
4114
|
-
const
|
|
4115
|
-
if (p.getKind() === SyntaxKind.PropertyAssignment) {
|
|
4116
|
-
return p.getName() === "static";
|
|
4117
|
-
}
|
|
4118
|
-
return false;
|
|
4119
|
-
});
|
|
4120
|
-
if (!staticProp || staticProp.getKind() !== SyntaxKind.PropertyAssignment) return [];
|
|
4121
|
-
const init = staticProp.getInitializer();
|
|
4267
|
+
const init = getProp(obj, "static");
|
|
4122
4268
|
if (!init || init.getKind() !== SyntaxKind.ArrayLiteralExpression) return [];
|
|
4123
|
-
|
|
4124
|
-
return arrayLiteral.getElements().filter((e) => e.getKind() === SyntaxKind.StringLiteral).map((e) => e.asKindOrThrow(SyntaxKind.StringLiteral).getLiteralValue());
|
|
4269
|
+
return init.asKindOrThrow(SyntaxKind.ArrayLiteralExpression).getElements().filter((e) => e.getKind() === SyntaxKind.StringLiteral).map((e) => e.asKindOrThrow(SyntaxKind.StringLiteral).getLiteralValue());
|
|
4125
4270
|
};
|
|
4126
4271
|
var extractRoutePatterns = (obj) => {
|
|
4127
|
-
const
|
|
4128
|
-
if (p.getKind() === SyntaxKind.PropertyAssignment) {
|
|
4129
|
-
return p.getName() === "routes";
|
|
4130
|
-
}
|
|
4131
|
-
return false;
|
|
4132
|
-
});
|
|
4133
|
-
if (!routesProp || routesProp.getKind() !== SyntaxKind.PropertyAssignment) return [];
|
|
4134
|
-
const init = routesProp.getInitializer();
|
|
4272
|
+
const init = getProp(obj, "routes");
|
|
4135
4273
|
if (!init || init.getKind() !== SyntaxKind.ObjectLiteralExpression) return [];
|
|
4136
|
-
|
|
4137
|
-
return routesObj.getProperties().map((p) => {
|
|
4274
|
+
return init.getProperties().map((p) => {
|
|
4138
4275
|
if (p.getKind() !== SyntaxKind.PropertyAssignment) return "";
|
|
4139
4276
|
const nameNode = p.getNameNode();
|
|
4140
4277
|
if (nameNode.getKind() === SyntaxKind.StringLiteral) {
|
|
@@ -4143,6 +4280,30 @@ var extractRoutePatterns = (obj) => {
|
|
|
4143
4280
|
return nameNode.getText();
|
|
4144
4281
|
}).filter(Boolean);
|
|
4145
4282
|
};
|
|
4283
|
+
var extractAuthConfigFromCall = (callExpr) => {
|
|
4284
|
+
if (bareName(callExpr.getExpression().getText()) !== "defineAuth") return void 0;
|
|
4285
|
+
const firstArg = callExpr.getArguments()[0];
|
|
4286
|
+
if (!firstArg || firstArg.getKind() !== SyntaxKind.ObjectLiteralExpression) return void 0;
|
|
4287
|
+
try {
|
|
4288
|
+
return new Function(`return ${firstArg.getText()}`)();
|
|
4289
|
+
} catch {
|
|
4290
|
+
return void 0;
|
|
4291
|
+
}
|
|
4292
|
+
};
|
|
4293
|
+
var extractAuthConfig = (obj, sourceFile) => {
|
|
4294
|
+
const init = getProp(obj, "auth");
|
|
4295
|
+
if (!init) return void 0;
|
|
4296
|
+
if (init.getKind() === SyntaxKind.CallExpression) {
|
|
4297
|
+
return extractAuthConfigFromCall(init);
|
|
4298
|
+
}
|
|
4299
|
+
if (init.getKind() === SyntaxKind.Identifier) {
|
|
4300
|
+
const varInit = sourceFile.getVariableDeclaration(init.getText())?.getInitializer();
|
|
4301
|
+
if (varInit?.getKind() === SyntaxKind.CallExpression) {
|
|
4302
|
+
return extractAuthConfigFromCall(varInit);
|
|
4303
|
+
}
|
|
4304
|
+
}
|
|
4305
|
+
return void 0;
|
|
4306
|
+
};
|
|
4146
4307
|
var handlerRegistry = {
|
|
4147
4308
|
table: {
|
|
4148
4309
|
defineFn: "defineTable",
|
|
@@ -4190,96 +4351,49 @@ var handlerRegistry = {
|
|
|
4190
4351
|
var extractHandlerConfigs = (source, type) => {
|
|
4191
4352
|
const { defineFn, handlerProps } = handlerRegistry[type];
|
|
4192
4353
|
const sourceFile = parseSource(source);
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
const
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
const depsKeys = extractDepsKeys(objLiteral);
|
|
4208
|
-
const paramEntries = extractParamEntries(objLiteral);
|
|
4209
|
-
const staticGlobs = extractStaticGlobs(objLiteral);
|
|
4210
|
-
const routePatterns = extractRoutePatterns(objLiteral);
|
|
4211
|
-
results.push({ exportName: "default", config, hasHandler, depsKeys, paramEntries, staticGlobs, routePatterns });
|
|
4212
|
-
}
|
|
4213
|
-
}
|
|
4214
|
-
}
|
|
4215
|
-
}
|
|
4216
|
-
sourceFile.getVariableStatements().forEach((stmt) => {
|
|
4217
|
-
if (!stmt.isExported()) return;
|
|
4218
|
-
stmt.getDeclarations().forEach((decl) => {
|
|
4219
|
-
const initializer = decl.getInitializer();
|
|
4220
|
-
if (!initializer || initializer.getKind() !== SyntaxKind.CallExpression) return;
|
|
4221
|
-
const callExpr = initializer.asKindOrThrow(SyntaxKind.CallExpression);
|
|
4222
|
-
if (callExpr.getExpression().getText() !== defineFn) return;
|
|
4223
|
-
const args = callExpr.getArguments();
|
|
4224
|
-
const firstArg = args[0];
|
|
4225
|
-
if (firstArg && firstArg.getKind() === SyntaxKind.ObjectLiteralExpression) {
|
|
4226
|
-
const objLiteral = firstArg;
|
|
4227
|
-
const configText = buildConfigWithoutRuntime(objLiteral);
|
|
4228
|
-
const exportName = decl.getName();
|
|
4229
|
-
const config = evalConfig(configText, exportName);
|
|
4230
|
-
const hasHandler = handlerProps.some((p) => extractPropertyFromObject(objLiteral, p) !== void 0);
|
|
4231
|
-
const depsKeys = extractDepsKeys(objLiteral);
|
|
4232
|
-
const paramEntries = extractParamEntries(objLiteral);
|
|
4233
|
-
const staticGlobs = extractStaticGlobs(objLiteral);
|
|
4234
|
-
const routePatterns = extractRoutePatterns(objLiteral);
|
|
4235
|
-
results.push({ exportName, config, hasHandler, depsKeys, paramEntries, staticGlobs, routePatterns });
|
|
4236
|
-
}
|
|
4237
|
-
});
|
|
4354
|
+
return findDefineCalls(sourceFile, defineFn).map(({ exportName, args }) => {
|
|
4355
|
+
const config = evalConfig(buildConfigWithoutRuntime(args), exportName);
|
|
4356
|
+
const hasHandler = handlerProps.some((p) => getProp(args, p) !== void 0);
|
|
4357
|
+
const authCfg = extractAuthConfig(args, sourceFile);
|
|
4358
|
+
return {
|
|
4359
|
+
exportName,
|
|
4360
|
+
config,
|
|
4361
|
+
hasHandler,
|
|
4362
|
+
depsKeys: extractDepsKeys(args),
|
|
4363
|
+
secretEntries: extractSecretEntries(args),
|
|
4364
|
+
staticGlobs: extractStaticGlobs(args),
|
|
4365
|
+
routePatterns: extractRoutePatterns(args),
|
|
4366
|
+
...authCfg ? { authConfig: authCfg } : {}
|
|
4367
|
+
};
|
|
4238
4368
|
});
|
|
4239
|
-
return results;
|
|
4240
4369
|
};
|
|
4241
4370
|
var generateMiddlewareEntryPoint = (source, runtimeDir2) => {
|
|
4242
4371
|
const sourceFile = parseSource(source);
|
|
4243
|
-
const
|
|
4244
|
-
const defineFn = handlerRegistry.staticSite.defineFn;
|
|
4372
|
+
const calls = findDefineCalls(sourceFile, handlerRegistry.staticSite.defineFn);
|
|
4245
4373
|
let middlewareFnText;
|
|
4246
4374
|
let exportName;
|
|
4247
|
-
const
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
const args = callExpr.getArguments();
|
|
4254
|
-
const firstArg = args[0];
|
|
4255
|
-
if (firstArg?.getKind() === SyntaxKind.ObjectLiteralExpression) {
|
|
4256
|
-
middlewareFnText = extractPropertyFromObject(firstArg, "middleware");
|
|
4257
|
-
exportName = "default";
|
|
4258
|
-
}
|
|
4259
|
-
}
|
|
4375
|
+
for (const call of calls) {
|
|
4376
|
+
const mw = getProp(call.args, "middleware")?.getText();
|
|
4377
|
+
if (mw) {
|
|
4378
|
+
middlewareFnText = mw;
|
|
4379
|
+
exportName = call.exportName;
|
|
4380
|
+
break;
|
|
4260
4381
|
}
|
|
4261
4382
|
}
|
|
4262
|
-
if (!middlewareFnText) {
|
|
4263
|
-
sourceFile.getVariableStatements().forEach((stmt) => {
|
|
4264
|
-
if (middlewareFnText || !stmt.isExported()) return;
|
|
4265
|
-
stmt.getDeclarations().forEach((decl) => {
|
|
4266
|
-
if (middlewareFnText) return;
|
|
4267
|
-
const init = decl.getInitializer();
|
|
4268
|
-
if (!init || init.getKind() !== SyntaxKind.CallExpression) return;
|
|
4269
|
-
const callExpr = init.asKindOrThrow(SyntaxKind.CallExpression);
|
|
4270
|
-
if (callExpr.getExpression().getText() !== defineFn) return;
|
|
4271
|
-
const args = callExpr.getArguments();
|
|
4272
|
-
const firstArg = args[0];
|
|
4273
|
-
if (firstArg?.getKind() === SyntaxKind.ObjectLiteralExpression) {
|
|
4274
|
-
middlewareFnText = extractPropertyFromObject(firstArg, "middleware");
|
|
4275
|
-
exportName = decl.getName();
|
|
4276
|
-
}
|
|
4277
|
-
});
|
|
4278
|
-
});
|
|
4279
|
-
}
|
|
4280
4383
|
if (!middlewareFnText || !exportName) {
|
|
4281
4384
|
throw new Error("Could not extract middleware function from source");
|
|
4282
4385
|
}
|
|
4386
|
+
const imports = sourceFile.getImportDeclarations().filter((d) => {
|
|
4387
|
+
const defaultImport = d.getDefaultImport()?.getText();
|
|
4388
|
+
if (defaultImport && middlewareFnText.includes(defaultImport)) return true;
|
|
4389
|
+
for (const spec of d.getNamedImports()) {
|
|
4390
|
+
const alias = spec.getAliasNode()?.getText() ?? spec.getName();
|
|
4391
|
+
if (middlewareFnText.includes(alias)) return true;
|
|
4392
|
+
}
|
|
4393
|
+
const ns = d.getNamespaceImport()?.getText();
|
|
4394
|
+
if (ns && middlewareFnText.includes(ns)) return true;
|
|
4395
|
+
return false;
|
|
4396
|
+
}).map((d) => d.getText()).join("\n");
|
|
4283
4397
|
const wrapperPath = runtimeDir2 ? handlerRegistry.staticSite.wrapperPath.replace("~/runtime", runtimeDir2) : handlerRegistry.staticSite.wrapperPath;
|
|
4284
4398
|
const entryPoint = `${imports}
|
|
4285
4399
|
import { wrapMiddlewareFn } from "${wrapperPath}";
|
|
@@ -4300,6 +4414,7 @@ export const handler = ${wrapperFn}(${importName});
|
|
|
4300
4414
|
};
|
|
4301
4415
|
|
|
4302
4416
|
// src/build/bundle.ts
|
|
4417
|
+
var AUTH_COOKIE_NAME = "__eff_session";
|
|
4303
4418
|
var extractTableConfigs = (source) => extractHandlerConfigs(source, "table");
|
|
4304
4419
|
var extractAppConfigs = (source) => extractHandlerConfigs(source, "app");
|
|
4305
4420
|
var extractStaticSiteConfigs = (source) => extractHandlerConfigs(source, "staticSite");
|
|
@@ -4316,7 +4431,8 @@ var bundle = (input) => Effect24.gen(function* () {
|
|
|
4316
4431
|
const sourcePath = path3.isAbsolute(input.file) ? input.file : `./${input.file}`;
|
|
4317
4432
|
const entryPoint = generateEntryPoint(sourcePath, exportName, type, runtimeDir);
|
|
4318
4433
|
const awsExternals = ["@aws-sdk/*", "@smithy/*"];
|
|
4319
|
-
const
|
|
4434
|
+
const nodeExternals = builtinModules.flatMap((m) => [m, `node:${m}`]);
|
|
4435
|
+
const allExternals = [.../* @__PURE__ */ new Set([...awsExternals, ...nodeExternals, ...externals])];
|
|
4320
4436
|
const result = yield* Effect24.tryPromise({
|
|
4321
4437
|
try: () => esbuild.build({
|
|
4322
4438
|
stdin: {
|
|
@@ -4331,7 +4447,8 @@ var bundle = (input) => Effect24.gen(function* () {
|
|
|
4331
4447
|
minify: false,
|
|
4332
4448
|
sourcemap: false,
|
|
4333
4449
|
format: input.format ?? "esm",
|
|
4334
|
-
external: allExternals
|
|
4450
|
+
external: allExternals,
|
|
4451
|
+
metafile: true
|
|
4335
4452
|
}),
|
|
4336
4453
|
catch: (error) => new Error(`esbuild failed: ${error}`)
|
|
4337
4454
|
});
|
|
@@ -4339,8 +4456,32 @@ var bundle = (input) => Effect24.gen(function* () {
|
|
|
4339
4456
|
if (!output) {
|
|
4340
4457
|
throw new Error("esbuild produced no output");
|
|
4341
4458
|
}
|
|
4342
|
-
|
|
4459
|
+
const bundleResult = { code: output.text };
|
|
4460
|
+
if (result.metafile) {
|
|
4461
|
+
bundleResult.topModules = analyzeMetafile(result.metafile);
|
|
4462
|
+
}
|
|
4463
|
+
return bundleResult;
|
|
4343
4464
|
});
|
|
4465
|
+
var analyzeMetafile = (metafile) => {
|
|
4466
|
+
const packageSizes = /* @__PURE__ */ new Map();
|
|
4467
|
+
for (const [filePath, info] of Object.entries(metafile.inputs)) {
|
|
4468
|
+
const nodeModIdx = filePath.lastIndexOf("node_modules/");
|
|
4469
|
+
let key;
|
|
4470
|
+
if (nodeModIdx !== -1) {
|
|
4471
|
+
const afterNm = filePath.slice(nodeModIdx + "node_modules/".length);
|
|
4472
|
+
if (afterNm.startsWith("@")) {
|
|
4473
|
+
const parts = afterNm.split("/");
|
|
4474
|
+
key = `${parts[0]}/${parts[1]}`;
|
|
4475
|
+
} else {
|
|
4476
|
+
key = afterNm.split("/")[0];
|
|
4477
|
+
}
|
|
4478
|
+
} else {
|
|
4479
|
+
key = "<project>";
|
|
4480
|
+
}
|
|
4481
|
+
packageSizes.set(key, (packageSizes.get(key) ?? 0) + info.bytes);
|
|
4482
|
+
}
|
|
4483
|
+
return Array.from(packageSizes.entries()).map(([p, bytes]) => ({ path: p, bytes })).sort((a, b) => b.bytes - a.bytes);
|
|
4484
|
+
};
|
|
4344
4485
|
var bundleMiddleware = (input) => Effect24.gen(function* () {
|
|
4345
4486
|
const absFile = path3.isAbsolute(input.file) ? input.file : path3.resolve(input.projectDir, input.file);
|
|
4346
4487
|
const source = fsSync2.readFileSync(absFile, "utf-8");
|
|
@@ -4371,6 +4512,106 @@ var bundleMiddleware = (input) => Effect24.gen(function* () {
|
|
|
4371
4512
|
}
|
|
4372
4513
|
return output.text;
|
|
4373
4514
|
});
|
|
4515
|
+
var bundleAuthMiddleware = (input) => Effect24.gen(function* () {
|
|
4516
|
+
const { authConfig, secret } = input;
|
|
4517
|
+
const loginPath = authConfig.loginPath;
|
|
4518
|
+
const publicPatterns = authConfig.public ?? [];
|
|
4519
|
+
const entryPoint = `
|
|
4520
|
+
import { createHmac } from "crypto";
|
|
4521
|
+
|
|
4522
|
+
const SECRET = ${JSON.stringify(secret)};
|
|
4523
|
+
const LOGIN_PATH = ${JSON.stringify(loginPath)};
|
|
4524
|
+
const PUBLIC = ${JSON.stringify(publicPatterns)};
|
|
4525
|
+
const COOKIE = ${JSON.stringify(AUTH_COOKIE_NAME)};
|
|
4526
|
+
|
|
4527
|
+
const isPublic = (uri) => {
|
|
4528
|
+
for (const p of PUBLIC) {
|
|
4529
|
+
if (p.endsWith("/*")) {
|
|
4530
|
+
if (uri.startsWith(p.slice(0, -1))) return true;
|
|
4531
|
+
} else if (p.endsWith("*")) {
|
|
4532
|
+
if (uri.startsWith(p.slice(0, -1))) return true;
|
|
4533
|
+
} else {
|
|
4534
|
+
if (uri === p) return true;
|
|
4535
|
+
}
|
|
4536
|
+
}
|
|
4537
|
+
return false;
|
|
4538
|
+
};
|
|
4539
|
+
|
|
4540
|
+
const verify = (cookie) => {
|
|
4541
|
+
if (!cookie) return false;
|
|
4542
|
+
const dot = cookie.indexOf(".");
|
|
4543
|
+
if (dot === -1) return false;
|
|
4544
|
+
const payload = cookie.slice(0, dot);
|
|
4545
|
+
const sig = cookie.slice(dot + 1);
|
|
4546
|
+
const expected = createHmac("sha256", SECRET).update(payload).digest("base64url");
|
|
4547
|
+
if (sig !== expected) return false;
|
|
4548
|
+
try {
|
|
4549
|
+
const data = JSON.parse(Buffer.from(payload, "base64url").toString("utf-8"));
|
|
4550
|
+
return data.exp > Math.floor(Date.now() / 1000);
|
|
4551
|
+
} catch { return false; }
|
|
4552
|
+
};
|
|
4553
|
+
|
|
4554
|
+
const parseCookies = (headers) => {
|
|
4555
|
+
const cookies = {};
|
|
4556
|
+
const cookieHeaders = headers.cookie;
|
|
4557
|
+
if (!cookieHeaders) return cookies;
|
|
4558
|
+
for (const { value } of cookieHeaders) {
|
|
4559
|
+
for (const pair of value.split(";")) {
|
|
4560
|
+
const eq = pair.indexOf("=");
|
|
4561
|
+
if (eq === -1) continue;
|
|
4562
|
+
const name = pair.slice(0, eq).trim();
|
|
4563
|
+
const val = pair.slice(eq + 1).trim();
|
|
4564
|
+
if (name) cookies[name] = val;
|
|
4565
|
+
}
|
|
4566
|
+
}
|
|
4567
|
+
return cookies;
|
|
4568
|
+
};
|
|
4569
|
+
|
|
4570
|
+
const rewrite = (uri) => {
|
|
4571
|
+
if (uri.endsWith("/")) return uri + "index.html";
|
|
4572
|
+
if (!uri.includes(".")) return uri + "/index.html";
|
|
4573
|
+
return uri;
|
|
4574
|
+
};
|
|
4575
|
+
|
|
4576
|
+
export const handler = async (event) => {
|
|
4577
|
+
const req = event.Records[0].cf.request;
|
|
4578
|
+
|
|
4579
|
+
if (isPublic(req.uri)) {
|
|
4580
|
+
req.uri = rewrite(req.uri);
|
|
4581
|
+
return req;
|
|
4582
|
+
}
|
|
4583
|
+
|
|
4584
|
+
const cookies = parseCookies(req.headers);
|
|
4585
|
+
if (verify(cookies[COOKIE])) {
|
|
4586
|
+
req.uri = rewrite(req.uri);
|
|
4587
|
+
return req;
|
|
4588
|
+
}
|
|
4589
|
+
|
|
4590
|
+
return {
|
|
4591
|
+
status: "302",
|
|
4592
|
+
statusDescription: "Found",
|
|
4593
|
+
headers: { location: [{ key: "Location", value: LOGIN_PATH }] },
|
|
4594
|
+
};
|
|
4595
|
+
};
|
|
4596
|
+
`;
|
|
4597
|
+
const result = yield* Effect24.tryPromise({
|
|
4598
|
+
try: () => esbuild.build({
|
|
4599
|
+
stdin: { contents: entryPoint, loader: "js", resolveDir: process.cwd() },
|
|
4600
|
+
bundle: true,
|
|
4601
|
+
platform: "node",
|
|
4602
|
+
target: "node22",
|
|
4603
|
+
write: false,
|
|
4604
|
+
minify: true,
|
|
4605
|
+
sourcemap: false,
|
|
4606
|
+
format: "esm",
|
|
4607
|
+
external: ["crypto"]
|
|
4608
|
+
}),
|
|
4609
|
+
catch: (error) => new Error(`esbuild failed (auth middleware): ${error}`)
|
|
4610
|
+
});
|
|
4611
|
+
const output = result.outputFiles?.[0];
|
|
4612
|
+
if (!output) throw new Error("esbuild produced no output for auth middleware");
|
|
4613
|
+
return output.text;
|
|
4614
|
+
});
|
|
4374
4615
|
var FIXED_DATE2 = /* @__PURE__ */ new Date(0);
|
|
4375
4616
|
var zip = (input) => Effect24.async((resume) => {
|
|
4376
4617
|
const chunks = [];
|
|
@@ -4470,21 +4711,25 @@ var flattenHandlers = (discovered) => {
|
|
|
4470
4711
|
];
|
|
4471
4712
|
};
|
|
4472
4713
|
|
|
4714
|
+
// src/deploy/deploy.ts
|
|
4715
|
+
import * as crypto5 from "crypto";
|
|
4716
|
+
|
|
4473
4717
|
// src/deploy/resolve-config.ts
|
|
4474
4718
|
import { Effect as Effect25 } from "effect";
|
|
4475
|
-
var
|
|
4719
|
+
var collectRequiredSecrets = (handlers, project, stage) => {
|
|
4476
4720
|
const seen = /* @__PURE__ */ new Map();
|
|
4477
4721
|
const collect = (handlerGroups) => {
|
|
4478
4722
|
for (const { exports } of handlerGroups) {
|
|
4479
4723
|
for (const fn13 of exports) {
|
|
4480
|
-
for (const { propName, ssmKey } of fn13.
|
|
4724
|
+
for (const { propName, ssmKey, generate } of fn13.secretEntries) {
|
|
4481
4725
|
const ssmPath = `/${project}/${stage}/${ssmKey}`;
|
|
4482
4726
|
if (!seen.has(ssmPath)) {
|
|
4483
4727
|
seen.set(ssmPath, {
|
|
4484
4728
|
ssmPath,
|
|
4485
4729
|
propName,
|
|
4486
4730
|
ssmKey,
|
|
4487
|
-
handlerName: fn13.exportName
|
|
4731
|
+
handlerName: fn13.exportName,
|
|
4732
|
+
...generate ? { generate } : {}
|
|
4488
4733
|
});
|
|
4489
4734
|
}
|
|
4490
4735
|
}
|
|
@@ -4497,11 +4742,34 @@ var collectRequiredParams = (handlers, project, stage) => {
|
|
|
4497
4742
|
collect(handlers.apiHandlers);
|
|
4498
4743
|
return Array.from(seen.values());
|
|
4499
4744
|
};
|
|
4500
|
-
var
|
|
4501
|
-
|
|
4745
|
+
var AUTH_SSM_KEY = "_auth-secret";
|
|
4746
|
+
var collectAuthSecret = (handlers, project, stage) => {
|
|
4747
|
+
const hasAuth = (groups) => groups.some((g) => g.exports.some((fn13) => fn13.authConfig));
|
|
4748
|
+
if (hasAuth(handlers.apiHandlers) || hasAuth(handlers.staticSiteHandlers)) {
|
|
4749
|
+
return {
|
|
4750
|
+
ssmPath: `/${project}/${stage}/${AUTH_SSM_KEY}`,
|
|
4751
|
+
propName: "_authSecret",
|
|
4752
|
+
ssmKey: AUTH_SSM_KEY,
|
|
4753
|
+
handlerName: "_auth",
|
|
4754
|
+
generate: { type: "hex", bytes: 32 }
|
|
4755
|
+
};
|
|
4756
|
+
}
|
|
4757
|
+
return void 0;
|
|
4758
|
+
};
|
|
4759
|
+
var fetchAuthSecretValue = (ssmPath) => Effect25.gen(function* () {
|
|
4760
|
+
const result = yield* ssm_exports.make("get_parameters", {
|
|
4761
|
+
Names: [ssmPath],
|
|
4762
|
+
WithDecryption: true
|
|
4763
|
+
});
|
|
4764
|
+
const value = result.Parameters?.[0]?.Value;
|
|
4765
|
+
if (!value) throw new Error(`Auth secret not found at ${ssmPath}`);
|
|
4766
|
+
return value;
|
|
4767
|
+
});
|
|
4768
|
+
var checkMissingSecrets = (secrets) => Effect25.gen(function* () {
|
|
4769
|
+
if (secrets.length === 0) return { existing: [], missing: [] };
|
|
4502
4770
|
const existingNames = /* @__PURE__ */ new Set();
|
|
4503
|
-
for (let i = 0; i <
|
|
4504
|
-
const batch =
|
|
4771
|
+
for (let i = 0; i < secrets.length; i += 10) {
|
|
4772
|
+
const batch = secrets.slice(i, i + 10);
|
|
4505
4773
|
const result = yield* ssm_exports.make("get_parameters", {
|
|
4506
4774
|
Names: batch.map((p) => p.ssmPath),
|
|
4507
4775
|
WithDecryption: false
|
|
@@ -4512,7 +4780,7 @@ var checkMissingParams = (params) => Effect25.gen(function* () {
|
|
|
4512
4780
|
}
|
|
4513
4781
|
const existing = [];
|
|
4514
4782
|
const missing = [];
|
|
4515
|
-
for (const p of
|
|
4783
|
+
for (const p of secrets) {
|
|
4516
4784
|
if (existingNames.has(p.ssmPath)) {
|
|
4517
4785
|
existing.push(p);
|
|
4518
4786
|
} else {
|
|
@@ -4530,6 +4798,12 @@ import { toSeconds } from "effortless-aws";
|
|
|
4530
4798
|
import { Effect as Effect26 } from "effect";
|
|
4531
4799
|
import * as fs3 from "fs/promises";
|
|
4532
4800
|
import * as path4 from "path";
|
|
4801
|
+
var formatBytes = (bytes) => {
|
|
4802
|
+
if (bytes < 1024) return `${bytes}B`;
|
|
4803
|
+
const kb = bytes / 1024;
|
|
4804
|
+
if (kb < 1024) return `${kb.toFixed(1)}KB`;
|
|
4805
|
+
return `${(kb / 1024).toFixed(2)}MB`;
|
|
4806
|
+
};
|
|
4533
4807
|
var readSource = (input) => Effect26.gen(function* () {
|
|
4534
4808
|
if ("code" in input && typeof input.code === "string") {
|
|
4535
4809
|
return input.code;
|
|
@@ -4542,10 +4816,11 @@ var ensureLayerAndExternal = (input) => Effect26.gen(function* () {
|
|
|
4542
4816
|
project: input.project,
|
|
4543
4817
|
stage: input.stage,
|
|
4544
4818
|
region: input.region,
|
|
4545
|
-
projectDir: input.packageDir
|
|
4819
|
+
projectDir: input.packageDir,
|
|
4820
|
+
extraNodeModules: input.extraNodeModules
|
|
4546
4821
|
});
|
|
4547
4822
|
const prodDeps = layerResult ? yield* readProductionDependencies(input.packageDir) : [];
|
|
4548
|
-
const { packages: external, warnings: layerWarnings } = prodDeps.length > 0 ? yield* Effect26.sync(() => collectLayerPackages(input.packageDir, prodDeps)) : { packages: [], warnings: [] };
|
|
4823
|
+
const { packages: external, warnings: layerWarnings } = prodDeps.length > 0 ? yield* Effect26.sync(() => collectLayerPackages(input.packageDir, prodDeps, input.extraNodeModules)) : { packages: [], warnings: [] };
|
|
4549
4824
|
for (const warning of layerWarnings) {
|
|
4550
4825
|
yield* Effect26.logWarning(`[layer] ${warning}`);
|
|
4551
4826
|
}
|
|
@@ -4590,14 +4865,21 @@ var deployCoreLambda = ({
|
|
|
4590
4865
|
mergedPermissions.length > 0 ? mergedPermissions : void 0,
|
|
4591
4866
|
makeTags(tagCtx, "iam-role")
|
|
4592
4867
|
);
|
|
4593
|
-
const
|
|
4868
|
+
const bundleResult = yield* bundle({
|
|
4594
4869
|
...input,
|
|
4595
4870
|
exportName,
|
|
4596
4871
|
...bundleType ? { type: bundleType } : {},
|
|
4597
4872
|
...external && external.length > 0 ? { external } : {}
|
|
4598
4873
|
});
|
|
4599
4874
|
const staticFiles = staticGlobs && staticGlobs.length > 0 ? resolveStaticFiles(staticGlobs, input.projectDir) : void 0;
|
|
4600
|
-
const
|
|
4875
|
+
const bundleSize = Buffer.byteLength(bundleResult.code, "utf-8");
|
|
4876
|
+
if (bundleResult.topModules && bundleSize > 500 * 1024) {
|
|
4877
|
+
const top = bundleResult.topModules.slice(0, 10);
|
|
4878
|
+
const lines = top.map((m) => ` ${formatBytes(m.bytes).padStart(8)} ${m.path}`).join("\n");
|
|
4879
|
+
yield* Effect26.logWarning(`Bundle "${handlerName}" is ${formatBytes(bundleSize)} \u2014 top modules:
|
|
4880
|
+
${lines}`);
|
|
4881
|
+
}
|
|
4882
|
+
const code = yield* zip({ content: bundleResult.code, staticFiles });
|
|
4601
4883
|
const environment = {
|
|
4602
4884
|
EFF_PROJECT: input.project,
|
|
4603
4885
|
EFF_STAGE: tagCtx.stage,
|
|
@@ -4617,7 +4899,7 @@ var deployCoreLambda = ({
|
|
|
4617
4899
|
...layerArn ? { layers: [layerArn] } : {},
|
|
4618
4900
|
environment
|
|
4619
4901
|
});
|
|
4620
|
-
return { functionArn, status, tagCtx };
|
|
4902
|
+
return { functionArn, status, tagCtx, bundleSize };
|
|
4621
4903
|
});
|
|
4622
4904
|
|
|
4623
4905
|
// src/deploy/deploy-table.ts
|
|
@@ -4639,7 +4921,7 @@ var deployTableFunction = ({ input, fn: fn13, layerArn, external, depsEnv, depsP
|
|
|
4639
4921
|
tags: makeTags(tagCtx, "dynamodb")
|
|
4640
4922
|
});
|
|
4641
4923
|
const selfEnv = { EFF_DEP_SELF: `table:${tableName}`, ...depsEnv };
|
|
4642
|
-
const { functionArn, status } = yield* deployCoreLambda({
|
|
4924
|
+
const { functionArn, status, bundleSize } = yield* deployCoreLambda({
|
|
4643
4925
|
input,
|
|
4644
4926
|
exportName,
|
|
4645
4927
|
handlerName,
|
|
@@ -4667,6 +4949,7 @@ var deployTableFunction = ({ input, fn: fn13, layerArn, external, depsEnv, depsP
|
|
|
4667
4949
|
exportName,
|
|
4668
4950
|
functionArn,
|
|
4669
4951
|
status,
|
|
4952
|
+
bundleSize,
|
|
4670
4953
|
tableArn,
|
|
4671
4954
|
streamArn
|
|
4672
4955
|
};
|
|
@@ -4683,7 +4966,8 @@ var deployTable = (input) => Effect27.gen(function* () {
|
|
|
4683
4966
|
project: input.project,
|
|
4684
4967
|
stage: resolveStage(input.stage),
|
|
4685
4968
|
region: input.region,
|
|
4686
|
-
packageDir: input.packageDir ?? input.projectDir
|
|
4969
|
+
packageDir: input.packageDir ?? input.projectDir,
|
|
4970
|
+
extraNodeModules: input.extraNodeModules
|
|
4687
4971
|
});
|
|
4688
4972
|
const result = yield* deployTableFunction({
|
|
4689
4973
|
input,
|
|
@@ -4712,7 +4996,8 @@ var deployAllTables = (input) => Effect27.gen(function* () {
|
|
|
4712
4996
|
project: input.project,
|
|
4713
4997
|
stage: resolveStage(input.stage),
|
|
4714
4998
|
region: input.region,
|
|
4715
|
-
packageDir: input.packageDir ?? input.projectDir
|
|
4999
|
+
packageDir: input.packageDir ?? input.projectDir,
|
|
5000
|
+
extraNodeModules: input.extraNodeModules
|
|
4716
5001
|
});
|
|
4717
5002
|
const results = yield* Effect27.forEach(
|
|
4718
5003
|
functions,
|
|
@@ -4741,7 +5026,7 @@ import { toSeconds as toSeconds2 } from "effortless-aws";
|
|
|
4741
5026
|
var deployApiFunction = ({ input, fn: fn13, layerArn, external, depsEnv, depsPermissions, staticGlobs }) => Effect28.gen(function* () {
|
|
4742
5027
|
const { exportName, config } = fn13;
|
|
4743
5028
|
const handlerName = exportName;
|
|
4744
|
-
const { functionArn, status } = yield* deployCoreLambda({
|
|
5029
|
+
const { functionArn, status, bundleSize } = yield* deployCoreLambda({
|
|
4745
5030
|
input,
|
|
4746
5031
|
exportName,
|
|
4747
5032
|
handlerName,
|
|
@@ -4755,7 +5040,7 @@ var deployApiFunction = ({ input, fn: fn13, layerArn, external, depsEnv, depsPer
|
|
|
4755
5040
|
...depsPermissions ? { depsPermissions } : {},
|
|
4756
5041
|
...staticGlobs && staticGlobs.length > 0 ? { staticGlobs } : {}
|
|
4757
5042
|
});
|
|
4758
|
-
return { exportName, functionArn, status, config, handlerName };
|
|
5043
|
+
return { exportName, functionArn, status, bundleSize, config, handlerName };
|
|
4759
5044
|
});
|
|
4760
5045
|
var deploy = (input) => Effect28.gen(function* () {
|
|
4761
5046
|
const source = yield* readSource(input);
|
|
@@ -4776,7 +5061,8 @@ var deploy = (input) => Effect28.gen(function* () {
|
|
|
4776
5061
|
project: input.project,
|
|
4777
5062
|
stage: tagCtx.stage,
|
|
4778
5063
|
region: input.region,
|
|
4779
|
-
packageDir: input.packageDir ?? input.projectDir
|
|
5064
|
+
packageDir: input.packageDir ?? input.projectDir,
|
|
5065
|
+
extraNodeModules: input.extraNodeModules
|
|
4780
5066
|
});
|
|
4781
5067
|
const { functionArn } = yield* deployApiFunction({
|
|
4782
5068
|
input,
|
|
@@ -5138,6 +5424,12 @@ var deployMiddlewareLambda = (input) => Effect31.gen(function* () {
|
|
|
5138
5424
|
makeTags(tagCtx, "iam-role")
|
|
5139
5425
|
);
|
|
5140
5426
|
const bundled = yield* bundleMiddleware({ projectDir, file });
|
|
5427
|
+
const bundleSizeKB = Math.round(bundled.length / 1024);
|
|
5428
|
+
if (bundleSizeKB > 50) {
|
|
5429
|
+
yield* Effect31.logWarning(
|
|
5430
|
+
`[middleware] Bundle size is ${bundleSizeKB}KB (expected <50KB). Middleware may be pulling in unrelated dependencies via barrel imports. Use direct file imports instead (e.g. import { Auth } from "./core/auth" instead of "./core").`
|
|
5431
|
+
);
|
|
5432
|
+
}
|
|
5141
5433
|
const code = yield* zip({ content: bundled });
|
|
5142
5434
|
const { functionArn } = yield* ensureLambda({
|
|
5143
5435
|
project,
|
|
@@ -5153,14 +5445,52 @@ var deployMiddlewareLambda = (input) => Effect31.gen(function* () {
|
|
|
5153
5445
|
}).pipe(
|
|
5154
5446
|
Effect31.provide(clients_exports.makeClients({ lambda: { region: "us-east-1" } }))
|
|
5155
5447
|
);
|
|
5156
|
-
const
|
|
5157
|
-
|
|
5158
|
-
|
|
5448
|
+
const edgeFunctionName = `${project}-${stage}-${middlewareName}`;
|
|
5449
|
+
yield* ensureEdgePermission(edgeFunctionName).pipe(
|
|
5450
|
+
Effect31.provide(clients_exports.makeClients({ lambda: { region: "us-east-1" } }))
|
|
5451
|
+
);
|
|
5452
|
+
const { versionArn } = yield* publishVersion(edgeFunctionName).pipe(
|
|
5159
5453
|
Effect31.provide(clients_exports.makeClients({ lambda: { region: "us-east-1" } }))
|
|
5160
5454
|
);
|
|
5161
5455
|
yield* Effect31.logDebug(`Middleware deployed: ${versionArn}`);
|
|
5162
5456
|
return { versionArn };
|
|
5163
5457
|
});
|
|
5458
|
+
var deployAuthMiddlewareLambda = (input) => Effect31.gen(function* () {
|
|
5459
|
+
const { project, stage, handlerName, tagCtx, authConfig, authSecret } = input;
|
|
5460
|
+
const middlewareName = `${handlerName}-middleware`;
|
|
5461
|
+
yield* Effect31.logDebug(`Deploying auth middleware Lambda@Edge: ${middlewareName}`);
|
|
5462
|
+
const roleArn = yield* ensureEdgeRole(
|
|
5463
|
+
project,
|
|
5464
|
+
stage,
|
|
5465
|
+
middlewareName,
|
|
5466
|
+
makeTags(tagCtx, "iam-role")
|
|
5467
|
+
);
|
|
5468
|
+
const bundled = yield* bundleAuthMiddleware({ authConfig, secret: authSecret });
|
|
5469
|
+
const code = yield* zip({ content: bundled });
|
|
5470
|
+
const edgeFunctionName = `${project}-${stage}-${middlewareName}`;
|
|
5471
|
+
yield* ensureLambda({
|
|
5472
|
+
project,
|
|
5473
|
+
stage,
|
|
5474
|
+
name: middlewareName,
|
|
5475
|
+
region: "us-east-1",
|
|
5476
|
+
roleArn,
|
|
5477
|
+
code,
|
|
5478
|
+
memory: 128,
|
|
5479
|
+
timeout: 5,
|
|
5480
|
+
architecture: Architecture3.x86_64,
|
|
5481
|
+
tags: makeTags(tagCtx, "lambda")
|
|
5482
|
+
}).pipe(
|
|
5483
|
+
Effect31.provide(clients_exports.makeClients({ lambda: { region: "us-east-1" } }))
|
|
5484
|
+
);
|
|
5485
|
+
yield* ensureEdgePermission(edgeFunctionName).pipe(
|
|
5486
|
+
Effect31.provide(clients_exports.makeClients({ lambda: { region: "us-east-1" } }))
|
|
5487
|
+
);
|
|
5488
|
+
const { versionArn } = yield* publishVersion(edgeFunctionName).pipe(
|
|
5489
|
+
Effect31.provide(clients_exports.makeClients({ lambda: { region: "us-east-1" } }))
|
|
5490
|
+
);
|
|
5491
|
+
yield* Effect31.logDebug(`Auth middleware deployed: ${versionArn}`);
|
|
5492
|
+
return { versionArn };
|
|
5493
|
+
});
|
|
5164
5494
|
var ERROR_PAGE_KEY = "_effortless/404.html";
|
|
5165
5495
|
var generateErrorPageHtml = () => `<!DOCTYPE html>
|
|
5166
5496
|
<html lang="en">
|
|
@@ -5265,7 +5595,20 @@ var deployStaticSite = (input) => Effect31.gen(function* () {
|
|
|
5265
5595
|
const isSpa = config.spa ?? false;
|
|
5266
5596
|
let urlRewriteFunctionArn;
|
|
5267
5597
|
let lambdaEdgeArn;
|
|
5268
|
-
|
|
5598
|
+
const hasAuth = !!(input.authSecret && input.authConfig);
|
|
5599
|
+
if (hasAuth) {
|
|
5600
|
+
const authResult = yield* deployAuthMiddlewareLambda({
|
|
5601
|
+
project,
|
|
5602
|
+
stage,
|
|
5603
|
+
handlerName,
|
|
5604
|
+
tagCtx,
|
|
5605
|
+
authConfig: input.authConfig,
|
|
5606
|
+
authSecret: input.authSecret
|
|
5607
|
+
}).pipe(
|
|
5608
|
+
Effect31.provide(clients_exports.makeClients({ iam: { region: "us-east-1" } }))
|
|
5609
|
+
);
|
|
5610
|
+
lambdaEdgeArn = authResult.versionArn;
|
|
5611
|
+
} else if (hasMiddleware && input.file) {
|
|
5269
5612
|
const result = yield* deployMiddlewareLambda({
|
|
5270
5613
|
projectDir,
|
|
5271
5614
|
project,
|
|
@@ -5395,7 +5738,7 @@ var deployFifoQueueFunction = ({ input, fn: fn13, layerArn, external, depsEnv, d
|
|
|
5395
5738
|
EFF_QUEUE_ARN: queueArn,
|
|
5396
5739
|
...depsEnv
|
|
5397
5740
|
};
|
|
5398
|
-
const { functionArn, status } = yield* deployCoreLambda({
|
|
5741
|
+
const { functionArn, status, bundleSize } = yield* deployCoreLambda({
|
|
5399
5742
|
input,
|
|
5400
5743
|
exportName,
|
|
5401
5744
|
handlerName,
|
|
@@ -5422,6 +5765,7 @@ var deployFifoQueueFunction = ({ input, fn: fn13, layerArn, external, depsEnv, d
|
|
|
5422
5765
|
exportName,
|
|
5423
5766
|
functionArn,
|
|
5424
5767
|
status,
|
|
5768
|
+
bundleSize,
|
|
5425
5769
|
queueUrl,
|
|
5426
5770
|
queueArn
|
|
5427
5771
|
};
|
|
@@ -5456,7 +5800,7 @@ var deployBucketFunction = ({ input, fn: fn13, layerArn, external, depsEnv, deps
|
|
|
5456
5800
|
};
|
|
5457
5801
|
}
|
|
5458
5802
|
const selfEnv = { EFF_DEP_SELF: `bucket:${bucketName}`, ...depsEnv };
|
|
5459
|
-
const { functionArn, status } = yield* deployCoreLambda({
|
|
5803
|
+
const { functionArn, status, bundleSize } = yield* deployCoreLambda({
|
|
5460
5804
|
input,
|
|
5461
5805
|
exportName,
|
|
5462
5806
|
handlerName,
|
|
@@ -5484,6 +5828,7 @@ var deployBucketFunction = ({ input, fn: fn13, layerArn, external, depsEnv, deps
|
|
|
5484
5828
|
exportName,
|
|
5485
5829
|
functionArn,
|
|
5486
5830
|
status,
|
|
5831
|
+
bundleSize,
|
|
5487
5832
|
bucketName,
|
|
5488
5833
|
bucketArn
|
|
5489
5834
|
};
|
|
@@ -5564,10 +5909,17 @@ var createLiveProgress = (manifest) => {
|
|
|
5564
5909
|
const sec = ((Date.now() - startTime) / 1e3).toFixed(1);
|
|
5565
5910
|
return c.dim(`${sec}s`);
|
|
5566
5911
|
};
|
|
5567
|
-
|
|
5912
|
+
const formatSize = (bytes) => {
|
|
5913
|
+
if (bytes < 1024) return `${bytes}B`;
|
|
5914
|
+
const kb = bytes / 1024;
|
|
5915
|
+
if (kb < 1024) return `${kb.toFixed(0)}KB`;
|
|
5916
|
+
return `${(kb / 1024).toFixed(1)}MB`;
|
|
5917
|
+
};
|
|
5918
|
+
return (name, type, status, bundleSize) => Effect35.sync(() => {
|
|
5568
5919
|
const key = `${name}:${type}`;
|
|
5569
5920
|
results.set(key, status);
|
|
5570
|
-
const
|
|
5921
|
+
const sizeInfo = bundleSize ? ` ${c.dim(formatSize(bundleSize))}` : "";
|
|
5922
|
+
const line = ` ${name} ${c.dim(`(${type})`)} ${statusLabel(status)}${sizeInfo} ${formatDuration()}`;
|
|
5571
5923
|
if (isTTY) {
|
|
5572
5924
|
const idx = lineIndex.get(key) ?? 0;
|
|
5573
5925
|
const up = manifest.length - idx;
|
|
@@ -5576,7 +5928,7 @@ var createLiveProgress = (manifest) => {
|
|
|
5576
5928
|
clearInterval(timer);
|
|
5577
5929
|
}
|
|
5578
5930
|
} else {
|
|
5579
|
-
process.stdout.write(` ${c.dim(`[${results.size}/${manifest.length}]`)} ${name} ${c.dim(`(${type})`)} ${statusLabel(status)} ${formatDuration()}
|
|
5931
|
+
process.stdout.write(` ${c.dim(`[${results.size}/${manifest.length}]`)} ${name} ${c.dim(`(${type})`)} ${statusLabel(status)}${sizeInfo} ${formatDuration()}
|
|
5580
5932
|
`);
|
|
5581
5933
|
}
|
|
5582
5934
|
});
|
|
@@ -5587,7 +5939,8 @@ var prepareLayer = (input) => Effect35.gen(function* () {
|
|
|
5587
5939
|
project: input.project,
|
|
5588
5940
|
stage: input.stage,
|
|
5589
5941
|
region: input.region,
|
|
5590
|
-
projectDir: input.packageDir
|
|
5942
|
+
projectDir: input.packageDir,
|
|
5943
|
+
extraNodeModules: input.extraNodeModules
|
|
5591
5944
|
}).pipe(
|
|
5592
5945
|
Effect35.provide(
|
|
5593
5946
|
clients_exports.makeClients({
|
|
@@ -5596,7 +5949,7 @@ var prepareLayer = (input) => Effect35.gen(function* () {
|
|
|
5596
5949
|
)
|
|
5597
5950
|
);
|
|
5598
5951
|
const prodDeps = layerResult ? yield* readProductionDependencies(input.packageDir) : [];
|
|
5599
|
-
const { packages: external, warnings: layerWarnings } = prodDeps.length > 0 ? yield* Effect35.sync(() => collectLayerPackages(input.packageDir, prodDeps)) : { packages: [], warnings: [] };
|
|
5952
|
+
const { packages: external, warnings: layerWarnings } = prodDeps.length > 0 ? yield* Effect35.sync(() => collectLayerPackages(input.packageDir, prodDeps, input.extraNodeModules)) : { packages: [], warnings: [] };
|
|
5600
5953
|
for (const warning of layerWarnings) {
|
|
5601
5954
|
yield* Effect35.logWarning(`[layer] ${warning}`);
|
|
5602
5955
|
}
|
|
@@ -5742,10 +6095,20 @@ var SSM_PERMISSIONS = [
|
|
|
5742
6095
|
"ssm:GetParameter",
|
|
5743
6096
|
"ssm:GetParameters"
|
|
5744
6097
|
];
|
|
5745
|
-
var
|
|
5746
|
-
|
|
6098
|
+
var executeGenerateSpec = (spec) => {
|
|
6099
|
+
switch (spec.type) {
|
|
6100
|
+
case "hex":
|
|
6101
|
+
return crypto5.randomBytes(spec.bytes).toString("hex");
|
|
6102
|
+
case "base64":
|
|
6103
|
+
return crypto5.randomBytes(spec.bytes).toString("base64url");
|
|
6104
|
+
case "uuid":
|
|
6105
|
+
return crypto5.randomUUID();
|
|
6106
|
+
}
|
|
6107
|
+
};
|
|
6108
|
+
var resolveSecrets = (secretEntries, project, stage) => {
|
|
6109
|
+
if (secretEntries.length === 0) return void 0;
|
|
5747
6110
|
const paramsEnv = {};
|
|
5748
|
-
for (const { propName, ssmKey } of
|
|
6111
|
+
for (const { propName, ssmKey } of secretEntries) {
|
|
5749
6112
|
paramsEnv[`EFF_PARAM_${propName}`] = `/${project}/${stage}/${ssmKey}`;
|
|
5750
6113
|
}
|
|
5751
6114
|
return { paramsEnv, paramsPermissions: SSM_PERMISSIONS };
|
|
@@ -5764,10 +6127,10 @@ var makeDeployInput = (ctx, file) => ({
|
|
|
5764
6127
|
region: ctx.input.region,
|
|
5765
6128
|
...ctx.input.stage ? { stage: ctx.input.stage } : {}
|
|
5766
6129
|
});
|
|
5767
|
-
var resolveHandlerEnv = (depsKeys,
|
|
6130
|
+
var resolveHandlerEnv = (depsKeys, secretEntries, ctx) => {
|
|
5768
6131
|
const resolved = mergeResolved(
|
|
5769
6132
|
resolveDeps(depsKeys, ctx.tableNameMap, ctx.bucketNameMap, ctx.mailerDomainMap, ctx.queueNameMap),
|
|
5770
|
-
|
|
6133
|
+
resolveSecrets(secretEntries, ctx.input.project, ctx.stage)
|
|
5771
6134
|
);
|
|
5772
6135
|
return {
|
|
5773
6136
|
depsEnv: resolved?.depsEnv ?? {},
|
|
@@ -5781,7 +6144,7 @@ var buildTableTasks = (ctx, handlers, results) => {
|
|
|
5781
6144
|
for (const fn13 of exports) {
|
|
5782
6145
|
tasks.push(
|
|
5783
6146
|
Effect35.gen(function* () {
|
|
5784
|
-
const env = resolveHandlerEnv(fn13.depsKeys, fn13.
|
|
6147
|
+
const env = resolveHandlerEnv(fn13.depsKeys, fn13.secretEntries, ctx);
|
|
5785
6148
|
const result = yield* deployTableFunction({
|
|
5786
6149
|
input: makeDeployInput(ctx, file),
|
|
5787
6150
|
fn: fn13,
|
|
@@ -5792,7 +6155,7 @@ var buildTableTasks = (ctx, handlers, results) => {
|
|
|
5792
6155
|
...fn13.staticGlobs.length > 0 ? { staticGlobs: fn13.staticGlobs } : {}
|
|
5793
6156
|
}).pipe(Effect35.provide(clients_exports.makeClients({ lambda: { region }, iam: { region }, dynamodb: { region } })));
|
|
5794
6157
|
results.push(result);
|
|
5795
|
-
yield* ctx.logComplete(fn13.exportName, "table", result.status);
|
|
6158
|
+
yield* ctx.logComplete(fn13.exportName, "table", result.status, result.bundleSize);
|
|
5796
6159
|
})
|
|
5797
6160
|
);
|
|
5798
6161
|
}
|
|
@@ -5837,6 +6200,12 @@ var buildStaticSiteTasks = (ctx, handlers, results, apiOriginDomain) => {
|
|
|
5837
6200
|
for (const fn13 of exports) {
|
|
5838
6201
|
tasks.push(
|
|
5839
6202
|
Effect35.gen(function* () {
|
|
6203
|
+
let authSecretValue;
|
|
6204
|
+
if (fn13.authConfig && ctx.authSecretPath) {
|
|
6205
|
+
authSecretValue = yield* fetchAuthSecretValue(ctx.authSecretPath).pipe(
|
|
6206
|
+
Effect35.provide(clients_exports.makeClients({ ssm: { region: ctx.input.region } }))
|
|
6207
|
+
);
|
|
6208
|
+
}
|
|
5840
6209
|
const result = yield* deployStaticSite({
|
|
5841
6210
|
projectDir: ctx.input.projectDir,
|
|
5842
6211
|
project: ctx.input.project,
|
|
@@ -5845,7 +6214,8 @@ var buildStaticSiteTasks = (ctx, handlers, results, apiOriginDomain) => {
|
|
|
5845
6214
|
fn: fn13,
|
|
5846
6215
|
verbose: ctx.input.verbose,
|
|
5847
6216
|
...fn13.hasHandler ? { file } : {},
|
|
5848
|
-
...apiOriginDomain ? { apiOriginDomain } : {}
|
|
6217
|
+
...apiOriginDomain ? { apiOriginDomain } : {},
|
|
6218
|
+
...authSecretValue && fn13.authConfig ? { authSecret: authSecretValue, authConfig: fn13.authConfig } : {}
|
|
5849
6219
|
}).pipe(Effect35.provide(clients_exports.makeClients({
|
|
5850
6220
|
s3: { region },
|
|
5851
6221
|
cloudfront: { region: "us-east-1" },
|
|
@@ -5867,7 +6237,7 @@ var buildFifoQueueTasks = (ctx, handlers, results) => {
|
|
|
5867
6237
|
for (const fn13 of exports) {
|
|
5868
6238
|
tasks.push(
|
|
5869
6239
|
Effect35.gen(function* () {
|
|
5870
|
-
const env = resolveHandlerEnv(fn13.depsKeys, fn13.
|
|
6240
|
+
const env = resolveHandlerEnv(fn13.depsKeys, fn13.secretEntries, ctx);
|
|
5871
6241
|
const result = yield* deployFifoQueueFunction({
|
|
5872
6242
|
input: makeDeployInput(ctx, file),
|
|
5873
6243
|
fn: fn13,
|
|
@@ -5878,7 +6248,7 @@ var buildFifoQueueTasks = (ctx, handlers, results) => {
|
|
|
5878
6248
|
...fn13.staticGlobs.length > 0 ? { staticGlobs: fn13.staticGlobs } : {}
|
|
5879
6249
|
}).pipe(Effect35.provide(clients_exports.makeClients({ lambda: { region }, iam: { region }, sqs: { region } })));
|
|
5880
6250
|
results.push(result);
|
|
5881
|
-
yield* ctx.logComplete(fn13.exportName, "queue", result.status);
|
|
6251
|
+
yield* ctx.logComplete(fn13.exportName, "queue", result.status, result.bundleSize);
|
|
5882
6252
|
})
|
|
5883
6253
|
);
|
|
5884
6254
|
}
|
|
@@ -5892,7 +6262,7 @@ var buildBucketTasks = (ctx, handlers, results) => {
|
|
|
5892
6262
|
for (const fn13 of exports) {
|
|
5893
6263
|
tasks.push(
|
|
5894
6264
|
Effect35.gen(function* () {
|
|
5895
|
-
const env = resolveHandlerEnv(fn13.depsKeys, fn13.
|
|
6265
|
+
const env = resolveHandlerEnv(fn13.depsKeys, fn13.secretEntries, ctx);
|
|
5896
6266
|
const result = yield* deployBucketFunction({
|
|
5897
6267
|
input: makeDeployInput(ctx, file),
|
|
5898
6268
|
fn: fn13,
|
|
@@ -5904,7 +6274,7 @@ var buildBucketTasks = (ctx, handlers, results) => {
|
|
|
5904
6274
|
}).pipe(Effect35.provide(clients_exports.makeClients({ lambda: { region }, iam: { region }, s3: { region } })));
|
|
5905
6275
|
results.push(result);
|
|
5906
6276
|
const status = result.status === "resource-only" ? "created" : result.status;
|
|
5907
|
-
yield* ctx.logComplete(fn13.exportName, "bucket", status);
|
|
6277
|
+
yield* ctx.logComplete(fn13.exportName, "bucket", status, result.bundleSize);
|
|
5908
6278
|
})
|
|
5909
6279
|
);
|
|
5910
6280
|
}
|
|
@@ -5939,8 +6309,12 @@ var buildApiTasks = (ctx, handlers, results) => {
|
|
|
5939
6309
|
for (const fn13 of exports) {
|
|
5940
6310
|
tasks.push(
|
|
5941
6311
|
Effect35.gen(function* () {
|
|
5942
|
-
const env = resolveHandlerEnv(fn13.depsKeys, fn13.
|
|
5943
|
-
|
|
6312
|
+
const env = resolveHandlerEnv(fn13.depsKeys, fn13.secretEntries, ctx);
|
|
6313
|
+
if (fn13.authConfig && ctx.authSecretPath) {
|
|
6314
|
+
env.depsEnv["EFF_AUTH_SECRET"] = ctx.authSecretPath;
|
|
6315
|
+
env.depsPermissions = [...env.depsPermissions, "ssm:GetParameter", "ssm:GetParameters"];
|
|
6316
|
+
}
|
|
6317
|
+
const { exportName, functionArn, status, bundleSize, handlerName } = yield* deployApiFunction({
|
|
5944
6318
|
input: makeDeployInput(ctx, file),
|
|
5945
6319
|
fn: fn13,
|
|
5946
6320
|
...ctx.layerArn ? { layerArn: ctx.layerArn } : {},
|
|
@@ -5957,7 +6331,7 @@ var buildApiTasks = (ctx, handlers, results) => {
|
|
|
5957
6331
|
Effect35.provide(clients_exports.makeClients({ lambda: { region } }))
|
|
5958
6332
|
);
|
|
5959
6333
|
results.push({ exportName, url: functionUrl, functionArn });
|
|
5960
|
-
yield* ctx.logComplete(exportName, "api", status);
|
|
6334
|
+
yield* ctx.logComplete(exportName, "api", status, bundleSize);
|
|
5961
6335
|
})
|
|
5962
6336
|
);
|
|
5963
6337
|
}
|
|
@@ -5994,16 +6368,33 @@ var deployProject = (input) => Effect35.gen(function* () {
|
|
|
5994
6368
|
yield* Console2.log(`
|
|
5995
6369
|
${c.dim("Handlers:")} ${parts.join(", ")}`);
|
|
5996
6370
|
const discovered = { tableHandlers, appHandlers, staticSiteHandlers, fifoQueueHandlers, bucketHandlers, mailerHandlers, apiHandlers };
|
|
5997
|
-
const
|
|
5998
|
-
|
|
5999
|
-
|
|
6371
|
+
const requiredSecrets = collectRequiredSecrets(discovered, input.project, stage);
|
|
6372
|
+
const authSecret = collectAuthSecret(discovered, input.project, stage);
|
|
6373
|
+
if (authSecret) requiredSecrets.push(authSecret);
|
|
6374
|
+
if (requiredSecrets.length > 0) {
|
|
6375
|
+
const { missing } = yield* checkMissingSecrets(requiredSecrets).pipe(
|
|
6000
6376
|
Effect35.provide(clients_exports.makeClients({ ssm: { region: input.region } }))
|
|
6001
6377
|
);
|
|
6002
|
-
|
|
6378
|
+
const withGenerators = missing.filter((m) => m.generate);
|
|
6379
|
+
const manualOnly = missing.filter((m) => !m.generate);
|
|
6380
|
+
if (withGenerators.length > 0) {
|
|
6381
|
+
for (const entry of withGenerators) {
|
|
6382
|
+
const value = executeGenerateSpec(entry.generate);
|
|
6383
|
+
yield* ssm_exports.make("put_parameter", {
|
|
6384
|
+
Name: entry.ssmPath,
|
|
6385
|
+
Value: value,
|
|
6386
|
+
Type: "SecureString"
|
|
6387
|
+
}).pipe(Effect35.provide(clients_exports.makeClients({ ssm: { region: input.region } })));
|
|
6388
|
+
yield* Effect35.logDebug(`Auto-created SSM parameter: ${entry.ssmPath}`);
|
|
6389
|
+
}
|
|
6003
6390
|
yield* Console2.log(`
|
|
6004
|
-
${c.
|
|
6391
|
+
${c.green("\u2713")} Auto-created ${withGenerators.length} secret(s)`);
|
|
6392
|
+
}
|
|
6393
|
+
if (manualOnly.length > 0) {
|
|
6394
|
+
yield* Console2.log(`
|
|
6395
|
+
${c.yellow("\u26A0")} Missing ${manualOnly.length} SSM parameter(s):
|
|
6005
6396
|
`);
|
|
6006
|
-
for (const p of
|
|
6397
|
+
for (const p of manualOnly) {
|
|
6007
6398
|
yield* Console2.log(` ${c.dim(p.handlerName)} \u2192 ${c.yellow(p.ssmPath)}`);
|
|
6008
6399
|
}
|
|
6009
6400
|
yield* Console2.log(`
|
|
@@ -6027,7 +6418,8 @@ var deployProject = (input) => Effect35.gen(function* () {
|
|
|
6027
6418
|
project: input.project,
|
|
6028
6419
|
stage,
|
|
6029
6420
|
region: input.region,
|
|
6030
|
-
packageDir: input.packageDir ?? input.projectDir
|
|
6421
|
+
packageDir: input.packageDir ?? input.projectDir,
|
|
6422
|
+
extraNodeModules: input.extraNodeModules
|
|
6031
6423
|
}) : { layerArn: void 0, layerVersion: void 0, layerStatus: void 0, external: [] };
|
|
6032
6424
|
if (layerArn && layerStatus) {
|
|
6033
6425
|
const status = layerStatus === "cached" ? c.dim("cached") : c.green("created");
|
|
@@ -6062,7 +6454,8 @@ var deployProject = (input) => Effect35.gen(function* () {
|
|
|
6062
6454
|
bucketNameMap,
|
|
6063
6455
|
mailerDomainMap,
|
|
6064
6456
|
queueNameMap,
|
|
6065
|
-
logComplete
|
|
6457
|
+
logComplete,
|
|
6458
|
+
...authSecret ? { authSecretPath: authSecret.ssmPath } : {}
|
|
6066
6459
|
};
|
|
6067
6460
|
const tableResults = [];
|
|
6068
6461
|
const appResults = [];
|
|
@@ -6265,7 +6658,8 @@ var deployCommand = Command.make(
|
|
|
6265
6658
|
stage: finalStage,
|
|
6266
6659
|
region: finalRegion,
|
|
6267
6660
|
noSites,
|
|
6268
|
-
verbose
|
|
6661
|
+
verbose,
|
|
6662
|
+
extraNodeModules: projectDir !== cwd ? [path10.join(projectDir, "node_modules")] : void 0
|
|
6269
6663
|
});
|
|
6270
6664
|
const total = results.tableResults.length + results.appResults.length + results.staticSiteResults.length + results.apiResults.length;
|
|
6271
6665
|
yield* Console3.log(`
|
|
@@ -6359,7 +6753,8 @@ Deployed ${tableResults.length} table handler(s):`));
|
|
|
6359
6753
|
project,
|
|
6360
6754
|
stage: finalStage,
|
|
6361
6755
|
region: finalRegion,
|
|
6362
|
-
exportName: foundExport
|
|
6756
|
+
exportName: foundExport,
|
|
6757
|
+
extraNodeModules: projectDir !== cwd ? [path10.join(projectDir, "node_modules")] : void 0
|
|
6363
6758
|
};
|
|
6364
6759
|
if (handlerType === "table") {
|
|
6365
6760
|
const result = yield* deployTable(input);
|
|
@@ -6464,9 +6859,9 @@ var STATUS_COLORS = {
|
|
|
6464
6859
|
var formatStatus = (status) => {
|
|
6465
6860
|
return STATUS_COLORS[status](status.padEnd(10));
|
|
6466
6861
|
};
|
|
6467
|
-
var formatRoute = (method,
|
|
6468
|
-
if (method &&
|
|
6469
|
-
if (
|
|
6862
|
+
var formatRoute = (method, path13) => {
|
|
6863
|
+
if (method && path13) return `${method.padEnd(5)} ${path13}`;
|
|
6864
|
+
if (path13) return path13;
|
|
6470
6865
|
return "";
|
|
6471
6866
|
};
|
|
6472
6867
|
var formatEntry = (entry) => {
|
|
@@ -7112,15 +7507,16 @@ var layerCommand = Command5.make(
|
|
|
7112
7507
|
"layer",
|
|
7113
7508
|
{ build: buildOption, output: outputOption, verbose: verboseOption },
|
|
7114
7509
|
({ build: build3, output, verbose }) => Effect43.gen(function* () {
|
|
7115
|
-
const { config, cwd } = yield* ProjectConfig;
|
|
7510
|
+
const { config, cwd, projectDir } = yield* ProjectConfig;
|
|
7511
|
+
const extraNodeModules = projectDir !== cwd ? [path11.join(projectDir, "node_modules")] : void 0;
|
|
7116
7512
|
if (build3) {
|
|
7117
|
-
yield* buildLayer(cwd, output, verbose);
|
|
7513
|
+
yield* buildLayer(cwd, output, verbose, extraNodeModules);
|
|
7118
7514
|
} else {
|
|
7119
|
-
yield* showLayerInfo(cwd, config?.name, verbose);
|
|
7515
|
+
yield* showLayerInfo(cwd, config?.name, verbose, extraNodeModules);
|
|
7120
7516
|
}
|
|
7121
7517
|
}).pipe(Effect43.provide(ProjectConfig.Live))
|
|
7122
7518
|
).pipe(Command5.withDescription("Inspect or locally build the shared Lambda dependency layer from package.json"));
|
|
7123
|
-
var showLayerInfo = (projectDir, projectName, verbose) => Effect43.gen(function* () {
|
|
7519
|
+
var showLayerInfo = (projectDir, projectName, verbose, extraNodeModules) => Effect43.gen(function* () {
|
|
7124
7520
|
yield* Console7.log(`
|
|
7125
7521
|
${c.bold("=== Layer Packages Preview ===")}
|
|
7126
7522
|
`);
|
|
@@ -7143,7 +7539,7 @@ ${c.bold("=== Layer Packages Preview ===")}
|
|
|
7143
7539
|
for (const dep of prodDeps) {
|
|
7144
7540
|
yield* Console7.log(` ${dep}`);
|
|
7145
7541
|
}
|
|
7146
|
-
const hash = yield* computeLockfileHash(projectDir).pipe(
|
|
7542
|
+
const hash = yield* computeLockfileHash(projectDir, extraNodeModules).pipe(
|
|
7147
7543
|
Effect43.catchAll(() => Effect43.succeed(null))
|
|
7148
7544
|
);
|
|
7149
7545
|
if (hash) {
|
|
@@ -7152,7 +7548,7 @@ Lockfile hash: ${hash}`);
|
|
|
7152
7548
|
} else {
|
|
7153
7549
|
yield* Console7.log("\nNo lockfile found (package-lock.json, pnpm-lock.yaml, or yarn.lock)");
|
|
7154
7550
|
}
|
|
7155
|
-
const { packages: allPackages, warnings: layerWarnings } = yield* Effect43.sync(() => collectLayerPackages(projectDir, prodDeps));
|
|
7551
|
+
const { packages: allPackages, warnings: layerWarnings } = yield* Effect43.sync(() => collectLayerPackages(projectDir, prodDeps, extraNodeModules));
|
|
7156
7552
|
if (layerWarnings.length > 0) {
|
|
7157
7553
|
yield* Console7.log(c.yellow(`
|
|
7158
7554
|
Warnings (${layerWarnings.length}):`));
|
|
@@ -7181,7 +7577,7 @@ Total packages for layer ${c.dim(`(${allPackages.length})`)}:`);
|
|
|
7181
7577
|
Layer name: ${projectName}-deps`);
|
|
7182
7578
|
}
|
|
7183
7579
|
});
|
|
7184
|
-
var buildLayer = (projectDir, output, verbose) => Effect43.gen(function* () {
|
|
7580
|
+
var buildLayer = (projectDir, output, verbose, extraNodeModules) => Effect43.gen(function* () {
|
|
7185
7581
|
const outputDir = path11.isAbsolute(output) ? output : path11.resolve(projectDir, output);
|
|
7186
7582
|
const layerDir = path11.join(outputDir, "nodejs", "node_modules");
|
|
7187
7583
|
const layerRoot = path11.join(outputDir, "nodejs");
|
|
@@ -7211,12 +7607,12 @@ ${c.bold("=== Building Layer Locally ===")}
|
|
|
7211
7607
|
for (const dep of prodDeps) {
|
|
7212
7608
|
yield* Console7.log(` ${dep}`);
|
|
7213
7609
|
}
|
|
7214
|
-
const hash = yield* computeLockfileHash(projectDir).pipe(
|
|
7610
|
+
const hash = yield* computeLockfileHash(projectDir, extraNodeModules).pipe(
|
|
7215
7611
|
Effect43.catchAll(() => Effect43.succeed("unknown"))
|
|
7216
7612
|
);
|
|
7217
7613
|
yield* Console7.log(`
|
|
7218
7614
|
Lockfile hash: ${hash}`);
|
|
7219
|
-
const { packages: allPackages, resolvedPaths, warnings: layerWarnings } = yield* Effect43.sync(() => collectLayerPackages(projectDir, prodDeps));
|
|
7615
|
+
const { packages: allPackages, resolvedPaths, warnings: layerWarnings } = yield* Effect43.sync(() => collectLayerPackages(projectDir, prodDeps, extraNodeModules));
|
|
7220
7616
|
if (layerWarnings.length > 0) {
|
|
7221
7617
|
yield* Console7.log(`
|
|
7222
7618
|
Warnings (${layerWarnings.length}):`);
|
|
@@ -7283,7 +7679,7 @@ var loadRequiredParams = (projectOpt, stage, region) => Effect44.gen(function* (
|
|
|
7283
7679
|
const handlers = discoverHandlers(files);
|
|
7284
7680
|
const finalStage = config?.stage ?? stage;
|
|
7285
7681
|
const finalRegion = config?.region ?? region;
|
|
7286
|
-
const params =
|
|
7682
|
+
const params = collectRequiredSecrets(handlers, project, finalStage);
|
|
7287
7683
|
return { params, project, stage: finalStage, region: finalRegion };
|
|
7288
7684
|
});
|
|
7289
7685
|
var listCommand = Command6.make(
|
|
@@ -7296,7 +7692,7 @@ var listCommand = Command6.make(
|
|
|
7296
7692
|
yield* Console8.log("No config parameters declared in handlers.");
|
|
7297
7693
|
return;
|
|
7298
7694
|
}
|
|
7299
|
-
const { existing, missing } = yield*
|
|
7695
|
+
const { existing, missing } = yield* checkMissingSecrets(params).pipe(
|
|
7300
7696
|
Effect44.provide(clients_exports.makeClients({ ssm: { region: ctx.region } }))
|
|
7301
7697
|
);
|
|
7302
7698
|
yield* Console8.log(`
|
|
@@ -7367,7 +7763,7 @@ var configRootCommand = Command6.make(
|
|
|
7367
7763
|
yield* Console8.log("No config parameters declared in handlers.");
|
|
7368
7764
|
return;
|
|
7369
7765
|
}
|
|
7370
|
-
const { missing } = yield*
|
|
7766
|
+
const { missing } = yield* checkMissingSecrets(params).pipe(
|
|
7371
7767
|
Effect44.provide(clients_exports.makeClients({ ssm: { region: ctx.region } }))
|
|
7372
7768
|
);
|
|
7373
7769
|
if (missing.length === 0) {
|
|
@@ -7416,25 +7812,189 @@ ${c.bold("Missing parameters")} ${c.dim(`(${ctx.project} / ${ctx.stage})`)}
|
|
|
7416
7812
|
);
|
|
7417
7813
|
var configCommand = configRootCommand;
|
|
7418
7814
|
|
|
7815
|
+
// src/cli/commands/build.ts
|
|
7816
|
+
import { Args as Args4, Command as Command7, Options as Options5 } from "@effect/cli";
|
|
7817
|
+
import { Effect as Effect45, Console as Console9, Option as Option6 } from "effect";
|
|
7818
|
+
import * as path12 from "path";
|
|
7819
|
+
import * as fs8 from "fs";
|
|
7820
|
+
var buildFileArg = Args4.file({ name: "file", exists: "yes" }).pipe(
|
|
7821
|
+
Args4.withDescription("Handler file to build"),
|
|
7822
|
+
Args4.optional
|
|
7823
|
+
);
|
|
7824
|
+
var buildAllOption = Options5.boolean("all").pipe(
|
|
7825
|
+
Options5.withDescription("Build all exports from file")
|
|
7826
|
+
);
|
|
7827
|
+
var buildTableOption = Options5.boolean("table").pipe(
|
|
7828
|
+
Options5.withDescription("Build as table handler (defineTable)")
|
|
7829
|
+
);
|
|
7830
|
+
var buildCommand = Command7.make(
|
|
7831
|
+
"build",
|
|
7832
|
+
{ file: buildFileArg, all: buildAllOption, table: buildTableOption, output: outputOption, verbose: verboseOption },
|
|
7833
|
+
({ file, all, table, output, verbose }) => Effect45.gen(function* () {
|
|
7834
|
+
const { config, projectDir, cwd } = yield* ProjectConfig;
|
|
7835
|
+
const outputDir = path12.isAbsolute(output) ? output : path12.resolve(projectDir, output);
|
|
7836
|
+
const extraNodeModules = projectDir !== cwd ? [path12.join(projectDir, "node_modules")] : void 0;
|
|
7837
|
+
if (!fs8.existsSync(outputDir)) {
|
|
7838
|
+
fs8.mkdirSync(outputDir, { recursive: true });
|
|
7839
|
+
}
|
|
7840
|
+
const prodDeps = yield* readProductionDependencies(projectDir).pipe(
|
|
7841
|
+
Effect45.catchAll(() => Effect45.succeed([]))
|
|
7842
|
+
);
|
|
7843
|
+
const { packages: external, warnings: layerWarnings } = prodDeps.length > 0 ? yield* Effect45.sync(() => collectLayerPackages(projectDir, prodDeps, extraNodeModules)) : { packages: [], warnings: [] };
|
|
7844
|
+
for (const warning of layerWarnings) {
|
|
7845
|
+
yield* Effect45.logWarning(`[layer] ${warning}`);
|
|
7846
|
+
}
|
|
7847
|
+
if (external.length > 0) {
|
|
7848
|
+
yield* Console9.log(`Using ${external.length} external packages (from layer)
|
|
7849
|
+
`);
|
|
7850
|
+
}
|
|
7851
|
+
yield* Option6.match(file, {
|
|
7852
|
+
onNone: () => Effect45.gen(function* () {
|
|
7853
|
+
const patterns = getPatternsFromConfig(config);
|
|
7854
|
+
if (!patterns) {
|
|
7855
|
+
yield* Console9.error("Error: No file specified and no 'handlers' patterns in config");
|
|
7856
|
+
return;
|
|
7857
|
+
}
|
|
7858
|
+
const files = findHandlerFiles(patterns, projectDir);
|
|
7859
|
+
const discovered = discoverHandlers(files);
|
|
7860
|
+
let builtCount = 0;
|
|
7861
|
+
for (const { file: handlerFile, exports } of discovered.apiHandlers) {
|
|
7862
|
+
const relativePath = path12.relative(projectDir, handlerFile);
|
|
7863
|
+
const baseName = path12.basename(handlerFile, path12.extname(handlerFile));
|
|
7864
|
+
for (const { exportName } of exports) {
|
|
7865
|
+
const outputName = exportName === "default" ? baseName : `${baseName}-${exportName}`;
|
|
7866
|
+
const outputPath = path12.join(outputDir, `${outputName}.mjs`);
|
|
7867
|
+
yield* Console9.log(`Building ${c.cyan("[api]")} ${c.bold(relativePath)}:${exportName}...`);
|
|
7868
|
+
const result = yield* bundle({
|
|
7869
|
+
projectDir,
|
|
7870
|
+
file: handlerFile,
|
|
7871
|
+
exportName,
|
|
7872
|
+
type: "api",
|
|
7873
|
+
...external.length > 0 ? { external } : {}
|
|
7874
|
+
});
|
|
7875
|
+
fs8.writeFileSync(outputPath, result.code);
|
|
7876
|
+
const size = (Buffer.byteLength(result.code) / 1024).toFixed(1);
|
|
7877
|
+
yield* Console9.log(` -> ${outputPath} ${c.dim(`(${size} KB)`)}`);
|
|
7878
|
+
if (result.topModules) {
|
|
7879
|
+
for (const m of result.topModules.slice(0, 5)) {
|
|
7880
|
+
yield* Console9.log(` ${c.dim(`${(m.bytes / 1024).toFixed(1)} KB`)} ${c.dim(m.path)}`);
|
|
7881
|
+
}
|
|
7882
|
+
}
|
|
7883
|
+
builtCount++;
|
|
7884
|
+
}
|
|
7885
|
+
}
|
|
7886
|
+
for (const { file: handlerFile, exports } of discovered.tableHandlers) {
|
|
7887
|
+
const relativePath = path12.relative(projectDir, handlerFile);
|
|
7888
|
+
const baseName = path12.basename(handlerFile, path12.extname(handlerFile));
|
|
7889
|
+
for (const { exportName } of exports) {
|
|
7890
|
+
const outputName = exportName === "default" ? baseName : `${baseName}-${exportName}`;
|
|
7891
|
+
const outputPath = path12.join(outputDir, `${outputName}.mjs`);
|
|
7892
|
+
yield* Console9.log(`Building ${c.cyan("[table]")} ${c.bold(relativePath)}:${exportName}...`);
|
|
7893
|
+
const result = yield* bundle({
|
|
7894
|
+
projectDir,
|
|
7895
|
+
file: handlerFile,
|
|
7896
|
+
exportName,
|
|
7897
|
+
type: "table",
|
|
7898
|
+
...external.length > 0 ? { external } : {}
|
|
7899
|
+
});
|
|
7900
|
+
fs8.writeFileSync(outputPath, result.code);
|
|
7901
|
+
const size = (Buffer.byteLength(result.code) / 1024).toFixed(1);
|
|
7902
|
+
yield* Console9.log(` -> ${outputPath} ${c.dim(`(${size} KB)`)}`);
|
|
7903
|
+
if (result.topModules) {
|
|
7904
|
+
for (const m of result.topModules.slice(0, 5)) {
|
|
7905
|
+
yield* Console9.log(` ${c.dim(`${(m.bytes / 1024).toFixed(1)} KB`)} ${c.dim(m.path)}`);
|
|
7906
|
+
}
|
|
7907
|
+
}
|
|
7908
|
+
builtCount++;
|
|
7909
|
+
}
|
|
7910
|
+
}
|
|
7911
|
+
yield* Console9.log(c.green(`
|
|
7912
|
+
Built ${builtCount} handler(s) to ${outputDir}`));
|
|
7913
|
+
}),
|
|
7914
|
+
onSome: (filePath) => Effect45.gen(function* () {
|
|
7915
|
+
const fullPath = path12.isAbsolute(filePath) ? filePath : path12.resolve(projectDir, filePath);
|
|
7916
|
+
const source = fs8.readFileSync(fullPath, "utf-8");
|
|
7917
|
+
const baseName = path12.basename(fullPath, path12.extname(fullPath));
|
|
7918
|
+
if (table) {
|
|
7919
|
+
const configs = extractTableConfigs(source);
|
|
7920
|
+
if (configs.length === 0) {
|
|
7921
|
+
yield* Console9.error("No defineTable handlers found in file");
|
|
7922
|
+
return;
|
|
7923
|
+
}
|
|
7924
|
+
const toBundle = all ? configs : [configs[0]];
|
|
7925
|
+
for (const { exportName } of toBundle) {
|
|
7926
|
+
const outputName = exportName === "default" ? baseName : `${baseName}-${exportName}`;
|
|
7927
|
+
const outputPath = path12.join(outputDir, `${outputName}.mjs`);
|
|
7928
|
+
yield* Console9.log(`Building ${c.cyan("[table]")} ${c.bold(exportName)}...`);
|
|
7929
|
+
const result = yield* bundle({
|
|
7930
|
+
projectDir,
|
|
7931
|
+
file: fullPath,
|
|
7932
|
+
exportName,
|
|
7933
|
+
type: "table",
|
|
7934
|
+
...external.length > 0 ? { external } : {}
|
|
7935
|
+
});
|
|
7936
|
+
fs8.writeFileSync(outputPath, result.code);
|
|
7937
|
+
const size = (Buffer.byteLength(result.code) / 1024).toFixed(1);
|
|
7938
|
+
yield* Console9.log(` -> ${outputPath} ${c.dim(`(${size} KB)`)}`);
|
|
7939
|
+
if (result.topModules) {
|
|
7940
|
+
for (const m of result.topModules.slice(0, 5)) {
|
|
7941
|
+
yield* Console9.log(` ${c.dim(`${(m.bytes / 1024).toFixed(1)} KB`)} ${c.dim(m.path)}`);
|
|
7942
|
+
}
|
|
7943
|
+
}
|
|
7944
|
+
}
|
|
7945
|
+
} else {
|
|
7946
|
+
const configs = extractApiConfigs(source);
|
|
7947
|
+
if (configs.length === 0) {
|
|
7948
|
+
yield* Console9.error("No defineApi handlers found in file");
|
|
7949
|
+
return;
|
|
7950
|
+
}
|
|
7951
|
+
const toBundle = all ? configs : [configs[0]];
|
|
7952
|
+
for (const { exportName } of toBundle) {
|
|
7953
|
+
const outputName = exportName === "default" ? baseName : `${baseName}-${exportName}`;
|
|
7954
|
+
const outputPath = path12.join(outputDir, `${outputName}.mjs`);
|
|
7955
|
+
yield* Console9.log(`Building ${c.cyan("[api]")} ${c.bold(exportName)}...`);
|
|
7956
|
+
const result = yield* bundle({
|
|
7957
|
+
projectDir,
|
|
7958
|
+
file: fullPath,
|
|
7959
|
+
exportName,
|
|
7960
|
+
...external.length > 0 ? { external } : {}
|
|
7961
|
+
});
|
|
7962
|
+
fs8.writeFileSync(outputPath, result.code);
|
|
7963
|
+
const size = (Buffer.byteLength(result.code) / 1024).toFixed(1);
|
|
7964
|
+
yield* Console9.log(` -> ${outputPath} ${c.dim(`(${size} KB)`)}`);
|
|
7965
|
+
if (result.topModules) {
|
|
7966
|
+
for (const m of result.topModules.slice(0, 5)) {
|
|
7967
|
+
yield* Console9.log(` ${c.dim(`${(m.bytes / 1024).toFixed(1)} KB`)} ${c.dim(m.path)}`);
|
|
7968
|
+
}
|
|
7969
|
+
}
|
|
7970
|
+
}
|
|
7971
|
+
}
|
|
7972
|
+
yield* Console9.log(`
|
|
7973
|
+
Output directory: ${outputDir}`);
|
|
7974
|
+
})
|
|
7975
|
+
});
|
|
7976
|
+
}).pipe(Effect45.provide(ProjectConfig.Live))
|
|
7977
|
+
).pipe(Command7.withDescription("Build handler bundles locally (for debugging)"));
|
|
7978
|
+
|
|
7419
7979
|
// src/cli/update-check.ts
|
|
7420
7980
|
import { homedir as homedir2 } from "os";
|
|
7421
|
-
import { join as
|
|
7422
|
-
import { readFileSync as
|
|
7981
|
+
import { join as join11 } from "path";
|
|
7982
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "fs";
|
|
7423
7983
|
var PACKAGE_NAME = "@effortless-aws/cli";
|
|
7424
7984
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
7425
|
-
var CACHE_DIR =
|
|
7426
|
-
var CACHE_FILE =
|
|
7985
|
+
var CACHE_DIR = join11(homedir2(), ".effortless-aws");
|
|
7986
|
+
var CACHE_FILE = join11(CACHE_DIR, "update-check.json");
|
|
7427
7987
|
function readCache() {
|
|
7428
7988
|
try {
|
|
7429
|
-
return JSON.parse(
|
|
7989
|
+
return JSON.parse(readFileSync6(CACHE_FILE, "utf-8"));
|
|
7430
7990
|
} catch {
|
|
7431
7991
|
return void 0;
|
|
7432
7992
|
}
|
|
7433
7993
|
}
|
|
7434
7994
|
function writeCache(data) {
|
|
7435
7995
|
try {
|
|
7436
|
-
|
|
7437
|
-
|
|
7996
|
+
mkdirSync3(CACHE_DIR, { recursive: true });
|
|
7997
|
+
writeFileSync3(CACHE_FILE, JSON.stringify(data));
|
|
7438
7998
|
} catch {
|
|
7439
7999
|
}
|
|
7440
8000
|
}
|
|
@@ -7496,18 +8056,18 @@ async function checkForUpdate(currentVersion) {
|
|
|
7496
8056
|
// src/cli/index.ts
|
|
7497
8057
|
var require2 = createRequire2(import.meta.url);
|
|
7498
8058
|
var { version } = require2("../../package.json");
|
|
7499
|
-
var mainCommand =
|
|
7500
|
-
|
|
7501
|
-
|
|
8059
|
+
var mainCommand = Command8.make("eff").pipe(
|
|
8060
|
+
Command8.withSubcommands([deployCommand, statusCommand, logsCommand, cleanupCommand, layerCommand, configCommand, buildCommand]),
|
|
8061
|
+
Command8.withDescription("Code-first AWS Lambda framework")
|
|
7502
8062
|
);
|
|
7503
|
-
var cli =
|
|
8063
|
+
var cli = Command8.run(mainCommand, {
|
|
7504
8064
|
name: "effortless",
|
|
7505
8065
|
version
|
|
7506
8066
|
});
|
|
7507
8067
|
var updateCheck = checkForUpdate(version);
|
|
7508
8068
|
cli(process.argv).pipe(
|
|
7509
|
-
|
|
7510
|
-
|
|
7511
|
-
|
|
8069
|
+
Effect46.provide(NodeContext.layer),
|
|
8070
|
+
Effect46.provide(CliConfig.layer({ showBuiltIns: false, showTypes: false })),
|
|
8071
|
+
Effect46.tap(() => Effect46.promise(() => updateCheck)),
|
|
7512
8072
|
NodeRuntime.runMain
|
|
7513
8073
|
);
|