@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,4 +1,5 @@
1
- export * from "./response.utils";
2
- export * from "./logger.utils";
3
- export * from "./date.utils";
4
- export * from "./env.utils";
1
+ export * from "./response.util";
2
+ export * from "./logger.util";
3
+ export * from "./date.util";
4
+ export * from "./env.util";
5
+ export * from "./pagination.util";
@@ -14,7 +14,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./response.utils"), exports);
18
- __exportStar(require("./logger.utils"), exports);
19
- __exportStar(require("./date.utils"), exports);
20
- __exportStar(require("./env.utils"), exports);
17
+ __exportStar(require("./response.util"), exports);
18
+ __exportStar(require("./logger.util"), exports);
19
+ __exportStar(require("./date.util"), exports);
20
+ __exportStar(require("./env.util"), exports);
21
+ __exportStar(require("./pagination.util"), exports);
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @file logger.utils.ts
3
+ * @description Minimal logger contract interface and common logger implementations (console, silent no-op).
4
+ */
5
+ /**
6
+ * Standard logger interface that components can depend on to avoid coupling to
7
+ * specific third-party logging engines.
8
+ */
9
+ export interface ILogger {
10
+ debug(obj: object, msg?: string): void;
11
+ debug(msg: string): void;
12
+ info(obj: object, msg?: string): void;
13
+ info(msg: string): void;
14
+ warn(obj: object, msg?: string): void;
15
+ warn(msg: string): void;
16
+ error(obj: object, msg?: string): void;
17
+ error(msg: string): void;
18
+ }
19
+ /**
20
+ * Silent no-op implementation discarded all log payloads.
21
+ */
22
+ export declare const noopLogger: ILogger;
23
+ /**
24
+ * Console logger implementing the ILogger interface mapping to native console output.
25
+ */
26
+ export declare const consoleLogger: ILogger;
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ /**
3
+ * @file logger.utils.ts
4
+ * @description Minimal logger contract interface and common logger implementations (console, silent no-op).
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.consoleLogger = exports.noopLogger = void 0;
8
+ /**
9
+ * Silent no-op implementation discarded all log payloads.
10
+ */
11
+ exports.noopLogger = {
12
+ debug: () => { },
13
+ info: () => { },
14
+ warn: () => { },
15
+ error: () => { },
16
+ };
17
+ /**
18
+ * Console logger implementing the ILogger interface mapping to native console output.
19
+ */
20
+ exports.consoleLogger = {
21
+ debug: (objOrMsg, msg) => {
22
+ if (typeof objOrMsg === "string") {
23
+ console.debug(objOrMsg);
24
+ }
25
+ else {
26
+ console.debug(msg ?? "", objOrMsg);
27
+ }
28
+ },
29
+ info: (objOrMsg, msg) => {
30
+ if (typeof objOrMsg === "string") {
31
+ console.info(objOrMsg);
32
+ }
33
+ else {
34
+ console.info(msg ?? "", objOrMsg);
35
+ }
36
+ },
37
+ warn: (objOrMsg, msg) => {
38
+ if (typeof objOrMsg === "string") {
39
+ console.warn(objOrMsg);
40
+ }
41
+ else {
42
+ console.warn(msg ?? "", objOrMsg);
43
+ }
44
+ },
45
+ error: (objOrMsg, msg) => {
46
+ if (typeof objOrMsg === "string") {
47
+ console.error(objOrMsg);
48
+ }
49
+ else {
50
+ console.error(msg ?? "", objOrMsg);
51
+ }
52
+ },
53
+ };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @file pagination.utils.ts
3
+ * @description Helper functions to calculate pagination metadata from repository outputs.
4
+ */
5
+ import { PaginationMeta } from '../dtos';
6
+ export declare function buildPaginationMeta(totalItems: number, limit: number, offset: number): PaginationMeta;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ /**
3
+ * @file pagination.utils.ts
4
+ * @description Helper functions to calculate pagination metadata from repository outputs.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.buildPaginationMeta = buildPaginationMeta;
8
+ function buildPaginationMeta(totalItems, limit, offset) {
9
+ const pageSize = limit > 0 ? limit : 1;
10
+ const totalPages = Math.ceil(totalItems / pageSize);
11
+ const currentPage = Math.floor(offset / pageSize) + 1;
12
+ return {
13
+ page: currentPage,
14
+ pageSize,
15
+ totalItems,
16
+ totalPages,
17
+ hasNext: currentPage < totalPages,
18
+ hasPrev: currentPage > 1,
19
+ };
20
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * @file response.utils.ts
3
+ * @description Helper functions to construct and send standardized API success and error response envelopes.
4
+ */
5
+ import { Response, Request } from "express";
6
+ /**
7
+ * Sends a successful standardized API response containing the data payload.
8
+ *
9
+ * @param {Response} res - Express response object.
10
+ * @param {Request} req - Express request object.
11
+ * @param {T} data - The payload data.
12
+ * @param {number} [statusCode=200] - HTTP status code.
13
+ * @returns {void}
14
+ */
15
+ export declare const success: <T>(res: Response, req: Request, data: T, statusCode?: number) => void;
16
+ /**
17
+ * Sends a failed standardized API response containing error details.
18
+ *
19
+ * @param {Response} res - Express response object.
20
+ * @param {Request} req - Express request object.
21
+ * @param {string} message - Human-readable error message.
22
+ * @param {string} code - Error code mapping.
23
+ * @param {number} [statusCode=400] - HTTP status code.
24
+ * @param {unknown} [details] - Optional error metadata details.
25
+ * @returns {void}
26
+ */
27
+ export declare const failure: (res: Response, req: Request, message: string, code: string, statusCode?: number, details?: unknown) => void;
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ /**
3
+ * @file response.utils.ts
4
+ * @description Helper functions to construct and send standardized API success and error response envelopes.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.failure = exports.success = void 0;
8
+ const crypto_1 = require("crypto");
9
+ /**
10
+ * Sends a successful standardized API response containing the data payload.
11
+ *
12
+ * @param {Response} res - Express response object.
13
+ * @param {Request} req - Express request object.
14
+ * @param {T} data - The payload data.
15
+ * @param {number} [statusCode=200] - HTTP status code.
16
+ * @returns {void}
17
+ */
18
+ const success = (res, req, data, statusCode = 200) => {
19
+ const response = {
20
+ success: true,
21
+ data,
22
+ meta: {
23
+ requestId: req.id ?? (0, crypto_1.randomUUID)(),
24
+ timestamp: new Date().toISOString(),
25
+ },
26
+ };
27
+ res.status(statusCode).json(response);
28
+ };
29
+ exports.success = success;
30
+ /**
31
+ * Sends a failed standardized API response containing error details.
32
+ *
33
+ * @param {Response} res - Express response object.
34
+ * @param {Request} req - Express request object.
35
+ * @param {string} message - Human-readable error message.
36
+ * @param {string} code - Error code mapping.
37
+ * @param {number} [statusCode=400] - HTTP status code.
38
+ * @param {unknown} [details] - Optional error metadata details.
39
+ * @returns {void}
40
+ */
41
+ const failure = (res, req, message, code, statusCode = 400, details) => {
42
+ const response = {
43
+ success: false,
44
+ error: {
45
+ code,
46
+ message,
47
+ ...(details !== undefined ? { details } : {}),
48
+ },
49
+ meta: {
50
+ requestId: req.id ?? (0, crypto_1.randomUUID)(),
51
+ timestamp: new Date().toISOString(),
52
+ },
53
+ };
54
+ res.status(statusCode).json(response);
55
+ };
56
+ exports.failure = failure;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @file slug.utils.ts
3
+ * @description Slug normalization and soft-delete suffixing helpers.
4
+ */
5
+ export declare function normalizeSlug(input: string): string;
6
+ export declare function isValidSlug(slug: string): boolean;
7
+ export declare function appendDeletedSuffix(slug: string, timestamp?: number): string;
8
+ export declare function stripDeletedSuffix(slug: string): string;
9
+ export declare function appendDisambiguationSuffix(slug: string, timestamp?: number): string;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ /**
3
+ * @file slug.utils.ts
4
+ * @description Slug normalization and soft-delete suffixing helpers.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.normalizeSlug = normalizeSlug;
8
+ exports.isValidSlug = isValidSlug;
9
+ exports.appendDeletedSuffix = appendDeletedSuffix;
10
+ exports.stripDeletedSuffix = stripDeletedSuffix;
11
+ exports.appendDisambiguationSuffix = appendDisambiguationSuffix;
12
+ const DELETED_SUFFIX_MARKER = '__deleted_';
13
+ function normalizeSlug(input) {
14
+ return input
15
+ .trim()
16
+ .toLowerCase()
17
+ .replace(/[^a-z0-9]+/g, '-')
18
+ .replace(/-+/g, '-')
19
+ .replace(/^-|-$/g, '');
20
+ }
21
+ function isValidSlug(slug) {
22
+ return /^[a-z0-9]+(-[a-z0-9]+)*$/.test(slug);
23
+ }
24
+ function appendDeletedSuffix(slug, timestamp = Date.now()) {
25
+ return `${stripDeletedSuffix(slug)}${DELETED_SUFFIX_MARKER}${timestamp}`;
26
+ }
27
+ function stripDeletedSuffix(slug) {
28
+ return slug.split(DELETED_SUFFIX_MARKER)[0];
29
+ }
30
+ function appendDisambiguationSuffix(slug, timestamp = Date.now()) {
31
+ return `${slug}-${timestamp}`;
32
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @file url-safety.utils.ts
3
+ * @description Validation helpers to mitigate SSRF risk for user-supplied destination URLs.
4
+ */
5
+ export declare function isPrivateOrBlockedHost(hostname: string): boolean;
6
+ export declare function isSafeWebhookUrl(value: string): boolean;
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ /**
3
+ * @file url-safety.utils.ts
4
+ * @description Validation helpers to mitigate SSRF risk for user-supplied destination URLs.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.isPrivateOrBlockedHost = isPrivateOrBlockedHost;
8
+ exports.isSafeWebhookUrl = isSafeWebhookUrl;
9
+ const BLOCKED_HOSTNAMES = new Set(['localhost', '0.0.0.0', '::1', '::']);
10
+ const BLOCKED_EXACT_IPS = new Set([
11
+ '169.254.169.254', // AWS, GCP, Azure IMDS
12
+ '169.254.170.2', // AWS ECS task metadata
13
+ 'fd00:ec2::254', // AWS IMDSv6
14
+ ]);
15
+ const PRIVATE_IPV4_RANGES = [
16
+ { test: (p) => p[0] === 10 },
17
+ { test: (p) => p[0] === 127 },
18
+ { test: (p) => p[0] === 172 && p[1] >= 16 && p[1] <= 31 },
19
+ { test: (p) => p[0] === 192 && p[1] === 168 },
20
+ { test: (p) => p[0] === 169 && p[1] === 254 },
21
+ { test: (p) => p[0] === 0 },
22
+ { test: (p) => p[0] >= 224 },
23
+ ];
24
+ const ALLOWED_PROTOCOLS = new Set(['http:', 'https:']);
25
+ function parseIpv4(hostname) {
26
+ const match = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(hostname);
27
+ if (!match)
28
+ return null;
29
+ const parts = match.slice(1, 5).map(Number);
30
+ if (parts.some((p) => p > 255))
31
+ return null;
32
+ return parts;
33
+ }
34
+ function isPrivateOrBlockedHost(hostname) {
35
+ const normalized = hostname.toLowerCase().replace(/^\[|\]$/g, '');
36
+ if (BLOCKED_HOSTNAMES.has(normalized))
37
+ return true;
38
+ if (BLOCKED_EXACT_IPS.has(normalized))
39
+ return true;
40
+ if (normalized.endsWith('.local') || normalized.endsWith('.internal'))
41
+ return true;
42
+ if (normalized.startsWith('::ffff:')) {
43
+ const unwrappedIpv4 = normalized.substring(7);
44
+ return isPrivateOrBlockedHost(unwrappedIpv4);
45
+ }
46
+ const ipv4 = parseIpv4(normalized);
47
+ if (ipv4) {
48
+ return PRIVATE_IPV4_RANGES.some(({ test }) => test(ipv4));
49
+ }
50
+ if (normalized === '::1' || normalized.startsWith('fc') || normalized.startsWith('fd') || normalized.startsWith('fe80')) {
51
+ return true;
52
+ }
53
+ return false;
54
+ }
55
+ function isSafeWebhookUrl(value) {
56
+ let url;
57
+ try {
58
+ url = new URL(value);
59
+ }
60
+ catch {
61
+ return false;
62
+ }
63
+ if (!ALLOWED_PROTOCOLS.has(url.protocol))
64
+ return false;
65
+ if (!url.hostname)
66
+ return false;
67
+ if (isPrivateOrBlockedHost(url.hostname))
68
+ return false;
69
+ if (url.username || url.password)
70
+ return false;
71
+ return true;
72
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@discover-cloud/shared",
3
- "version": "1.2.8",
3
+ "version": "1.3.0",
4
4
  "private": false,
5
5
  "type": "commonjs",
6
6
  "main": "dist/index.js",
@@ -16,6 +16,7 @@
16
16
  "access": "public"
17
17
  },
18
18
  "dependencies": {
19
+ "amqplib": "^2.0.1",
19
20
  "axios-retry": "^4.5.0",
20
21
  "jose": "^6.1.3",
21
22
  "redis": "^5.11.0"
@@ -26,6 +27,7 @@
26
27
  "zod": "^4.3.6"
27
28
  },
28
29
  "devDependencies": {
30
+ "@types/amqplib": "^0.10.8",
29
31
  "@types/express": "^5.0.6",
30
32
  "@types/node": "^25.3.0",
31
33
  "axios": "^1.13.5",
@@ -1,78 +0,0 @@
1
- import { AccountRole, GlobalPermission, OrganizationRole, OrgPermission } from "../enums";
2
- import { AccessContext } from "../types";
3
- /**
4
- * GLOBAL ROLE PERMISSION MAP
5
- * ───────────────────────────
6
- * Defines which GlobalPermissions each AccountRole carries.
7
- * This is the single source of truth — the Redis permission cache
8
- * derives from this map on a cold cache miss.
9
- *
10
- * Design principles:
11
- * - SUPERADMIN gets all permissions (dynamically via Object.values, not a
12
- * hardcoded list — so new permissions are automatically granted on addition)
13
- * - Each role has only the minimum permissions it needs (least privilege)
14
- * - Permissions are additive — no role inherits from another at runtime
15
- * - Adding a new permission: add to GlobalPermission enum, then grant it here
16
- *
17
- * ┌─────────────┬──────────────────────────────────────────────────────┐
18
- * │ Role │ Key permissions │
19
- * ├─────────────┼──────────────────────────────────────────────────────┤
20
- * │ SUPERADMIN │ Everything — full platform control │
21
- * │ ADMIN │ User mgmt, cost data access, logs, health, support │
22
- * │ SUPPORT │ Read-only user + cost data for support work │
23
- * │ MODERATOR │ Content moderation only (future) │
24
- * │ USER │ No global permissions — service layer gates own data │
25
- * └─────────────┴──────────────────────────────────────────────────────┘
26
- */
27
- export declare const globalRolePermissions: Record<AccountRole, readonly GlobalPermission[]>;
28
- /**
29
- * ORG ROLE PERMISSION MAP (future work)
30
- * ────────────────────────────────────────
31
- * Org permissions are NOT embedded in the JWT — they're fetched from the DB
32
- * by tenant middleware within each service because:
33
- * 1. Org membership changes frequently (invites, role changes, removal)
34
- * 2. A user can be in multiple orgs with different roles
35
- * 3. Embedding them in the JWT would create stale permission windows
36
- *
37
- * This map is used by tenant middleware for the DB-free fast path:
38
- * if the org role is already known (e.g. from a prior DB fetch cached in
39
- * Redis), derive permissions here rather than re-querying the DB.
40
- *
41
- * NOTE: All entries use OrgPermission values only — no cross-namespace mixing
42
- * with GlobalPermission. Org admin membership management is expressed via
43
- * the dedicated OrgPermission.* values below.
44
- */
45
- export declare const orgRolePermissions: Record<OrganizationRole, readonly OrgPermission[]>;
46
- /**
47
- * hasGlobalPermission
48
- * Checks if a GlobalPermission is present in the AccessContext's perms array.
49
- * Perms are populated from the Redis permission cache (derived from the role
50
- * map on a miss) — never read directly from the JWT.
51
- *
52
- * Machine contexts always return false — they carry no user permissions.
53
- */
54
- export declare const hasGlobalPermission: (ctx: AccessContext, permission: GlobalPermission) => boolean;
55
- /**
56
- * isAllowed
57
- * Unified permission check for both GlobalPermission and OrgPermission.
58
- *
59
- * GlobalPermission → checked against ctx.perms (Redis cache, derived from role)
60
- * OrgPermission → intentionally returns false here; handled by tenant
61
- * middleware in each service via DB lookup. This function
62
- * is not the place for org permission checks — the boundary
63
- * is explicit by design.
64
- */
65
- export declare const isAllowed: (ctx: AccessContext, permission: GlobalPermission | OrgPermission) => boolean;
66
- /**
67
- * isSuperAdmin
68
- * Convenience guard for cases where superadmin-only logic is needed
69
- * beyond a single permission check (e.g. bypassing org scoping entirely).
70
- */
71
- export declare const isSuperAdmin: (ctx: AccessContext) => boolean;
72
- /**
73
- * deriveGlobalPermissions
74
- * Derives permissions for a role from the static map.
75
- * Called by PermissionCacheService on a cold cache miss.
76
- * Returns a mutable copy — callers can extend it if needed.
77
- */
78
- export declare const deriveGlobalPermissions: (role: AccountRole) => GlobalPermission[];
@@ -1,174 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.deriveGlobalPermissions = exports.isSuperAdmin = exports.isAllowed = exports.hasGlobalPermission = exports.orgRolePermissions = exports.globalRolePermissions = void 0;
4
- const enums_1 = require("../enums");
5
- /**
6
- * GLOBAL ROLE PERMISSION MAP
7
- * ───────────────────────────
8
- * Defines which GlobalPermissions each AccountRole carries.
9
- * This is the single source of truth — the Redis permission cache
10
- * derives from this map on a cold cache miss.
11
- *
12
- * Design principles:
13
- * - SUPERADMIN gets all permissions (dynamically via Object.values, not a
14
- * hardcoded list — so new permissions are automatically granted on addition)
15
- * - Each role has only the minimum permissions it needs (least privilege)
16
- * - Permissions are additive — no role inherits from another at runtime
17
- * - Adding a new permission: add to GlobalPermission enum, then grant it here
18
- *
19
- * ┌─────────────┬──────────────────────────────────────────────────────┐
20
- * │ Role │ Key permissions │
21
- * ├─────────────┼──────────────────────────────────────────────────────┤
22
- * │ SUPERADMIN │ Everything — full platform control │
23
- * │ ADMIN │ User mgmt, cost data access, logs, health, support │
24
- * │ SUPPORT │ Read-only user + cost data for support work │
25
- * │ MODERATOR │ Content moderation only (future) │
26
- * │ USER │ No global permissions — service layer gates own data │
27
- * └─────────────┴──────────────────────────────────────────────────────┘
28
- */
29
- exports.globalRolePermissions = {
30
- [enums_1.AccountRole.SUPERADMIN]: Object.values(enums_1.GlobalPermission),
31
- [enums_1.AccountRole.ADMIN]: [
32
- // Account management (no impersonate, no hard delete)
33
- enums_1.GlobalPermission.MANAGE_ACCOUNTS,
34
- enums_1.GlobalPermission.VIEW_ANY_ACCOUNT,
35
- enums_1.GlobalPermission.SUSPEND_ACCOUNT,
36
- // Cloud cost data
37
- enums_1.GlobalPermission.VIEW_ANY_COST_DATA,
38
- enums_1.GlobalPermission.EXPORT_ANY_COST_DATA,
39
- enums_1.GlobalPermission.MANAGE_COST_ALERTS,
40
- // Platform operations
41
- enums_1.GlobalPermission.VIEW_SYSTEM_LOGS,
42
- enums_1.GlobalPermission.VIEW_SYSTEM_HEALTH,
43
- // Support tooling
44
- enums_1.GlobalPermission.SUPPORT_VIEW,
45
- enums_1.GlobalPermission.SUPPORT_WRITE,
46
- ],
47
- [enums_1.AccountRole.SUPPORT]: [
48
- // Read-only access to user data and cost data for support purposes.
49
- // Cannot write, cannot manage accounts, cannot access system internals.
50
- enums_1.GlobalPermission.VIEW_ANY_ACCOUNT,
51
- enums_1.GlobalPermission.VIEW_ANY_COST_DATA,
52
- enums_1.GlobalPermission.SUPPORT_VIEW,
53
- ],
54
- [enums_1.AccountRole.MODERATOR]: [
55
- // Content moderation only — no access to user accounts or cost data.
56
- enums_1.GlobalPermission.MODERATE_CONTENT,
57
- ],
58
- // Standard users carry zero global permissions.
59
- // All their data access is gated at the service layer
60
- // (they can only see their own cost data, their own account, etc.)
61
- [enums_1.AccountRole.USER]: [],
62
- };
63
- /**
64
- * ORG ROLE PERMISSION MAP (future work)
65
- * ────────────────────────────────────────
66
- * Org permissions are NOT embedded in the JWT — they're fetched from the DB
67
- * by tenant middleware within each service because:
68
- * 1. Org membership changes frequently (invites, role changes, removal)
69
- * 2. A user can be in multiple orgs with different roles
70
- * 3. Embedding them in the JWT would create stale permission windows
71
- *
72
- * This map is used by tenant middleware for the DB-free fast path:
73
- * if the org role is already known (e.g. from a prior DB fetch cached in
74
- * Redis), derive permissions here rather than re-querying the DB.
75
- *
76
- * NOTE: All entries use OrgPermission values only — no cross-namespace mixing
77
- * with GlobalPermission. Org admin membership management is expressed via
78
- * the dedicated OrgPermission.* values below.
79
- */
80
- exports.orgRolePermissions = {
81
- [enums_1.OrganizationRole.OWNER]: Object.values(enums_1.OrgPermission), // Full org control
82
- [enums_1.OrganizationRole.ADMIN]: [
83
- enums_1.OrgPermission.MANAGE_ORG_SETTINGS,
84
- enums_1.OrgPermission.INVITE_MEMBERS,
85
- enums_1.OrgPermission.REMOVE_MEMBERS,
86
- enums_1.OrgPermission.CHANGE_MEMBER_ROLES,
87
- enums_1.OrgPermission.VIEW_MEMBERS,
88
- enums_1.OrgPermission.VIEW_COST_DATA,
89
- enums_1.OrgPermission.EXPORT_COST_DATA,
90
- enums_1.OrgPermission.MANAGE_COST_REPORTS,
91
- enums_1.OrgPermission.MANAGE_ALERTS,
92
- enums_1.OrgPermission.MANAGE_CLOUD_ACCOUNTS,
93
- enums_1.OrgPermission.VIEW_CLOUD_ACCOUNTS,
94
- enums_1.OrgPermission.VIEW_BILLING,
95
- ],
96
- [enums_1.OrganizationRole.EDITOR]: [
97
- enums_1.OrgPermission.VIEW_MEMBERS,
98
- enums_1.OrgPermission.VIEW_COST_DATA,
99
- enums_1.OrgPermission.EXPORT_COST_DATA,
100
- enums_1.OrgPermission.MANAGE_COST_REPORTS,
101
- enums_1.OrgPermission.MANAGE_ALERTS,
102
- enums_1.OrgPermission.VIEW_CLOUD_ACCOUNTS,
103
- ],
104
- [enums_1.OrganizationRole.VIEWER]: [
105
- enums_1.OrgPermission.VIEW_MEMBERS,
106
- enums_1.OrgPermission.VIEW_COST_DATA,
107
- enums_1.OrgPermission.VIEW_CLOUD_ACCOUNTS,
108
- ],
109
- [enums_1.OrganizationRole.BILLING]: [
110
- enums_1.OrgPermission.VIEW_BILLING,
111
- enums_1.OrgPermission.MANAGE_BILLING,
112
- enums_1.OrgPermission.VIEW_COST_DATA,
113
- enums_1.OrgPermission.EXPORT_COST_DATA,
114
- ],
115
- };
116
- /* ====================================================================
117
- PERMISSION CHECK HELPERS
118
- ==================================================================== */
119
- /**
120
- * hasGlobalPermission
121
- * Checks if a GlobalPermission is present in the AccessContext's perms array.
122
- * Perms are populated from the Redis permission cache (derived from the role
123
- * map on a miss) — never read directly from the JWT.
124
- *
125
- * Machine contexts always return false — they carry no user permissions.
126
- */
127
- const hasGlobalPermission = (ctx, permission) => {
128
- if (ctx.kind !== "human")
129
- return false;
130
- return ctx.perms.includes(permission);
131
- };
132
- exports.hasGlobalPermission = hasGlobalPermission;
133
- /**
134
- * isAllowed
135
- * Unified permission check for both GlobalPermission and OrgPermission.
136
- *
137
- * GlobalPermission → checked against ctx.perms (Redis cache, derived from role)
138
- * OrgPermission → intentionally returns false here; handled by tenant
139
- * middleware in each service via DB lookup. This function
140
- * is not the place for org permission checks — the boundary
141
- * is explicit by design.
142
- */
143
- const isAllowed = (ctx, permission) => {
144
- if (ctx.kind !== "human")
145
- return false;
146
- if (Object.values(enums_1.GlobalPermission).includes(permission)) {
147
- return (0, exports.hasGlobalPermission)(ctx, permission);
148
- }
149
- // OrgPermission — not handled here by design.
150
- // Use tenant middleware (DB-backed) within the relevant service.
151
- return false;
152
- };
153
- exports.isAllowed = isAllowed;
154
- /**
155
- * isSuperAdmin
156
- * Convenience guard for cases where superadmin-only logic is needed
157
- * beyond a single permission check (e.g. bypassing org scoping entirely).
158
- */
159
- const isSuperAdmin = (ctx) => {
160
- if (ctx.kind !== "human")
161
- return false;
162
- return ctx.accountRole === enums_1.AccountRole.SUPERADMIN;
163
- };
164
- exports.isSuperAdmin = isSuperAdmin;
165
- /**
166
- * deriveGlobalPermissions
167
- * Derives permissions for a role from the static map.
168
- * Called by PermissionCacheService on a cold cache miss.
169
- * Returns a mutable copy — callers can extend it if needed.
170
- */
171
- const deriveGlobalPermissions = (role) => {
172
- return [...(exports.globalRolePermissions[role] ?? [])];
173
- };
174
- exports.deriveGlobalPermissions = deriveGlobalPermissions;
@@ -1,10 +0,0 @@
1
- import { AccountRole, OrganizationRole, MembershipStatus } from "../enums";
2
- export interface AccessContext {
3
- accountId: string;
4
- accountRole: AccountRole;
5
- membership?: {
6
- organizationId: string;
7
- role: OrganizationRole;
8
- status: MembershipStatus;
9
- };
10
- }
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
@@ -1 +0,0 @@
1
- export * from "./access-context.js";
@@ -1,17 +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 __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./access-context.js"), exports);