@usageflow/express 0.1.4 → 0.1.6
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/plugin.d.ts +6 -13
- package/dist/plugin.js +32 -79
- package/dist/plugin.js.map +1 -1
- package/dist/utils.d.ts +3 -0
- package/dist/utils.js +139 -0
- package/dist/utils.js.map +1 -0
- package/package.json +10 -4
- package/src/plugin.ts +41 -104
package/dist/plugin.d.ts
CHANGED
|
@@ -1,19 +1,12 @@
|
|
|
1
1
|
import { Request, Response, NextFunction } from "express";
|
|
2
|
-
import { UsageFlowAPI, Route
|
|
3
|
-
declare global {
|
|
4
|
-
namespace Express {
|
|
5
|
-
interface Request {
|
|
6
|
-
usageflow?: {
|
|
7
|
-
startTime: number;
|
|
8
|
-
eventId?: string;
|
|
9
|
-
metadata?: RequestMetadata;
|
|
10
|
-
};
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
}
|
|
2
|
+
import { UsageFlowAPI, Route } from "@usageflow/core";
|
|
14
3
|
export declare class ExpressUsageFlowAPI extends UsageFlowAPI {
|
|
4
|
+
/**
|
|
5
|
+
* Get the route pattern (e.g., /express/users/:id) from the request
|
|
6
|
+
* Tries multiple methods to get the route pattern since request.route
|
|
7
|
+
* may not be available in middleware that runs before route matching
|
|
8
|
+
*/
|
|
15
9
|
private collectRequestMetadata;
|
|
16
10
|
private executeRequestWithMetadata;
|
|
17
11
|
createMiddleware(routes: Route[], whitelistRoutes?: Route[]): (request: Request, response: Response, next: NextFunction) => Promise<void>;
|
|
18
|
-
protected guessLedgerId(request: Request): string;
|
|
19
12
|
}
|
package/dist/plugin.js
CHANGED
|
@@ -3,6 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ExpressUsageFlowAPI = void 0;
|
|
4
4
|
const core_1 = require("@usageflow/core");
|
|
5
5
|
class ExpressUsageFlowAPI extends core_1.UsageFlowAPI {
|
|
6
|
+
/**
|
|
7
|
+
* Get the route pattern (e.g., /express/users/:id) from the request
|
|
8
|
+
* Tries multiple methods to get the route pattern since request.route
|
|
9
|
+
* may not be available in middleware that runs before route matching
|
|
10
|
+
*/
|
|
6
11
|
async collectRequestMetadata(request) {
|
|
7
12
|
const headers = this.sanitizeHeaders(request.headers);
|
|
8
13
|
// Get client IP, handling forwarded headers
|
|
@@ -11,9 +16,20 @@ class ExpressUsageFlowAPI extends core_1.UsageFlowAPI {
|
|
|
11
16
|
if (forwardedFor && typeof forwardedFor === "string") {
|
|
12
17
|
clientIP = forwardedFor.split(",")[0].trim();
|
|
13
18
|
}
|
|
19
|
+
const routePattern = request.route?.path || request.app._router.stack.find((route) => {
|
|
20
|
+
// a => a.path == request.url
|
|
21
|
+
if (!route.route)
|
|
22
|
+
return false;
|
|
23
|
+
if (route.path) {
|
|
24
|
+
return route.path == request.url;
|
|
25
|
+
}
|
|
26
|
+
if (route.regexp) {
|
|
27
|
+
return route.regexp.test(request.url);
|
|
28
|
+
}
|
|
29
|
+
})?.route?.path || request.url;
|
|
14
30
|
const metadata = {
|
|
15
31
|
method: request.method,
|
|
16
|
-
url:
|
|
32
|
+
url: routePattern,
|
|
17
33
|
rawUrl: request.originalUrl || "/",
|
|
18
34
|
clientIP: clientIP || "unknown",
|
|
19
35
|
userAgent: request.headers["user-agent"],
|
|
@@ -29,40 +45,13 @@ class ExpressUsageFlowAPI extends core_1.UsageFlowAPI {
|
|
|
29
45
|
if (!this.apiKey) {
|
|
30
46
|
throw new Error("API key not initialized");
|
|
31
47
|
}
|
|
32
|
-
const headers = {
|
|
33
|
-
"x-usage-key": this.apiKey,
|
|
34
|
-
"Content-Type": "application/json",
|
|
35
|
-
};
|
|
36
48
|
const payload = {
|
|
37
49
|
alias: ledgerId,
|
|
38
50
|
amount: 1,
|
|
39
51
|
metadata,
|
|
52
|
+
duration: 1000
|
|
40
53
|
};
|
|
41
|
-
|
|
42
|
-
const response = await fetch(`${this.usageflowUrl}/api/v1/ledgers/measure/allocate`, {
|
|
43
|
-
method: "POST",
|
|
44
|
-
headers,
|
|
45
|
-
body: JSON.stringify(payload),
|
|
46
|
-
});
|
|
47
|
-
const data = await response.json();
|
|
48
|
-
if (response.status === 400) {
|
|
49
|
-
throw new Error(data.message);
|
|
50
|
-
}
|
|
51
|
-
if (response.ok) {
|
|
52
|
-
request.usageflow.eventId = data.eventId;
|
|
53
|
-
request.usageflow.metadata = metadata;
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
throw new Error(data.message || "Unknown error occurred");
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
catch (error) {
|
|
60
|
-
if (error.message ==
|
|
61
|
-
"Failed to use resource after retries: Faile to preform operation") {
|
|
62
|
-
throw new Error("Failed to allocate resource");
|
|
63
|
-
}
|
|
64
|
-
throw error;
|
|
65
|
-
}
|
|
54
|
+
await this.allocationRequest(request, payload, metadata);
|
|
66
55
|
}
|
|
67
56
|
createMiddleware(routes, whitelistRoutes = []) {
|
|
68
57
|
const routesMap = this.createRoutesMap(routes);
|
|
@@ -70,7 +59,8 @@ class ExpressUsageFlowAPI extends core_1.UsageFlowAPI {
|
|
|
70
59
|
const self = this;
|
|
71
60
|
return async (request, response, next) => {
|
|
72
61
|
const method = request.method;
|
|
73
|
-
const
|
|
62
|
+
const routePattern = self.getRoutePattern(request);
|
|
63
|
+
const url = routePattern;
|
|
74
64
|
request.usageflow = {
|
|
75
65
|
startTime: Date.now(),
|
|
76
66
|
};
|
|
@@ -81,8 +71,10 @@ class ExpressUsageFlowAPI extends core_1.UsageFlowAPI {
|
|
|
81
71
|
return next();
|
|
82
72
|
}
|
|
83
73
|
const metadata = await this.collectRequestMetadata(request);
|
|
74
|
+
metadata.url = url;
|
|
75
|
+
let ledgerId = this.guessLedgerId(request);
|
|
84
76
|
try {
|
|
85
|
-
await this.executeRequestWithMetadata(
|
|
77
|
+
await this.executeRequestWithMetadata(ledgerId, metadata, request, response);
|
|
86
78
|
// Capture response data
|
|
87
79
|
const originalEnd = response.end;
|
|
88
80
|
response.end = function (chunk, encoding, cb) {
|
|
@@ -134,18 +126,16 @@ class ExpressUsageFlowAPI extends core_1.UsageFlowAPI {
|
|
|
134
126
|
Date.now() - request.usageflow.startTime;
|
|
135
127
|
}
|
|
136
128
|
const payload = {
|
|
137
|
-
alias:
|
|
129
|
+
alias: ledgerId,
|
|
138
130
|
amount: 1,
|
|
139
131
|
allocationId: request.usageflow?.eventId,
|
|
140
|
-
metadata,
|
|
132
|
+
metadata: metadata,
|
|
141
133
|
};
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
body: JSON.stringify(payload),
|
|
146
|
-
}).catch((error) => {
|
|
147
|
-
console.error("Error finalizing request:", error);
|
|
134
|
+
self.useAllocationRequest(payload).catch((err) => {
|
|
135
|
+
console.error("[UsageFlow] Error finalizing allocation request:", err);
|
|
136
|
+
throw err;
|
|
148
137
|
});
|
|
138
|
+
// Send via WebSocket if connected
|
|
149
139
|
// Handle the different overloadsx
|
|
150
140
|
if (typeof chunk === "function") {
|
|
151
141
|
return originalEnd.call(this, undefined, "utf8", chunk);
|
|
@@ -158,7 +148,8 @@ class ExpressUsageFlowAPI extends core_1.UsageFlowAPI {
|
|
|
158
148
|
next();
|
|
159
149
|
}
|
|
160
150
|
catch (error) {
|
|
161
|
-
console.error("Error executing request with metadata:", error);
|
|
151
|
+
console.error("[UsageFlow] Error executing request with metadata:", error);
|
|
152
|
+
console.error("[UsageFlow] Error stack:", error?.stack);
|
|
162
153
|
response.status(400).json({
|
|
163
154
|
message: error.message,
|
|
164
155
|
blocked: true,
|
|
@@ -167,44 +158,6 @@ class ExpressUsageFlowAPI extends core_1.UsageFlowAPI {
|
|
|
167
158
|
}
|
|
168
159
|
};
|
|
169
160
|
}
|
|
170
|
-
guessLedgerId(request) {
|
|
171
|
-
const method = request.method;
|
|
172
|
-
const url = request.route?.path || request.path;
|
|
173
|
-
const config = this.apiConfig;
|
|
174
|
-
if (!config?.identityFieldName || !config?.identityFieldLocation) {
|
|
175
|
-
return `${method} ${url}`;
|
|
176
|
-
}
|
|
177
|
-
const fieldName = config.identityFieldName;
|
|
178
|
-
const location = config.identityFieldLocation;
|
|
179
|
-
switch (location) {
|
|
180
|
-
case "path_params":
|
|
181
|
-
if (request.params?.[fieldName]) {
|
|
182
|
-
return `${method} ${url} ${request.params[fieldName]}`;
|
|
183
|
-
}
|
|
184
|
-
break;
|
|
185
|
-
case "query_params":
|
|
186
|
-
if (request.query?.[fieldName]) {
|
|
187
|
-
return `${method} ${url} ${request.query[fieldName]}`;
|
|
188
|
-
}
|
|
189
|
-
break;
|
|
190
|
-
case "body":
|
|
191
|
-
if (request.body?.[fieldName]) {
|
|
192
|
-
return `${method} ${url} ${request.body[fieldName]}`;
|
|
193
|
-
}
|
|
194
|
-
break;
|
|
195
|
-
case "bearer_token":
|
|
196
|
-
const authHeader = request.headers.authorization;
|
|
197
|
-
const token = this.extractBearerToken(authHeader);
|
|
198
|
-
if (token) {
|
|
199
|
-
const claims = this.decodeJwtUnverified(token);
|
|
200
|
-
if (claims?.[fieldName]) {
|
|
201
|
-
return `${method} ${url} ${claims[fieldName]}`;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
break;
|
|
205
|
-
}
|
|
206
|
-
return `${method} ${url}`;
|
|
207
|
-
}
|
|
208
161
|
}
|
|
209
162
|
exports.ExpressUsageFlowAPI = ExpressUsageFlowAPI;
|
|
210
163
|
//# sourceMappingURL=plugin.js.map
|
package/dist/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":";;;AACA,
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":";;;AACA,0CAA+G;AAI/G,MAAa,mBAAoB,SAAQ,mBAAY;IACjD;;;;OAIG;IAEK,KAAK,CAAC,sBAAsB,CAChC,OAAgB;QAEhB,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,CAChC,OAAO,CAAC,OAAiC,CAC5C,CAAC;QAEF,4CAA4C;QAC5C,IAAI,QAAQ,GAAG,OAAO,CAAC,EAAE,CAAC;QAC1B,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;QACxD,IAAI,YAAY,IAAI,OAAO,YAAY,KAAK,QAAQ,EAAE,CAAC;YACnD,QAAQ,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACjD,CAAC;QAED,MAAM,YAAY,GAAG,OAAO,CAAC,KAAK,EAAE,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAU,EAAE,EAAE;YACtF,6BAA6B;YAC7B,IAAI,CAAC,KAAK,CAAC,KAAK;gBAAE,OAAO,KAAK,CAAC;YAC/B,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;gBACb,OAAO,KAAK,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC;YACrC,CAAC;YAED,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;gBACf,OAAO,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAC1C,CAAC;QAEL,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC;QAE/B,MAAM,QAAQ,GAAoB;YAC9B,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,GAAG,EAAE,YAAY;YACjB,MAAM,EAAE,OAAO,CAAC,WAAW,IAAI,GAAG;YAClC,QAAQ,EAAE,QAAQ,IAAI,SAAS;YAC/B,SAAS,EAAE,OAAO,CAAC,OAAO,CAAC,YAAY,CAAW;YAClD,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,OAAO;YACP,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI;YACzE,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI;YAC1E,IAAI,EAAE,OAAO,CAAC,IAAI;SACrB,CAAC;QAEF,OAAO,QAAQ,CAAC;IACpB,CAAC;IAEO,KAAK,CAAC,0BAA0B,CACpC,QAAgB,EAChB,QAAyB,EACzB,OAAgB,EAChB,QAAkB;QAElB,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;QAC/C,CAAC;QAED,MAAM,OAAO,GAAG;YACZ,KAAK,EAAE,QAAQ;YACf,MAAM,EAAE,CAAC;YACT,QAAQ;YACR,QAAQ,EAAE,IAAI;SACjB,CAAC;QAEF,MAAM,IAAI,CAAC,iBAAiB,CAAC,OAAsC,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC5F,CAAC;IAEM,gBAAgB,CAAC,MAAe,EAAE,kBAA2B,EAAE;QAClE,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;QAC/C,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,CAAC,eAAe,CAAC,CAAC;QAC3D,MAAM,IAAI,GAAG,IAAI,CAAC;QAGlB,OAAO,KAAK,EAAE,OAAgB,EAAE,QAAkB,EAAE,IAAkB,EAAE,EAAE;YACtE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAC9B,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;YACnD,MAAM,GAAG,GAAG,YAAY,CAAC;YAEzB,OAAO,CAAC,SAAS,GAAG;gBAChB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;aACxB,CAAC;YAEF,IAAI,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,GAAG,IAAI,EAAE,EAAE,YAAY,CAAC,EAAE,CAAC;gBACxD,OAAO,IAAI,EAAE,CAAC;YAClB,CAAC;YAED,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,MAAM,EAAE,GAAG,IAAI,EAAE,EAAE,SAAS,CAAC,EAAE,CAAC;gBACzD,OAAO,IAAI,EAAE,CAAC;YAClB,CAAC;YAED,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC;YAC5D,QAAQ,CAAC,GAAG,GAAG,GAAG,CAAC;YACnB,IAAI,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;YAE3C,IAAI,CAAC;gBACD,MAAM,IAAI,CAAC,0BAA0B,CACjC,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,QAAQ,CACX,CAAC;gBAEF,wBAAwB;gBACxB,MAAM,WAAW,GAAG,QAAQ,CAAC,GAAG,CAAC;gBACjC,QAAQ,CAAC,GAAG,GAAG,UAEX,KAAW,EACX,QAAyB,EACzB,EAAe;oBAEf,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,EAAE,CAAC;wBAC9B,OAAO,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,IAAI,MAAM,EAAE,EAAE,CAAC,CAAC;oBACjE,CAAC;oBAED,MAAM,QAAQ,GACV,OAAO,CAAC,SAAS,EAAE,QAAQ,IAAI,EAAE,CAAC;oBACtC,QAAQ,CAAC,kBAAkB,GAAG,QAAQ,CAAC,UAAU,CAAC;oBAElD,6CAA6C;oBAC7C,IAAI,KAAK,EAAE,CAAC;wBACR,IAAI,CAAC;4BACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;gCAC5B,wCAAwC;gCACxC,IAAI,CAAC;oCACD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;oCAChC,QAAgB,CAAC,IAAI,GAAG,MAAM,CAAC;gCACpC,CAAC;gCAAC,MAAM,CAAC;oCACL,0CAA0C;oCACzC,QAAgB,CAAC,IAAI,GAAG,KAAK,CAAC;gCACnC,CAAC;4BACL,CAAC;iCAAM,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gCAChC,MAAM,GAAG,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;gCACnC,wCAAwC;gCACxC,IAAI,CAAC;oCACD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;oCAC9B,QAAgB,CAAC,IAAI,GAAG,MAAM,CAAC;gCACpC,CAAC;gCAAC,MAAM,CAAC;oCACL,0CAA0C;oCACzC,QAAgB,CAAC,IAAI,GAAG,GAAG,CAAC;gCACjC,CAAC;4BACL,CAAC;iCAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;gCAClC,QAAgB,CAAC,IAAI,GAAG,KAAK,CAAC;4BACnC,CAAC;wBACL,CAAC;wBAAC,OAAO,KAAK,EAAE,CAAC;4BACb,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAC;wBACzD,CAAC;oBACL,CAAC;oBAED,MAAM,OAAO,GAAG;wBACZ,aAAa,EAAE,IAAI,CAAC,MAAO;wBAC3B,cAAc,EAAE,kBAAkB;qBACrC,CAAC;oBAEF,IAAI,OAAO,CAAC,SAAS,EAAE,SAAS,EAAE,CAAC;wBAC/B,QAAQ,CAAC,eAAe;4BACpB,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,SAAS,CAAC,SAAS,CAAC;oBACjD,CAAC;oBAED,MAAM,OAAO,GAAyB;wBAClC,KAAK,EAAE,QAAQ;wBACf,MAAM,EAAE,CAAC;wBACT,YAAY,EAAE,OAAO,CAAC,SAAS,EAAE,OAAO;wBACxC,QAAQ,EAAE,QAA2B;qBACxC,CAAC;oBAEF,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,GAAQ,EAAE,EAAE;wBAClD,OAAO,CAAC,KAAK,CAAC,kDAAkD,EAAE,GAAG,CAAC,CAAC;wBACvE,MAAM,GAAG,CAAC;oBACd,CAAC,CAAC,CAAC;oBACH,kCAAkC;oBAGlC,kCAAkC;oBAClC,IAAI,OAAO,KAAK,KAAK,UAAU,EAAE,CAAC;wBAC9B,OAAO,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;oBAC5D,CAAC;oBACD,IAAI,OAAO,QAAQ,KAAK,UAAU,EAAE,CAAC;wBACjC,OAAO,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;oBAC3D,CAAC;oBACD,OAAO,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,IAAI,MAAM,EAAE,EAAE,CAAC,CAAC;gBACjE,CAAwB,CAAC;gBAEzB,IAAI,EAAE,CAAC;YACX,CAAC;YAAC,OAAO,KAAU,EAAE,CAAC;gBAClB,OAAO,CAAC,KAAK,CAAC,oDAAoD,EAAE,KAAK,CAAC,CAAC;gBAC3E,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;gBACxD,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;oBACtB,OAAO,EAAE,KAAK,CAAC,OAAO;oBACtB,OAAO,EAAE,IAAI;iBAChB,CAAC,CAAC;gBACH,OAAO;YACX,CAAC;QACL,CAAC,CAAC;IACN,CAAC;CAEJ;AAtMD,kDAsMC"}
|
package/dist/utils.d.ts
ADDED
package/dist/utils.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sendAsync = sendAsync;
|
|
4
|
+
function sendAsync(ws, payload) {
|
|
5
|
+
return new Promise((resolve, reject) => {
|
|
6
|
+
const id = Math.random().toString(36).slice(2);
|
|
7
|
+
const message = { id, ...payload };
|
|
8
|
+
function handleMessage(data) {
|
|
9
|
+
const response = JSON.parse(data.toString());
|
|
10
|
+
if (response.replyTo === id) {
|
|
11
|
+
ws.off('message', handleMessage);
|
|
12
|
+
resolve(response);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
ws.on('message', handleMessage);
|
|
16
|
+
ws.send(JSON.stringify(message), (err) => {
|
|
17
|
+
if (err)
|
|
18
|
+
reject(err);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
// export class UsageFlowSocketManger {
|
|
23
|
+
// private ws: WebSocket | null = null;
|
|
24
|
+
// private wsUrl: string = "ws://127.0.0.1:9000/ws";
|
|
25
|
+
// private wsConnected: boolean = false;
|
|
26
|
+
// constructor(private apiKey: string) {
|
|
27
|
+
// this.apiKey = apiKey;
|
|
28
|
+
// this.connect().catch((error) => {
|
|
29
|
+
// console.error("[UsageFlow] Failed to establish WebSocket connection:", error);
|
|
30
|
+
// });
|
|
31
|
+
// }
|
|
32
|
+
// async establishWebSocketConnection(): Promise<void> {
|
|
33
|
+
// if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
34
|
+
// this.wsConnected = true;
|
|
35
|
+
// return;
|
|
36
|
+
// }
|
|
37
|
+
// if (!this.apiKey) {
|
|
38
|
+
// console.warn("[UsageFlow] Cannot establish WebSocket connection: API key not initialized");
|
|
39
|
+
// return;
|
|
40
|
+
// }
|
|
41
|
+
// return new Promise((resolve, reject) => {
|
|
42
|
+
// try {
|
|
43
|
+
// console.log(`[UsageFlow] Establishing WebSocket connection to ${this.wsUrl}`);
|
|
44
|
+
// if (!this.apiKey) {
|
|
45
|
+
// reject(new Error("API key not available"));
|
|
46
|
+
// return;
|
|
47
|
+
// }
|
|
48
|
+
// const headers: Record<string, string> = {
|
|
49
|
+
// "x-usage-key": this.apiKey,
|
|
50
|
+
// };
|
|
51
|
+
// this.ws = new WebSocket(this.wsUrl, {
|
|
52
|
+
// headers,
|
|
53
|
+
// family: 4 // This forces IPv4
|
|
54
|
+
// });
|
|
55
|
+
// this.ws.on("open", () => {
|
|
56
|
+
// console.log("[UsageFlow] WebSocket connection established");
|
|
57
|
+
// this.wsConnected = true;
|
|
58
|
+
// resolve();
|
|
59
|
+
// });
|
|
60
|
+
// this.ws.on("error", (error: Error) => {
|
|
61
|
+
// console.error("[UsageFlow] WebSocket error:", error);
|
|
62
|
+
// this.wsConnected = false;
|
|
63
|
+
// reject(error);
|
|
64
|
+
// });
|
|
65
|
+
// this.ws.on("close", () => {
|
|
66
|
+
// console.log("[UsageFlow] WebSocket connection closed");
|
|
67
|
+
// this.wsConnected = false;
|
|
68
|
+
// // Attempt to reconnect after a delay
|
|
69
|
+
// setTimeout(() => {
|
|
70
|
+
// if (this.apiKey) {
|
|
71
|
+
// this.establishWebSocketConnection().catch(console.error);
|
|
72
|
+
// }
|
|
73
|
+
// }, 5000);
|
|
74
|
+
// });
|
|
75
|
+
// this.ws.on("message", (data: WebSocket.Data) => {
|
|
76
|
+
// console.log("[UsageFlow] WebSocket message received:", data.toString());
|
|
77
|
+
// });
|
|
78
|
+
// } catch (error) {
|
|
79
|
+
// console.error("[UsageFlow] Error creating WebSocket connection:", error);
|
|
80
|
+
// this.wsConnected = false;
|
|
81
|
+
// reject(error);
|
|
82
|
+
// }
|
|
83
|
+
// });
|
|
84
|
+
// }
|
|
85
|
+
// public async connect(): Promise<void> {
|
|
86
|
+
// this.ws = new WebSocket(this.wsUrl);
|
|
87
|
+
// this.ws.on("open", () => {
|
|
88
|
+
// this.wsConnected = true;
|
|
89
|
+
// });
|
|
90
|
+
// this.ws.on("error", (error: Error) => {
|
|
91
|
+
// this.wsConnected = false;
|
|
92
|
+
// throw error;
|
|
93
|
+
// });
|
|
94
|
+
// this.ws.on("close", () => {
|
|
95
|
+
// this.wsConnected = false;
|
|
96
|
+
// });
|
|
97
|
+
// }
|
|
98
|
+
// public async sendAsync<T>(payload: UsageFlowSocketMessage): Promise<T> {
|
|
99
|
+
// if (!this.ws || !this.wsConnected) {
|
|
100
|
+
// throw new Error("WebSocket not connected");
|
|
101
|
+
// }
|
|
102
|
+
// const socketResponse = await sendAsync(this.ws, payload);
|
|
103
|
+
// return socketResponse as T;
|
|
104
|
+
// }
|
|
105
|
+
// public send(payload: UsageFlowSocketMessage): void {
|
|
106
|
+
// if (!this.ws || !this.wsConnected) {
|
|
107
|
+
// throw new Error("WebSocket not connected");
|
|
108
|
+
// }
|
|
109
|
+
// this.ws.send(JSON.stringify(payload));
|
|
110
|
+
// }
|
|
111
|
+
// public close(): void {
|
|
112
|
+
// if (this.ws) {
|
|
113
|
+
// this.ws.close();
|
|
114
|
+
// }
|
|
115
|
+
// this.ws = null;
|
|
116
|
+
// this.wsConnected = false;
|
|
117
|
+
// }
|
|
118
|
+
// public isConnected(): boolean {
|
|
119
|
+
// return this.wsConnected;
|
|
120
|
+
// }
|
|
121
|
+
// public getWs(): WebSocket | null {
|
|
122
|
+
// return this.ws;
|
|
123
|
+
// }
|
|
124
|
+
// /**
|
|
125
|
+
// * Clean up resources including WebSocket connection
|
|
126
|
+
// */
|
|
127
|
+
// public destroy(): void {
|
|
128
|
+
// if (this.ws) {
|
|
129
|
+
// console.log("[UsageFlow] Closing WebSocket connection");
|
|
130
|
+
// this.ws.removeAllListeners();
|
|
131
|
+
// if (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING) {
|
|
132
|
+
// this.ws.close();
|
|
133
|
+
// }
|
|
134
|
+
// this.ws = null;
|
|
135
|
+
// this.wsConnected = false;
|
|
136
|
+
// }
|
|
137
|
+
// }
|
|
138
|
+
// }
|
|
139
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":";;AAGA,8BAkBC;AAlBD,SAAgB,SAAS,CAAC,EAAa,EAAE,OAA+B;IACpE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACnC,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC/C,MAAM,OAAO,GAAG,EAAE,EAAE,EAAE,GAAG,OAAO,EAAE,CAAC;QAEnC,SAAS,aAAa,CAAC,IAAoB;YACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;YAC7C,IAAI,QAAQ,CAAC,OAAO,KAAK,EAAE,EAAE,CAAC;gBAC1B,EAAE,CAAC,GAAG,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;gBACjC,OAAO,CAAC,QAAQ,CAAC,CAAC;YACtB,CAAC;QACL,CAAC;QAED,EAAE,CAAC,EAAE,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;QAChC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE;YACrC,IAAI,GAAG;gBAAE,MAAM,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;AACP,CAAC;AAGD,uCAAuC;AACvC,2CAA2C;AAC3C,wDAAwD;AACxD,4CAA4C;AAE5C,4CAA4C;AAC5C,gCAAgC;AAChC,4CAA4C;AAC5C,6FAA6F;AAC7F,cAAc;AAEd,QAAQ;AAER,4DAA4D;AAC5D,kEAAkE;AAClE,uCAAuC;AACvC,sBAAsB;AACtB,YAAY;AAEZ,8BAA8B;AAC9B,0GAA0G;AAC1G,sBAAsB;AACtB,YAAY;AAEZ,oDAAoD;AACpD,oBAAoB;AACpB,iGAAiG;AAEjG,sCAAsC;AACtC,kEAAkE;AAClE,8BAA8B;AAC9B,oBAAoB;AAEpB,4DAA4D;AAC5D,kDAAkD;AAClD,qBAAqB;AAErB,wDAAwD;AACxD,+BAA+B;AAC/B,qDAAqD;AACrD,sBAAsB;AAEtB,6CAA6C;AAC7C,mFAAmF;AACnF,+CAA+C;AAC/C,iCAAiC;AACjC,sBAAsB;AAEtB,0DAA0D;AAC1D,4EAA4E;AAC5E,gDAAgD;AAChD,qCAAqC;AACrC,sBAAsB;AAEtB,8CAA8C;AAC9C,8EAA8E;AAC9E,gDAAgD;AAChD,4DAA4D;AAC5D,yCAAyC;AACzC,6CAA6C;AAC7C,wFAAwF;AACxF,4BAA4B;AAC5B,gCAAgC;AAChC,sBAAsB;AAEtB,oEAAoE;AACpE,+FAA+F;AAC/F,sBAAsB;AACtB,gCAAgC;AAChC,4FAA4F;AAC5F,4CAA4C;AAC5C,iCAAiC;AACjC,gBAAgB;AAChB,cAAc;AACd,QAAQ;AAGR,8CAA8C;AAC9C,+CAA+C;AAC/C,qCAAqC;AACrC,uCAAuC;AACvC,cAAc;AACd,kDAAkD;AAClD,wCAAwC;AACxC,2BAA2B;AAC3B,cAAc;AACd,sCAAsC;AACtC,wCAAwC;AACxC,cAAc;AACd,QAAQ;AAER,+EAA+E;AAC/E,+CAA+C;AAC/C,0DAA0D;AAC1D,YAAY;AAEZ,oEAAoE;AACpE,sCAAsC;AACtC,QAAQ;AAER,2DAA2D;AAC3D,+CAA+C;AAC/C,0DAA0D;AAC1D,YAAY;AAEZ,iDAAiD;AAEjD,QAAQ;AAER,6BAA6B;AAC7B,yBAAyB;AACzB,+BAA+B;AAC/B,YAAY;AACZ,0BAA0B;AAC1B,oCAAoC;AACpC,QAAQ;AAER,sCAAsC;AACtC,mCAAmC;AACnC,QAAQ;AAER,yCAAyC;AACzC,0BAA0B;AAC1B,QAAQ;AAGR,UAAU;AACV,2DAA2D;AAC3D,UAAU;AACV,+BAA+B;AAC/B,yBAAyB;AACzB,uEAAuE;AACvE,4CAA4C;AAC5C,0GAA0G;AAC1G,mCAAmC;AACnC,gBAAgB;AAChB,8BAA8B;AAC9B,wCAAwC;AACxC,YAAY;AACZ,QAAQ;AAIR,IAAI"}
|
package/package.json
CHANGED
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@usageflow/express",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "UsageFlow plugin for Express applications",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"build": "tsc",
|
|
9
9
|
"test": "jest",
|
|
10
|
-
"prepare": "npm run build"
|
|
10
|
+
"prepare": "npm run build",
|
|
11
|
+
"prepublishOnly": "npm run build"
|
|
12
|
+
},
|
|
13
|
+
"publishConfig": {
|
|
14
|
+
"access": "public"
|
|
11
15
|
},
|
|
12
16
|
"dependencies": {
|
|
13
|
-
"@usageflow/core": "^0.1.
|
|
14
|
-
"express": "^4.18.0"
|
|
17
|
+
"@usageflow/core": "^0.1.5",
|
|
18
|
+
"express": "^4.18.0",
|
|
19
|
+
"ws": "^8.16.0"
|
|
15
20
|
},
|
|
16
21
|
"homepage": "https://usageflow.io",
|
|
17
22
|
"repository": {
|
|
@@ -22,6 +27,7 @@
|
|
|
22
27
|
"devDependencies": {
|
|
23
28
|
"@types/express": "^4.17.0",
|
|
24
29
|
"@types/node": "^20.0.0",
|
|
30
|
+
"@types/ws": "^8.5.10",
|
|
25
31
|
"typescript": "^5.0.0",
|
|
26
32
|
"jest": "^29.0.0",
|
|
27
33
|
"@types/jest": "^29.0.0",
|
package/src/plugin.ts
CHANGED
|
@@ -1,19 +1,15 @@
|
|
|
1
1
|
import { Request, Response, NextFunction } from "express";
|
|
2
|
-
import { UsageFlowAPI, Route, RequestMetadata } from "@usageflow/core";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
namespace Express {
|
|
6
|
-
interface Request {
|
|
7
|
-
usageflow?: {
|
|
8
|
-
startTime: number;
|
|
9
|
-
eventId?: string;
|
|
10
|
-
metadata?: RequestMetadata;
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
}
|
|
2
|
+
import { UsageFlowAPI, Route, RequestMetadata, RequestForAllocation, UsageFlowRequest } from "@usageflow/core";
|
|
3
|
+
|
|
4
|
+
|
|
15
5
|
|
|
16
6
|
export class ExpressUsageFlowAPI extends UsageFlowAPI {
|
|
7
|
+
/**
|
|
8
|
+
* Get the route pattern (e.g., /express/users/:id) from the request
|
|
9
|
+
* Tries multiple methods to get the route pattern since request.route
|
|
10
|
+
* may not be available in middleware that runs before route matching
|
|
11
|
+
*/
|
|
12
|
+
|
|
17
13
|
private async collectRequestMetadata(
|
|
18
14
|
request: Request,
|
|
19
15
|
): Promise<RequestMetadata> {
|
|
@@ -28,9 +24,22 @@ export class ExpressUsageFlowAPI extends UsageFlowAPI {
|
|
|
28
24
|
clientIP = forwardedFor.split(",")[0].trim();
|
|
29
25
|
}
|
|
30
26
|
|
|
27
|
+
const routePattern = request.route?.path || request.app._router.stack.find((route: any) => {
|
|
28
|
+
// a => a.path == request.url
|
|
29
|
+
if (!route.route) return false;
|
|
30
|
+
if (route.path) {
|
|
31
|
+
return route.path == request.url;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (route.regexp) {
|
|
35
|
+
return route.regexp.test(request.url);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
})?.route?.path || request.url;
|
|
39
|
+
|
|
31
40
|
const metadata: RequestMetadata = {
|
|
32
41
|
method: request.method,
|
|
33
|
-
url:
|
|
42
|
+
url: routePattern,
|
|
34
43
|
rawUrl: request.originalUrl || "/",
|
|
35
44
|
clientIP: clientIP || "unknown",
|
|
36
45
|
userAgent: request.headers["user-agent"] as string,
|
|
@@ -54,48 +63,14 @@ export class ExpressUsageFlowAPI extends UsageFlowAPI {
|
|
|
54
63
|
throw new Error("API key not initialized");
|
|
55
64
|
}
|
|
56
65
|
|
|
57
|
-
const headers = {
|
|
58
|
-
"x-usage-key": this.apiKey,
|
|
59
|
-
"Content-Type": "application/json",
|
|
60
|
-
};
|
|
61
|
-
|
|
62
66
|
const payload = {
|
|
63
67
|
alias: ledgerId,
|
|
64
68
|
amount: 1,
|
|
65
69
|
metadata,
|
|
70
|
+
duration: 1000
|
|
66
71
|
};
|
|
67
72
|
|
|
68
|
-
|
|
69
|
-
const response = await fetch(
|
|
70
|
-
`${this.usageflowUrl}/api/v1/ledgers/measure/allocate`,
|
|
71
|
-
{
|
|
72
|
-
method: "POST",
|
|
73
|
-
headers,
|
|
74
|
-
body: JSON.stringify(payload),
|
|
75
|
-
},
|
|
76
|
-
);
|
|
77
|
-
|
|
78
|
-
const data = await response.json();
|
|
79
|
-
|
|
80
|
-
if (response.status === 400) {
|
|
81
|
-
throw new Error(data.message);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (response.ok) {
|
|
85
|
-
request.usageflow!.eventId = data.eventId;
|
|
86
|
-
request.usageflow!.metadata = metadata;
|
|
87
|
-
} else {
|
|
88
|
-
throw new Error(data.message || "Unknown error occurred");
|
|
89
|
-
}
|
|
90
|
-
} catch (error: any) {
|
|
91
|
-
if (
|
|
92
|
-
error.message ==
|
|
93
|
-
"Failed to use resource after retries: Faile to preform operation"
|
|
94
|
-
) {
|
|
95
|
-
throw new Error("Failed to allocate resource");
|
|
96
|
-
}
|
|
97
|
-
throw error;
|
|
98
|
-
}
|
|
73
|
+
await this.allocationRequest(request as unknown as UsageFlowRequest, payload, metadata);
|
|
99
74
|
}
|
|
100
75
|
|
|
101
76
|
public createMiddleware(routes: Route[], whitelistRoutes: Route[] = []) {
|
|
@@ -103,9 +78,11 @@ export class ExpressUsageFlowAPI extends UsageFlowAPI {
|
|
|
103
78
|
const whitelistMap = this.createRoutesMap(whitelistRoutes);
|
|
104
79
|
const self = this;
|
|
105
80
|
|
|
81
|
+
|
|
106
82
|
return async (request: Request, response: Response, next: NextFunction) => {
|
|
107
83
|
const method = request.method;
|
|
108
|
-
const
|
|
84
|
+
const routePattern = self.getRoutePattern(request);
|
|
85
|
+
const url = routePattern;
|
|
109
86
|
|
|
110
87
|
request.usageflow = {
|
|
111
88
|
startTime: Date.now(),
|
|
@@ -120,10 +97,12 @@ export class ExpressUsageFlowAPI extends UsageFlowAPI {
|
|
|
120
97
|
}
|
|
121
98
|
|
|
122
99
|
const metadata = await this.collectRequestMetadata(request);
|
|
100
|
+
metadata.url = url;
|
|
101
|
+
let ledgerId = this.guessLedgerId(request);
|
|
123
102
|
|
|
124
103
|
try {
|
|
125
104
|
await this.executeRequestWithMetadata(
|
|
126
|
-
|
|
105
|
+
ledgerId,
|
|
127
106
|
metadata,
|
|
128
107
|
request,
|
|
129
108
|
response,
|
|
@@ -185,20 +164,19 @@ export class ExpressUsageFlowAPI extends UsageFlowAPI {
|
|
|
185
164
|
Date.now() - request.usageflow.startTime;
|
|
186
165
|
}
|
|
187
166
|
|
|
188
|
-
const payload = {
|
|
189
|
-
alias:
|
|
167
|
+
const payload: RequestForAllocation = {
|
|
168
|
+
alias: ledgerId,
|
|
190
169
|
amount: 1,
|
|
191
170
|
allocationId: request.usageflow?.eventId,
|
|
192
|
-
metadata,
|
|
171
|
+
metadata: metadata as RequestMetadata,
|
|
193
172
|
};
|
|
194
173
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
body: JSON.stringify(payload),
|
|
199
|
-
}).catch((error) => {
|
|
200
|
-
console.error("Error finalizing request:", error);
|
|
174
|
+
self.useAllocationRequest(payload).catch((err: any) => {
|
|
175
|
+
console.error("[UsageFlow] Error finalizing allocation request:", err);
|
|
176
|
+
throw err;
|
|
201
177
|
});
|
|
178
|
+
// Send via WebSocket if connected
|
|
179
|
+
|
|
202
180
|
|
|
203
181
|
// Handle the different overloadsx
|
|
204
182
|
if (typeof chunk === "function") {
|
|
@@ -212,7 +190,8 @@ export class ExpressUsageFlowAPI extends UsageFlowAPI {
|
|
|
212
190
|
|
|
213
191
|
next();
|
|
214
192
|
} catch (error: any) {
|
|
215
|
-
console.error("Error executing request with metadata:", error);
|
|
193
|
+
console.error("[UsageFlow] Error executing request with metadata:", error);
|
|
194
|
+
console.error("[UsageFlow] Error stack:", error?.stack);
|
|
216
195
|
response.status(400).json({
|
|
217
196
|
message: error.message,
|
|
218
197
|
blocked: true,
|
|
@@ -222,46 +201,4 @@ export class ExpressUsageFlowAPI extends UsageFlowAPI {
|
|
|
222
201
|
};
|
|
223
202
|
}
|
|
224
203
|
|
|
225
|
-
protected guessLedgerId(request: Request): string {
|
|
226
|
-
const method = request.method;
|
|
227
|
-
const url = request.route?.path || request.path;
|
|
228
|
-
const config = this.apiConfig
|
|
229
|
-
|
|
230
|
-
if (!config?.identityFieldName || !config?.identityFieldLocation) {
|
|
231
|
-
return `${method} ${url}`;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
const fieldName = config.identityFieldName;
|
|
235
|
-
const location = config.identityFieldLocation;
|
|
236
|
-
|
|
237
|
-
switch (location) {
|
|
238
|
-
case "path_params":
|
|
239
|
-
if (request.params?.[fieldName]) {
|
|
240
|
-
return `${method} ${url} ${request.params[fieldName]}`;
|
|
241
|
-
}
|
|
242
|
-
break;
|
|
243
|
-
case "query_params":
|
|
244
|
-
if (request.query?.[fieldName]) {
|
|
245
|
-
return `${method} ${url} ${request.query[fieldName]}`;
|
|
246
|
-
}
|
|
247
|
-
break;
|
|
248
|
-
case "body":
|
|
249
|
-
if (request.body?.[fieldName]) {
|
|
250
|
-
return `${method} ${url} ${request.body[fieldName]}`;
|
|
251
|
-
}
|
|
252
|
-
break;
|
|
253
|
-
case "bearer_token":
|
|
254
|
-
const authHeader = request.headers.authorization;
|
|
255
|
-
const token = this.extractBearerToken(authHeader);
|
|
256
|
-
if (token) {
|
|
257
|
-
const claims = this.decodeJwtUnverified(token);
|
|
258
|
-
if (claims?.[fieldName]) {
|
|
259
|
-
return `${method} ${url} ${claims[fieldName]}`;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
break;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
return `${method} ${url}`;
|
|
266
|
-
}
|
|
267
204
|
}
|