@effortless-aws/cli 0.7.0 → 0.8.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.
Files changed (2) hide show
  1. package/dist/cli/index.js +161 -8
  2. package/package.json +2 -2
package/dist/cli/index.js CHANGED
@@ -4238,6 +4238,56 @@ var extractHandlerConfigs = (source, type) => {
4238
4238
  });
4239
4239
  return results;
4240
4240
  };
4241
+ var generateMiddlewareEntryPoint = (source, runtimeDir2) => {
4242
+ const sourceFile = parseSource(source);
4243
+ const imports = sourceFile.getImportDeclarations().map((d) => d.getText()).join("\n");
4244
+ const defineFn = handlerRegistry.staticSite.defineFn;
4245
+ let middlewareFnText;
4246
+ let exportName;
4247
+ const exportDefault = sourceFile.getExportAssignment((e) => !e.isExportEquals());
4248
+ if (exportDefault) {
4249
+ const expr = exportDefault.getExpression();
4250
+ if (expr.getKind() === SyntaxKind.CallExpression) {
4251
+ const callExpr = expr.asKindOrThrow(SyntaxKind.CallExpression);
4252
+ if (callExpr.getExpression().getText() === defineFn) {
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
+ }
4260
+ }
4261
+ }
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
+ if (!middlewareFnText || !exportName) {
4281
+ throw new Error("Could not extract middleware function from source");
4282
+ }
4283
+ const wrapperPath = runtimeDir2 ? handlerRegistry.staticSite.wrapperPath.replace("~/runtime", runtimeDir2) : handlerRegistry.staticSite.wrapperPath;
4284
+ const entryPoint = `${imports}
4285
+ import { wrapMiddlewareFn } from "${wrapperPath}";
4286
+ const __middleware = ${middlewareFnText};
4287
+ export const handler = wrapMiddlewareFn(__middleware);
4288
+ `;
4289
+ return { entryPoint, exportName };
4290
+ };
4241
4291
  var generateEntryPoint = (sourcePath, exportName, type, runtimeDir2) => {
4242
4292
  const { wrapperFn, wrapperPath } = handlerRegistry[type];
4243
4293
  const resolvedWrapperPath = runtimeDir2 ? wrapperPath.replace("~/runtime", runtimeDir2) : wrapperPath;
@@ -4291,6 +4341,36 @@ var bundle = (input) => Effect24.gen(function* () {
4291
4341
  }
4292
4342
  return output.text;
4293
4343
  });
4344
+ var bundleMiddleware = (input) => Effect24.gen(function* () {
4345
+ const absFile = path3.isAbsolute(input.file) ? input.file : path3.resolve(input.projectDir, input.file);
4346
+ const source = fsSync2.readFileSync(absFile, "utf-8");
4347
+ const sourceDir = path3.dirname(absFile);
4348
+ const { entryPoint } = generateMiddlewareEntryPoint(source, runtimeDir);
4349
+ const awsExternals = ["@aws-sdk/*", "@smithy/*"];
4350
+ const result = yield* Effect24.tryPromise({
4351
+ try: () => esbuild.build({
4352
+ stdin: {
4353
+ contents: entryPoint,
4354
+ loader: "ts",
4355
+ resolveDir: sourceDir
4356
+ },
4357
+ bundle: true,
4358
+ platform: "node",
4359
+ target: "node22",
4360
+ write: false,
4361
+ minify: false,
4362
+ sourcemap: false,
4363
+ format: "esm",
4364
+ external: awsExternals
4365
+ }),
4366
+ catch: (error) => new Error(`esbuild failed (middleware): ${error}`)
4367
+ });
4368
+ const output = result.outputFiles?.[0];
4369
+ if (!output) {
4370
+ throw new Error("esbuild produced no output for middleware");
4371
+ }
4372
+ return output.text;
4373
+ });
4294
4374
  var FIXED_DATE2 = /* @__PURE__ */ new Date(0);
4295
4375
  var zip = (input) => Effect24.async((resume) => {
4296
4376
  const chunks = [];
@@ -5048,7 +5128,7 @@ var submitToGoogleIndexing = (input) => Effect30.gen(function* () {
5048
5128
 
5049
5129
  // src/deploy/deploy-static-site.ts
5050
5130
  var deployMiddlewareLambda = (input) => Effect31.gen(function* () {
5051
- const { projectDir, project, stage, handlerName, file, exportName, tagCtx } = input;
5131
+ const { projectDir, project, stage, handlerName, file, tagCtx } = input;
5052
5132
  const middlewareName = `${handlerName}-middleware`;
5053
5133
  yield* Effect31.logDebug(`Deploying middleware Lambda@Edge: ${middlewareName}`);
5054
5134
  const roleArn = yield* ensureEdgeRole(
@@ -5057,12 +5137,7 @@ var deployMiddlewareLambda = (input) => Effect31.gen(function* () {
5057
5137
  middlewareName,
5058
5138
  makeTags(tagCtx, "iam-role")
5059
5139
  );
5060
- const bundled = yield* bundle({
5061
- projectDir,
5062
- file,
5063
- exportName,
5064
- type: "staticSite"
5065
- });
5140
+ const bundled = yield* bundleMiddleware({ projectDir, file });
5066
5141
  const code = yield* zip({ content: bundled });
5067
5142
  const { functionArn } = yield* ensureLambda({
5068
5143
  project,
@@ -5197,7 +5272,6 @@ var deployStaticSite = (input) => Effect31.gen(function* () {
5197
5272
  stage,
5198
5273
  handlerName,
5199
5274
  file: input.file,
5200
- exportName,
5201
5275
  tagCtx
5202
5276
  }).pipe(
5203
5277
  Effect31.provide(clients_exports.makeClients({ iam: { region: "us-east-1" } }))
@@ -7342,6 +7416,83 @@ ${c.bold("Missing parameters")} ${c.dim(`(${ctx.project} / ${ctx.stage})`)}
7342
7416
  );
7343
7417
  var configCommand = configRootCommand;
7344
7418
 
7419
+ // src/cli/update-check.ts
7420
+ import { homedir as homedir2 } from "os";
7421
+ import { join as join9 } from "path";
7422
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
7423
+ var PACKAGE_NAME = "@effortless-aws/cli";
7424
+ var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
7425
+ var CACHE_DIR = join9(homedir2(), ".effortless-aws");
7426
+ var CACHE_FILE = join9(CACHE_DIR, "update-check.json");
7427
+ function readCache() {
7428
+ try {
7429
+ return JSON.parse(readFileSync5(CACHE_FILE, "utf-8"));
7430
+ } catch {
7431
+ return void 0;
7432
+ }
7433
+ }
7434
+ function writeCache(data) {
7435
+ try {
7436
+ mkdirSync2(CACHE_DIR, { recursive: true });
7437
+ writeFileSync2(CACHE_FILE, JSON.stringify(data));
7438
+ } catch {
7439
+ }
7440
+ }
7441
+ async function fetchLatestVersion() {
7442
+ try {
7443
+ const controller = new AbortController();
7444
+ const timeout = setTimeout(() => controller.abort(), 3e3);
7445
+ const res = await fetch(
7446
+ `https://registry.npmjs.org/${PACKAGE_NAME}/latest`,
7447
+ { signal: controller.signal }
7448
+ );
7449
+ clearTimeout(timeout);
7450
+ if (!res.ok) return void 0;
7451
+ const data = await res.json();
7452
+ return data.version;
7453
+ } catch {
7454
+ return void 0;
7455
+ }
7456
+ }
7457
+ function compareVersions(current, latest) {
7458
+ const parse = (v) => v.split(".").map(Number);
7459
+ const [cMajor, cMinor, cPatch] = parse(current);
7460
+ const [lMajor, lMinor, lPatch] = parse(latest);
7461
+ if (lMajor !== cMajor) return lMajor > cMajor;
7462
+ if (lMinor !== cMinor) return lMinor > cMinor;
7463
+ return lPatch > cPatch;
7464
+ }
7465
+ async function checkForUpdate(currentVersion) {
7466
+ const cache = readCache();
7467
+ const now = Date.now();
7468
+ let latestVersion;
7469
+ if (cache && now - cache.lastCheck < CHECK_INTERVAL_MS) {
7470
+ latestVersion = cache.latestVersion;
7471
+ } else {
7472
+ latestVersion = await fetchLatestVersion();
7473
+ if (latestVersion) {
7474
+ writeCache({ lastCheck: now, latestVersion });
7475
+ }
7476
+ }
7477
+ if (latestVersion && compareVersions(currentVersion, latestVersion)) {
7478
+ const border = "\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510";
7479
+ const bottom = "\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518";
7480
+ const pad = (line, width) => {
7481
+ const visible = line.replace(/\x1b\[[0-9;]*m/g, "");
7482
+ return line + " ".repeat(Math.max(0, width - visible.length));
7483
+ };
7484
+ const W = 39;
7485
+ const line1 = `Update available! ${c.dim(currentVersion)} ${c.dim("\u2192")} ${c.green(latestVersion)}`;
7486
+ const line2 = `Run ${c.cyan(`pnpm i -g ${PACKAGE_NAME}`)} to update`;
7487
+ console.log();
7488
+ console.log(` ${border}`);
7489
+ console.log(` \u2502 ${pad(line1, W)} \u2502`);
7490
+ console.log(` \u2502 ${pad(line2, W)} \u2502`);
7491
+ console.log(` ${bottom}`);
7492
+ console.log();
7493
+ }
7494
+ }
7495
+
7345
7496
  // src/cli/index.ts
7346
7497
  var require2 = createRequire2(import.meta.url);
7347
7498
  var { version } = require2("../../package.json");
@@ -7353,8 +7504,10 @@ var cli = Command7.run(mainCommand, {
7353
7504
  name: "effortless",
7354
7505
  version
7355
7506
  });
7507
+ var updateCheck = checkForUpdate(version);
7356
7508
  cli(process.argv).pipe(
7357
7509
  Effect45.provide(NodeContext.layer),
7358
7510
  Effect45.provide(CliConfig.layer({ showBuiltIns: false, showTypes: false })),
7511
+ Effect45.tap(() => Effect45.promise(() => updateCheck)),
7359
7512
  NodeRuntime.runMain
7360
7513
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effortless-aws/cli",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "description": "CLI and deploy tooling for effortless-aws",
@@ -39,7 +39,7 @@
39
39
  "esbuild": "^0.25.0",
40
40
  "glob": "^13.0.0",
41
41
  "ts-morph": "^27.0.2",
42
- "effortless-aws": "0.23.0"
42
+ "effortless-aws": "0.23.1"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@effect-ak/aws-sdk": "1.0.0-rc.3",