@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
@@ -1,34 +1,28 @@
1
1
  "use strict";
2
+ /**
3
+ * @file app-error.ts
4
+ * @description Base class for operational errors throughout the application ecosystem.
5
+ * Structured to support clean serialization in global error boundaries.
6
+ */
2
7
  Object.defineProperty(exports, "__esModule", { value: true });
3
8
  exports.AppError = void 0;
4
9
  /**
5
- * APP ERROR (@discover-cloud/shared)
6
- * ─────────────────────────────────────
7
- * Base class for all known operational errors across every service.
8
- * Subclasses (see http-errors.ts) map to specific HTTP status codes and
9
- * error codes that the global error handler serialises into responses.
10
- *
11
- * Design decisions:
12
- * - GlobalErrorHandler catches `instanceof AppError` — no duck-typing,
13
- * no accidental matches on arbitrary thrown objects.
14
- * - details?: unknown (not any) — TypeScript's type checking is preserved
15
- * on the most variable field. Callers that need a specific details shape
16
- * should cast after an instanceof guard.
17
- * - Object.freeze(this) — prevents accidental post-construction mutation of
18
- * a thrown error. Freeze is shallow: if details is an object, its contents
19
- * remain mutable. This is acceptable — details is for logging/response
20
- * context, not program logic.
21
- * - captureStackTrace — strips the AppError constructor frame from the stack
22
- * so the trace points to the throw site, not the base class constructor.
10
+ * Base operational error class. Extends standard Error with application-specific
11
+ * machine codes and HTTP status mapping.
23
12
  */
24
13
  class AppError extends Error {
14
+ /**
15
+ * @param {string} code - Machine-readable stable error code identifier.
16
+ * @param {number} statusCode - Target HTTP status code mapping (e.g. 404, 409).
17
+ * @param {string} message - Human-readable error message.
18
+ * @param {unknown} [details] - Optional structured context context data.
19
+ */
25
20
  constructor(code, statusCode, message, details) {
26
21
  super(message);
27
22
  this.code = code;
28
23
  this.statusCode = statusCode;
29
24
  this.details = details;
30
- this.name = this.constructor.name; // "NotFoundError", "ConflictError", etc.
31
- // Available in V8 (Node.js / Chrome) — no-ops gracefully in other engines.
25
+ this.name = this.constructor.name;
32
26
  if (typeof Error.captureStackTrace === "function") {
33
27
  Error.captureStackTrace(this, this.constructor);
34
28
  }
@@ -1,47 +1,135 @@
1
+ /**
2
+ * @file http-errors.ts
3
+ * @description Operational error subclasses mapping common HTTP status codes to AppError types.
4
+ */
1
5
  import { AppError } from "./app-error";
2
6
  /**
3
- * HTTP ERRORS (@discover-cloud/shared)
4
- * ───────────────────────────────────────
5
- * Typed subclasses of AppError for every common HTTP error status.
6
- *
7
- * GlobalErrorHandler catches these via `instanceof AppError` and maps
8
- * statusCode + code directly to the response — no additional switch/if needed.
9
- *
10
- * Usage:
11
- * throw new NotFoundError("Account not found");
12
- * throw new ConflictError("Email already in use");
13
- * throw new BadRequestError("Validation failed", { field: "email" });
14
- *
15
- * Adding a new error type:
16
- * 1. Add a subclass here following the existing pattern.
17
- * 2. Pick the correct HTTP status code.
18
- * 3. Choose a SCREAMING_SNAKE_CASE code that is stable across versions
19
- * (clients may key on it for error handling).
7
+ * 400 Bad Request error.
20
8
  */
21
9
  export declare class BadRequestError extends AppError {
10
+ /**
11
+ * @param {string} [message] - Error explanation message.
12
+ * @param {unknown} [details] - Detailed error context.
13
+ */
22
14
  constructor(message?: string, details?: unknown);
23
15
  }
16
+ /**
17
+ * 401 Unauthorized error.
18
+ */
24
19
  export declare class UnauthorizedError extends AppError {
20
+ /**
21
+ * @param {string} [message] - Error explanation message.
22
+ * @param {unknown} [details] - Detailed error context.
23
+ */
25
24
  constructor(message?: string, details?: unknown);
26
25
  }
26
+ /**
27
+ * 403 Forbidden error.
28
+ */
27
29
  export declare class ForbiddenError extends AppError {
30
+ /**
31
+ * @param {string} [message] - Error explanation message.
32
+ * @param {unknown} [details] - Detailed error context.
33
+ */
28
34
  constructor(message?: string, details?: unknown);
29
35
  }
36
+ /**
37
+ * 404 Not Found error.
38
+ */
30
39
  export declare class NotFoundError extends AppError {
40
+ /**
41
+ * @param {string} [message] - Error explanation message.
42
+ * @param {unknown} [details] - Detailed error context.
43
+ */
44
+ constructor(message?: string, details?: unknown);
45
+ }
46
+ /**
47
+ * 410 Gone error.
48
+ */
49
+ export declare class GoneError extends AppError {
50
+ /**
51
+ * @param {string} [message] - Error explanation message.
52
+ * @param {unknown} [details] - Detailed error context.
53
+ */
31
54
  constructor(message?: string, details?: unknown);
32
55
  }
56
+ /**
57
+ * 409 Conflict error.
58
+ */
33
59
  export declare class ConflictError extends AppError {
60
+ /**
61
+ * @param {string} [message] - Error explanation message.
62
+ * @param {unknown} [details] - Detailed error context.
63
+ */
34
64
  constructor(message?: string, details?: unknown);
35
65
  }
66
+ /**
67
+ * 422 Unprocessable Entity error.
68
+ */
36
69
  export declare class UnprocessableEntityError extends AppError {
70
+ /**
71
+ * @param {string} [message] - Error explanation message.
72
+ * @param {unknown} [details] - Detailed error context.
73
+ */
37
74
  constructor(message?: string, details?: unknown);
38
75
  }
76
+ /**
77
+ * 429 Too Many Requests error.
78
+ */
39
79
  export declare class TooManyRequestsError extends AppError {
80
+ /**
81
+ * @param {string} [message] - Error explanation message.
82
+ * @param {unknown} [details] - Detailed error context.
83
+ */
40
84
  constructor(message?: string, details?: unknown);
41
85
  }
86
+ /**
87
+ * 500 Internal Server Error.
88
+ */
42
89
  export declare class InternalServerError extends AppError {
90
+ /**
91
+ * @param {string} [message] - Error explanation message.
92
+ * @param {unknown} [details] - Detailed error context.
93
+ */
43
94
  constructor(message?: string, details?: unknown);
44
95
  }
96
+ /**
97
+ * 503 Service Unavailable error.
98
+ */
45
99
  export declare class ServiceUnavailableError extends AppError {
100
+ /**
101
+ * @param {string} [message] - Error explanation message.
102
+ * @param {unknown} [details] - Detailed error context.
103
+ */
104
+ constructor(message?: string, details?: unknown);
105
+ }
106
+ /**
107
+ * 403 Account Pending Deletion error.
108
+ *
109
+ * Thrown when a soft-deleted user account is accessed in a context that does
110
+ * not allow implicit restore (e.g. login). The client should present a recovery
111
+ * prompt rather than treating this as a generic auth failure.
112
+ */
113
+ export declare class AccountPendingDeletionError extends AppError {
114
+ constructor(message?: string, details?: unknown);
115
+ }
116
+ /**
117
+ * 403 Organization Pending Deletion error.
118
+ *
119
+ * Thrown when a soft-deleted organization is accessed in a context that does
120
+ * not allow implicit restore (e.g. slug conflict on create). The client should
121
+ * prompt the user to restore the organization instead.
122
+ */
123
+ export declare class OrganizationPendingDeletionError extends AppError {
124
+ constructor(message?: string, details?: unknown);
125
+ }
126
+ /**
127
+ * 403 Workspace Pending Deletion error.
128
+ *
129
+ * Thrown when a soft-deleted workspace is accessed in a context that does
130
+ * not allow implicit restore (e.g. slug conflict on create). The client should
131
+ * prompt the user to restore the workspace instead.
132
+ */
133
+ export declare class WorkspacePendingDeletionError extends AppError {
46
134
  constructor(message?: string, details?: unknown);
47
135
  }
@@ -1,92 +1,177 @@
1
1
  "use strict";
2
+ /**
3
+ * @file http-errors.ts
4
+ * @description Operational error subclasses mapping common HTTP status codes to AppError types.
5
+ */
2
6
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ServiceUnavailableError = exports.InternalServerError = exports.TooManyRequestsError = exports.UnprocessableEntityError = exports.ConflictError = exports.NotFoundError = exports.ForbiddenError = exports.UnauthorizedError = exports.BadRequestError = void 0;
7
+ exports.WorkspacePendingDeletionError = exports.OrganizationPendingDeletionError = exports.AccountPendingDeletionError = exports.ServiceUnavailableError = exports.InternalServerError = exports.TooManyRequestsError = exports.UnprocessableEntityError = exports.ConflictError = exports.GoneError = exports.NotFoundError = exports.ForbiddenError = exports.UnauthorizedError = exports.BadRequestError = void 0;
4
8
  const app_error_1 = require("./app-error");
5
9
  /**
6
- * HTTP ERRORS (@discover-cloud/shared)
7
- * ───────────────────────────────────────
8
- * Typed subclasses of AppError for every common HTTP error status.
9
- *
10
- * GlobalErrorHandler catches these via `instanceof AppError` and maps
11
- * statusCode + code directly to the response — no additional switch/if needed.
12
- *
13
- * Usage:
14
- * throw new NotFoundError("Account not found");
15
- * throw new ConflictError("Email already in use");
16
- * throw new BadRequestError("Validation failed", { field: "email" });
17
- *
18
- * Adding a new error type:
19
- * 1. Add a subclass here following the existing pattern.
20
- * 2. Pick the correct HTTP status code.
21
- * 3. Choose a SCREAMING_SNAKE_CASE code that is stable across versions
22
- * (clients may key on it for error handling).
10
+ * 400 Bad Request error.
23
11
  */
24
- // 400 — The request is malformed or contains invalid input.
25
12
  class BadRequestError extends app_error_1.AppError {
13
+ /**
14
+ * @param {string} [message] - Error explanation message.
15
+ * @param {unknown} [details] - Detailed error context.
16
+ */
26
17
  constructor(message = "Bad Request", details) {
27
18
  super("BAD_REQUEST", 400, message, details);
28
19
  }
29
20
  }
30
21
  exports.BadRequestError = BadRequestError;
31
- // 401 — No valid credentials were supplied (missing or expired token).
32
- // Distinct from 403: the client may retry after authenticating.
22
+ /**
23
+ * 401 Unauthorized error.
24
+ */
33
25
  class UnauthorizedError extends app_error_1.AppError {
26
+ /**
27
+ * @param {string} [message] - Error explanation message.
28
+ * @param {unknown} [details] - Detailed error context.
29
+ */
34
30
  constructor(message = "Unauthorized", details) {
35
31
  super("UNAUTHORIZED", 401, message, details);
36
32
  }
37
33
  }
38
34
  exports.UnauthorizedError = UnauthorizedError;
39
- // 403 — Valid credentials were supplied but the caller lacks permission.
40
- // Retrying with the same credentials will not help.
35
+ /**
36
+ * 403 Forbidden error.
37
+ */
41
38
  class ForbiddenError extends app_error_1.AppError {
39
+ /**
40
+ * @param {string} [message] - Error explanation message.
41
+ * @param {unknown} [details] - Detailed error context.
42
+ */
42
43
  constructor(message = "Forbidden", details) {
43
44
  super("FORBIDDEN", 403, message, details);
44
45
  }
45
46
  }
46
47
  exports.ForbiddenError = ForbiddenError;
47
- // 404 — The requested resource does not exist.
48
+ /**
49
+ * 404 Not Found error.
50
+ */
48
51
  class NotFoundError extends app_error_1.AppError {
52
+ /**
53
+ * @param {string} [message] - Error explanation message.
54
+ * @param {unknown} [details] - Detailed error context.
55
+ */
49
56
  constructor(message = "Not Found", details) {
50
57
  super("NOT_FOUND", 404, message, details);
51
58
  }
52
59
  }
53
60
  exports.NotFoundError = NotFoundError;
54
- // 409 — The request conflicts with the current state of the resource
55
- // (e.g. duplicate email, concurrent edit conflict).
61
+ /**
62
+ * 410 Gone error.
63
+ */
64
+ class GoneError extends app_error_1.AppError {
65
+ /**
66
+ * @param {string} [message] - Error explanation message.
67
+ * @param {unknown} [details] - Detailed error context.
68
+ */
69
+ constructor(message = "Gone", details) {
70
+ super("GONE", 410, message, details);
71
+ }
72
+ }
73
+ exports.GoneError = GoneError;
74
+ /**
75
+ * 409 Conflict error.
76
+ */
56
77
  class ConflictError extends app_error_1.AppError {
78
+ /**
79
+ * @param {string} [message] - Error explanation message.
80
+ * @param {unknown} [details] - Detailed error context.
81
+ */
57
82
  constructor(message = "Conflict", details) {
58
83
  super("CONFLICT", 409, message, details);
59
84
  }
60
85
  }
61
86
  exports.ConflictError = ConflictError;
62
- // 422 — The request is well-formed but semantically invalid
63
- // (e.g. Zod validation passed structurally but business rules failed).
87
+ /**
88
+ * 422 Unprocessable Entity error.
89
+ */
64
90
  class UnprocessableEntityError extends app_error_1.AppError {
91
+ /**
92
+ * @param {string} [message] - Error explanation message.
93
+ * @param {unknown} [details] - Detailed error context.
94
+ */
65
95
  constructor(message = "Unprocessable Entity", details) {
66
96
  super("UNPROCESSABLE_ENTITY", 422, message, details);
67
97
  }
68
98
  }
69
99
  exports.UnprocessableEntityError = UnprocessableEntityError;
70
- // 429 — The caller has exceeded the rate limit. Clients should back off.
100
+ /**
101
+ * 429 Too Many Requests error.
102
+ */
71
103
  class TooManyRequestsError extends app_error_1.AppError {
104
+ /**
105
+ * @param {string} [message] - Error explanation message.
106
+ * @param {unknown} [details] - Detailed error context.
107
+ */
72
108
  constructor(message = "Too Many Requests", details) {
73
109
  super("TOO_MANY_REQUESTS", 429, message, details);
74
110
  }
75
111
  }
76
112
  exports.TooManyRequestsError = TooManyRequestsError;
77
- // 500 — An unexpected internal error occurred. Should never be thrown
78
- // intentionally use more specific errors wherever possible.
113
+ /**
114
+ * 500 Internal Server Error.
115
+ */
79
116
  class InternalServerError extends app_error_1.AppError {
117
+ /**
118
+ * @param {string} [message] - Error explanation message.
119
+ * @param {unknown} [details] - Detailed error context.
120
+ */
80
121
  constructor(message = "Internal Server Error", details) {
81
122
  super("INTERNAL_SERVER_ERROR", 500, message, details);
82
123
  }
83
124
  }
84
125
  exports.InternalServerError = InternalServerError;
85
- // 503 — The service (or a dependency) is temporarily unavailable.
86
- // Clients may retry after the indicated delay.
126
+ /**
127
+ * 503 Service Unavailable error.
128
+ */
87
129
  class ServiceUnavailableError extends app_error_1.AppError {
130
+ /**
131
+ * @param {string} [message] - Error explanation message.
132
+ * @param {unknown} [details] - Detailed error context.
133
+ */
88
134
  constructor(message = "Service Unavailable", details) {
89
135
  super("SERVICE_UNAVAILABLE", 503, message, details);
90
136
  }
91
137
  }
92
138
  exports.ServiceUnavailableError = ServiceUnavailableError;
139
+ /**
140
+ * 403 Account Pending Deletion error.
141
+ *
142
+ * Thrown when a soft-deleted user account is accessed in a context that does
143
+ * not allow implicit restore (e.g. login). The client should present a recovery
144
+ * prompt rather than treating this as a generic auth failure.
145
+ */
146
+ class AccountPendingDeletionError extends app_error_1.AppError {
147
+ constructor(message = "This account is scheduled for deletion. Recover it within the 30-day window.", details) {
148
+ super("ACCOUNT_PENDING_DELETION", 403, message, details);
149
+ }
150
+ }
151
+ exports.AccountPendingDeletionError = AccountPendingDeletionError;
152
+ /**
153
+ * 403 Organization Pending Deletion error.
154
+ *
155
+ * Thrown when a soft-deleted organization is accessed in a context that does
156
+ * not allow implicit restore (e.g. slug conflict on create). The client should
157
+ * prompt the user to restore the organization instead.
158
+ */
159
+ class OrganizationPendingDeletionError extends app_error_1.AppError {
160
+ constructor(message = "This organization is scheduled for deletion. Restore it within the 30-day window.", details) {
161
+ super("ORGANIZATION_PENDING_DELETION", 403, message, details);
162
+ }
163
+ }
164
+ exports.OrganizationPendingDeletionError = OrganizationPendingDeletionError;
165
+ /**
166
+ * 403 Workspace Pending Deletion error.
167
+ *
168
+ * Thrown when a soft-deleted workspace is accessed in a context that does
169
+ * not allow implicit restore (e.g. slug conflict on create). The client should
170
+ * prompt the user to restore the workspace instead.
171
+ */
172
+ class WorkspacePendingDeletionError extends app_error_1.AppError {
173
+ constructor(message = "This workspace is scheduled for deletion. Restore it within the 30-day window.", details) {
174
+ super("WORKSPACE_PENDING_DELETION", 403, message, details);
175
+ }
176
+ }
177
+ exports.WorkspacePendingDeletionError = WorkspacePendingDeletionError;
@@ -1 +1,2 @@
1
1
  export * from "./service-client";
2
+ export * from "./request-context";
@@ -15,3 +15,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./service-client"), exports);
18
+ __exportStar(require("./request-context"), exports);
@@ -0,0 +1,8 @@
1
+ import { Request } from "express";
2
+ import { UserContext, MachineContext, RequestMetadataContext } from "../types";
3
+ export declare function getUserContext(req: Request): UserContext;
4
+ export declare function getMachineContext(req: Request): MachineContext;
5
+ export declare function getRequestContext(req: Request): RequestMetadataContext;
6
+ export declare function getValidatedBody<T>(req: Request): T;
7
+ export declare function getValidatedParams<T>(req: Request): T;
8
+ export declare function getValidatedQuery<T>(req: Request): T;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getUserContext = getUserContext;
4
+ exports.getMachineContext = getMachineContext;
5
+ exports.getRequestContext = getRequestContext;
6
+ exports.getValidatedBody = getValidatedBody;
7
+ exports.getValidatedParams = getValidatedParams;
8
+ exports.getValidatedQuery = getValidatedQuery;
9
+ function getUserContext(req) {
10
+ const ctx = req.authContext;
11
+ if (!ctx || ctx.type !== "user") {
12
+ throw new Error("User context missing. Did you forget requireUser?");
13
+ }
14
+ return ctx;
15
+ }
16
+ function getMachineContext(req) {
17
+ const ctx = req.authContext;
18
+ if (!ctx || ctx.type !== "machine") {
19
+ throw new Error("Machine context missing. Did you forget requireMachine?");
20
+ }
21
+ return ctx;
22
+ }
23
+ function getRequestContext(req) {
24
+ if (!req.requestContext) {
25
+ throw new Error("Request context missing. Did you forget requestContext middleware?");
26
+ }
27
+ return req.requestContext;
28
+ }
29
+ function getValidatedBody(req) {
30
+ return req.validated?.body;
31
+ }
32
+ function getValidatedParams(req) {
33
+ return req.validated?.params;
34
+ }
35
+ function getValidatedQuery(req) {
36
+ return req.validated?.query;
37
+ }
@@ -1,61 +1,114 @@
1
+ /**
2
+ * @file service-client.ts
3
+ * @description HTTP client wrapper for service-to-service communication.
4
+ * Handles automatic JWT forwarding, request correlation tracking via header propagation,
5
+ * and automatic retry behaviors on transient failures.
6
+ */
1
7
  import { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
2
8
  import { Request } from "express";
3
9
  /**
4
- * SERVICE CLIENT (@discover-cloud/shared)
5
- * ─────────────────────────────────────────
6
- * HTTP client for service-to-service communication.
7
- *
8
- * Two call patterns:
9
- *
10
- * Pattern 1 — JWT-forwarding (user-initiated requests)
11
- * Pass the current Express Request — Authorization + x-request-id are
12
- * forwarded automatically. Used when the downstream service needs to
13
- * act on behalf of the authenticated user.
14
- * Methods: getWithAuth, postWithAuth, patchWithAuth, deleteWithAuth
15
- *
16
- * Pattern 2 — Internal calls (service-initiated, no incoming request)
17
- * Pass explicit headers — used when calls originate from service logic
18
- * rather than from an HTTP handler (e.g. auth service → user service
19
- * during account creation). Caller is responsible for providing the
20
- * X-Internal-Secret header.
21
- * Methods: get, post, patch, delete
22
- *
23
- * Retry strategy:
24
- * - Retries on network errors and 5xx responses only (up to 3 attempts,
25
- * exponential backoff). 4xx responses are never retried — they are
26
- * deterministic caller errors that won't resolve on retry.
27
- *
28
- * Timeout:
29
- * - 8 seconds per request (covers retry delays separately via axiosRetry).
30
- * Adjust per-call via config.timeout if a specific route needs more.
10
+ * ServiceClient encapsulates an AxiosInstance configured for service-to-service HTTP requests.
11
+ * Supports token forwarding (Pattern 1) and secure internal calls (Pattern 2).
31
12
  */
32
13
  export declare class ServiceClient {
33
14
  readonly http: AxiosInstance;
15
+ /**
16
+ * Initializes the Axios instance with a base URL, timeout, and retry rules.
17
+ *
18
+ * @param {string} baseURL - Downstream service base URL.
19
+ */
34
20
  constructor(baseURL: string);
21
+ /**
22
+ * Performs an HTTP GET request while forwarding authorization and request headers.
23
+ *
24
+ * @param {string} url - Request target endpoint relative path.
25
+ * @param {Request} req - The current Express request object.
26
+ * @param {AxiosRequestConfig} [config] - Optional request configuration parameters.
27
+ * @returns {Promise<AxiosResponse<T>>} Axios response promise.
28
+ */
35
29
  getWithAuth<T = unknown>(url: string, req: Request, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
30
+ /**
31
+ * Performs an HTTP POST request while forwarding authorization and request headers.
32
+ *
33
+ * @param {string} url - Request target endpoint relative path.
34
+ * @param {unknown} data - JSON request body data payload.
35
+ * @param {Request} req - The current Express request object.
36
+ * @param {AxiosRequestConfig} [config] - Optional request configuration parameters.
37
+ * @returns {Promise<AxiosResponse<T>>} Axios response promise.
38
+ */
36
39
  postWithAuth<T = unknown>(url: string, data: unknown, req: Request, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
40
+ /**
41
+ * Performs an HTTP PATCH request while forwarding authorization and request headers.
42
+ *
43
+ * @param {string} url - Request target endpoint relative path.
44
+ * @param {unknown} data - JSON request body data payload.
45
+ * @param {Request} req - The current Express request object.
46
+ * @param {AxiosRequestConfig} [config] - Optional request configuration parameters.
47
+ * @returns {Promise<AxiosResponse<T>>} Axios response promise.
48
+ */
37
49
  patchWithAuth<T = unknown>(url: string, data: unknown, req: Request, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
50
+ /**
51
+ * Performs an HTTP DELETE request while forwarding authorization and request headers.
52
+ *
53
+ * @param {string} url - Request target endpoint relative path.
54
+ * @param {Request} req - The current Express request object.
55
+ * @param {AxiosRequestConfig} [config] - Optional request configuration parameters.
56
+ * @returns {Promise<AxiosResponse<T>>} Axios response promise.
57
+ */
38
58
  deleteWithAuth<T = unknown>(url: string, req: Request, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
59
+ /**
60
+ * Performs an HTTP GET request with explicit header configurations.
61
+ *
62
+ * @param {string} url - Request target endpoint relative path.
63
+ * @param {Record<string, string>} headers - Header keys and values to attach.
64
+ * @param {AxiosRequestConfig} [config] - Optional request configuration parameters.
65
+ * @returns {Promise<AxiosResponse<T>>} Axios response promise.
66
+ */
39
67
  get<T = unknown>(url: string, headers: Record<string, string>, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
68
+ /**
69
+ * Performs an HTTP POST request with explicit header configurations.
70
+ *
71
+ * @param {string} url - Request target endpoint relative path.
72
+ * @param {unknown} data - JSON request body data payload.
73
+ * @param {Record<string, string>} headers - Header keys and values to attach.
74
+ * @param {AxiosRequestConfig} [config] - Optional request configuration parameters.
75
+ * @returns {Promise<AxiosResponse<T>>} Axios response promise.
76
+ */
40
77
  post<T = unknown>(url: string, data: unknown, headers: Record<string, string>, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
78
+ /**
79
+ * Performs an HTTP PATCH request with explicit header configurations.
80
+ *
81
+ * @param {string} url - Request target endpoint relative path.
82
+ * @param {unknown} data - JSON request body data payload.
83
+ * @param {Record<string, string>} headers - Header keys and values to attach.
84
+ * @param {AxiosRequestConfig} [config] - Optional request configuration parameters.
85
+ * @returns {Promise<AxiosResponse<T>>} Axios response promise.
86
+ */
41
87
  patch<T = unknown>(url: string, data: unknown, headers: Record<string, string>, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
88
+ /**
89
+ * Performs an HTTP DELETE request with explicit header configurations.
90
+ *
91
+ * @param {string} url - Request target endpoint relative path.
92
+ * @param {Record<string, string>} headers - Header keys and values to attach.
93
+ * @param {AxiosRequestConfig} [config] - Optional request configuration parameters.
94
+ * @returns {Promise<AxiosResponse<T>>} Axios response promise.
95
+ */
42
96
  delete<T = unknown>(url: string, headers: Record<string, string>, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
43
97
  /**
44
- * mergeAuth
45
- * Extracts Authorization and x-request-id from the Express request
46
- * and merges them into the Axios config headers.
98
+ * Extracts authorization credentials and tracing identifiers from Express requests
99
+ * and merges them into Axios config header values.
47
100
  *
48
- * x-request-id precedence:
49
- * 1. req.id set by express-request-id or equivalent middleware
50
- * 2. x-request-id header forwarded from the upstream caller
51
- * 3. Synthetic fallback (timestamp) — should not appear in production
52
- * if request-id middleware is wired correctly in the gateway
101
+ * @param {Request} req - The current Express request.
102
+ * @param {AxiosRequestConfig} [config] - The existing Axios request configuration.
103
+ * @returns {AxiosRequestConfig} The merged Axios request configuration.
53
104
  */
54
105
  private mergeAuth;
55
106
  /**
56
- * mergeHeaders
57
- * Merges caller-supplied headers into the Axios config.
58
- * Caller-supplied headers take precedence over config.headers.
107
+ * Integrates user-supplied headers into the request configuration object.
108
+ *
109
+ * @param {Record<string, string>} headers - The headers to merge.
110
+ * @param {AxiosRequestConfig} [config] - The existing Axios request configuration.
111
+ * @returns {AxiosRequestConfig} The merged Axios request configuration.
59
112
  */
60
113
  private mergeHeaders;
61
114
  }