@statoss/sdk 0.0.0-stage → 0.1.1

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 (88) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +411 -2
  3. package/dist/cjs/client.d.ts +50 -0
  4. package/dist/cjs/client.js +462 -0
  5. package/dist/cjs/dsn.d.ts +25 -0
  6. package/dist/cjs/dsn.js +62 -0
  7. package/dist/cjs/envelope.d.ts +36 -0
  8. package/dist/cjs/envelope.js +55 -0
  9. package/dist/cjs/event.d.ts +9 -0
  10. package/dist/cjs/event.js +128 -0
  11. package/dist/cjs/hub.d.ts +37 -0
  12. package/dist/cjs/hub.js +119 -0
  13. package/dist/cjs/index.d.ts +38 -0
  14. package/dist/cjs/index.js +107 -0
  15. package/dist/cjs/integrations/browser.d.ts +7 -0
  16. package/dist/cjs/integrations/browser.js +124 -0
  17. package/dist/cjs/integrations/console.d.ts +3 -0
  18. package/dist/cjs/integrations/console.js +106 -0
  19. package/dist/cjs/integrations/dedupe.d.ts +7 -0
  20. package/dist/cjs/integrations/dedupe.js +32 -0
  21. package/dist/cjs/integrations/fetch.d.ts +3 -0
  22. package/dist/cjs/integrations/fetch.js +69 -0
  23. package/dist/cjs/integrations/handlers.d.ts +9 -0
  24. package/dist/cjs/integrations/handlers.js +192 -0
  25. package/dist/cjs/levels.d.ts +20 -0
  26. package/dist/cjs/levels.js +77 -0
  27. package/dist/cjs/logger.d.ts +18 -0
  28. package/dist/cjs/logger.js +38 -0
  29. package/dist/cjs/package.json +1 -0
  30. package/dist/cjs/ratelimit.d.ts +11 -0
  31. package/dist/cjs/ratelimit.js +50 -0
  32. package/dist/cjs/runtime.d.ts +42 -0
  33. package/dist/cjs/runtime.js +188 -0
  34. package/dist/cjs/scope.d.ts +30 -0
  35. package/dist/cjs/scope.js +127 -0
  36. package/dist/cjs/stack.d.ts +9 -0
  37. package/dist/cjs/stack.js +129 -0
  38. package/dist/cjs/transport.d.ts +40 -0
  39. package/dist/cjs/transport.js +218 -0
  40. package/dist/cjs/types.d.ts +180 -0
  41. package/dist/cjs/types.js +2 -0
  42. package/dist/cjs/utils.d.ts +27 -0
  43. package/dist/cjs/utils.js +227 -0
  44. package/dist/cjs/version.d.ts +3 -0
  45. package/dist/cjs/version.js +7 -0
  46. package/dist/esm/client.d.ts +50 -0
  47. package/dist/esm/client.js +458 -0
  48. package/dist/esm/dsn.d.ts +25 -0
  49. package/dist/esm/dsn.js +55 -0
  50. package/dist/esm/envelope.d.ts +36 -0
  51. package/dist/esm/envelope.js +49 -0
  52. package/dist/esm/event.d.ts +9 -0
  53. package/dist/esm/event.js +124 -0
  54. package/dist/esm/hub.d.ts +37 -0
  55. package/dist/esm/hub.js +111 -0
  56. package/dist/esm/index.d.ts +38 -0
  57. package/dist/esm/index.js +88 -0
  58. package/dist/esm/integrations/browser.d.ts +7 -0
  59. package/dist/esm/integrations/browser.js +119 -0
  60. package/dist/esm/integrations/console.d.ts +3 -0
  61. package/dist/esm/integrations/console.js +103 -0
  62. package/dist/esm/integrations/dedupe.d.ts +7 -0
  63. package/dist/esm/integrations/dedupe.js +29 -0
  64. package/dist/esm/integrations/fetch.d.ts +3 -0
  65. package/dist/esm/integrations/fetch.js +66 -0
  66. package/dist/esm/integrations/handlers.d.ts +9 -0
  67. package/dist/esm/integrations/handlers.js +188 -0
  68. package/dist/esm/levels.d.ts +20 -0
  69. package/dist/esm/levels.js +69 -0
  70. package/dist/esm/logger.d.ts +18 -0
  71. package/dist/esm/logger.js +33 -0
  72. package/dist/esm/ratelimit.d.ts +11 -0
  73. package/dist/esm/ratelimit.js +45 -0
  74. package/dist/esm/runtime.d.ts +42 -0
  75. package/dist/esm/runtime.js +181 -0
  76. package/dist/esm/scope.d.ts +30 -0
  77. package/dist/esm/scope.js +123 -0
  78. package/dist/esm/stack.d.ts +9 -0
  79. package/dist/esm/stack.js +125 -0
  80. package/dist/esm/transport.d.ts +40 -0
  81. package/dist/esm/transport.js +213 -0
  82. package/dist/esm/types.d.ts +180 -0
  83. package/dist/esm/types.js +1 -0
  84. package/dist/esm/utils.d.ts +27 -0
  85. package/dist/esm/utils.js +211 -0
  86. package/dist/esm/version.d.ts +3 -0
  87. package/dist/esm/version.js +4 -0
  88. package/package.json +48 -4
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.eventSignature = eventSignature;
4
+ /**
5
+ * What makes two events the same for dedupe, as Sentry's Dedupe compares
6
+ * them: message, exception types and values, frames and fingerprint.
7
+ * Undefined for events with neither message nor exception.
8
+ */
9
+ function eventSignature(event) {
10
+ const exceptions = event.exception?.values?.map((e) => [
11
+ e.type,
12
+ e.value,
13
+ (e.stacktrace?.frames ?? []).map((f) => [
14
+ f.filename,
15
+ f.function,
16
+ f.lineno,
17
+ f.colno,
18
+ ]),
19
+ ]);
20
+ if (!exceptions && event.message === undefined)
21
+ return undefined;
22
+ try {
23
+ return JSON.stringify([
24
+ event.message ?? null,
25
+ exceptions ?? null,
26
+ event.fingerprint ?? null,
27
+ ]);
28
+ }
29
+ catch {
30
+ return undefined;
31
+ }
32
+ }
@@ -0,0 +1,3 @@
1
+ import type { Client } from "../client.js";
2
+ /** Breadcrumbs for fetch calls: method, URL without secrets, status. */
3
+ export declare function installFetch(client: Client): (() => void) | undefined;
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.installFetch = installFetch;
4
+ const utils_js_1 = require("../utils.js");
5
+ function describe(args) {
6
+ const [input, init] = args;
7
+ let method = "GET";
8
+ let url = "";
9
+ if (typeof input === "string") {
10
+ url = input;
11
+ }
12
+ else if ((0, utils_js_1.isObject)(input)) {
13
+ if (typeof input.url === "string")
14
+ url = input.url;
15
+ else if (typeof input.href === "string")
16
+ url = input.href;
17
+ if (typeof input.method === "string")
18
+ method = input.method;
19
+ }
20
+ else if (input !== undefined) {
21
+ url = String(input);
22
+ }
23
+ if ((0, utils_js_1.isObject)(init) && typeof init.method === "string")
24
+ method = init.method;
25
+ return { method: method.toUpperCase(), url };
26
+ }
27
+ function levelFor(status) {
28
+ if (status >= 500)
29
+ return "error";
30
+ if (status >= 400)
31
+ return "warning";
32
+ return "info";
33
+ }
34
+ /** Breadcrumbs for fetch calls: method, URL without secrets, status. */
35
+ function installFetch(client) {
36
+ const g = globalThis;
37
+ const original = g.fetch;
38
+ if (typeof original !== "function")
39
+ return undefined;
40
+ const wrapper = function (...args) {
41
+ const request = (0, utils_js_1.safely)(() => describe(args));
42
+ const result = original.apply(globalThis, args);
43
+ if (!request || !(0, utils_js_1.isThenable)(result) || client.isOwnUrl(request.url))
44
+ return result;
45
+ const data = { method: request.method, url: (0, utils_js_1.scrubUrl)(request.url) };
46
+ return result.then((response) => {
47
+ (0, utils_js_1.safely)(() => {
48
+ const status = (0, utils_js_1.isObject)(response) && typeof response.status === "number"
49
+ ? response.status
50
+ : 0;
51
+ client.addBreadcrumb({
52
+ type: "http",
53
+ category: "fetch",
54
+ level: levelFor(status),
55
+ data: { ...data, status_code: status },
56
+ }, { input: args, response });
57
+ });
58
+ return response;
59
+ }, (error) => {
60
+ (0, utils_js_1.safely)(() => client.addBreadcrumb({ type: "http", category: "fetch", level: "error", data }, { input: args, error }));
61
+ throw error;
62
+ });
63
+ };
64
+ g.fetch = wrapper;
65
+ return () => {
66
+ if (g.fetch === wrapper)
67
+ g.fetch = original;
68
+ };
69
+ }
@@ -0,0 +1,9 @@
1
+ import type { Client } from "../client.js";
2
+ import { type ProcessLike } from "../runtime.js";
3
+ /**
4
+ * Uncaught errors and unhandled rejections, per runtime. Edge runtimes have
5
+ * no global hook, so there the app captures in its handlers.
6
+ */
7
+ export declare function installGlobalHandlers(client: Client): (() => void) | undefined;
8
+ /** Node's --unhandled-rejections mode from NODE_OPTIONS and the command line (which wins); "throw" by default. */
9
+ export declare function rejectionMode(proc: ProcessLike): string;
@@ -0,0 +1,192 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.installGlobalHandlers = installGlobalHandlers;
4
+ exports.rejectionMode = rejectionMode;
5
+ const logger_js_1 = require("../logger.js");
6
+ const runtime_js_1 = require("../runtime.js");
7
+ const stack_js_1 = require("../stack.js");
8
+ const utils_js_1 = require("../utils.js");
9
+ const SHUTDOWN_TIMEOUT_MS = 2000;
10
+ /**
11
+ * Uncaught errors and unhandled rejections, per runtime. Edge runtimes have
12
+ * no global hook, so there the app captures in its handlers.
13
+ */
14
+ function installGlobalHandlers(client) {
15
+ switch (client.runtime.name) {
16
+ case "node":
17
+ case "bun":
18
+ return processHandlers(client);
19
+ case "deno":
20
+ return eventHandlers(client, true);
21
+ case "browser":
22
+ case "worker":
23
+ return eventHandlers(client, false);
24
+ default:
25
+ return undefined;
26
+ }
27
+ }
28
+ /** Node's --unhandled-rejections mode from NODE_OPTIONS and the command line (which wins); "throw" by default. */
29
+ function rejectionMode(proc) {
30
+ const flags = [
31
+ ...String((0, utils_js_1.safely)(() => proc.env?.NODE_OPTIONS) ?? "").split(/\s+/),
32
+ ...((0, utils_js_1.safely)(() => proc.execArgv) ?? []),
33
+ ];
34
+ let mode = "throw";
35
+ for (let i = 0; i < flags.length; i++) {
36
+ const flag = flags[i];
37
+ if (flag.startsWith("--unhandled-rejections=")) {
38
+ mode = flag.slice("--unhandled-rejections=".length);
39
+ }
40
+ else if (flag === "--unhandled-rejections" && i + 1 < flags.length) {
41
+ mode = flags[++i];
42
+ }
43
+ }
44
+ return ["strict", "warn", "none", "warn-with-error-code"].includes(mode)
45
+ ? mode
46
+ : "throw";
47
+ }
48
+ /** The error Node raises for a rejection with a value that is not an Error. */
49
+ function rejectionError(reason) {
50
+ const error = new Error(`This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "${(0, utils_js_1.truncate)((0, utils_js_1.safeString)(reason), 200)}".`);
51
+ error.name = "UnhandledPromiseRejection";
52
+ error.code = "ERR_UNHANDLED_REJECTION";
53
+ return error;
54
+ }
55
+ /**
56
+ * Node and Bun. A listener on uncaughtException or unhandledRejection
57
+ * switches off the runtime's own handling, so the SDK does what the runtime
58
+ * would have done, after sending:
59
+ * - uncaught exception: print it and exit with 1, unless the app has its own
60
+ * listener;
61
+ * - unhandled rejection, by Node's --unhandled-rejections mode: "throw" (the
62
+ * default) raises it as an uncaught exception, so the app's listener gets
63
+ * it or the process exits with 1; "warn-with-error-code" prints it and sets
64
+ * the exit code to 1; "warn" and "none" keep running; "strict" is raised by
65
+ * Node itself. An app with its own unhandledRejection listener decides.
66
+ */
67
+ function processHandlers(client) {
68
+ const proc = (0, runtime_js_1.getProcess)();
69
+ if (!proc ||
70
+ typeof proc.on !== "function" ||
71
+ typeof proc.listeners !== "function") {
72
+ return undefined;
73
+ }
74
+ const mode = rejectionMode(proc);
75
+ let shuttingDown = false;
76
+ let reraised = undefined;
77
+ const others = (event, own) => (proc.listeners?.(event) ?? []).filter((l) => l !== own && l.name !== "domainUncaughtExceptionClear").length;
78
+ const shutdown = (error) => {
79
+ if (shuttingDown)
80
+ return;
81
+ shuttingDown = true;
82
+ // First: if nothing keeps the process alive while sending, it still ends with 1.
83
+ (0, utils_js_1.safely)(() => {
84
+ proc.exitCode = 1;
85
+ });
86
+ (0, logger_js_1.printError)(error);
87
+ const exit = () => {
88
+ (0, utils_js_1.safely)(() => proc.exit?.(1));
89
+ };
90
+ client.flush(SHUTDOWN_TIMEOUT_MS).then(exit, exit);
91
+ };
92
+ const onUncaught = (error, origin) => {
93
+ // A rejection passed on by onRejection below was captured there.
94
+ if (reraised === undefined || error !== reraised) {
95
+ const fromRejection = origin === "unhandledRejection";
96
+ client.captureUnhandled(error, {
97
+ type: fromRejection ? "onunhandledrejection" : "onuncaughtexception",
98
+ handled: false,
99
+ }, "fatal", { rejection: fromRejection });
100
+ }
101
+ if (others("uncaughtException", onUncaught) > 0)
102
+ return;
103
+ shutdown(error);
104
+ };
105
+ const onRejection = (reason) => {
106
+ // In strict mode Node has already raised it as an uncaught exception.
107
+ if (mode === "strict")
108
+ return;
109
+ const ownListener = others("unhandledRejection", onRejection) > 0;
110
+ const crashes = mode === "throw" &&
111
+ !ownListener &&
112
+ others("uncaughtException", onUncaught) === 0;
113
+ client.captureUnhandled(reason, { type: "onunhandledrejection", handled: false }, crashes ? "fatal" : "error", { rejection: true });
114
+ if (ownListener)
115
+ return;
116
+ if (mode === "throw") {
117
+ const error = (0, utils_js_1.isErrorLike)(reason) ? reason : rejectionError(reason);
118
+ reraised = error;
119
+ (0, utils_js_1.safely)(() => proc.emit?.("uncaughtException", error, "unhandledRejection"));
120
+ reraised = undefined;
121
+ }
122
+ else if (mode === "warn-with-error-code") {
123
+ (0, logger_js_1.printError)("Unhandled promise rejection:", reason);
124
+ (0, utils_js_1.safely)(() => {
125
+ proc.exitCode = 1;
126
+ });
127
+ }
128
+ };
129
+ proc.on("uncaughtException", onUncaught);
130
+ proc.on("unhandledRejection", onRejection);
131
+ return () => {
132
+ const off = proc.off ?? proc.removeListener;
133
+ (0, utils_js_1.safely)(() => off?.call(proc, "uncaughtException", onUncaught));
134
+ (0, utils_js_1.safely)(() => off?.call(proc, "unhandledRejection", onRejection));
135
+ };
136
+ }
137
+ /**
138
+ * Browsers, web workers and Deno: the error and unhandledrejection events.
139
+ * Deno exits on them, so there the SDK prevents that, sends, and then throws
140
+ * the error again for Deno to print and exit as it would have, as Sentry's
141
+ * Deno SDK does. A listener of the app's that already called preventDefault
142
+ * keeps the process running.
143
+ */
144
+ function eventHandlers(client, deno) {
145
+ const target = globalThis;
146
+ if (typeof target.addEventListener !== "function")
147
+ return undefined;
148
+ let exiting = false;
149
+ const crash = (event, error) => {
150
+ if (!deno || event.defaultPrevented)
151
+ return;
152
+ (0, utils_js_1.safely)(() => event.preventDefault?.());
153
+ exiting = true;
154
+ const rethrow = () => {
155
+ throw error;
156
+ };
157
+ void client.flush(SHUTDOWN_TIMEOUT_MS).then(rethrow, rethrow);
158
+ };
159
+ const onError = (event) => {
160
+ if (exiting || !(0, utils_js_1.isObject)(event))
161
+ return;
162
+ const error = event.error;
163
+ const message = typeof event.message === "string" && event.message
164
+ ? event.message
165
+ : undefined;
166
+ const filename = typeof event.filename === "string" ? event.filename : undefined;
167
+ // Cross-origin scripts give only "Script error." with a null error.
168
+ client.captureUnhandled(error !== undefined && error !== null
169
+ ? error
170
+ : (message ?? "Unknown error"), { type: "onerror", handled: false }, deno ? "fatal" : "error", {
171
+ frame: filename && !(0, utils_js_1.isErrorLike)(error)
172
+ ? (0, stack_js_1.frameAt)(filename, typeof event.lineno === "number" ? event.lineno : undefined, typeof event.colno === "number" ? event.colno : undefined)
173
+ : undefined,
174
+ });
175
+ crash(event, error);
176
+ };
177
+ const onRejection = (event) => {
178
+ if (exiting || !(0, utils_js_1.isObject)(event))
179
+ return;
180
+ const reason = "reason" in event
181
+ ? event.reason
182
+ : event.detail?.reason;
183
+ client.captureUnhandled(reason, { type: "onunhandledrejection", handled: false }, deno ? "fatal" : "error", { rejection: true });
184
+ crash(event, reason);
185
+ };
186
+ target.addEventListener("error", onError);
187
+ target.addEventListener("unhandledrejection", onRejection);
188
+ return () => {
189
+ (0, utils_js_1.safely)(() => target.removeEventListener?.("error", onError));
190
+ (0, utils_js_1.safely)(() => target.removeEventListener?.("unhandledrejection", onRejection));
191
+ };
192
+ }
@@ -0,0 +1,20 @@
1
+ import type { Logger } from "./logger.js";
2
+ import type { SentryLevel } from "./types.js";
3
+ export declare const SENTRY_LEVELS: readonly SentryLevel[];
4
+ export declare const LEVEL_TAG = "statoss.level";
5
+ export declare const CATEGORY_TAG = "statoss.category";
6
+ export declare function isSentryLevel(value: unknown): value is SentryLevel;
7
+ export declare function isValidName(value: unknown): value is string;
8
+ /** Keeps the entries of init's `levels` that are usable, logging the rest in debug mode. */
9
+ export declare function readLevels(input: unknown, logger: Logger): Record<string, SentryLevel>;
10
+ export interface LevelChoice {
11
+ level: SentryLevel;
12
+ /** The custom name, when the level was one. */
13
+ custom?: string;
14
+ }
15
+ /**
16
+ * Picks the first usable level from candidates in order of precedence. A
17
+ * custom name is sent as its mapped Sentry level (error when unmapped).
18
+ */
19
+ export declare function chooseLevel(candidates: unknown[], levels: Record<string, SentryLevel>, fallback: SentryLevel, logger: Logger): LevelChoice;
20
+ export declare function readCategory(value: unknown, logger: Logger): string | undefined;
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CATEGORY_TAG = exports.LEVEL_TAG = exports.SENTRY_LEVELS = void 0;
4
+ exports.isSentryLevel = isSentryLevel;
5
+ exports.isValidName = isValidName;
6
+ exports.readLevels = readLevels;
7
+ exports.chooseLevel = chooseLevel;
8
+ exports.readCategory = readCategory;
9
+ const utils_js_1 = require("./utils.js");
10
+ exports.SENTRY_LEVELS = [
11
+ "fatal",
12
+ "error",
13
+ "warning",
14
+ "info",
15
+ "debug",
16
+ ];
17
+ /** Custom level and category names: what the server accepts as tag values to filter on. */
18
+ const NAME_RE = /^[a-z0-9._-]{1,64}$/;
19
+ exports.LEVEL_TAG = "statoss.level";
20
+ exports.CATEGORY_TAG = "statoss.category";
21
+ function isSentryLevel(value) {
22
+ return (typeof value === "string" &&
23
+ exports.SENTRY_LEVELS.includes(value));
24
+ }
25
+ function isValidName(value) {
26
+ return typeof value === "string" && NAME_RE.test(value);
27
+ }
28
+ /** Keeps the entries of init's `levels` that are usable, logging the rest in debug mode. */
29
+ function readLevels(input, logger) {
30
+ const out = {};
31
+ if (input === undefined || input === null)
32
+ return out;
33
+ if (typeof input !== "object") {
34
+ logger.warn('Ignored `levels`: it should be an object such as { "payment-failed": "error" }.');
35
+ return out;
36
+ }
37
+ for (const [name, level] of Object.entries(input)) {
38
+ if (isSentryLevel(name)) {
39
+ logger.warn(`Ignored level "${name}" in \`levels\`: it is already a Sentry level.`);
40
+ }
41
+ else if (!isValidName(name)) {
42
+ logger.warn(`Ignored level "${name}" in \`levels\`: use 1 to 64 lowercase letters, digits, dots, dashes or underscores.`);
43
+ }
44
+ else if (!isSentryLevel(level)) {
45
+ logger.warn(`Ignored level "${name}" in \`levels\`: map it to fatal, error, warning, info or debug.`);
46
+ }
47
+ else {
48
+ out[name] = level;
49
+ }
50
+ }
51
+ return out;
52
+ }
53
+ /**
54
+ * Picks the first usable level from candidates in order of precedence. A
55
+ * custom name is sent as its mapped Sentry level (error when unmapped).
56
+ */
57
+ function chooseLevel(candidates, levels, fallback, logger) {
58
+ for (const candidate of candidates) {
59
+ if (candidate === undefined || candidate === null)
60
+ continue;
61
+ if (isSentryLevel(candidate))
62
+ return { level: candidate };
63
+ if (isValidName(candidate)) {
64
+ return { level: levels[candidate] ?? "error", custom: candidate };
65
+ }
66
+ logger.warn(`Ignored level "${(0, utils_js_1.safeString)(candidate)}": use a Sentry level or 1 to 64 lowercase letters, digits, dots, dashes or underscores.`);
67
+ }
68
+ return { level: fallback };
69
+ }
70
+ function readCategory(value, logger) {
71
+ if (value === undefined || value === null)
72
+ return undefined;
73
+ if (isValidName(value))
74
+ return value;
75
+ logger.warn(`Ignored category "${(0, utils_js_1.safeString)(value)}": use 1 to 64 lowercase letters, digits, dots, dashes or underscores.`);
76
+ return undefined;
77
+ }
@@ -0,0 +1,18 @@
1
+ export type ConsoleMethod = "debug" | "info" | "warn" | "error" | "log" | "assert";
2
+ type ConsoleFn = (...args: unknown[]) => void;
3
+ /** The console methods as they were before the console integration wrapped them. */
4
+ export declare const originalConsole: Partial<Record<ConsoleMethod, ConsoleFn>>;
5
+ export interface Logger {
6
+ readonly enabled: boolean;
7
+ log(...args: unknown[]): void;
8
+ warn(...args: unknown[]): void;
9
+ error(...args: unknown[]): void;
10
+ }
11
+ /** Writes only when debug is on, and never through the wrapped console. */
12
+ export declare function makeLogger(enabled: boolean): Logger;
13
+ /**
14
+ * Prints an error the way the runtime would have if the SDK had not taken
15
+ * over its crash handling. Not a debug message, so it ignores `debug`.
16
+ */
17
+ export declare function printError(...args: unknown[]): void;
18
+ export {};
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.originalConsole = void 0;
4
+ exports.makeLogger = makeLogger;
5
+ exports.printError = printError;
6
+ /** The console methods as they were before the console integration wrapped them. */
7
+ exports.originalConsole = {};
8
+ function call(method, args) {
9
+ try {
10
+ const c = globalThis
11
+ .console;
12
+ const fn = exports.originalConsole[method] ?? c?.[method];
13
+ if (typeof fn === "function")
14
+ fn.apply(c, args);
15
+ }
16
+ catch {
17
+ // nowhere left to report to
18
+ }
19
+ }
20
+ /** Writes only when debug is on, and never through the wrapped console. */
21
+ function makeLogger(enabled) {
22
+ const write = (method) => enabled
23
+ ? (...args) => call(method, ["[StatOSS]", ...args])
24
+ : () => undefined;
25
+ return {
26
+ enabled,
27
+ log: write("log"),
28
+ warn: write("warn"),
29
+ error: write("error"),
30
+ };
31
+ }
32
+ /**
33
+ * Prints an error the way the runtime would have if the SDK had not taken
34
+ * over its crash handling. Not a debug message, so it ignores `debug`.
35
+ */
36
+ function printError(...args) {
37
+ call("error", args);
38
+ }
@@ -0,0 +1 @@
1
+ { "type": "commonjs" }
@@ -0,0 +1,11 @@
1
+ /** Per category (or "all"), the time in ms until which nothing is sent. */
2
+ export type RateLimits = Record<string, number>;
3
+ export declare function parseRetryAfter(header: string, now: number): number;
4
+ /**
5
+ * Applies a response's limits as Sentry's SDKs do. X-Sentry-Rate-Limits
6
+ * entries are "seconds:categories:scope:reason", categories split by ";" and
7
+ * empty for all. Its scope (key, project, organization) and reason (such as
8
+ * usage_exceeded) do not change what the client does: wait, then try again.
9
+ */
10
+ export declare function updateRateLimits(limits: RateLimits, status: number, rateLimitHeader: string | null | undefined, retryAfterHeader: string | null | undefined, now: number): RateLimits;
11
+ export declare function isRateLimited(limits: RateLimits, category: string, now: number): boolean;
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseRetryAfter = parseRetryAfter;
4
+ exports.updateRateLimits = updateRateLimits;
5
+ exports.isRateLimited = isRateLimited;
6
+ const DEFAULT_RETRY_MS = 60000;
7
+ function parseRetryAfter(header, now) {
8
+ const seconds = parseInt(header, 10);
9
+ if (!Number.isNaN(seconds))
10
+ return seconds * 1000;
11
+ const date = Date.parse(header);
12
+ if (!Number.isNaN(date))
13
+ return date - now;
14
+ return DEFAULT_RETRY_MS;
15
+ }
16
+ /**
17
+ * Applies a response's limits as Sentry's SDKs do. X-Sentry-Rate-Limits
18
+ * entries are "seconds:categories:scope:reason", categories split by ";" and
19
+ * empty for all. Its scope (key, project, organization) and reason (such as
20
+ * usage_exceeded) do not change what the client does: wait, then try again.
21
+ */
22
+ function updateRateLimits(limits, status, rateLimitHeader, retryAfterHeader, now) {
23
+ const next = { ...limits };
24
+ if (rateLimitHeader) {
25
+ for (const entry of rateLimitHeader.trim().split(",")) {
26
+ const [retryAfter, categories] = entry.trim().split(":", 2);
27
+ const seconds = parseInt(retryAfter, 10);
28
+ const until = now + (Number.isNaN(seconds) ? 60 : seconds) * 1000;
29
+ if (!categories) {
30
+ next.all = until;
31
+ }
32
+ else {
33
+ for (const category of categories.split(";")) {
34
+ if (category)
35
+ next[category] = until;
36
+ }
37
+ }
38
+ }
39
+ }
40
+ else if (retryAfterHeader) {
41
+ next.all = now + parseRetryAfter(retryAfterHeader, now);
42
+ }
43
+ else if (status === 429) {
44
+ next.all = now + DEFAULT_RETRY_MS;
45
+ }
46
+ return next;
47
+ }
48
+ function isRateLimited(limits, category, now) {
49
+ return (limits[category] || limits.all || 0) > now;
50
+ }
@@ -0,0 +1,42 @@
1
+ export type RuntimeName = "browser" | "worker" | "node" | "bun" | "deno" | "cloudflare" | "vercel-edge" | "unknown";
2
+ export interface RuntimeInfo {
3
+ name: RuntimeName;
4
+ platform: "javascript" | "node";
5
+ /** Browsers and web workers: key in the query, keepalive, page context. */
6
+ browserLike: boolean;
7
+ serverName?: string;
8
+ contexts: Record<string, Record<string, unknown>>;
9
+ }
10
+ /** The parts of Node's process the SDK reads, all optional. */
11
+ export interface ProcessLike {
12
+ version?: string;
13
+ versions?: Record<string, string | undefined>;
14
+ platform?: string;
15
+ arch?: string;
16
+ getBuiltinModule?: (id: string) => unknown;
17
+ on?: (event: string, listener: (...args: never[]) => void) => unknown;
18
+ off?: (event: string, listener: (...args: never[]) => void) => unknown;
19
+ removeListener?: (event: string, listener: (...args: never[]) => void) => unknown;
20
+ listeners?: (event: string) => ((...args: never[]) => void)[];
21
+ emit?: (event: string, ...args: unknown[]) => boolean;
22
+ exit?: (code?: number) => never;
23
+ exitCode?: number | string;
24
+ execArgv?: string[];
25
+ env?: Record<string, string | undefined>;
26
+ }
27
+ export declare function getProcess(): ProcessLike | undefined;
28
+ /** A Node built-in without a static import, so bundlers for the browser never see one. */
29
+ export declare function getBuiltin<T>(id: string): T | undefined;
30
+ export declare function detectRuntime(): RuntimeName;
31
+ /** Browser and OS from a user agent, for the common browsers only. */
32
+ export declare function parseUserAgent(ua: string): {
33
+ browser?: {
34
+ name: string;
35
+ version: string;
36
+ };
37
+ os?: {
38
+ name: string;
39
+ version?: string;
40
+ };
41
+ };
42
+ export declare function describeRuntime(name?: RuntimeName): RuntimeInfo;