@genn-inc/cluebase-frontend-sdk 0.0.1 → 0.0.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.
Files changed (77) hide show
  1. package/README.md +11 -9
  2. package/dist/_generated/correlation-attribute-keys.js +4 -0
  3. package/dist/_generated/otel-span-conversion.d.ts +0 -34
  4. package/dist/_generated/otel-span-conversion.js +0 -32
  5. package/dist/context/action-context.d.ts +39 -0
  6. package/dist/context/action-context.js +318 -0
  7. package/dist/context/browser-storage.d.ts +0 -12
  8. package/dist/context/browser-storage.js +0 -13
  9. package/dist/context/identity.js +0 -4
  10. package/dist/context/organization.d.ts +0 -4
  11. package/dist/context/organization.js +0 -7
  12. package/dist/context/session.js +0 -3
  13. package/dist/context/tab.js +0 -5
  14. package/dist/context/trace.d.ts +13 -1
  15. package/dist/context/trace.js +119 -21
  16. package/dist/exporter/batch.d.ts +0 -12
  17. package/dist/exporter/batch.js +0 -27
  18. package/dist/exporter/browser-outbox.js +0 -17
  19. package/dist/exporter/client.d.ts +0 -15
  20. package/dist/exporter/client.js +0 -43
  21. package/dist/exporter/delivery-response-contract.js +0 -6
  22. package/dist/exporter/delivery-response.d.ts +0 -16
  23. package/dist/exporter/delivery-response.js +0 -19
  24. package/dist/exporter/frontend-resource.d.ts +0 -9
  25. package/dist/exporter/frontend-resource.js +0 -9
  26. package/dist/exporter/observation-source-event-exporter.d.ts +0 -28
  27. package/dist/exporter/observation-source-event-exporter.js +0 -18
  28. package/dist/exporter/parameter-snapshot.js +1 -24
  29. package/dist/exporter/raw-event-to-source-signal.js +18 -11
  30. package/dist/exporter/sanitize.d.ts +1 -12
  31. package/dist/exporter/sanitize.js +6 -39
  32. package/dist/exporter/source-event.d.ts +2 -0
  33. package/dist/exporter/span-to-source-signal.js +7 -3
  34. package/dist/exporter/text-fingerprint.d.ts +0 -8
  35. package/dist/exporter/text-fingerprint.js +0 -8
  36. package/dist/index.d.ts +0 -4
  37. package/dist/index.js +16 -44
  38. package/dist/instrumentation/action.js +3 -2
  39. package/dist/instrumentation/cluebase-authored-attributes.d.ts +0 -2
  40. package/dist/instrumentation/cluebase-authored-attributes.js +0 -23
  41. package/dist/instrumentation/common.d.ts +0 -63
  42. package/dist/instrumentation/common.js +0 -48
  43. package/dist/instrumentation/dom.d.ts +0 -25
  44. package/dist/instrumentation/dom.js +5 -41
  45. package/dist/instrumentation/drag.js +1 -2
  46. package/dist/instrumentation/form.js +1 -2
  47. package/dist/instrumentation/input.js +10 -8
  48. package/dist/instrumentation/naming-evidence.d.ts +0 -12
  49. package/dist/instrumentation/navigation.js +0 -2
  50. package/dist/instrumentation/network-request.d.ts +2 -2
  51. package/dist/instrumentation/network-request.js +1 -2
  52. package/dist/instrumentation/network-span-attributes.d.ts +0 -7
  53. package/dist/instrumentation/network-span-attributes.js +1 -3
  54. package/dist/instrumentation/network.js +6 -1
  55. package/dist/instrumentation/page.js +0 -2
  56. package/dist/instrumentation/performance.js +0 -7
  57. package/dist/integrations/react-router.js +0 -3
  58. package/dist/internal/internal-log.d.ts +0 -7
  59. package/dist/internal/internal-log.js +0 -11
  60. package/dist/provider/_version.d.ts +1 -1
  61. package/dist/provider/_version.js +1 -1
  62. package/dist/provider/config.d.ts +0 -7
  63. package/dist/provider/config.js +3 -16
  64. package/dist/provider/constants.d.ts +1 -17
  65. package/dist/provider/constants.js +1 -31
  66. package/dist/provider/privacy-policy-store.d.ts +0 -12
  67. package/dist/provider/privacy-policy-store.js +0 -12
  68. package/dist/provider/sdk-error.d.ts +7 -0
  69. package/dist/provider/sdk-error.js +48 -0
  70. package/dist/provider/sdk-event-pipeline.d.ts +1 -1
  71. package/dist/provider/sdk-event-pipeline.js +41 -54
  72. package/dist/provider/sdk-otel-pipeline.js +50 -4
  73. package/dist/provider/sdk-runtime-surfaces.js +3 -1
  74. package/dist/provider/sdk.js +18 -24
  75. package/dist/provider/types.d.ts +3 -39
  76. package/dist/provider/usage-governor.js +0 -2
  77. package/package.json +53 -58
@@ -1,4 +1,4 @@
1
- import { trace } from "@opentelemetry/api";
1
+ import { context, propagation, trace } from "@opentelemetry/api";
2
2
  import { resourceFromAttributes } from "@opentelemetry/resources";
3
3
  import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base";
4
4
  import { WebTracerProvider } from "@opentelemetry/sdk-trace-web";
@@ -7,6 +7,15 @@ import { ObservationSourceEventExporter } from "../exporter/observation-source-e
7
7
  import { createFrontendResourceAttributes } from "../exporter/frontend-resource.js";
8
8
  import { createCluebaseNetworkPropagator } from "../instrumentation/network.js";
9
9
  import { getSessionCaptureEligibility } from "./sdk-event-pipeline.js";
10
+ const globalSnapshots = new WeakMap();
11
+ const readContextManager = () => Reflect.get(context, "_getContextManager").call(context);
12
+ const readPropagator = () => Reflect.get(propagation, "_getGlobalPropagator").call(propagation);
13
+ const isNoopContextManager = (manager) => manager.constructor.name === "NoopContextManager";
14
+ const isNoopPropagator = (propagator) => propagator.constructor.name === "NoopTextMapPropagator";
15
+ const getTracerDelegate = (provider) => {
16
+ const candidate = provider;
17
+ return candidate.getDelegate?.();
18
+ };
10
19
  export const createCluebaseOtelPipeline = ({ resolved, getTransport, getContext, }) => {
11
20
  if (!getTransport()) {
12
21
  return null;
@@ -73,9 +82,22 @@ export const createCluebaseOtelPipeline = ({ resolved, getTransport, getContext,
73
82
  const mode = resolved.otelProviderMode;
74
83
  const shouldRegister = mode === "register" || (mode === "detect" && !hasHostInstalledProvider());
75
84
  if (shouldRegister) {
85
+ const contextBeforeRegister = readContextManager();
86
+ const propagatorBeforeRegister = readPropagator();
76
87
  provider.register({
77
88
  propagator: createCluebaseNetworkPropagator(),
78
89
  });
90
+ globalSnapshots.set(provider, {
91
+ installedTracer: getTracerDelegate(trace.getTracerProvider()) === provider ? provider : null,
92
+ installedContextManager: isNoopContextManager(contextBeforeRegister)
93
+ ? readContextManager()
94
+ : null,
95
+ installedPropagator: isNoopPropagator(propagatorBeforeRegister)
96
+ ? readPropagator()
97
+ : null,
98
+ contextWasAlreadyRegistered: !isNoopContextManager(contextBeforeRegister),
99
+ propagatorWasAlreadyRegistered: !isNoopPropagator(propagatorBeforeRegister),
100
+ });
79
101
  }
80
102
  return provider;
81
103
  };
@@ -95,7 +117,10 @@ export const shutdownCluebaseOtelProvider = (provider) => {
95
117
  if (!provider) {
96
118
  return;
97
119
  }
98
- void provider.shutdown().catch(() => undefined);
120
+ void provider
121
+ .shutdown()
122
+ .catch(() => undefined)
123
+ .finally(() => restoreCluebaseOtelGlobals(provider));
99
124
  };
100
125
  export const shutdownCluebaseOtelProviderAsync = async (provider) => {
101
126
  if (!provider) {
@@ -105,8 +130,30 @@ export const shutdownCluebaseOtelProviderAsync = async (provider) => {
105
130
  await provider.shutdown();
106
131
  }
107
132
  catch {
108
- // shutdown is best-effort per OTel contract.
109
133
  }
134
+ finally {
135
+ restoreCluebaseOtelGlobals(provider);
136
+ }
137
+ };
138
+ const restoreCluebaseOtelGlobals = (provider) => {
139
+ const snapshot = globalSnapshots.get(provider);
140
+ if (!snapshot)
141
+ return;
142
+ if (snapshot.installedTracer &&
143
+ getTracerDelegate(trace.getTracerProvider()) === snapshot.installedTracer) {
144
+ trace.disable();
145
+ }
146
+ if (!snapshot.contextWasAlreadyRegistered &&
147
+ snapshot.installedContextManager &&
148
+ readContextManager() === snapshot.installedContextManager) {
149
+ context.disable();
150
+ }
151
+ if (!snapshot.propagatorWasAlreadyRegistered &&
152
+ snapshot.installedPropagator &&
153
+ readPropagator() === snapshot.installedPropagator) {
154
+ propagation.disable();
155
+ }
156
+ globalSnapshots.delete(provider);
110
157
  };
111
158
  export const forceFlushCluebaseOtelProvider = async (provider, signal) => {
112
159
  if (!provider) {
@@ -116,7 +163,6 @@ export const forceFlushCluebaseOtelProvider = async (provider, signal) => {
116
163
  await awaitWithAbort(provider.forceFlush(), signal);
117
164
  }
118
165
  catch {
119
- // forceFlush is best-effort per OTel contract.
120
166
  }
121
167
  };
122
168
  const awaitWithAbort = async (promise, signal) => {
@@ -47,6 +47,9 @@ export class ProviderRuntimeSurfaces {
47
47
  input.interactionId ??
48
48
  null);
49
49
  },
50
+ bindEventContext: (event) => {
51
+ this.getTraceManager()?.bindEventContext(event);
52
+ },
50
53
  requestFlush: () => {
51
54
  void this.flushCaptureSummaries("capture_flush");
52
55
  if (this.flushDebounceTimer)
@@ -208,7 +211,6 @@ export class ProviderRuntimeSurfaces {
208
211
  dispose();
209
212
  }
210
213
  catch {
211
- // Ignore.
212
214
  }
213
215
  }
214
216
  this.unloadHandlers = [];
@@ -15,6 +15,7 @@ import { isValidPublicCustomEventName, normalizeProfileAvatarUrl, normalizePubli
15
15
  import { OFFICIAL_CUSTOM_EVENT_NAME, ProviderEventPipeline, readCurrentLifecycleUrl, } from "./sdk-event-pipeline.js";
16
16
  import { createCluebaseOtelPipeline, forceFlushCluebaseOtelProvider, shutdownCluebaseOtelProvider, shutdownCluebaseOtelProviderAsync, } from "./sdk-otel-pipeline.js";
17
17
  import { ProviderRuntimeSurfaces } from "./sdk-runtime-surfaces.js";
18
+ import { getSdkErrorDetails, reportSdkError } from "./sdk-error.js";
18
19
  const createNoopLogger = () => {
19
20
  return {
20
21
  debug: () => undefined,
@@ -47,10 +48,6 @@ class CluebaseBrowserSdkImpl {
47
48
  this.traceManager = null;
48
49
  this.diagnostics = new DiagnosticStore();
49
50
  this.transport = null;
50
- // OTel TracerProvider wired with the source-signal exporter so every span
51
- // produced by `@opentelemetry/api`'s global tracer flows through
52
- // `ObservationSourceEventExporter` → `BatchTransport.enqueue` →
53
- // Cluebase ingest endpoint.
54
51
  this.tracerProvider = null;
55
52
  this.logger = logger;
56
53
  this.internalMetrics = new InternalMetricsStore();
@@ -120,6 +117,7 @@ class CluebaseBrowserSdkImpl {
120
117
  this.tabManager = new TabManager();
121
118
  this.organizationManager = new OrganizationManager();
122
119
  this.traceManager = new TraceManager();
120
+ this.traceManager.enableAsyncContext();
123
121
  this.environmentManager = new EnvironmentManager({
124
122
  frontendRelease: resolved.release.frontendRelease,
125
123
  contextTraitsProvider: resolved.contextTraitsProvider,
@@ -168,9 +166,6 @@ class CluebaseBrowserSdkImpl {
168
166
  if (this.consent !== "denied") {
169
167
  this.warmupBrowserToken(ingestClient);
170
168
  }
171
- // Wire WebTracerProvider with the canonical exporter. The provider is
172
- // registered globally so OTel-instrumented code and capture modules
173
- // converge on the same transport buffer.
174
169
  this.tracerProvider = createCluebaseOtelPipeline({
175
170
  resolved,
176
171
  getTransport: () => this.transport,
@@ -198,11 +193,24 @@ class CluebaseBrowserSdkImpl {
198
193
  }
199
194
  this.installUnloadHandlers();
200
195
  }
201
- catch {
196
+ catch (error) {
197
+ const errorDetails = getSdkErrorDetails(error);
202
198
  this.logger.error("Cluebase Frontend SDK init failed", {
203
199
  error_code: "sdk_operation_failed",
200
+ ...errorDetails,
204
201
  });
202
+ reportSdkError("init", error);
205
203
  this.warnPublicDrop("init", "sdk_operation_failed");
204
+ try {
205
+ this.shutdown();
206
+ }
207
+ catch (cleanupError) {
208
+ this.logger.error("Cluebase Frontend SDK init cleanup failed", {
209
+ error_code: "sdk_cleanup_failed",
210
+ ...getSdkErrorDetails(cleanupError),
211
+ });
212
+ reportSdkError("init cleanup", cleanupError);
213
+ }
206
214
  }
207
215
  }
208
216
  identify(userId, traits) {
@@ -214,8 +222,6 @@ class CluebaseBrowserSdkImpl {
214
222
  return;
215
223
  }
216
224
  try {
217
- // Capture the pre-identify anonymous id so the worker can fuse the
218
- // anonymous → identified subject as a single resolution chain.
219
225
  const normalizedUserId = normalizePublicIdentityId(userId);
220
226
  if (!normalizedUserId) {
221
227
  this.warnPublicDrop("identify", "userId must be a non-empty string");
@@ -380,7 +386,6 @@ class CluebaseBrowserSdkImpl {
380
386
  },
381
387
  });
382
388
  }
383
- // SDK は observation source event だけを送り、ingest core が意味付けを行う。
384
389
  setConsent(consent) {
385
390
  this.consent = consent;
386
391
  if (!this.initialized) {
@@ -421,7 +426,6 @@ class CluebaseBrowserSdkImpl {
421
426
  }
422
427
  }
423
428
  catch {
424
- // Public warnings must never break the host app.
425
429
  }
426
430
  }
427
431
  warnPublicFieldDrop(operation, field, _reason) {
@@ -436,7 +440,6 @@ class CluebaseBrowserSdkImpl {
436
440
  }
437
441
  }
438
442
  catch {
439
- // Public warnings must never break the host app.
440
443
  }
441
444
  }
442
445
  sanitizeIdentifyTraits(traits) {
@@ -479,7 +482,6 @@ class CluebaseBrowserSdkImpl {
479
482
  flushLifecycleEvents() {
480
483
  void this.transport?.flush();
481
484
  }
482
- // 内部 transport の即時 flush を要求する。SPA navigation や明示的 shutdown シナリオ用。
483
485
  async flush() {
484
486
  const deadline = this.transport?.beginFlushDeadline();
485
487
  try {
@@ -491,7 +493,6 @@ class CluebaseBrowserSdkImpl {
491
493
  this.transport?.endFlushDeadline(deadline);
492
494
  }
493
495
  }
494
- // 残バッファを flush した上で SDK を停止する。テスト / 明示的 shutdown 用。
495
496
  async close() {
496
497
  const closeSignal = this.transport?.beginClose();
497
498
  await awaitUntilDeadline(this.flushCaptureSummaries("close"), closeSignal);
@@ -499,7 +500,7 @@ class CluebaseBrowserSdkImpl {
499
500
  await forceFlushCluebaseOtelProvider(this.tracerProvider, closeSignal ?? undefined);
500
501
  await this.transport?.close();
501
502
  if (this.transport?.getDiagnostics().lifecycle === "closing_failed") {
502
- this.runtimeSurfaces.stopRuntimeSurfaces();
503
+ await this.shutdownAsync();
503
504
  return;
504
505
  }
505
506
  await this.shutdownAsync();
@@ -544,14 +545,6 @@ class CluebaseBrowserSdkImpl {
544
545
  refreshSessionCaptureEligibility() {
545
546
  this.eventPipeline.refreshSessionCaptureEligibility();
546
547
  }
547
- /**
548
- * Sanitize an identity value (userId / organizationId) before publishing.
549
- * If the caller passed an email / phone / credit-card / SSN-shaped
550
- * value, hash it deterministically and warn via the internal logger.
551
- * This prevents raw PII from landing in canonical span attributes
552
- * (`cluebase.actor.user_id`) and raw observation storage.
553
- *
554
- */
555
548
  sanitizeIdentityValue(field, raw) {
556
549
  if (typeof raw !== "string")
557
550
  return raw;
@@ -587,6 +580,7 @@ class CluebaseBrowserSdkImpl {
587
580
  this.transport.dispose();
588
581
  this.transport = null;
589
582
  }
583
+ this.traceManager?.disableAsyncContext();
590
584
  this.traceManager = null;
591
585
  this.initialized = false;
592
586
  this.initSignature = null;
@@ -3,11 +3,6 @@ import type { DiagnosticsSnapshot } from "../exporter/diagnostics.js";
3
3
  import type { FrontendEventName, ParameterCaptureMode, SdkCollectionMode } from "./contracts.js";
4
4
  export type { FrontendEventCategory, FrontendEventName, FrontendEventStatus, ParameterCaptureMode, SdkCollectionMode, } from "./contracts.js";
5
5
  export type CluebaseConsentState = "granted" | "denied" | "unknown";
6
- /**
7
- * MVP group taxonomy. Public `cluebase.group(...)` accepts only the customer
8
- * company concept. `account` / `workspace` are future concepts and are not
9
- * exposed as MVP group inputs.
10
- */
11
6
  export type CluebaseGroupType = "organization";
12
7
  export type CanonicalJsonValue = string | number | boolean | null | CanonicalJsonValue[] | {
13
8
  [key: string]: CanonicalJsonValue;
@@ -37,14 +32,8 @@ export type DiagnosticCollectionConfig = {
37
32
  reason?: string;
38
33
  enabledBy?: string;
39
34
  };
40
- /**
41
- * Public bootstrap options accepted by `cluebase.init`.
42
- *
43
- * The SDK derives dev/prod from the `projectKey` prefix. Browser ingest obtains
44
- * short-lived tokens from `POST <endpoint>/api/v1/ingest/browser-tokens`.
45
- */
46
35
  export type CluebaseInitOptions = {
47
- endpoint: string;
36
+ endpoint?: string;
48
37
  projectKey: string;
49
38
  autocapture?: boolean;
50
39
  captureNetwork?: boolean;
@@ -70,23 +59,6 @@ export type CluebaseInitOptions = {
70
59
  frontendRelease?: string;
71
60
  };
72
61
  contextTraitsProvider?: () => CluebaseTrackProperties;
73
- /**
74
- * Controls how the SDK's internal ``WebTracerProvider`` interacts with
75
- * the page's global OTel context.
76
- *
77
- * - ``"register"`` (default for SDKs initialised on pages without
78
- * pre-existing OTel): call ``WebTracerProvider#register()`` so any
79
- * ``trace.getTracer(...)`` call in the page routes through Cluebase's
80
- * exporter, including Cluebase's own runtime span emissions.
81
- * - ``"standalone"``: do not register globally. Cluebase's pipeline is
82
- * private; only spans created via the SDK's own internal tracer
83
- * reach the exporter. Use this when the host app already manages an
84
- * OTel TracerProvider (Sentry, Datadog, Honeycomb, etc.) and Cluebase
85
- * must not hijack it.
86
- * - ``"detect"`` (recommended): inspect ``trace.getTracerProvider()``;
87
- * if a non-proxy provider is already installed, behave as
88
- * ``standalone``; otherwise behave as ``register``.
89
- */
90
62
  otelProviderMode?: "register" | "standalone" | "detect";
91
63
  };
92
64
  export type ResolvedCluebaseConfig = {
@@ -195,6 +167,7 @@ export type CluebaseContext = {
195
167
  trace_id: string;
196
168
  request_id: string;
197
169
  request_span_id: string;
170
+ action_id: string | null;
198
171
  interaction_id: string;
199
172
  correlation_id: string | null;
200
173
  sdk_collection_mode: SdkCollectionMode;
@@ -255,16 +228,6 @@ export type CluebaseSubjectProfile = {
255
228
  contact_identity_hash: string | null;
256
229
  contact_domain: string | null;
257
230
  };
258
- /**
259
- * Customer-facing trait dict accepted by `cluebase.identify` /
260
- * `cluebase.setOrganization`.
261
- *
262
- * Customers use the camelCase form on every SDK. The ingest core normalizes
263
- * these values after receiving the SDK source signal.
264
- *
265
- * `displayName`, `email`, and `emailAddress` are accepted alternate keys.
266
- * Email traits are transported only as privacy-safe contact-derived fields.
267
- */
268
231
  export type CluebaseSubjectTraits = {
269
232
  name?: string | null;
270
233
  email?: string | null;
@@ -315,6 +278,7 @@ export type CaptureModuleContext = {
315
278
  interactionScopeKey?: string | null;
316
279
  nowMs?: number;
317
280
  }) => string | null;
281
+ bindEventContext?: (event: Event) => void;
318
282
  requestFlush?: () => void;
319
283
  };
320
284
  export type CaptureStopHandle = {
@@ -4,8 +4,6 @@ export const DEFAULT_INGEST_USAGE_GOVERNOR_FEEDBACK = {
4
4
  limitReasons: [],
5
5
  retryAfterAt: null,
6
6
  };
7
- // 正本から生成した一覧をそのまま使います。ここへ書き写していたため
8
- // `replay_storage` が抜け、受付側が「止めよ」と言っても画面側が捨てていました。
9
7
  const COST_CAPABILITIES = new Set(GENERATED_COST_CAPABILITIES);
10
8
  const LIMIT_KINDS = new Set(GENERATED_LIMIT_KINDS);
11
9
  const THRESHOLD_STAGES = new Set(GENERATED_THRESHOLD_STAGES);
package/package.json CHANGED
@@ -1,59 +1,54 @@
1
1
  {
2
- "name": "@genn-inc/cluebase-frontend-sdk",
3
- "version": "0.0.1",
4
- "repository": {
5
- "type": "git",
6
- "url": "git+https://github.com/genn-inc/cluebase.git"
7
- },
8
- "description": "Cluebase Frontend SDK — OTel-based observation-source event capture for frontend apps",
9
- "type": "module",
10
- "main": "dist/index.js",
11
- "types": "dist/index.d.ts",
12
- "files": [
13
- "dist/",
14
- "README.md"
15
- ],
16
- "exports": {
17
- ".": {
18
- "types": "./dist/index.d.ts",
19
- "browser": "./dist/index.js",
20
- "default": "./dist/index.js"
21
- }
22
- },
23
- "scripts": {
24
- "build": "node ./scripts/clean-dist.mjs && node ../../../scripts/generate-shared-contract-tables.mjs && node ./scripts/generate-version-module.mjs && tsc -p tsconfig.build.json && node ./scripts/fix-esm-relative-imports.mjs",
25
- "prepack": "pnpm build",
26
- "prepublishOnly": "pnpm lint && pnpm test:cov && pnpm typecheck && pnpm test:package-import",
27
- "lint": "pnpm exec biome lint src",
28
- "test:package-import": "pnpm build && node ../../../tests/distribution/frontend-sdk/check-package-import.mjs",
29
- "typecheck": "tsc -p tsconfig.typecheck.json",
30
- "_comment_test": "実環境が要る試験 (`*-live.test.ts`) を既定の実行から外します (`tests/README.md` §12.2)。**綴りで拾います** — file 名を並べると、新しい live を足した人がここへ足し忘れて黙ります。**設定側 (`vitest.config.ts`) の `exclude` には置けません**: 実測 (2026-08-21) では、そこへ置くと live を名指しした実行まで `No test files found` で落ちます。script に置けば、手元と CI で対象が同じまま、実環境のあるジョブだけが名指しで拾えます。",
31
- "test": "vitest run --config ../../../tests/config/vitest/frontend-sdk.config.ts --exclude \"../../../tests/integration/frontend-sdk/**/*-live.test.ts\"",
32
- "test:cov": "vitest run --config ../../../tests/config/vitest/frontend-sdk.config.ts --coverage --exclude \"../../../tests/integration/frontend-sdk/**/*-live.test.ts\"",
33
- "_comment_test_live": "実環境がある段だけがここを呼びます。**vitest の位置引数は glob ではなく道筋への部分一致です** — 実測 (2026-08-21): `vitest run \"src/**/*-live.test.ts\"` は `No test files found` で 0 件、`vitest run live.test.ts` は 1 件。綴りを CI ではなくここに置くので、CI 側は script 名を呼ぶだけになります。",
34
- "test:live": "vitest run --config ../../../tests/config/vitest/frontend-sdk.config.ts ../../../tests/integration/frontend-sdk"
35
- },
36
- "devDependencies": {
37
- "@cluebase/schema": "workspace:*",
38
- "@cluebase/shared": "workspace:*",
39
- "@vitest/coverage-v8": "^3.2.4",
40
- "jsdom": "^26.1.0",
41
- "typescript": "^5.9.3",
42
- "vitest": "^3.2.7"
43
- },
44
- "dependencies": {
45
- "@noble/hashes": "1.8.0",
46
- "@opentelemetry/api": ">=1.9.1 <1.10.0",
47
- "@opentelemetry/api-logs": ">=0.218.0 <1.0.0",
48
- "@opentelemetry/browser-instrumentation": ">=0.5.2 <1.0.0",
49
- "@opentelemetry/core": ">=2.7.1 <3.0.0",
50
- "@opentelemetry/instrumentation-document-load": ">=0.63.0 <1.0.0",
51
- "@opentelemetry/instrumentation-fetch": ">=0.218.0 <1.0.0",
52
- "@opentelemetry/instrumentation-xml-http-request": ">=0.218.0 <1.0.0",
53
- "@opentelemetry/resources": ">=2.7.1 <3.0.0",
54
- "@opentelemetry/sdk-trace-base": ">=2.7.1 <3.0.0",
55
- "@opentelemetry/sdk-trace-web": ">=2.7.1 <3.0.0",
56
- "json-canonicalize": "2.0.0",
57
- "zod": "^4.4.3"
58
- }
59
- }
2
+ "name": "@genn-inc/cluebase-frontend-sdk",
3
+ "version": "0.0.3",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "git+https://github.com/genn-inc/cluebase.git"
7
+ },
8
+ "description": "Cluebase Frontend SDK — OTel-based observation-source event capture for frontend apps",
9
+ "type": "module",
10
+ "main": "dist/index.js",
11
+ "types": "dist/index.d.ts",
12
+ "files": [
13
+ "dist/",
14
+ "README.md"
15
+ ],
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "browser": "./dist/index.js",
20
+ "default": "./dist/index.js"
21
+ }
22
+ },
23
+ "devDependencies": {
24
+ "@vitest/coverage-v8": "^3.2.4",
25
+ "jsdom": "^26.1.0",
26
+ "typescript": "^5.9.3",
27
+ "vitest": "^3.2.7",
28
+ "@cluebase/schema": "1.0.0",
29
+ "@cluebase/shared": "1.0.0"
30
+ },
31
+ "dependencies": {
32
+ "@noble/hashes": "1.8.0",
33
+ "@opentelemetry/api": ">=1.9.1 <1.10.0",
34
+ "@opentelemetry/api-logs": ">=0.218.0 <1.0.0",
35
+ "@opentelemetry/browser-instrumentation": ">=0.5.2 <1.0.0",
36
+ "@opentelemetry/core": ">=2.7.1 <3.0.0",
37
+ "@opentelemetry/instrumentation-document-load": ">=0.63.0 <1.0.0",
38
+ "@opentelemetry/instrumentation-fetch": ">=0.218.0 <1.0.0",
39
+ "@opentelemetry/instrumentation-xml-http-request": ">=0.218.0 <1.0.0",
40
+ "@opentelemetry/resources": ">=2.7.1 <3.0.0",
41
+ "@opentelemetry/sdk-trace-base": ">=2.7.1 <3.0.0",
42
+ "@opentelemetry/sdk-trace-web": ">=2.7.1 <3.0.0",
43
+ "json-canonicalize": "2.0.0",
44
+ "zod": "^4.4.3"
45
+ },
46
+ "scripts": {
47
+ "build": "node ./scripts/clean-dist.mjs && node ../../../scripts/generate-shared-contract-tables.mjs && node ./scripts/generate-version-module.mjs && tsc -p tsconfig.build.json && node ./scripts/fix-esm-relative-imports.mjs",
48
+ "lint": "pnpm exec biome lint src",
49
+ "test:package-import": "pnpm build && node ../../../tests/distribution/frontend-sdk/check-package-import.mjs",
50
+ "typecheck": "tsc -p tsconfig.typecheck.json",
51
+ "test": "vitest run --config ../../../tests/config/vitest/frontend-sdk.config.ts",
52
+ "test:cov": "vitest run --config ../../../tests/config/vitest/frontend-sdk.config.ts --coverage"
53
+ }
54
+ }