@go-to-k/cdkd 0.162.1 → 0.162.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -51328,6 +51328,56 @@ function matchPreflight(req, config) {
51328
51328
  };
51329
51329
  }
51330
51330
  /**
51331
+ * Apply CORS headers to an **actual** (non-preflight) response. CORS
51332
+ * spec requires that 2xx / 4xx / 5xx responses all carry
51333
+ * `Access-Control-Allow-Origin` (only preflight responses also need
51334
+ * `Allow-Methods` / `Allow-Headers` / `Max-Age`) — without it the
51335
+ * browser blocks the response body from JS regardless of status code.
51336
+ *
51337
+ * Looks up the route's `apiLogicalId` in `corsConfigByApiId`. When a
51338
+ * matching config + the request Origin satisfies `AllowOrigins`, sets:
51339
+ *
51340
+ * - `Access-Control-Allow-Origin: <origin or *>` (always)
51341
+ * - `Vary: Origin` (when origin echoed)
51342
+ * - `Access-Control-Allow-Credentials: true` (when configured)
51343
+ * - `Access-Control-Expose-Headers: <list>` (when configured)
51344
+ *
51345
+ * `Allow-Methods` / `Allow-Headers` / `Max-Age` are preflight-only and
51346
+ * deliberately NOT set on actual responses.
51347
+ *
51348
+ * Caller must invoke this BEFORE writing the response body (otherwise
51349
+ * `res.headersSent` flips and `setHeader` becomes a no-op). Idempotent:
51350
+ * a second call with the same args overwrites the same headers.
51351
+ *
51352
+ * No-op when:
51353
+ * - `route.apiLogicalId` is undefined (no surface-config-bearing
51354
+ * resource — e.g. routes discovered before issue #644's apiLogicalId
51355
+ * plumbing existed; harmless on routes without CORS to apply)
51356
+ * - The route's API has no entry in `corsConfigByApiId`
51357
+ * - The request has no `Origin` header (non-CORS request — same
51358
+ * posture as the matchPreflight gate)
51359
+ * - The Origin is not in the AllowOrigins list (browser will block
51360
+ * anyway; we don't smuggle through unauthorized origins by accident)
51361
+ */
51362
+ function applyCorsResponseHeaders(res, apiLogicalId, corsConfigByApiId, requestOrigin) {
51363
+ if (!apiLogicalId) return;
51364
+ const cors = corsConfigByApiId.get(apiLogicalId);
51365
+ if (!cors) return;
51366
+ if (!requestOrigin) return;
51367
+ const originMatch = matchOrigin(requestOrigin, cors.AllowOrigins);
51368
+ if (!originMatch) return;
51369
+ const allowOrigin = originMatch === "*" && cors.AllowCredentials !== true ? "*" : requestOrigin;
51370
+ res.setHeader("Access-Control-Allow-Origin", allowOrigin);
51371
+ if (allowOrigin !== "*") {
51372
+ const existing = res.getHeader("Vary");
51373
+ if (typeof existing === "string" && existing.length > 0) {
51374
+ if (!existing.split(",").map((t) => t.trim()).some((t) => t.toLowerCase() === "origin")) res.setHeader("Vary", `${existing}, Origin`);
51375
+ } else res.setHeader("Vary", "Origin");
51376
+ }
51377
+ if (cors.AllowCredentials === true) res.setHeader("Access-Control-Allow-Credentials", "true");
51378
+ if (cors.ExposeHeaders.length > 0) res.setHeader("Access-Control-Expose-Headers", cors.ExposeHeaders.join(","));
51379
+ }
51380
+ /**
51331
51381
  * Whether the request's Origin matches the AllowOrigins list. Returns
51332
51382
  * `'*'` when a wildcard matched, the literal entry on a literal match,
51333
51383
  * `null` otherwise. The literal case is used by the caller to decide
@@ -53237,11 +53287,16 @@ async function handleRequest(req, res, state, opts) {
53237
53287
  writeError(res, 404, "{\"message\":\"Not Found\"}");
53238
53288
  return;
53239
53289
  }
53290
+ const requestOrigin = pickFirstHeaderValue(collectHeaders(req), "origin") ?? void 0;
53291
+ const applyCors = () => {
53292
+ applyCorsResponseHeaders(res, match.route.apiLogicalId, state.corsConfigByApiId, requestOrigin);
53293
+ };
53240
53294
  if (match.route.mockCors) {
53241
53295
  writeMockCorsPreflight(res, match.route.mockCors);
53242
53296
  return;
53243
53297
  }
53244
53298
  if (match.route.unsupported) {
53299
+ applyCors();
53245
53300
  writeNotImplemented(res, match.route.unsupported.reason);
53246
53301
  return;
53247
53302
  }
@@ -53268,10 +53323,12 @@ async function handleRequest(req, res, state, opts) {
53268
53323
  outcome = await runAuthorizerPass(authorizer, snapshot, matchCtx, state, opts, baseEvent["requestContext"]);
53269
53324
  } catch (err) {
53270
53325
  logger.error(`Authorizer ${authorizer.logicalId} threw for ${match.route.declaredAt}: ${err instanceof Error ? err.message : String(err)}`);
53326
+ applyCors();
53271
53327
  writeAuthRejection(res, match.route.apiVersion, "policy-deny", authorizer.kind);
53272
53328
  return;
53273
53329
  }
53274
53330
  if (!outcome.result.allow) {
53331
+ applyCors();
53275
53332
  writeAuthRejection(res, match.route.apiVersion, outcome.denyKind ?? "policy-deny", authorizer.kind);
53276
53333
  return;
53277
53334
  }
@@ -53280,16 +53337,21 @@ async function handleRequest(req, res, state, opts) {
53280
53337
  if (overlay) baseEvent = applyAuthorizerOverlay(baseEvent, overlay);
53281
53338
  }
53282
53339
  if (match.route.serviceIntegration) {
53340
+ applyCors();
53283
53341
  await handleServiceIntegrationRequest(req, res, match, bodyBuf, opts, authorizer, authResult);
53284
53342
  return;
53285
53343
  }
53286
53344
  if (match.route.restV1Integration) {
53287
53345
  try {
53288
- writeIntegrationOutcome(res, await dispatchRestV1Integration(match.route.restV1Integration, snapshot, matchCtx, state, opts));
53346
+ const outcome = await dispatchRestV1Integration(match.route.restV1Integration, snapshot, matchCtx, state, opts);
53347
+ applyCors();
53348
+ writeIntegrationOutcome(res, outcome);
53289
53349
  } catch (err) {
53290
53350
  logger.error(`REST v1 ${match.route.restV1Integration.kind} dispatch failed for ${match.route.declaredAt}: ${err instanceof Error ? err.message : String(err)}`);
53291
- if (!res.headersSent) writeError(res, 502);
53292
- else res.end();
53351
+ if (!res.headersSent) {
53352
+ applyCors();
53353
+ writeError(res, 502);
53354
+ } else res.end();
53293
53355
  }
53294
53356
  return;
53295
53357
  }
@@ -53298,6 +53360,7 @@ async function handleRequest(req, res, state, opts) {
53298
53360
  handle = await state.pool.acquire(match.route.lambdaLogicalId);
53299
53361
  } catch (err) {
53300
53362
  logger.error(`Failed to acquire container for ${match.route.lambdaLogicalId}: ${err instanceof Error ? err.message : String(err)}`);
53363
+ applyCors();
53301
53364
  writeError(res, 502);
53302
53365
  return;
53303
53366
  }
@@ -53306,6 +53369,7 @@ async function handleRequest(req, res, state, opts) {
53306
53369
  try {
53307
53370
  streamResult = await invokeRieStreaming(handle.containerHost, handle.hostPort, baseEvent, opts.rieTimeoutMs);
53308
53371
  try {
53372
+ applyCors();
53309
53373
  writeStreamingResponse(res, streamResult, () => state.pool.release(handle));
53310
53374
  } catch (writeErr) {
53311
53375
  streamResult.body.on("error", () => {});
@@ -53315,8 +53379,10 @@ async function handleRequest(req, res, state, opts) {
53315
53379
  return;
53316
53380
  } catch (err) {
53317
53381
  logger.error(`RIE streaming invoke failed for ${match.route.lambdaLogicalId}: ${err instanceof Error ? err.message : String(err)}`);
53318
- if (!res.headersSent) writeError(res, 502);
53319
- else res.end();
53382
+ if (!res.headersSent) {
53383
+ applyCors();
53384
+ writeError(res, 502);
53385
+ } else res.end();
53320
53386
  state.pool.release(handle);
53321
53387
  return;
53322
53388
  }
@@ -53326,11 +53392,14 @@ async function handleRequest(req, res, state, opts) {
53326
53392
  res.statusCode = translated.statusCode;
53327
53393
  for (const [name, value] of Object.entries(translated.headers)) res.setHeader(name, value);
53328
53394
  if (translated.cookies.length > 0) res.setHeader("set-cookie", translated.cookies);
53395
+ applyCors();
53329
53396
  res.end(translated.body);
53330
53397
  } catch (err) {
53331
53398
  logger.error(`RIE invoke failed for ${match.route.lambdaLogicalId}: ${err instanceof Error ? err.message : String(err)}`);
53332
- if (!res.headersSent) writeError(res, 502);
53333
- else res.end();
53399
+ if (!res.headersSent) {
53400
+ applyCors();
53401
+ writeError(res, 502);
53402
+ } else res.end();
53334
53403
  } finally {
53335
53404
  state.pool.release(handle);
53336
53405
  }
@@ -60201,7 +60270,7 @@ function reorderArgs(argv) {
60201
60270
  */
60202
60271
  async function main() {
60203
60272
  const program = new Command();
60204
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.162.1");
60273
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.162.2");
60205
60274
  program.addCommand(createBootstrapCommand());
60206
60275
  program.addCommand(createSynthCommand());
60207
60276
  program.addCommand(createListCommand());