@discover-cloud/shared 1.2.8 → 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
@@ -1,23 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.GlobalErrorHandler = void 0;
4
- const zod_1 = require("zod");
5
- const utils_1 = require("../utils");
6
- class GlobalErrorHandler {
7
- static handle(err, req, res, _next) {
8
- // Standardized logging using req.id from your requestId middleware
9
- console.error(`[req ${req.id}]`, err);
10
- // 1. Zod Validation Errors
11
- if (err instanceof zod_1.ZodError) {
12
- return (0, utils_1.failure)(res, "Validation failed", 400, err.flatten());
13
- }
14
- // 2. Custom App Errors (instanceof checks for BadRequestError, etc.)
15
- const custom = err;
16
- if (custom.statusCode) {
17
- return (0, utils_1.failure)(res, custom.message ?? "Error", custom.statusCode, custom.details);
18
- }
19
- // 3. Fallback: Internal Server Error
20
- return (0, utils_1.failure)(res, "Internal Server Error", 500);
21
- }
22
- }
23
- exports.GlobalErrorHandler = GlobalErrorHandler;
@@ -1,2 +0,0 @@
1
- import { Request, Response, NextFunction } from "express";
2
- export declare const requestId: (req: Request, _res: Response, next: NextFunction) => void;
@@ -1,9 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.requestId = void 0;
4
- const crypto_1 = require("crypto");
5
- const requestId = (req, _res, next) => {
6
- req.id = (0, crypto_1.randomUUID)();
7
- next();
8
- };
9
- exports.requestId = requestId;
@@ -1,22 +0,0 @@
1
- import { Request, Response, NextFunction } from "express";
2
- /**
3
- * REQUEST ID MIDDLEWARE (@discover-cloud/shared)
4
- * ─────────────────────────────────────────────────
5
- * Attaches a unique request ID to req.id for distributed tracing.
6
- * Register early in the middleware stack — before any logger or handler
7
- * that needs to include the request ID in its output.
8
- *
9
- * Priority:
10
- * 1. x-request-id header forwarded by the API Gateway (or load balancer)
11
- * 2. Newly generated UUID v4 if no upstream header is present
12
- *
13
- * Why forward the upstream header?
14
- * The gateway mints a requestId and stamps it on every internal request.
15
- * If downstream services generate their own IDs, the same logical request
16
- * carries different IDs in each service's logs, breaking cross-service
17
- * log correlation. Forwarding the upstream ID keeps the trace consistent.
18
- *
19
- * The resolved ID is also echoed back on the response via x-request-id
20
- * so clients and proxies can correlate their own logs with the service's.
21
- */
22
- export declare const requestId: (req: Request, res: Response, next: NextFunction) => void;
@@ -1,34 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.requestId = void 0;
4
- const crypto_1 = require("crypto");
5
- /**
6
- * REQUEST ID MIDDLEWARE (@discover-cloud/shared)
7
- * ─────────────────────────────────────────────────
8
- * Attaches a unique request ID to req.id for distributed tracing.
9
- * Register early in the middleware stack — before any logger or handler
10
- * that needs to include the request ID in its output.
11
- *
12
- * Priority:
13
- * 1. x-request-id header forwarded by the API Gateway (or load balancer)
14
- * 2. Newly generated UUID v4 if no upstream header is present
15
- *
16
- * Why forward the upstream header?
17
- * The gateway mints a requestId and stamps it on every internal request.
18
- * If downstream services generate their own IDs, the same logical request
19
- * carries different IDs in each service's logs, breaking cross-service
20
- * log correlation. Forwarding the upstream ID keeps the trace consistent.
21
- *
22
- * The resolved ID is also echoed back on the response via x-request-id
23
- * so clients and proxies can correlate their own logs with the service's.
24
- */
25
- const requestId = (req, res, next) => {
26
- const upstream = req.headers["x-request-id"];
27
- // Header can be a string array (multi-value header) — take the first value.
28
- const id = Array.isArray(upstream) ? upstream[0] : (upstream ?? (0, crypto_1.randomUUID)());
29
- req.id = id;
30
- // Echo back on the response for client-side and proxy-side correlation.
31
- res.setHeader("x-request-id", id);
32
- next();
33
- };
34
- exports.requestId = requestId;
@@ -1,10 +0,0 @@
1
- import { Request, Response, NextFunction } from "express";
2
- import { InternalJwtPayload } from "../types";
3
- export interface IJwtVerifier {
4
- verifyAccessToken(token: string): Promise<InternalJwtPayload>;
5
- }
6
- export declare class RequireAuthMiddleware {
7
- private readonly verifier;
8
- constructor(verifier: IJwtVerifier);
9
- handle: (req: Request, _res: Response, next: NextFunction) => Promise<void>;
10
- }
@@ -1,34 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RequireAuthMiddleware = void 0;
4
- const errors_1 = require("../errors");
5
- class RequireAuthMiddleware {
6
- constructor(verifier) {
7
- this.verifier = verifier;
8
- this.handle = async (req, _res, next) => {
9
- const header = req.headers.authorization;
10
- if (!header?.startsWith("Bearer ")) {
11
- return next(new errors_1.UnauthorizedError("Missing Authorization header"));
12
- }
13
- const token = header.slice(7);
14
- try {
15
- // 1. Verify against Gateway Public Keys
16
- const payload = await this.verifier.verifyAccessToken(token);
17
- // 2. Store the raw payload (Access to .jti for logouts/suspensions)
18
- req.internalAuth = payload;
19
- // 3. Build AccessContext if it's a human user
20
- if (payload.accountId && payload.accountRole) {
21
- req.accessContext = {
22
- accountId: payload.accountId,
23
- accountRole: payload.accountRole,
24
- };
25
- }
26
- next();
27
- }
28
- catch (err) {
29
- next(new errors_1.UnauthorizedError("Unauthorized: Token validation failed"));
30
- }
31
- };
32
- }
33
- }
34
- exports.RequireAuthMiddleware = RequireAuthMiddleware;
@@ -1,2 +0,0 @@
1
- import { Request, Response, NextFunction } from "express";
2
- export declare const requireHuman: (req: Request, res: Response, next: NextFunction) => void;
@@ -1,18 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.requireHuman = void 0;
4
- const utils_1 = require("../utils");
5
- const types_1 = require("../types");
6
- const requireHuman = (req, res, next) => {
7
- const ctx = req.accessContext;
8
- if (!ctx) {
9
- (0, utils_1.failure)(res, req, "Unauthorized: No access context", "UNAUTHORIZED", 401);
10
- return;
11
- }
12
- if (!(0, types_1.isHumanContext)(ctx)) {
13
- (0, utils_1.failure)(res, req, "Human token required", "FORBIDDEN", 403);
14
- return;
15
- }
16
- next();
17
- };
18
- exports.requireHuman = requireHuman;
@@ -1,18 +0,0 @@
1
- import { Request, Response, NextFunction } from "express";
2
- import { ILogger } from "../utils/logger.utils";
3
- export interface RequireInternalOptions {
4
- /**
5
- * Gateway JWKS URI.
6
- * Defaults to GATEWAY_JWKS_URI env var, then the docker-compose default.
7
- * Must point to the gateway, not any individual service.
8
- */
9
- gatewayJwksUri?: string;
10
- /**
11
- * Permitted serviceIds. Reject any machine token whose serviceId is
12
- * not in this list, even if the signature is valid.
13
- * Omit to accept any valid machine token (not recommended in production).
14
- */
15
- allowedServices?: string[];
16
- logger?: ILogger;
17
- }
18
- export declare function requireInternal(options?: RequireInternalOptions): (req: Request, res: Response, next: NextFunction) => Promise<void>;
@@ -1,183 +0,0 @@
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.requireInternal = requireInternal;
37
- const jose = __importStar(require("jose"));
38
- const types_1 = require("../types");
39
- const logger_utils_1 = require("../utils/logger.utils");
40
- /**
41
- * REQUIRE INTERNAL MIDDLEWARE (@discover-cloud/shared)
42
- * ─────────────────────────────────────────────────────────────────────────
43
- * Protects /internal/* routes by verifying a gateway-signed machine JWT.
44
- * Replaces X-Internal-Secret on all service-to-service endpoints.
45
- *
46
- * Trust model:
47
- * All machine tokens are signed by the gateway's private key and verified
48
- * against the gateway's JWKS endpoint — the same trust root used for
49
- * human tokens. There is exactly one signing authority in the system.
50
- *
51
- * Verification:
52
- * 1. Extract Bearer token from Authorization header
53
- * 2. Verify RS256 signature against gateway JWKS
54
- * 3. Assert typ === "internal" (token confusion defence)
55
- * 4. Assert isMachine === true (rejects human tokens on internal routes)
56
- * 5. Assert serviceId is in the allowlist (optional but recommended)
57
- * 6. Attach MachineAccessContext to req.accessContext
58
- *
59
- * JWKS caching:
60
- * One RemoteJWKSet instance is created per middleware instance (i.e. per
61
- * service process), cached internally by jose for JWKS_CACHE_MAX_AGE_MS.
62
- * No per-request network call under normal operation.
63
- *
64
- * Allowlist:
65
- * Pass allowedServices to restrict which services can call this endpoint.
66
- * Example: requireInternal({ allowedServices: ["cloud-service"] })
67
- * Defaults to accepting any valid machine token if omitted.
68
- * Always set this in production — it limits blast radius if a service
69
- * is compromised.
70
- *
71
- * Usage:
72
- * // insights-service internal routes
73
- * router.use("/internal", requireInternal({
74
- * gatewayJwksUri: process.env.GATEWAY_JWKS_URI,
75
- * allowedServices: ["cloud-service"],
76
- * logger,
77
- * }));
78
- */
79
- const CLOCK_TOLERANCE_S = 30;
80
- const JWKS_CACHE_MAX_AGE_MS = 10 * 60 * 1000;
81
- const JWKS_FETCH_TIMEOUT_MS = 5000;
82
- function requireInternal(options = {}) {
83
- const logger = options.logger ?? logger_utils_1.noopLogger;
84
- const jwksUri = options.gatewayJwksUri ??
85
- process.env["GATEWAY_JWKS_URI"] ??
86
- "http://api-gateway:3000/.well-known/jwks.json";
87
- const issuer = process.env["INTERNAL_JWT_ISSUER"] ?? "discover-cloud:api-gateway";
88
- const audience = process.env["INTERNAL_JWT_AUDIENCE"] ?? "discover-cloud:internal";
89
- // One JWKS instance per middleware — jose caches the key set internally
90
- const jwks = jose.createRemoteJWKSet(new URL(jwksUri), {
91
- cacheMaxAge: JWKS_CACHE_MAX_AGE_MS,
92
- timeoutDuration: JWKS_FETCH_TIMEOUT_MS,
93
- });
94
- const { allowedServices } = options;
95
- return async (req, res, next) => {
96
- const header = req.headers.authorization;
97
- if (!header?.startsWith("Bearer ")) {
98
- res.status(401).json({
99
- success: false,
100
- error: { code: "UNAUTHORIZED", message: "Missing Authorization header" },
101
- });
102
- return;
103
- }
104
- const token = header.slice(7);
105
- try {
106
- const { payload } = await jose.jwtVerify(token, jwks, {
107
- issuer,
108
- audience,
109
- algorithms: ["RS256"],
110
- clockTolerance: CLOCK_TOLERANCE_S,
111
- });
112
- // Token confusion defence — reject human tokens that somehow
113
- // reach an internal route (wrong header forwarded by caller)
114
- if (payload["typ"] !== "internal") {
115
- res.status(401).json({
116
- success: false,
117
- error: { code: "INVALID_TOKEN", message: "Token type must be 'internal'" },
118
- });
119
- return;
120
- }
121
- // Machine guard — reject human internal tokens on machine-only routes
122
- if (payload["isMachine"] !== true) {
123
- res.status(403).json({
124
- success: false,
125
- error: { code: "FORBIDDEN", message: "Machine token required for internal routes" },
126
- });
127
- return;
128
- }
129
- try {
130
- (0, types_1.assertMachinePayload)(payload);
131
- }
132
- catch {
133
- res.status(401).json({
134
- success: false,
135
- error: {
136
- code: "INVALID_TOKEN",
137
- message: "Invalid machine token payload",
138
- },
139
- });
140
- return;
141
- }
142
- const serviceId = payload.serviceId;
143
- // Allowlist — tightest possible scope per endpoint
144
- if (allowedServices && !allowedServices.includes(serviceId)) {
145
- logger.warn({ requestId: req.id, serviceId }, "[requireInternal] serviceId not in allowlist");
146
- res.status(403).json({
147
- success: false,
148
- error: { code: "FORBIDDEN", message: "Service not permitted to call this endpoint" },
149
- });
150
- return;
151
- }
152
- const context = { kind: "machine", serviceId };
153
- req.internalAuth = payload;
154
- req.accessContext = context;
155
- logger.debug({ requestId: req.id, serviceId, jti: payload.jti }, "[requireInternal] Machine token verified");
156
- next();
157
- }
158
- catch (err) {
159
- if (err instanceof jose.errors.JWTExpired) {
160
- res.status(401).json({
161
- success: false,
162
- error: { code: "TOKEN_EXPIRED", message: "Machine token has expired" },
163
- });
164
- return;
165
- }
166
- if (err instanceof jose.errors.JWSSignatureVerificationFailed ||
167
- err instanceof jose.errors.JWTClaimValidationFailed ||
168
- err instanceof jose.errors.JWSInvalid ||
169
- err instanceof jose.errors.JWTInvalid) {
170
- res.status(401).json({
171
- success: false,
172
- error: { code: "INVALID_TOKEN", message: "Machine token is invalid" },
173
- });
174
- return;
175
- }
176
- logger.error({ err, requestId: req.id }, "[requireInternal] Unexpected error verifying machine token");
177
- res.status(503).json({
178
- success: false,
179
- error: { code: "SERVICE_UNAVAILABLE", message: "Authentication temporarily unavailable" },
180
- });
181
- }
182
- };
183
- }
@@ -1,5 +0,0 @@
1
- import { Request, Response, NextFunction } from "express";
2
- import { ZodType } from "zod";
3
- export declare class Validator {
4
- static validate<T>(schema: ZodType<T>, source?: "body" | "params" | "query"): (req: Request, _res: Response, next: NextFunction) => void;
5
- }
@@ -1,18 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Validator = void 0;
4
- class Validator {
5
- static validate(schema, source = "body") {
6
- return (req, _res, next) => {
7
- const result = schema.safeParse(req[source]);
8
- if (!result.success) {
9
- // Pass to GlobalErrorHandler
10
- return next(result.error);
11
- }
12
- // Populate req.validated (defined in your shared .d.ts)
13
- req.validated = result.data;
14
- next();
15
- };
16
- }
17
- }
18
- exports.Validator = Validator;
@@ -1,20 +0,0 @@
1
- import { Request, Response, NextFunction } from "express";
2
- /**
3
- * VALIDATED MERGE HELPERS
4
- * ─────────────────────────
5
- * Used in routes that run two Validator.validate calls (e.g. params + body,
6
- * or params + query). Each call overwrites req.validated, so values from
7
- * the first validator must be captured before the second runs.
8
- *
9
- * Pattern:
10
- * Validator.validate(paramsSchema, "params"), // req.validated = { id }
11
- * captureValidated("id", "_capturedId"), // stashes id
12
- * Validator.validate(bodySchema, "body"), // req.validated = { role }
13
- * mergeValidated("id", "_capturedId"), // req.validated = { id, role }
14
- *
15
- * The cast through unknown is required — TypeScript won't allow a direct
16
- * cast from Request to Record<string, unknown> because they don't overlap
17
- * enough. Casting to unknown first tells TypeScript we know what we're doing.
18
- */
19
- export declare const captureValidated: (key: string, tempKey: string) => (req: Request, _res: Response, next: NextFunction) => void;
20
- export declare const mergeValidated: (key: string, tempKey: string) => (req: Request, _res: Response, next: NextFunction) => void;
@@ -1,33 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.mergeValidated = exports.captureValidated = void 0;
4
- /**
5
- * VALIDATED MERGE HELPERS
6
- * ─────────────────────────
7
- * Used in routes that run two Validator.validate calls (e.g. params + body,
8
- * or params + query). Each call overwrites req.validated, so values from
9
- * the first validator must be captured before the second runs.
10
- *
11
- * Pattern:
12
- * Validator.validate(paramsSchema, "params"), // req.validated = { id }
13
- * captureValidated("id", "_capturedId"), // stashes id
14
- * Validator.validate(bodySchema, "body"), // req.validated = { role }
15
- * mergeValidated("id", "_capturedId"), // req.validated = { id, role }
16
- *
17
- * The cast through unknown is required — TypeScript won't allow a direct
18
- * cast from Request to Record<string, unknown> because they don't overlap
19
- * enough. Casting to unknown first tells TypeScript we know what we're doing.
20
- */
21
- const captureValidated = (key, tempKey) => (req, _res, next) => {
22
- req[tempKey] = req.validated[key];
23
- next();
24
- };
25
- exports.captureValidated = captureValidated;
26
- const mergeValidated = (key, tempKey) => (req, _res, next) => {
27
- req.validated = {
28
- ...req.validated,
29
- [key]: req[tempKey],
30
- };
31
- next();
32
- };
33
- exports.mergeValidated = mergeValidated;
@@ -1,7 +0,0 @@
1
- import { Request, Response, NextFunction } from "express";
2
- import { InternalJwtService } from "../internal";
3
- export declare class VerifyInternalJwtMiddleware {
4
- private readonly internalJwt;
5
- constructor(internalJwt: InternalJwtService);
6
- handle: (req: Request, _res: Response, next: NextFunction) => Promise<void>;
7
- }
@@ -1,25 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.VerifyInternalJwtMiddleware = void 0;
4
- const errors_1 = require("../errors"); // Shared errors
5
- class VerifyInternalJwtMiddleware {
6
- constructor(internalJwt) {
7
- this.internalJwt = internalJwt;
8
- this.handle = async (req, _res, next) => {
9
- const raw = req.headers["x-internal-token"]; // Standardize header name
10
- if (!raw || typeof raw !== "string") {
11
- return next(new errors_1.UnauthorizedError("Missing internal token"));
12
- }
13
- try {
14
- const payload = await this.internalJwt.verify(raw);
15
- // Populate standardized internalAuth (from your shared .d.ts)
16
- req.internalAuth = payload;
17
- next();
18
- }
19
- catch (err) {
20
- next(new errors_1.UnauthorizedError("Invalid internal token"));
21
- }
22
- };
23
- }
24
- }
25
- exports.VerifyInternalJwtMiddleware = VerifyInternalJwtMiddleware;
@@ -1,10 +0,0 @@
1
- import { AccountRole, GlobalPermission, OrganizationRole, OrgPermission } from "../enums";
2
- import { AccessContext } from "../types";
3
- export declare const globalRolePermissions: Record<AccountRole, readonly GlobalPermission[]>;
4
- export declare const orgRolePermissions: Record<OrganizationRole, readonly OrgPermission[]>;
5
- /**
6
- * Updated isAllowed
7
- * Since memberships are no longer in the JWT, this function
8
- * primarily validates Global permissions.
9
- */
10
- export declare const isAllowed: (ctx: AccessContext, permission: GlobalPermission | OrgPermission) => boolean;
@@ -1,40 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isAllowed = exports.orgRolePermissions = exports.globalRolePermissions = void 0;
4
- const enums_1 = require("../enums");
5
- exports.globalRolePermissions = {
6
- [enums_1.AccountRole.SUPERADMIN]: Object.values(enums_1.GlobalPermission), // Superadmin gets everything
7
- [enums_1.AccountRole.ADMIN]: [
8
- enums_1.GlobalPermission.MANAGE_USERS,
9
- enums_1.GlobalPermission.SUPPORT_ACTIONS,
10
- enums_1.GlobalPermission.VIEW_SYSTEM_LOGS
11
- ],
12
- [enums_1.AccountRole.SUPPORT]: [enums_1.GlobalPermission.SUPPORT_ACTIONS],
13
- [enums_1.AccountRole.MODERATOR]: [enums_1.GlobalPermission.MODERATE_CONTENT],
14
- [enums_1.AccountRole.USER]: []
15
- };
16
- // We keep this here as a reference for local service lookups
17
- exports.orgRolePermissions = {
18
- [enums_1.OrganizationRole.OWNER]: [enums_1.OrgPermission.MANAGE_ORG, enums_1.OrgPermission.MANAGE_MEMBERS],
19
- [enums_1.OrganizationRole.ADMIN]: [enums_1.OrgPermission.MANAGE_MEMBERS],
20
- [enums_1.OrganizationRole.EDITOR]: [],
21
- [enums_1.OrganizationRole.VIEWER]: [],
22
- };
23
- const canPerformGlobalPermission = (role, permission) => {
24
- return exports.globalRolePermissions[role]?.includes(permission) ?? false;
25
- };
26
- /**
27
- * Updated isAllowed
28
- * Since memberships are no longer in the JWT, this function
29
- * primarily validates Global permissions.
30
- */
31
- const isAllowed = (ctx, permission) => {
32
- // 1. Check if it's a Global Permission (Handled via JWT role)
33
- if (Object.values(enums_1.GlobalPermission).includes(permission)) {
34
- return canPerformGlobalPermission(ctx.accountRole, permission);
35
- }
36
- // 2. Org Permissions are now handled by specific "Tenant Middleware"
37
- // within the microservices because they require a DB check.
38
- return false;
39
- };
40
- exports.isAllowed = isAllowed;
@@ -1 +0,0 @@
1
- export * from "./guard";
@@ -1,22 +0,0 @@
1
- import "express-serve-static-core";
2
- import { JWTPayload } from "jose";
3
- import { AccountRole } from "../enums";
4
- export interface AccessContext {
5
- accountId: string;
6
- accountRole: AccountRole;
7
- }
8
- export interface InternalJwtPayload extends JWTPayload {
9
- jti: string;
10
- accountId?: string;
11
- accountRole?: string;
12
- isMachine?: boolean;
13
- }
14
- declare module "express-serve-static-core" {
15
- interface Request {
16
- id: string;
17
- validated?: any;
18
- accessContext?: AccessContext;
19
- internalAuth?: InternalJwtPayload;
20
- }
21
- }
22
- export {};
@@ -1,3 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- require("express-serve-static-core");
@@ -1,25 +0,0 @@
1
- /**
2
- * DATE SERIALIZATION UTILS (@discover-cloud/shared)
3
- * ─────────────────────────────────────────────────────
4
- * Converts Date objects to ISO 8601 strings for HTTP responses.
5
- * Use these in toDto() mappers — never call .toISOString() inline.
6
- *
7
- * Why centralise this?
8
- * DTOs cross HTTP boundaries where JSON has no Date type. Domain models
9
- * keep Date objects internally; these helpers handle the conversion at
10
- * the boundary in a single consistent place. If the serialisation format
11
- * ever needs to change (e.g. add milliseconds truncation, force UTC
12
- * suffix), there is one place to update.
13
- */
14
- /**
15
- * toIso
16
- * Converts a Date to an ISO 8601 string.
17
- * Use for non-nullable timestamp fields in DTOs.
18
- */
19
- export declare const toIso: (date: Date) => string;
20
- /**
21
- * toIsoOrNull
22
- * Converts a Date to an ISO 8601 string, or returns null if the value
23
- * is absent. Use for nullable timestamp fields (e.g. revokedAt, deletedAt).
24
- */
25
- export declare const toIsoOrNull: (date: Date | null | undefined) => string | null;
@@ -1,30 +0,0 @@
1
- "use strict";
2
- /**
3
- * DATE SERIALIZATION UTILS (@discover-cloud/shared)
4
- * ─────────────────────────────────────────────────────
5
- * Converts Date objects to ISO 8601 strings for HTTP responses.
6
- * Use these in toDto() mappers — never call .toISOString() inline.
7
- *
8
- * Why centralise this?
9
- * DTOs cross HTTP boundaries where JSON has no Date type. Domain models
10
- * keep Date objects internally; these helpers handle the conversion at
11
- * the boundary in a single consistent place. If the serialisation format
12
- * ever needs to change (e.g. add milliseconds truncation, force UTC
13
- * suffix), there is one place to update.
14
- */
15
- Object.defineProperty(exports, "__esModule", { value: true });
16
- exports.toIsoOrNull = exports.toIso = void 0;
17
- /**
18
- * toIso
19
- * Converts a Date to an ISO 8601 string.
20
- * Use for non-nullable timestamp fields in DTOs.
21
- */
22
- const toIso = (date) => date.toISOString();
23
- exports.toIso = toIso;
24
- /**
25
- * toIsoOrNull
26
- * Converts a Date to an ISO 8601 string, or returns null if the value
27
- * is absent. Use for nullable timestamp fields (e.g. revokedAt, deletedAt).
28
- */
29
- const toIsoOrNull = (date) => date ? date.toISOString() : null;
30
- exports.toIsoOrNull = toIsoOrNull;