@discover-cloud/shared 1.0.0 → 1.0.1

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 (47) hide show
  1. package/dist/authorization/index.d.ts +2 -0
  2. package/dist/authorization/index.js +18 -0
  3. package/dist/authorization/permission-cache.service.d.ts +12 -0
  4. package/dist/authorization/permission-cache.service.js +132 -0
  5. package/dist/authorization/permissions.d.ts +74 -0
  6. package/dist/authorization/permissions.js +171 -0
  7. package/dist/dto/auth-service.dtos.d.ts +5 -12
  8. package/dist/dto/response.dtos.d.ts +34 -27
  9. package/dist/dto/response.dtos.js +4 -0
  10. package/dist/dto/user-service.dtos.d.ts +9 -13
  11. package/dist/enums/domain.enums.d.ts +42 -0
  12. package/dist/enums/domain.enums.js +79 -0
  13. package/dist/enums/index.d.ts +2 -3
  14. package/dist/enums/index.js +2 -3
  15. package/dist/enums/permissions.enums.d.ts +124 -0
  16. package/dist/enums/permissions.enums.js +141 -0
  17. package/dist/errors/app-error.d.ts +19 -2
  18. package/dist/errors/app-error.js +17 -2
  19. package/dist/errors/http-errors.d.ts +18 -0
  20. package/dist/errors/http-errors.js +25 -1
  21. package/dist/http/index.d.ts +1 -0
  22. package/dist/http/index.js +17 -0
  23. package/dist/http/service-client.d.ts +23 -7
  24. package/dist/http/service-client.js +54 -22
  25. package/dist/index.d.ts +2 -1
  26. package/dist/index.js +2 -1
  27. package/dist/jwt/index.d.ts +1 -2
  28. package/dist/jwt/index.js +1 -2
  29. package/dist/jwt/internal-jwt-verifier.d.ts +35 -0
  30. package/dist/jwt/internal-jwt-verifier.js +162 -0
  31. package/dist/middleware/authorize.middleware.d.ts +22 -0
  32. package/dist/middleware/authorize.middleware.js +77 -0
  33. package/dist/middleware/error-handler.middleware.d.ts +23 -0
  34. package/dist/middleware/error-handler.middleware.js +52 -0
  35. package/dist/middleware/index.d.ts +4 -5
  36. package/dist/middleware/index.js +4 -5
  37. package/dist/middleware/request-id.middleware.d.ts +20 -0
  38. package/dist/middleware/request-id.middleware.js +34 -0
  39. package/dist/middleware/validate.middleware.d.ts +26 -0
  40. package/dist/middleware/validate.middleware.js +41 -0
  41. package/dist/types/express.types.d.ts +148 -0
  42. package/dist/types/express.types.js +42 -0
  43. package/dist/types/index.d.ts +1 -1
  44. package/dist/types/index.js +1 -1
  45. package/dist/utils/response.d.ts +2 -1
  46. package/dist/utils/response.js +6 -3
  47. package/package.json +3 -2
@@ -0,0 +1,2 @@
1
+ export * from "./permissions";
2
+ export * from "./permission-cache.service";
@@ -0,0 +1,18 @@
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("./permissions"), exports);
18
+ __exportStar(require("./permission-cache.service"), exports);
@@ -0,0 +1,12 @@
1
+ import { GlobalPermission, AccountRole } from "../enums";
2
+ export declare class PermissionCacheService {
3
+ private readonly client;
4
+ private connected;
5
+ constructor();
6
+ resolve(accountId: string, accountRole: AccountRole): Promise<GlobalPermission[]>;
7
+ invalidate(accountId: string): Promise<void>;
8
+ invalidateMany(accountIds: string[]): Promise<void>;
9
+ private key;
10
+ private safeGet;
11
+ private safeSet;
12
+ }
@@ -0,0 +1,132 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PermissionCacheService = void 0;
4
+ const redis_1 = require("redis");
5
+ const permissions_1 = require("./permissions");
6
+ /**
7
+ * PERMISSION CACHE SERVICE (@discover-cloud/shared)
8
+ * ─────────────────────────────────────────────────────
9
+ * Redis-backed permission cache. Sits between JWT verification and route
10
+ * handlers — loads permissions for a verified accountId + role, caches
11
+ * them, and exposes invalidation for role changes and account lifecycle events.
12
+ *
13
+ * Cache key: perms:{accountId}
14
+ * Cache value: JSON array of GlobalPermission
15
+ * TTL: 24 hours (auto-evicted; role changes trigger explicit invalidation)
16
+ *
17
+ * Cold cache strategy:
18
+ * Derive from globalRolePermissions (role → perms map).
19
+ * No DB call — the role is already verified in the JWT, and all permissions
20
+ * are statically derived from it.
21
+ *
22
+ * Invalidation triggers:
23
+ * - Role change → invalidate(accountId)
24
+ * - Suspension → invalidate(accountId)
25
+ * - Account deletion → invalidate(accountId)
26
+ *
27
+ * NOTE: Uses console.* for logging — shared cannot depend on a service-specific
28
+ * logger (pino, winston, etc.). Each service's own logger will capture these
29
+ * via stdout in production.
30
+ */
31
+ const CACHE_TTL_SECONDS = 24 * 60 * 60; // 24 hours
32
+ const KEY_PREFIX = "perms";
33
+ class PermissionCacheService {
34
+ constructor() {
35
+ this.connected = false;
36
+ this.client = (0, redis_1.createClient)({
37
+ url: process.env.REDIS_URL ?? "redis://localhost:6379",
38
+ });
39
+ this.client.on("error", (err) => {
40
+ console.error("[PermissionCache] Redis client error", err);
41
+ });
42
+ this.client.on("ready", () => {
43
+ this.connected = true;
44
+ console.info("[PermissionCache] Redis connected");
45
+ });
46
+ this.client.connect().catch((err) => {
47
+ console.error("[PermissionCache] Redis connection failed", err);
48
+ });
49
+ }
50
+ /* ----------------------------------------------------------------
51
+ resolve
52
+ Returns permissions for an account, loading from cache or deriving
53
+ from the role map on a miss.
54
+
55
+ Never throws — on any Redis failure it falls back to deriving
56
+ from the role map directly (degraded but functional).
57
+ ---------------------------------------------------------------- */
58
+ async resolve(accountId, accountRole) {
59
+ const cached = await this.safeGet(accountId);
60
+ if (cached !== null)
61
+ return cached;
62
+ // Cache miss — derive from role map (no DB call)
63
+ const perms = [
64
+ ...(permissions_1.globalRolePermissions[accountRole] ?? []),
65
+ ];
66
+ // Write back (fire-and-forget — don't block the request)
67
+ this.safeSet(accountId, perms).catch(() => { });
68
+ return perms;
69
+ }
70
+ /* ----------------------------------------------------------------
71
+ invalidate
72
+ Removes a specific account's permission cache entry.
73
+ Call on: role change, suspension, account deletion.
74
+ ---------------------------------------------------------------- */
75
+ async invalidate(accountId) {
76
+ try {
77
+ await this.client.del(this.key(accountId));
78
+ console.info(`[PermissionCache] Invalidated: ${accountId}`);
79
+ }
80
+ catch (err) {
81
+ // Log but don't throw — stale entry expires via TTL at worst
82
+ console.error(`[PermissionCache] Failed to invalidate: ${accountId}`, err);
83
+ }
84
+ }
85
+ /* ----------------------------------------------------------------
86
+ invalidateMany
87
+ Batch invalidation — use when a role definition changes globally.
88
+ ---------------------------------------------------------------- */
89
+ async invalidateMany(accountIds) {
90
+ if (accountIds.length === 0)
91
+ return;
92
+ try {
93
+ const keys = accountIds.map((id) => this.key(id));
94
+ await this.client.del(keys);
95
+ console.info(`[PermissionCache] Batch invalidated ${accountIds.length} entries`);
96
+ }
97
+ catch (err) {
98
+ console.error("[PermissionCache] Batch invalidation failed", err);
99
+ }
100
+ }
101
+ /* ----------------------------------------------------------------
102
+ Private helpers
103
+ ---------------------------------------------------------------- */
104
+ key(accountId) {
105
+ return `${KEY_PREFIX}:${accountId}`;
106
+ }
107
+ async safeGet(accountId) {
108
+ if (!this.connected)
109
+ return null;
110
+ try {
111
+ const raw = await this.client.get(this.key(accountId));
112
+ if (!raw)
113
+ return null;
114
+ return JSON.parse(raw);
115
+ }
116
+ catch (err) {
117
+ console.warn(`[PermissionCache] Cache get failed for ${accountId}, bypassing`, err);
118
+ return null;
119
+ }
120
+ }
121
+ async safeSet(accountId, perms) {
122
+ if (!this.connected)
123
+ return;
124
+ try {
125
+ await this.client.set(this.key(accountId), JSON.stringify(perms), { EX: CACHE_TTL_SECONDS });
126
+ }
127
+ catch (err) {
128
+ console.warn(`[PermissionCache] Cache set failed for ${accountId}`, err);
129
+ }
130
+ }
131
+ }
132
+ exports.PermissionCacheService = PermissionCacheService;
@@ -0,0 +1,74 @@
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, not hardcoded list)
12
+ * - Each role has only the minimum permissions it needs (least privilege)
13
+ * - Permissions are additive — no role inherits from another at runtime
14
+ * - Adding a new permission: add to the enum above, then grant it here
15
+ *
16
+ * ┌─────────────┬──────────────────────────────────────────────────────┐
17
+ * │ Role │ Key permissions │
18
+ * ├─────────────┼──────────────────────────────────────────────────────┤
19
+ * │ SUPERADMIN │ Everything — full platform control │
20
+ * │ ADMIN │ User mgmt, cost data access, logs, health, support │
21
+ * │ SUPPORT │ Read-only user + cost data for support work │
22
+ * │ MODERATOR │ Content moderation only (future) │
23
+ * │ USER │ No global permissions — service layer gates own data │
24
+ * └─────────────┴──────────────────────────────────────────────────────┘
25
+ */
26
+ export declare const globalRolePermissions: Record<AccountRole, readonly GlobalPermission[]>;
27
+ /**
28
+ * ORG ROLE PERMISSION MAP (future work)
29
+ * ────────────────────────────────────────
30
+ * Org permissions are NOT in the JWT — they're fetched from the DB
31
+ * by tenant middleware within each service because:
32
+ * 1. Org membership changes frequently (invites, role changes, removal)
33
+ * 2. A user can be in multiple orgs with different roles
34
+ * 3. Embedding them in the JWT would create stale permission windows
35
+ *
36
+ * This map is used by tenant middleware for the DB-free fast path:
37
+ * if the org role is already known (e.g. from a prior DB fetch cached in
38
+ * Redis), derive permissions from here rather than re-querying the DB.
39
+ */
40
+ export declare const orgRolePermissions: Record<OrganizationRole, readonly OrgPermission[]>;
41
+ /**
42
+ * hasGlobalPermission
43
+ * Checks if a GlobalPermission is in the AccessContext's perms array.
44
+ * Perms come from the Redis permission cache, not from the JWT directly.
45
+ *
46
+ * This is the primary check for platform-level authorization.
47
+ */
48
+ export declare const hasGlobalPermission: (ctx: AccessContext, permission: GlobalPermission) => boolean;
49
+ /**
50
+ * isAllowed
51
+ * Unified permission check for both GlobalPermission and OrgPermission.
52
+ *
53
+ * GlobalPermission → checked against ctx.perms (Redis cache, derived from role)
54
+ * OrgPermission → returns false here; handled by tenant middleware in each
55
+ * service via DB lookup. This function is intentionally not
56
+ * the place for org permission checks.
57
+ *
58
+ * This makes the boundary explicit: callers that need org permission checks
59
+ * should use their service's tenant middleware, not isAllowed().
60
+ */
61
+ export declare const isAllowed: (ctx: AccessContext, permission: GlobalPermission | OrgPermission) => boolean;
62
+ /**
63
+ * isSuperAdmin
64
+ * Convenience guard for the rare cases where superadmin-only logic
65
+ * is needed beyond a single permission check.
66
+ */
67
+ export declare const isSuperAdmin: (ctx: AccessContext) => boolean;
68
+ /**
69
+ * deriveGlobalPermissions
70
+ * Derives permissions for a role from the static map.
71
+ * Called by PermissionCacheService on a cold cache miss.
72
+ * Returns a mutable copy — callers can extend it if needed.
73
+ */
74
+ export declare const deriveGlobalPermissions: (role: AccountRole) => GlobalPermission[];
@@ -0,0 +1,171 @@
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, not hardcoded list)
14
+ * - Each role has only the minimum permissions it needs (least privilege)
15
+ * - Permissions are additive — no role inherits from another at runtime
16
+ * - Adding a new permission: add to the enum above, then grant it here
17
+ *
18
+ * ┌─────────────┬──────────────────────────────────────────────────────┐
19
+ * │ Role │ Key permissions │
20
+ * ├─────────────┼──────────────────────────────────────────────────────┤
21
+ * │ SUPERADMIN │ Everything — full platform control │
22
+ * │ ADMIN │ User mgmt, cost data access, logs, health, support │
23
+ * │ SUPPORT │ Read-only user + cost data for support work │
24
+ * │ MODERATOR │ Content moderation only (future) │
25
+ * │ USER │ No global permissions — service layer gates own data │
26
+ * └─────────────┴──────────────────────────────────────────────────────┘
27
+ */
28
+ exports.globalRolePermissions = {
29
+ [enums_1.AccountRole.SUPERADMIN]: Object.values(enums_1.GlobalPermission),
30
+ [enums_1.AccountRole.ADMIN]: [
31
+ // Account management (no impersonate, no hard delete)
32
+ enums_1.GlobalPermission.MANAGE_ACCOUNTS,
33
+ enums_1.GlobalPermission.VIEW_ANY_ACCOUNT,
34
+ enums_1.GlobalPermission.SUSPEND_ACCOUNT,
35
+ // Cloud cost data
36
+ enums_1.GlobalPermission.VIEW_ANY_COST_DATA,
37
+ enums_1.GlobalPermission.EXPORT_ANY_COST_DATA,
38
+ enums_1.GlobalPermission.MANAGE_COST_ALERTS,
39
+ // Platform operations
40
+ enums_1.GlobalPermission.VIEW_SYSTEM_LOGS,
41
+ enums_1.GlobalPermission.VIEW_SYSTEM_HEALTH,
42
+ // Support tooling
43
+ enums_1.GlobalPermission.SUPPORT_VIEW,
44
+ enums_1.GlobalPermission.SUPPORT_WRITE,
45
+ ],
46
+ [enums_1.AccountRole.SUPPORT]: [
47
+ // Read-only access to user data and cost data for support purposes
48
+ // Cannot write, cannot manage accounts, cannot access system internals
49
+ enums_1.GlobalPermission.VIEW_ANY_ACCOUNT,
50
+ enums_1.GlobalPermission.VIEW_ANY_COST_DATA,
51
+ enums_1.GlobalPermission.SUPPORT_VIEW,
52
+ ],
53
+ [enums_1.AccountRole.MODERATOR]: [
54
+ // Only content moderation — no access to user accounts or cost data
55
+ enums_1.GlobalPermission.MODERATE_CONTENT,
56
+ ],
57
+ // Standard users have zero global permissions.
58
+ // All their data access is handled at the service level
59
+ // (they can only see their own cost data, their own account, etc.)
60
+ [enums_1.AccountRole.USER]: [],
61
+ };
62
+ /**
63
+ * ORG ROLE PERMISSION MAP (future work)
64
+ * ────────────────────────────────────────
65
+ * Org permissions are NOT in the JWT — they're fetched from the DB
66
+ * by tenant middleware within each service because:
67
+ * 1. Org membership changes frequently (invites, role changes, removal)
68
+ * 2. A user can be in multiple orgs with different roles
69
+ * 3. Embedding them in the JWT would create stale permission windows
70
+ *
71
+ * This map is used by tenant middleware for the DB-free fast path:
72
+ * if the org role is already known (e.g. from a prior DB fetch cached in
73
+ * Redis), derive permissions from here rather than re-querying the DB.
74
+ */
75
+ exports.orgRolePermissions = {
76
+ [enums_1.OrganizationRole.OWNER]: Object.values(enums_1.OrgPermission), // Full org control
77
+ [enums_1.OrganizationRole.ADMIN]: [
78
+ enums_1.GlobalPermission.MANAGE_ACCOUNTS, // intentional re-use shape — org admin manages org members
79
+ enums_1.OrgPermission.MANAGE_ORG_SETTINGS,
80
+ enums_1.OrgPermission.INVITE_MEMBERS,
81
+ enums_1.OrgPermission.REMOVE_MEMBERS,
82
+ enums_1.OrgPermission.CHANGE_MEMBER_ROLES,
83
+ enums_1.OrgPermission.VIEW_MEMBERS,
84
+ enums_1.OrgPermission.VIEW_COST_DATA,
85
+ enums_1.OrgPermission.EXPORT_COST_DATA,
86
+ enums_1.OrgPermission.MANAGE_COST_REPORTS,
87
+ enums_1.OrgPermission.MANAGE_ALERTS,
88
+ enums_1.OrgPermission.MANAGE_CLOUD_ACCOUNTS,
89
+ enums_1.OrgPermission.VIEW_CLOUD_ACCOUNTS,
90
+ enums_1.OrgPermission.VIEW_BILLING,
91
+ ],
92
+ [enums_1.OrganizationRole.EDITOR]: [
93
+ enums_1.OrgPermission.VIEW_MEMBERS,
94
+ enums_1.OrgPermission.VIEW_COST_DATA,
95
+ enums_1.OrgPermission.EXPORT_COST_DATA,
96
+ enums_1.OrgPermission.MANAGE_COST_REPORTS,
97
+ enums_1.OrgPermission.MANAGE_ALERTS,
98
+ enums_1.OrgPermission.VIEW_CLOUD_ACCOUNTS,
99
+ ],
100
+ [enums_1.OrganizationRole.VIEWER]: [
101
+ enums_1.OrgPermission.VIEW_MEMBERS,
102
+ enums_1.OrgPermission.VIEW_COST_DATA,
103
+ enums_1.OrgPermission.VIEW_CLOUD_ACCOUNTS,
104
+ ],
105
+ [enums_1.OrganizationRole.BILLING]: [
106
+ enums_1.OrgPermission.VIEW_BILLING,
107
+ enums_1.OrgPermission.MANAGE_BILLING,
108
+ enums_1.OrgPermission.VIEW_COST_DATA,
109
+ enums_1.OrgPermission.EXPORT_COST_DATA,
110
+ ],
111
+ };
112
+ /* ====================================================================
113
+ PERMISSION CHECK HELPERS
114
+ ==================================================================== */
115
+ /**
116
+ * hasGlobalPermission
117
+ * Checks if a GlobalPermission is in the AccessContext's perms array.
118
+ * Perms come from the Redis permission cache, not from the JWT directly.
119
+ *
120
+ * This is the primary check for platform-level authorization.
121
+ */
122
+ const hasGlobalPermission = (ctx, permission) => {
123
+ if (ctx.kind !== "human")
124
+ return false;
125
+ return ctx.perms.includes(permission);
126
+ };
127
+ exports.hasGlobalPermission = hasGlobalPermission;
128
+ /**
129
+ * isAllowed
130
+ * Unified permission check for both GlobalPermission and OrgPermission.
131
+ *
132
+ * GlobalPermission → checked against ctx.perms (Redis cache, derived from role)
133
+ * OrgPermission → returns false here; handled by tenant middleware in each
134
+ * service via DB lookup. This function is intentionally not
135
+ * the place for org permission checks.
136
+ *
137
+ * This makes the boundary explicit: callers that need org permission checks
138
+ * should use their service's tenant middleware, not isAllowed().
139
+ */
140
+ const isAllowed = (ctx, permission) => {
141
+ if (ctx.kind !== "human")
142
+ return false;
143
+ if (Object.values(enums_1.GlobalPermission).includes(permission)) {
144
+ return (0, exports.hasGlobalPermission)(ctx, permission);
145
+ }
146
+ // OrgPermission — not handled here by design.
147
+ // Use tenant middleware (DB-backed) within the relevant service.
148
+ return false;
149
+ };
150
+ exports.isAllowed = isAllowed;
151
+ /**
152
+ * isSuperAdmin
153
+ * Convenience guard for the rare cases where superadmin-only logic
154
+ * is needed beyond a single permission check.
155
+ */
156
+ const isSuperAdmin = (ctx) => {
157
+ if (ctx.kind !== "human")
158
+ return false;
159
+ return ctx.accountRole === enums_1.AccountRole.SUPERADMIN;
160
+ };
161
+ exports.isSuperAdmin = isSuperAdmin;
162
+ /**
163
+ * deriveGlobalPermissions
164
+ * Derives permissions for a role from the static map.
165
+ * Called by PermissionCacheService on a cold cache miss.
166
+ * Returns a mutable copy — callers can extend it if needed.
167
+ */
168
+ const deriveGlobalPermissions = (role) => {
169
+ return [...(exports.globalRolePermissions[role] ?? [])];
170
+ };
171
+ exports.deriveGlobalPermissions = deriveGlobalPermissions;
@@ -1,5 +1,5 @@
1
1
  import { AccountStatus } from "../enums";
2
- export interface AccountDTO {
2
+ export interface AccountDto {
3
3
  id: string;
4
4
  email: string;
5
5
  isVerified: boolean;
@@ -7,7 +7,7 @@ export interface AccountDTO {
7
7
  createdAt: Date;
8
8
  updatedAt: Date;
9
9
  }
10
- export interface EmailVerificationDTO {
10
+ export interface EmailVerificationDto {
11
11
  id: string;
12
12
  accountId: string;
13
13
  token: string;
@@ -15,17 +15,15 @@ export interface EmailVerificationDTO {
15
15
  isUsed: boolean;
16
16
  createdAt: Date;
17
17
  }
18
- export interface OAuthIdentityDTO {
18
+ export interface OAuthIdentityDto {
19
19
  id: string;
20
20
  accountId: string;
21
21
  provider: string;
22
22
  providerId: string;
23
- accessToken: string | null;
24
- refreshToken: string | null;
25
23
  createdAt: Date;
26
24
  updatedAt: Date;
27
25
  }
28
- export interface PasswordResetDTO {
26
+ export interface PasswordResetDto {
29
27
  id: string;
30
28
  accountId: string;
31
29
  token: string;
@@ -33,10 +31,9 @@ export interface PasswordResetDTO {
33
31
  isUsed: boolean;
34
32
  createdAt: Date;
35
33
  }
36
- export interface SessionDTO {
34
+ export interface SessionDto {
37
35
  id: string;
38
36
  accountId: string;
39
- token: string;
40
37
  expiresAt: Date;
41
38
  revokedAt: Date | null;
42
39
  ipAddress: string | null;
@@ -45,7 +42,3 @@ export interface SessionDTO {
45
42
  createdAt: Date;
46
43
  updatedAt: Date;
47
44
  }
48
- export interface TokensResponseDto {
49
- accessToken: string;
50
- refreshToken: string;
51
- }
@@ -1,5 +1,5 @@
1
1
  export interface ApiMeta {
2
- requestId: string | null;
2
+ requestId: string;
3
3
  timestamp: string;
4
4
  }
5
5
  export interface ApiSuccessResponse<T> {
@@ -10,39 +10,46 @@ export interface ApiSuccessResponse<T> {
10
10
  export interface ApiErrorResponse {
11
11
  success: false;
12
12
  error: {
13
- code?: string;
13
+ code: string;
14
14
  message: string;
15
15
  details?: unknown;
16
16
  };
17
17
  meta: ApiMeta;
18
18
  }
19
+ /**
20
+ * Returned on login / token refresh.
21
+ * accessToken goes in the response body.
22
+ * refreshToken goes in an HttpOnly cookie — not in the body.
23
+ * Only include refreshToken here if your client explicitly needs it
24
+ * (e.g. mobile clients that can't use cookies).
25
+ */
26
+ export interface TokensResponseDto {
27
+ accessToken: string;
28
+ }
29
+ /** Generic message — use for simple confirmations */
19
30
  export interface MessageResponseDto {
20
31
  message: string;
21
32
  }
22
- export interface LoggedOutResponseDto {
23
- loggedOut: boolean;
24
- }
25
- export interface LoggedOutAllResponseDto {
26
- loggedOutAll: boolean;
27
- }
28
- export interface SuspendedResponseDto {
29
- suspended: boolean;
30
- }
31
- export interface ActivatedResponseDto {
32
- activated: boolean;
33
- }
34
- export interface DeletedResponseDto {
35
- deleted: boolean;
36
- }
37
- export interface RevokedResponseDto {
38
- revoked: boolean;
39
- }
40
- export interface AddedResponseDto {
41
- added: boolean;
42
- }
43
- export interface UpdatedResponseDto {
44
- updated: boolean;
33
+ /**
34
+ * Generic action confirmation — use when the client needs to know
35
+ * which action was performed (e.g. in a polling or event-driven context).
36
+ *
37
+ * action: machine-readable string, e.g. "account.suspended", "session.revoked"
38
+ * message: human-readable description
39
+ */
40
+ export interface ActionResponseDto {
41
+ action: string;
42
+ message: string;
45
43
  }
46
- export interface CreatedResponseDto {
47
- created: boolean;
44
+ export interface PaginationMeta {
45
+ page: number;
46
+ pageSize: number;
47
+ totalItems: number;
48
+ totalPages: number;
49
+ hasNext: boolean;
50
+ hasPrev: boolean;
51
+ }
52
+ export interface PaginatedResponseDto<T> {
53
+ items: T[];
54
+ pagination: PaginationMeta;
48
55
  }
@@ -1,2 +1,6 @@
1
1
  "use strict";
2
+ /* ====================================================================
3
+ RESPONSE DTOs
4
+ Shared HTTP response shapes used across all services.
5
+ ==================================================================== */
2
6
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,14 +1,13 @@
1
- import { OrganizationRole, MembershipStatus, OrganizationStatus, Theme, Currency, UserStatus } from "../enums";
2
- export interface UserDTO {
1
+ import { AccountStatus, OrganizationRole, MembershipStatus, OrganizationStatus, Theme, Currency } from "../enums";
2
+ export interface UserDto {
3
3
  id: string;
4
4
  email: string;
5
- status: UserStatus;
5
+ status: AccountStatus;
6
6
  createdAt: Date;
7
7
  updatedAt: Date;
8
- deletedAt: Date | null;
9
8
  }
10
- export interface UserProfileDTO {
11
- id: string | null;
9
+ export interface UserProfileDto {
10
+ id: string;
12
11
  userId: string;
13
12
  displayName: string | null;
14
13
  avatarUrl: string | null;
@@ -20,10 +19,9 @@ export interface UserProfileDTO {
20
19
  pronouns: string | null;
21
20
  createdAt: Date;
22
21
  updatedAt: Date;
23
- deletedAt: Date | null;
24
22
  }
25
- export interface UserPreferencesDTO {
26
- id: string | null;
23
+ export interface UserPreferencesDto {
24
+ id: string;
27
25
  userId: string;
28
26
  theme: Theme;
29
27
  language: string;
@@ -31,9 +29,8 @@ export interface UserPreferencesDTO {
31
29
  emailAlerts: boolean;
32
30
  createdAt: Date;
33
31
  updatedAt: Date;
34
- deletedAt: Date | null;
35
32
  }
36
- export interface OrganizationDTO {
33
+ export interface OrganizationDto {
37
34
  id: string;
38
35
  name: string;
39
36
  slug: string;
@@ -42,7 +39,7 @@ export interface OrganizationDTO {
42
39
  updatedAt: Date;
43
40
  deletedAt: Date | null;
44
41
  }
45
- export interface OrganizationMemberDTO {
42
+ export interface OrganizationMemberDto {
46
43
  id: string;
47
44
  userId: string;
48
45
  organizationId: string;
@@ -50,5 +47,4 @@ export interface OrganizationMemberDTO {
50
47
  status: MembershipStatus;
51
48
  createdAt: Date;
52
49
  updatedAt: Date;
53
- deletedAt: Date | null;
54
50
  }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * DOMAIN STATUS & CONFIGURATION ENUMS
3
+ * ──────────────────────────────────────
4
+ * General-purpose enums for entity lifecycle, UI preferences, and
5
+ * configuration. Permission-related enums live in permissions.types.ts.
6
+ */
7
+ export declare enum AccountStatus {
8
+ ACTIVE = "ACTIVE",
9
+ SUSPENDED = "SUSPENDED",// Access revoked, data retained, reversible
10
+ DELETED = "DELETED"
11
+ }
12
+ export declare enum OrganizationStatus {
13
+ ACTIVE = "ACTIVE",
14
+ SUSPENDED = "SUSPENDED",// Platform-level suspension (non-payment, policy)
15
+ CLOSED = "CLOSED"
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
+ export declare enum MembershipStatus {
23
+ PENDING = "PENDING",
24
+ ACTIVE = "ACTIVE",
25
+ SUSPENDED = "SUSPENDED",
26
+ REMOVED = "REMOVED"
27
+ }
28
+ export declare enum Theme {
29
+ LIGHT = "LIGHT",
30
+ DARK = "DARK",
31
+ SYSTEM = "SYSTEM"
32
+ }
33
+ 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
41
+ SGD = "SGD"
42
+ }