@flareapp/node 0.1.0 → 0.2.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 +20 -2
- package/dist/index.cjs +848 -0
- package/dist/index.d.cts +138 -0
- package/dist/index.d.mts +138 -0
- package/dist/index.mjs +763 -0
- package/package.json +5 -2
- package/.oxlintrc.json +0 -7
- package/.release-it.json +0 -13
- package/CHANGELOG.md +0 -22
- package/src/Flare.ts +0 -224
- package/src/context/body.ts +0 -185
- package/src/context/collectNode.ts +0 -116
- package/src/context/headers.ts +0 -90
- package/src/context/process.ts +0 -25
- package/src/index.ts +0 -27
- package/src/process/fatal.ts +0 -54
- package/src/process/handlers.ts +0 -109
- package/src/scope/AsyncLocalStorageScopeProvider.ts +0 -86
- package/src/scope/NodeScope.ts +0 -8
- package/src/stacktrace/DiskFileReader.ts +0 -57
- package/src/types.ts +0 -37
- package/tests/asyncScopeProvider.test.ts +0 -43
- package/tests/body.test.ts +0 -129
- package/tests/diskFileReader.test.ts +0 -36
- package/tests/fatalHandlers.test.ts +0 -140
- package/tests/flush.test.ts +0 -11
- package/tests/headers.test.ts +0 -86
- package/tests/integration.test.ts +0 -63
- package/tests/lifecycle.test.ts +0 -71
- package/tests/nodeContextCollector.test.ts +0 -106
- package/tests/nodeExports.test.ts +0 -11
- package/tests/nodeScope.test.ts +0 -19
- package/tests/processAttributes.test.ts +0 -15
- package/tests/processHandlers.test.ts +0 -47
- package/tests/regexFlagSanitization.test.ts +0 -88
- package/tests/scopeIsolation.test.ts +0 -47
- package/tests/setFrameworkScope.test.ts +0 -86
- package/tsconfig.json +0 -9
- package/vitest.config.ts +0 -18
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { AttributeValue, Attributes, Config, ContextCollector, DEFAULT_URL_DENYLIST, EntryPointHandler, FileReader, Flare, Flare as Flare$1, FlushFn, FlushScheduler, Framework, GlobalScopeProvider, Glow, Logger, MessageLevel, NullFileReader, OverriddenGrouping, Report, Scope, Scope as Scope$1, ScopeProvider, SdkInfo, SpanEvent, StackFrame, convertToError, redactUrlQuery, resolveDenylist } from "@flareapp/core";
|
|
2
|
+
|
|
3
|
+
//#region src/types.d.ts
|
|
4
|
+
type RequestContext = {
|
|
5
|
+
method?: string;
|
|
6
|
+
path?: string;
|
|
7
|
+
url?: string;
|
|
8
|
+
headers?: Record<string, string | string[] | undefined>;
|
|
9
|
+
body?: unknown;
|
|
10
|
+
};
|
|
11
|
+
type User = {
|
|
12
|
+
id?: string | number;
|
|
13
|
+
email?: string;
|
|
14
|
+
username?: string;
|
|
15
|
+
ipAddress?: string;
|
|
16
|
+
};
|
|
17
|
+
type FatalMode = 'off' | 'report' | 'report-and-exit';
|
|
18
|
+
type NodeOptions = {
|
|
19
|
+
uncaughtExceptionMode?: FatalMode;
|
|
20
|
+
unhandledRejectionMode?: FatalMode;
|
|
21
|
+
shutdownTimeoutMs?: number;
|
|
22
|
+
headerDenylist?: RegExp;
|
|
23
|
+
headerAllowlist?: RegExp | null;
|
|
24
|
+
replaceDefaultHeaderDenylist?: boolean;
|
|
25
|
+
captureRequestBody?: boolean;
|
|
26
|
+
bodyMaxBytes?: number;
|
|
27
|
+
bodyAllowedContentTypes?: RegExp;
|
|
28
|
+
bodyKeyDenylist?: RegExp;
|
|
29
|
+
};
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/scope/NodeScope.d.ts
|
|
32
|
+
declare class NodeScope extends Scope$1 {
|
|
33
|
+
request: RequestContext;
|
|
34
|
+
user: User | null;
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region src/Flare.d.ts
|
|
38
|
+
/**
|
|
39
|
+
* Node.js-specific `Flare` singleton, exposed from `@flareapp/node` as `flare`.
|
|
40
|
+
*
|
|
41
|
+
* Subclasses core's `Flare` and wires the Node-only seams in its constructor:
|
|
42
|
+
*
|
|
43
|
+
* - `AsyncLocalStorageScopeProvider` so each `runWithContext(...)` callback
|
|
44
|
+
* gets its own `NodeScope` (glows, attributes, user, entry-point, request),
|
|
45
|
+
* isolated from concurrent requests.
|
|
46
|
+
* - `makeNodeContextCollector(...)` to project the current `NodeScope` and
|
|
47
|
+
* process info into report attributes (http.request.*, url.path, etc).
|
|
48
|
+
* - `DiskFileReader` to read source files for stack-trace snippets via
|
|
49
|
+
* `node:fs/promises` instead of the browser's `fetch`.
|
|
50
|
+
* - `ProcessHandlerManager` to attach/detach `uncaughtException` and
|
|
51
|
+
* `unhandledRejection` listeners based on the current `NodeOptions`.
|
|
52
|
+
*
|
|
53
|
+
* Also adds Node-only API surface on top of core: `configureNode(...)`,
|
|
54
|
+
* `runWithContext(...)`, `mergeContext(...)`, `setUser(...)`, `getContext()`,
|
|
55
|
+
* `removeProcessListeners()`. Inherited core methods (`light`, `configure`,
|
|
56
|
+
* `addContext`, `glow`, etc.) return `this`, so chaining keeps the
|
|
57
|
+
* `NodeFlare` type and `configureNode(...)` stays callable mid-chain.
|
|
58
|
+
*/
|
|
59
|
+
declare class NodeFlare extends Flare$1 {
|
|
60
|
+
private nodeOptions;
|
|
61
|
+
private isLit;
|
|
62
|
+
private nodeScopeProvider;
|
|
63
|
+
private handlerManager;
|
|
64
|
+
constructor();
|
|
65
|
+
/**
|
|
66
|
+
* Set the API key (and optional debug flag), then reconcile process
|
|
67
|
+
* listeners with the current `nodeOptions`. Reconcile runs on EVERY call,
|
|
68
|
+
* not just the first, so `light()` is the right escape hatch to re-attach
|
|
69
|
+
* after `removeProcessListeners()`.
|
|
70
|
+
*/
|
|
71
|
+
light(key?: string, debug?: boolean): this;
|
|
72
|
+
/**
|
|
73
|
+
* Merge Node-only options (fatal-handler modes, header/body redaction
|
|
74
|
+
* config, shutdown timeout) into the active configuration. Safe to call
|
|
75
|
+
* before or after `light()`:
|
|
76
|
+
*
|
|
77
|
+
* - Before `light()`: options are stored; listeners are attached when
|
|
78
|
+
* `light()` runs.
|
|
79
|
+
* - After `light()`: options are stored AND listeners are reconciled
|
|
80
|
+
* immediately, so flipping a mode to `'off'` detaches the handler and
|
|
81
|
+
* flipping it back to `'report'`/`'report-and-exit'` re-attaches.
|
|
82
|
+
*
|
|
83
|
+
* Regex options (`headerAllowlist`, `bodyAllowedContentTypes`,
|
|
84
|
+
* `bodyKeyDenylist`) are passed through `sanitizeRegex` to strip stateful
|
|
85
|
+
* `g`/`y` flags; without that, `RegExp.prototype.test` would skip matches
|
|
86
|
+
* across keys.
|
|
87
|
+
*/
|
|
88
|
+
configureNode(partial: Partial<NodeOptions>): NodeFlare;
|
|
89
|
+
/**
|
|
90
|
+
* Run `fn` inside a fresh `NodeScope` carrying the supplied request
|
|
91
|
+
* metadata. Inside `fn` (and any async work it awaits), `flare.glow(...)`,
|
|
92
|
+
* `flare.addContext(...)`, `flare.setUser(...)`, and `flare.report(...)`
|
|
93
|
+
* see a scope that is isolated from other concurrent requests.
|
|
94
|
+
*
|
|
95
|
+
* Mirrors a typical web-framework middleware: call once per request,
|
|
96
|
+
* wrapping the request handler, and the SDK will attribute any error
|
|
97
|
+
* reported inside the chain to the right request.
|
|
98
|
+
*/
|
|
99
|
+
runWithContext<T>(request: RequestContext, fn: () => T): T;
|
|
100
|
+
/**
|
|
101
|
+
* Patch the request metadata on the active scope after `runWithContext(...)`
|
|
102
|
+
* has already started. Useful when fields become known partway through a
|
|
103
|
+
* request (e.g., the resolved absolute URL after proxy headers are parsed).
|
|
104
|
+
*
|
|
105
|
+
* Outside any `runWithContext(...)` callback, this writes to the fallback
|
|
106
|
+
* scope; the patch is visible to subsequent reports issued from outside a
|
|
107
|
+
* request scope but is NOT inherited by future `runWithContext(...)` calls.
|
|
108
|
+
*/
|
|
109
|
+
mergeContext(partial: Partial<RequestContext>): void;
|
|
110
|
+
/**
|
|
111
|
+
* Attach an authenticated user to the active scope. Inside a request scope
|
|
112
|
+
* this is per-request; outside it lands on the fallback scope. The fields
|
|
113
|
+
* are projected to OTel-style keys (`enduser.id`, `enduser.email`,
|
|
114
|
+
* `enduser.username`, `client.address`) by the Node context collector.
|
|
115
|
+
*/
|
|
116
|
+
setUser(user: User | null): void;
|
|
117
|
+
/**
|
|
118
|
+
* Returns the request scope when called inside `runWithContext(...)`, or
|
|
119
|
+
* `null` outside. Intentionally returns `null` (not the fallback scope)
|
|
120
|
+
* when no request is active, so callers can distinguish "we are inside a
|
|
121
|
+
* request" from "we are not". Primarily useful for debugging.
|
|
122
|
+
*/
|
|
123
|
+
getContext(): NodeScope | null;
|
|
124
|
+
/**
|
|
125
|
+
* Detach the `uncaughtException` and `unhandledRejection` listeners
|
|
126
|
+
* without changing `nodeOptions`. Intended for tests and for graceful
|
|
127
|
+
* shutdown paths where you want to take ownership of process exit
|
|
128
|
+
* yourself.
|
|
129
|
+
*
|
|
130
|
+
* Calling `light()` afterwards re-attaches based on the current options.
|
|
131
|
+
*/
|
|
132
|
+
removeProcessListeners(): void;
|
|
133
|
+
}
|
|
134
|
+
//#endregion
|
|
135
|
+
//#region src/index.d.ts
|
|
136
|
+
declare const flare: NodeFlare;
|
|
137
|
+
//#endregion
|
|
138
|
+
export { type AttributeValue, type Attributes, type Config, type ContextCollector, DEFAULT_URL_DENYLIST, type EntryPointHandler, type FatalMode, type FileReader, Flare, type FlushFn, type FlushScheduler, type Framework, GlobalScopeProvider, type Glow, Logger, type MessageLevel, NodeFlare, type NodeOptions, NodeScope, NullFileReader, type OverriddenGrouping, type Report, type RequestContext, Scope, type ScopeProvider, type SdkInfo, type SpanEvent, type StackFrame, type User, convertToError, flare, redactUrlQuery, resolveDenylist };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { AttributeValue, Attributes, Config, ContextCollector, DEFAULT_URL_DENYLIST, EntryPointHandler, FileReader, Flare, Flare as Flare$1, FlushFn, FlushScheduler, Framework, GlobalScopeProvider, Glow, Logger, MessageLevel, NullFileReader, OverriddenGrouping, Report, Scope, Scope as Scope$1, ScopeProvider, SdkInfo, SpanEvent, StackFrame, convertToError, redactUrlQuery, resolveDenylist } from "@flareapp/core";
|
|
2
|
+
|
|
3
|
+
//#region src/types.d.ts
|
|
4
|
+
type RequestContext = {
|
|
5
|
+
method?: string;
|
|
6
|
+
path?: string;
|
|
7
|
+
url?: string;
|
|
8
|
+
headers?: Record<string, string | string[] | undefined>;
|
|
9
|
+
body?: unknown;
|
|
10
|
+
};
|
|
11
|
+
type User = {
|
|
12
|
+
id?: string | number;
|
|
13
|
+
email?: string;
|
|
14
|
+
username?: string;
|
|
15
|
+
ipAddress?: string;
|
|
16
|
+
};
|
|
17
|
+
type FatalMode = 'off' | 'report' | 'report-and-exit';
|
|
18
|
+
type NodeOptions = {
|
|
19
|
+
uncaughtExceptionMode?: FatalMode;
|
|
20
|
+
unhandledRejectionMode?: FatalMode;
|
|
21
|
+
shutdownTimeoutMs?: number;
|
|
22
|
+
headerDenylist?: RegExp;
|
|
23
|
+
headerAllowlist?: RegExp | null;
|
|
24
|
+
replaceDefaultHeaderDenylist?: boolean;
|
|
25
|
+
captureRequestBody?: boolean;
|
|
26
|
+
bodyMaxBytes?: number;
|
|
27
|
+
bodyAllowedContentTypes?: RegExp;
|
|
28
|
+
bodyKeyDenylist?: RegExp;
|
|
29
|
+
};
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/scope/NodeScope.d.ts
|
|
32
|
+
declare class NodeScope extends Scope$1 {
|
|
33
|
+
request: RequestContext;
|
|
34
|
+
user: User | null;
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region src/Flare.d.ts
|
|
38
|
+
/**
|
|
39
|
+
* Node.js-specific `Flare` singleton, exposed from `@flareapp/node` as `flare`.
|
|
40
|
+
*
|
|
41
|
+
* Subclasses core's `Flare` and wires the Node-only seams in its constructor:
|
|
42
|
+
*
|
|
43
|
+
* - `AsyncLocalStorageScopeProvider` so each `runWithContext(...)` callback
|
|
44
|
+
* gets its own `NodeScope` (glows, attributes, user, entry-point, request),
|
|
45
|
+
* isolated from concurrent requests.
|
|
46
|
+
* - `makeNodeContextCollector(...)` to project the current `NodeScope` and
|
|
47
|
+
* process info into report attributes (http.request.*, url.path, etc).
|
|
48
|
+
* - `DiskFileReader` to read source files for stack-trace snippets via
|
|
49
|
+
* `node:fs/promises` instead of the browser's `fetch`.
|
|
50
|
+
* - `ProcessHandlerManager` to attach/detach `uncaughtException` and
|
|
51
|
+
* `unhandledRejection` listeners based on the current `NodeOptions`.
|
|
52
|
+
*
|
|
53
|
+
* Also adds Node-only API surface on top of core: `configureNode(...)`,
|
|
54
|
+
* `runWithContext(...)`, `mergeContext(...)`, `setUser(...)`, `getContext()`,
|
|
55
|
+
* `removeProcessListeners()`. Inherited core methods (`light`, `configure`,
|
|
56
|
+
* `addContext`, `glow`, etc.) return `this`, so chaining keeps the
|
|
57
|
+
* `NodeFlare` type and `configureNode(...)` stays callable mid-chain.
|
|
58
|
+
*/
|
|
59
|
+
declare class NodeFlare extends Flare$1 {
|
|
60
|
+
private nodeOptions;
|
|
61
|
+
private isLit;
|
|
62
|
+
private nodeScopeProvider;
|
|
63
|
+
private handlerManager;
|
|
64
|
+
constructor();
|
|
65
|
+
/**
|
|
66
|
+
* Set the API key (and optional debug flag), then reconcile process
|
|
67
|
+
* listeners with the current `nodeOptions`. Reconcile runs on EVERY call,
|
|
68
|
+
* not just the first, so `light()` is the right escape hatch to re-attach
|
|
69
|
+
* after `removeProcessListeners()`.
|
|
70
|
+
*/
|
|
71
|
+
light(key?: string, debug?: boolean): this;
|
|
72
|
+
/**
|
|
73
|
+
* Merge Node-only options (fatal-handler modes, header/body redaction
|
|
74
|
+
* config, shutdown timeout) into the active configuration. Safe to call
|
|
75
|
+
* before or after `light()`:
|
|
76
|
+
*
|
|
77
|
+
* - Before `light()`: options are stored; listeners are attached when
|
|
78
|
+
* `light()` runs.
|
|
79
|
+
* - After `light()`: options are stored AND listeners are reconciled
|
|
80
|
+
* immediately, so flipping a mode to `'off'` detaches the handler and
|
|
81
|
+
* flipping it back to `'report'`/`'report-and-exit'` re-attaches.
|
|
82
|
+
*
|
|
83
|
+
* Regex options (`headerAllowlist`, `bodyAllowedContentTypes`,
|
|
84
|
+
* `bodyKeyDenylist`) are passed through `sanitizeRegex` to strip stateful
|
|
85
|
+
* `g`/`y` flags; without that, `RegExp.prototype.test` would skip matches
|
|
86
|
+
* across keys.
|
|
87
|
+
*/
|
|
88
|
+
configureNode(partial: Partial<NodeOptions>): NodeFlare;
|
|
89
|
+
/**
|
|
90
|
+
* Run `fn` inside a fresh `NodeScope` carrying the supplied request
|
|
91
|
+
* metadata. Inside `fn` (and any async work it awaits), `flare.glow(...)`,
|
|
92
|
+
* `flare.addContext(...)`, `flare.setUser(...)`, and `flare.report(...)`
|
|
93
|
+
* see a scope that is isolated from other concurrent requests.
|
|
94
|
+
*
|
|
95
|
+
* Mirrors a typical web-framework middleware: call once per request,
|
|
96
|
+
* wrapping the request handler, and the SDK will attribute any error
|
|
97
|
+
* reported inside the chain to the right request.
|
|
98
|
+
*/
|
|
99
|
+
runWithContext<T>(request: RequestContext, fn: () => T): T;
|
|
100
|
+
/**
|
|
101
|
+
* Patch the request metadata on the active scope after `runWithContext(...)`
|
|
102
|
+
* has already started. Useful when fields become known partway through a
|
|
103
|
+
* request (e.g., the resolved absolute URL after proxy headers are parsed).
|
|
104
|
+
*
|
|
105
|
+
* Outside any `runWithContext(...)` callback, this writes to the fallback
|
|
106
|
+
* scope; the patch is visible to subsequent reports issued from outside a
|
|
107
|
+
* request scope but is NOT inherited by future `runWithContext(...)` calls.
|
|
108
|
+
*/
|
|
109
|
+
mergeContext(partial: Partial<RequestContext>): void;
|
|
110
|
+
/**
|
|
111
|
+
* Attach an authenticated user to the active scope. Inside a request scope
|
|
112
|
+
* this is per-request; outside it lands on the fallback scope. The fields
|
|
113
|
+
* are projected to OTel-style keys (`enduser.id`, `enduser.email`,
|
|
114
|
+
* `enduser.username`, `client.address`) by the Node context collector.
|
|
115
|
+
*/
|
|
116
|
+
setUser(user: User | null): void;
|
|
117
|
+
/**
|
|
118
|
+
* Returns the request scope when called inside `runWithContext(...)`, or
|
|
119
|
+
* `null` outside. Intentionally returns `null` (not the fallback scope)
|
|
120
|
+
* when no request is active, so callers can distinguish "we are inside a
|
|
121
|
+
* request" from "we are not". Primarily useful for debugging.
|
|
122
|
+
*/
|
|
123
|
+
getContext(): NodeScope | null;
|
|
124
|
+
/**
|
|
125
|
+
* Detach the `uncaughtException` and `unhandledRejection` listeners
|
|
126
|
+
* without changing `nodeOptions`. Intended for tests and for graceful
|
|
127
|
+
* shutdown paths where you want to take ownership of process exit
|
|
128
|
+
* yourself.
|
|
129
|
+
*
|
|
130
|
+
* Calling `light()` afterwards re-attaches based on the current options.
|
|
131
|
+
*/
|
|
132
|
+
removeProcessListeners(): void;
|
|
133
|
+
}
|
|
134
|
+
//#endregion
|
|
135
|
+
//#region src/index.d.ts
|
|
136
|
+
declare const flare: NodeFlare;
|
|
137
|
+
//#endregion
|
|
138
|
+
export { type AttributeValue, type Attributes, type Config, type ContextCollector, DEFAULT_URL_DENYLIST, type EntryPointHandler, type FatalMode, type FileReader, Flare, type FlushFn, type FlushScheduler, type Framework, GlobalScopeProvider, type Glow, Logger, type MessageLevel, NodeFlare, type NodeOptions, NodeScope, NullFileReader, type OverriddenGrouping, type Report, type RequestContext, Scope, type ScopeProvider, type SdkInfo, type SpanEvent, type StackFrame, type User, convertToError, flare, redactUrlQuery, resolveDenylist };
|