apitally 0.6.1 → 0.7.0

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.
Files changed (198) hide show
  1. package/dist/common/client.cjs +514 -0
  2. package/dist/common/client.cjs.map +1 -0
  3. package/dist/common/client.d.cts +36 -0
  4. package/{lib/types → dist}/common/client.d.ts +12 -9
  5. package/dist/common/client.js +481 -0
  6. package/dist/common/client.js.map +1 -0
  7. package/dist/common/logging.cjs +41 -0
  8. package/dist/common/logging.cjs.map +1 -0
  9. package/dist/common/logging.d.cts +11 -0
  10. package/{lib/types → dist}/common/logging.d.ts +6 -3
  11. package/dist/common/logging.js +18 -0
  12. package/dist/common/logging.js.map +1 -0
  13. package/dist/common/packageVersions.cjs +42 -0
  14. package/dist/common/packageVersions.cjs.map +1 -0
  15. package/dist/common/packageVersions.d.cts +3 -0
  16. package/dist/common/packageVersions.d.ts +3 -0
  17. package/dist/common/packageVersions.js +18 -0
  18. package/dist/common/packageVersions.js.map +1 -0
  19. package/dist/common/paramValidation.cjs +43 -0
  20. package/dist/common/paramValidation.cjs.map +1 -0
  21. package/dist/common/paramValidation.d.cts +4 -0
  22. package/dist/common/paramValidation.d.ts +4 -0
  23. package/dist/common/paramValidation.js +19 -0
  24. package/dist/common/paramValidation.js.map +1 -0
  25. package/dist/common/requestCounter.cjs +111 -0
  26. package/dist/common/requestCounter.cjs.map +1 -0
  27. package/dist/common/requestCounter.d.cts +18 -0
  28. package/{lib/types → dist}/common/requestCounter.d.ts +7 -3
  29. package/dist/common/requestCounter.js +92 -0
  30. package/dist/common/requestCounter.js.map +1 -0
  31. package/dist/common/serverErrorCounter.cjs +133 -0
  32. package/dist/common/serverErrorCounter.cjs.map +1 -0
  33. package/dist/common/serverErrorCounter.d.cts +20 -0
  34. package/{lib/types → dist}/common/serverErrorCounter.d.ts +7 -3
  35. package/dist/common/serverErrorCounter.js +104 -0
  36. package/dist/common/serverErrorCounter.js.map +1 -0
  37. package/dist/common/types.cjs +19 -0
  38. package/dist/common/types.cjs.map +1 -0
  39. package/dist/common/types.d.cts +76 -0
  40. package/{lib/types → dist}/common/types.d.ts +17 -14
  41. package/dist/common/types.js +1 -0
  42. package/dist/common/types.js.map +1 -0
  43. package/dist/common/validationErrorCounter.cjs +76 -0
  44. package/dist/common/validationErrorCounter.cjs.map +1 -0
  45. package/dist/common/validationErrorCounter.d.cts +14 -0
  46. package/{lib/types → dist}/common/validationErrorCounter.d.ts +7 -3
  47. package/dist/common/validationErrorCounter.js +57 -0
  48. package/dist/common/validationErrorCounter.js.map +1 -0
  49. package/dist/express/index.cjs +837 -0
  50. package/dist/express/index.cjs.map +1 -0
  51. package/dist/express/index.d.cts +5 -0
  52. package/dist/express/index.d.ts +5 -0
  53. package/dist/express/index.js +801 -0
  54. package/dist/express/index.js.map +1 -0
  55. package/dist/express/listEndpoints.cjs +144 -0
  56. package/dist/express/listEndpoints.cjs.map +1 -0
  57. package/dist/express/listEndpoints.d.cts +3 -0
  58. package/dist/express/listEndpoints.d.ts +3 -0
  59. package/dist/express/listEndpoints.js +125 -0
  60. package/dist/express/listEndpoints.js.map +1 -0
  61. package/dist/express/middleware.cjs +835 -0
  62. package/dist/express/middleware.cjs.map +1 -0
  63. package/dist/express/middleware.d.cts +14 -0
  64. package/dist/express/middleware.d.ts +14 -0
  65. package/dist/express/middleware.js +801 -0
  66. package/dist/express/middleware.js.map +1 -0
  67. package/dist/fastify/index.cjs +685 -0
  68. package/dist/fastify/index.cjs.map +1 -0
  69. package/dist/fastify/index.d.cts +5 -0
  70. package/dist/fastify/index.d.ts +5 -0
  71. package/dist/fastify/index.js +649 -0
  72. package/dist/fastify/index.js.map +1 -0
  73. package/dist/fastify/plugin.cjs +679 -0
  74. package/dist/fastify/plugin.cjs.map +1 -0
  75. package/dist/fastify/plugin.d.cts +18 -0
  76. package/{lib/types → dist}/fastify/plugin.d.ts +7 -4
  77. package/dist/fastify/plugin.js +649 -0
  78. package/dist/fastify/plugin.js.map +1 -0
  79. package/dist/index.cjs +2 -0
  80. package/dist/index.cjs.map +1 -0
  81. package/dist/index.d.cts +2 -0
  82. package/dist/index.d.ts +2 -0
  83. package/dist/index.js +1 -0
  84. package/dist/index.js.map +1 -0
  85. package/dist/koa/index.cjs +655 -0
  86. package/dist/koa/index.cjs.map +1 -0
  87. package/dist/koa/index.d.cts +5 -0
  88. package/dist/koa/index.d.ts +5 -0
  89. package/dist/koa/index.js +619 -0
  90. package/dist/koa/index.js.map +1 -0
  91. package/dist/koa/middleware.cjs +655 -0
  92. package/dist/koa/middleware.cjs.map +1 -0
  93. package/dist/koa/middleware.d.cts +8 -0
  94. package/dist/koa/middleware.d.ts +8 -0
  95. package/dist/koa/middleware.js +619 -0
  96. package/dist/koa/middleware.js.map +1 -0
  97. package/dist/nestjs/index.cjs +837 -0
  98. package/dist/nestjs/index.cjs.map +1 -0
  99. package/dist/nestjs/index.d.cts +5 -0
  100. package/dist/nestjs/index.d.ts +5 -0
  101. package/dist/nestjs/index.js +801 -0
  102. package/dist/nestjs/index.js.map +1 -0
  103. package/package.json +55 -92
  104. package/lib/cjs/common/client.cjs +0 -334
  105. package/lib/cjs/common/client.cjs.map +0 -1
  106. package/lib/cjs/common/logging.cjs +0 -17
  107. package/lib/cjs/common/logging.cjs.map +0 -1
  108. package/lib/cjs/common/packageVersions.cjs +0 -16
  109. package/lib/cjs/common/packageVersions.cjs.map +0 -1
  110. package/lib/cjs/common/paramValidation.cjs +0 -16
  111. package/lib/cjs/common/paramValidation.cjs.map +0 -1
  112. package/lib/cjs/common/requestCounter.cjs +0 -108
  113. package/lib/cjs/common/requestCounter.cjs.map +0 -1
  114. package/lib/cjs/common/serverErrorCounter.cjs +0 -154
  115. package/lib/cjs/common/serverErrorCounter.cjs.map +0 -1
  116. package/lib/cjs/common/types.cjs +0 -6
  117. package/lib/cjs/common/types.cjs.map +0 -1
  118. package/lib/cjs/common/validationErrorCounter.cjs +0 -60
  119. package/lib/cjs/common/validationErrorCounter.cjs.map +0 -1
  120. package/lib/cjs/express/index.cjs +0 -13
  121. package/lib/cjs/express/index.cjs.map +0 -1
  122. package/lib/cjs/express/listEndpoints.cjs +0 -177
  123. package/lib/cjs/express/listEndpoints.cjs.map +0 -1
  124. package/lib/cjs/express/middleware.cjs +0 -189
  125. package/lib/cjs/express/middleware.cjs.map +0 -1
  126. package/lib/cjs/fastify/index.cjs +0 -14
  127. package/lib/cjs/fastify/index.cjs.map +0 -1
  128. package/lib/cjs/fastify/plugin.cjs +0 -171
  129. package/lib/cjs/fastify/plugin.cjs.map +0 -1
  130. package/lib/cjs/index.cjs +0 -6
  131. package/lib/cjs/index.cjs.map +0 -1
  132. package/lib/cjs/koa/index.cjs +0 -13
  133. package/lib/cjs/koa/index.cjs.map +0 -1
  134. package/lib/cjs/koa/middleware.cjs +0 -139
  135. package/lib/cjs/koa/middleware.cjs.map +0 -1
  136. package/lib/cjs/nestjs/index.cjs +0 -13
  137. package/lib/cjs/nestjs/index.cjs.map +0 -1
  138. package/lib/esm/common/client.js +0 -324
  139. package/lib/esm/common/client.js.map +0 -1
  140. package/lib/esm/common/logging.js +0 -11
  141. package/lib/esm/common/logging.js.map +0 -1
  142. package/lib/esm/common/packageVersions.js +0 -10
  143. package/lib/esm/common/packageVersions.js.map +0 -1
  144. package/lib/esm/common/paramValidation.js +0 -9
  145. package/lib/esm/common/paramValidation.js.map +0 -1
  146. package/lib/esm/common/requestCounter.js +0 -102
  147. package/lib/esm/common/requestCounter.js.map +0 -1
  148. package/lib/esm/common/serverErrorCounter.js +0 -143
  149. package/lib/esm/common/serverErrorCounter.js.map +0 -1
  150. package/lib/esm/common/types.js +0 -1
  151. package/lib/esm/common/types.js.map +0 -1
  152. package/lib/esm/common/validationErrorCounter.js +0 -54
  153. package/lib/esm/common/validationErrorCounter.js.map +0 -1
  154. package/lib/esm/express/index.js +0 -1
  155. package/lib/esm/express/index.js.map +0 -1
  156. package/lib/esm/express/listEndpoints.js +0 -170
  157. package/lib/esm/express/listEndpoints.js.map +0 -1
  158. package/lib/esm/express/middleware.js +0 -182
  159. package/lib/esm/express/middleware.js.map +0 -1
  160. package/lib/esm/fastify/index.js +0 -1
  161. package/lib/esm/fastify/index.js.map +0 -1
  162. package/lib/esm/fastify/plugin.js +0 -164
  163. package/lib/esm/fastify/plugin.js.map +0 -1
  164. package/lib/esm/index.js +0 -1
  165. package/lib/esm/index.js.map +0 -1
  166. package/lib/esm/koa/index.js +0 -1
  167. package/lib/esm/koa/index.js.map +0 -1
  168. package/lib/esm/koa/middleware.js +0 -132
  169. package/lib/esm/koa/middleware.js.map +0 -1
  170. package/lib/esm/nestjs/index.js +0 -1
  171. package/lib/esm/nestjs/index.js.map +0 -1
  172. package/lib/types/common/client.d.ts.map +0 -1
  173. package/lib/types/common/logging.d.ts.map +0 -1
  174. package/lib/types/common/packageVersions.d.ts +0 -2
  175. package/lib/types/common/packageVersions.d.ts.map +0 -1
  176. package/lib/types/common/paramValidation.d.ts +0 -3
  177. package/lib/types/common/paramValidation.d.ts.map +0 -1
  178. package/lib/types/common/requestCounter.d.ts.map +0 -1
  179. package/lib/types/common/serverErrorCounter.d.ts.map +0 -1
  180. package/lib/types/common/types.d.ts.map +0 -1
  181. package/lib/types/common/validationErrorCounter.d.ts.map +0 -1
  182. package/lib/types/express/index.d.ts +0 -2
  183. package/lib/types/express/index.d.ts.map +0 -1
  184. package/lib/types/express/listEndpoints.d.ts +0 -3
  185. package/lib/types/express/listEndpoints.d.ts.map +0 -1
  186. package/lib/types/express/middleware.d.ts +0 -10
  187. package/lib/types/express/middleware.d.ts.map +0 -1
  188. package/lib/types/fastify/index.d.ts +0 -2
  189. package/lib/types/fastify/index.d.ts.map +0 -1
  190. package/lib/types/fastify/plugin.d.ts.map +0 -1
  191. package/lib/types/index.d.ts +0 -2
  192. package/lib/types/index.d.ts.map +0 -1
  193. package/lib/types/koa/index.d.ts +0 -2
  194. package/lib/types/koa/index.d.ts.map +0 -1
  195. package/lib/types/koa/middleware.d.ts +0 -4
  196. package/lib/types/koa/middleware.d.ts.map +0 -1
  197. package/lib/types/nestjs/index.d.ts +0 -2
  198. package/lib/types/nestjs/index.d.ts.map +0 -1
@@ -0,0 +1,619 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
4
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
+
6
+ // src/common/client.ts
7
+ import { randomUUID } from "crypto";
8
+ import fetchRetry from "fetch-retry";
9
+
10
+ // src/common/logging.ts
11
+ import { createLogger, format, transports } from "winston";
12
+ var getLogger = /* @__PURE__ */ __name(() => {
13
+ return createLogger({
14
+ level: process.env.APITALLY_DEBUG ? "debug" : "warn",
15
+ format: format.combine(format.colorize(), format.timestamp(), format.printf((info) => `${info.timestamp} ${info.level}: ${info.message}`)),
16
+ transports: [
17
+ new transports.Console()
18
+ ]
19
+ });
20
+ }, "getLogger");
21
+
22
+ // src/common/paramValidation.ts
23
+ function isValidClientId(clientId) {
24
+ const regexExp = /^[0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
25
+ return regexExp.test(clientId);
26
+ }
27
+ __name(isValidClientId, "isValidClientId");
28
+ function isValidEnv(env) {
29
+ const regexExp = /^[\w-]{1,32}$/;
30
+ return regexExp.test(env);
31
+ }
32
+ __name(isValidEnv, "isValidEnv");
33
+
34
+ // src/common/requestCounter.ts
35
+ var _RequestCounter = class _RequestCounter {
36
+ requestCounts;
37
+ requestSizeSums;
38
+ responseSizeSums;
39
+ responseTimes;
40
+ requestSizes;
41
+ responseSizes;
42
+ constructor() {
43
+ this.requestCounts = /* @__PURE__ */ new Map();
44
+ this.requestSizeSums = /* @__PURE__ */ new Map();
45
+ this.responseSizeSums = /* @__PURE__ */ new Map();
46
+ this.responseTimes = /* @__PURE__ */ new Map();
47
+ this.requestSizes = /* @__PURE__ */ new Map();
48
+ this.responseSizes = /* @__PURE__ */ new Map();
49
+ }
50
+ getKey(requestInfo) {
51
+ return [
52
+ requestInfo.consumer || "",
53
+ requestInfo.method.toUpperCase(),
54
+ requestInfo.path,
55
+ requestInfo.statusCode
56
+ ].join("|");
57
+ }
58
+ addRequest(requestInfo) {
59
+ const key = this.getKey(requestInfo);
60
+ this.requestCounts.set(key, (this.requestCounts.get(key) || 0) + 1);
61
+ if (!this.responseTimes.has(key)) {
62
+ this.responseTimes.set(key, /* @__PURE__ */ new Map());
63
+ }
64
+ const responseTimeMap = this.responseTimes.get(key);
65
+ const responseTimeMsBin = Math.floor(requestInfo.responseTime / 10) * 10;
66
+ responseTimeMap.set(responseTimeMsBin, (responseTimeMap.get(responseTimeMsBin) || 0) + 1);
67
+ if (requestInfo.requestSize !== void 0) {
68
+ requestInfo.requestSize = Number(requestInfo.requestSize);
69
+ this.requestSizeSums.set(key, (this.requestSizeSums.get(key) || 0) + requestInfo.requestSize);
70
+ if (!this.requestSizes.has(key)) {
71
+ this.requestSizes.set(key, /* @__PURE__ */ new Map());
72
+ }
73
+ const requestSizeMap = this.requestSizes.get(key);
74
+ const requestSizeKbBin = Math.floor(requestInfo.requestSize / 1e3);
75
+ requestSizeMap.set(requestSizeKbBin, (requestSizeMap.get(requestSizeKbBin) || 0) + 1);
76
+ }
77
+ if (requestInfo.responseSize !== void 0) {
78
+ requestInfo.responseSize = Number(requestInfo.responseSize);
79
+ this.responseSizeSums.set(key, (this.responseSizeSums.get(key) || 0) + requestInfo.responseSize);
80
+ if (!this.responseSizes.has(key)) {
81
+ this.responseSizes.set(key, /* @__PURE__ */ new Map());
82
+ }
83
+ const responseSizeMap = this.responseSizes.get(key);
84
+ const responseSizeKbBin = Math.floor(requestInfo.responseSize / 1e3);
85
+ responseSizeMap.set(responseSizeKbBin, (responseSizeMap.get(responseSizeKbBin) || 0) + 1);
86
+ }
87
+ }
88
+ getAndResetRequests() {
89
+ const data = [];
90
+ this.requestCounts.forEach((count, key) => {
91
+ const [consumer, method, path, statusCodeStr] = key.split("|");
92
+ const responseTimes = this.responseTimes.get(key) || /* @__PURE__ */ new Map();
93
+ const requestSizes = this.requestSizes.get(key) || /* @__PURE__ */ new Map();
94
+ const responseSizes = this.responseSizes.get(key) || /* @__PURE__ */ new Map();
95
+ data.push({
96
+ consumer: consumer || null,
97
+ method,
98
+ path,
99
+ status_code: parseInt(statusCodeStr),
100
+ request_count: count,
101
+ request_size_sum: this.requestSizeSums.get(key) || 0,
102
+ response_size_sum: this.responseSizeSums.get(key) || 0,
103
+ response_times: Object.fromEntries(responseTimes),
104
+ request_sizes: Object.fromEntries(requestSizes),
105
+ response_sizes: Object.fromEntries(responseSizes)
106
+ });
107
+ });
108
+ this.requestCounts.clear();
109
+ this.requestSizeSums.clear();
110
+ this.responseSizeSums.clear();
111
+ this.responseTimes.clear();
112
+ this.requestSizes.clear();
113
+ this.responseSizes.clear();
114
+ return data;
115
+ }
116
+ };
117
+ __name(_RequestCounter, "RequestCounter");
118
+ var RequestCounter = _RequestCounter;
119
+
120
+ // src/common/serverErrorCounter.ts
121
+ import { createHash } from "crypto";
122
+ var MAX_MSG_LENGTH = 2048;
123
+ var MAX_STACKTRACE_LENGTH = 65536;
124
+ var _ServerErrorCounter = class _ServerErrorCounter {
125
+ errorCounts;
126
+ errorDetails;
127
+ sentryEventIds;
128
+ sentry;
129
+ constructor() {
130
+ this.errorCounts = /* @__PURE__ */ new Map();
131
+ this.errorDetails = /* @__PURE__ */ new Map();
132
+ this.sentryEventIds = /* @__PURE__ */ new Map();
133
+ this.tryImportSentry();
134
+ }
135
+ addServerError(serverError) {
136
+ const key = this.getKey(serverError);
137
+ if (!this.errorDetails.has(key)) {
138
+ this.errorDetails.set(key, serverError);
139
+ }
140
+ this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);
141
+ this.captureSentryEventId(key);
142
+ }
143
+ getAndResetServerErrors() {
144
+ const data = [];
145
+ this.errorCounts.forEach((count, key) => {
146
+ const serverError = this.errorDetails.get(key);
147
+ if (serverError) {
148
+ data.push({
149
+ consumer: serverError.consumer || null,
150
+ method: serverError.method,
151
+ path: serverError.path,
152
+ type: serverError.type,
153
+ msg: this.getTruncatedMessage(serverError.msg),
154
+ traceback: this.getTruncatedStack(serverError.traceback),
155
+ sentry_event_id: this.sentryEventIds.get(key) || null,
156
+ error_count: count
157
+ });
158
+ }
159
+ });
160
+ this.errorCounts.clear();
161
+ this.errorDetails.clear();
162
+ return data;
163
+ }
164
+ getKey(serverError) {
165
+ const hashInput = [
166
+ serverError.consumer || "",
167
+ serverError.method.toUpperCase(),
168
+ serverError.path,
169
+ serverError.type,
170
+ serverError.msg.trim(),
171
+ serverError.traceback.trim()
172
+ ].join("|");
173
+ return createHash("md5").update(hashInput).digest("hex");
174
+ }
175
+ getTruncatedMessage(msg) {
176
+ msg = msg.trim();
177
+ if (msg.length <= MAX_MSG_LENGTH) {
178
+ return msg;
179
+ }
180
+ const suffix = "... (truncated)";
181
+ const cutoff = MAX_MSG_LENGTH - suffix.length;
182
+ return msg.substring(0, cutoff) + suffix;
183
+ }
184
+ getTruncatedStack(stack) {
185
+ const suffix = "... (truncated) ...";
186
+ const cutoff = MAX_STACKTRACE_LENGTH - suffix.length;
187
+ const lines = stack.trim().split("\n");
188
+ const truncatedLines = [];
189
+ let length = 0;
190
+ for (const line of lines) {
191
+ if (length + line.length + 1 > cutoff) {
192
+ truncatedLines.push(suffix);
193
+ break;
194
+ }
195
+ truncatedLines.push(line);
196
+ length += line.length + 1;
197
+ }
198
+ return truncatedLines.join("\n");
199
+ }
200
+ captureSentryEventId(serverErrorKey) {
201
+ if (this.sentry && this.sentry.lastEventId) {
202
+ const eventId = this.sentry.lastEventId();
203
+ if (eventId) {
204
+ this.sentryEventIds.set(serverErrorKey, eventId);
205
+ }
206
+ }
207
+ }
208
+ async tryImportSentry() {
209
+ try {
210
+ this.sentry = await import("@sentry/node");
211
+ } catch (e) {
212
+ }
213
+ }
214
+ };
215
+ __name(_ServerErrorCounter, "ServerErrorCounter");
216
+ var ServerErrorCounter = _ServerErrorCounter;
217
+
218
+ // src/common/validationErrorCounter.ts
219
+ import { createHash as createHash2 } from "crypto";
220
+ var _ValidationErrorCounter = class _ValidationErrorCounter {
221
+ errorCounts;
222
+ errorDetails;
223
+ constructor() {
224
+ this.errorCounts = /* @__PURE__ */ new Map();
225
+ this.errorDetails = /* @__PURE__ */ new Map();
226
+ }
227
+ addValidationError(validationError) {
228
+ const key = this.getKey(validationError);
229
+ if (!this.errorDetails.has(key)) {
230
+ this.errorDetails.set(key, validationError);
231
+ }
232
+ this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);
233
+ }
234
+ getAndResetValidationErrors() {
235
+ const data = [];
236
+ this.errorCounts.forEach((count, key) => {
237
+ const validationError = this.errorDetails.get(key);
238
+ if (validationError) {
239
+ data.push({
240
+ consumer: validationError.consumer || null,
241
+ method: validationError.method,
242
+ path: validationError.path,
243
+ loc: validationError.loc.split("."),
244
+ msg: validationError.msg,
245
+ type: validationError.type,
246
+ error_count: count
247
+ });
248
+ }
249
+ });
250
+ this.errorCounts.clear();
251
+ this.errorDetails.clear();
252
+ return data;
253
+ }
254
+ getKey(validationError) {
255
+ const hashInput = [
256
+ validationError.consumer || "",
257
+ validationError.method.toUpperCase(),
258
+ validationError.path,
259
+ validationError.loc,
260
+ validationError.msg.trim(),
261
+ validationError.type
262
+ ].join("|");
263
+ return createHash2("md5").update(hashInput).digest("hex");
264
+ }
265
+ };
266
+ __name(_ValidationErrorCounter, "ValidationErrorCounter");
267
+ var ValidationErrorCounter = _ValidationErrorCounter;
268
+
269
+ // src/common/client.ts
270
+ var SYNC_INTERVAL = 6e4;
271
+ var INITIAL_SYNC_INTERVAL = 1e4;
272
+ var INITIAL_SYNC_INTERVAL_DURATION = 36e5;
273
+ var MAX_QUEUE_TIME = 36e5;
274
+ var _a;
275
+ var HTTPError = (_a = class extends Error {
276
+ response;
277
+ constructor(response) {
278
+ const reason = response.status ? `status code ${response.status}` : "an unknown error";
279
+ super(`Request failed with ${reason}`);
280
+ this.response = response;
281
+ }
282
+ }, __name(_a, "HTTPError"), _a);
283
+ var _ApitallyClient = class _ApitallyClient {
284
+ clientId;
285
+ env;
286
+ instanceUuid;
287
+ requestsDataQueue;
288
+ syncIntervalId;
289
+ appInfo;
290
+ appInfoSent = false;
291
+ requestCounter;
292
+ validationErrorCounter;
293
+ serverErrorCounter;
294
+ logger;
295
+ constructor({ clientId, env = "dev", logger }) {
296
+ if (_ApitallyClient.instance) {
297
+ throw new Error("Apitally client is already initialized");
298
+ }
299
+ if (!isValidClientId(clientId)) {
300
+ throw new Error(`Invalid client ID '${clientId}' (expecting hexadeciaml UUID format)`);
301
+ }
302
+ if (!isValidEnv(env)) {
303
+ throw new Error(`Invalid env '${env}' (expecting 1-32 alphanumeric lowercase characters and hyphens only)`);
304
+ }
305
+ _ApitallyClient.instance = this;
306
+ this.clientId = clientId;
307
+ this.env = env;
308
+ this.instanceUuid = randomUUID();
309
+ this.requestsDataQueue = [];
310
+ this.requestCounter = new RequestCounter();
311
+ this.validationErrorCounter = new ValidationErrorCounter();
312
+ this.serverErrorCounter = new ServerErrorCounter();
313
+ this.logger = logger || getLogger();
314
+ this.startSync();
315
+ this.handleShutdown = this.handleShutdown.bind(this);
316
+ }
317
+ static getInstance() {
318
+ if (!_ApitallyClient.instance) {
319
+ throw new Error("Apitally client is not initialized");
320
+ }
321
+ return _ApitallyClient.instance;
322
+ }
323
+ static async shutdown() {
324
+ if (_ApitallyClient.instance) {
325
+ await _ApitallyClient.instance.handleShutdown();
326
+ }
327
+ }
328
+ async handleShutdown() {
329
+ this.stopSync();
330
+ await this.sendRequestsData();
331
+ _ApitallyClient.instance = void 0;
332
+ }
333
+ getHubUrlPrefix() {
334
+ const baseURL = process.env.APITALLY_HUB_BASE_URL || "https://hub.apitally.io";
335
+ const version = "v1";
336
+ return `${baseURL}/${version}/${this.clientId}/${this.env}/`;
337
+ }
338
+ async makeHubRequest(url, payload) {
339
+ const fetchWithRetry = fetchRetry(fetch, {
340
+ retries: 3,
341
+ retryDelay: 1e3,
342
+ retryOn: [
343
+ 408,
344
+ 429,
345
+ 500,
346
+ 502,
347
+ 503,
348
+ 504
349
+ ]
350
+ });
351
+ const response = await fetchWithRetry(this.getHubUrlPrefix() + url, {
352
+ method: "POST",
353
+ body: JSON.stringify(payload),
354
+ headers: {
355
+ "Content-Type": "application/json"
356
+ }
357
+ });
358
+ if (!response.ok) {
359
+ throw new HTTPError(response);
360
+ }
361
+ }
362
+ startSync() {
363
+ this.sync();
364
+ this.syncIntervalId = setInterval(() => {
365
+ this.sync();
366
+ }, INITIAL_SYNC_INTERVAL);
367
+ setTimeout(() => {
368
+ clearInterval(this.syncIntervalId);
369
+ this.syncIntervalId = setInterval(() => {
370
+ this.sync();
371
+ }, SYNC_INTERVAL);
372
+ }, INITIAL_SYNC_INTERVAL_DURATION);
373
+ }
374
+ async sync() {
375
+ try {
376
+ const promises = [
377
+ this.sendRequestsData()
378
+ ];
379
+ if (!this.appInfoSent) {
380
+ promises.push(this.sendAppInfo());
381
+ }
382
+ await Promise.all(promises);
383
+ } catch (error) {
384
+ this.logger.error("Error while syncing with Apitally Hub", {
385
+ error
386
+ });
387
+ }
388
+ }
389
+ stopSync() {
390
+ if (this.syncIntervalId) {
391
+ clearInterval(this.syncIntervalId);
392
+ this.syncIntervalId = void 0;
393
+ }
394
+ }
395
+ setAppInfo(appInfo) {
396
+ this.appInfo = appInfo;
397
+ this.appInfoSent = false;
398
+ this.sendAppInfo();
399
+ }
400
+ async sendAppInfo() {
401
+ if (this.appInfo) {
402
+ this.logger.debug("Sending app info to Apitally Hub");
403
+ const payload = {
404
+ instance_uuid: this.instanceUuid,
405
+ message_uuid: randomUUID(),
406
+ ...this.appInfo
407
+ };
408
+ try {
409
+ await this.makeHubRequest("info", payload);
410
+ this.appInfoSent = true;
411
+ } catch (error) {
412
+ const handled = this.handleHubError(error);
413
+ if (!handled) {
414
+ this.logger.error(error.message);
415
+ this.logger.debug("Error while sending app info to Apitally Hub (will retry)", {
416
+ error
417
+ });
418
+ }
419
+ }
420
+ }
421
+ }
422
+ async sendRequestsData() {
423
+ this.logger.debug("Sending requests data to Apitally Hub");
424
+ const newPayload = {
425
+ time_offset: 0,
426
+ instance_uuid: this.instanceUuid,
427
+ message_uuid: randomUUID(),
428
+ requests: this.requestCounter.getAndResetRequests(),
429
+ validation_errors: this.validationErrorCounter.getAndResetValidationErrors(),
430
+ server_errors: this.serverErrorCounter.getAndResetServerErrors()
431
+ };
432
+ this.requestsDataQueue.push([
433
+ Date.now(),
434
+ newPayload
435
+ ]);
436
+ const failedItems = [];
437
+ while (this.requestsDataQueue.length > 0) {
438
+ const queueItem = this.requestsDataQueue.shift();
439
+ if (queueItem) {
440
+ const [time, payload] = queueItem;
441
+ try {
442
+ const timeOffset = Date.now() - time;
443
+ if (timeOffset <= MAX_QUEUE_TIME) {
444
+ payload.time_offset = timeOffset / 1e3;
445
+ await this.makeHubRequest("requests", payload);
446
+ }
447
+ } catch (error) {
448
+ const handled = this.handleHubError(error);
449
+ if (!handled) {
450
+ this.logger.debug("Error while sending requests data to Apitally Hub (will retry)", {
451
+ error
452
+ });
453
+ failedItems.push(queueItem);
454
+ }
455
+ }
456
+ }
457
+ }
458
+ this.requestsDataQueue = failedItems;
459
+ }
460
+ handleHubError(error) {
461
+ if (error instanceof HTTPError) {
462
+ if (error.response.status === 404) {
463
+ this.logger.error(`Invalid Apitally client ID: '${this.clientId}'`);
464
+ this.stopSync();
465
+ return true;
466
+ }
467
+ if (error.response.status === 422) {
468
+ this.logger.error("Received validation error from Apitally Hub");
469
+ return true;
470
+ }
471
+ }
472
+ return false;
473
+ }
474
+ };
475
+ __name(_ApitallyClient, "ApitallyClient");
476
+ __publicField(_ApitallyClient, "instance");
477
+ var ApitallyClient = _ApitallyClient;
478
+
479
+ // src/common/packageVersions.ts
480
+ import { createRequire } from "module";
481
+ function getPackageVersion(name) {
482
+ try {
483
+ const _require = createRequire(import.meta.url);
484
+ return _require(`${name}/package.json`).version || null;
485
+ } catch (error) {
486
+ return null;
487
+ }
488
+ }
489
+ __name(getPackageVersion, "getPackageVersion");
490
+
491
+ // src/koa/middleware.ts
492
+ var useApitally = /* @__PURE__ */ __name((app, config) => {
493
+ const client = new ApitallyClient(config);
494
+ const middleware = getMiddleware(client);
495
+ app.use(middleware);
496
+ setTimeout(() => {
497
+ client.setAppInfo(getAppInfo(app, config.appVersion));
498
+ }, 1e3);
499
+ }, "useApitally");
500
+ var getMiddleware = /* @__PURE__ */ __name((client) => {
501
+ return async (ctx, next) => {
502
+ let path;
503
+ let statusCode;
504
+ const startTime = performance.now();
505
+ try {
506
+ await next();
507
+ } catch (error) {
508
+ path = getPath(ctx);
509
+ statusCode = error.statusCode || error.status || 500;
510
+ if (path && statusCode === 500 && error instanceof Error) {
511
+ client.serverErrorCounter.addServerError({
512
+ consumer: getConsumer(ctx),
513
+ method: ctx.request.method,
514
+ path,
515
+ type: error.name,
516
+ msg: error.message,
517
+ traceback: error.stack || ""
518
+ });
519
+ }
520
+ throw error;
521
+ } finally {
522
+ if (!path) {
523
+ path = getPath(ctx);
524
+ }
525
+ if (path) {
526
+ try {
527
+ client.requestCounter.addRequest({
528
+ consumer: getConsumer(ctx),
529
+ method: ctx.request.method,
530
+ path,
531
+ statusCode: statusCode || ctx.response.status,
532
+ responseTime: performance.now() - startTime,
533
+ requestSize: ctx.request.length,
534
+ responseSize: ctx.response.length
535
+ });
536
+ } catch (error) {
537
+ client.logger.error("Error while logging request in Apitally middleware.", {
538
+ context: ctx,
539
+ error
540
+ });
541
+ }
542
+ }
543
+ }
544
+ };
545
+ }, "getMiddleware");
546
+ var getPath = /* @__PURE__ */ __name((ctx) => {
547
+ return ctx._matchedRoute || ctx.routePath;
548
+ }, "getPath");
549
+ var getConsumer = /* @__PURE__ */ __name((ctx) => {
550
+ if (ctx.state.apitallyConsumer) {
551
+ return String(ctx.state.apitallyConsumer);
552
+ } else if (ctx.state.consumerIdentifier) {
553
+ return String(ctx.state.consumerIdentifier);
554
+ }
555
+ return null;
556
+ }, "getConsumer");
557
+ var getAppInfo = /* @__PURE__ */ __name((app, appVersion) => {
558
+ const versions = [
559
+ [
560
+ "nodejs",
561
+ process.version.replace(/^v/, "")
562
+ ]
563
+ ];
564
+ const koaVersion = getPackageVersion("koa");
565
+ const apitallyVersion = getPackageVersion("../..");
566
+ if (koaVersion) {
567
+ versions.push([
568
+ "koa",
569
+ koaVersion
570
+ ]);
571
+ }
572
+ if (apitallyVersion) {
573
+ versions.push([
574
+ "apitally",
575
+ apitallyVersion
576
+ ]);
577
+ }
578
+ if (appVersion) {
579
+ versions.push([
580
+ "app",
581
+ appVersion
582
+ ]);
583
+ }
584
+ return {
585
+ paths: listEndpoints(app),
586
+ versions: Object.fromEntries(versions),
587
+ client: "js:koa"
588
+ };
589
+ }, "getAppInfo");
590
+ var isKoaRouterMiddleware = /* @__PURE__ */ __name((middleware) => {
591
+ return typeof middleware === "function" && middleware.router && Array.isArray(middleware.router.stack);
592
+ }, "isKoaRouterMiddleware");
593
+ var listEndpoints = /* @__PURE__ */ __name((app) => {
594
+ const endpoints = [];
595
+ app.middleware.forEach((middleware) => {
596
+ if (isKoaRouterMiddleware(middleware)) {
597
+ middleware.router.stack.forEach((layer) => {
598
+ if (layer.methods && layer.methods.length > 0) {
599
+ layer.methods.forEach((method) => {
600
+ if (![
601
+ "HEAD",
602
+ "OPTIONS"
603
+ ].includes(method.toUpperCase())) {
604
+ endpoints.push({
605
+ method: method.toUpperCase(),
606
+ path: layer.path
607
+ });
608
+ }
609
+ });
610
+ }
611
+ });
612
+ }
613
+ });
614
+ return endpoints;
615
+ }, "listEndpoints");
616
+ export {
617
+ useApitally
618
+ };
619
+ //# sourceMappingURL=index.js.map