@usageflow/core 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/base.d.ts +16 -6
- package/dist/base.js +253 -29
- package/dist/base.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/socket.d.ts +21 -0
- package/dist/socket.js +216 -0
- package/dist/socket.js.map +1 -0
- package/dist/types.d.ts +75 -0
- package/dist/types.js.map +1 -1
- package/package.json +9 -3
- package/src/base.ts +285 -30
- package/src/index.ts +2 -1
- package/src/socket.ts +251 -0
- package/src/types.ts +84 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"socket.js","sourceRoot":"","sources":["../src/socket.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,3 +1,33 @@
|
|
|
1
|
+
declare global {
|
|
2
|
+
namespace Express {
|
|
3
|
+
interface Request {
|
|
4
|
+
usageflow?: {
|
|
5
|
+
startTime: number;
|
|
6
|
+
eventId?: string;
|
|
7
|
+
metadata?: RequestMetadata;
|
|
8
|
+
};
|
|
9
|
+
baseUrl: string;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
namespace Fastify {
|
|
13
|
+
interface FastifyRequest {
|
|
14
|
+
usageflow?: {
|
|
15
|
+
startTime: number;
|
|
16
|
+
eventId?: string;
|
|
17
|
+
metadata?: RequestMetadata;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
namespace NestJS {
|
|
22
|
+
interface Request {
|
|
23
|
+
usageflow?: {
|
|
24
|
+
startTime: number;
|
|
25
|
+
eventId?: string;
|
|
26
|
+
metadata?: RequestMetadata;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
1
31
|
export interface Route {
|
|
2
32
|
method: string;
|
|
3
33
|
url: string;
|
|
@@ -22,6 +52,8 @@ export interface ResponseMetadata {
|
|
|
22
52
|
timestamp: string;
|
|
23
53
|
}
|
|
24
54
|
export interface UsageFlowConfig {
|
|
55
|
+
url: string;
|
|
56
|
+
method: string;
|
|
25
57
|
identityFieldName?: string;
|
|
26
58
|
identityFieldLocation?: string;
|
|
27
59
|
}
|
|
@@ -36,3 +68,46 @@ export type RoutesMap = Record<string, Record<string, boolean>>;
|
|
|
36
68
|
export declare class UsageFlowError extends Error {
|
|
37
69
|
constructor(message: string);
|
|
38
70
|
}
|
|
71
|
+
export interface RequestForAllocation {
|
|
72
|
+
alias: string;
|
|
73
|
+
amount: number;
|
|
74
|
+
allocationId?: string;
|
|
75
|
+
metadata: RequestMetadata;
|
|
76
|
+
duration?: number;
|
|
77
|
+
}
|
|
78
|
+
export type MessageTypes = 'request_for_allocation' | 'use_allocation' | 'get_application_policies';
|
|
79
|
+
export interface UsageFlowSocketMessage {
|
|
80
|
+
type: MessageTypes;
|
|
81
|
+
payload: RequestForAllocation | null;
|
|
82
|
+
}
|
|
83
|
+
export interface UsageFlowSocketResponse<T> {
|
|
84
|
+
type: 'success' | 'error';
|
|
85
|
+
payload: T;
|
|
86
|
+
status: 'success' | 'error' | 400;
|
|
87
|
+
message: string;
|
|
88
|
+
error?: string;
|
|
89
|
+
}
|
|
90
|
+
export interface UsageFlowRequest {
|
|
91
|
+
method: string;
|
|
92
|
+
url?: string;
|
|
93
|
+
path?: string;
|
|
94
|
+
baseUrl?: string;
|
|
95
|
+
route?: {
|
|
96
|
+
path: string;
|
|
97
|
+
};
|
|
98
|
+
app?: any;
|
|
99
|
+
params?: Record<string, any>;
|
|
100
|
+
query?: Record<string, any>;
|
|
101
|
+
body?: any;
|
|
102
|
+
headers: Record<string, string | string[] | undefined> | Headers;
|
|
103
|
+
ip?: string;
|
|
104
|
+
originalUrl?: string;
|
|
105
|
+
usageflow?: {
|
|
106
|
+
eventId?: string;
|
|
107
|
+
metadata?: RequestMetadata;
|
|
108
|
+
startTime?: number;
|
|
109
|
+
};
|
|
110
|
+
routeOptions?: {
|
|
111
|
+
url: string;
|
|
112
|
+
};
|
|
113
|
+
}
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;;AA6EA,MAAa,cAAe,SAAQ,KAAK;IACrC,YAAY,OAAe;QACvB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IACjC,CAAC;CACJ;AALD,wCAKC"}
|
package/package.json
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@usageflow/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "Core functionality for UsageFlow integrations",
|
|
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
|
-
"axios": "^1.6.0"
|
|
17
|
+
"axios": "^1.6.0",
|
|
18
|
+
"ws": "^8.16.0"
|
|
14
19
|
},
|
|
15
20
|
"homepage": "https://usageflow.io",
|
|
16
21
|
"repository": {
|
|
@@ -20,6 +25,7 @@
|
|
|
20
25
|
},
|
|
21
26
|
"devDependencies": {
|
|
22
27
|
"@types/node": "^20.0.0",
|
|
28
|
+
"@types/ws": "^8.5.10",
|
|
23
29
|
"typescript": "^5.0.0",
|
|
24
30
|
"jest": "^29.0.0",
|
|
25
31
|
"@types/jest": "^29.0.0",
|
package/src/base.ts
CHANGED
|
@@ -5,15 +5,20 @@ import {
|
|
|
5
5
|
UsageFlowError,
|
|
6
6
|
RoutesMap,
|
|
7
7
|
Headers,
|
|
8
|
+
RequestForAllocation,
|
|
9
|
+
RequestMetadata,
|
|
10
|
+
UsageFlowRequest,
|
|
8
11
|
} from "./types";
|
|
12
|
+
import { UsageFlowSocketManger } from "./socket";
|
|
9
13
|
|
|
10
14
|
export abstract class UsageFlowAPI {
|
|
11
15
|
protected apiKey: string | null = null;
|
|
12
16
|
protected usageflowUrl: string = "https://api.usageflow.io";
|
|
13
|
-
|
|
14
|
-
protected
|
|
17
|
+
protected webServer: 'express' | 'fastify' | 'nestjs' = 'express';
|
|
18
|
+
protected apiConfigs: UsageFlowConfig[] = [];
|
|
15
19
|
private configUpdateInterval: NodeJS.Timeout | null = null;
|
|
16
|
-
|
|
20
|
+
socketManager: UsageFlowSocketManger | null = null;
|
|
21
|
+
private applicationId: boolean = false;
|
|
17
22
|
/**
|
|
18
23
|
* Initialize the UsageFlow API with credentials
|
|
19
24
|
*/
|
|
@@ -22,12 +27,24 @@ export abstract class UsageFlowAPI {
|
|
|
22
27
|
usageflowUrl: string = "https://api.usageflow.io",
|
|
23
28
|
): UsageFlowAPI {
|
|
24
29
|
this.apiKey = apiKey;
|
|
25
|
-
|
|
26
30
|
this.usageflowUrl = usageflowUrl;
|
|
27
|
-
this.startConfigUpdater();
|
|
31
|
+
// this.startConfigUpdater();
|
|
32
|
+
this.socketManager = new UsageFlowSocketManger(apiKey);
|
|
33
|
+
// Connect the socket manager
|
|
34
|
+
this.socketManager.connect().catch((error) => {
|
|
35
|
+
console.error("[UsageFlow] Failed to establish WebSocket connection:", error);
|
|
36
|
+
}).then(() => {
|
|
37
|
+
this.startConfigUpdater();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
|
|
28
41
|
return this;
|
|
29
42
|
}
|
|
30
43
|
|
|
44
|
+
public setWebServer(webServer: 'express' | 'fastify' | 'nestjs'): void {
|
|
45
|
+
this.webServer = webServer;
|
|
46
|
+
}
|
|
47
|
+
|
|
31
48
|
public getApiKey(): string | null {
|
|
32
49
|
return this.apiKey;
|
|
33
50
|
}
|
|
@@ -44,40 +61,259 @@ export abstract class UsageFlowAPI {
|
|
|
44
61
|
clearInterval(this.configUpdateInterval);
|
|
45
62
|
}
|
|
46
63
|
|
|
64
|
+
this.fetchApiPolicies().catch(console.error);
|
|
47
65
|
this.configUpdateInterval = setInterval(async () => {
|
|
48
|
-
|
|
49
|
-
const config = await this.fetchApiConfig();
|
|
50
|
-
if (config) {
|
|
51
|
-
this.apiConfig = config;
|
|
52
|
-
}
|
|
53
|
-
} catch (error) {
|
|
54
|
-
console.error("Error fetching API config:", error);
|
|
55
|
-
}
|
|
66
|
+
await this.fetchApiPolicies();
|
|
56
67
|
}, 60000);
|
|
57
68
|
|
|
58
|
-
this.fetchApiConfig().catch(console.error);
|
|
69
|
+
// this.fetchApiConfig().catch(console.error);
|
|
59
70
|
}
|
|
60
71
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if (!this.apiKey) {
|
|
66
|
-
throw new UsageFlowError("API key not initialized");
|
|
72
|
+
protected getRoutePattern(request: UsageFlowRequest): string {
|
|
73
|
+
|
|
74
|
+
if (this.webServer === 'fastify') {
|
|
75
|
+
return request?.routeOptions?.url || request.url || '';
|
|
67
76
|
}
|
|
68
77
|
|
|
78
|
+
const routePattern = request.route?.path || request.app._router.stack.find((route: any) => {
|
|
79
|
+
// a => a.path == request.url
|
|
80
|
+
if (!route.route) return false;
|
|
81
|
+
if (route.path) {
|
|
82
|
+
return route.path == request.url;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (route.regexp) {
|
|
86
|
+
return route.regexp.test(request.url);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
})?.route?.path
|
|
90
|
+
|
|
91
|
+
if (routePattern) {
|
|
92
|
+
return routePattern;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Method 1: Use request.route.path (available after route matching)
|
|
96
|
+
if (request.route?.path) {
|
|
97
|
+
const baseUrl = request.baseUrl || "";
|
|
98
|
+
const routePath = request.route.path;
|
|
99
|
+
// Combine baseUrl and routePath to get full pattern
|
|
100
|
+
const fullPath = baseUrl + routePath;
|
|
101
|
+
return fullPath || "/";
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Method 2: Try to find route from router stack
|
|
69
105
|
try {
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
106
|
+
const app = request.app;
|
|
107
|
+
const router = (app as any)._router;
|
|
108
|
+
if (router && router.stack) {
|
|
109
|
+
const method = request.method.toLowerCase();
|
|
110
|
+
const path = request.path || request.url?.split("?")[0] || "";
|
|
111
|
+
|
|
112
|
+
// Search through router stack for matching route
|
|
113
|
+
for (const layer of router.stack) {
|
|
114
|
+
if (layer.route) {
|
|
115
|
+
const route = layer.route;
|
|
116
|
+
const routePath = route.path;
|
|
117
|
+
const routeMethods = Object.keys(route.methods).map(m => m.toLowerCase());
|
|
118
|
+
|
|
119
|
+
// Check if method matches and path pattern matches
|
|
120
|
+
if (routeMethods.includes(method) || routeMethods.includes("*")) {
|
|
121
|
+
// Try to match the pattern by checking if params match
|
|
122
|
+
const pattern = (request.baseUrl || "") + routePath;
|
|
123
|
+
// Simple check: if we have params and the route has params, it might match
|
|
124
|
+
if (request.params && Object.keys(request.params).length > 0) {
|
|
125
|
+
// Check if route path contains the param names
|
|
126
|
+
const paramNames = Object.keys(request.params);
|
|
127
|
+
const routeHasParams = paramNames.some(param => routePath.includes(`:${param}`));
|
|
128
|
+
if (routeHasParams) {
|
|
129
|
+
return pattern;
|
|
130
|
+
}
|
|
131
|
+
} else if (!routePath.includes(":")) {
|
|
132
|
+
// If no params in request and route has no params, check exact match
|
|
133
|
+
if (path === pattern || path === routePath) {
|
|
134
|
+
return pattern;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
} else if (layer.name === "router" && layer.handle && layer.handle.stack) {
|
|
139
|
+
// Handle router middleware (nested routers)
|
|
140
|
+
const mountPath = layer.regexp.source
|
|
141
|
+
.replace("\\/?", "")
|
|
142
|
+
.replace("(?=\\/|$)", "")
|
|
143
|
+
.replace(/\\\//g, "/")
|
|
144
|
+
.replace(/\^/g, "")
|
|
145
|
+
.replace(/\$/g, "")
|
|
146
|
+
.replace(/\\/g, "");
|
|
147
|
+
|
|
148
|
+
for (const subLayer of layer.handle.stack) {
|
|
149
|
+
if (subLayer.route) {
|
|
150
|
+
const route = subLayer.route;
|
|
151
|
+
const routePath = route.path;
|
|
152
|
+
const routeMethods = Object.keys(route.methods).map(m => m.toLowerCase());
|
|
153
|
+
|
|
154
|
+
if (routeMethods.includes(method) || routeMethods.includes("*")) {
|
|
155
|
+
const fullPath = mountPath + routePath;
|
|
156
|
+
// Check if this route matches by examining params
|
|
157
|
+
if (request.params && Object.keys(request.params).length > 0) {
|
|
158
|
+
const paramNames = Object.keys(request.params);
|
|
159
|
+
const routeHasParams = paramNames.some(param => routePath.includes(`:${param}`));
|
|
160
|
+
if (routeHasParams) {
|
|
161
|
+
return fullPath;
|
|
162
|
+
}
|
|
163
|
+
} else if (!routePath.includes(":")) {
|
|
164
|
+
const currentPath = request.path || request.url?.split("?")[0] || "";
|
|
165
|
+
if (currentPath === fullPath || currentPath === routePath) {
|
|
166
|
+
return fullPath;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
78
175
|
} catch (error) {
|
|
79
|
-
|
|
80
|
-
|
|
176
|
+
// Silently fail and try next method
|
|
177
|
+
console.debug("[UsageFlow] Could not extract route from router stack:", error);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Method 3: Reconstruct pattern from params and path
|
|
181
|
+
if (request.params && Object.keys(request.params).length > 0) {
|
|
182
|
+
let path = request.path || request.url?.split("?")[0] || "/";
|
|
183
|
+
const baseUrl = request.baseUrl || "";
|
|
184
|
+
|
|
185
|
+
// Split path into segments and replace matching segments with param names
|
|
186
|
+
const pathSegments = path.split("/");
|
|
187
|
+
const paramEntries = Object.entries(request.params);
|
|
188
|
+
|
|
189
|
+
// Replace segments that match param values with :paramName
|
|
190
|
+
for (let i = 0; i < pathSegments.length; i++) {
|
|
191
|
+
for (const [paramName, paramValue] of paramEntries) {
|
|
192
|
+
if (pathSegments[i] === paramValue) {
|
|
193
|
+
pathSegments[i] = `:${paramName}`;
|
|
194
|
+
break; // Only replace once per segment
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const pattern = baseUrl + pathSegments.join("/");
|
|
200
|
+
return pattern;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Fallback: return baseUrl + path or just path
|
|
204
|
+
const baseUrl = request.baseUrl || "";
|
|
205
|
+
const path = request.path || request.url?.split("?")[0] || "/";
|
|
206
|
+
return baseUrl + path || "/";
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
public guessLedgerId(request: UsageFlowRequest): string {
|
|
210
|
+
const method = request.method;
|
|
211
|
+
const url = this.getRoutePattern(request);
|
|
212
|
+
const configs = this.apiConfigs
|
|
213
|
+
|
|
214
|
+
if (!configs.length) {
|
|
215
|
+
return `${method} ${url}`;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
for (const config of configs) {
|
|
220
|
+
const fieldName = config.identityFieldName!;
|
|
221
|
+
const location = config.identityFieldLocation;
|
|
222
|
+
|
|
223
|
+
switch (location) {
|
|
224
|
+
case "path_params":
|
|
225
|
+
if (request.params?.[fieldName]) {
|
|
226
|
+
return `${method} ${url} ${request.params[fieldName]}`;
|
|
227
|
+
}
|
|
228
|
+
break;
|
|
229
|
+
case "query_params":
|
|
230
|
+
if (request.query?.[fieldName]) {
|
|
231
|
+
return `${method} ${url} ${request.query[fieldName]}`;
|
|
232
|
+
}
|
|
233
|
+
break;
|
|
234
|
+
case "body":
|
|
235
|
+
if (request.body?.[fieldName]) {
|
|
236
|
+
return `${method} ${url} ${request.body[fieldName]}`;
|
|
237
|
+
}
|
|
238
|
+
break;
|
|
239
|
+
case "bearer_token":
|
|
240
|
+
const authHeader = this.getHeaderValue(request.headers, 'authorization');
|
|
241
|
+
const token = this.extractBearerToken(authHeader || undefined);
|
|
242
|
+
if (token) {
|
|
243
|
+
const claims = this.decodeJwtUnverified(token);
|
|
244
|
+
if (claims?.[fieldName]) {
|
|
245
|
+
return `${method} ${url} ${claims[fieldName]}`;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
break;
|
|
249
|
+
|
|
250
|
+
case "headers": {
|
|
251
|
+
const headerValue = this.getHeaderValue(request.headers, fieldName);
|
|
252
|
+
if (headerValue) {
|
|
253
|
+
return `${method} ${url} ${headerValue}`;
|
|
254
|
+
}
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return `${method} ${url}`;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
private async fetchApiPolicies(): Promise<void> {
|
|
264
|
+
if (this.socketManager && this.socketManager.isConnected()) {
|
|
265
|
+
const response = await this.socketManager.sendAsync<{ policies: UsageFlowConfig[], total: number }>({
|
|
266
|
+
type: "get_application_policies",
|
|
267
|
+
payload: null,
|
|
268
|
+
});
|
|
269
|
+
if (response.type === 'success') {
|
|
270
|
+
this.apiConfigs = response.payload?.policies || [];
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
async useAllocationRequest(
|
|
276
|
+
payload: RequestForAllocation,
|
|
277
|
+
): Promise<void> {
|
|
278
|
+
if (this.socketManager && this.socketManager.isConnected()) {
|
|
279
|
+
this.socketManager.sendAsync<any>({
|
|
280
|
+
type: "use_allocation",
|
|
281
|
+
payload
|
|
282
|
+
}).catch((error) => {
|
|
283
|
+
console.error("[UsageFlow] Error sending finalization via WebSocket:", error);
|
|
284
|
+
throw error;
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
async allocationRequest(
|
|
291
|
+
request: UsageFlowRequest,
|
|
292
|
+
payload: RequestForAllocation,
|
|
293
|
+
metadata: RequestMetadata,
|
|
294
|
+
): Promise<void> {
|
|
295
|
+
if (this.socketManager && this.socketManager.isConnected()) {
|
|
296
|
+
try {
|
|
297
|
+
const allocationResponse = await this.socketManager.sendAsync<any>({
|
|
298
|
+
type: "request_for_allocation",
|
|
299
|
+
payload
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
if (allocationResponse.type === 'error') {
|
|
303
|
+
throw new Error(allocationResponse.message || allocationResponse.error);
|
|
304
|
+
}
|
|
305
|
+
if (allocationResponse.type === 'success') {
|
|
306
|
+
request.usageflow!.eventId = allocationResponse.payload.allocationId;
|
|
307
|
+
request.usageflow!.metadata = metadata;
|
|
308
|
+
return;
|
|
309
|
+
} else {
|
|
310
|
+
throw new Error(allocationResponse.message || "Unknown error occurred");
|
|
311
|
+
}
|
|
312
|
+
} catch (error: any) {
|
|
313
|
+
console.error("[UsageFlow] WebSocket allocation failed, falling back to HTTP:", error);
|
|
314
|
+
throw error;
|
|
315
|
+
// Fall through to HTTP request
|
|
316
|
+
}
|
|
81
317
|
}
|
|
82
318
|
}
|
|
83
319
|
|
|
@@ -191,6 +427,25 @@ export abstract class UsageFlowAPI {
|
|
|
191
427
|
return parts[1];
|
|
192
428
|
}
|
|
193
429
|
|
|
430
|
+
/**
|
|
431
|
+
* Get header value from headers object (handles both Record and Headers types)
|
|
432
|
+
*/
|
|
433
|
+
private getHeaderValue(headers: Record<string, string | string[] | undefined> | Headers, key: string): string | null {
|
|
434
|
+
// Check if it's a Headers object (from Fetch API) by checking for the 'get' method
|
|
435
|
+
if (headers && typeof (headers as any).get === 'function') {
|
|
436
|
+
return (headers as any).get(key) || null;
|
|
437
|
+
}
|
|
438
|
+
// Otherwise, treat it as a Record
|
|
439
|
+
const value = (headers as Record<string, string | string[] | undefined>)[key];
|
|
440
|
+
if (typeof value === 'string') {
|
|
441
|
+
return value;
|
|
442
|
+
}
|
|
443
|
+
if (Array.isArray(value) && value.length > 0) {
|
|
444
|
+
return value[0];
|
|
445
|
+
}
|
|
446
|
+
return null;
|
|
447
|
+
}
|
|
448
|
+
|
|
194
449
|
/**
|
|
195
450
|
* Decodes a JWT token without verifying the signature
|
|
196
451
|
* @param token The JWT token to decode
|
package/src/index.ts
CHANGED