@discover-cloud/shared 1.2.9 → 1.3.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 (165) hide show
  1. package/dist/authorization/index.d.ts +1 -1
  2. package/dist/authorization/index.js +1 -1
  3. package/dist/authorization/permission-cache.service.d.ts +104 -16
  4. package/dist/authorization/permission-cache.service.js +156 -143
  5. package/dist/authorization/permission-checker.d.ts +30 -0
  6. package/dist/authorization/permission-checker.js +40 -0
  7. package/dist/contracts/auth-service/account.dto.d.ts +30 -0
  8. package/dist/contracts/auth-service/account.dto.js +7 -0
  9. package/dist/contracts/auth-service/auth.dto.d.ts +21 -0
  10. package/dist/contracts/auth-service/auth.dto.js +10 -0
  11. package/dist/dtos/auth-service.dto.d.ts +72 -26
  12. package/dist/dtos/auth-service.dto.js +4 -0
  13. package/dist/dtos/cloud-service.dto.d.ts +51 -27
  14. package/dist/dtos/cloud-service.dto.js +5 -0
  15. package/dist/dtos/insights-service.dto.d.ts +18 -27
  16. package/dist/dtos/insights-service.dto.js +8 -0
  17. package/dist/dtos/response.dto.d.ts +7 -84
  18. package/dist/dtos/response.dto.js +2 -21
  19. package/dist/dtos/user-service.dto.d.ts +118 -13
  20. package/dist/enums/domain.enums.d.ts +246 -75
  21. package/dist/enums/domain.enums.js +305 -102
  22. package/dist/enums/permissions.enums.d.ts +142 -80
  23. package/dist/enums/permissions.enums.js +174 -133
  24. package/dist/errors/app-error.d.ts +13 -18
  25. package/dist/errors/app-error.js +14 -20
  26. package/dist/errors/http-errors.d.ts +105 -17
  27. package/dist/errors/http-errors.js +118 -33
  28. package/dist/http/index.d.ts +1 -0
  29. package/dist/http/index.js +1 -0
  30. package/dist/http/request-context.d.ts +8 -0
  31. package/dist/http/request-context.js +37 -0
  32. package/dist/http/service-client.d.ts +91 -38
  33. package/dist/http/service-client.js +102 -53
  34. package/dist/index.d.ts +1 -0
  35. package/dist/index.js +1 -0
  36. package/dist/jwt/index.d.ts +2 -1
  37. package/dist/jwt/index.js +2 -1
  38. package/dist/jwt/machine-jwt-verifier.d.ts +21 -0
  39. package/dist/jwt/machine-jwt-verifier.js +84 -0
  40. package/dist/jwt/machine-token-client.d.ts +35 -4
  41. package/dist/jwt/machine-token-client.js +57 -23
  42. package/dist/jwt/user-jwt-verifier.d.ts +31 -0
  43. package/dist/jwt/user-jwt-verifier.js +101 -0
  44. package/dist/messaging/index.d.ts +1 -0
  45. package/dist/{security → messaging}/index.js +1 -1
  46. package/dist/messaging/rabbitmq.client.d.ts +13 -0
  47. package/dist/messaging/rabbitmq.client.js +127 -0
  48. package/dist/middleware/error-handler.middleware.d.ts +8 -28
  49. package/dist/middleware/error-handler.middleware.js +61 -52
  50. package/dist/middleware/index.d.ts +7 -5
  51. package/dist/middleware/index.js +7 -5
  52. package/dist/middleware/request-context.middleware.d.ts +17 -0
  53. package/dist/middleware/request-context.middleware.js +73 -0
  54. package/dist/middleware/require-auth.middleware.d.ts +17 -70
  55. package/dist/middleware/require-auth.middleware.js +24 -103
  56. package/dist/middleware/require-machine.middleware.d.ts +38 -0
  57. package/dist/middleware/require-machine.middleware.js +123 -0
  58. package/dist/middleware/require-org-permission-from-body.middleware.d.ts +10 -0
  59. package/dist/middleware/require-org-permission-from-body.middleware.js +24 -0
  60. package/dist/middleware/require-org-permission.middleware.d.ts +19 -0
  61. package/dist/middleware/require-org-permission.middleware.js +115 -0
  62. package/dist/middleware/require-platform-permission.middleware.d.ts +19 -0
  63. package/dist/middleware/require-platform-permission.middleware.js +91 -0
  64. package/dist/middleware/require-user.middleware.d.ts +14 -0
  65. package/dist/middleware/require-user.middleware.js +30 -0
  66. package/dist/middleware/require-workspace-permission.middleware.d.ts +20 -0
  67. package/dist/middleware/require-workspace-permission.middleware.js +114 -0
  68. package/dist/middleware/validate.middleware.d.ts +29 -29
  69. package/dist/middleware/validate.middleware.js +30 -32
  70. package/dist/types/express.types.d.ts +83 -122
  71. package/dist/types/express.types.js +28 -47
  72. package/dist/utils/date.util.d.ts +6 -0
  73. package/dist/utils/date.util.js +11 -0
  74. package/dist/utils/env.util.d.ts +6 -0
  75. package/dist/utils/env.util.js +19 -0
  76. package/dist/utils/index.d.ts +5 -4
  77. package/dist/utils/index.js +5 -4
  78. package/dist/utils/logger.util.d.ts +26 -0
  79. package/dist/utils/logger.util.js +53 -0
  80. package/dist/utils/pagination.util.d.ts +6 -0
  81. package/dist/utils/pagination.util.js +20 -0
  82. package/dist/utils/response.util.d.ts +27 -0
  83. package/dist/utils/response.util.js +56 -0
  84. package/dist/utils/slug.util.d.ts +9 -0
  85. package/dist/utils/slug.util.js +32 -0
  86. package/dist/utils/url-safety.util.d.ts +6 -0
  87. package/dist/utils/url-safety.util.js +72 -0
  88. package/package.json +3 -1
  89. package/dist/authorization/permissions.d.ts +0 -78
  90. package/dist/authorization/permissions.js +0 -174
  91. package/dist/context/access-context.d.ts +0 -10
  92. package/dist/context/access-context.js +0 -2
  93. package/dist/context/index.d.ts +0 -1
  94. package/dist/context/index.js +0 -17
  95. package/dist/dto/auth-service.dtos.d.ts +0 -44
  96. package/dist/dto/auth-service.dtos.js +0 -2
  97. package/dist/dto/index.d.ts +0 -3
  98. package/dist/dto/index.js +0 -19
  99. package/dist/dto/response.dtos.d.ts +0 -55
  100. package/dist/dto/response.dtos.js +0 -6
  101. package/dist/dto/user-service.dtos.d.ts +0 -50
  102. package/dist/dto/user-service.dtos.js +0 -2
  103. package/dist/enums/auth-service.enums.d.ts +0 -12
  104. package/dist/enums/auth-service.enums.js +0 -17
  105. package/dist/enums/permissions.types.d.ts +0 -12
  106. package/dist/enums/permissions.types.js +0 -17
  107. package/dist/enums/user-service.enums.d.ts +0 -32
  108. package/dist/enums/user-service.enums.js +0 -41
  109. package/dist/internal/index.d.ts +0 -4
  110. package/dist/internal/index.js +0 -20
  111. package/dist/internal/internal-jwt.service.d.ts +0 -13
  112. package/dist/internal/internal-jwt.service.js +0 -88
  113. package/dist/internal/internal-jwt.types.d.ts +0 -7
  114. package/dist/internal/internal-jwt.types.js +0 -2
  115. package/dist/internal/internal-key-manager.d.ts +0 -16
  116. package/dist/internal/internal-key-manager.js +0 -67
  117. package/dist/internal/registry.d.ts +0 -8
  118. package/dist/internal/registry.js +0 -34
  119. package/dist/internal/service-client.d.ts +0 -9
  120. package/dist/internal/service-client.js +0 -94
  121. package/dist/jwt/internal-jwt-verifier.d.ts +0 -41
  122. package/dist/jwt/internal-jwt-verifier.js +0 -185
  123. package/dist/jwt/jwt-verifier.d.ts +0 -9
  124. package/dist/jwt/jwt-verifier.js +0 -36
  125. package/dist/jwt/service-client.d.ts +0 -7
  126. package/dist/jwt/service-client.js +0 -87
  127. package/dist/middleware/authorize.d.ts +0 -3
  128. package/dist/middleware/authorize.js +0 -24
  129. package/dist/middleware/authorize.middleware.d.ts +0 -54
  130. package/dist/middleware/authorize.middleware.js +0 -104
  131. package/dist/middleware/error-handler.d.ts +0 -4
  132. package/dist/middleware/error-handler.js +0 -23
  133. package/dist/middleware/request-id.d.ts +0 -2
  134. package/dist/middleware/request-id.js +0 -9
  135. package/dist/middleware/request-id.middleware.d.ts +0 -22
  136. package/dist/middleware/request-id.middleware.js +0 -34
  137. package/dist/middleware/require-auth.d.ts +0 -10
  138. package/dist/middleware/require-auth.js +0 -34
  139. package/dist/middleware/require-human.middleware.d.ts +0 -2
  140. package/dist/middleware/require-human.middleware.js +0 -18
  141. package/dist/middleware/require-internal.middleware.d.ts +0 -18
  142. package/dist/middleware/require-internal.middleware.js +0 -183
  143. package/dist/middleware/validate.d.ts +0 -5
  144. package/dist/middleware/validate.js +0 -18
  145. package/dist/middleware/validated-merge.middleware.d.ts +0 -20
  146. package/dist/middleware/validated-merge.middleware.js +0 -33
  147. package/dist/middleware/verify-internal-jwt.d.ts +0 -7
  148. package/dist/middleware/verify-internal-jwt.js +0 -25
  149. package/dist/security/guard.d.ts +0 -10
  150. package/dist/security/guard.js +0 -40
  151. package/dist/security/index.d.ts +0 -1
  152. package/dist/types/express.d.ts +0 -22
  153. package/dist/types/express.js +0 -3
  154. package/dist/utils/date.utils.d.ts +0 -25
  155. package/dist/utils/date.utils.js +0 -30
  156. package/dist/utils/env.d.ts +0 -46
  157. package/dist/utils/env.js +0 -61
  158. package/dist/utils/env.utils.d.ts +0 -46
  159. package/dist/utils/env.utils.js +0 -61
  160. package/dist/utils/logger.utils.d.ts +0 -66
  161. package/dist/utils/logger.utils.js +0 -97
  162. package/dist/utils/response.d.ts +0 -4
  163. package/dist/utils/response.js +0 -35
  164. package/dist/utils/response.utils.d.ts +0 -54
  165. package/dist/utils/response.utils.js +0 -85
@@ -0,0 +1,13 @@
1
+ export declare class RabbitMQClient {
2
+ private connection;
3
+ private channel;
4
+ private url;
5
+ private exchangeName;
6
+ constructor(url: string);
7
+ connect(): Promise<void>;
8
+ publishEvent(routingKey: string, payload: any): Promise<void>;
9
+ subscribe(queueName: string, routingKey: string, handler: (payload: any) => Promise<void>, options?: {
10
+ prefetch?: number;
11
+ }): Promise<void>;
12
+ close(): Promise<void>;
13
+ }
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.RabbitMQClient = void 0;
37
+ const amqplib = __importStar(require("amqplib"));
38
+ class RabbitMQClient {
39
+ constructor(url) {
40
+ this.connection = null;
41
+ this.channel = null;
42
+ this.exchangeName = 'discovercloud.topic';
43
+ this.url = url;
44
+ }
45
+ async connect() {
46
+ if (this.connection && this.channel) {
47
+ return;
48
+ }
49
+ try {
50
+ this.connection = await amqplib.connect(this.url);
51
+ this.connection.on('error', (err) => {
52
+ console.error('RabbitMQ Connection Error:', err);
53
+ });
54
+ this.connection.on('close', () => {
55
+ console.warn('RabbitMQ Connection Closed. Reconnecting...');
56
+ this.connection = null;
57
+ this.channel = null;
58
+ setTimeout(() => this.connect(), 5000);
59
+ });
60
+ this.channel = await this.connection.createChannel();
61
+ // Ensure the main topic exchange exists
62
+ await this.channel.assertExchange(this.exchangeName, 'topic', { durable: true });
63
+ console.log('✅ Connected to RabbitMQ');
64
+ }
65
+ catch (error) {
66
+ console.error('❌ Failed to connect to RabbitMQ:', error);
67
+ setTimeout(() => this.connect(), 5000);
68
+ }
69
+ }
70
+ async publishEvent(routingKey, payload) {
71
+ if (!this.channel) {
72
+ throw new Error('RabbitMQ Channel not initialized');
73
+ }
74
+ const buffer = Buffer.from(JSON.stringify(payload));
75
+ this.channel.publish(this.exchangeName, routingKey, buffer, {
76
+ persistent: true,
77
+ contentType: 'application/json',
78
+ timestamp: Date.now(),
79
+ });
80
+ }
81
+ async subscribe(queueName, routingKey, handler, options = {}) {
82
+ if (!this.channel) {
83
+ throw new Error('RabbitMQ Channel not initialized');
84
+ }
85
+ if (options.prefetch) {
86
+ await this.channel.prefetch(options.prefetch);
87
+ }
88
+ // Dead Letter configuration
89
+ const dlxName = `${this.exchangeName}.dlx`;
90
+ const dlqName = `${queueName}.dlq`;
91
+ await this.channel.assertExchange(dlxName, 'topic', { durable: true });
92
+ await this.channel.assertQueue(dlqName, { durable: true });
93
+ await this.channel.bindQueue(dlqName, dlxName, routingKey);
94
+ // Assert main queue with DLX bindings
95
+ await this.channel.assertQueue(queueName, {
96
+ durable: true,
97
+ deadLetterExchange: dlxName,
98
+ deadLetterRoutingKey: routingKey,
99
+ });
100
+ await this.channel.bindQueue(queueName, this.exchangeName, routingKey);
101
+ this.channel.consume(queueName, async (msg) => {
102
+ if (!msg)
103
+ return;
104
+ try {
105
+ const payload = JSON.parse(msg.content.toString());
106
+ await handler(payload);
107
+ this.channel.ack(msg);
108
+ }
109
+ catch (error) {
110
+ console.error(`Error processing message from ${queueName}:`, error);
111
+ // Nack the message and don't requeue, so it goes to the DLX
112
+ this.channel.nack(msg, false, false);
113
+ }
114
+ });
115
+ console.log(`📡 Subscribed to queue [${queueName}] with routing key [${routingKey}]`);
116
+ }
117
+ async close() {
118
+ if (this.channel) {
119
+ await this.channel.close();
120
+ }
121
+ if (this.connection) {
122
+ await this.connection.close();
123
+ }
124
+ console.log('RabbitMQ connection closed.');
125
+ }
126
+ }
127
+ exports.RabbitMQClient = RabbitMQClient;
@@ -1,30 +1,10 @@
1
- import { Request, Response, NextFunction } from "express";
2
1
  /**
3
- * GLOBAL ERROR HANDLER (@discover-cloud/shared)
4
- * ────────────────────────────────────────────────
5
- * Centralised Express error handler. Register as the last middleware in
6
- * every service's app.ts:
7
- *
8
- * app.use(GlobalErrorHandler.handle);
9
- *
10
- * Handles in order:
11
- * 1. ZodError → 400 VALIDATION_ERROR with flattened field errors
12
- * 2. AppError → mapped statusCode + code (details forwarded to client)
13
- * 3. Unknown → 500 INTERNAL_SERVER_ERROR (internals never leaked)
14
- *
15
- * Logging strategy:
16
- * Development — full error object printed for stack traces during development.
17
- * Production — message only for AppError/Error (no stack, no details in logs).
18
- * Unknown errors log the raw value at warn level.
19
- * In production, a structured logger (Pino) replaces console.*
20
- * in each service — these console calls are captured by stdout.
21
- *
22
- * Security:
23
- * Unknown (unexpected) errors never expose internals to the client.
24
- * AppError.details IS forwarded — callers that set details on an AppError
25
- * are intentionally choosing to surface that context (e.g. validation hints).
26
- * Never put secrets, stack traces, or raw DB errors in AppError.details.
2
+ * @file error-handler.middleware.ts
3
+ * @description Central Express error handler. Register as the final middleware.
27
4
  */
28
- export declare class GlobalErrorHandler {
29
- static handle(err: unknown, req: Request, res: Response, _next: NextFunction): void;
30
- }
5
+ import { ErrorRequestHandler } from "express";
6
+ import { ILogger } from "../utils";
7
+ /**
8
+ * Creates global Express error middleware.
9
+ */
10
+ export declare function createGlobalErrorHandler(logger?: ILogger): ErrorRequestHandler;
@@ -1,70 +1,79 @@
1
1
  "use strict";
2
+ /**
3
+ * @file error-handler.middleware.ts
4
+ * @description Central Express error handler. Register as the final middleware.
5
+ */
2
6
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.GlobalErrorHandler = void 0;
7
+ exports.createGlobalErrorHandler = createGlobalErrorHandler;
4
8
  const zod_1 = require("zod");
5
9
  const errors_1 = require("../errors");
6
10
  const utils_1 = require("../utils");
7
11
  /**
8
- * GLOBAL ERROR HANDLER (@discover-cloud/shared)
9
- * ────────────────────────────────────────────────
10
- * Centralised Express error handler. Register as the last middleware in
11
- * every service's app.ts:
12
- *
13
- * app.use(GlobalErrorHandler.handle);
14
- *
15
- * Handles in order:
16
- * 1. ZodError → 400 VALIDATION_ERROR with flattened field errors
17
- * 2. AppError → mapped statusCode + code (details forwarded to client)
18
- * 3. Unknown → 500 INTERNAL_SERVER_ERROR (internals never leaked)
19
- *
20
- * Logging strategy:
21
- * Development — full error object printed for stack traces during development.
22
- * Production — message only for AppError/Error (no stack, no details in logs).
23
- * Unknown errors log the raw value at warn level.
24
- * In production, a structured logger (Pino) replaces console.*
25
- * in each service — these console calls are captured by stdout.
26
- *
27
- * Security:
28
- * Unknown (unexpected) errors never expose internals to the client.
29
- * AppError.details IS forwarded — callers that set details on an AppError
30
- * are intentionally choosing to surface that context (e.g. validation hints).
31
- * Never put secrets, stack traces, or raw DB errors in AppError.details.
12
+ * Detects malformed JSON thrown by express.json().
32
13
  */
33
- class GlobalErrorHandler {
34
- static handle(err, req, res, _next) {
35
- // ── Logging ──────────────────────────────────────────────────────────
36
- if (process.env["NODE_ENV"] !== "production") {
37
- // Full object in development — stack traces + details are useful locally.
38
- console.error(`[req ${req.id}]`, err);
39
- }
40
- else if (err instanceof Error) {
41
- // Production: message only — no stack, no details, no internal paths.
42
- console.error(`[req ${req.id}] ${err.name}: ${err.message}`);
43
- }
44
- else {
45
- // Non-Error throw (string, object, etc.) — log at warn; this should not happen.
46
- console.warn(`[req ${req.id}] Non-Error thrown:`, typeof err);
14
+ function isMalformedJsonError(err) {
15
+ return (err instanceof SyntaxError &&
16
+ "status" in err &&
17
+ typeof err.status === "number" &&
18
+ "body" in err);
19
+ }
20
+ /**
21
+ * Converts any thrown value into Error.
22
+ */
23
+ function normalizeError(err) {
24
+ if (err instanceof Error) {
25
+ return err;
26
+ }
27
+ if (typeof err === "string") {
28
+ return new Error(err);
29
+ }
30
+ return new Error(JSON.stringify(err));
31
+ }
32
+ /**
33
+ * Creates global Express error middleware.
34
+ */
35
+ function createGlobalErrorHandler(logger = utils_1.noopLogger) {
36
+ return (err, req, res, _next) => {
37
+ const error = normalizeError(err);
38
+ const requestId = req.requestContext?.requestId ?? req.id;
39
+ /**
40
+ * Malformed JSON
41
+ */
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);
45
+ return;
47
46
  }
48
- // ── 1. Zod validation errors ─────────────────────────────────────────
47
+ /**
48
+ * Validation failures
49
+ */
49
50
  if (err instanceof zod_1.ZodError) {
50
- // flatten() groups errors into fieldErrors (keyed by path) and formErrors
51
- // (top-level). This shape is stable across Zod versions and is what
52
- // clients should key on for field-level error display.
51
+ logger.warn({ requestId, err: error }, "Request validation failed");
53
52
  (0, utils_1.failure)(res, req, "Validation failed", "VALIDATION_ERROR", 400, err.flatten());
54
53
  return;
55
54
  }
56
- // ── 2. Known AppError subclasses ─────────────────────────────────────
57
- // instanceof check — no duck-typing, no accidental matches.
58
- // AppError.details is caller-controlled context (e.g. validation hints)
59
- // and is intentionally forwarded to the client.
55
+ /**
56
+ * Known application errors
57
+ */
60
58
  if (err instanceof errors_1.AppError) {
59
+ const payload = {
60
+ requestId,
61
+ code: err.code,
62
+ err: error,
63
+ };
64
+ if (err.statusCode >= 500) {
65
+ logger.error(payload, err.message);
66
+ }
67
+ else {
68
+ logger.warn(payload, err.message);
69
+ }
61
70
  (0, utils_1.failure)(res, req, err.message, err.code, err.statusCode, err.details);
62
71
  return;
63
72
  }
64
- // ── 3. Unexpected errors — never leak internals ───────────────────────
65
- // Generic 500 with no details. The actual error is logged above (production:
66
- // message only; development: full object). Nothing internal reaches the client.
73
+ /**
74
+ * Unknown crashes
75
+ */
76
+ logger.error({ requestId, err: error }, "Unhandled exception");
67
77
  (0, utils_1.failure)(res, req, "Internal Server Error", "INTERNAL_SERVER_ERROR", 500);
68
- }
78
+ };
69
79
  }
70
- exports.GlobalErrorHandler = GlobalErrorHandler;
@@ -1,8 +1,10 @@
1
1
  export * from "./error-handler.middleware";
2
2
  export * from "./validate.middleware";
3
- export * from "./request-id.middleware";
4
- export * from "./authorize.middleware";
5
- export * from "./validated-merge.middleware";
6
- export * from "./require-internal.middleware";
3
+ export * from "./request-context.middleware";
4
+ export * from "./require-machine.middleware";
7
5
  export * from "./require-auth.middleware";
8
- export * from "./require-human.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";
@@ -16,9 +16,11 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./error-handler.middleware"), exports);
18
18
  __exportStar(require("./validate.middleware"), exports);
19
- __exportStar(require("./request-id.middleware"), exports);
20
- __exportStar(require("./authorize.middleware"), exports);
21
- __exportStar(require("./validated-merge.middleware"), exports);
22
- __exportStar(require("./require-internal.middleware"), exports);
19
+ __exportStar(require("./request-context.middleware"), exports);
20
+ __exportStar(require("./require-machine.middleware"), exports);
23
21
  __exportStar(require("./require-auth.middleware"), exports);
24
- __exportStar(require("./require-human.middleware"), exports);
22
+ __exportStar(require("./require-user.middleware"), exports);
23
+ __exportStar(require("./require-org-permission.middleware"), exports);
24
+ __exportStar(require("./require-workspace-permission.middleware"), exports);
25
+ __exportStar(require("./require-platform-permission.middleware"), exports);
26
+ __exportStar(require("./require-org-permission-from-body.middleware"), exports);
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @file request-context.middleware.ts
3
+ * @description Express middleware to assign request tracing and audit metadata context.
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
+ */
17
+ export declare const requestContext: (req: Request, res: Response, next: NextFunction) => void;
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ /**
3
+ * @file request-context.middleware.ts
4
+ * @description Express middleware to assign request tracing and audit metadata context.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.requestContext = void 0;
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
+ */
15
+ function normalizeIp(ip) {
16
+ if (!ip) {
17
+ return null;
18
+ }
19
+ if (ip === "::1") {
20
+ return "127.0.0.1";
21
+ }
22
+ if (ip.startsWith("::ffff:")) {
23
+ return ip.substring(7);
24
+ }
25
+ return ip;
26
+ }
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
+ function resolveClientIp(req) {
39
+ const forwarded = req.headers["x-forwarded-for"];
40
+ if (forwarded) {
41
+ const value = Array.isArray(forwarded) ? forwarded[0] : forwarded;
42
+ return normalizeIp(value.split(",")[0].trim());
43
+ }
44
+ const realIp = req.headers["x-real-ip"];
45
+ if (realIp) {
46
+ return normalizeIp(Array.isArray(realIp) ? realIp[0] : realIp);
47
+ }
48
+ return normalizeIp(req.socket.remoteAddress ?? null);
49
+ }
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
+ const requestContext = (req, res, next) => {
62
+ const upstream = req.headers["x-request-id"];
63
+ const requestId = Array.isArray(upstream) ? upstream[0] : (upstream ?? (0, crypto_1.randomUUID)());
64
+ req.id = requestId;
65
+ req.requestContext = {
66
+ requestId,
67
+ ipAddress: resolveClientIp(req),
68
+ userAgent: req.headers["user-agent"] ?? null,
69
+ };
70
+ res.setHeader("x-request-id", requestId);
71
+ next();
72
+ };
73
+ exports.requestContext = requestContext;
@@ -1,85 +1,32 @@
1
+ /**
2
+ * @file require-auth.middleware.ts
3
+ * @description Authentication boundary middleware. Verifies the internal gateway JWT,
4
+ * builds the auth context, and gates endpoints.
5
+ */
1
6
  import { Request, Response, NextFunction } from "express";
2
- import { AccountRole, GlobalPermission } from "../enums";
3
7
  import { ILogger } from "../utils";
4
- import { InternalJwtVerifier } from "../jwt/internal-jwt-verifier";
8
+ import { UserJwtVerifier } from "../jwt/user-jwt-verifier";
5
9
  /**
6
- * REQUIRE AUTH MIDDLEWARE (@discover-cloud/shared)
7
- * ─────────────────────────────────────────────────────────────────────────
8
- * Verifies the internal JWT, resolves permissions from the Redis cache,
9
- * and attaches the typed AccessContext to req.accessContext.
10
- *
11
- * Moved to shared so every downstream service (auth, user, cloud, insights)
12
- * uses the same verified implementation rather than maintaining their own copy.
13
- *
14
- * Token extraction:
15
- * Reads a Bearer token from the Authorization header.
16
- * Does not support cookie-based auth — that is the API gateway's responsibility.
17
- *
18
- * On success:
19
- * req.internalAuth → raw verified JWT payload (use for jti, caller, requestId)
20
- * req.accessContext → clean typed context (use in controllers and services)
21
- *
22
- * On failure:
23
- * Returns a structured error response and does NOT call next().
24
- * next(err) is only called for genuinely unexpected errors (not auth failures).
25
- *
26
- * Inline guards (requirePermission, requireRole):
27
- * Convenience methods for single-route guards. For router-level permission
28
- * enforcement, prefer the standalone factories in permission.middleware.ts —
29
- * they don't require a reference to this class instance.
30
- *
31
- * Logging:
32
- * Unexpected errors are logged at "error" level with requestId for correlation.
33
- * Auth failures (expired, invalid token) are intentionally not logged at error
34
- * level — they are client errors, not server faults.
35
- *
36
- * Usage in each service's app.ts:
37
- * import { RequireAuthMiddleware } from "@discover-cloud/shared";
38
- *
39
- * const requireAuth = new RequireAuthMiddleware(jwtVerifier, logger);
40
- * router.use(requireAuth.handle);
10
+ * Middleware handling authentication validation.
11
+ * Extracts the JWT, verifies it via UserJwtVerifier, and attaches the AuthContext.
41
12
  */
42
13
  export declare class RequireAuthMiddleware {
43
14
  private readonly verifier;
44
15
  private readonly logger;
45
- constructor(verifier: InternalJwtVerifier, logger?: ILogger);
46
16
  /**
47
- * Core authentication middleware.
48
- * Apply via: router.use(requireAuth.handle) or router.get("/", requireAuth.handle, controller.x)
17
+ * @param {UserJwtVerifier} verifier - The token verification engine.
18
+ * @param {ILogger} [logger] - Optional logger instance.
49
19
  */
50
- handle: (req: Request, res: Response, next: NextFunction) => Promise<void>;
20
+ constructor(verifier: UserJwtVerifier, logger?: ILogger);
51
21
  /**
52
- * Inline permission guard use when this class instance is available at the call site.
53
- * For router-level guards, prefer requireGlobalPermission() from permission.middleware.ts.
22
+ * Core Express middleware handler for authenticating requests.
54
23
  *
55
- * Usage: router.get("/", requireAuth.handle, requireAuth.requirePermission(P.READ_ACCOUNTS), controller.list)
56
- */
57
- requirePermission: (permission: GlobalPermission) => (req: Request, res: Response, next: NextFunction) => void;
58
- /**
59
- * Inline role guard — use when this class instance is available at the call site.
60
- *
61
- * Prefer permission-based guards over role-based guards where possible.
62
- * Role checks are appropriate for coarse access gates (e.g. "only admins enter this router").
63
- */
64
- requireRole: (role: AccountRole) => (req: Request, res: Response, next: NextFunction) => void;
65
- /**
66
- * Extracts the Bearer token from the Authorization header.
67
- * Returns null (not an error) if the header is absent or malformed —
68
- * callers decide how to handle the missing token.
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>}
69
28
  */
29
+ handle: (req: Request, res: Response, next: NextFunction) => Promise<void>;
70
30
  private extractBearer;
71
- /**
72
- * Maps jose verification errors to appropriate HTTP responses.
73
- *
74
- * Error categories:
75
- * JWTExpired → 401 TOKEN_EXPIRED (client should refresh)
76
- * JWTClaimValidationFailed,
77
- * JWSSignatureVerificationFailed,
78
- * JWSInvalid, JWTInvalid → 401 INVALID_TOKEN (client should re-login)
79
- * Anything else → 503 SERVICE_UNAVAILABLE (unexpected — log at error)
80
- *
81
- * Security note: generic "invalid token" messages are intentional.
82
- * Never expose which specific claim failed — that aids token forgery attempts.
83
- */
84
31
  private handleJwtError;
85
32
  }