@discover-cloud/shared 1.0.5 → 1.0.7

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.
@@ -0,0 +1,40 @@
1
+ import { CloudProvider, CloudAccountStatus, AwsAuthMethod, GcpAuthMethod, AzureAuthMethod, SyncStatus, SyncType } from "../enums";
2
+ /**
3
+ * CLOUD SERVICE DTOs
4
+ * ───────────────────
5
+ * Shapes returned by the cloud service over HTTP.
6
+ *
7
+ * CloudAccountDto never includes encryptedCredentials — credentials
8
+ * are write-only. authMethod is the resolved union of whichever
9
+ * provider-specific method is set (only one is ever non-null).
10
+ *
11
+ * SyncJobDto is read-only — sync jobs are created internally by the
12
+ * orchestrator and exposed for status polling only.
13
+ */
14
+ export interface CloudAccountDto {
15
+ id: string;
16
+ userId: string;
17
+ alias: string;
18
+ provider: CloudProvider;
19
+ status: CloudAccountStatus;
20
+ authMethod: AwsAuthMethod | GcpAuthMethod | AzureAuthMethod | null;
21
+ lastSyncAt: Date | null;
22
+ lastErrorAt: Date | null;
23
+ lastErrorMsg: string | null;
24
+ createdAt: Date;
25
+ updatedAt: Date;
26
+ }
27
+ export interface SyncJobDto {
28
+ id: string;
29
+ cloudAccountId: string;
30
+ type: SyncType;
31
+ status: SyncStatus;
32
+ startedAt: Date | null;
33
+ completedAt: Date | null;
34
+ errorMessage: string | null;
35
+ resourcesSynced: number;
36
+ costRecords: number;
37
+ budgetsSynced: number;
38
+ createdAt: Date;
39
+ updatedAt: Date;
40
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,3 +1,4 @@
1
1
  export * from "./user-service.dto";
2
2
  export * from "./auth-service.dto";
3
+ export * from "./cloud-service.dto";
3
4
  export * from "./response.dto";
@@ -16,4 +16,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./user-service.dto"), exports);
18
18
  __exportStar(require("./auth-service.dto"), exports);
19
+ __exportStar(require("./cloud-service.dto"), exports);
19
20
  __exportStar(require("./response.dto"), exports);
@@ -6,19 +6,14 @@
6
6
  */
7
7
  export declare enum AccountStatus {
8
8
  ACTIVE = "ACTIVE",
9
- SUSPENDED = "SUSPENDED",// Access revoked, data retained, reversible
9
+ SUSPENDED = "SUSPENDED",
10
10
  DELETED = "DELETED"
11
11
  }
12
12
  export declare enum OrganizationStatus {
13
13
  ACTIVE = "ACTIVE",
14
- SUSPENDED = "SUSPENDED",// Platform-level suspension (non-payment, policy)
14
+ SUSPENDED = "SUSPENDED",
15
15
  CLOSED = "CLOSED"
16
16
  }
17
- /**
18
- * OrganizationRole lives in permissions.types.ts alongside OrgPermission
19
- * so the role → permission map stays co-located with the role definition.
20
- * Re-exported from enums/index.ts for convenience.
21
- */
22
17
  export declare enum MembershipStatus {
23
18
  PENDING = "PENDING",
24
19
  ACTIVE = "ACTIVE",
@@ -31,12 +26,53 @@ export declare enum Theme {
31
26
  SYSTEM = "SYSTEM"
32
27
  }
33
28
  export declare enum Currency {
34
- USD = "USD",// US Dollar — default, all cloud providers
35
- EUR = "EUR",// Euro — AWS/GCP/Azure EU regions
36
- GBP = "GBP",// British Pound — AWS/GCP/Azure UK regions
37
- INR = "INR",// Indian Rupee — AWS/GCP/Azure AP south regions
38
- AUD = "AUD",// Australian Dollar
39
- CAD = "CAD",// Canadian Dollar
40
- JPY = "JPY",// Japanese Yen
29
+ USD = "USD",
30
+ EUR = "EUR",
31
+ GBP = "GBP",
32
+ INR = "INR",
33
+ AUD = "AUD",
34
+ CAD = "CAD",
35
+ JPY = "JPY",
41
36
  SGD = "SGD"
42
37
  }
38
+ export declare enum CloudProvider {
39
+ AWS = "AWS",
40
+ GCP = "GCP",
41
+ AZURE = "AZURE"
42
+ }
43
+ export declare enum AwsAuthMethod {
44
+ ACCESS_KEY = "ACCESS_KEY",// Access Key ID + Secret
45
+ IAM_ROLE = "IAM_ROLE",// Role ARN + External ID
46
+ IAM_IDENTITY_CENTER = "IAM_IDENTITY_CENTER",// SSO
47
+ IAM_ROLES_ANYWHERE = "IAM_ROLES_ANYWHERE"
48
+ }
49
+ export declare enum GcpAuthMethod {
50
+ SERVICE_ACCOUNT_KEY = "SERVICE_ACCOUNT_KEY",
51
+ WORKLOAD_IDENTITY = "WORKLOAD_IDENTITY",
52
+ SERVICE_ACCOUNT_IMPERSONATION = "SERVICE_ACCOUNT_IMPERSONATION"
53
+ }
54
+ export declare enum AzureAuthMethod {
55
+ SERVICE_PRINCIPAL_SECRET = "SERVICE_PRINCIPAL_SECRET",
56
+ SERVICE_PRINCIPAL_CERTIFICATE = "SERVICE_PRINCIPAL_CERTIFICATE",
57
+ MANAGED_IDENTITY_USER = "MANAGED_IDENTITY_USER",
58
+ MANAGED_IDENTITY_SYSTEM = "MANAGED_IDENTITY_SYSTEM"
59
+ }
60
+ export declare enum CloudAccountStatus {
61
+ PENDING = "PENDING",// Connected, never synced
62
+ ACTIVE = "ACTIVE",// Last sync succeeded
63
+ ERROR = "ERROR",// Last sync failed
64
+ INACTIVE = "INACTIVE"
65
+ }
66
+ export declare enum SyncStatus {
67
+ PENDING = "PENDING",
68
+ RUNNING = "RUNNING",
69
+ SUCCESS = "SUCCESS",
70
+ FAILED = "FAILED",
71
+ PARTIAL = "PARTIAL"
72
+ }
73
+ export declare enum SyncType {
74
+ FULL = "FULL",// All data types
75
+ COSTS = "COSTS",// Cost records only
76
+ RESOURCES = "RESOURCES",// Resource inventory only
77
+ BUDGETS = "BUDGETS"
78
+ }
@@ -6,11 +6,9 @@
6
6
  * configuration. Permission-related enums live in permissions.types.ts.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.Currency = exports.Theme = exports.MembershipStatus = exports.OrganizationStatus = exports.AccountStatus = void 0;
9
+ exports.SyncType = exports.SyncStatus = exports.CloudAccountStatus = exports.AzureAuthMethod = exports.GcpAuthMethod = exports.AwsAuthMethod = exports.CloudProvider = exports.Currency = exports.Theme = exports.MembershipStatus = exports.OrganizationStatus = exports.AccountStatus = void 0;
10
10
  /* ====================================================================
11
11
  ACCOUNT
12
- Lifecycle states for a platform account (auth domain).
13
- Replaces the duplicate UserStatus — there is only Account in auth.
14
12
  ==================================================================== */
15
13
  var AccountStatus;
16
14
  (function (AccountStatus) {
@@ -19,7 +17,7 @@ var AccountStatus;
19
17
  AccountStatus["DELETED"] = "DELETED";
20
18
  })(AccountStatus || (exports.AccountStatus = AccountStatus = {}));
21
19
  /* ====================================================================
22
- ORGANIZATION (future work — defined now for type completeness)
20
+ ORGANIZATION
23
21
  ==================================================================== */
24
22
  var OrganizationStatus;
25
23
  (function (OrganizationStatus) {
@@ -27,21 +25,6 @@ var OrganizationStatus;
27
25
  OrganizationStatus["SUSPENDED"] = "SUSPENDED";
28
26
  OrganizationStatus["CLOSED"] = "CLOSED";
29
27
  })(OrganizationStatus || (exports.OrganizationStatus = OrganizationStatus = {}));
30
- /**
31
- * OrganizationRole lives in permissions.types.ts alongside OrgPermission
32
- * so the role → permission map stays co-located with the role definition.
33
- * Re-exported from enums/index.ts for convenience.
34
- */
35
- /* ====================================================================
36
- MEMBERSHIP (future work)
37
- Tracks a user's membership state within an organization.
38
-
39
- PENDING — invite sent, not yet accepted
40
- ACTIVE — full org member
41
- SUSPENDED — access revoked by org admin, invite not cancelled
42
- REMOVED — explicitly removed by admin (different from suspended —
43
- removed members must be re-invited to regain access)
44
- ==================================================================== */
45
28
  var MembershipStatus;
46
29
  (function (MembershipStatus) {
47
30
  MembershipStatus["PENDING"] = "PENDING";
@@ -58,14 +41,6 @@ var Theme;
58
41
  Theme["DARK"] = "DARK";
59
42
  Theme["SYSTEM"] = "SYSTEM";
60
43
  })(Theme || (exports.Theme = Theme = {}));
61
- /* ====================================================================
62
- CURRENCY
63
- Cloud cost monitoring — users see costs in their preferred currency.
64
- Amounts are stored in USD (base currency) and converted at display time.
65
-
66
- Expand this list as you add cloud provider regions:
67
- AUD, CAD, JPY, SGD, BRL, KRW, SEK, NOK, CHF, MXN ...
68
- ==================================================================== */
69
44
  var Currency;
70
45
  (function (Currency) {
71
46
  Currency["USD"] = "USD";
@@ -77,3 +52,67 @@ var Currency;
77
52
  Currency["JPY"] = "JPY";
78
53
  Currency["SGD"] = "SGD";
79
54
  })(Currency || (exports.Currency = Currency = {}));
55
+ /* ====================================================================
56
+ CLOUD PROVIDERS
57
+ Used by cloud-service for account connections and insights-service
58
+ for storing normalized cost/resource data.
59
+ ==================================================================== */
60
+ var CloudProvider;
61
+ (function (CloudProvider) {
62
+ CloudProvider["AWS"] = "AWS";
63
+ CloudProvider["GCP"] = "GCP";
64
+ CloudProvider["AZURE"] = "AZURE";
65
+ })(CloudProvider || (exports.CloudProvider = CloudProvider = {}));
66
+ /* ====================================================================
67
+ CLOUD ACCOUNT AUTH METHODS
68
+ Discriminator for which credential shape is stored per provider.
69
+ Each provider has its own enum — only one is set per CloudAccount.
70
+ ==================================================================== */
71
+ var AwsAuthMethod;
72
+ (function (AwsAuthMethod) {
73
+ AwsAuthMethod["ACCESS_KEY"] = "ACCESS_KEY";
74
+ AwsAuthMethod["IAM_ROLE"] = "IAM_ROLE";
75
+ AwsAuthMethod["IAM_IDENTITY_CENTER"] = "IAM_IDENTITY_CENTER";
76
+ AwsAuthMethod["IAM_ROLES_ANYWHERE"] = "IAM_ROLES_ANYWHERE";
77
+ })(AwsAuthMethod || (exports.AwsAuthMethod = AwsAuthMethod = {}));
78
+ var GcpAuthMethod;
79
+ (function (GcpAuthMethod) {
80
+ GcpAuthMethod["SERVICE_ACCOUNT_KEY"] = "SERVICE_ACCOUNT_KEY";
81
+ GcpAuthMethod["WORKLOAD_IDENTITY"] = "WORKLOAD_IDENTITY";
82
+ GcpAuthMethod["SERVICE_ACCOUNT_IMPERSONATION"] = "SERVICE_ACCOUNT_IMPERSONATION";
83
+ })(GcpAuthMethod || (exports.GcpAuthMethod = GcpAuthMethod = {}));
84
+ var AzureAuthMethod;
85
+ (function (AzureAuthMethod) {
86
+ AzureAuthMethod["SERVICE_PRINCIPAL_SECRET"] = "SERVICE_PRINCIPAL_SECRET";
87
+ AzureAuthMethod["SERVICE_PRINCIPAL_CERTIFICATE"] = "SERVICE_PRINCIPAL_CERTIFICATE";
88
+ AzureAuthMethod["MANAGED_IDENTITY_USER"] = "MANAGED_IDENTITY_USER";
89
+ AzureAuthMethod["MANAGED_IDENTITY_SYSTEM"] = "MANAGED_IDENTITY_SYSTEM";
90
+ })(AzureAuthMethod || (exports.AzureAuthMethod = AzureAuthMethod = {}));
91
+ /* ====================================================================
92
+ CLOUD ACCOUNT STATUS
93
+ ==================================================================== */
94
+ var CloudAccountStatus;
95
+ (function (CloudAccountStatus) {
96
+ CloudAccountStatus["PENDING"] = "PENDING";
97
+ CloudAccountStatus["ACTIVE"] = "ACTIVE";
98
+ CloudAccountStatus["ERROR"] = "ERROR";
99
+ CloudAccountStatus["INACTIVE"] = "INACTIVE";
100
+ })(CloudAccountStatus || (exports.CloudAccountStatus = CloudAccountStatus = {}));
101
+ /* ====================================================================
102
+ SYNC JOB
103
+ ==================================================================== */
104
+ var SyncStatus;
105
+ (function (SyncStatus) {
106
+ SyncStatus["PENDING"] = "PENDING";
107
+ SyncStatus["RUNNING"] = "RUNNING";
108
+ SyncStatus["SUCCESS"] = "SUCCESS";
109
+ SyncStatus["FAILED"] = "FAILED";
110
+ SyncStatus["PARTIAL"] = "PARTIAL";
111
+ })(SyncStatus || (exports.SyncStatus = SyncStatus = {}));
112
+ var SyncType;
113
+ (function (SyncType) {
114
+ SyncType["FULL"] = "FULL";
115
+ SyncType["COSTS"] = "COSTS";
116
+ SyncType["RESOURCES"] = "RESOURCES";
117
+ SyncType["BUDGETS"] = "BUDGETS";
118
+ })(SyncType || (exports.SyncType = SyncType = {}));
@@ -3,29 +3,34 @@ import { Request } from "express";
3
3
  /**
4
4
  * SERVICE CLIENT
5
5
  * ───────────────
6
- * HTTP client for service-to-service calls.
7
- * Forwards the internal JWT and request ID from the current Express request.
6
+ * HTTP client for service-to-service communication.
8
7
  *
9
- * Fixes vs original:
10
- * - Removed `validateStatus: () => true` — it silently swallowed 4xx/5xx,
11
- * forcing every caller to manually check response.status. Removed so
12
- * axios throws naturally on error responses.
13
- * - `postWithAuth(url, data: any)` → `data: unknown` — no silent any
14
- * - requestId fallback now consistent with requestId middleware logic
15
- * - Added `patchWithAuth` and `deleteWithAuth` — common enough to include
16
- * - Retry only on network errors + 5xx (not 4xx those are caller errors)
8
+ * Two call patterns:
9
+ *
10
+ * 1. JWT-forwarding (user-initiated requests)
11
+ * Pass the current Express Request — Authorization + x-request-id
12
+ * are forwarded automatically.
13
+ * Use: getWithAuth, postWithAuth, patchWithAuth, deleteWithAuth
14
+ *
15
+ * 2. Internal calls (service-to-service, no incoming request)
16
+ * Pass explicit headers — used by UserServiceClient in auth service
17
+ * where calls originate from service logic, not from an HTTP handler.
18
+ * Use: get, post, patch, delete
19
+ *
20
+ * Retry strategy: network errors + 5xx only. Never retries 4xx —
21
+ * those are deterministic caller errors.
17
22
  */
18
23
  export declare class ServiceClient {
19
24
  readonly http: AxiosInstance;
20
25
  constructor(baseURL: string);
21
- private setupRetry;
22
26
  getWithAuth<T = unknown>(url: string, req: Request, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
23
27
  postWithAuth<T = unknown>(url: string, data: unknown, req: Request, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
24
28
  patchWithAuth<T = unknown>(url: string, data: unknown, req: Request, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
25
29
  deleteWithAuth<T = unknown>(url: string, req: Request, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
26
- /**
27
- * Merges Authorization + x-request-id into any provided config.
28
- * The internal JWT is forwarded as-is the gateway already minted it.
29
- */
30
+ get<T = unknown>(url: string, headers: Record<string, string>, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
31
+ post<T = unknown>(url: string, data: unknown, headers: Record<string, string>, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
32
+ patch<T = unknown>(url: string, data: unknown, headers: Record<string, string>, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
33
+ delete<T = unknown>(url: string, headers: Record<string, string>, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
30
34
  private mergeAuth;
35
+ private mergeHeaders;
31
36
  }
@@ -9,17 +9,22 @@ const axios_retry_1 = __importDefault(require("axios-retry"));
9
9
  /**
10
10
  * SERVICE CLIENT
11
11
  * ───────────────
12
- * HTTP client for service-to-service calls.
13
- * Forwards the internal JWT and request ID from the current Express request.
12
+ * HTTP client for service-to-service communication.
14
13
  *
15
- * Fixes vs original:
16
- * - Removed `validateStatus: () => true` — it silently swallowed 4xx/5xx,
17
- * forcing every caller to manually check response.status. Removed so
18
- * axios throws naturally on error responses.
19
- * - `postWithAuth(url, data: any)` → `data: unknown` — no silent any
20
- * - requestId fallback now consistent with requestId middleware logic
21
- * - Added `patchWithAuth` and `deleteWithAuth` — common enough to include
22
- * - Retry only on network errors + 5xx (not 4xx those are caller errors)
14
+ * Two call patterns:
15
+ *
16
+ * 1. JWT-forwarding (user-initiated requests)
17
+ * Pass the current Express Request — Authorization + x-request-id
18
+ * are forwarded automatically.
19
+ * Use: getWithAuth, postWithAuth, patchWithAuth, deleteWithAuth
20
+ *
21
+ * 2. Internal calls (service-to-service, no incoming request)
22
+ * Pass explicit headers — used by UserServiceClient in auth service
23
+ * where calls originate from service logic, not from an HTTP handler.
24
+ * Use: get, post, patch, delete
25
+ *
26
+ * Retry strategy: network errors + 5xx only. Never retries 4xx —
27
+ * those are deterministic caller errors.
23
28
  */
24
29
  class ServiceClient {
25
30
  constructor(baseURL) {
@@ -27,15 +32,10 @@ class ServiceClient {
27
32
  baseURL,
28
33
  timeout: 8000,
29
34
  });
30
- this.setupRetry();
31
- }
32
- setupRetry() {
33
35
  (0, axios_retry_1.default)(this.http, {
34
36
  retries: 3,
35
37
  retryDelay: axios_retry_1.default.exponentialDelay,
36
38
  retryCondition: (err) => {
37
- // Retry on network errors or 5xx only
38
- // Do NOT retry 4xx — those are deterministic failures
39
39
  if (axios_retry_1.default.isNetworkError(err))
40
40
  return true;
41
41
  const status = err.response?.status ?? 0;
@@ -44,10 +44,8 @@ class ServiceClient {
44
44
  });
45
45
  }
46
46
  /* ----------------------------------------------------------------
47
- Auth-forwarding methods
48
- Pass the current Express Request to automatically forward:
49
- - Authorization: Bearer <internal-jwt>
50
- - x-request-id: <propagated request ID>
47
+ Pattern 1 — JWT-forwarding (pass Express req)
48
+ Forwards Authorization header + x-request-id automatically.
51
49
  ---------------------------------------------------------------- */
52
50
  async getWithAuth(url, req, config) {
53
51
  return this.http.get(url, this.mergeAuth(req, config));
@@ -61,17 +59,28 @@ class ServiceClient {
61
59
  async deleteWithAuth(url, req, config) {
62
60
  return this.http.delete(url, this.mergeAuth(req, config));
63
61
  }
62
+ /* ----------------------------------------------------------------
63
+ Pattern 2 — Internal calls (explicit headers, no Express req)
64
+ Used for service-initiated calls (e.g. auth service → user service)
65
+ where there is no incoming HTTP request to forward from.
66
+ ---------------------------------------------------------------- */
67
+ async get(url, headers, config) {
68
+ return this.http.get(url, this.mergeHeaders(headers, config));
69
+ }
70
+ async post(url, data, headers, config) {
71
+ return this.http.post(url, data, this.mergeHeaders(headers, config));
72
+ }
73
+ async patch(url, data, headers, config) {
74
+ return this.http.patch(url, data, this.mergeHeaders(headers, config));
75
+ }
76
+ async delete(url, headers, config) {
77
+ return this.http.delete(url, this.mergeHeaders(headers, config));
78
+ }
64
79
  /* ----------------------------------------------------------------
65
80
  Private helpers
66
81
  ---------------------------------------------------------------- */
67
- /**
68
- * Merges Authorization + x-request-id into any provided config.
69
- * The internal JWT is forwarded as-is — the gateway already minted it.
70
- */
71
82
  mergeAuth(req, config) {
72
83
  const authHeader = req.headers.authorization;
73
- // req.id is set by requestId middleware — always a string at this point.
74
- // Fall back to x-request-id header if somehow req.id isn't set yet.
75
84
  const upstream = req.headers["x-request-id"];
76
85
  const requestId = req.id
77
86
  ?? (Array.isArray(upstream) ? upstream[0] : upstream)
@@ -85,5 +94,14 @@ class ServiceClient {
85
94
  },
86
95
  };
87
96
  }
97
+ mergeHeaders(headers, config) {
98
+ return {
99
+ ...config,
100
+ headers: {
101
+ ...config?.headers,
102
+ ...headers,
103
+ },
104
+ };
105
+ }
88
106
  }
89
107
  exports.ServiceClient = ServiceClient;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@discover-cloud/shared",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "private": false,
5
5
  "type": "commonjs",
6
6
  "main": "dist/index.js",