autotel-tanstack 1.13.24 → 1.13.26

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/auto.d.ts CHANGED
@@ -1,46 +1,42 @@
1
+ export { i as instrument } from './instrument-DRR7VL63.js';
1
2
  export { functionTracingMiddleware, tracingMiddleware } from './middleware.js';
2
3
  export { traceServerFn } from './server-functions.js';
3
4
  export { traceBeforeLoad, traceLoader } from './loaders.js';
5
+ import 'autotel';
4
6
  import './types-m5OjZJ-4.js';
5
7
  import '@opentelemetry/api';
6
8
  import '@tanstack/react-router';
7
9
 
8
10
  /**
9
- * Zero-config auto-instrumentation for TanStack Start
11
+ * Zero-config auto-instrumentation for TanStack Start.
10
12
  *
11
- * Import this module to automatically instrument TanStack Start applications
12
- * with OpenTelemetry tracing. Configuration is read from environment variables.
13
+ * Importing this module configures OpenTelemetry tracing from environment
14
+ * variables it is simply `instrument()` with no options. For subscribers,
15
+ * structured logs, canonical log lines, or an explicit endpoint, call
16
+ * `instrument(options)` from `autotel-tanstack` directly (see ./instrument).
13
17
  *
14
- * Environment Variables:
18
+ * Environment Variables (resolved by autotel core):
15
19
  * - OTEL_SERVICE_NAME: Service name (default: 'tanstack-start')
16
20
  * - OTEL_EXPORTER_OTLP_ENDPOINT: OTLP collector URL
17
- * - OTEL_EXPORTER_OTLP_HEADERS: Authentication headers (key=value,key=value)
18
- * - AUTOTEL_DEBUG: Set to 'true' or 'pretty' to log spans to the server console
21
+ * - OTEL_EXPORTER_OTLP_HEADERS: Auth headers (key=value,key=value)
22
+ * - AUTOTEL_DEBUG: 'true' | 'pretty' to log spans to the server console
19
23
  *
20
24
  * @example
21
25
  * ```typescript
22
26
  * // app/start.ts
23
27
  * import 'autotel-tanstack/auto';
24
28
  * import { createStart } from '@tanstack/react-start';
25
- *
26
- * // Tracing is automatically configured!
27
29
  * export const startInstance = createStart(() => ({}));
28
30
  * ```
29
31
  *
30
32
  * @module
31
33
  */
32
34
 
33
- /**
34
- * Check if auto-instrumentation is active
35
- */
35
+ /** Check if auto-instrumentation is active. */
36
36
  declare function isAutoInstrumentationActive(): boolean;
37
- /**
38
- * Get the configured service name
39
- */
37
+ /** The configured service name. */
40
38
  declare function getServiceName(): string;
41
- /**
42
- * Get the configured endpoint
43
- */
39
+ /** The configured OTLP endpoint, if any. */
44
40
  declare function getEndpoint(): string | undefined;
45
41
 
46
42
  export { getEndpoint, getServiceName, isAutoInstrumentationActive };
package/dist/auto.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { instrument } from './chunk-7OXOAS64.js';
2
+ export { instrument } from './chunk-7OXOAS64.js';
1
3
  export { functionTracingMiddleware, tracingMiddleware } from './chunk-LRA2UVVS.js';
2
4
  export { traceServerFn } from './chunk-ESU66L3L.js';
3
5
  export { traceBeforeLoad, traceLoader } from './chunk-KPXGFKPU.js';
@@ -6,62 +8,23 @@ import './chunk-CCME55EK.js';
6
8
  import './chunk-I4LX3LOG.js';
7
9
  import './chunk-NTY64BKS.js';
8
10
  import './chunk-EGRHWZRV.js';
9
- import { init } from 'autotel';
10
- import { InMemorySpanExporter } from 'autotel/exporters';
11
- import { SimpleSpanProcessor } from 'autotel/processors';
12
11
 
13
- var service = process.env.OTEL_SERVICE_NAME || "tanstack-start";
14
- var endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
15
- var headers;
16
- if (process.env.OTEL_EXPORTER_OTLP_HEADERS) {
17
- headers = {};
18
- const pairs = process.env.OTEL_EXPORTER_OTLP_HEADERS.split(",");
19
- for (const pair of pairs) {
20
- const [key, value] = pair.split("=");
21
- if (key && value) {
22
- headers[key.trim()] = value.trim();
23
- }
24
- }
25
- }
26
- function resolveDebug() {
27
- const env = process.env.AUTOTEL_DEBUG;
28
- if (env === "pretty") return "pretty";
29
- if (env === "true" || env === "1") return true;
30
- if (env === "false" || env === "0") return false;
31
- if (!endpoint && process.env.NODE_ENV === "development") return "pretty";
32
- return false;
33
- }
34
- if (process.env.E2E === "1") {
35
- const e2eExporter = new InMemorySpanExporter();
36
- const e2eProcessor = new SimpleSpanProcessor(e2eExporter);
37
- globalThis.__testSpanExporter = e2eExporter;
38
- init({
39
- service,
40
- spanProcessors: [e2eProcessor]
41
- });
42
- } else {
43
- init({
44
- service,
45
- endpoint,
46
- headers,
47
- debug: resolveDebug()
48
- });
49
- }
12
+ // src/auto.ts
13
+ instrument();
50
14
  if (process.env.NODE_ENV === "development" || process.env.AUTOTEL_DEBUG) {
51
- console.log("[autotel-tanstack] Auto-initialized with:", {
52
- service,
53
- endpoint: process.env.E2E === "1" ? "(E2E: in-memory)" : endpoint || "(not configured)",
54
- hasHeaders: !!headers
15
+ console.log("[autotel-tanstack] Auto-initialized", {
16
+ service: process.env.OTEL_SERVICE_NAME || "tanstack-start",
17
+ endpoint: process.env.E2E === "1" ? "(E2E: in-memory)" : process.env.OTEL_EXPORTER_OTLP_ENDPOINT || "(not configured)"
55
18
  });
56
19
  }
57
20
  function isAutoInstrumentationActive() {
58
21
  return true;
59
22
  }
60
23
  function getServiceName() {
61
- return service;
24
+ return process.env.OTEL_SERVICE_NAME || "tanstack-start";
62
25
  }
63
26
  function getEndpoint() {
64
- return endpoint;
27
+ return process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
65
28
  }
66
29
 
67
30
  export { getEndpoint, getServiceName, isAutoInstrumentationActive };
package/dist/auto.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/auto.ts"],"names":[],"mappings":";;;;;;;;;;;;AA8BA,IAAM,OAAA,GAAU,OAAA,CAAQ,GAAA,CAAI,iBAAA,IAAqB,gBAAA;AAGjD,IAAM,QAAA,GAAW,QAAQ,GAAA,CAAI,2BAAA;AAG7B,IAAI,OAAA;AACJ,IAAI,OAAA,CAAQ,IAAI,0BAAA,EAA4B;AAC1C,EAAA,OAAA,GAAU,EAAC;AACX,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,GAAA,CAAI,0BAAA,CAA2B,MAAM,GAAG,CAAA;AAC9D,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,IAAA,MAAM,CAAC,GAAA,EAAK,KAAK,CAAA,GAAI,IAAA,CAAK,MAAM,GAAG,CAAA;AACnC,IAAA,IAAI,OAAO,KAAA,EAAO;AAChB,MAAA,OAAA,CAAQ,GAAA,CAAI,IAAA,EAAM,CAAA,GAAI,MAAM,IAAA,EAAK;AAAA,IACnC;AAAA,EACF;AACF;AAIA,SAAS,YAAA,GAAmC;AAC1C,EAAA,MAAM,GAAA,GAAM,QAAQ,GAAA,CAAI,aAAA;AACxB,EAAA,IAAI,GAAA,KAAQ,UAAU,OAAO,QAAA;AAC7B,EAAA,IAAI,GAAA,KAAQ,MAAA,IAAU,GAAA,KAAQ,GAAA,EAAK,OAAO,IAAA;AAC1C,EAAA,IAAI,GAAA,KAAQ,OAAA,IAAW,GAAA,KAAQ,GAAA,EAAK,OAAO,KAAA;AAC3C,EAAA,IAAI,CAAC,QAAA,IAAY,OAAA,CAAQ,GAAA,CAAI,QAAA,KAAa,eAAe,OAAO,QAAA;AAChE,EAAA,OAAO,KAAA;AACT;AAMA,IAAI,OAAA,CAAQ,GAAA,CAAI,GAAA,KAAQ,GAAA,EAAK;AAC3B,EAAA,MAAM,WAAA,GAAc,IAAI,oBAAA,EAAqB;AAC7C,EAAA,MAAM,YAAA,GAAe,IAAI,mBAAA,CAAoB,WAAW,CAAA;AACxD,EAAC,WAAuC,kBAAA,GAAqB,WAAA;AAE7D,EAAA,IAAA,CAAK;AAAA,IACH,OAAA;AAAA,IACA,cAAA,EAAgB,CAAC,YAAY;AAAA,GAC9B,CAAA;AACH,CAAA,MAAO;AAEL,EAAA,IAAA,CAAK;AAAA,IACH,OAAA;AAAA,IACA,QAAA;AAAA,IACA,OAAA;AAAA,IACA,OAAO,YAAA;AAAa,GACrB,CAAA;AACH;AAGA,IAAI,QAAQ,GAAA,CAAI,QAAA,KAAa,aAAA,IAAiB,OAAA,CAAQ,IAAI,aAAA,EAAe;AACvE,EAAA,OAAA,CAAQ,IAAI,2CAAA,EAA6C;AAAA,IACvD,OAAA;AAAA,IACA,UACE,OAAA,CAAQ,GAAA,CAAI,GAAA,KAAQ,GAAA,GAChB,qBACA,QAAA,IAAY,kBAAA;AAAA,IAClB,UAAA,EAAY,CAAC,CAAC;AAAA,GACf,CAAA;AACH;AAUO,SAAS,2BAAA,GAAuC;AACrD,EAAA,OAAO,IAAA;AACT;AAKO,SAAS,cAAA,GAAyB;AACvC,EAAA,OAAO,OAAA;AACT;AAKO,SAAS,WAAA,GAAkC;AAChD,EAAA,OAAO,QAAA;AACT","file":"auto.js","sourcesContent":["/**\n * Zero-config auto-instrumentation for TanStack Start\n *\n * Import this module to automatically instrument TanStack Start applications\n * with OpenTelemetry tracing. Configuration is read from environment variables.\n *\n * Environment Variables:\n * - OTEL_SERVICE_NAME: Service name (default: 'tanstack-start')\n * - OTEL_EXPORTER_OTLP_ENDPOINT: OTLP collector URL\n * - OTEL_EXPORTER_OTLP_HEADERS: Authentication headers (key=value,key=value)\n * - AUTOTEL_DEBUG: Set to 'true' or 'pretty' to log spans to the server console\n *\n * @example\n * ```typescript\n * // app/start.ts\n * import 'autotel-tanstack/auto';\n * import { createStart } from '@tanstack/react-start';\n *\n * // Tracing is automatically configured!\n * export const startInstance = createStart(() => ({}));\n * ```\n *\n * @module\n */\n\nimport { init } from 'autotel';\nimport { InMemorySpanExporter } from 'autotel/exporters';\nimport { SimpleSpanProcessor } from 'autotel/processors';\n\n// Parse service name\nconst service = process.env.OTEL_SERVICE_NAME || 'tanstack-start';\n\n// Parse endpoint\nconst endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT;\n\n// Parse headers\nlet headers: Record<string, string> | undefined;\nif (process.env.OTEL_EXPORTER_OTLP_HEADERS) {\n headers = {};\n const pairs = process.env.OTEL_EXPORTER_OTLP_HEADERS.split(',');\n for (const pair of pairs) {\n const [key, value] = pair.split('=');\n if (key && value) {\n headers[key.trim()] = value.trim();\n }\n }\n}\n\n// Debug: span output to server console. AUTOTEL_DEBUG=pretty | true, or default\n// to pretty in dev when no OTLP endpoint is set so you see spans immediately.\nfunction resolveDebug(): boolean | 'pretty' {\n const env = process.env.AUTOTEL_DEBUG;\n if (env === 'pretty') return 'pretty';\n if (env === 'true' || env === '1') return true;\n if (env === 'false' || env === '0') return false;\n if (!endpoint && process.env.NODE_ENV === 'development') return 'pretty';\n return false;\n}\n\n// E2E mode: use InMemorySpanExporter so tests can capture and assert on spans.\n// When E2E=1, skip the normal OTLP path and use in-memory storage instead.\n// Note: combined E2E + OTLP (two processors) is handled at integration level\n// because constructing an OTLP processor requires deps not available here.\nif (process.env.E2E === '1') {\n const e2eExporter = new InMemorySpanExporter();\n const e2eProcessor = new SimpleSpanProcessor(e2eExporter);\n (globalThis as Record<string, unknown>).__testSpanExporter = e2eExporter;\n\n init({\n service,\n spanProcessors: [e2eProcessor],\n });\n} else {\n // Initialize autotel (production path — unchanged)\n init({\n service,\n endpoint,\n headers,\n debug: resolveDebug(),\n });\n}\n\n// Log initialization (only in development)\nif (process.env.NODE_ENV === 'development' || process.env.AUTOTEL_DEBUG) {\n console.log('[autotel-tanstack] Auto-initialized with:', {\n service,\n endpoint:\n process.env.E2E === '1'\n ? '(E2E: in-memory)'\n : endpoint || '(not configured)',\n hasHeaders: !!headers,\n });\n}\n\n// Re-export middleware for convenience\nexport { tracingMiddleware, functionTracingMiddleware } from './middleware';\nexport { traceServerFn } from './server-functions';\nexport { traceLoader, traceBeforeLoad } from './loaders';\n\n/**\n * Check if auto-instrumentation is active\n */\nexport function isAutoInstrumentationActive(): boolean {\n return true;\n}\n\n/**\n * Get the configured service name\n */\nexport function getServiceName(): string {\n return service;\n}\n\n/**\n * Get the configured endpoint\n */\nexport function getEndpoint(): string | undefined {\n return endpoint;\n}\n"]}
1
+ {"version":3,"sources":["../src/auto.ts"],"names":[],"mappings":";;;;;;;;;;;;AA2BA,UAAA,EAAW;AAGX,IAAI,QAAQ,GAAA,CAAI,QAAA,KAAa,aAAA,IAAiB,OAAA,CAAQ,IAAI,aAAA,EAAe;AACvE,EAAA,OAAA,CAAQ,IAAI,qCAAA,EAAuC;AAAA,IACjD,OAAA,EAAS,OAAA,CAAQ,GAAA,CAAI,iBAAA,IAAqB,gBAAA;AAAA,IAC1C,QAAA,EACE,QAAQ,GAAA,CAAI,GAAA,KAAQ,MAChB,kBAAA,GACA,OAAA,CAAQ,IAAI,2BAAA,IAA+B;AAAA,GAClD,CAAA;AACH;AASO,SAAS,2BAAA,GAAuC;AACrD,EAAA,OAAO,IAAA;AACT;AAGO,SAAS,cAAA,GAAyB;AACvC,EAAA,OAAO,OAAA,CAAQ,IAAI,iBAAA,IAAqB,gBAAA;AAC1C;AAGO,SAAS,WAAA,GAAkC;AAChD,EAAA,OAAO,QAAQ,GAAA,CAAI,2BAAA;AACrB","file":"auto.js","sourcesContent":["/**\n * Zero-config auto-instrumentation for TanStack Start.\n *\n * Importing this module configures OpenTelemetry tracing from environment\n * variables — it is simply `instrument()` with no options. For subscribers,\n * structured logs, canonical log lines, or an explicit endpoint, call\n * `instrument(options)` from `autotel-tanstack` directly (see ./instrument).\n *\n * Environment Variables (resolved by autotel core):\n * - OTEL_SERVICE_NAME: Service name (default: 'tanstack-start')\n * - OTEL_EXPORTER_OTLP_ENDPOINT: OTLP collector URL\n * - OTEL_EXPORTER_OTLP_HEADERS: Auth headers (key=value,key=value)\n * - AUTOTEL_DEBUG: 'true' | 'pretty' to log spans to the server console\n *\n * @example\n * ```typescript\n * // app/start.ts\n * import 'autotel-tanstack/auto';\n * import { createStart } from '@tanstack/react-start';\n * export const startInstance = createStart(() => ({}));\n * ```\n *\n * @module\n */\n\nimport { instrument } from './instrument';\n\ninstrument();\n\n// Surface what happened, in development only.\nif (process.env.NODE_ENV === 'development' || process.env.AUTOTEL_DEBUG) {\n console.log('[autotel-tanstack] Auto-initialized', {\n service: process.env.OTEL_SERVICE_NAME || 'tanstack-start',\n endpoint:\n process.env.E2E === '1'\n ? '(E2E: in-memory)'\n : process.env.OTEL_EXPORTER_OTLP_ENDPOINT || '(not configured)',\n });\n}\n\n// Re-export the configurable form + middleware/helpers for convenience.\nexport { instrument } from './instrument';\nexport { tracingMiddleware, functionTracingMiddleware } from './middleware';\nexport { traceServerFn } from './server-functions';\nexport { traceLoader, traceBeforeLoad } from './loaders';\n\n/** Check if auto-instrumentation is active. */\nexport function isAutoInstrumentationActive(): boolean {\n return true;\n}\n\n/** The configured service name. */\nexport function getServiceName(): string {\n return process.env.OTEL_SERVICE_NAME || 'tanstack-start';\n}\n\n/** The configured OTLP endpoint, if any. */\nexport function getEndpoint(): string | undefined {\n return process.env.OTEL_EXPORTER_OTLP_ENDPOINT;\n}\n"]}
@@ -0,0 +1,41 @@
1
+ import { isInitialized, init } from 'autotel';
2
+ import { InMemorySpanExporter } from 'autotel/exporters';
3
+ import { SimpleSpanProcessor } from 'autotel/processors';
4
+
5
+ // src/instrument.ts
6
+ var DEFAULT_SERVICE = "tanstack-start";
7
+ function resolveDebug(explicit, endpoint) {
8
+ if (explicit !== void 0) return explicit;
9
+ const env = process.env.AUTOTEL_DEBUG;
10
+ if (env === "pretty") return "pretty";
11
+ if (env === "true" || env === "1") return true;
12
+ if (env === "false" || env === "0") return false;
13
+ if (!endpoint && process.env.NODE_ENV === "development") return "pretty";
14
+ return false;
15
+ }
16
+ function instrument(options = {}) {
17
+ if (isInitialized()) return;
18
+ const service = options.service ?? process.env.OTEL_SERVICE_NAME ?? DEFAULT_SERVICE;
19
+ if (process.env.E2E === "1") {
20
+ const exporter = new InMemorySpanExporter();
21
+ globalThis.__testSpanExporter = exporter;
22
+ init({
23
+ service,
24
+ subscribers: options.subscribers,
25
+ spanProcessors: [
26
+ new SimpleSpanProcessor(exporter),
27
+ ...options.spanProcessors ?? []
28
+ ]
29
+ });
30
+ return;
31
+ }
32
+ init({
33
+ ...options,
34
+ service,
35
+ debug: resolveDebug(options.debug, options.endpoint)
36
+ });
37
+ }
38
+
39
+ export { instrument };
40
+ //# sourceMappingURL=chunk-7OXOAS64.js.map
41
+ //# sourceMappingURL=chunk-7OXOAS64.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/instrument.ts"],"names":[],"mappings":";;;;;AAgDA,IAAM,eAAA,GAAkB,gBAAA;AAOxB,SAAS,YAAA,CACP,UACA,QAAA,EACoB;AACpB,EAAA,IAAI,QAAA,KAAa,QAAW,OAAO,QAAA;AACnC,EAAA,MAAM,GAAA,GAAM,QAAQ,GAAA,CAAI,aAAA;AACxB,EAAA,IAAI,GAAA,KAAQ,UAAU,OAAO,QAAA;AAC7B,EAAA,IAAI,GAAA,KAAQ,MAAA,IAAU,GAAA,KAAQ,GAAA,EAAK,OAAO,IAAA;AAC1C,EAAA,IAAI,GAAA,KAAQ,OAAA,IAAW,GAAA,KAAQ,GAAA,EAAK,OAAO,KAAA;AAC3C,EAAA,IAAI,CAAC,QAAA,IAAY,OAAA,CAAQ,GAAA,CAAI,QAAA,KAAa,eAAe,OAAO,QAAA;AAChE,EAAA,OAAO,KAAA;AACT;AAEO,SAAS,UAAA,CAAW,OAAA,GAA6B,EAAC,EAAS;AAGhE,EAAA,IAAI,eAAc,EAAG;AAErB,EAAA,MAAM,OAAA,GACJ,OAAA,CAAQ,OAAA,IAAW,OAAA,CAAQ,IAAI,iBAAA,IAAqB,eAAA;AAEtD,EAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,GAAA,KAAQ,GAAA,EAAK;AAE3B,IAAA,MAAM,QAAA,GAAW,IAAI,oBAAA,EAAqB;AAC1C,IAAC,WAAuC,kBAAA,GAAqB,QAAA;AAC7D,IAAA,IAAA,CAAK;AAAA,MACH,OAAA;AAAA,MACA,aAAa,OAAA,CAAQ,WAAA;AAAA,MACrB,cAAA,EAAgB;AAAA,QACd,IAAI,oBAAoB,QAAQ,CAAA;AAAA,QAChC,GAAI,OAAA,CAAQ,cAAA,IAAkB;AAAC;AACjC,KACD,CAAA;AACD,IAAA;AAAA,EACF;AAEA,EAAA,IAAA,CAAK;AAAA,IACH,GAAG,OAAA;AAAA,IACH,OAAA;AAAA,IACA,KAAA,EAAO,YAAA,CAAa,OAAA,CAAQ,KAAA,EAAO,QAAQ,QAAQ;AAAA,GACpD,CAAA;AACH","file":"chunk-7OXOAS64.js","sourcesContent":["/**\n * Configurable tracing setup for TanStack Start.\n *\n * `instrument(options)` is a thin wrapper over autotel's `init` that adds the\n * TanStack defaults so apps don't hand-roll them:\n *\n * - service name defaults to `OTEL_SERVICE_NAME` or `'tanstack-start'`;\n * - `debug` resolves from `AUTOTEL_DEBUG` (`pretty` in dev when no endpoint set);\n * - when `E2E=1`, spans are captured by an `InMemorySpanExporter` exposed as\n * `globalThis.__testSpanExporter` (for span assertions) instead of shipping\n * over OTLP;\n * - it's idempotent — a second call is a no-op.\n *\n * Everything else — `endpoint`, `headers`, `subscribers`, `logs`,\n * `canonicalLogLines`, extra `spanProcessors`, … — passes straight through to\n * `init`, and the standard `OTEL_*` env vars are resolved by autotel core, so\n * apps never re-parse them.\n *\n * The zero-config `autotel-tanstack/auto` side-effect module is just\n * `instrument()` with no options.\n *\n * @example\n * ```ts\n * import { instrument } from 'autotel-tanstack';\n * import { PostHogSubscriber } from 'autotel-subscribers';\n *\n * instrument({\n * subscribers: process.env.POSTHOG_KEY\n * ? [new PostHogSubscriber({ apiKey: process.env.POSTHOG_KEY })]\n * : [],\n * logs: true,\n * canonicalLogLines: { enabled: true, rootSpansOnly: true },\n * });\n * ```\n *\n * @module\n */\n\nimport { init, isInitialized, type AutotelConfig } from 'autotel';\nimport { InMemorySpanExporter } from 'autotel/exporters';\nimport { SimpleSpanProcessor } from 'autotel/processors';\n\n// `service` is optional here — instrument() defaults it to OTEL_SERVICE_NAME or\n// 'tanstack-start'. Everything else matches autotel's init config.\nexport type InstrumentOptions = Omit<AutotelConfig, 'service'> & {\n service?: string;\n};\n\nconst DEFAULT_SERVICE = 'tanstack-start';\n\n/**\n * Resolve span-debug output: an explicit option wins; otherwise `AUTOTEL_DEBUG`\n * (`pretty` | `true`/`1` | `false`/`0`); otherwise pretty-print in development\n * when there's no OTLP endpoint, so spans are visible immediately.\n */\nfunction resolveDebug(\n explicit: AutotelConfig['debug'],\n endpoint: string | undefined,\n): boolean | 'pretty' {\n if (explicit !== undefined) return explicit;\n const env = process.env.AUTOTEL_DEBUG;\n if (env === 'pretty') return 'pretty';\n if (env === 'true' || env === '1') return true;\n if (env === 'false' || env === '0') return false;\n if (!endpoint && process.env.NODE_ENV === 'development') return 'pretty';\n return false;\n}\n\nexport function instrument(options: InstrumentOptions = {}): void {\n // Idempotent: tolerate the instrumentation module being evaluated more than\n // once (HMR, multiple entry points) without re-initializing.\n if (isInitialized()) return;\n\n const service =\n options.service ?? process.env.OTEL_SERVICE_NAME ?? DEFAULT_SERVICE;\n\n if (process.env.E2E === '1') {\n // Capture spans in memory for test assertions; skip OTLP/logs entirely.\n const exporter = new InMemorySpanExporter();\n (globalThis as Record<string, unknown>).__testSpanExporter = exporter;\n init({\n service,\n subscribers: options.subscribers,\n spanProcessors: [\n new SimpleSpanProcessor(exporter),\n ...(options.spanProcessors ?? []),\n ],\n });\n return;\n }\n\n init({\n ...options,\n service,\n debug: resolveDebug(options.debug, options.endpoint),\n });\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -7,6 +7,7 @@ export { createTracedHeaders, extractContextFromRequest, getActiveContext, injec
7
7
  export { DebugHeadersConfig, debugHeadersMiddleware } from './debug-headers.js';
8
8
  export { TimingStats, createMetricsHandler, metricsCollector, recordTiming } from './metrics.js';
9
9
  export { ErrorReport, createErrorReportingHandler, errorStore, reportError, withErrorReporting } from './error-reporting.js';
10
+ export { I as InstrumentOptions, i as instrument } from './instrument-DRR7VL63.js';
10
11
  export { flush, init, shutdown, span, trace } from 'autotel';
11
12
  import '@opentelemetry/api';
12
13
  import '@tanstack/react-router';
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  export { debugHeadersMiddleware } from './chunk-UTPW3QRT.js';
2
2
  export { createMetricsHandler, metricsCollector, recordTiming } from './chunk-G526TOMY.js';
3
3
  export { createErrorReportingHandler, errorStore, reportError, withErrorReporting } from './chunk-XXBHZR3M.js';
4
+ export { instrument } from './chunk-7OXOAS64.js';
4
5
  export { createTracingMiddleware, createTracingServerHandler, functionTracingMiddleware, tracingMiddleware } from './chunk-LRA2UVVS.js';
5
6
  export { createTracedServerFnFactory, traceServerFn } from './chunk-ESU66L3L.js';
6
7
  export { createTracedRoute, traceBeforeLoad, traceLoader } from './chunk-KPXGFKPU.js';
@@ -0,0 +1,46 @@
1
+ import { AutotelConfig } from 'autotel';
2
+
3
+ /**
4
+ * Configurable tracing setup for TanStack Start.
5
+ *
6
+ * `instrument(options)` is a thin wrapper over autotel's `init` that adds the
7
+ * TanStack defaults so apps don't hand-roll them:
8
+ *
9
+ * - service name defaults to `OTEL_SERVICE_NAME` or `'tanstack-start'`;
10
+ * - `debug` resolves from `AUTOTEL_DEBUG` (`pretty` in dev when no endpoint set);
11
+ * - when `E2E=1`, spans are captured by an `InMemorySpanExporter` exposed as
12
+ * `globalThis.__testSpanExporter` (for span assertions) instead of shipping
13
+ * over OTLP;
14
+ * - it's idempotent — a second call is a no-op.
15
+ *
16
+ * Everything else — `endpoint`, `headers`, `subscribers`, `logs`,
17
+ * `canonicalLogLines`, extra `spanProcessors`, … — passes straight through to
18
+ * `init`, and the standard `OTEL_*` env vars are resolved by autotel core, so
19
+ * apps never re-parse them.
20
+ *
21
+ * The zero-config `autotel-tanstack/auto` side-effect module is just
22
+ * `instrument()` with no options.
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * import { instrument } from 'autotel-tanstack';
27
+ * import { PostHogSubscriber } from 'autotel-subscribers';
28
+ *
29
+ * instrument({
30
+ * subscribers: process.env.POSTHOG_KEY
31
+ * ? [new PostHogSubscriber({ apiKey: process.env.POSTHOG_KEY })]
32
+ * : [],
33
+ * logs: true,
34
+ * canonicalLogLines: { enabled: true, rootSpansOnly: true },
35
+ * });
36
+ * ```
37
+ *
38
+ * @module
39
+ */
40
+
41
+ type InstrumentOptions = Omit<AutotelConfig, 'service'> & {
42
+ service?: string;
43
+ };
44
+ declare function instrument(options?: InstrumentOptions): void;
45
+
46
+ export { type InstrumentOptions as I, instrument as i };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autotel-tanstack",
3
- "version": "1.13.24",
3
+ "version": "1.13.26",
4
4
  "description": "OpenTelemetry instrumentation for TanStack Start - automatic tracing for server functions, middleware, and route loaders",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -120,8 +120,8 @@
120
120
  "license": "MIT",
121
121
  "dependencies": {
122
122
  "@opentelemetry/api": "^1.9.1",
123
- "autotel": "3.4.0",
124
- "autotel-adapters": "0.3.2",
123
+ "autotel": "3.4.2",
124
+ "autotel-adapters": "0.3.4",
125
125
  "autotel-edge": "3.16.12"
126
126
  },
127
127
  "peerDependencies": {
package/src/auto.test.ts CHANGED
@@ -7,6 +7,8 @@ const mockGetFinishedSpans = vi.fn(() => []);
7
7
 
8
8
  vi.mock('autotel', () => ({
9
9
  init: mockInit,
10
+ // instrument() guards on this; false so every test proceeds to init().
11
+ isInitialized: vi.fn(() => false),
10
12
  }));
11
13
 
12
14
  const mockExporterInstance = {
@@ -85,15 +87,20 @@ describe('auto.ts E2E mode', () => {
85
87
  expect(call.spanProcessors).toHaveLength(2);
86
88
  });
87
89
 
88
- it('passes endpoint and debug to init in production mode', async () => {
90
+ it('initializes in production mode without injecting an in-memory processor', async () => {
91
+ // The OTLP endpoint/headers are resolved by autotel core from env, so the
92
+ // zero-config path no longer passes them explicitly — it just inits.
89
93
  delete process.env.E2E;
90
94
  process.env.OTEL_EXPORTER_OTLP_ENDPOINT = 'http://localhost:4318';
91
95
  await import('./auto');
92
- expect(mockInit).toHaveBeenCalledWith(
93
- expect.objectContaining({
94
- endpoint: 'http://localhost:4318',
95
- }),
96
- );
96
+ expect(mockInit).toHaveBeenCalledOnce();
97
+ const call = mockInit.mock.calls[0][0] as {
98
+ spanProcessors?: unknown[];
99
+ service?: string;
100
+ };
101
+ expect(call.spanProcessors).toBeUndefined();
102
+ expect(call.service).toBe('tanstack-start');
103
+ expect(MockInMemorySpanExporter).not.toHaveBeenCalled();
97
104
  });
98
105
 
99
106
  it('uses OTEL_SERVICE_NAME env var', async () => {
package/src/auto.ts CHANGED
@@ -1,119 +1,60 @@
1
1
  /**
2
- * Zero-config auto-instrumentation for TanStack Start
2
+ * Zero-config auto-instrumentation for TanStack Start.
3
3
  *
4
- * Import this module to automatically instrument TanStack Start applications
5
- * with OpenTelemetry tracing. Configuration is read from environment variables.
4
+ * Importing this module configures OpenTelemetry tracing from environment
5
+ * variables it is simply `instrument()` with no options. For subscribers,
6
+ * structured logs, canonical log lines, or an explicit endpoint, call
7
+ * `instrument(options)` from `autotel-tanstack` directly (see ./instrument).
6
8
  *
7
- * Environment Variables:
9
+ * Environment Variables (resolved by autotel core):
8
10
  * - OTEL_SERVICE_NAME: Service name (default: 'tanstack-start')
9
11
  * - OTEL_EXPORTER_OTLP_ENDPOINT: OTLP collector URL
10
- * - OTEL_EXPORTER_OTLP_HEADERS: Authentication headers (key=value,key=value)
11
- * - AUTOTEL_DEBUG: Set to 'true' or 'pretty' to log spans to the server console
12
+ * - OTEL_EXPORTER_OTLP_HEADERS: Auth headers (key=value,key=value)
13
+ * - AUTOTEL_DEBUG: 'true' | 'pretty' to log spans to the server console
12
14
  *
13
15
  * @example
14
16
  * ```typescript
15
17
  * // app/start.ts
16
18
  * import 'autotel-tanstack/auto';
17
19
  * import { createStart } from '@tanstack/react-start';
18
- *
19
- * // Tracing is automatically configured!
20
20
  * export const startInstance = createStart(() => ({}));
21
21
  * ```
22
22
  *
23
23
  * @module
24
24
  */
25
25
 
26
- import { init } from 'autotel';
27
- import { InMemorySpanExporter } from 'autotel/exporters';
28
- import { SimpleSpanProcessor } from 'autotel/processors';
29
-
30
- // Parse service name
31
- const service = process.env.OTEL_SERVICE_NAME || 'tanstack-start';
26
+ import { instrument } from './instrument';
32
27
 
33
- // Parse endpoint
34
- const endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
28
+ instrument();
35
29
 
36
- // Parse headers
37
- let headers: Record<string, string> | undefined;
38
- if (process.env.OTEL_EXPORTER_OTLP_HEADERS) {
39
- headers = {};
40
- const pairs = process.env.OTEL_EXPORTER_OTLP_HEADERS.split(',');
41
- for (const pair of pairs) {
42
- const [key, value] = pair.split('=');
43
- if (key && value) {
44
- headers[key.trim()] = value.trim();
45
- }
46
- }
47
- }
48
-
49
- // Debug: span output to server console. AUTOTEL_DEBUG=pretty | true, or default
50
- // to pretty in dev when no OTLP endpoint is set so you see spans immediately.
51
- function resolveDebug(): boolean | 'pretty' {
52
- const env = process.env.AUTOTEL_DEBUG;
53
- if (env === 'pretty') return 'pretty';
54
- if (env === 'true' || env === '1') return true;
55
- if (env === 'false' || env === '0') return false;
56
- if (!endpoint && process.env.NODE_ENV === 'development') return 'pretty';
57
- return false;
58
- }
59
-
60
- // E2E mode: use InMemorySpanExporter so tests can capture and assert on spans.
61
- // When E2E=1, skip the normal OTLP path and use in-memory storage instead.
62
- // Note: combined E2E + OTLP (two processors) is handled at integration level
63
- // because constructing an OTLP processor requires deps not available here.
64
- if (process.env.E2E === '1') {
65
- const e2eExporter = new InMemorySpanExporter();
66
- const e2eProcessor = new SimpleSpanProcessor(e2eExporter);
67
- (globalThis as Record<string, unknown>).__testSpanExporter = e2eExporter;
68
-
69
- init({
70
- service,
71
- spanProcessors: [e2eProcessor],
72
- });
73
- } else {
74
- // Initialize autotel (production path — unchanged)
75
- init({
76
- service,
77
- endpoint,
78
- headers,
79
- debug: resolveDebug(),
80
- });
81
- }
82
-
83
- // Log initialization (only in development)
30
+ // Surface what happened, in development only.
84
31
  if (process.env.NODE_ENV === 'development' || process.env.AUTOTEL_DEBUG) {
85
- console.log('[autotel-tanstack] Auto-initialized with:', {
86
- service,
32
+ console.log('[autotel-tanstack] Auto-initialized', {
33
+ service: process.env.OTEL_SERVICE_NAME || 'tanstack-start',
87
34
  endpoint:
88
35
  process.env.E2E === '1'
89
36
  ? '(E2E: in-memory)'
90
- : endpoint || '(not configured)',
91
- hasHeaders: !!headers,
37
+ : process.env.OTEL_EXPORTER_OTLP_ENDPOINT || '(not configured)',
92
38
  });
93
39
  }
94
40
 
95
- // Re-export middleware for convenience
41
+ // Re-export the configurable form + middleware/helpers for convenience.
42
+ export { instrument } from './instrument';
96
43
  export { tracingMiddleware, functionTracingMiddleware } from './middleware';
97
44
  export { traceServerFn } from './server-functions';
98
45
  export { traceLoader, traceBeforeLoad } from './loaders';
99
46
 
100
- /**
101
- * Check if auto-instrumentation is active
102
- */
47
+ /** Check if auto-instrumentation is active. */
103
48
  export function isAutoInstrumentationActive(): boolean {
104
49
  return true;
105
50
  }
106
51
 
107
- /**
108
- * Get the configured service name
109
- */
52
+ /** The configured service name. */
110
53
  export function getServiceName(): string {
111
- return service;
54
+ return process.env.OTEL_SERVICE_NAME || 'tanstack-start';
112
55
  }
113
56
 
114
- /**
115
- * Get the configured endpoint
116
- */
57
+ /** The configured OTLP endpoint, if any. */
117
58
  export function getEndpoint(): string | undefined {
118
- return endpoint;
59
+ return process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
119
60
  }
package/src/index.ts CHANGED
@@ -84,6 +84,10 @@ export {
84
84
  type ErrorReport,
85
85
  } from './error-reporting';
86
86
 
87
+ // Configurable TanStack Start tracing setup (the configurable form of the
88
+ // zero-config `autotel-tanstack/auto` import).
89
+ export { instrument, type InstrumentOptions } from './instrument';
90
+
87
91
  // Re-export autotel core utilities for convenience
88
92
  // Note: These should only be used on the server side
89
93
  // They use Node.js APIs (AsyncLocalStorage) that don't exist in the browser
@@ -0,0 +1,131 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+
3
+ // Hoisted so the values exist when the (also-hoisted) vi.mock factories run,
4
+ // since instrument is imported statically below.
5
+ const {
6
+ mockInit,
7
+ mockIsInitialized,
8
+ mockExporter,
9
+ MockInMemorySpanExporter,
10
+ MockSimpleSpanProcessor,
11
+ } = vi.hoisted(() => {
12
+ const exporter = { reset: vi.fn(), getFinishedSpans: vi.fn(() => []) };
13
+ return {
14
+ mockInit: vi.fn(),
15
+ mockIsInitialized: vi.fn(() => false),
16
+ mockExporter: exporter,
17
+ MockInMemorySpanExporter: vi.fn(function () {
18
+ return exporter;
19
+ }),
20
+ MockSimpleSpanProcessor: vi.fn(function (exp: unknown) {
21
+ return { exporter: exp };
22
+ }),
23
+ };
24
+ });
25
+
26
+ vi.mock('autotel', () => ({
27
+ init: mockInit,
28
+ isInitialized: mockIsInitialized,
29
+ }));
30
+ vi.mock('autotel/exporters', () => ({
31
+ InMemorySpanExporter: MockInMemorySpanExporter,
32
+ }));
33
+ vi.mock('autotel/processors', () => ({
34
+ SimpleSpanProcessor: MockSimpleSpanProcessor,
35
+ }));
36
+
37
+ import { instrument } from './instrument';
38
+
39
+ type InitCall = {
40
+ service?: string;
41
+ endpoint?: string;
42
+ debug?: boolean | 'pretty';
43
+ logs?: unknown;
44
+ subscribers?: unknown;
45
+ spanProcessors?: unknown[];
46
+ };
47
+ const lastInit = () => mockInit.mock.calls[0][0] as InitCall;
48
+
49
+ describe('instrument()', () => {
50
+ const originalEnv = { ...process.env };
51
+
52
+ beforeEach(() => {
53
+ mockInit.mockReset();
54
+ mockIsInitialized.mockReturnValue(false);
55
+ MockInMemorySpanExporter.mockClear();
56
+ MockSimpleSpanProcessor.mockClear();
57
+ delete (globalThis as Record<string, unknown>).__testSpanExporter;
58
+ delete process.env.E2E;
59
+ delete process.env.AUTOTEL_DEBUG;
60
+ delete process.env.OTEL_SERVICE_NAME;
61
+ delete process.env.NODE_ENV;
62
+ });
63
+ afterEach(() => {
64
+ process.env = { ...originalEnv };
65
+ });
66
+
67
+ it('is idempotent — does nothing when already initialized', () => {
68
+ mockIsInitialized.mockReturnValue(true);
69
+ instrument({ service: 'x' });
70
+ expect(mockInit).not.toHaveBeenCalled();
71
+ });
72
+
73
+ it('defaults the service name to tanstack-start', () => {
74
+ instrument();
75
+ expect(lastInit().service).toBe('tanstack-start');
76
+ });
77
+
78
+ it('prefers an explicit service over OTEL_SERVICE_NAME', () => {
79
+ process.env.OTEL_SERVICE_NAME = 'from-env';
80
+ instrument({ service: 'explicit' });
81
+ expect(lastInit().service).toBe('explicit');
82
+ });
83
+
84
+ it('falls back to OTEL_SERVICE_NAME', () => {
85
+ process.env.OTEL_SERVICE_NAME = 'from-env';
86
+ instrument();
87
+ expect(lastInit().service).toBe('from-env');
88
+ });
89
+
90
+ it('passes options straight through to init in normal mode', () => {
91
+ const subscribers = [{ name: 'sub' } as never];
92
+ instrument({
93
+ endpoint: 'http://collector:4318',
94
+ subscribers,
95
+ logs: true,
96
+ });
97
+ const call = lastInit();
98
+ expect(call.endpoint).toBe('http://collector:4318');
99
+ expect(call.subscribers).toBe(subscribers);
100
+ expect(call.logs).toBe(true);
101
+ expect(call.spanProcessors).toBeUndefined();
102
+ });
103
+
104
+ it('resolves debug from AUTOTEL_DEBUG', () => {
105
+ process.env.AUTOTEL_DEBUG = 'pretty';
106
+ instrument({ endpoint: 'http://c:4318' });
107
+ expect(lastInit().debug).toBe('pretty');
108
+ });
109
+
110
+ it('pretty-prints in dev when no endpoint is set', () => {
111
+ process.env.NODE_ENV = 'development';
112
+ instrument();
113
+ expect(lastInit().debug).toBe('pretty');
114
+ });
115
+
116
+ it('captures spans in memory under E2E=1 and skips OTLP + logs', () => {
117
+ process.env.E2E = '1';
118
+ const subscribers = [{ name: 'sub' } as never];
119
+ instrument({ endpoint: 'http://c:4318', subscribers, logs: true });
120
+
121
+ expect(MockInMemorySpanExporter).toHaveBeenCalledOnce();
122
+ const call = lastInit();
123
+ expect(call.spanProcessors).toHaveLength(1);
124
+ expect(call.endpoint).toBeUndefined(); // no OTLP shipping in tests
125
+ expect(call.logs).toBeUndefined(); // logs off in E2E
126
+ expect(call.subscribers).toBe(subscribers); // subscribers still flow
127
+ expect((globalThis as Record<string, unknown>).__testSpanExporter).toBe(
128
+ mockExporter,
129
+ );
130
+ });
131
+ });
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Configurable tracing setup for TanStack Start.
3
+ *
4
+ * `instrument(options)` is a thin wrapper over autotel's `init` that adds the
5
+ * TanStack defaults so apps don't hand-roll them:
6
+ *
7
+ * - service name defaults to `OTEL_SERVICE_NAME` or `'tanstack-start'`;
8
+ * - `debug` resolves from `AUTOTEL_DEBUG` (`pretty` in dev when no endpoint set);
9
+ * - when `E2E=1`, spans are captured by an `InMemorySpanExporter` exposed as
10
+ * `globalThis.__testSpanExporter` (for span assertions) instead of shipping
11
+ * over OTLP;
12
+ * - it's idempotent — a second call is a no-op.
13
+ *
14
+ * Everything else — `endpoint`, `headers`, `subscribers`, `logs`,
15
+ * `canonicalLogLines`, extra `spanProcessors`, … — passes straight through to
16
+ * `init`, and the standard `OTEL_*` env vars are resolved by autotel core, so
17
+ * apps never re-parse them.
18
+ *
19
+ * The zero-config `autotel-tanstack/auto` side-effect module is just
20
+ * `instrument()` with no options.
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * import { instrument } from 'autotel-tanstack';
25
+ * import { PostHogSubscriber } from 'autotel-subscribers';
26
+ *
27
+ * instrument({
28
+ * subscribers: process.env.POSTHOG_KEY
29
+ * ? [new PostHogSubscriber({ apiKey: process.env.POSTHOG_KEY })]
30
+ * : [],
31
+ * logs: true,
32
+ * canonicalLogLines: { enabled: true, rootSpansOnly: true },
33
+ * });
34
+ * ```
35
+ *
36
+ * @module
37
+ */
38
+
39
+ import { init, isInitialized, type AutotelConfig } from 'autotel';
40
+ import { InMemorySpanExporter } from 'autotel/exporters';
41
+ import { SimpleSpanProcessor } from 'autotel/processors';
42
+
43
+ // `service` is optional here — instrument() defaults it to OTEL_SERVICE_NAME or
44
+ // 'tanstack-start'. Everything else matches autotel's init config.
45
+ export type InstrumentOptions = Omit<AutotelConfig, 'service'> & {
46
+ service?: string;
47
+ };
48
+
49
+ const DEFAULT_SERVICE = 'tanstack-start';
50
+
51
+ /**
52
+ * Resolve span-debug output: an explicit option wins; otherwise `AUTOTEL_DEBUG`
53
+ * (`pretty` | `true`/`1` | `false`/`0`); otherwise pretty-print in development
54
+ * when there's no OTLP endpoint, so spans are visible immediately.
55
+ */
56
+ function resolveDebug(
57
+ explicit: AutotelConfig['debug'],
58
+ endpoint: string | undefined,
59
+ ): boolean | 'pretty' {
60
+ if (explicit !== undefined) return explicit;
61
+ const env = process.env.AUTOTEL_DEBUG;
62
+ if (env === 'pretty') return 'pretty';
63
+ if (env === 'true' || env === '1') return true;
64
+ if (env === 'false' || env === '0') return false;
65
+ if (!endpoint && process.env.NODE_ENV === 'development') return 'pretty';
66
+ return false;
67
+ }
68
+
69
+ export function instrument(options: InstrumentOptions = {}): void {
70
+ // Idempotent: tolerate the instrumentation module being evaluated more than
71
+ // once (HMR, multiple entry points) without re-initializing.
72
+ if (isInitialized()) return;
73
+
74
+ const service =
75
+ options.service ?? process.env.OTEL_SERVICE_NAME ?? DEFAULT_SERVICE;
76
+
77
+ if (process.env.E2E === '1') {
78
+ // Capture spans in memory for test assertions; skip OTLP/logs entirely.
79
+ const exporter = new InMemorySpanExporter();
80
+ (globalThis as Record<string, unknown>).__testSpanExporter = exporter;
81
+ init({
82
+ service,
83
+ subscribers: options.subscribers,
84
+ spanProcessors: [
85
+ new SimpleSpanProcessor(exporter),
86
+ ...(options.spanProcessors ?? []),
87
+ ],
88
+ });
89
+ return;
90
+ }
91
+
92
+ init({
93
+ ...options,
94
+ service,
95
+ debug: resolveDebug(options.debug, options.endpoint),
96
+ });
97
+ }