@faststats/nitro 0.5.0 → 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.
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import { createRequire } from "node:module";
|
|
2
|
-
import { readFileSync } from "node:fs";
|
|
3
|
-
import { version } from "node:os";
|
|
4
1
|
//#region src/options.ts
|
|
5
2
|
const DEFAULT_ENDPOINT = "https://metrics.faststats.dev/v1/error";
|
|
6
3
|
const envInt = (key, fallback) => {
|
|
@@ -23,18 +20,9 @@ function resolveFaststatsNitroOptions(overrides = {}) {
|
|
|
23
20
|
};
|
|
24
21
|
}
|
|
25
22
|
const SDK_NAME = "@faststats/nitro";
|
|
26
|
-
const SDK_VERSION = "0.
|
|
23
|
+
const SDK_VERSION = "0.7.0";
|
|
27
24
|
//#endregion
|
|
28
25
|
//#region src/context.ts
|
|
29
|
-
function readPackageVersion(name) {
|
|
30
|
-
try {
|
|
31
|
-
const raw = readFileSync(createRequire(import.meta.url).resolve(`${name}/package.json`), "utf8");
|
|
32
|
-
const pkg = JSON.parse(raw);
|
|
33
|
-
return typeof pkg.version === "string" ? pkg.version : void 0;
|
|
34
|
-
} catch {
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
26
|
function detectRuntime() {
|
|
39
27
|
if (typeof Bun !== "undefined" && Bun.version !== void 0) return {
|
|
40
28
|
runtime: "bun",
|
|
@@ -67,15 +55,11 @@ function buildServerReportContext(extra = {}) {
|
|
|
67
55
|
return {
|
|
68
56
|
source: "@faststats/nitro",
|
|
69
57
|
...extra,
|
|
70
|
-
nitroVersion: readPackageVersion("nitropack") ?? readPackageVersion("nitro"),
|
|
71
58
|
nitroPreset: process?.env?.NITRO_PRESET,
|
|
72
59
|
runtime,
|
|
73
60
|
runtimeVersion,
|
|
74
|
-
os: process?.release?.name ?? "unknown",
|
|
75
|
-
osVersion: version() || "unknown",
|
|
76
61
|
platform: process?.platform ?? "unknown",
|
|
77
|
-
arch: process?.arch ?? "unknown"
|
|
78
|
-
...process?.cwd?.() ? { cwd: process.cwd() } : {}
|
|
62
|
+
arch: process?.arch ?? "unknown"
|
|
79
63
|
};
|
|
80
64
|
}
|
|
81
65
|
//#endregion
|
|
@@ -97,39 +81,19 @@ function serializeCause(cause) {
|
|
|
97
81
|
message: cause
|
|
98
82
|
};
|
|
99
83
|
}
|
|
100
|
-
function
|
|
101
|
-
if (!cause) return "";
|
|
102
|
-
return `${cause.error}\0${cause.message ?? ""}\0${causeFingerprint(cause.cause)}`;
|
|
103
|
-
}
|
|
104
|
-
function hashMessage(message, cause) {
|
|
105
|
-
const key = [
|
|
106
|
-
"error",
|
|
107
|
-
message,
|
|
108
|
-
"",
|
|
109
|
-
"",
|
|
110
|
-
causeFingerprint(cause)
|
|
111
|
-
].join("\0");
|
|
112
|
-
let a = 2166136261;
|
|
113
|
-
let b = 3598710387;
|
|
114
|
-
for (let i = 0; i < key.length; i++) {
|
|
115
|
-
const c = key.charCodeAt(i);
|
|
116
|
-
a = Math.imul(a ^ c, 16777619);
|
|
117
|
-
b = Math.imul(b ^ c, 2246822519);
|
|
118
|
-
}
|
|
119
|
-
return `err_${(a >>> 0).toString(16).padStart(8, "0")}${(b >>> 0).toString(16).padStart(8, "0")}`;
|
|
120
|
-
}
|
|
121
|
-
function hashServerError(error) {
|
|
84
|
+
function normalizeServerError(error) {
|
|
122
85
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
123
86
|
const name = err.name?.trim() || "Error";
|
|
124
87
|
const cause = serializeCause(err.cause);
|
|
88
|
+
const entry = {
|
|
89
|
+
error: name,
|
|
90
|
+
message: err.message,
|
|
91
|
+
stack: parseStack(err.stack),
|
|
92
|
+
...cause ? { cause } : {}
|
|
93
|
+
};
|
|
125
94
|
return {
|
|
126
|
-
|
|
127
|
-
entry
|
|
128
|
-
error: name,
|
|
129
|
-
message: err.message,
|
|
130
|
-
stack: parseStack(err.stack),
|
|
131
|
-
...cause ? { cause } : {}
|
|
132
|
-
}
|
|
95
|
+
key: JSON.stringify(entry),
|
|
96
|
+
entry
|
|
133
97
|
};
|
|
134
98
|
}
|
|
135
99
|
//#endregion
|
|
@@ -139,55 +103,40 @@ const defaultRuntime = {
|
|
|
139
103
|
setTimeout: (callback, delay) => setTimeout(callback, delay),
|
|
140
104
|
clearTimeout: (timer) => clearTimeout(timer),
|
|
141
105
|
now: () => Date.now(),
|
|
142
|
-
randomUUID: () => crypto.randomUUID?.() ?? `sess-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`,
|
|
143
106
|
warn: (...args) => console.warn(...args)
|
|
144
107
|
};
|
|
145
108
|
function definedStrings(context) {
|
|
146
109
|
return Object.fromEntries(Object.entries(context).filter(([, value]) => value !== void 0 && value !== ""));
|
|
147
110
|
}
|
|
111
|
+
function mergeBucket(target, incoming) {
|
|
112
|
+
target.count += incoming.count;
|
|
113
|
+
}
|
|
148
114
|
function mergeBuckets(target, incoming) {
|
|
149
115
|
for (const [hash, bucket] of incoming) {
|
|
150
116
|
const existing = target.get(hash);
|
|
151
|
-
if (
|
|
152
|
-
|
|
153
|
-
continue;
|
|
154
|
-
}
|
|
155
|
-
existing.count += bucket.count;
|
|
156
|
-
if (bucket.path !== void 0) existing.path = bucket.path;
|
|
157
|
-
if (bucket.tags.length > 0) existing.tags = bucket.tags;
|
|
117
|
+
if (existing) mergeBucket(existing, bucket);
|
|
118
|
+
else target.set(hash, { ...bucket });
|
|
158
119
|
}
|
|
159
120
|
}
|
|
160
|
-
function buildPayload(buckets, options
|
|
161
|
-
const errors = [
|
|
121
|
+
function buildPayload(buckets, options) {
|
|
122
|
+
const errors = [];
|
|
123
|
+
for (const bucket of buckets.values()) errors.push({
|
|
162
124
|
...bucket.entry,
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
let routeCount = -1;
|
|
169
|
-
const custom = {};
|
|
170
|
-
for (const bucket of buckets.values()) {
|
|
171
|
-
if (bucket.path !== void 0 && bucket.count > routeCount) {
|
|
172
|
-
routeCount = bucket.count;
|
|
173
|
-
route = bucket.path;
|
|
125
|
+
count: bucket.count,
|
|
126
|
+
context: {
|
|
127
|
+
...bucket.path ? { route: bucket.path } : {},
|
|
128
|
+
...bucket.tags.length ? { tags: bucket.tags.join(",") } : {},
|
|
129
|
+
...bucket.custom
|
|
174
130
|
}
|
|
175
|
-
|
|
176
|
-
}
|
|
131
|
+
});
|
|
177
132
|
return {
|
|
178
133
|
errors,
|
|
179
|
-
|
|
134
|
+
language: "javascript",
|
|
135
|
+
...options.sessionId ? { sessionId: options.sessionId } : {},
|
|
180
136
|
...options.buildId ? { buildId: options.buildId } : {},
|
|
181
137
|
sdkName: SDK_NAME,
|
|
182
138
|
sdkVersion: SDK_VERSION,
|
|
183
|
-
context: {
|
|
184
|
-
...definedStrings(buildServerReportContext({
|
|
185
|
-
route,
|
|
186
|
-
plugin: options.pluginId,
|
|
187
|
-
tags: tags.length > 0 ? tags.join(",") : void 0
|
|
188
|
-
})),
|
|
189
|
-
...custom
|
|
190
|
-
}
|
|
139
|
+
context: definedStrings(buildServerReportContext({ plugin: options.pluginId }))
|
|
191
140
|
};
|
|
192
141
|
}
|
|
193
142
|
function createNitroErrorReporter(options, runtime) {
|
|
@@ -196,16 +145,10 @@ function createNitroErrorReporter(options, runtime) {
|
|
|
196
145
|
let flushing = false;
|
|
197
146
|
let consecutiveFailures = 0;
|
|
198
147
|
let pausedUntil = 0;
|
|
199
|
-
let sessionId = options.sessionId;
|
|
200
|
-
const getSessionId = () => {
|
|
201
|
-
sessionId ??= runtime.randomUUID();
|
|
202
|
-
return sessionId;
|
|
203
|
-
};
|
|
204
148
|
const clearTimer = () => {
|
|
205
|
-
if (timer
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
}
|
|
149
|
+
if (timer === null) return;
|
|
150
|
+
runtime.clearTimeout(timer);
|
|
151
|
+
timer = null;
|
|
209
152
|
};
|
|
210
153
|
const scheduleFlush = () => {
|
|
211
154
|
if (timer !== null) return;
|
|
@@ -222,7 +165,7 @@ function createNitroErrorReporter(options, runtime) {
|
|
|
222
165
|
"Content-Type": "application/json",
|
|
223
166
|
Authorization: `Bearer ${options.token}`
|
|
224
167
|
},
|
|
225
|
-
body: JSON.stringify(buildPayload(snapshot, options
|
|
168
|
+
body: JSON.stringify(buildPayload(snapshot, options))
|
|
226
169
|
});
|
|
227
170
|
if (response.ok) return true;
|
|
228
171
|
if (options.debug) runtime.warn("[faststats nitro] report failed", response.status, await response.text());
|
|
@@ -263,31 +206,30 @@ function createNitroErrorReporter(options, runtime) {
|
|
|
263
206
|
if (options.debug) runtime.warn("[faststats nitro] FASTSTATS_TOKEN not set; skipping error report");
|
|
264
207
|
return;
|
|
265
208
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
}) ?? {};
|
|
280
|
-
} catch {
|
|
281
|
-
custom = {};
|
|
282
|
-
}
|
|
283
|
-
buckets.set(hash, {
|
|
284
|
-
entry,
|
|
285
|
-
count: 1,
|
|
286
|
-
path: args.path,
|
|
287
|
-
tags: args.tags,
|
|
288
|
-
custom
|
|
289
|
-
});
|
|
209
|
+
const { key, entry } = normalizeServerError(error);
|
|
210
|
+
let custom = {};
|
|
211
|
+
if (options.getContext) try {
|
|
212
|
+
custom = await options.getContext({
|
|
213
|
+
error,
|
|
214
|
+
...args
|
|
215
|
+
}) ?? {};
|
|
216
|
+
} catch {}
|
|
217
|
+
let customKey = "";
|
|
218
|
+
try {
|
|
219
|
+
customKey = JSON.stringify(custom);
|
|
220
|
+
} catch {
|
|
221
|
+
custom = {};
|
|
290
222
|
}
|
|
223
|
+
const bucketKey = `${key}\0${args.path ?? ""}\0${args.tags.join("\0")}\0${customKey}`;
|
|
224
|
+
const existing = buckets.get(bucketKey);
|
|
225
|
+
if (existing) mergeBucket(existing, { count: 1 });
|
|
226
|
+
else buckets.set(bucketKey, {
|
|
227
|
+
entry,
|
|
228
|
+
count: 1,
|
|
229
|
+
path: args.path,
|
|
230
|
+
tags: args.tags,
|
|
231
|
+
custom
|
|
232
|
+
});
|
|
291
233
|
if (buckets.size >= options.maxBatchHashes) {
|
|
292
234
|
clearTimer();
|
|
293
235
|
await flush();
|
|
@@ -299,18 +241,22 @@ function createNitroErrorReporter(options, runtime) {
|
|
|
299
241
|
//#endregion
|
|
300
242
|
//#region src/plugin-hook.ts
|
|
301
243
|
function extractPath(event) {
|
|
302
|
-
if (!event || typeof event !== "object") return;
|
|
244
|
+
if (!event || typeof event !== "object") return void 0;
|
|
303
245
|
const e = event;
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
246
|
+
const value = e.path ?? e.node?.req?.url;
|
|
247
|
+
if (value === void 0) return void 0;
|
|
248
|
+
try {
|
|
249
|
+
return new URL(String(value), "http://faststats.local").pathname;
|
|
250
|
+
} catch {
|
|
251
|
+
return String(value).split(/[?#]/, 1)[0];
|
|
252
|
+
}
|
|
307
253
|
}
|
|
308
254
|
function createNitroErrorHook(resolved) {
|
|
309
255
|
const reporter = createNitroErrorReporter(resolved, defaultRuntime);
|
|
310
256
|
return (error, context) => {
|
|
311
257
|
reporter.report(error, {
|
|
312
258
|
path: extractPath(context.event),
|
|
313
|
-
tags: Array.isArray(context.tags) ? context.tags : []
|
|
259
|
+
tags: Array.isArray(context.tags) ? context.tags.filter((tag) => typeof tag === "string") : []
|
|
314
260
|
});
|
|
315
261
|
};
|
|
316
262
|
}
|
package/dist/v2.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as resolveFaststatsNitroOptions, t as createNitroErrorHook } from "./plugin-hook-
|
|
1
|
+
import { n as resolveFaststatsNitroOptions, t as createNitroErrorHook } from "./plugin-hook-4hE4T3qk.mjs";
|
|
2
2
|
import { defineNitroPlugin } from "nitropack/runtime";
|
|
3
3
|
//#region src/v2.ts
|
|
4
4
|
function createFaststatsNitroPluginV2(options) {
|
package/dist/v3.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as resolveFaststatsNitroOptions, t as createNitroErrorHook } from "./plugin-hook-
|
|
1
|
+
import { n as resolveFaststatsNitroOptions, t as createNitroErrorHook } from "./plugin-hook-4hE4T3qk.mjs";
|
|
2
2
|
import { definePlugin } from "nitro";
|
|
3
3
|
//#region src/v3.ts
|
|
4
4
|
function createFaststatsNitroPluginV3(options) {
|