@discover-cloud/shared 1.2.6 → 1.2.8

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.
@@ -2,11 +2,12 @@ import { ILogger } from "../utils";
2
2
  export declare class MachineTokenClient {
3
3
  private readonly gatewayUrl;
4
4
  private readonly serviceId;
5
+ private readonly internalSecret?;
5
6
  private readonly logger;
6
7
  private cache;
7
8
  private fetchPromise;
8
- constructor(gatewayUrl: string, serviceId: string, logger?: ILogger);
9
+ constructor(gatewayUrl: string, serviceId: string, internalSecret?: string | undefined, logger?: ILogger);
9
10
  getToken(requestId?: string): Promise<string>;
10
- private isValid;
11
+ private getValidCachedToken;
11
12
  private fetchToken;
12
13
  }
@@ -4,16 +4,18 @@ exports.MachineTokenClient = void 0;
4
4
  const utils_1 = require("../utils");
5
5
  const REFRESH_BUFFER_S = 10;
6
6
  class MachineTokenClient {
7
- constructor(gatewayUrl, serviceId, logger = utils_1.noopLogger) {
7
+ constructor(gatewayUrl, serviceId, internalSecret, logger = utils_1.noopLogger) {
8
8
  this.gatewayUrl = gatewayUrl;
9
9
  this.serviceId = serviceId;
10
+ this.internalSecret = internalSecret;
10
11
  this.logger = logger;
11
12
  this.cache = null;
12
13
  this.fetchPromise = null;
13
14
  }
14
15
  async getToken(requestId) {
15
- if (this.isValid()) {
16
- return this.cache.token;
16
+ const cachedToken = this.getValidCachedToken();
17
+ if (cachedToken) {
18
+ return cachedToken.token;
17
19
  }
18
20
  if (!this.fetchPromise) {
19
21
  this.fetchPromise = this.fetchToken(requestId).finally(() => {
@@ -22,21 +24,32 @@ class MachineTokenClient {
22
24
  }
23
25
  return this.fetchPromise;
24
26
  }
25
- isValid() {
26
- if (!this.cache)
27
- return false;
27
+ getValidCachedToken() {
28
+ if (!this.cache) {
29
+ return null;
30
+ }
28
31
  const nowS = Math.floor(Date.now() / 1000);
29
- return this.cache.expiresAt - REFRESH_BUFFER_S > nowS;
32
+ if (this.cache.expiresAt - REFRESH_BUFFER_S <= nowS) {
33
+ return null;
34
+ }
35
+ return this.cache;
30
36
  }
31
37
  async fetchToken(requestId) {
32
38
  const url = `${this.gatewayUrl}/internal/machine-token`;
33
39
  this.logger.debug({ serviceId: this.serviceId, requestId }, "Fetching machine token");
40
+ const headers = {
41
+ "content-type": "application/json",
42
+ };
43
+ if (this.internalSecret) {
44
+ headers["x-internal-secret"] = this.internalSecret;
45
+ }
34
46
  const response = await fetch(url, {
35
47
  method: "POST",
36
- headers: {
37
- "content-type": "application/json",
38
- },
39
- body: JSON.stringify({ serviceId: this.serviceId, requestId }),
48
+ headers,
49
+ body: JSON.stringify({
50
+ serviceId: this.serviceId,
51
+ requestId,
52
+ }),
40
53
  });
41
54
  if (!response.ok) {
42
55
  const text = await response.text().catch(() => "(unreadable)");
@@ -48,7 +61,10 @@ class MachineTokenClient {
48
61
  token: body.data.token,
49
62
  expiresAt: nowS + body.data.expiresIn,
50
63
  };
51
- this.logger.info({ serviceId: this.serviceId, expiresAt: this.cache.expiresAt }, "Machine token cached");
64
+ this.logger.info({
65
+ serviceId: this.serviceId,
66
+ expiresAt: this.cache.expiresAt,
67
+ }, "Machine token cached");
52
68
  return this.cache.token;
53
69
  }
54
70
  }
@@ -1,6 +1,5 @@
1
1
  import { Request, Response, NextFunction } from "express";
2
- import { AccountRole } from "../enums";
3
- import { GlobalPermission } from "../enums";
2
+ import { AccountRole, GlobalPermission } from "../enums";
4
3
  import { ILogger } from "../utils";
5
4
  import { InternalJwtVerifier } from "../jwt/internal-jwt-verifier";
6
5
  /**
@@ -4,7 +4,6 @@ exports.RequireAuthMiddleware = void 0;
4
4
  const jose_1 = require("jose");
5
5
  const utils_1 = require("../utils");
6
6
  const internal_jwt_verifier_1 = require("../jwt/internal-jwt-verifier");
7
- const utils_2 = require("../utils");
8
7
  /**
9
8
  * REQUIRE AUTH MIDDLEWARE (@discover-cloud/shared)
10
9
  * ─────────────────────────────────────────────────────────────────────────
@@ -53,7 +52,7 @@ class RequireAuthMiddleware {
53
52
  this.handle = async (req, res, next) => {
54
53
  const token = this.extractBearer(req);
55
54
  if (!token) {
56
- (0, utils_2.failure)(res, req, "Missing Authorization header", "UNAUTHORIZED", 401);
55
+ (0, utils_1.failure)(res, req, "Missing Authorization header", "UNAUTHORIZED", 401);
57
56
  return;
58
57
  }
59
58
  try {
@@ -83,11 +82,11 @@ class RequireAuthMiddleware {
83
82
  const ctx = req.accessContext;
84
83
  if (!ctx) {
85
84
  // Should not happen after handle() — indicates middleware ordering bug
86
- (0, utils_2.failure)(res, req, "No access context — ensure requireAuth runs first", "UNAUTHORIZED", 401);
85
+ (0, utils_1.failure)(res, req, "No access context — ensure requireAuth runs first", "UNAUTHORIZED", 401);
87
86
  return;
88
87
  }
89
88
  if (!internal_jwt_verifier_1.InternalJwtVerifier.hasPermission(ctx, permission)) {
90
- (0, utils_2.failure)(res, req, `Missing required permission: ${permission}`, "FORBIDDEN", 403);
89
+ (0, utils_1.failure)(res, req, `Missing required permission: ${permission}`, "FORBIDDEN", 403);
91
90
  return;
92
91
  }
93
92
  next();
@@ -101,11 +100,11 @@ class RequireAuthMiddleware {
101
100
  this.requireRole = (role) => (req, res, next) => {
102
101
  const ctx = req.accessContext;
103
102
  if (!ctx) {
104
- (0, utils_2.failure)(res, req, "No access context — ensure requireAuth runs first", "UNAUTHORIZED", 401);
103
+ (0, utils_1.failure)(res, req, "No access context — ensure requireAuth runs first", "UNAUTHORIZED", 401);
105
104
  return;
106
105
  }
107
106
  if (!internal_jwt_verifier_1.InternalJwtVerifier.hasRole(ctx, role)) {
108
- (0, utils_2.failure)(res, req, `Missing required role: ${role}`, "FORBIDDEN", 403);
107
+ (0, utils_1.failure)(res, req, `Missing required role: ${role}`, "FORBIDDEN", 403);
109
108
  return;
110
109
  }
111
110
  next();
@@ -145,19 +144,19 @@ class RequireAuthMiddleware {
145
144
  */
146
145
  handleJwtError(err, req, res) {
147
146
  if (err instanceof jose_1.errors.JWTExpired) {
148
- (0, utils_2.failure)(res, req, "Your session has expired. Please log in again.", "TOKEN_EXPIRED", 401);
147
+ (0, utils_1.failure)(res, req, "Your session has expired. Please log in again.", "TOKEN_EXPIRED", 401);
149
148
  return;
150
149
  }
151
150
  if (err instanceof jose_1.errors.JWTClaimValidationFailed ||
152
151
  err instanceof jose_1.errors.JWSSignatureVerificationFailed ||
153
152
  err instanceof jose_1.errors.JWSInvalid ||
154
153
  err instanceof jose_1.errors.JWTInvalid) {
155
- (0, utils_2.failure)(res, req, "Token is invalid or has been tampered with.", "INVALID_TOKEN", 401);
154
+ (0, utils_1.failure)(res, req, "Token is invalid or has been tampered with.", "INVALID_TOKEN", 401);
156
155
  return;
157
156
  }
158
157
  // Unexpected error — log for investigation, return a safe 503
159
158
  this.logger.error({ err, requestId: req.id }, "RequireAuthMiddleware: unexpected error during JWT verification");
160
- (0, utils_2.failure)(res, req, "Authentication service is temporarily unavailable.", "SERVICE_UNAVAILABLE", 503);
159
+ (0, utils_1.failure)(res, req, "Authentication service is temporarily unavailable.", "SERVICE_UNAVAILABLE", 503);
161
160
  }
162
161
  }
163
162
  exports.RequireAuthMiddleware = RequireAuthMiddleware;
package/package.json CHANGED
@@ -1,36 +1,36 @@
1
- {
2
- "name": "@discover-cloud/shared",
3
- "version": "1.2.6",
4
- "private": false,
5
- "type": "commonjs",
6
- "main": "dist/index.js",
7
- "types": "dist/index.d.ts",
8
- "files": [
9
- "dist"
10
- ],
11
- "scripts": {
12
- "build": "tsc -p tsconfig.json",
13
- "prepublishOnly": "npm run build"
14
- },
15
- "publishConfig": {
16
- "access": "public"
17
- },
18
- "dependencies": {
19
- "axios-retry": "^4.5.0",
20
- "jose": "^6.1.3",
21
- "redis": "^5.11.0"
22
- },
23
- "peerDependencies": {
24
- "axios": "^1.13.5",
25
- "express": "^5.2.1",
26
- "zod": "^4.3.6"
27
- },
28
- "devDependencies": {
29
- "@types/express": "^5.0.6",
30
- "@types/node": "^25.3.0",
31
- "axios": "^1.13.5",
32
- "express": "^5.2.1",
33
- "typescript": "^5.9.3",
34
- "zod": "^4.3.6"
35
- }
36
- }
1
+ {
2
+ "name": "@discover-cloud/shared",
3
+ "version": "1.2.8",
4
+ "private": false,
5
+ "type": "commonjs",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "scripts": {
12
+ "build": "tsc -p tsconfig.json",
13
+ "prepublishOnly": "npm run build"
14
+ },
15
+ "publishConfig": {
16
+ "access": "public"
17
+ },
18
+ "dependencies": {
19
+ "axios-retry": "^4.5.0",
20
+ "jose": "^6.1.3",
21
+ "redis": "^5.11.0"
22
+ },
23
+ "peerDependencies": {
24
+ "axios": "^1.13.5",
25
+ "express": "^5.2.1",
26
+ "zod": "^4.3.6"
27
+ },
28
+ "devDependencies": {
29
+ "@types/express": "^5.0.6",
30
+ "@types/node": "^25.3.0",
31
+ "axios": "^1.13.5",
32
+ "express": "^5.2.1",
33
+ "typescript": "^5.9.3",
34
+ "zod": "^4.3.6"
35
+ }
36
+ }