@burdenoff/be-sdk 2026.518.1 → 2026.518.3
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/dist/{chunk-CFUKZDDU.js → chunk-5FJZI7VX.js} +3 -3
- package/dist/{chunk-CFUKZDDU.js.map → chunk-5FJZI7VX.js.map} +1 -1
- package/dist/{chunk-QLEZPUAV.js → chunk-BESBOSX2.js} +3 -3
- package/dist/{chunk-QLEZPUAV.js.map → chunk-BESBOSX2.js.map} +1 -1
- package/dist/{chunk-4XAEES25.js → chunk-KTPFSXZF.js} +4 -850
- package/dist/chunk-KTPFSXZF.js.map +1 -0
- package/dist/chunk-REF7PANB.js +852 -0
- package/dist/chunk-REF7PANB.js.map +1 -0
- package/dist/graph/index.js +3 -3
- package/dist/index.js +14 -13
- package/dist/index.js.map +1 -1
- package/dist/instrumentation/index.js +2 -1
- package/dist/metrics/index.d.ts +17 -0
- package/dist/metrics/index.js +53 -0
- package/dist/metrics/index.js.map +1 -0
- package/dist/telemetry/index.js +3 -2
- package/dist/telemetry/index.js.map +1 -1
- package/dist/tracker/index.js +2 -2
- package/package.json +3 -3
- package/dist/chunk-4XAEES25.js.map +0 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { Instrument, Log, Metric, STANDARD_METRICS, SpanKind, SpanStatus, Trace, Tracer, createApolloInlineTracePlugin, createGraphQLInstrumentationPlugin, createPrometheusPlugin, extractOperationInfo, extractTraceContext, getGraphQLOperationFromContext, getGraphQLSpanFromContext, getLogger, getTraceContext, getTracer, initializeInstrumentation, initializeTracer, injectTraceContext, instrumentResolver, instrumentResolverMap, instrumented, isApolloInlineTraceAvailable, isInstrumentationInitialized, isPrometheusAvailable, isTracerInitialized, resetInstrumentation, setupInstrumentation, startSpan, traced, withSpan } from '../chunk-KTPFSXZF.js';
|
|
2
|
+
export { DEFAULT_CACHE_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_EVENT_QUEUE_CONFIG, DEFAULT_FEATURE_FLAGS, DEFAULT_GRAPHQL_CONFIG, DEFAULT_HTTP_CONFIG, DEFAULT_LOGGING_CONFIG, DEFAULT_METRICS_CONFIG, DEFAULT_TRACING_CONFIG, ENV_VARS, MetricsRegistry, buildDatabaseConfig, buildFeatureFlags, buildGraphQLConfig, buildInstrumentationConfig, buildMetricsConfig, buildTracingConfig, createCounter, createGauge, createHistogram, createUpDownCounter, getInstrumentationConfig, getMetricsRegistry, initializeInstrumentationConfig, initializeMetricsRegistry, isFeatureEnabled, isInstrumentationConfigInitialized, isMetricsRegistryInitialized, resetInstrumentationConfig, resetMetricsRegistry, updateInstrumentationConfig } from '../chunk-REF7PANB.js';
|
|
2
3
|
export { logger } from '../chunk-CBZNP6RF.js';
|
|
3
4
|
import '../chunk-XE4OXN2W.js';
|
|
4
5
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
interface WorkspaceQuotaCollector {
|
|
2
|
+
readonly metricName: string;
|
|
3
|
+
readonly help: string;
|
|
4
|
+
readonly quotaName: string;
|
|
5
|
+
collect(): Promise<Map<string, number>>;
|
|
6
|
+
}
|
|
7
|
+
declare class WorkspaceQuotaRegistry {
|
|
8
|
+
private readonly collectors;
|
|
9
|
+
private readonly gauges;
|
|
10
|
+
register(collector: WorkspaceQuotaCollector): void;
|
|
11
|
+
collectAll(): Promise<void>;
|
|
12
|
+
getCollectors(): readonly WorkspaceQuotaCollector[];
|
|
13
|
+
}
|
|
14
|
+
declare function getWorkspaceQuotaRegistry(): WorkspaceQuotaRegistry;
|
|
15
|
+
declare function resetWorkspaceQuotaRegistry(): void;
|
|
16
|
+
|
|
17
|
+
export { type WorkspaceQuotaCollector, getWorkspaceQuotaRegistry, resetWorkspaceQuotaRegistry };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { getMetricsRegistry } from '../chunk-REF7PANB.js';
|
|
2
|
+
import { __name } from '../chunk-XE4OXN2W.js';
|
|
3
|
+
|
|
4
|
+
// src/metrics/workspace-quota-metrics.ts
|
|
5
|
+
var WorkspaceQuotaRegistry = class WorkspaceQuotaRegistry2 {
|
|
6
|
+
static {
|
|
7
|
+
__name(this, "WorkspaceQuotaRegistry");
|
|
8
|
+
}
|
|
9
|
+
collectors = [];
|
|
10
|
+
gauges = /* @__PURE__ */ new Map();
|
|
11
|
+
register(collector) {
|
|
12
|
+
this.collectors.push(collector);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Runs all registered collectors and updates their gauges with fresh values.
|
|
16
|
+
* Gauges are created lazily on first collectAll() to ensure MetricsRegistry
|
|
17
|
+
* is initialized before gauge creation (instrumentation must be set up first).
|
|
18
|
+
*/
|
|
19
|
+
async collectAll() {
|
|
20
|
+
await Promise.allSettled(this.collectors.map(async (collector) => {
|
|
21
|
+
if (!this.gauges.has(collector.metricName)) {
|
|
22
|
+
this.gauges.set(collector.metricName, getMetricsRegistry().createGauge(collector.metricName, collector.help));
|
|
23
|
+
}
|
|
24
|
+
const gauge = this.gauges.get(collector.metricName);
|
|
25
|
+
if (!gauge) return;
|
|
26
|
+
const values = await collector.collect();
|
|
27
|
+
for (const [workspaceId, value] of values) {
|
|
28
|
+
gauge.set(value, {
|
|
29
|
+
workspace_id: workspaceId,
|
|
30
|
+
quota_name: collector.quotaName
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
/** Returns registered collectors — useful for activity-svc to discover tracked quota names. */
|
|
36
|
+
getCollectors() {
|
|
37
|
+
return this.collectors;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
var _registry = null;
|
|
41
|
+
function getWorkspaceQuotaRegistry() {
|
|
42
|
+
if (!_registry) _registry = new WorkspaceQuotaRegistry();
|
|
43
|
+
return _registry;
|
|
44
|
+
}
|
|
45
|
+
__name(getWorkspaceQuotaRegistry, "getWorkspaceQuotaRegistry");
|
|
46
|
+
function resetWorkspaceQuotaRegistry() {
|
|
47
|
+
_registry = null;
|
|
48
|
+
}
|
|
49
|
+
__name(resetWorkspaceQuotaRegistry, "resetWorkspaceQuotaRegistry");
|
|
50
|
+
|
|
51
|
+
export { getWorkspaceQuotaRegistry, resetWorkspaceQuotaRegistry };
|
|
52
|
+
//# sourceMappingURL=index.js.map
|
|
53
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/metrics/workspace-quota-metrics.ts"],"names":["WorkspaceQuotaRegistry","collectors","gauges","Map","register","collector","push","collectAll","Promise","allSettled","map","has","metricName","set","getMetricsRegistry","createGauge","help","gauge","get","values","collect","workspaceId","value","workspace_id","quota_name","quotaName","getCollectors","_registry","getWorkspaceQuotaRegistry","resetWorkspaceQuotaRegistry"],"mappings":";;;;AAkCA,IAAMA,sBAAAA,GAAN,MAAMA,uBAAAA,CAAAA;EAlCN;;;AAmCmBC,EAAAA,UAAAA,GAAwC,EAAA;AACxCC,EAAAA,MAAAA,uBAAaC,GAAAA,EAAAA;AAE9BC,EAAAA,QAAAA,CAASC,SAAAA,EAA0C;AACjD,IAAA,IAAA,CAAKJ,UAAAA,CAAWK,KAAKD,SAAAA,CAAAA;AACvB,EAAA;;;;;;AAOA,EAAA,MAAME,UAAAA,GAA4B;AAChC,IAAA,MAAMC,QAAQC,UAAAA,CACZ,IAAA,CAAKR,UAAAA,CAAWS,GAAAA,CAAI,OAAOL,SAAAA,KAAAA;AACzB,MAAA,IAAI,CAAC,IAAA,CAAKH,MAAAA,CAAOS,GAAAA,CAAIN,SAAAA,CAAUO,UAAU,CAAA,EAAG;AAC1C,QAAA,IAAA,CAAKV,MAAAA,CAAOW,GAAAA,CACVR,SAAAA,CAAUO,UAAAA,EACVE,kBAAAA,EAAAA,CAAqBC,WAAAA,CAAYV,SAAAA,CAAUO,UAAAA,EAAYP,SAAAA,CAAUW,IAAI,CAAA,CAAA;AAEzE,MAAA;AACA,MAAA,MAAMC,KAAAA,GAAQ,IAAA,CAAKf,MAAAA,CAAOgB,GAAAA,CAAIb,UAAUO,UAAU,CAAA;AAClD,MAAA,IAAI,CAACK,KAAAA,EAAO;AACZ,MAAA,MAAME,MAAAA,GAAS,MAAMd,SAAAA,CAAUe,OAAAA,EAAO;AACtC,MAAA,KAAA,MAAW,CAACC,WAAAA,EAAaC,KAAAA,CAAAA,IAAUH,MAAAA,EAAQ;AACzCF,QAAAA,KAAAA,CAAMJ,IAAIS,KAAAA,EAAO;UAAEC,YAAAA,EAAcF,WAAAA;AAAaG,UAAAA,UAAAA,EAAYnB,SAAAA,CAAUoB;SAAU,CAAA;AAChF,MAAA;AACF,IAAA,CAAA,CAAA,CAAA;AAEJ,EAAA;;EAGAC,aAAAA,GAAoD;AAClD,IAAA,OAAO,IAAA,CAAKzB,UAAAA;AACd,EAAA;AACF,CAAA;AAEA,IAAI0B,SAAAA,GAA2C,IAAA;AAExC,SAASC,yBAAAA,GAAAA;AACd,EAAA,IAAI,CAACD,SAAAA,EAAWA,SAAAA,GAAY,IAAI3B,sBAAAA,EAAAA;AAChC,EAAA,OAAO2B,SAAAA;AACT;AAHgBC,MAAAA,CAAAA,yBAAAA,EAAAA,2BAAAA,CAAAA;AAMT,SAASC,2BAAAA,GAAAA;AACdF,EAAAA,SAAAA,GAAY,IAAA;AACd;AAFgBE,MAAAA,CAAAA,2BAAAA,EAAAA,6BAAAA,CAAAA","file":"index.js","sourcesContent":["import { getMetricsRegistry } from '../instrumentation/metrics-collector.js';\nimport type { Gauge } from '../instrumentation/metrics-collector.js';\n\n/**\n * A single workspace-scoped quota metric.\n *\n * Services implement this and register it with WorkspaceQuotaRegistry at startup.\n * The metrics endpoint calls collectAll() on every scrape so values are always fresh.\n *\n * Pattern:\n * 1. Service registers collectors at startup (after instrumentation is initialized)\n * 2. /api/metrics handler calls collectAll() before serializing Prometheus output\n * 3. activity-svc scrapes /api/metrics and correlates values via quotaName to billing limits\n */\nexport interface WorkspaceQuotaCollector {\n /** Prometheus metric name, e.g. \"vibecontrols_tunnels_active\" */\n readonly metricName: string;\n /** Human-readable description shown in Prometheus HELP output */\n readonly help: string;\n /**\n * Billing quota name this metric maps to.\n * activity-svc uses this to correlate scraped values with quota limits.\n * e.g. \"vibecontrols.tunnels.active\"\n */\n readonly quotaName: string;\n /**\n * Called on every Prometheus scrape.\n * Must return current value per workspace ID.\n * Should be a fast, bounded DB query (GROUP BY workspace_id).\n * Failures are caught with Promise.allSettled — one failing collector does not block others.\n */\n collect(): Promise<Map<string, number>>;\n}\n\nclass WorkspaceQuotaRegistry {\n private readonly collectors: WorkspaceQuotaCollector[] = [];\n private readonly gauges = new Map<string, Gauge>();\n\n register(collector: WorkspaceQuotaCollector): void {\n this.collectors.push(collector);\n }\n\n /**\n * Runs all registered collectors and updates their gauges with fresh values.\n * Gauges are created lazily on first collectAll() to ensure MetricsRegistry\n * is initialized before gauge creation (instrumentation must be set up first).\n */\n async collectAll(): Promise<void> {\n await Promise.allSettled(\n this.collectors.map(async (collector) => {\n if (!this.gauges.has(collector.metricName)) {\n this.gauges.set(\n collector.metricName,\n getMetricsRegistry().createGauge(collector.metricName, collector.help)\n );\n }\n const gauge = this.gauges.get(collector.metricName);\n if (!gauge) return;\n const values = await collector.collect();\n for (const [workspaceId, value] of values) {\n gauge.set(value, { workspace_id: workspaceId, quota_name: collector.quotaName });\n }\n })\n );\n }\n\n /** Returns registered collectors — useful for activity-svc to discover tracked quota names. */\n getCollectors(): readonly WorkspaceQuotaCollector[] {\n return this.collectors;\n }\n}\n\nlet _registry: WorkspaceQuotaRegistry | null = null;\n\nexport function getWorkspaceQuotaRegistry(): WorkspaceQuotaRegistry {\n if (!_registry) _registry = new WorkspaceQuotaRegistry();\n return _registry;\n}\n\n/** For testing only. */\nexport function resetWorkspaceQuotaRegistry(): void {\n _registry = null;\n}\n"]}
|
package/dist/telemetry/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { DEFAULT_REDACT_PATHS, createPinoLogger } from '../chunk-SNEOLWXT.js';
|
|
2
|
-
import { setActiveTelemetryLogger, setupInstrumentation } from '../chunk-
|
|
3
|
-
export { initializeInstrumentation, setupInstrumentation } from '../chunk-
|
|
2
|
+
import { setActiveTelemetryLogger, setupInstrumentation } from '../chunk-KTPFSXZF.js';
|
|
3
|
+
export { initializeInstrumentation, setupInstrumentation } from '../chunk-KTPFSXZF.js';
|
|
4
|
+
import '../chunk-REF7PANB.js';
|
|
4
5
|
import { redactSensitiveFields, logger } from '../chunk-CBZNP6RF.js';
|
|
5
6
|
import { __name } from '../chunk-XE4OXN2W.js';
|
|
6
7
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/telemetry/health.ts","../../src/telemetry/metrics-endpoint.ts","../../src/telemetry/prisma-logging.ts","../../src/telemetry/index.ts"],"names":["createHealthRoutes","_deps","Proxy","get","_target","prop","undefined","loadDefaultRegistry","mod","collectDefaultMetrics","register","createMetricsRoutesImpl","app","opts","path","ctx","registry","ctxWithSet","set","status","headers","contentType","metrics","createMetricsRoutes","createPrismaLoggingExtension","logger","name","query","$allOperations","model","operation","args","start","Date","now","result","debug","duration_ms","redactSensitiveFields","err","error","Error","message","String","resolveEnv","explicit","fromEnv","process","env","resolveVersion","resolveEndpoint","proto","resolveSampling","Number","isFinite","Math","min","max","parsed","resolveOtelSdkEnabled","sdkDisabled","otelEnabled","bootstrapTelemetry","cfg","serviceVersion","otlpEndpoint","sampleRatio","createPinoLogger","serviceName","version","setActiveTelemetryLogger","instrumentation","setupInstrumentation","tracing","samplingRate","otelSdk","createOtelSdk","boundary","module","info","metricsEnabled","metricsDropReason","warn","reason","shutdown","defaultLogger","setLevel","getLevel"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * `/health`, `/health/live`, `/health/ready` Elysia routes with a 1s\n * result cache so readiness checks can't stampede Postgres.\n *\n * Dependencies (prisma, eventQueue, valkey) are optional — omit any client and\n * the readiness check simply skips it.\n */\n\ninterface PrismaLike {\n $queryRaw: (strings: TemplateStringsArray) => Promise<unknown>;\n}\ninterface EventQueueLike {\n isConnected?: () => boolean | Promise<boolean>;\n healthCheck?: () => Promise<{ ok: boolean }>;\n}\ninterface ValkeyLike {\n ping: () => Promise<unknown>;\n}\n\nexport interface HealthDeps {\n prisma?: PrismaLike;\n eventQueue?: EventQueueLike;\n valkey?: ValkeyLike;\n /** Service version reported on /health. */\n version?: string;\n /** Service name reported on /health. */\n serviceName?: string;\n}\n\ninterface CachedStatus {\n ready: boolean;\n checked: Record<string, { ok: boolean; error?: string }>;\n at: number;\n}\n\nconst CACHE_TTL_MS = 1000;\n\nasync function probeReady(deps: HealthDeps): Promise<CachedStatus> {\n const checked: Record<string, { ok: boolean; error?: string }> = {};\n\n if (deps.prisma) {\n try {\n await deps.prisma.$queryRaw`SELECT 1`;\n checked['postgres'] = { ok: true };\n } catch (err) {\n checked['postgres'] = {\n ok: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n\n if (deps.eventQueue) {\n try {\n const connected =\n typeof deps.eventQueue.isConnected === 'function'\n ? await Promise.resolve(deps.eventQueue.isConnected())\n : ((await deps.eventQueue.healthCheck?.())?.ok ?? true);\n checked['eventQueue'] = { ok: Boolean(connected) };\n } catch (err) {\n checked['eventQueue'] = {\n ok: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n\n if (deps.valkey) {\n try {\n await deps.valkey.ping();\n checked['valkey'] = { ok: true };\n } catch (err) {\n checked['valkey'] = {\n ok: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n\n const ready = Object.values(checked).every((c) => c.ok);\n return { ready, checked, at: Date.now() };\n}\n\nexport function createHealthRoutes(_deps: HealthDeps = {}): unknown {\n // Return an Elysia app lazily so be-sdk doesn't hard-require elysia.\n return new Proxy(\n {},\n {\n get(_target, prop): unknown {\n // Tell TypeScript consumers the returned object is an Elysia plugin;\n // the actual mount happens via `createHealthRoutesImpl`. Services\n // that prefer direct use can call `createHealthRoutesImpl(elysia, deps)`.\n if (prop === 'use' || prop === 'then') return undefined;\n return undefined;\n },\n }\n );\n}\n\n/**\n * Mount health routes on an existing Elysia app. Callers hold a reference\n * to Elysia themselves; be-sdk stays decoupled.\n */\nexport function createHealthRoutesImpl<\n App extends {\n get: (path: string, handler: (ctx: unknown) => unknown) => App;\n },\n>(app: App, deps: HealthDeps = {}): App {\n let cache: CachedStatus | null = null;\n\n const getStatus = async (): Promise<CachedStatus> => {\n if (cache && Date.now() - cache.at < CACHE_TTL_MS) return cache;\n cache = await probeReady(deps);\n return cache;\n };\n\n app.get('/health/live', () => ({\n status: 'ok',\n serviceName: deps.serviceName,\n version: deps.version,\n }));\n\n app.get('/health/ready', async (ctx: unknown): Promise<unknown> => {\n const status = await getStatus();\n const ctxWithSet = ctx as { set?: { status?: number } };\n if (!status.ready && ctxWithSet.set) ctxWithSet.set.status = 503;\n return {\n status: status.ready ? 'ok' : 'degraded',\n serviceName: deps.serviceName,\n version: deps.version,\n checks: status.checked,\n };\n });\n\n app.get('/health', async (ctx: unknown): Promise<unknown> => {\n const status = await getStatus();\n const ctxWithSet = ctx as { set?: { status?: number } };\n if (!status.ready && ctxWithSet.set) ctxWithSet.set.status = 503;\n return {\n status: status.ready ? 'ok' : 'degraded',\n serviceName: deps.serviceName,\n version: deps.version,\n checks: status.checked,\n uptime_s: Math.round(process.uptime()),\n };\n });\n\n return app;\n}\n","/**\n * Prometheus `/metrics` route mounter. Uses the shared `prom-client`\n * default registry so all instrumentation (GraphQL Envelop, Prisma,\n * runtime) shows up on a single endpoint.\n */\n\ninterface PromRegistryLike {\n metrics: () => Promise<string> | string;\n contentType?: string;\n}\n\nexport interface MetricsMountOptions {\n registry?: PromRegistryLike;\n path?: string;\n}\n\nexport async function loadDefaultRegistry(): Promise<PromRegistryLike | null> {\n try {\n const mod = (await import('prom-client')) as unknown as {\n register: PromRegistryLike;\n collectDefaultMetrics: (opts?: Record<string, unknown>) => void;\n };\n // Kick runtime metrics into the default registry if not already.\n try {\n mod.collectDefaultMetrics({ register: mod.register });\n } catch {\n // Already registered — ignore duplicate-metric errors.\n }\n return mod.register;\n } catch {\n return null;\n }\n}\n\nexport function createMetricsRoutesImpl<\n App extends {\n get: (path: string, handler: (ctx: unknown) => unknown) => App;\n },\n>(app: App, opts: MetricsMountOptions = {}): App {\n const path = opts.path ?? '/metrics';\n\n app.get(path, async (ctx: unknown): Promise<unknown> => {\n const registry = opts.registry ?? (await loadDefaultRegistry());\n const ctxWithSet = ctx as { set?: { status?: number; headers?: Record<string, string> } };\n if (!registry) {\n if (ctxWithSet.set) ctxWithSet.set.status = 503;\n return '# prom-client not installed\\n';\n }\n if (ctxWithSet.set) {\n ctxWithSet.set.status = 200;\n ctxWithSet.set.headers = {\n 'content-type': registry.contentType ?? 'text/plain; version=0.0.4; charset=utf-8',\n };\n }\n return registry.metrics();\n });\n\n return app;\n}\n\n/**\n * Legacy export name used by the service template. Composes the Elysia\n * plugin-style function that `new Elysia().use(...)` accepts.\n */\nexport function createMetricsRoutes(opts: MetricsMountOptions = {}): unknown {\n return (app: Parameters<typeof createMetricsRoutesImpl>[0]): unknown => createMetricsRoutesImpl(app, opts);\n}\n","/**\n * Prisma client extension that pipes query events through the SDK logger\n * with trace/span correlation fields auto-injected. The\n * `@prisma/instrumentation` peer provides the spans\n * themselves; this extension only adds structured log events on top.\n */\nimport type { Logger } from '../logger/index.js';\nimport { redactSensitiveFields } from '../logger/index.js';\n\ntype PrismaQueryArgs = {\n model?: string;\n operation: string;\n args: unknown;\n query: (args: unknown) => Promise<unknown>;\n};\n\n/**\n * Returns a Prisma Client extension object compatible with the\n * `$extends()` API (Prisma v5+).\n *\n * ```ts\n * export const prisma = new PrismaClient().$extends(\n * createPrismaLoggingExtension(logger)\n * );\n * ```\n */\nexport function createPrismaLoggingExtension(logger: Logger): {\n name: string;\n query: {\n $allOperations: (args: PrismaQueryArgs) => Promise<unknown>;\n };\n} {\n return {\n name: 'burdenoff-pino-logging',\n query: {\n async $allOperations({ model, operation, args, query }: PrismaQueryArgs): Promise<unknown> {\n const start = Date.now();\n try {\n const result = await query(args);\n logger.debug('prisma.query', {\n model,\n operation,\n duration_ms: Date.now() - start,\n args: redactSensitiveFields(args),\n });\n return result;\n } catch (err) {\n logger.error('prisma.error', {\n model,\n operation,\n duration_ms: Date.now() - start,\n error: err instanceof Error ? err.message : String(err),\n });\n throw err;\n }\n },\n },\n };\n}\n","/**\n * Unified telemetry bootstrap for Burdenoff services.\n *\n * Composes the existing `instrumentation/` + `observability/` + `logger/`\n * modules and adds:\n * - `bootstrapTelemetry({ serviceName, boundary, module, env })` — single\n * call that initializes OTel, wires Pino logger with trace fields,\n * exposes GraphQL Yoga plugins, registers process exit hooks.\n * - `createHealthRoutes({ prisma, nats, valkey, version })` — `/health`,\n * `/health/live`, `/health/ready` Elysia routes.\n * - `createMetricsRoutes(registry?)` — `/metrics` Prometheus exposition.\n * - `createPrismaLoggingExtension(logger)` — Prisma extension that pipes\n * query events through Pino with trace/span correlation ids.\n *\n * The module does not pull in `@opentelemetry/sdk-node` or `pino` as direct\n * deps — services install those as optional peers, and imports are lazy so\n * services that don't install them still load.\n */\n\nimport type { Logger as BaseLogger } from '../logger/index.js';\nimport { logger as defaultLogger } from '../logger/index.js';\nimport {\n initializeInstrumentation,\n setupInstrumentation,\n type SetupInstrumentationOptions,\n type InstrumentationSetupResult,\n} from '../instrumentation/index.js';\nimport { setActiveTelemetryLogger } from './logger-state.js';\nimport type { OtelSdkHandle } from './sdk.js';\n\nexport { createHealthRoutes } from './health.js';\nexport { createMetricsRoutes } from './metrics-endpoint.js';\nexport { createPrismaLoggingExtension } from './prisma-logging.js';\nexport { DEFAULT_REDACT_PATHS } from './pino-redaction.js';\nexport { createPinoLogger } from './pino-logger.js';\n\nexport type Boundary = 'wspace' | 'global' | 'gateway';\nexport type Env = 'alpha' | 'prod' | 'dev';\n\nexport interface TelemetryConfig {\n /** Full service name, e.g. \"wspace-auth-svc\". */\n serviceName: string;\n /** Semver of the service deployment; defaults to `process.env.npm_package_version`. */\n serviceVersion?: string;\n /** Monorepo boundary: `wspace`, `global`, or `gateway`. */\n boundary: Boundary;\n /** Module slug, e.g. `auth` (omit for gateways). */\n module?: string;\n /** Deployment environment; defaults to alpha for non-production NODE_ENV. */\n env?: Env;\n /**\n * OTLP endpoint for spans/metrics/logs. Defaults to\n * `$OTEL_EXPORTER_OTLP_ENDPOINT` or\n * `http://alloy.sre.svc.cluster.local:4318`.\n */\n otlpEndpoint?: string;\n /** Head-based sampling ratio. Default: alpha=1.0, prod=0.1. */\n sampleRatio?: number;\n /** Extra options forwarded to `setupInstrumentation`. */\n instrumentation?: SetupInstrumentationOptions;\n}\n\nexport interface TelemetryHandle {\n /** The configured service name (for use in health routes, etc.). */\n serviceName: string;\n /** The resolved service version. */\n serviceVersion: string;\n /** Environment. */\n env: Env;\n /** The Pino-backed logger. */\n logger: BaseLogger;\n /** Initialized instrumentation (tracer + metrics + plugins). */\n instrumentation: InstrumentationSetupResult;\n /** Cleanup hook; services call on SIGTERM. */\n shutdown: () => Promise<void>;\n}\n\nfunction resolveEnv(explicit?: Env): Env {\n if (explicit) return explicit;\n const fromEnv = process.env['DEPLOY_ENV'] ?? process.env['NODE_ENV'] ?? '';\n if (fromEnv === 'production' || fromEnv === 'prod') return 'prod';\n if (fromEnv === 'development' || fromEnv === 'dev') return 'dev';\n return 'alpha';\n}\n\nfunction resolveVersion(explicit?: string): string {\n if (explicit) return explicit;\n return process.env['npm_package_version'] ?? process.env['SERVICE_VERSION'] ?? '0.0.0';\n}\n\nfunction resolveEndpoint(explicit?: string): string {\n if (explicit) return explicit;\n const proto = 'http';\n return process.env['OTEL_EXPORTER_OTLP_ENDPOINT'] ?? `${proto}://alloy.sre.svc.cluster.local:4318`;\n}\n\nfunction resolveSampling(explicit: number | undefined, env: Env): number {\n if (typeof explicit === 'number' && Number.isFinite(explicit)) return Math.min(1, Math.max(0, explicit));\n const fromEnv = process.env['OTEL_TRACES_SAMPLER_ARG'];\n if (fromEnv) {\n const parsed = Number(fromEnv);\n if (Number.isFinite(parsed)) return Math.min(1, Math.max(0, parsed));\n }\n if (env === 'prod') return 0.1;\n return 1.0;\n}\n\nfunction resolveOtelSdkEnabled(): boolean {\n const sdkDisabled = process.env['OTEL_SDK_DISABLED'];\n if (sdkDisabled === 'true' || sdkDisabled === '1') return false;\n const otelEnabled = process.env['OTEL_ENABLED'];\n if (otelEnabled === 'false' || otelEnabled === '0') return false;\n return true;\n}\n\n/**\n * Bootstrap the full telemetry stack for a service.\n *\n * Services call this ONCE at startup **before** importing Prisma / GraphQL\n * Yoga / NATS so OTel can auto-instrument their dependencies.\n *\n * ```ts\n * // src/telemetry.ts\n * import { bootstrapTelemetry } from '@burdenoff/be-sdk/telemetry';\n * export const telemetry = await bootstrapTelemetry({\n * serviceName: 'wspace-auth-svc',\n * boundary: 'wspace',\n * module: 'auth',\n * });\n *\n * // src/index.ts — must be the FIRST import line.\n * import './telemetry.js';\n * ```\n */\nexport async function bootstrapTelemetry(cfg: TelemetryConfig): Promise<TelemetryHandle> {\n const env = resolveEnv(cfg.env);\n const serviceVersion = resolveVersion(cfg.serviceVersion);\n const otlpEndpoint = resolveEndpoint(cfg.otlpEndpoint);\n const sampleRatio = resolveSampling(cfg.sampleRatio, env);\n\n // Pino logger with trace/span correlation + redaction.\n // createPinoLogger is async (loads pino via dynamic import); awaiting it\n // is required — without await, `logger` is a Promise and calls like\n // logger.warn(...) crash with \"logger.warn is not a function\" during the\n // sdk-node fallback path.\n const { createPinoLogger } = await import('./pino-logger.js');\n const logger = await createPinoLogger({\n serviceName: cfg.serviceName,\n env,\n version: serviceVersion,\n });\n setActiveTelemetryLogger(logger);\n\n // Initialize core instrumentation (tracer, metrics registry, envelop plugins).\n // `setupInstrumentation` internally calls `initializeInstrumentation`.\n const instrumentation = setupInstrumentation(cfg.serviceName, {\n ...cfg.instrumentation,\n tracing: {\n serviceName: cfg.serviceName,\n ...(cfg.instrumentation?.tracing ?? {}),\n samplingRate: sampleRatio,\n },\n metrics: {\n serviceName: cfg.serviceName,\n ...(cfg.instrumentation?.metrics ?? {}),\n },\n });\n\n // Start the NodeSDK exporter pipeline if sdk-node is present (optional).\n let otelSdk: OtelSdkHandle | undefined;\n if (resolveOtelSdkEnabled()) {\n try {\n const { createOtelSdk } = await import('./sdk.js');\n otelSdk = await createOtelSdk({\n serviceName: cfg.serviceName,\n serviceVersion,\n boundary: cfg.boundary,\n module: cfg.module,\n env,\n otlpEndpoint,\n sampleRatio,\n });\n // Explicit success log includes metrics path status so an operator can\n // distinguish traces-only startup from full traces+metrics startup.\n logger.info('[telemetry] OpenTelemetry exporter pipeline started', {\n serviceName: cfg.serviceName,\n otlpEndpoint: otlpEndpoint ? '<configured>' : '<not set>',\n sampleRatio,\n metricsEnabled: otelSdk.metricsEnabled,\n });\n\n if (!otelSdk.metricsEnabled && otelSdk.metricsDropReason) {\n logger.warn('[telemetry] OpenTelemetry metrics reader disabled; continuing with traces only', {\n serviceName: cfg.serviceName,\n reason: otelSdk.metricsDropReason,\n });\n }\n } catch (err) {\n logger.warn('[telemetry] OpenTelemetry exporter pipeline failed to start; continuing with logs only', {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n } else {\n logger.info('[telemetry] OTel SDK exporter disabled by env');\n }\n\n const shutdown = async (): Promise<void> => {\n try {\n if (otelSdk?.shutdown) await otelSdk.shutdown();\n } catch (err) {\n (logger as unknown as BaseLogger).warn('[telemetry] shutdown error (ignored)', {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n };\n\n // Mirror defaultLogger so services that still use the singleton get trace-enriched output.\n defaultLogger.setLevel(logger.getLevel?.() ?? 'info');\n\n return {\n serviceName: cfg.serviceName,\n serviceVersion,\n env,\n logger: logger as unknown as BaseLogger,\n instrumentation,\n shutdown,\n };\n}\n\n// Re-export what services typically import.\nexport { initializeInstrumentation, setupInstrumentation };\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/telemetry/health.ts","../../src/telemetry/metrics-endpoint.ts","../../src/telemetry/prisma-logging.ts","../../src/telemetry/index.ts"],"names":["createHealthRoutes","_deps","Proxy","get","_target","prop","undefined","loadDefaultRegistry","mod","collectDefaultMetrics","register","createMetricsRoutesImpl","app","opts","path","ctx","registry","ctxWithSet","set","status","headers","contentType","metrics","createMetricsRoutes","createPrismaLoggingExtension","logger","name","query","$allOperations","model","operation","args","start","Date","now","result","debug","duration_ms","redactSensitiveFields","err","error","Error","message","String","resolveEnv","explicit","fromEnv","process","env","resolveVersion","resolveEndpoint","proto","resolveSampling","Number","isFinite","Math","min","max","parsed","resolveOtelSdkEnabled","sdkDisabled","otelEnabled","bootstrapTelemetry","cfg","serviceVersion","otlpEndpoint","sampleRatio","createPinoLogger","serviceName","version","setActiveTelemetryLogger","instrumentation","setupInstrumentation","tracing","samplingRate","otelSdk","createOtelSdk","boundary","module","info","metricsEnabled","metricsDropReason","warn","reason","shutdown","defaultLogger","setLevel","getLevel"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * `/health`, `/health/live`, `/health/ready` Elysia routes with a 1s\n * result cache so readiness checks can't stampede Postgres.\n *\n * Dependencies (prisma, eventQueue, valkey) are optional — omit any client and\n * the readiness check simply skips it.\n */\n\ninterface PrismaLike {\n $queryRaw: (strings: TemplateStringsArray) => Promise<unknown>;\n}\ninterface EventQueueLike {\n isConnected?: () => boolean | Promise<boolean>;\n healthCheck?: () => Promise<{ ok: boolean }>;\n}\ninterface ValkeyLike {\n ping: () => Promise<unknown>;\n}\n\nexport interface HealthDeps {\n prisma?: PrismaLike;\n eventQueue?: EventQueueLike;\n valkey?: ValkeyLike;\n /** Service version reported on /health. */\n version?: string;\n /** Service name reported on /health. */\n serviceName?: string;\n}\n\ninterface CachedStatus {\n ready: boolean;\n checked: Record<string, { ok: boolean; error?: string }>;\n at: number;\n}\n\nconst CACHE_TTL_MS = 1000;\n\nasync function probeReady(deps: HealthDeps): Promise<CachedStatus> {\n const checked: Record<string, { ok: boolean; error?: string }> = {};\n\n if (deps.prisma) {\n try {\n await deps.prisma.$queryRaw`SELECT 1`;\n checked['postgres'] = { ok: true };\n } catch (err) {\n checked['postgres'] = {\n ok: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n\n if (deps.eventQueue) {\n try {\n const connected =\n typeof deps.eventQueue.isConnected === 'function'\n ? await Promise.resolve(deps.eventQueue.isConnected())\n : ((await deps.eventQueue.healthCheck?.())?.ok ?? true);\n checked['eventQueue'] = { ok: Boolean(connected) };\n } catch (err) {\n checked['eventQueue'] = {\n ok: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n\n if (deps.valkey) {\n try {\n await deps.valkey.ping();\n checked['valkey'] = { ok: true };\n } catch (err) {\n checked['valkey'] = {\n ok: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n\n const ready = Object.values(checked).every((c) => c.ok);\n return { ready, checked, at: Date.now() };\n}\n\nexport function createHealthRoutes(_deps: HealthDeps = {}): unknown {\n // Return an Elysia app lazily so be-sdk doesn't hard-require elysia.\n return new Proxy(\n {},\n {\n get(_target, prop): unknown {\n // Tell TypeScript consumers the returned object is an Elysia plugin;\n // the actual mount happens via `createHealthRoutesImpl`. Services\n // that prefer direct use can call `createHealthRoutesImpl(elysia, deps)`.\n if (prop === 'use' || prop === 'then') return undefined;\n return undefined;\n },\n }\n );\n}\n\n/**\n * Mount health routes on an existing Elysia app. Callers hold a reference\n * to Elysia themselves; be-sdk stays decoupled.\n */\nexport function createHealthRoutesImpl<\n App extends {\n get: (path: string, handler: (ctx: unknown) => unknown) => App;\n },\n>(app: App, deps: HealthDeps = {}): App {\n let cache: CachedStatus | null = null;\n\n const getStatus = async (): Promise<CachedStatus> => {\n if (cache && Date.now() - cache.at < CACHE_TTL_MS) return cache;\n cache = await probeReady(deps);\n return cache;\n };\n\n app.get('/health/live', () => ({\n status: 'ok',\n serviceName: deps.serviceName,\n version: deps.version,\n }));\n\n app.get('/health/ready', async (ctx: unknown): Promise<unknown> => {\n const status = await getStatus();\n const ctxWithSet = ctx as { set?: { status?: number } };\n if (!status.ready && ctxWithSet.set) ctxWithSet.set.status = 503;\n return {\n status: status.ready ? 'ok' : 'degraded',\n serviceName: deps.serviceName,\n version: deps.version,\n checks: status.checked,\n };\n });\n\n app.get('/health', async (ctx: unknown): Promise<unknown> => {\n const status = await getStatus();\n const ctxWithSet = ctx as { set?: { status?: number } };\n if (!status.ready && ctxWithSet.set) ctxWithSet.set.status = 503;\n return {\n status: status.ready ? 'ok' : 'degraded',\n serviceName: deps.serviceName,\n version: deps.version,\n checks: status.checked,\n uptime_s: Math.round(process.uptime()),\n };\n });\n\n return app;\n}\n","/**\n * Prometheus `/metrics` route mounter. Uses the shared `prom-client`\n * default registry so all instrumentation (GraphQL Envelop, Prisma,\n * runtime) shows up on a single endpoint.\n */\n\ninterface PromRegistryLike {\n metrics: () => Promise<string> | string;\n contentType?: string;\n}\n\nexport interface MetricsMountOptions {\n registry?: PromRegistryLike;\n path?: string;\n}\n\nexport async function loadDefaultRegistry(): Promise<PromRegistryLike | null> {\n try {\n const mod = (await import('prom-client')) as unknown as {\n register: PromRegistryLike;\n collectDefaultMetrics: (opts?: Record<string, unknown>) => void;\n };\n // Kick runtime metrics into the default registry if not already.\n try {\n mod.collectDefaultMetrics({ register: mod.register });\n } catch {\n // Already registered — ignore duplicate-metric errors.\n }\n return mod.register;\n } catch {\n return null;\n }\n}\n\nexport function createMetricsRoutesImpl<\n App extends {\n get: (path: string, handler: (ctx: unknown) => unknown) => App;\n },\n>(app: App, opts: MetricsMountOptions = {}): App {\n const path = opts.path ?? '/metrics';\n\n app.get(path, async (ctx: unknown): Promise<unknown> => {\n const registry = opts.registry ?? (await loadDefaultRegistry());\n const ctxWithSet = ctx as { set?: { status?: number; headers?: Record<string, string> } };\n if (!registry) {\n if (ctxWithSet.set) ctxWithSet.set.status = 503;\n return '# prom-client not installed\\n';\n }\n if (ctxWithSet.set) {\n ctxWithSet.set.status = 200;\n ctxWithSet.set.headers = {\n 'content-type': registry.contentType ?? 'text/plain; version=0.0.4; charset=utf-8',\n };\n }\n return registry.metrics();\n });\n\n return app;\n}\n\n/**\n * Legacy export name used by the service template. Composes the Elysia\n * plugin-style function that `new Elysia().use(...)` accepts.\n */\nexport function createMetricsRoutes(opts: MetricsMountOptions = {}): unknown {\n return (app: Parameters<typeof createMetricsRoutesImpl>[0]): unknown => createMetricsRoutesImpl(app, opts);\n}\n","/**\n * Prisma client extension that pipes query events through the SDK logger\n * with trace/span correlation fields auto-injected. The\n * `@prisma/instrumentation` peer provides the spans\n * themselves; this extension only adds structured log events on top.\n */\nimport type { Logger } from '../logger/index.js';\nimport { redactSensitiveFields } from '../logger/index.js';\n\ntype PrismaQueryArgs = {\n model?: string;\n operation: string;\n args: unknown;\n query: (args: unknown) => Promise<unknown>;\n};\n\n/**\n * Returns a Prisma Client extension object compatible with the\n * `$extends()` API (Prisma v5+).\n *\n * ```ts\n * export const prisma = new PrismaClient().$extends(\n * createPrismaLoggingExtension(logger)\n * );\n * ```\n */\nexport function createPrismaLoggingExtension(logger: Logger): {\n name: string;\n query: {\n $allOperations: (args: PrismaQueryArgs) => Promise<unknown>;\n };\n} {\n return {\n name: 'burdenoff-pino-logging',\n query: {\n async $allOperations({ model, operation, args, query }: PrismaQueryArgs): Promise<unknown> {\n const start = Date.now();\n try {\n const result = await query(args);\n logger.debug('prisma.query', {\n model,\n operation,\n duration_ms: Date.now() - start,\n args: redactSensitiveFields(args),\n });\n return result;\n } catch (err) {\n logger.error('prisma.error', {\n model,\n operation,\n duration_ms: Date.now() - start,\n error: err instanceof Error ? err.message : String(err),\n });\n throw err;\n }\n },\n },\n };\n}\n","/**\n * Unified telemetry bootstrap for Burdenoff services.\n *\n * Composes the existing `instrumentation/` + `observability/` + `logger/`\n * modules and adds:\n * - `bootstrapTelemetry({ serviceName, boundary, module, env })` — single\n * call that initializes OTel, wires Pino logger with trace fields,\n * exposes GraphQL Yoga plugins, registers process exit hooks.\n * - `createHealthRoutes({ prisma, nats, valkey, version })` — `/health`,\n * `/health/live`, `/health/ready` Elysia routes.\n * - `createMetricsRoutes(registry?)` — `/metrics` Prometheus exposition.\n * - `createPrismaLoggingExtension(logger)` — Prisma extension that pipes\n * query events through Pino with trace/span correlation ids.\n *\n * The module does not pull in `@opentelemetry/sdk-node` or `pino` as direct\n * deps — services install those as optional peers, and imports are lazy so\n * services that don't install them still load.\n */\n\nimport type { Logger as BaseLogger } from '../logger/index.js';\nimport { logger as defaultLogger } from '../logger/index.js';\nimport {\n initializeInstrumentation,\n setupInstrumentation,\n type SetupInstrumentationOptions,\n type InstrumentationSetupResult,\n} from '../instrumentation/index.js';\nimport { setActiveTelemetryLogger } from './logger-state.js';\nimport type { OtelSdkHandle } from './sdk.js';\n\nexport { createHealthRoutes } from './health.js';\nexport { createMetricsRoutes } from './metrics-endpoint.js';\nexport { createPrismaLoggingExtension } from './prisma-logging.js';\nexport { DEFAULT_REDACT_PATHS } from './pino-redaction.js';\nexport { createPinoLogger } from './pino-logger.js';\n\nexport type Boundary = 'wspace' | 'global' | 'gateway';\nexport type Env = 'alpha' | 'prod' | 'dev';\n\nexport interface TelemetryConfig {\n /** Full service name, e.g. \"wspace-auth-svc\". */\n serviceName: string;\n /** Semver of the service deployment; defaults to `process.env.npm_package_version`. */\n serviceVersion?: string;\n /** Monorepo boundary: `wspace`, `global`, or `gateway`. */\n boundary: Boundary;\n /** Module slug, e.g. `auth` (omit for gateways). */\n module?: string;\n /** Deployment environment; defaults to alpha for non-production NODE_ENV. */\n env?: Env;\n /**\n * OTLP endpoint for spans/metrics/logs. Defaults to\n * `$OTEL_EXPORTER_OTLP_ENDPOINT` or\n * `http://alloy.sre.svc.cluster.local:4318`.\n */\n otlpEndpoint?: string;\n /** Head-based sampling ratio. Default: alpha=1.0, prod=0.1. */\n sampleRatio?: number;\n /** Extra options forwarded to `setupInstrumentation`. */\n instrumentation?: SetupInstrumentationOptions;\n}\n\nexport interface TelemetryHandle {\n /** The configured service name (for use in health routes, etc.). */\n serviceName: string;\n /** The resolved service version. */\n serviceVersion: string;\n /** Environment. */\n env: Env;\n /** The Pino-backed logger. */\n logger: BaseLogger;\n /** Initialized instrumentation (tracer + metrics + plugins). */\n instrumentation: InstrumentationSetupResult;\n /** Cleanup hook; services call on SIGTERM. */\n shutdown: () => Promise<void>;\n}\n\nfunction resolveEnv(explicit?: Env): Env {\n if (explicit) return explicit;\n const fromEnv = process.env['DEPLOY_ENV'] ?? process.env['NODE_ENV'] ?? '';\n if (fromEnv === 'production' || fromEnv === 'prod') return 'prod';\n if (fromEnv === 'development' || fromEnv === 'dev') return 'dev';\n return 'alpha';\n}\n\nfunction resolveVersion(explicit?: string): string {\n if (explicit) return explicit;\n return process.env['npm_package_version'] ?? process.env['SERVICE_VERSION'] ?? '0.0.0';\n}\n\nfunction resolveEndpoint(explicit?: string): string {\n if (explicit) return explicit;\n const proto = 'http';\n return process.env['OTEL_EXPORTER_OTLP_ENDPOINT'] ?? `${proto}://alloy.sre.svc.cluster.local:4318`;\n}\n\nfunction resolveSampling(explicit: number | undefined, env: Env): number {\n if (typeof explicit === 'number' && Number.isFinite(explicit)) return Math.min(1, Math.max(0, explicit));\n const fromEnv = process.env['OTEL_TRACES_SAMPLER_ARG'];\n if (fromEnv) {\n const parsed = Number(fromEnv);\n if (Number.isFinite(parsed)) return Math.min(1, Math.max(0, parsed));\n }\n if (env === 'prod') return 0.1;\n return 1.0;\n}\n\nfunction resolveOtelSdkEnabled(): boolean {\n const sdkDisabled = process.env['OTEL_SDK_DISABLED'];\n if (sdkDisabled === 'true' || sdkDisabled === '1') return false;\n const otelEnabled = process.env['OTEL_ENABLED'];\n if (otelEnabled === 'false' || otelEnabled === '0') return false;\n return true;\n}\n\n/**\n * Bootstrap the full telemetry stack for a service.\n *\n * Services call this ONCE at startup **before** importing Prisma / GraphQL\n * Yoga / NATS so OTel can auto-instrument their dependencies.\n *\n * ```ts\n * // src/telemetry.ts\n * import { bootstrapTelemetry } from '@burdenoff/be-sdk/telemetry';\n * export const telemetry = await bootstrapTelemetry({\n * serviceName: 'wspace-auth-svc',\n * boundary: 'wspace',\n * module: 'auth',\n * });\n *\n * // src/index.ts — must be the FIRST import line.\n * import './telemetry.js';\n * ```\n */\nexport async function bootstrapTelemetry(cfg: TelemetryConfig): Promise<TelemetryHandle> {\n const env = resolveEnv(cfg.env);\n const serviceVersion = resolveVersion(cfg.serviceVersion);\n const otlpEndpoint = resolveEndpoint(cfg.otlpEndpoint);\n const sampleRatio = resolveSampling(cfg.sampleRatio, env);\n\n // Pino logger with trace/span correlation + redaction.\n // createPinoLogger is async (loads pino via dynamic import); awaiting it\n // is required — without await, `logger` is a Promise and calls like\n // logger.warn(...) crash with \"logger.warn is not a function\" during the\n // sdk-node fallback path.\n const { createPinoLogger } = await import('./pino-logger.js');\n const logger = await createPinoLogger({\n serviceName: cfg.serviceName,\n env,\n version: serviceVersion,\n });\n setActiveTelemetryLogger(logger);\n\n // Initialize core instrumentation (tracer, metrics registry, envelop plugins).\n // `setupInstrumentation` internally calls `initializeInstrumentation`.\n const instrumentation = setupInstrumentation(cfg.serviceName, {\n ...cfg.instrumentation,\n tracing: {\n serviceName: cfg.serviceName,\n ...(cfg.instrumentation?.tracing ?? {}),\n samplingRate: sampleRatio,\n },\n metrics: {\n serviceName: cfg.serviceName,\n ...(cfg.instrumentation?.metrics ?? {}),\n },\n });\n\n // Start the NodeSDK exporter pipeline if sdk-node is present (optional).\n let otelSdk: OtelSdkHandle | undefined;\n if (resolveOtelSdkEnabled()) {\n try {\n const { createOtelSdk } = await import('./sdk.js');\n otelSdk = await createOtelSdk({\n serviceName: cfg.serviceName,\n serviceVersion,\n boundary: cfg.boundary,\n module: cfg.module,\n env,\n otlpEndpoint,\n sampleRatio,\n });\n // Explicit success log includes metrics path status so an operator can\n // distinguish traces-only startup from full traces+metrics startup.\n logger.info('[telemetry] OpenTelemetry exporter pipeline started', {\n serviceName: cfg.serviceName,\n otlpEndpoint: otlpEndpoint ? '<configured>' : '<not set>',\n sampleRatio,\n metricsEnabled: otelSdk.metricsEnabled,\n });\n\n if (!otelSdk.metricsEnabled && otelSdk.metricsDropReason) {\n logger.warn('[telemetry] OpenTelemetry metrics reader disabled; continuing with traces only', {\n serviceName: cfg.serviceName,\n reason: otelSdk.metricsDropReason,\n });\n }\n } catch (err) {\n logger.warn('[telemetry] OpenTelemetry exporter pipeline failed to start; continuing with logs only', {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n } else {\n logger.info('[telemetry] OTel SDK exporter disabled by env');\n }\n\n const shutdown = async (): Promise<void> => {\n try {\n if (otelSdk?.shutdown) await otelSdk.shutdown();\n } catch (err) {\n (logger as unknown as BaseLogger).warn('[telemetry] shutdown error (ignored)', {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n };\n\n // Mirror defaultLogger so services that still use the singleton get trace-enriched output.\n defaultLogger.setLevel(logger.getLevel?.() ?? 'info');\n\n return {\n serviceName: cfg.serviceName,\n serviceVersion,\n env,\n logger: logger as unknown as BaseLogger,\n instrumentation,\n shutdown,\n };\n}\n\n// Re-export what services typically import.\nexport { initializeInstrumentation, setupInstrumentation };\n"]}
|
package/dist/tracker/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { TrackerModule, UNIFIED_TRACKER_CONSTANTS, UnifiedTrackerStub, UsageMetricType, createProductTracker, trackOperation, trackerStub } from '../chunk-
|
|
2
|
-
import '../chunk-RMDKB5O7.js';
|
|
1
|
+
export { TrackerModule, UNIFIED_TRACKER_CONSTANTS, UnifiedTrackerStub, UsageMetricType, createProductTracker, trackOperation, trackerStub } from '../chunk-5FJZI7VX.js';
|
|
3
2
|
import '../chunk-O2MEBPDT.js';
|
|
3
|
+
import '../chunk-RMDKB5O7.js';
|
|
4
4
|
import '../chunk-O6RHB2YP.js';
|
|
5
5
|
import '../chunk-HP6JTFNR.js';
|
|
6
6
|
import '../chunk-CBZNP6RF.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@burdenoff/be-sdk",
|
|
3
|
-
"version": "2026.518.
|
|
3
|
+
"version": "2026.518.3",
|
|
4
4
|
"description": "Backend SDK for Burdenoff products providing unified access to notifications, RBAC, activity tracking, usage monitoring, and more",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -67,8 +67,8 @@
|
|
|
67
67
|
"deps:status": "bun scripts/deps-mode.ts status",
|
|
68
68
|
"deps:workspace": "bun scripts/deps-mode.ts workspace",
|
|
69
69
|
"dev": "tsx watch ./src/index.ts",
|
|
70
|
-
"build": "tsup src/index.ts src/init/index.ts src/logger/index.ts src/cache/index.ts src/database/index.ts src/event-queue/index.ts src/graph/index.ts src/middleware/index.ts src/observability/index.ts src/graphql/index.ts src/graphql/services/index.ts src/prisma/index.ts src/utils/index.ts src/notifications/index.ts src/tracker/index.ts src/export/index.ts src/dataloader/index.ts src/prisma/generator/index.ts src/server/index.ts src/i18n/index.ts src/instrumentation/index.ts src/rbac/index.ts src/temporal/index.ts src/client/internal-client.ts src/layer/index.ts src/gateway/index.ts src/gateway/security/index.ts src/crypto/index.ts src/feature-flags/index.ts src/telemetry/index.ts src/auth/index.ts src/captcha/index.ts --format esm --dts --clean --shims",
|
|
71
|
-
"build:watch": "tsup src/index.ts src/init/index.ts src/logger/index.ts src/cache/index.ts src/database/index.ts src/event-queue/index.ts src/graph/index.ts src/middleware/index.ts src/observability/index.ts src/graphql/index.ts src/graphql/services/index.ts src/prisma/index.ts src/utils/index.ts src/notifications/index.ts src/tracker/index.ts src/export/index.ts src/dataloader/index.ts src/prisma/generator/index.ts src/server/index.ts src/i18n/index.ts src/instrumentation/index.ts src/rbac/index.ts src/temporal/index.ts src/client/internal-client.ts src/layer/index.ts src/gateway/index.ts src/gateway/security/index.ts src/crypto/index.ts src/feature-flags/index.ts src/telemetry/index.ts src/auth/index.ts src/captcha/index.ts --format esm --dts --watch --shims",
|
|
70
|
+
"build": "tsup src/index.ts src/init/index.ts src/logger/index.ts src/cache/index.ts src/database/index.ts src/event-queue/index.ts src/graph/index.ts src/middleware/index.ts src/observability/index.ts src/graphql/index.ts src/graphql/services/index.ts src/prisma/index.ts src/utils/index.ts src/notifications/index.ts src/tracker/index.ts src/export/index.ts src/dataloader/index.ts src/prisma/generator/index.ts src/server/index.ts src/i18n/index.ts src/instrumentation/index.ts src/rbac/index.ts src/temporal/index.ts src/client/internal-client.ts src/layer/index.ts src/gateway/index.ts src/gateway/security/index.ts src/crypto/index.ts src/feature-flags/index.ts src/telemetry/index.ts src/auth/index.ts src/captcha/index.ts src/metrics/index.ts --format esm --dts --clean --shims",
|
|
71
|
+
"build:watch": "tsup src/index.ts src/init/index.ts src/logger/index.ts src/cache/index.ts src/database/index.ts src/event-queue/index.ts src/graph/index.ts src/middleware/index.ts src/observability/index.ts src/graphql/index.ts src/graphql/services/index.ts src/prisma/index.ts src/utils/index.ts src/notifications/index.ts src/tracker/index.ts src/export/index.ts src/dataloader/index.ts src/prisma/generator/index.ts src/server/index.ts src/i18n/index.ts src/instrumentation/index.ts src/rbac/index.ts src/temporal/index.ts src/client/internal-client.ts src/layer/index.ts src/gateway/index.ts src/gateway/security/index.ts src/crypto/index.ts src/feature-flags/index.ts src/telemetry/index.ts src/auth/index.ts src/captcha/index.ts src/metrics/index.ts --format esm --dts --watch --shims",
|
|
72
72
|
"typecheck": "tsc --noEmit",
|
|
73
73
|
"lint": "eslint ./src",
|
|
74
74
|
"lint:sanity": "if [ \"${CI:-}\" = \"true\" ]; then bun run lint; else bun run lint -- --cache --cache-location .eslintcache; fi",
|