@hawk.so/nextjs 1.0.0 → 1.1.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.
- package/README.md +161 -115
- package/dist/client.js +163 -0
- package/dist/{index.cjs → config.cjs} +82 -45
- package/dist/{index.d.cts → config.d.cts} +1 -1
- package/dist/config.d.ts +75 -0
- package/dist/{index.js → config.js} +72 -35
- package/dist/edge.js +435 -0
- package/dist/index.d.ts +280 -40
- package/dist/react.cjs +199 -0
- package/dist/react.js +179 -0
- package/dist/server.cjs +500 -0
- package/dist/server.js +452 -0
- package/package.json +38 -13
package/dist/react.js
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/react/index.tsx
|
|
4
|
+
import { Component, useEffect } from "react";
|
|
5
|
+
|
|
6
|
+
// src/common/carrier.ts
|
|
7
|
+
var CARRIER_KEY = /* @__PURE__ */ Symbol.for("hawk.nextjs");
|
|
8
|
+
function getCarrier() {
|
|
9
|
+
const store = globalThis;
|
|
10
|
+
store[CARRIER_KEY] ??= {};
|
|
11
|
+
return store[CARRIER_KEY];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// src/common/control-flow.ts
|
|
15
|
+
var CONTROL_FLOW_DIGEST_PREFIXES = [
|
|
16
|
+
"NEXT_REDIRECT",
|
|
17
|
+
"NEXT_HTTP_ERROR_FALLBACK;",
|
|
18
|
+
"NEXT_NOT_FOUND",
|
|
19
|
+
"BAILOUT_TO_CLIENT_SIDE_RENDERING",
|
|
20
|
+
"DYNAMIC_SERVER_USAGE",
|
|
21
|
+
"NEXT_PRERENDER_INTERRUPTED",
|
|
22
|
+
"HANGING_PROMISE_REJECTION"
|
|
23
|
+
];
|
|
24
|
+
var STATIC_GEN_BAILOUT_CODE = "NEXT_STATIC_GEN_BAILOUT";
|
|
25
|
+
var REACT_POSTPONE_TYPE = /* @__PURE__ */ Symbol.for("react.postpone");
|
|
26
|
+
var MAX_CAUSE_DEPTH = 5;
|
|
27
|
+
function isControlFlowDigest(value) {
|
|
28
|
+
return typeof value === "string" && CONTROL_FLOW_DIGEST_PREFIXES.some((prefix) => value.startsWith(prefix));
|
|
29
|
+
}
|
|
30
|
+
function isNextControlFlowError(error) {
|
|
31
|
+
let current = error;
|
|
32
|
+
for (let depth = 0; depth < MAX_CAUSE_DEPTH; depth++) {
|
|
33
|
+
if (typeof current !== "object" || current === null) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
const value = current;
|
|
37
|
+
if (isControlFlowDigest(value.digest) || isControlFlowDigest(value.message) || value.code === STATIC_GEN_BAILOUT_CODE || value.$$typeof === REACT_POSTPONE_TYPE) {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
current = value.cause;
|
|
41
|
+
}
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
function getDigest(error) {
|
|
45
|
+
if (typeof error === "object" && error !== null) {
|
|
46
|
+
const { digest } = error;
|
|
47
|
+
if (typeof digest === "string" && digest !== "") {
|
|
48
|
+
return digest;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return void 0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// src/react/index.tsx
|
|
55
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
56
|
+
function captureBoundaryError(error, boundary, componentStack) {
|
|
57
|
+
if (isNextControlFlowError(error) || getDigest(error) !== void 0) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
getCarrier().capture?.(error, {
|
|
61
|
+
boundary,
|
|
62
|
+
...typeof componentStack === "string" ? { componentStack } : {}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
function useHawkError(error) {
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
captureBoundaryError(error, "error");
|
|
68
|
+
}, [error]);
|
|
69
|
+
}
|
|
70
|
+
var globalErrorStyles = {
|
|
71
|
+
container: {
|
|
72
|
+
fontFamily: "system-ui, sans-serif",
|
|
73
|
+
minHeight: "100vh",
|
|
74
|
+
display: "flex",
|
|
75
|
+
flexDirection: "column",
|
|
76
|
+
alignItems: "center",
|
|
77
|
+
justifyContent: "center",
|
|
78
|
+
gap: 16,
|
|
79
|
+
textAlign: "center"
|
|
80
|
+
},
|
|
81
|
+
title: {
|
|
82
|
+
fontSize: 14,
|
|
83
|
+
fontWeight: 400,
|
|
84
|
+
margin: 0
|
|
85
|
+
},
|
|
86
|
+
digest: {
|
|
87
|
+
fontSize: 12,
|
|
88
|
+
opacity: 0.6,
|
|
89
|
+
margin: 0
|
|
90
|
+
},
|
|
91
|
+
button: {
|
|
92
|
+
fontSize: 14,
|
|
93
|
+
padding: "6px 14px",
|
|
94
|
+
cursor: "pointer"
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
function HawkGlobalError({ error, reset }) {
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
captureBoundaryError(error, "global-error");
|
|
100
|
+
}, [error]);
|
|
101
|
+
const side = error.digest === void 0 ? "client" : "server";
|
|
102
|
+
return /* @__PURE__ */ jsx("html", { lang: "en", children: /* @__PURE__ */ jsx("body", { children: /* @__PURE__ */ jsxs("main", { style: globalErrorStyles.container, children: [
|
|
103
|
+
/* @__PURE__ */ jsxs("h2", { style: globalErrorStyles.title, children: [
|
|
104
|
+
"Application error: a ",
|
|
105
|
+
side,
|
|
106
|
+
"-side exception has occurred."
|
|
107
|
+
] }),
|
|
108
|
+
error.digest !== void 0 && /* @__PURE__ */ jsxs("p", { style: globalErrorStyles.digest, children: [
|
|
109
|
+
"Digest: ",
|
|
110
|
+
error.digest
|
|
111
|
+
] }),
|
|
112
|
+
reset !== void 0 && /* @__PURE__ */ jsx("button", { type: "button", style: globalErrorStyles.button, onClick: reset, children: "Try again" })
|
|
113
|
+
] }) }) });
|
|
114
|
+
}
|
|
115
|
+
var HawkErrorBoundary = class extends Component {
|
|
116
|
+
/**
|
|
117
|
+
* Initial state
|
|
118
|
+
*/
|
|
119
|
+
state = {
|
|
120
|
+
hasError: false,
|
|
121
|
+
error: null
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* Shows the fallback after an error
|
|
125
|
+
* @param error - caught error
|
|
126
|
+
*/
|
|
127
|
+
static getDerivedStateFromError(error) {
|
|
128
|
+
return {
|
|
129
|
+
hasError: true,
|
|
130
|
+
error
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Sends the caught error
|
|
135
|
+
* @param error - caught error
|
|
136
|
+
* @param info - component stack
|
|
137
|
+
*/
|
|
138
|
+
componentDidCatch(error, info) {
|
|
139
|
+
if (isNextControlFlowError(error)) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
captureBoundaryError(error, "boundary", info.componentStack);
|
|
143
|
+
this.props.onError?.(error, info);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Renders the children again
|
|
147
|
+
*/
|
|
148
|
+
reset = () => {
|
|
149
|
+
this.setState({
|
|
150
|
+
hasError: false,
|
|
151
|
+
error: null
|
|
152
|
+
});
|
|
153
|
+
};
|
|
154
|
+
/**
|
|
155
|
+
* Renders the children or the fallback
|
|
156
|
+
*/
|
|
157
|
+
render() {
|
|
158
|
+
const { hasError, error } = this.state;
|
|
159
|
+
if (!hasError) {
|
|
160
|
+
return this.props.children;
|
|
161
|
+
}
|
|
162
|
+
if (isNextControlFlowError(error)) {
|
|
163
|
+
throw error;
|
|
164
|
+
}
|
|
165
|
+
const { fallback } = this.props;
|
|
166
|
+
if (typeof fallback === "function") {
|
|
167
|
+
return fallback({
|
|
168
|
+
error,
|
|
169
|
+
reset: this.reset
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
return fallback ?? null;
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
export {
|
|
176
|
+
HawkErrorBoundary,
|
|
177
|
+
HawkGlobalError,
|
|
178
|
+
useHawkError
|
|
179
|
+
};
|
package/dist/server.cjs
ADDED
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/server/index.ts
|
|
31
|
+
var server_exports = {};
|
|
32
|
+
__export(server_exports, {
|
|
33
|
+
HawkErrorBoundary: () => import_react.HawkErrorBoundary,
|
|
34
|
+
HawkGlobalError: () => import_react.HawkGlobalError,
|
|
35
|
+
breadcrumbs: () => breadcrumbs,
|
|
36
|
+
clearUser: () => clearUser,
|
|
37
|
+
flush: () => flush,
|
|
38
|
+
init: () => init,
|
|
39
|
+
onRequestError: () => onRequestError,
|
|
40
|
+
onRouterTransitionStart: () => onRouterTransitionStart,
|
|
41
|
+
send: () => send,
|
|
42
|
+
setContext: () => setContext,
|
|
43
|
+
setUser: () => setUser,
|
|
44
|
+
useHawkError: () => import_react.useHawkError
|
|
45
|
+
});
|
|
46
|
+
module.exports = __toCommonJS(server_exports);
|
|
47
|
+
|
|
48
|
+
// src/server/sdk.ts
|
|
49
|
+
var import_core3 = require("@hawk.so/core");
|
|
50
|
+
|
|
51
|
+
// src/common/carrier.ts
|
|
52
|
+
var CARRIER_KEY = /* @__PURE__ */ Symbol.for("hawk.nextjs");
|
|
53
|
+
function getCarrier() {
|
|
54
|
+
const store = globalThis;
|
|
55
|
+
store[CARRIER_KEY] ??= {};
|
|
56
|
+
return store[CARRIER_KEY];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// src/common/control-flow.ts
|
|
60
|
+
var CONTROL_FLOW_DIGEST_PREFIXES = [
|
|
61
|
+
"NEXT_REDIRECT",
|
|
62
|
+
"NEXT_HTTP_ERROR_FALLBACK;",
|
|
63
|
+
"NEXT_NOT_FOUND",
|
|
64
|
+
"BAILOUT_TO_CLIENT_SIDE_RENDERING",
|
|
65
|
+
"DYNAMIC_SERVER_USAGE",
|
|
66
|
+
"NEXT_PRERENDER_INTERRUPTED",
|
|
67
|
+
"HANGING_PROMISE_REJECTION"
|
|
68
|
+
];
|
|
69
|
+
var STATIC_GEN_BAILOUT_CODE = "NEXT_STATIC_GEN_BAILOUT";
|
|
70
|
+
var REACT_POSTPONE_TYPE = /* @__PURE__ */ Symbol.for("react.postpone");
|
|
71
|
+
var MAX_CAUSE_DEPTH = 5;
|
|
72
|
+
function isControlFlowDigest(value) {
|
|
73
|
+
return typeof value === "string" && CONTROL_FLOW_DIGEST_PREFIXES.some((prefix) => value.startsWith(prefix));
|
|
74
|
+
}
|
|
75
|
+
function isNextControlFlowError(error) {
|
|
76
|
+
let current = error;
|
|
77
|
+
for (let depth = 0; depth < MAX_CAUSE_DEPTH; depth++) {
|
|
78
|
+
if (typeof current !== "object" || current === null) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
const value = current;
|
|
82
|
+
if (isControlFlowDigest(value.digest) || isControlFlowDigest(value.message) || value.code === STATIC_GEN_BAILOUT_CODE || value.$$typeof === REACT_POSTPONE_TYPE) {
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
current = value.cause;
|
|
86
|
+
}
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
function getDigest(error) {
|
|
90
|
+
if (typeof error === "object" && error !== null) {
|
|
91
|
+
const { digest } = error;
|
|
92
|
+
if (typeof digest === "string" && digest !== "") {
|
|
93
|
+
return digest;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return void 0;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// src/common/error.ts
|
|
100
|
+
function isErrorLike(value) {
|
|
101
|
+
return typeof value === "object" && value !== null && typeof value.message === "string" && typeof value.stack === "string";
|
|
102
|
+
}
|
|
103
|
+
function normalizeError(value) {
|
|
104
|
+
if (value instanceof Error || typeof value === "string") {
|
|
105
|
+
return value;
|
|
106
|
+
}
|
|
107
|
+
if (isErrorLike(value)) {
|
|
108
|
+
const error = new Error(value.message);
|
|
109
|
+
error.name = typeof value.name === "string" ? value.name : error.name;
|
|
110
|
+
error.stack = value.stack;
|
|
111
|
+
return error;
|
|
112
|
+
}
|
|
113
|
+
try {
|
|
114
|
+
return JSON.stringify(value) ?? String(value);
|
|
115
|
+
} catch (_error) {
|
|
116
|
+
return String(value);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// src/common/options.ts
|
|
121
|
+
var DEFAULT_FLUSH_TIMEOUT = 2e3;
|
|
122
|
+
|
|
123
|
+
// src/common/request.ts
|
|
124
|
+
var SAFE_HEADERS = ["host", "referer", "user-agent"];
|
|
125
|
+
function pickSafeHeaders(headers) {
|
|
126
|
+
const result = {};
|
|
127
|
+
for (const name of SAFE_HEADERS) {
|
|
128
|
+
const value = headers[name];
|
|
129
|
+
if (value !== void 0) {
|
|
130
|
+
result[name] = Array.isArray(value) ? value.join(", ") : value;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return result;
|
|
134
|
+
}
|
|
135
|
+
function getRequestAddons(error, request, context) {
|
|
136
|
+
const addons = {
|
|
137
|
+
digest: getDigest(error),
|
|
138
|
+
routerKind: context.routerKind,
|
|
139
|
+
routePath: context.routePath,
|
|
140
|
+
routeType: context.routeType,
|
|
141
|
+
renderSource: context.renderSource,
|
|
142
|
+
revalidateReason: context.revalidateReason,
|
|
143
|
+
renderType: context.renderType,
|
|
144
|
+
method: request.method,
|
|
145
|
+
path: request.path,
|
|
146
|
+
headers: pickSafeHeaders(request.headers)
|
|
147
|
+
};
|
|
148
|
+
return Object.fromEntries(Object.entries(addons).filter(([, value]) => value !== void 0));
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// src/server/catcher.ts
|
|
152
|
+
var import_core2 = require("@hawk.so/core");
|
|
153
|
+
|
|
154
|
+
// src/common/timeout.ts
|
|
155
|
+
async function settleWithTimeout(promises, timeout) {
|
|
156
|
+
const list = [...promises];
|
|
157
|
+
if (list.length === 0) {
|
|
158
|
+
return true;
|
|
159
|
+
}
|
|
160
|
+
let timer;
|
|
161
|
+
const timeoutReached = new Promise((resolve) => {
|
|
162
|
+
timer = setTimeout(() => resolve(false), timeout);
|
|
163
|
+
});
|
|
164
|
+
const allSettled = Promise.allSettled(list).then(() => true);
|
|
165
|
+
try {
|
|
166
|
+
return await Promise.race([allSettled, timeoutReached]);
|
|
167
|
+
} finally {
|
|
168
|
+
clearTimeout(timer);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// src/common/version.ts
|
|
173
|
+
var VERSION = true ? "1.1.0" : "dev";
|
|
174
|
+
|
|
175
|
+
// src/server/stack-parser.ts
|
|
176
|
+
var import_core = require("@hawk.so/core");
|
|
177
|
+
var import_error_stack_parser = __toESM(require("error-stack-parser"), 1);
|
|
178
|
+
var ServerStackParser = class extends import_core.StackParser {
|
|
179
|
+
/**
|
|
180
|
+
* Returns frames of the stack trace
|
|
181
|
+
* @param error - error with the stack trace
|
|
182
|
+
*/
|
|
183
|
+
parse(error) {
|
|
184
|
+
const frames = import_error_stack_parser.default.parse(error).map((frame) => ({
|
|
185
|
+
file: frame.fileName ?? "",
|
|
186
|
+
line: frame.lineNumber ?? 0,
|
|
187
|
+
column: frame.columnNumber,
|
|
188
|
+
function: frame.functionName,
|
|
189
|
+
arguments: frame.args
|
|
190
|
+
}));
|
|
191
|
+
return Promise.resolve(frames);
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
// src/server/transport.ts
|
|
196
|
+
var REQUEST_TIMEOUT = 1e4;
|
|
197
|
+
var FetchTransport = class {
|
|
198
|
+
/**
|
|
199
|
+
* Collector endpoint
|
|
200
|
+
*/
|
|
201
|
+
endpoint;
|
|
202
|
+
/**
|
|
203
|
+
* Requests in progress
|
|
204
|
+
*/
|
|
205
|
+
pending = /* @__PURE__ */ new Set();
|
|
206
|
+
/**
|
|
207
|
+
* @param endpoint - collector endpoint, e.g. `https://<integration id>.k1.hawk.so/`
|
|
208
|
+
*/
|
|
209
|
+
constructor(endpoint) {
|
|
210
|
+
this.endpoint = endpoint;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Sends the event
|
|
214
|
+
* @param message - event with the token and the catcher type
|
|
215
|
+
*/
|
|
216
|
+
send(message) {
|
|
217
|
+
const request = this.post(message).finally(() => {
|
|
218
|
+
this.pending.delete(request);
|
|
219
|
+
});
|
|
220
|
+
this.pending.add(request);
|
|
221
|
+
return request;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Waits for the requests in progress
|
|
225
|
+
* @param timeout - max time to wait, in milliseconds
|
|
226
|
+
* @returns false when the timeout is reached
|
|
227
|
+
*/
|
|
228
|
+
flush(timeout) {
|
|
229
|
+
return settleWithTimeout(this.pending, timeout);
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Posts the event to the collector
|
|
233
|
+
* @param message - event with the token and the catcher type
|
|
234
|
+
*/
|
|
235
|
+
async post(message) {
|
|
236
|
+
const controller = new AbortController();
|
|
237
|
+
const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT);
|
|
238
|
+
try {
|
|
239
|
+
const response = await fetch(this.endpoint, {
|
|
240
|
+
method: "POST",
|
|
241
|
+
headers: [["Content-Type", "application/json"]],
|
|
242
|
+
body: JSON.stringify(message),
|
|
243
|
+
signal: controller.signal
|
|
244
|
+
});
|
|
245
|
+
if (!response.ok) {
|
|
246
|
+
throw new Error(`Collector responded with ${response.status} ${response.statusText}`);
|
|
247
|
+
}
|
|
248
|
+
} finally {
|
|
249
|
+
clearTimeout(timer);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
// src/server/catcher.ts
|
|
255
|
+
var usersByError = /* @__PURE__ */ new WeakMap();
|
|
256
|
+
var noopStorage = {
|
|
257
|
+
getItem: () => null,
|
|
258
|
+
setItem: () => void 0,
|
|
259
|
+
removeItem: () => void 0
|
|
260
|
+
};
|
|
261
|
+
var zeroRandomGenerator = {
|
|
262
|
+
getRandomNumbers: (length) => new Uint8Array(length)
|
|
263
|
+
};
|
|
264
|
+
var ServerUserManager = class extends import_core2.HawkUserManager {
|
|
265
|
+
/**
|
|
266
|
+
* Creates a manager that never stores the user
|
|
267
|
+
*/
|
|
268
|
+
constructor() {
|
|
269
|
+
super(noopStorage, zeroRandomGenerator);
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
var ServerUserProcessor = class {
|
|
273
|
+
/**
|
|
274
|
+
* @param payload - event being built
|
|
275
|
+
* @param error - sent error
|
|
276
|
+
*/
|
|
277
|
+
apply(payload, error) {
|
|
278
|
+
const user = typeof error === "object" ? usersByError.get(error) : void 0;
|
|
279
|
+
if (user !== void 0) {
|
|
280
|
+
payload.user = user;
|
|
281
|
+
} else {
|
|
282
|
+
delete payload.user;
|
|
283
|
+
}
|
|
284
|
+
return payload;
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
function getDefaultEndpoint(token) {
|
|
288
|
+
return `https://${(0, import_core2.decodeIntegrationId)(token)}.k1.hawk.so/`;
|
|
289
|
+
}
|
|
290
|
+
var ServerCatcher = class extends import_core2.BaseCatcher {
|
|
291
|
+
/**
|
|
292
|
+
* Transport kept to wait for the events in progress
|
|
293
|
+
*/
|
|
294
|
+
fetchTransport;
|
|
295
|
+
/**
|
|
296
|
+
* Current runtime: `nodejs` or `edge`
|
|
297
|
+
*/
|
|
298
|
+
runtime;
|
|
299
|
+
/**
|
|
300
|
+
* Events being built: the stack trace is parsed asynchronously before the event gets to the transport
|
|
301
|
+
*/
|
|
302
|
+
pending = /* @__PURE__ */ new Set();
|
|
303
|
+
/**
|
|
304
|
+
* @param settings - token, release and other settings
|
|
305
|
+
* @throws when the token is invalid and the collector endpoint is not set
|
|
306
|
+
*/
|
|
307
|
+
constructor(settings) {
|
|
308
|
+
const transport = new FetchTransport(settings.collectorEndpoint ?? getDefaultEndpoint(settings.token));
|
|
309
|
+
super(settings.token, transport, new ServerUserManager(), settings.release, settings.context, settings.beforeSend);
|
|
310
|
+
this.fetchTransport = transport;
|
|
311
|
+
this.runtime = settings.runtime;
|
|
312
|
+
this.addMessageProcessor(new ServerUserProcessor());
|
|
313
|
+
this.stackParser = new ServerStackParser();
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Sends the error and resolves when it is passed to the transport
|
|
317
|
+
* @param error - error or message
|
|
318
|
+
* @param options - context, user and Next.js data of the event
|
|
319
|
+
*/
|
|
320
|
+
capture(error, options = {}) {
|
|
321
|
+
if (options.user !== void 0 && typeof error === "object") {
|
|
322
|
+
usersByError.set(error, options.user);
|
|
323
|
+
}
|
|
324
|
+
const addons = {
|
|
325
|
+
runtime: this.runtime,
|
|
326
|
+
...options.addons
|
|
327
|
+
};
|
|
328
|
+
const building = this.formatAndSend(error, { nextjs: addons }, options.context).finally(() => {
|
|
329
|
+
this.pending.delete(building);
|
|
330
|
+
});
|
|
331
|
+
this.pending.add(building);
|
|
332
|
+
return building;
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Waits for the events being built and sent
|
|
336
|
+
* @param timeout - max time to wait, in milliseconds
|
|
337
|
+
* @returns false when the timeout is reached
|
|
338
|
+
*/
|
|
339
|
+
async flush(timeout) {
|
|
340
|
+
const deadline = Date.now() + timeout;
|
|
341
|
+
if (!await settleWithTimeout(this.pending, timeout)) {
|
|
342
|
+
return false;
|
|
343
|
+
}
|
|
344
|
+
return this.fetchTransport.flush(Math.max(deadline - Date.now(), 0));
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Returns the catcher type
|
|
348
|
+
*/
|
|
349
|
+
getCatcherType() {
|
|
350
|
+
return "errors/nodejs";
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Returns the catcher version
|
|
354
|
+
*/
|
|
355
|
+
getCatcherVersion() {
|
|
356
|
+
return VERSION;
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
// src/server/sdk.ts
|
|
361
|
+
var REQUEST_CONTEXT_KEY = /* @__PURE__ */ Symbol.for("@next/request-context");
|
|
362
|
+
var noopBreadcrumbs = {
|
|
363
|
+
add: () => void 0,
|
|
364
|
+
get: () => [],
|
|
365
|
+
clear: () => void 0
|
|
366
|
+
};
|
|
367
|
+
var isSetUserWarningShown = false;
|
|
368
|
+
function getCatcher() {
|
|
369
|
+
return getCarrier().catcher;
|
|
370
|
+
}
|
|
371
|
+
function setConsoleLogger() {
|
|
372
|
+
if ((0, import_core3.isLoggerSet)()) {
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
(0, import_core3.setLogger)((message, type = "log", args) => {
|
|
376
|
+
const method = type === "warn" || type === "error" || type === "info" ? type : "log";
|
|
377
|
+
const text = `\u{1F985} Hawk | ${message}`;
|
|
378
|
+
if (args === void 0) {
|
|
379
|
+
console[method](text);
|
|
380
|
+
} else {
|
|
381
|
+
console[method](text, args);
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
function getEnvToken() {
|
|
386
|
+
return [process.env.HAWK_TOKEN, process.env.NEXT_PUBLIC_HAWK_TOKEN].find((value) => value !== void 0 && value !== "");
|
|
387
|
+
}
|
|
388
|
+
function waitUntil(promise) {
|
|
389
|
+
globalThis[REQUEST_CONTEXT_KEY]?.get?.()?.waitUntil?.(promise);
|
|
390
|
+
}
|
|
391
|
+
function initServerCatcher(options, runtime) {
|
|
392
|
+
const carrier = getCarrier();
|
|
393
|
+
if (carrier.catcher !== void 0) {
|
|
394
|
+
return void 0;
|
|
395
|
+
}
|
|
396
|
+
setConsoleLogger();
|
|
397
|
+
const token = options.token ?? getEnvToken();
|
|
398
|
+
if (token === void 0 || token === "") {
|
|
399
|
+
(0, import_core3.log)("Integration Token is not provided, errors will not be sent. Set NEXT_PUBLIC_HAWK_TOKEN or pass `token` to init()", "warn");
|
|
400
|
+
return void 0;
|
|
401
|
+
}
|
|
402
|
+
try {
|
|
403
|
+
carrier.catcher = new ServerCatcher({
|
|
404
|
+
token,
|
|
405
|
+
release: options.release ?? process.env.HAWK_RELEASE,
|
|
406
|
+
context: options.context,
|
|
407
|
+
beforeSend: options.beforeSend,
|
|
408
|
+
collectorEndpoint: options.collectorEndpoint,
|
|
409
|
+
runtime
|
|
410
|
+
});
|
|
411
|
+
} catch (_error) {
|
|
412
|
+
(0, import_core3.log)("Invalid Integration Token, errors will not be sent", "error");
|
|
413
|
+
return void 0;
|
|
414
|
+
}
|
|
415
|
+
const { catcher } = carrier;
|
|
416
|
+
carrier.capture = (error, addons) => {
|
|
417
|
+
void catcher.capture(normalizeError(error), { addons });
|
|
418
|
+
};
|
|
419
|
+
return catcher;
|
|
420
|
+
}
|
|
421
|
+
async function captureServerError(error, options = {}) {
|
|
422
|
+
const catcher = getCatcher();
|
|
423
|
+
if (catcher === void 0 || isNextControlFlowError(error)) {
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
await catcher.capture(normalizeError(error), options);
|
|
427
|
+
}
|
|
428
|
+
function send(error, context, user) {
|
|
429
|
+
void captureServerError(error, {
|
|
430
|
+
context,
|
|
431
|
+
user
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
function setUser(_user) {
|
|
435
|
+
if (!isSetUserWarningShown) {
|
|
436
|
+
isSetUserWarningShown = true;
|
|
437
|
+
(0, import_core3.log)("setUser() is ignored on the server, pass the user to send() instead", "warn");
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
function clearUser() {
|
|
441
|
+
}
|
|
442
|
+
function setContext(context) {
|
|
443
|
+
getCatcher()?.setContext(context);
|
|
444
|
+
}
|
|
445
|
+
var breadcrumbs = noopBreadcrumbs;
|
|
446
|
+
async function flush(timeout = DEFAULT_FLUSH_TIMEOUT) {
|
|
447
|
+
const catcher = getCatcher();
|
|
448
|
+
return catcher === void 0 ? false : catcher.flush(timeout);
|
|
449
|
+
}
|
|
450
|
+
async function onRequestError(error, request, context) {
|
|
451
|
+
const catcher = getCatcher();
|
|
452
|
+
if (catcher === void 0 || isNextControlFlowError(error)) {
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
const sending = captureServerError(error, {
|
|
456
|
+
addons: getRequestAddons(error, request, context)
|
|
457
|
+
}).then(() => catcher.flush(DEFAULT_FLUSH_TIMEOUT));
|
|
458
|
+
waitUntil(sending);
|
|
459
|
+
await sending;
|
|
460
|
+
}
|
|
461
|
+
function onRouterTransitionStart(_url, _navigationType) {
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// src/server/index.ts
|
|
465
|
+
var import_react = require("./react.cjs");
|
|
466
|
+
async function handleProcessError(event, error) {
|
|
467
|
+
await captureServerError(error);
|
|
468
|
+
await flush();
|
|
469
|
+
if (process.listenerCount(event) === 1) {
|
|
470
|
+
console.error(error);
|
|
471
|
+
process.exit(1);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
function init(options = {}) {
|
|
475
|
+
const catcher = initServerCatcher(options, "nodejs");
|
|
476
|
+
if (catcher === void 0 || options.disableGlobalErrorsHandling === true) {
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
process.on("uncaughtException", (error) => {
|
|
480
|
+
void handleProcessError("uncaughtException", error);
|
|
481
|
+
});
|
|
482
|
+
process.on("unhandledRejection", (reason) => {
|
|
483
|
+
void handleProcessError("unhandledRejection", reason);
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
487
|
+
0 && (module.exports = {
|
|
488
|
+
HawkErrorBoundary,
|
|
489
|
+
HawkGlobalError,
|
|
490
|
+
breadcrumbs,
|
|
491
|
+
clearUser,
|
|
492
|
+
flush,
|
|
493
|
+
init,
|
|
494
|
+
onRequestError,
|
|
495
|
+
onRouterTransitionStart,
|
|
496
|
+
send,
|
|
497
|
+
setContext,
|
|
498
|
+
setUser,
|
|
499
|
+
useHawkError
|
|
500
|
+
});
|