@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 CHANGED
@@ -1,19 +1,12 @@
1
1
  import { Request, Response, NextFunction } from "express";
2
- import { UsageFlowAPI, Route, RequestMetadata } from "@usageflow/core";
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: request.route?.path || request.path || request.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
- try {
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 url = request.route?.path || request.path || request.url;
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(`${method} ${url}`, metadata, request, response);
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: `${request.method} ${request.route?.path || request.path || request.url || "/"}`,
129
+ alias: ledgerId,
138
130
  amount: 1,
139
131
  allocationId: request.usageflow?.eventId,
140
- metadata,
132
+ metadata: metadata,
141
133
  };
142
- fetch(`${self.usageflowUrl}/api/v1/ledgers/measure/allocate/use`, {
143
- method: "POST",
144
- headers,
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
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import WebSocket from "ws";
2
+ import { UsageFlowSocketMessage } from "@usageflow/core";
3
+ export declare function sendAsync(ws: WebSocket, payload: UsageFlowSocketMessage): Promise<unknown>;
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":"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"}
package/package.json CHANGED
@@ -1,17 +1,22 @@
1
1
  {
2
2
  "name": "@usageflow/express",
3
- "version": "0.1.4",
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.3",
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
- declare global {
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: request.route?.path || request.path || request.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
- try {
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 url = request.route?.path || request.path || request.url;
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
- `${method} ${url}`,
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: `${request.method} ${request.route?.path || request.path || request.url || "/"}`,
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
- fetch(`${self.usageflowUrl}/api/v1/ledgers/measure/allocate/use`, {
196
- method: "POST",
197
- headers,
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
  }