@usageflow/express 0.1.5 → 0.1.7

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,6 +71,7 @@ class ExpressUsageFlowAPI extends core_1.UsageFlowAPI {
81
71
  return next();
82
72
  }
83
73
  const metadata = await this.collectRequestMetadata(request);
74
+ metadata.url = url;
84
75
  let ledgerId = this.guessLedgerId(request);
85
76
  try {
86
77
  await this.executeRequestWithMetadata(ledgerId, metadata, request, response);
@@ -138,15 +129,13 @@ class ExpressUsageFlowAPI extends core_1.UsageFlowAPI {
138
129
  alias: ledgerId,
139
130
  amount: 1,
140
131
  allocationId: request.usageflow?.eventId,
141
- metadata,
132
+ metadata: metadata,
142
133
  };
143
- fetch(`${self.usageflowUrl}/api/v1/ledgers/measure/allocate/use`, {
144
- method: "POST",
145
- headers,
146
- body: JSON.stringify(payload),
147
- }).catch((error) => {
148
- console.error("Error finalizing request:", error);
134
+ self.useAllocationRequest(payload).catch((err) => {
135
+ console.error("[UsageFlow] Error finalizing allocation request:", err);
136
+ throw err;
149
137
  });
138
+ // Send via WebSocket if connected
150
139
  // Handle the different overloadsx
151
140
  if (typeof chunk === "function") {
152
141
  return originalEnd.call(this, undefined, "utf8", chunk);
@@ -159,7 +148,8 @@ class ExpressUsageFlowAPI extends core_1.UsageFlowAPI {
159
148
  next();
160
149
  }
161
150
  catch (error) {
162
- 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);
163
153
  response.status(400).json({
164
154
  message: error.message,
165
155
  blocked: true,
@@ -168,44 +158,6 @@ class ExpressUsageFlowAPI extends core_1.UsageFlowAPI {
168
158
  }
169
159
  };
170
160
  }
171
- guessLedgerId(request) {
172
- const method = request.method;
173
- const url = request.route?.path || request.path;
174
- const config = this.apiConfig;
175
- if (!config?.identityFieldName || !config?.identityFieldLocation) {
176
- return `${method} ${url}`;
177
- }
178
- const fieldName = config.identityFieldName;
179
- const location = config.identityFieldLocation;
180
- switch (location) {
181
- case "path_params":
182
- if (request.params?.[fieldName]) {
183
- return `${method} ${url} ${request.params[fieldName]}`;
184
- }
185
- break;
186
- case "query_params":
187
- if (request.query?.[fieldName]) {
188
- return `${method} ${url} ${request.query[fieldName]}`;
189
- }
190
- break;
191
- case "body":
192
- if (request.body?.[fieldName]) {
193
- return `${method} ${url} ${request.body[fieldName]}`;
194
- }
195
- break;
196
- case "bearer_token":
197
- const authHeader = request.headers.authorization;
198
- const token = this.extractBearerToken(authHeader);
199
- if (token) {
200
- const claims = this.decodeJwtUnverified(token);
201
- if (claims?.[fieldName]) {
202
- return `${method} ${url} ${claims[fieldName]}`;
203
- }
204
- }
205
- break;
206
- }
207
- return `${method} ${url}`;
208
- }
209
161
  }
210
162
  exports.ExpressUsageFlowAPI = ExpressUsageFlowAPI;
211
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.5",
3
+ "version": "0.1.7",
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.2.3",
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,6 +97,7 @@ export class ExpressUsageFlowAPI extends UsageFlowAPI {
120
97
  }
121
98
 
122
99
  const metadata = await this.collectRequestMetadata(request);
100
+ metadata.url = url;
123
101
  let ledgerId = this.guessLedgerId(request);
124
102
 
125
103
  try {
@@ -186,20 +164,19 @@ export class ExpressUsageFlowAPI extends UsageFlowAPI {
186
164
  Date.now() - request.usageflow.startTime;
187
165
  }
188
166
 
189
- const payload = {
167
+ const payload: RequestForAllocation = {
190
168
  alias: ledgerId,
191
169
  amount: 1,
192
170
  allocationId: request.usageflow?.eventId,
193
- metadata,
171
+ metadata: metadata as RequestMetadata,
194
172
  };
195
173
 
196
- fetch(`${self.usageflowUrl}/api/v1/ledgers/measure/allocate/use`, {
197
- method: "POST",
198
- headers,
199
- body: JSON.stringify(payload),
200
- }).catch((error) => {
201
- 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;
202
177
  });
178
+ // Send via WebSocket if connected
179
+
203
180
 
204
181
  // Handle the different overloadsx
205
182
  if (typeof chunk === "function") {
@@ -213,7 +190,8 @@ export class ExpressUsageFlowAPI extends UsageFlowAPI {
213
190
 
214
191
  next();
215
192
  } catch (error: any) {
216
- 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);
217
195
  response.status(400).json({
218
196
  message: error.message,
219
197
  blocked: true,
@@ -223,46 +201,4 @@ export class ExpressUsageFlowAPI extends UsageFlowAPI {
223
201
  };
224
202
  }
225
203
 
226
- protected guessLedgerId(request: Request): string {
227
- const method = request.method;
228
- const url = request.route?.path || request.path;
229
- const config = this.apiConfig
230
-
231
- if (!config?.identityFieldName || !config?.identityFieldLocation) {
232
- return `${method} ${url}`;
233
- }
234
-
235
- const fieldName = config.identityFieldName;
236
- const location = config.identityFieldLocation;
237
-
238
- switch (location) {
239
- case "path_params":
240
- if (request.params?.[fieldName]) {
241
- return `${method} ${url} ${request.params[fieldName]}`;
242
- }
243
- break;
244
- case "query_params":
245
- if (request.query?.[fieldName]) {
246
- return `${method} ${url} ${request.query[fieldName]}`;
247
- }
248
- break;
249
- case "body":
250
- if (request.body?.[fieldName]) {
251
- return `${method} ${url} ${request.body[fieldName]}`;
252
- }
253
- break;
254
- case "bearer_token":
255
- const authHeader = request.headers.authorization;
256
- const token = this.extractBearerToken(authHeader);
257
- if (token) {
258
- const claims = this.decodeJwtUnverified(token);
259
- if (claims?.[fieldName]) {
260
- return `${method} ${url} ${claims[fieldName]}`;
261
- }
262
- }
263
- break;
264
- }
265
-
266
- return `${method} ${url}`;
267
- }
268
204
  }