@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.
- package/dist/authorization/index.d.ts +2 -0
- package/dist/authorization/index.js +18 -0
- package/dist/authorization/permission-cache.service.d.ts +12 -0
- package/dist/authorization/permission-cache.service.js +132 -0
- package/dist/authorization/permissions.d.ts +74 -0
- package/dist/authorization/permissions.js +171 -0
- package/dist/dto/auth-service.dtos.d.ts +5 -12
- package/dist/dto/response.dtos.d.ts +34 -27
- package/dist/dto/response.dtos.js +4 -0
- package/dist/dto/user-service.dtos.d.ts +9 -13
- package/dist/enums/domain.enums.d.ts +42 -0
- package/dist/enums/domain.enums.js +79 -0
- package/dist/enums/index.d.ts +2 -3
- package/dist/enums/index.js +2 -3
- package/dist/enums/permissions.enums.d.ts +124 -0
- package/dist/enums/permissions.enums.js +141 -0
- package/dist/errors/app-error.d.ts +19 -2
- package/dist/errors/app-error.js +17 -2
- package/dist/errors/http-errors.d.ts +18 -0
- package/dist/errors/http-errors.js +25 -1
- package/dist/http/index.d.ts +1 -0
- package/dist/http/index.js +17 -0
- package/dist/http/service-client.d.ts +23 -7
- package/dist/http/service-client.js +54 -22
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/jwt/index.d.ts +1 -2
- package/dist/jwt/index.js +1 -2
- package/dist/jwt/internal-jwt-verifier.d.ts +35 -0
- package/dist/jwt/internal-jwt-verifier.js +162 -0
- package/dist/middleware/authorize.middleware.d.ts +22 -0
- package/dist/middleware/authorize.middleware.js +77 -0
- package/dist/middleware/error-handler.middleware.d.ts +23 -0
- package/dist/middleware/error-handler.middleware.js +52 -0
- package/dist/middleware/index.d.ts +4 -5
- package/dist/middleware/index.js +4 -5
- package/dist/middleware/request-id.middleware.d.ts +20 -0
- package/dist/middleware/request-id.middleware.js +34 -0
- package/dist/middleware/validate.middleware.d.ts +26 -0
- package/dist/middleware/validate.middleware.js +41 -0
- package/dist/types/express.types.d.ts +148 -0
- package/dist/types/express.types.js +42 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.js +1 -1
- package/dist/utils/response.d.ts +2 -1
- package/dist/utils/response.js +6 -3
- package/package.json +3 -2
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EXPRESS TYPE AUGMENTATION + JWT PAYLOAD TYPES
|
|
3
|
+
* ───────────────────────────────────────────────
|
|
4
|
+
* Single source of truth for everything attached to Express's Request object
|
|
5
|
+
* and all internal JWT payload shapes.
|
|
6
|
+
*
|
|
7
|
+
* Belongs in @discover-cloud/shared — import in each service's entrypoint:
|
|
8
|
+
* import "@discover-cloud/shared/types/express";
|
|
9
|
+
*
|
|
10
|
+
* ─── Permission flow ────────────────────────────────────────────────
|
|
11
|
+
* JWT carries: accountId + accountRole (lean, no perms)
|
|
12
|
+
* Cache derives: GlobalPermission[] (Redis → role map on miss)
|
|
13
|
+
* AccessContext has: perms (populated by auth middleware)
|
|
14
|
+
*
|
|
15
|
+
* perms never touch the JWT — they live in the permission cache and are
|
|
16
|
+
* resolved into req.accessContext by RequireAuthMiddleware on every request.
|
|
17
|
+
*/
|
|
18
|
+
import "express-serve-static-core";
|
|
19
|
+
import { JWTPayload } from "jose";
|
|
20
|
+
import { AccountRole } from "../enums";
|
|
21
|
+
import { GlobalPermission } from "../enums";
|
|
22
|
+
interface BaseInternalJwtPayload extends JWTPayload {
|
|
23
|
+
/**
|
|
24
|
+
* JWT ID — REQUIRED.
|
|
25
|
+
* Used for the Redis kill-switch (session revocation / account suspension).
|
|
26
|
+
* Overrides JWTPayload's optional jti with required.
|
|
27
|
+
*/
|
|
28
|
+
jti: string;
|
|
29
|
+
/** typ discriminator — guards against token type confusion attacks */
|
|
30
|
+
typ: "internal";
|
|
31
|
+
/**
|
|
32
|
+
* The entity that last minted or forwarded this token.
|
|
33
|
+
* "api-gateway" → direct user-initiated request
|
|
34
|
+
* "order-service" → service-to-service call on behalf of a user
|
|
35
|
+
* Used for audit logging and conditional authorization.
|
|
36
|
+
*/
|
|
37
|
+
caller: string;
|
|
38
|
+
/**
|
|
39
|
+
* Propagated request ID for distributed tracing.
|
|
40
|
+
* Ties together logs across the entire service call chain.
|
|
41
|
+
*/
|
|
42
|
+
requestId?: string;
|
|
43
|
+
iss: string;
|
|
44
|
+
aud: string | string[];
|
|
45
|
+
iat: number;
|
|
46
|
+
exp: number;
|
|
47
|
+
nbf: number;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Human JWT payload — issued on behalf of an authenticated user.
|
|
51
|
+
* Minted by the gateway after verifying an external JWT.
|
|
52
|
+
*
|
|
53
|
+
* accountRole is carried so the permission cache can derive perms
|
|
54
|
+
* from globalRolePermissions on a cold cache miss — without a DB call.
|
|
55
|
+
*/
|
|
56
|
+
export interface HumanInternalJwtPayload extends BaseInternalJwtPayload {
|
|
57
|
+
isMachine: false;
|
|
58
|
+
accountId: string;
|
|
59
|
+
accountRole: AccountRole;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Machine JWT payload — service-to-service calls with no user context.
|
|
63
|
+
* Intentionally carries NO user fields — absence is enforced by the type.
|
|
64
|
+
*/
|
|
65
|
+
export interface MachineInternalJwtPayload extends BaseInternalJwtPayload {
|
|
66
|
+
isMachine: true;
|
|
67
|
+
serviceId: string;
|
|
68
|
+
}
|
|
69
|
+
/** The full internal JWT payload union — use this in verifiers and auth middleware */
|
|
70
|
+
export type InternalJwtPayload = HumanInternalJwtPayload | MachineInternalJwtPayload;
|
|
71
|
+
export interface HumanAccessContext {
|
|
72
|
+
kind: "human";
|
|
73
|
+
accountId: string;
|
|
74
|
+
accountRole: AccountRole;
|
|
75
|
+
/**
|
|
76
|
+
* Resolved from Redis permission cache — NOT from the JWT.
|
|
77
|
+
* Always present by the time req.accessContext is set.
|
|
78
|
+
* Invalidated on role change, suspension, and account deletion.
|
|
79
|
+
*/
|
|
80
|
+
perms: GlobalPermission[];
|
|
81
|
+
}
|
|
82
|
+
export interface MachineAccessContext {
|
|
83
|
+
kind: "machine";
|
|
84
|
+
serviceId: string;
|
|
85
|
+
}
|
|
86
|
+
export type AccessContext = HumanAccessContext | MachineAccessContext;
|
|
87
|
+
export declare function isHumanPayload(payload: InternalJwtPayload): payload is HumanInternalJwtPayload;
|
|
88
|
+
export declare function isMachinePayload(payload: InternalJwtPayload): payload is MachineInternalJwtPayload;
|
|
89
|
+
export declare function isHumanContext(ctx: AccessContext): ctx is HumanAccessContext;
|
|
90
|
+
export declare function isMachineContext(ctx: AccessContext): ctx is MachineAccessContext;
|
|
91
|
+
export interface VerifiedAccessPayload {
|
|
92
|
+
accountId: string;
|
|
93
|
+
accountRole: AccountRole;
|
|
94
|
+
typ: "access";
|
|
95
|
+
iss: string;
|
|
96
|
+
aud: string | string[];
|
|
97
|
+
iat: number;
|
|
98
|
+
exp: number;
|
|
99
|
+
nbf: number;
|
|
100
|
+
jti: string;
|
|
101
|
+
}
|
|
102
|
+
export interface VerifiedRefreshPayload {
|
|
103
|
+
accountId: string;
|
|
104
|
+
typ: "refresh";
|
|
105
|
+
iss: string;
|
|
106
|
+
aud: string | string[];
|
|
107
|
+
iat: number;
|
|
108
|
+
exp: number;
|
|
109
|
+
nbf: number;
|
|
110
|
+
jti: string;
|
|
111
|
+
}
|
|
112
|
+
declare module "express-serve-static-core" {
|
|
113
|
+
interface Request {
|
|
114
|
+
/**
|
|
115
|
+
* Unique request ID — set by requestId middleware.
|
|
116
|
+
* Respects upstream x-request-id from the gateway / load balancer.
|
|
117
|
+
* Always present after requestId middleware runs.
|
|
118
|
+
*/
|
|
119
|
+
id: string;
|
|
120
|
+
/**
|
|
121
|
+
* Validated + parsed request body/query/params/headers.
|
|
122
|
+
* Typed as unknown — narrow at the route level:
|
|
123
|
+
*
|
|
124
|
+
* const body = req.validated as z.infer<typeof CreateOrderSchema>;
|
|
125
|
+
*
|
|
126
|
+
* Never cast to any.
|
|
127
|
+
*/
|
|
128
|
+
validated?: unknown;
|
|
129
|
+
/**
|
|
130
|
+
* Raw verified internal JWT payload.
|
|
131
|
+
* Set by RequireAuthMiddleware after InternalJwtVerifier.verifyInternal().
|
|
132
|
+
*
|
|
133
|
+
* Prefer req.accessContext in route handlers.
|
|
134
|
+
* Access this only when you need raw JWT claims (e.g. jti for blacklisting).
|
|
135
|
+
*/
|
|
136
|
+
internalAuth?: InternalJwtPayload;
|
|
137
|
+
/**
|
|
138
|
+
* Clean access context — built from internalAuth + permission cache.
|
|
139
|
+
* This is what route handlers, controllers, and domain services use.
|
|
140
|
+
*
|
|
141
|
+
* if (isHumanContext(req.accessContext)) {
|
|
142
|
+
* const { accountId, accountRole, perms } = req.accessContext;
|
|
143
|
+
* }
|
|
144
|
+
*/
|
|
145
|
+
accessContext?: AccessContext;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* EXPRESS TYPE AUGMENTATION + JWT PAYLOAD TYPES
|
|
4
|
+
* ───────────────────────────────────────────────
|
|
5
|
+
* Single source of truth for everything attached to Express's Request object
|
|
6
|
+
* and all internal JWT payload shapes.
|
|
7
|
+
*
|
|
8
|
+
* Belongs in @discover-cloud/shared — import in each service's entrypoint:
|
|
9
|
+
* import "@discover-cloud/shared/types/express";
|
|
10
|
+
*
|
|
11
|
+
* ─── Permission flow ────────────────────────────────────────────────
|
|
12
|
+
* JWT carries: accountId + accountRole (lean, no perms)
|
|
13
|
+
* Cache derives: GlobalPermission[] (Redis → role map on miss)
|
|
14
|
+
* AccessContext has: perms (populated by auth middleware)
|
|
15
|
+
*
|
|
16
|
+
* perms never touch the JWT — they live in the permission cache and are
|
|
17
|
+
* resolved into req.accessContext by RequireAuthMiddleware on every request.
|
|
18
|
+
*/
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.isHumanPayload = isHumanPayload;
|
|
21
|
+
exports.isMachinePayload = isMachinePayload;
|
|
22
|
+
exports.isHumanContext = isHumanContext;
|
|
23
|
+
exports.isMachineContext = isMachineContext;
|
|
24
|
+
require("express-serve-static-core");
|
|
25
|
+
/* ====================================================================
|
|
26
|
+
4. TYPE GUARDS
|
|
27
|
+
|
|
28
|
+
Use these over raw property checks — TypeScript narrows correctly
|
|
29
|
+
through them on both InternalJwtPayload and AccessContext.
|
|
30
|
+
==================================================================== */
|
|
31
|
+
function isHumanPayload(payload) {
|
|
32
|
+
return payload.isMachine === false;
|
|
33
|
+
}
|
|
34
|
+
function isMachinePayload(payload) {
|
|
35
|
+
return payload.isMachine === true;
|
|
36
|
+
}
|
|
37
|
+
function isHumanContext(ctx) {
|
|
38
|
+
return ctx.kind === "human";
|
|
39
|
+
}
|
|
40
|
+
function isMachineContext(ctx) {
|
|
41
|
+
return ctx.kind === "machine";
|
|
42
|
+
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export * from "./express";
|
|
1
|
+
export * from "./express.types";
|
package/dist/types/index.js
CHANGED
|
@@ -14,4 +14,4 @@ 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("./express"), exports);
|
|
17
|
+
__exportStar(require("./express.types"), exports);
|
package/dist/utils/response.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import { Response } from "express";
|
|
2
2
|
export declare const success: <T>(res: Response, data: T, statusCode?: number) => Response<any, Record<string, any>>;
|
|
3
|
-
export declare const failure: (res: Response, message: string,
|
|
3
|
+
export declare const failure: (res: Response, message: string, code: string, // <-- Added to match the DTO requirement
|
|
4
|
+
statusCode?: number, details?: unknown) => Response<any, Record<string, any>>;
|
package/dist/utils/response.js
CHANGED
|
@@ -2,28 +2,31 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.failure = exports.success = void 0;
|
|
4
4
|
const success = (res, data, statusCode = 200) => {
|
|
5
|
+
// Cast to Request to access properties safely, assuming module augmentation
|
|
5
6
|
const req = res.req;
|
|
6
7
|
const response = {
|
|
7
8
|
success: true,
|
|
8
9
|
data,
|
|
9
10
|
meta: {
|
|
10
|
-
requestId: req
|
|
11
|
+
requestId: req.id ?? "unknown", // Fallback if middleware failed
|
|
11
12
|
timestamp: new Date().toISOString()
|
|
12
13
|
}
|
|
13
14
|
};
|
|
14
15
|
return res.status(statusCode).json(response);
|
|
15
16
|
};
|
|
16
17
|
exports.success = success;
|
|
17
|
-
const failure = (res, message,
|
|
18
|
+
const failure = (res, message, code, // <-- Added to match the DTO requirement
|
|
19
|
+
statusCode = 400, details) => {
|
|
18
20
|
const req = res.req;
|
|
19
21
|
const response = {
|
|
20
22
|
success: false,
|
|
21
23
|
error: {
|
|
24
|
+
code, // <-- Added here
|
|
22
25
|
message,
|
|
23
26
|
details: details ?? null
|
|
24
27
|
},
|
|
25
28
|
meta: {
|
|
26
|
-
requestId: req
|
|
29
|
+
requestId: req.id ?? "unknown",
|
|
27
30
|
timestamp: new Date().toISOString()
|
|
28
31
|
}
|
|
29
32
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@discover-cloud/shared",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"axios-retry": "^4.5.0",
|
|
20
|
-
"jose": "^6.1.3"
|
|
20
|
+
"jose": "^6.1.3",
|
|
21
|
+
"redis": "^5.11.0"
|
|
21
22
|
},
|
|
22
23
|
"peerDependencies": {
|
|
23
24
|
"axios": "^1.13.5",
|