@hellsoft/vaka-node 0.0.0-stage → 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.
@@ -0,0 +1,45 @@
1
+ import { Scope, type RequestInfo } from './scope';
2
+ type Crumb = Parameters<Scope['addBreadcrumb']>[0];
3
+ /** Breadcrumbs for console.warn/error and outgoing HTTP (fetch/undici and node:http). */
4
+ export declare function installBreadcrumbs(endpoint: string, add: (b: Crumb) => void): void;
5
+ export declare function uninstallIntegrations(): void;
6
+ export interface ProcessHooks {
7
+ capture: (err: unknown, fatal: boolean, mechanism: string) => void;
8
+ flush: (ms: number) => Promise<unknown>;
9
+ /** 'strict' exits like Node's default; 'warn' logs and keeps running; 'none' only reports. */
10
+ unhandledRejection: 'strict' | 'warn' | 'none';
11
+ exitOnUncaught: boolean;
12
+ shutdownTimeoutMs: number;
13
+ }
14
+ export declare function installProcessHandlers(h: ProcessHooks): void;
15
+ /** Node's own --unhandled-rejections setting, mapped to ours. */
16
+ export declare function nodeRejectionMode(): 'strict' | 'warn' | 'none';
17
+ export interface ReqLike {
18
+ method?: string;
19
+ url?: string;
20
+ originalUrl?: string;
21
+ headers?: Record<string, string | string[] | undefined>;
22
+ route?: {
23
+ path?: string;
24
+ };
25
+ routeOptions?: {
26
+ url?: string;
27
+ };
28
+ routerPath?: string;
29
+ protocol?: string;
30
+ }
31
+ export declare function requestInfo(req: ReqLike): RequestInfo;
32
+ type Capture = (err: unknown, ctx: {
33
+ handled: boolean;
34
+ mechanism: string;
35
+ status?: number;
36
+ }) => void;
37
+ /** Express/Connect middleware: one scope per request. Mount it before your routes. */
38
+ export declare function makeRequestHandler(): (req: ReqLike, _res: unknown, next: (err?: unknown) => void) => void;
39
+ /** Express error middleware. Mount it after your routes and before other error handlers. */
40
+ export declare function makeErrorHandler(capture: Capture, shouldCapture: (status: number) => boolean): (err: unknown, req: ReqLike, res: {
41
+ statusCode?: number;
42
+ }, next: (err?: unknown) => void) => void;
43
+ /** Fastify plugin: a scope per request and capture of errors from handlers and hooks. */
44
+ export declare function makeFastifyPlugin(capture: Capture, shouldCapture: (status: number) => boolean): any;
45
+ export {};
package/dist/otel.d.ts ADDED
@@ -0,0 +1,38 @@
1
+ import type { Context } from '@opentelemetry/api';
2
+ import { NodeSDK } from '@opentelemetry/sdk-node';
3
+ import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';
4
+ import { type LogRecordProcessor } from '@opentelemetry/sdk-logs';
5
+ import { type Span, type SpanProcessor } from '@opentelemetry/sdk-trace';
6
+ import type { Instrumentation } from '@opentelemetry/instrumentation';
7
+ export interface OtelConfig {
8
+ endpoint: string;
9
+ key: string;
10
+ serviceName?: string;
11
+ release?: string;
12
+ environment?: string;
13
+ tracesSampleRate: number;
14
+ logs: boolean;
15
+ instrumentations?: (Instrumentation | Instrumentation[])[];
16
+ resourceAttributes?: Record<string, string | number | boolean>;
17
+ }
18
+ /** An OTLP/HTTP (protobuf) span exporter that sends to Vaka. Use it with your own NodeSDK. */
19
+ export declare function vakaSpanExporter(o: {
20
+ endpoint: string;
21
+ key: string;
22
+ }): OTLPTraceExporter;
23
+ /** A batching log record processor that sends OpenTelemetry logs to Vaka. */
24
+ export declare function vakaLogRecordProcessor(o: {
25
+ endpoint: string;
26
+ key: string;
27
+ }): LogRecordProcessor;
28
+ /**
29
+ * Copies the current Vaka scope (user id, flags) onto every span as it starts, so traces can be
30
+ * filtered by user and split by flag variant.
31
+ */
32
+ export declare class VakaScopeSpanProcessor implements SpanProcessor {
33
+ onStart(span: Span, _ctx: Context): void;
34
+ onEnd(): void;
35
+ forceFlush(): Promise<void>;
36
+ shutdown(): Promise<void>;
37
+ }
38
+ export declare function startOtel(c: OtelConfig): NodeSDK;
@@ -0,0 +1,41 @@
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 __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (let key of __getOwnPropNames(from))
11
+ if (!__hasOwnProp.call(to, key) && key !== except)
12
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
+ }
14
+ return to;
15
+ };
16
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
17
+ // If the importer is in node compatibility mode or this is not an ESM
18
+ // file that has been converted to a CommonJS file using a Babel-
19
+ // compatible transform (i.e. "__esModule" has not been set), then set
20
+ // "default" to the CommonJS "module.exports" for node compatibility.
21
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
24
+
25
+ // src/register.ts
26
+ var nodeModule = __toESM(require("node:module"));
27
+ var import_node_url = require("node:url");
28
+ var import_index = require("./index.cjs");
29
+ var import_meta = {};
30
+ var register2 = nodeModule.register;
31
+ if (register2 && process.env.VAKA_ESM_HOOK !== "0") {
32
+ try {
33
+ const parent = typeof __filename !== "undefined" ? (0, import_node_url.pathToFileURL)(__filename).href : import_meta.url;
34
+ register2("@opentelemetry/instrumentation/hook.mjs", parent);
35
+ } catch {
36
+ }
37
+ }
38
+ (0, import_index.init)({
39
+ tracesSampleRate: process.env.VAKA_TRACES_SAMPLE_RATE ? Number(process.env.VAKA_TRACES_SAMPLE_RATE) : void 0,
40
+ debug: process.env.VAKA_DEBUG === "1" || process.env.VAKA_DEBUG === "true"
41
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,16 @@
1
+ // src/register.ts
2
+ import * as nodeModule from "node:module";
3
+ import { pathToFileURL } from "node:url";
4
+ import { init } from "./index.mjs";
5
+ var register2 = nodeModule.register;
6
+ if (register2 && process.env.VAKA_ESM_HOOK !== "0") {
7
+ try {
8
+ const parent = typeof __filename !== "undefined" ? pathToFileURL(__filename).href : import.meta.url;
9
+ register2("@opentelemetry/instrumentation/hook.mjs", parent);
10
+ } catch {
11
+ }
12
+ }
13
+ init({
14
+ tracesSampleRate: process.env.VAKA_TRACES_SAMPLE_RATE ? Number(process.env.VAKA_TRACES_SAMPLE_RATE) : void 0,
15
+ debug: process.env.VAKA_DEBUG === "1" || process.env.VAKA_DEBUG === "true"
16
+ });
@@ -0,0 +1,44 @@
1
+ import { AsyncLocalStorage } from 'node:async_hooks';
2
+ export type Level = 'fatal' | 'error' | 'warning' | 'info';
3
+ export interface Breadcrumb {
4
+ timestamp?: string;
5
+ category?: string;
6
+ type?: string;
7
+ message?: string;
8
+ level?: Level;
9
+ data?: Record<string, unknown>;
10
+ }
11
+ export interface User {
12
+ id: string;
13
+ [k: string]: unknown;
14
+ }
15
+ export interface RequestInfo {
16
+ method?: string;
17
+ url?: string;
18
+ route?: string;
19
+ query_string?: string;
20
+ headers?: Record<string, string>;
21
+ }
22
+ export declare const MAX_BREADCRUMBS = 100;
23
+ /** Per-request (or global) state attached to everything captured while it is active. */
24
+ export declare class Scope {
25
+ user?: User;
26
+ tags: Record<string, string>;
27
+ contexts: Record<string, Record<string, unknown>>;
28
+ breadcrumbs: Breadcrumb[];
29
+ flags: Record<string, string>;
30
+ request?: RequestInfo;
31
+ transaction?: string;
32
+ clone(): Scope;
33
+ addBreadcrumb(b: Breadcrumb, max?: number): void;
34
+ }
35
+ export declare const storage: AsyncLocalStorage<Scope>;
36
+ export declare let globalScope: Scope;
37
+ /** The scope of the current request, or the global scope outside one. */
38
+ export declare function currentScope(): Scope;
39
+ /**
40
+ * Run `fn` with a fresh scope that starts as a copy of the current one. Tags, user, breadcrumbs
41
+ * and flags set inside stay inside (per request when used in middleware).
42
+ */
43
+ export declare function withScope<T>(fn: (scope: Scope) => T): T;
44
+ export declare function _resetScopes(): void;
@@ -0,0 +1,16 @@
1
+ export interface Frame {
2
+ function?: string;
3
+ module?: string;
4
+ abs_path?: string;
5
+ filename?: string;
6
+ lineno?: number;
7
+ colno?: number;
8
+ in_app?: boolean;
9
+ context_line?: string;
10
+ pre_context?: string[];
11
+ post_context?: string[];
12
+ }
13
+ /** Parse a V8 (Node) stack string into frames, crash site first. */
14
+ export declare function parseStack(stack: string | undefined, cwd?: string): Frame[];
15
+ /** Add `context_line`, `pre_context` and `post_context` from disk to the first in-app frames. */
16
+ export declare function addSourceContext(frames: Frame[], maxFrames?: number): Frame[];
@@ -0,0 +1,33 @@
1
+ export interface Item {
2
+ type: 'error' | 'event' | 'session' | 'span';
3
+ [k: string]: unknown;
4
+ }
5
+ export interface TransportOptions {
6
+ endpoint: string;
7
+ key: string;
8
+ sdk: {
9
+ name: string;
10
+ version: string;
11
+ };
12
+ flushIntervalMs: number;
13
+ log: (...a: unknown[]) => void;
14
+ }
15
+ /** Batches items to `POST /ingest/v1/batch`, with backoff on 429/5xx and shutdown on 401. */
16
+ export declare class Transport {
17
+ private o;
18
+ private queue;
19
+ private timer;
20
+ private backoffUntil;
21
+ private backoffMs;
22
+ private inflight;
23
+ disabled: boolean;
24
+ constructor(o: TransportOptions);
25
+ send(item: Item, urgent?: boolean): void;
26
+ private schedule;
27
+ private drain;
28
+ private post;
29
+ private retry;
30
+ /** Send everything queued now, waiting at most `timeoutMs`. Resolves true when all was sent. */
31
+ flush(timeoutMs?: number): Promise<boolean>;
32
+ pending(): number;
33
+ }
package/package.json CHANGED
@@ -1,6 +1,68 @@
1
1
  {
2
2
  "name": "@hellsoft/vaka-node",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "publishConfig": {"access": "public"},
4
+ "version": "0.2.0",
5
+ "description": "Vaka Node.js SDK: crash reporting, OpenTelemetry tracing and logs, feature flags",
6
+ "license": "MIT OR Apache-2.0",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/ErikHellman/vaka",
10
+ "directory": "sdks/node"
11
+ },
12
+ "homepage": "https://vaka.hellsoft.se/sdk-node",
13
+ "keywords": [
14
+ "vaka",
15
+ "crash-reporting",
16
+ "error-tracking",
17
+ "opentelemetry",
18
+ "feature-flags",
19
+ "analytics"
20
+ ],
21
+ "engines": {
22
+ "node": ">=22.15.0"
23
+ },
24
+ "main": "./dist/index.cjs",
25
+ "module": "./dist/index.mjs",
26
+ "types": "./dist/index.d.ts",
27
+ "exports": {
28
+ ".": {
29
+ "types": "./dist/index.d.ts",
30
+ "import": "./dist/index.mjs",
31
+ "require": "./dist/index.cjs"
32
+ },
33
+ "./register": {
34
+ "types": "./dist/register.d.ts",
35
+ "import": "./dist/register.mjs",
36
+ "require": "./dist/register.cjs"
37
+ },
38
+ "./package.json": "./package.json"
39
+ },
40
+ "files": [
41
+ "dist",
42
+ "README.md"
43
+ ],
44
+ "scripts": {
45
+ "build": "node build.mjs && tsc --emitDeclarationOnly",
46
+ "typecheck": "tsc --noEmit",
47
+ "test": "npm run build && node --test test/*.test.mjs"
48
+ },
49
+ "dependencies": {
50
+ "@opentelemetry/api": "^1.10.0",
51
+ "@opentelemetry/core": "^3.1.1",
52
+ "@opentelemetry/exporter-logs-otlp-proto": "^0.301.2",
53
+ "@opentelemetry/exporter-trace-otlp-proto": "^0.301.2",
54
+ "@opentelemetry/instrumentation": "^0.301.2",
55
+ "@opentelemetry/instrumentation-http": "^0.301.2",
56
+ "@opentelemetry/resources": "^3.1.1",
57
+ "@opentelemetry/sdk-logs": "^3.1.1",
58
+ "@opentelemetry/sdk-node": "^0.301.2",
59
+ "@opentelemetry/sdk-trace": "^3.1.1"
60
+ },
61
+ "devDependencies": {
62
+ "@types/node": "^22.20.5",
63
+ "esbuild": "^0.24.2",
64
+ "express": "^4.22.3",
65
+ "fastify": "^5.12.8",
66
+ "typescript": "^5.9.3"
67
+ }
68
+ }