@discover-cloud/shared 1.3.0 → 1.4.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 (81) hide show
  1. package/dist/authorization/index.d.ts +2 -2
  2. package/dist/authorization/permission-cache.service.js +27 -11
  3. package/dist/context/index.d.ts +1 -0
  4. package/dist/context/index.js +17 -0
  5. package/dist/context/request-context.storage.d.ts +21 -0
  6. package/dist/context/request-context.storage.js +37 -0
  7. package/dist/contracts/auth-service/account.dto.d.ts +1 -1
  8. package/dist/contracts/index.d.ts +1 -0
  9. package/dist/contracts/index.js +17 -0
  10. package/dist/contracts/visibility.d.ts +63 -0
  11. package/dist/contracts/visibility.js +10 -0
  12. package/dist/dtos/audit-service.types.d.ts +42 -0
  13. package/dist/dtos/audit-service.types.js +31 -0
  14. package/dist/dtos/auth-service.dto.d.ts +16 -1
  15. package/dist/dtos/cloud-service.dto.d.ts +9 -3
  16. package/dist/dtos/index.d.ts +6 -5
  17. package/dist/dtos/index.js +1 -0
  18. package/dist/dtos/insights-service.dto.d.ts +174 -13
  19. package/dist/dtos/response.dto.d.ts +6 -0
  20. package/dist/dtos/user-service.dto.d.ts +52 -7
  21. package/dist/enums/domain.enums.d.ts +52 -26
  22. package/dist/enums/domain.enums.js +64 -40
  23. package/dist/enums/index.d.ts +2 -2
  24. package/dist/errors/app-error.js +1 -1
  25. package/dist/errors/http-errors.d.ts +1 -1
  26. package/dist/errors/http-errors.js +26 -26
  27. package/dist/errors/index.d.ts +2 -2
  28. package/dist/http/index.d.ts +2 -2
  29. package/dist/http/request-context.d.ts +2 -2
  30. package/dist/http/request-context.js +5 -5
  31. package/dist/http/service-client.d.ts +2 -2
  32. package/dist/http/service-client.js +2 -2
  33. package/dist/index.d.ts +11 -10
  34. package/dist/index.js +1 -0
  35. package/dist/jwt/index.d.ts +3 -3
  36. package/dist/jwt/machine-jwt-verifier.d.ts +1 -1
  37. package/dist/jwt/machine-jwt-verifier.js +13 -14
  38. package/dist/jwt/machine-token-client.d.ts +1 -1
  39. package/dist/jwt/machine-token-client.js +8 -8
  40. package/dist/jwt/user-jwt-verifier.d.ts +1 -1
  41. package/dist/jwt/user-jwt-verifier.js +17 -16
  42. package/dist/messaging/audit.publisher.d.ts +14 -0
  43. package/dist/messaging/audit.publisher.js +49 -0
  44. package/dist/messaging/index.d.ts +1 -0
  45. package/dist/messaging/index.js +1 -0
  46. package/dist/messaging/rabbitmq.client.d.ts +5 -3
  47. package/dist/messaging/rabbitmq.client.js +17 -11
  48. package/dist/middleware/error-handler.middleware.d.ts +2 -2
  49. package/dist/middleware/error-handler.middleware.js +10 -10
  50. package/dist/middleware/index.d.ts +10 -10
  51. package/dist/middleware/request-context.middleware.d.ts +1 -12
  52. package/dist/middleware/request-context.middleware.js +17 -42
  53. package/dist/middleware/require-auth.middleware.d.ts +3 -19
  54. package/dist/middleware/require-auth.middleware.js +17 -26
  55. package/dist/middleware/require-machine.middleware.d.ts +2 -27
  56. package/dist/middleware/require-machine.middleware.js +30 -25
  57. package/dist/middleware/require-org-permission-from-body.middleware.js +1 -2
  58. package/dist/middleware/require-org-permission.middleware.d.ts +3 -3
  59. package/dist/middleware/require-org-permission.middleware.js +28 -28
  60. package/dist/middleware/require-platform-permission.middleware.d.ts +3 -3
  61. package/dist/middleware/require-platform-permission.middleware.js +10 -10
  62. package/dist/middleware/require-user.middleware.d.ts +1 -1
  63. package/dist/middleware/require-user.middleware.js +2 -2
  64. package/dist/middleware/require-workspace-permission.middleware.d.ts +3 -3
  65. package/dist/middleware/require-workspace-permission.middleware.js +25 -25
  66. package/dist/middleware/validate.middleware.d.ts +3 -3
  67. package/dist/middleware/validate.middleware.js +1 -1
  68. package/dist/types/audit.types.d.ts +39 -0
  69. package/dist/types/audit.types.js +30 -0
  70. package/dist/types/express.types.d.ts +14 -7
  71. package/dist/types/express.types.js +10 -10
  72. package/dist/types/index.d.ts +1 -1
  73. package/dist/utils/env.util.js +1 -1
  74. package/dist/utils/index.d.ts +5 -5
  75. package/dist/utils/logger.util.d.ts +5 -0
  76. package/dist/utils/logger.util.js +46 -8
  77. package/dist/utils/request-context.als.d.ts +10 -0
  78. package/dist/utils/request-context.als.js +5 -0
  79. package/dist/utils/response.util.d.ts +1 -1
  80. package/dist/utils/url-safety.util.js +4 -1
  81. package/package.json +1 -1
@@ -35,12 +35,14 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.RabbitMQClient = void 0;
37
37
  const amqplib = __importStar(require("amqplib"));
38
+ const logger_util_1 = require("../utils/logger.util");
38
39
  class RabbitMQClient {
39
- constructor(url) {
40
+ constructor(url, logger = logger_util_1.consoleLogger) {
40
41
  this.connection = null;
41
42
  this.channel = null;
42
43
  this.exchangeName = 'discovercloud.topic';
43
44
  this.url = url;
45
+ this.logger = logger;
44
46
  }
45
47
  async connect() {
46
48
  if (this.connection && this.channel) {
@@ -49,21 +51,23 @@ class RabbitMQClient {
49
51
  try {
50
52
  this.connection = await amqplib.connect(this.url);
51
53
  this.connection.on('error', (err) => {
52
- console.error('RabbitMQ Connection Error:', err);
54
+ this.logger.error(err, 'RabbitMQ Connection Error');
53
55
  });
54
56
  this.connection.on('close', () => {
55
- console.warn('RabbitMQ Connection Closed. Reconnecting...');
57
+ this.logger.warn('RabbitMQ Connection Closed. Reconnecting...');
56
58
  this.connection = null;
57
59
  this.channel = null;
58
60
  setTimeout(() => this.connect(), 5000);
59
61
  });
60
62
  this.channel = await this.connection.createChannel();
61
63
  // Ensure the main topic exchange exists
62
- await this.channel.assertExchange(this.exchangeName, 'topic', { durable: true });
63
- console.log('✅ Connected to RabbitMQ');
64
+ await this.channel.assertExchange(this.exchangeName, 'topic', {
65
+ durable: true,
66
+ });
67
+ this.logger.info('✅ Connected to RabbitMQ');
64
68
  }
65
69
  catch (error) {
66
- console.error('❌ Failed to connect to RabbitMQ:', error);
70
+ this.logger.error(error, '❌ Failed to connect to RabbitMQ');
67
71
  setTimeout(() => this.connect(), 5000);
68
72
  }
69
73
  }
@@ -104,15 +108,17 @@ class RabbitMQClient {
104
108
  try {
105
109
  const payload = JSON.parse(msg.content.toString());
106
110
  await handler(payload);
107
- this.channel.ack(msg);
111
+ // Fix: Use optional chaining instead of non-null assertion (!)
112
+ this.channel?.ack(msg);
108
113
  }
109
114
  catch (error) {
110
- console.error(`Error processing message from ${queueName}:`, error);
115
+ this.logger.error(error, `Error processing message from ${queueName}`);
116
+ // Fix: Use optional chaining instead of non-null assertion (!)
111
117
  // Nack the message and don't requeue, so it goes to the DLX
112
- this.channel.nack(msg, false, false);
118
+ this.channel?.nack(msg, false, false);
113
119
  }
114
120
  });
115
- console.log(`📡 Subscribed to queue [${queueName}] with routing key [${routingKey}]`);
121
+ this.logger.info(`📡 Subscribed to queue [${queueName}] with routing key [${routingKey}]`);
116
122
  }
117
123
  async close() {
118
124
  if (this.channel) {
@@ -121,7 +127,7 @@ class RabbitMQClient {
121
127
  if (this.connection) {
122
128
  await this.connection.close();
123
129
  }
124
- console.log('RabbitMQ connection closed.');
130
+ this.logger.info('RabbitMQ connection closed.');
125
131
  }
126
132
  }
127
133
  exports.RabbitMQClient = RabbitMQClient;
@@ -2,8 +2,8 @@
2
2
  * @file error-handler.middleware.ts
3
3
  * @description Central Express error handler. Register as the final middleware.
4
4
  */
5
- import { ErrorRequestHandler } from "express";
6
- import { ILogger } from "../utils";
5
+ import { ErrorRequestHandler } from 'express';
6
+ import { ILogger } from '../utils';
7
7
  /**
8
8
  * Creates global Express error middleware.
9
9
  */
@@ -13,9 +13,9 @@ const utils_1 = require("../utils");
13
13
  */
14
14
  function isMalformedJsonError(err) {
15
15
  return (err instanceof SyntaxError &&
16
- "status" in err &&
17
- typeof err.status === "number" &&
18
- "body" in err);
16
+ 'status' in err &&
17
+ typeof err.status === 'number' &&
18
+ 'body' in err);
19
19
  }
20
20
  /**
21
21
  * Converts any thrown value into Error.
@@ -24,7 +24,7 @@ function normalizeError(err) {
24
24
  if (err instanceof Error) {
25
25
  return err;
26
26
  }
27
- if (typeof err === "string") {
27
+ if (typeof err === 'string') {
28
28
  return new Error(err);
29
29
  }
30
30
  return new Error(JSON.stringify(err));
@@ -40,16 +40,16 @@ function createGlobalErrorHandler(logger = utils_1.noopLogger) {
40
40
  * Malformed JSON
41
41
  */
42
42
  if (isMalformedJsonError(err) && err.status === 400) {
43
- logger.warn({ requestId, err: error }, "Malformed JSON payload");
44
- (0, utils_1.failure)(res, req, "Invalid JSON payload", "BAD_REQUEST", 400);
43
+ logger.warn({ requestId, err: error }, 'Malformed JSON payload');
44
+ (0, utils_1.failure)(res, req, 'Invalid JSON payload', 'BAD_REQUEST', 400);
45
45
  return;
46
46
  }
47
47
  /**
48
48
  * Validation failures
49
49
  */
50
50
  if (err instanceof zod_1.ZodError) {
51
- logger.warn({ requestId, err: error }, "Request validation failed");
52
- (0, utils_1.failure)(res, req, "Validation failed", "VALIDATION_ERROR", 400, err.flatten());
51
+ logger.warn({ requestId, err: error }, 'Request validation failed');
52
+ (0, utils_1.failure)(res, req, 'Validation failed', 'VALIDATION_ERROR', 400, err.flatten());
53
53
  return;
54
54
  }
55
55
  /**
@@ -73,7 +73,7 @@ function createGlobalErrorHandler(logger = utils_1.noopLogger) {
73
73
  /**
74
74
  * Unknown crashes
75
75
  */
76
- logger.error({ requestId, err: error }, "Unhandled exception");
77
- (0, utils_1.failure)(res, req, "Internal Server Error", "INTERNAL_SERVER_ERROR", 500);
76
+ logger.error({ requestId, err: error }, 'Unhandled exception');
77
+ (0, utils_1.failure)(res, req, 'Internal Server Error', 'INTERNAL_SERVER_ERROR', 500);
78
78
  };
79
79
  }
@@ -1,10 +1,10 @@
1
- export * from "./error-handler.middleware";
2
- export * from "./validate.middleware";
3
- export * from "./request-context.middleware";
4
- export * from "./require-machine.middleware";
5
- export * from "./require-auth.middleware";
6
- export * from "./require-user.middleware";
7
- export * from "./require-org-permission.middleware";
8
- export * from "./require-workspace-permission.middleware";
9
- export * from "./require-platform-permission.middleware";
10
- export * from "./require-org-permission-from-body.middleware";
1
+ export * from './error-handler.middleware';
2
+ export * from './validate.middleware';
3
+ export * from './request-context.middleware';
4
+ export * from './require-machine.middleware';
5
+ export * from './require-auth.middleware';
6
+ export * from './require-user.middleware';
7
+ export * from './require-org-permission.middleware';
8
+ export * from './require-workspace-permission.middleware';
9
+ export * from './require-platform-permission.middleware';
10
+ export * from './require-org-permission-from-body.middleware';
@@ -2,16 +2,5 @@
2
2
  * @file request-context.middleware.ts
3
3
  * @description Express middleware to assign request tracing and audit metadata context.
4
4
  */
5
- import { Request, Response, NextFunction } from "express";
6
- /**
7
- * Attaches request metadata used for:
8
- * - distributed tracing
9
- * - audit logs
10
- * - debugging correlation
11
- *
12
- * @param {Request} req - Express request object.
13
- * @param {Response} res - Express response object.
14
- * @param {NextFunction} next - Express next middleware function.
15
- * @returns {void}
16
- */
5
+ import { Request, Response, NextFunction } from 'express';
17
6
  export declare const requestContext: (req: Request, res: Response, next: NextFunction) => void;
@@ -6,68 +6,43 @@
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.requestContext = void 0;
8
8
  const crypto_1 = require("crypto");
9
- /**
10
- * Normalizes IPv4-mapped IPv6 addresses.
11
- *
12
- * @param {string | null} ip - Raw IP.
13
- * @returns {string | null} Normalized IP.
14
- */
9
+ const request_context_storage_1 = require("../context/request-context.storage");
15
10
  function normalizeIp(ip) {
16
- if (!ip) {
11
+ if (!ip)
17
12
  return null;
13
+ if (ip === '::1') {
14
+ return '127.0.0.1';
18
15
  }
19
- if (ip === "::1") {
20
- return "127.0.0.1";
21
- }
22
- if (ip.startsWith("::ffff:")) {
16
+ if (ip.startsWith('::ffff:')) {
23
17
  return ip.substring(7);
24
18
  }
25
19
  return ip;
26
20
  }
27
- /**
28
- * Resolves original client IP forwarded by the API Gateway.
29
- *
30
- * Priority:
31
- * 1. x-forwarded-for
32
- * 2. x-real-ip
33
- * 3. socket fallback (local development only)
34
- *
35
- * @param {Request} req - Express request object.
36
- * @returns {string | null} Client IP address.
37
- */
38
21
  function resolveClientIp(req) {
39
- const forwarded = req.headers["x-forwarded-for"];
22
+ const forwarded = req.headers['x-forwarded-for'];
40
23
  if (forwarded) {
41
24
  const value = Array.isArray(forwarded) ? forwarded[0] : forwarded;
42
- return normalizeIp(value.split(",")[0].trim());
25
+ return normalizeIp(value.split(',')[0].trim());
43
26
  }
44
- const realIp = req.headers["x-real-ip"];
27
+ const realIp = req.headers['x-real-ip'];
45
28
  if (realIp) {
46
29
  return normalizeIp(Array.isArray(realIp) ? realIp[0] : realIp);
47
30
  }
48
31
  return normalizeIp(req.socket.remoteAddress ?? null);
49
32
  }
50
- /**
51
- * Attaches request metadata used for:
52
- * - distributed tracing
53
- * - audit logs
54
- * - debugging correlation
55
- *
56
- * @param {Request} req - Express request object.
57
- * @param {Response} res - Express response object.
58
- * @param {NextFunction} next - Express next middleware function.
59
- * @returns {void}
60
- */
61
33
  const requestContext = (req, res, next) => {
62
- const upstream = req.headers["x-request-id"];
34
+ const upstream = req.headers['x-request-id'];
63
35
  const requestId = Array.isArray(upstream) ? upstream[0] : (upstream ?? (0, crypto_1.randomUUID)());
64
- req.id = requestId;
65
- req.requestContext = {
36
+ // Explicitly type this as AuditRequestContext so TS knows it's mutable
37
+ // and allows the `.actor` property to be assigned by the auth middlewares later.
38
+ const context = {
66
39
  requestId,
67
40
  ipAddress: resolveClientIp(req),
68
- userAgent: req.headers["user-agent"] ?? null,
41
+ userAgent: req.headers['user-agent'] ?? null,
69
42
  };
70
- res.setHeader("x-request-id", requestId);
71
- next();
43
+ req.id = requestId;
44
+ req.requestContext = context;
45
+ res.setHeader('x-request-id', requestId);
46
+ request_context_storage_1.requestContextStorage.run(context, () => next());
72
47
  };
73
48
  exports.requestContext = requestContext;
@@ -3,29 +3,13 @@
3
3
  * @description Authentication boundary middleware. Verifies the internal gateway JWT,
4
4
  * builds the auth context, and gates endpoints.
5
5
  */
6
- import { Request, Response, NextFunction } from "express";
7
- import { ILogger } from "../utils";
8
- import { UserJwtVerifier } from "../jwt/user-jwt-verifier";
9
- /**
10
- * Middleware handling authentication validation.
11
- * Extracts the JWT, verifies it via UserJwtVerifier, and attaches the AuthContext.
12
- */
6
+ import { Request, Response, NextFunction } from 'express';
7
+ import { ILogger } from '../utils';
8
+ import { UserJwtVerifier } from '../jwt/user-jwt-verifier';
13
9
  export declare class RequireAuthMiddleware {
14
10
  private readonly verifier;
15
11
  private readonly logger;
16
- /**
17
- * @param {UserJwtVerifier} verifier - The token verification engine.
18
- * @param {ILogger} [logger] - Optional logger instance.
19
- */
20
12
  constructor(verifier: UserJwtVerifier, logger?: ILogger);
21
- /**
22
- * Core Express middleware handler for authenticating requests.
23
- *
24
- * @param {Request} req - Express request object.
25
- * @param {Response} res - Express response object.
26
- * @param {NextFunction} next - Express next function.
27
- * @returns {Promise<void>}
28
- */
29
13
  handle: (req: Request, res: Response, next: NextFunction) => Promise<void>;
30
14
  private extractBearer;
31
15
  private handleJwtError;
@@ -8,41 +8,28 @@ Object.defineProperty(exports, "__esModule", { value: true });
8
8
  exports.RequireAuthMiddleware = void 0;
9
9
  const jose_1 = require("jose");
10
10
  const utils_1 = require("../utils");
11
- /**
12
- * Middleware handling authentication validation.
13
- * Extracts the JWT, verifies it via UserJwtVerifier, and attaches the AuthContext.
14
- */
11
+ const request_context_storage_1 = require("../context/request-context.storage");
15
12
  class RequireAuthMiddleware {
16
- /**
17
- * @param {UserJwtVerifier} verifier - The token verification engine.
18
- * @param {ILogger} [logger] - Optional logger instance.
19
- */
20
13
  constructor(verifier, logger = utils_1.noopLogger) {
21
14
  this.verifier = verifier;
22
15
  this.logger = logger;
23
- /**
24
- * Core Express middleware handler for authenticating requests.
25
- *
26
- * @param {Request} req - Express request object.
27
- * @param {Response} res - Express response object.
28
- * @param {NextFunction} next - Express next function.
29
- * @returns {Promise<void>}
30
- */
31
16
  this.handle = async (req, res, next) => {
32
17
  const token = this.extractBearer(req);
33
18
  if (!token) {
34
- (0, utils_1.failure)(res, req, "Missing Authorization header", "UNAUTHORIZED", 401);
19
+ (0, utils_1.failure)(res, req, 'Missing Authorization header', 'UNAUTHORIZED', 401);
35
20
  return;
36
21
  }
37
22
  try {
38
23
  const { payload, context } = await this.verifier.buildAccessContext(token);
39
24
  req.authPayload = payload;
40
25
  req.authContext = context;
26
+ // Attach audit context. Will throw if requestContextStorage is not initialized.
27
+ request_context_storage_1.RequestContextProvider.setActor(context);
41
28
  this.logger.debug({
42
29
  requestId: req.id,
43
30
  identity: context.accountId,
44
31
  type: context.type,
45
- }, "Request authenticated");
32
+ }, 'Request authenticated');
46
33
  next();
47
34
  }
48
35
  catch (err) {
@@ -55,29 +42,33 @@ class RequireAuthMiddleware {
55
42
  --------------------------------------------------------------------------- */
56
43
  extractBearer(req) {
57
44
  const header = req.headers.authorization;
58
- if (!header) {
45
+ if (!header)
59
46
  return null;
60
- }
61
47
  const [scheme, token] = header.trim().split(/\s+/);
62
- if (scheme !== "Bearer" || !token) {
48
+ if (scheme !== 'Bearer' || !token)
63
49
  return null;
64
- }
65
50
  return token;
66
51
  }
67
52
  handleJwtError(err, req, res) {
68
53
  if (err instanceof jose_1.errors.JWTExpired) {
69
- (0, utils_1.failure)(res, req, "Your session has expired. Please log in again.", "TOKEN_EXPIRED", 401);
54
+ (0, utils_1.failure)(res, req, 'Your session has expired. Please log in again.', 'TOKEN_EXPIRED', 401);
70
55
  return;
71
56
  }
72
57
  if (err instanceof jose_1.errors.JWTClaimValidationFailed ||
73
58
  err instanceof jose_1.errors.JWSSignatureVerificationFailed ||
74
59
  err instanceof jose_1.errors.JWSInvalid ||
75
60
  err instanceof jose_1.errors.JWTInvalid) {
76
- (0, utils_1.failure)(res, req, "Token is invalid or has been tampered with.", "INVALID_TOKEN", 401);
61
+ (0, utils_1.failure)(res, req, 'Token is invalid or has been tampered with.', 'INVALID_TOKEN', 401);
62
+ return;
63
+ }
64
+ // Catch the specific Developer Error from RequestContextProvider
65
+ if (err instanceof Error && err.message.includes('AuditRequestContext')) {
66
+ this.logger.error({ err, requestId: req.id }, 'CRITICAL: RequireAuthMiddleware failed because requestContextStorage is not initialized. Check your middleware order.');
67
+ (0, utils_1.failure)(res, req, 'Internal server configuration error.', 'INTERNAL_SERVER_ERROR', 500);
77
68
  return;
78
69
  }
79
- this.logger.error({ err, requestId: req.id }, "RequireAuthMiddleware: unexpected error during JWT verification");
80
- (0, utils_1.failure)(res, req, "Authentication service is temporarily unavailable.", "SERVICE_UNAVAILABLE", 503);
70
+ this.logger.error({ err, requestId: req.id }, 'RequireAuthMiddleware: unexpected error during JWT verification');
71
+ (0, utils_1.failure)(res, req, 'Authentication service is temporarily unavailable.', 'SERVICE_UNAVAILABLE', 503);
81
72
  }
82
73
  }
83
74
  exports.RequireAuthMiddleware = RequireAuthMiddleware;
@@ -3,36 +3,11 @@
3
3
  * @description Express middleware enforcing auth-service issued machine JWT verification
4
4
  * for service-to-service communication endpoints.
5
5
  */
6
- import { RequestHandler } from "express";
7
- import { ILogger } from "../utils/logger.util";
8
- /**
9
- * Configuration options for machine authentication middleware.
10
- */
6
+ import { RequestHandler } from 'express';
7
+ import { ILogger } from '../utils/logger.util';
11
8
  export interface RequireMachineOptions {
12
- /**
13
- * Auth-service JWKS endpoint used to verify machine JWT signatures.
14
- */
15
9
  authServiceJwksUri?: string;
16
- /**
17
- * Service identifiers allowed to access this endpoint.
18
- */
19
10
  allowedServices?: string[];
20
- /**
21
- * Optional structured logger.
22
- */
23
11
  logger?: ILogger;
24
12
  }
25
- /**
26
- * Creates middleware requiring a valid machine JWT.
27
- *
28
- * Flow:
29
- * - Extract Bearer token
30
- * - Verify RS256 signature using auth-service JWKS
31
- * - Validate machine token claims
32
- * - Apply service allowlist
33
- * - Attach MachineContext
34
- *
35
- * @param {RequireMachineOptions} [options] - Middleware configuration options.
36
- * @returns {RequestHandler} Express middleware handler.
37
- */
38
13
  export declare function requireMachine(options?: RequireMachineOptions): RequestHandler;
@@ -42,29 +42,20 @@ exports.requireMachine = requireMachine;
42
42
  const jose = __importStar(require("jose"));
43
43
  const logger_util_1 = require("../utils/logger.util");
44
44
  const machine_jwt_verifier_1 = require("../jwt/machine-jwt-verifier");
45
- /**
46
- * Creates middleware requiring a valid machine JWT.
47
- *
48
- * Flow:
49
- * - Extract Bearer token
50
- * - Verify RS256 signature using auth-service JWKS
51
- * - Validate machine token claims
52
- * - Apply service allowlist
53
- * - Attach MachineContext
54
- *
55
- * @param {RequireMachineOptions} [options] - Middleware configuration options.
56
- * @returns {RequestHandler} Express middleware handler.
57
- */
45
+ const request_context_storage_1 = require("../context/request-context.storage");
58
46
  function requireMachine(options = {}) {
59
47
  const logger = options.logger ?? logger_util_1.noopLogger;
60
48
  const verifier = new machine_jwt_verifier_1.MachineJwtVerifier(options.authServiceJwksUri);
61
49
  const { allowedServices } = options;
62
50
  return async (req, res, next) => {
63
51
  const header = req.headers.authorization;
64
- if (!header?.startsWith("Bearer ")) {
52
+ if (!header?.startsWith('Bearer ')) {
65
53
  res.status(401).json({
66
54
  success: false,
67
- error: { code: "UNAUTHORIZED", message: "Missing Authorization header" },
55
+ error: {
56
+ code: 'UNAUTHORIZED',
57
+ message: 'Missing Authorization header',
58
+ },
68
59
  });
69
60
  return;
70
61
  }
@@ -72,31 +63,33 @@ function requireMachine(options = {}) {
72
63
  try {
73
64
  const payload = await verifier.verify(token);
74
65
  if (allowedServices && !allowedServices.includes(payload.serviceId)) {
75
- logger.warn({ requestId: req.id, serviceId: payload.serviceId }, "[requireMachine] Service rejected");
66
+ logger.warn({ requestId: req.id, serviceId: payload.serviceId }, '[requireMachine] Service rejected');
76
67
  res.status(403).json({
77
68
  success: false,
78
69
  error: {
79
- code: "FORBIDDEN",
80
- message: "Service is not permitted to access this endpoint",
70
+ code: 'FORBIDDEN',
71
+ message: 'Service is not permitted to access this endpoint',
81
72
  },
82
73
  });
83
74
  return;
84
75
  }
85
76
  const context = {
86
- type: "machine",
77
+ type: 'machine',
87
78
  serviceId: payload.serviceId,
88
79
  scopes: payload.scopes,
89
80
  };
90
81
  req.authPayload = payload;
91
82
  req.authContext = context;
92
- logger.debug({ requestId: req.id, serviceId: payload.serviceId, jti: payload.jti }, "[requireMachine] Machine authenticated");
83
+ // Attach audit context. Will throw if requestContextStorage is not initialized.
84
+ request_context_storage_1.RequestContextProvider.setActor(context);
85
+ logger.debug({ requestId: req.id, serviceId: payload.serviceId, jti: payload.jti }, '[requireMachine] Machine authenticated');
93
86
  next();
94
87
  }
95
88
  catch (err) {
96
89
  if (err instanceof jose.errors.JWTExpired) {
97
90
  res.status(401).json({
98
91
  success: false,
99
- error: { code: "TOKEN_EXPIRED", message: "Machine token expired" },
92
+ error: { code: 'TOKEN_EXPIRED', message: 'Machine token expired' },
100
93
  });
101
94
  return;
102
95
  }
@@ -106,16 +99,28 @@ function requireMachine(options = {}) {
106
99
  err instanceof jose.errors.JWTInvalid) {
107
100
  res.status(401).json({
108
101
  success: false,
109
- error: { code: "INVALID_TOKEN", message: "Invalid machine token" },
102
+ error: { code: 'INVALID_TOKEN', message: 'Invalid machine token' },
103
+ });
104
+ return;
105
+ }
106
+ // Catch the specific Developer Error from RequestContextProvider
107
+ if (err instanceof Error && err.message.includes('AuditRequestContext')) {
108
+ logger.error({ err, requestId: req.id }, 'CRITICAL: [requireMachine] failed because requestContextStorage is not initialized. Check middleware order.');
109
+ res.status(500).json({
110
+ success: false,
111
+ error: {
112
+ code: 'INTERNAL_SERVER_ERROR',
113
+ message: 'Internal server configuration error',
114
+ },
110
115
  });
111
116
  return;
112
117
  }
113
- logger.error({ err, requestId: req.id }, "[requireMachine] Machine authentication failure");
118
+ logger.error({ err, requestId: req.id }, '[requireMachine] Machine authentication failure');
114
119
  res.status(503).json({
115
120
  success: false,
116
121
  error: {
117
- code: "SERVICE_UNAVAILABLE",
118
- message: "Machine authentication temporarily unavailable",
122
+ code: 'SERVICE_UNAVAILABLE',
123
+ message: 'Machine authentication temporarily unavailable',
119
124
  },
120
125
  });
121
126
  }
@@ -9,8 +9,7 @@ exports.createRequireOrgPermissionFromBody = void 0;
9
9
  const createRequireOrgPermissionFromBody = (requireOrgPermission) => {
10
10
  const requireOrgPermissionFromBody = (permission) => {
11
11
  return async (req, res, next) => {
12
- const organizationId = req.body?.organizationId ??
13
- req.validated?.body?.organizationId;
12
+ const organizationId = req.body?.organizationId ?? req.validated?.body?.organizationId;
14
13
  if (!organizationId) {
15
14
  return next();
16
15
  }
@@ -2,9 +2,9 @@
2
2
  * @file require-org-permission.middleware.ts
3
3
  * @description Express middleware generator to enforce organization-scoped permission checks.
4
4
  */
5
- import { RequestHandler } from "express";
6
- import { Permission } from "../enums";
7
- import { PermissionCacheService } from "../authorization/permission-cache.service";
5
+ import { RequestHandler } from 'express';
6
+ import { Permission } from '../enums';
7
+ import { PermissionCacheService } from '../authorization/permission-cache.service';
8
8
  /**
9
9
  * Creates requireOrgPermission middleware factory.
10
10
  *