diff --git a/.github/workflows/browser-telemetry.yml b/.github/workflows/browser-telemetry.yml new file mode 100644 index 0000000000..b14b4e0b7a --- /dev/null +++ b/.github/workflows/browser-telemetry.yml @@ -0,0 +1,27 @@ +name: telemetry/browser-telemetry + +on: + push: + branches: [main, 'feat/**'] + paths-ignore: + - '**.md' #Do not need to run CI for markdown changes. + pull_request: + branches: [main, 'feat/**'] + paths-ignore: + - '**.md' + +jobs: + build-test-browser-telemetry: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20.x + registry-url: 'https://registry.npmjs.org' + - id: shared + name: Shared CI Steps + uses: ./actions/ci + with: + workspace_name: '@launchdarkly/browser-telemetry' + workspace_path: packages/telemetry/browser-telemetry diff --git a/package.json b/package.json index 38052de4db..4444b7c8fe 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,8 @@ "packages/sdk/browser/contract-tests/adapter", "packages/sdk/server-ai", "packages/sdk/server-ai/examples/bedrock", - "packages/sdk/server-ai/examples/openai" + "packages/sdk/server-ai/examples/openai", + "packages/telemetry/browser-telemetry" ], "private": true, "scripts": { diff --git a/packages/telemetry/browser-telemetry/README.md b/packages/telemetry/browser-telemetry/README.md new file mode 100644 index 0000000000..816ee4d6d2 --- /dev/null +++ b/packages/telemetry/browser-telemetry/README.md @@ -0,0 +1,41 @@ +# Telemetry integration for LaunchDarkly browser SDKs. + +# ⛔️⛔️⛔️⛔️ + +> [!WARNING] +> This is an alpha version. The API is not stabilized and will introduce breaking changes. + +TODO Add badges + +## LaunchDarkly overview + +[LaunchDarkly](https://www.launchdarkly.com) is a feature management platform that serves over 100 billion feature flags daily to help teams build better software, faster. [Get started](https://docs.launchdarkly.com/home/getting-started) using LaunchDarkly today! + +[![Twitter Follow](https://img.shields.io/twitter/follow/launchdarkly.svg?style=social&label=Follow&maxAge=2592000)](https://twitter.com/intent/follow?screen_name=launchdarkly) + +## Compatibility + +TODO + +## Setup + +TODO + +## Contributing + +We encourage pull requests and other contributions from the community. Check out our [contributing guidelines](CONTRIBUTING.md) for instructions on how to contribute to this SDK. + +## About LaunchDarkly + +- LaunchDarkly is a continuous delivery platform that provides feature flags as a service and allows developers to iterate quickly and safely. We allow you to easily flag your features and manage them from the LaunchDarkly dashboard. With LaunchDarkly, you can: + - Roll out a new feature to a subset of your users (like a group of users who opt-in to a beta tester group), gathering feedback and bug reports from real-world use cases. + - Gradually roll out a feature to an increasing percentage of users, and track the effect that the feature has on key metrics (for instance, how likely is a user to complete a purchase if they have feature A versus feature B?). + - Turn off a feature that you realize is causing performance problems in production, without needing to re-deploy, or even restart the application with a changed configuration file. + - Grant access to certain features based on user attributes, like payment plan (eg: users on the ‘gold’ plan get access to more features than users in the ‘silver’ plan). + - Disable parts of your application to facilitate maintenance, without taking everything offline. +- LaunchDarkly provides feature flag SDKs for a wide variety of languages and technologies. Check out [our documentation](https://docs.launchdarkly.com/sdk) for a complete list. +- Explore LaunchDarkly + - [launchdarkly.com](https://www.launchdarkly.com/ 'LaunchDarkly Main Website') for more information + - [docs.launchdarkly.com](https://docs.launchdarkly.com/ 'LaunchDarkly Documentation') for our documentation and SDK reference guides + - [apidocs.launchdarkly.com](https://apidocs.launchdarkly.com/ 'LaunchDarkly API Documentation') for our API documentation + - [blog.launchdarkly.com](https://blog.launchdarkly.com/ 'LaunchDarkly Blog Documentation') for the latest product updates diff --git a/packages/telemetry/browser-telemetry/__tests__/empty.test.ts b/packages/telemetry/browser-telemetry/__tests__/empty.test.ts new file mode 100644 index 0000000000..759ca77be0 --- /dev/null +++ b/packages/telemetry/browser-telemetry/__tests__/empty.test.ts @@ -0,0 +1,4 @@ +it('runs tests', () => { + // Placeholder so CI can run tests. + expect(true).toBeTruthy(); +}); diff --git a/packages/telemetry/browser-telemetry/jest.config.json b/packages/telemetry/browser-telemetry/jest.config.json new file mode 100644 index 0000000000..6d2e223cd6 --- /dev/null +++ b/packages/telemetry/browser-telemetry/jest.config.json @@ -0,0 +1,16 @@ +{ + "verbose": true, + "testEnvironment": "jest-environment-jsdom", + "testPathIgnorePatterns": ["./dist", "./src"], + "testMatch": ["**.test.ts"], + "setupFiles": ["./setup-jest.js"], + "transform": { + "^.+\\.ts$": [ + "ts-jest", + { + "tsConfig": "tsconfig.test.json" + } + ], + "^.+.tsx?$": ["ts-jest", {}] + } +} diff --git a/packages/telemetry/browser-telemetry/package.json b/packages/telemetry/browser-telemetry/package.json new file mode 100644 index 0000000000..433acb1db0 --- /dev/null +++ b/packages/telemetry/browser-telemetry/package.json @@ -0,0 +1,77 @@ +{ + "name": "@launchdarkly/browser-telemetry", + "version": "0.0.9", + "packageManager": "yarn@3.4.1", + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "require": { + "types": "./dist/index.d.cts", + "require": "./dist/index.cjs" + }, + "import": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js" + } + } + }, + "files": [ + "dist" + ], + "description": "Telemetry integration for LaunchDarkly browser SDKs.", + "scripts": { + "test": "npx jest --runInBand", + "build": "tsup", + "prettier": "prettier --write 'src/*.@(js|ts|tsx|json)'", + "check": "yarn && yarn prettier && yarn lint && tsc && yarn test", + "lint": "npx eslint . --ext .ts" + }, + "homepage": "https://github.com/launchdarkly/js-core/tree/main/packages/telemetry/browser-telemetry", + "repository": { + "type": "git", + "url": "git+https://github.com/launchdarkly/js-core.git" + }, + "keywords": [ + "launchdarkly", + "analytics", + "telemetry" + ], + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/launchdarkly/js-core/issues" + }, + "dependencies": { + "rrweb": "2.0.0-alpha.4", + "tracekit": "^0.4.6" + }, + "peerDependencies": { + "launchdarkly-js-client-sdk": "^3.4.0" + }, + "devDependencies": { + "@jest/globals": "^29.7.0", + "@trivago/prettier-plugin-sort-imports": "^4.1.1", + "@types/css-font-loading-module": "^0.0.13", + "@types/jest": "^29.5.11", + "@typescript-eslint/eslint-plugin": "^6.20.0", + "@typescript-eslint/parser": "^6.20.0", + "eslint": "^8.45.0", + "eslint-config-airbnb-base": "^15.0.0", + "eslint-config-airbnb-typescript": "^17.1.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-import": "^2.27.5", + "eslint-plugin-jest": "^27.6.3", + "eslint-plugin-prettier": "^5.0.0", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", + "launchdarkly-js-test-helpers": "^2.2.0", + "prettier": "^3.0.0", + "rimraf": "^5.0.5", + "ts-jest": "^29.1.1", + "tsup": "^8.3.5", + "typedoc": "0.25.0", + "typescript": "^5.5.3" + } +} diff --git a/packages/telemetry/browser-telemetry/setup-jest.js b/packages/telemetry/browser-telemetry/setup-jest.js new file mode 100644 index 0000000000..e17ac62cb1 --- /dev/null +++ b/packages/telemetry/browser-telemetry/setup-jest.js @@ -0,0 +1,24 @@ +const { TextEncoder, TextDecoder } = require('node:util'); +const crypto = require('node:crypto'); + +global.TextEncoder = TextEncoder; + +Object.assign(window, { TextDecoder, TextEncoder }); + +// Based on: +// https://stackoverflow.com/a/71750830 + +Object.defineProperty(global.self, 'crypto', { + value: { + getRandomValues: (arr) => crypto.randomBytes(arr.length), + subtle: { + digest: (algorithm, data) => { + return new Promise((resolve) => + resolve( + crypto.createHash(algorithm.toLowerCase().replace('-', '')).update(data).digest(), + ), + ); + }, + }, + }, +}); diff --git a/packages/telemetry/browser-telemetry/src/api/Breadcrumb.ts b/packages/telemetry/browser-telemetry/src/api/Breadcrumb.ts new file mode 100644 index 0000000000..dfeb0ec19f --- /dev/null +++ b/packages/telemetry/browser-telemetry/src/api/Breadcrumb.ts @@ -0,0 +1,163 @@ +/** + * Defines the 'class' of the breadcrumb. + */ +export type BreadcrumbClass = + | 'custom' + | 'log' + | 'navigation' + | 'feature-management' + | 'ui' + | 'http'; + +/** + * Indicates the severity of the breadcrumb. + */ +export type BreadcrumbLevel = 'error' | 'warning' | 'info' | 'debug'; + +/** + * Types of data support with breadcrumbs. + */ +export type BreadcrumbDataValue = boolean | number | string; + +/** + * Defines arbitrary data that may be associated with a breadcrumb. + */ +export type BreadcrumbData = Record; + +/** + * Interface which defines a breadcrumb. + */ +export interface Breadcrumb { + /** + * The class of the breadcrumb. This is the top level categorization of breadcrumbs. + */ + class: BreadcrumbClass; + + /** + * When the event associated with the breadcrumb happened. The timestamp is in milliseconds since January 1, 1970 + * Universal Coordinated Time (UTC) + * + * For most breadcrumbs this will not be different than the time of breadcrumb creation, but if there is a delay + * between the event and breadcrumb capture, then the time of the event should be used instead. + */ + timestamp: number; + + /** + * The level of severity of the breadcrumb. The default choice of level should be `info` if there isn't a clear + * reason to use a different level. + */ + level: BreadcrumbLevel; + + /** + * The type of the breadcrumb. Each class may be split into multiple types with the type more specifically + * categorizing the type of event. + */ + type?: string; + + /** + * A message associated with the breadcrumb. + */ + message?: string; + + /** + * Any data associated with the breadcrumb. + */ + data?: BreadcrumbData; +} + +/** + * Utility type which allows for easy extension of base breadcrumb type. + */ +type ImplementsCrumb = U; + +/** + * Type for custom breadcrumbs. + */ +export type CustomBreadcrumb = ImplementsCrumb<{ + class: 'custom'; + timestamp: number; + level: BreadcrumbLevel; + type?: string; + message?: string; + data?: BreadcrumbData; +}>; + +/** + * Type for log breadcrumbs. + */ +export type LogBreadcrumb = ImplementsCrumb<{ + class: 'log'; + timestamp: number; + level: BreadcrumbLevel; + message: string; + data?: BreadcrumbData; +}>; + +/** + * Type for navigation breadcrumbs. + */ +export type NavigationBreadcrumb = ImplementsCrumb<{ + class: 'navigation'; + timestamp: number; + level: 'info'; + type?: string; + data?: { + /** + * The location being navigated from. In a web application this would typically be a URL. + */ + from?: string; + /** + * The location being navigated to. In a web application this would typically be a URL. + */ + to?: string; + }; +}>; + +/** + * Type for feature management breadcrumbs. + */ +export type FeatureManagementBreadcrumb = ImplementsCrumb<{ + class: 'feature-management'; + timestamp: number; + level: 'info'; + type: 'flag-evaluated' | 'flag-detail-changed'; + data?: { + /** + * The flag key. + */ + key?: string; + // Not supporting JSON flags in breadcrumbs. As noted in design we may want to eventually support none of the + // values in the breadcrumb. + /** + * The evaluated value for simple types. + */ + value?: boolean | string | number; + }; +}>; + +/** + * Type for UI breadcrumbs. + */ +export type UiBreadcrumb = ImplementsCrumb<{ + class: 'ui'; + timestamp: number; + level: 'info'; + type: 'click' | 'input'; + message: string; +}>; + +/** + * Type for HTTP breadcrumbs. + */ +export type HttpBreadcrumb = ImplementsCrumb<{ + class: 'http'; + timestamp: number; + level: 'error' | 'info'; // Error if an error status code? + type: 'xhr' | 'fetch'; + data?: { + url?: string; + method?: string; + statusCode: number; + statusText: string; + }; +}>; diff --git a/packages/telemetry/browser-telemetry/src/api/BrowserTelemetry.ts b/packages/telemetry/browser-telemetry/src/api/BrowserTelemetry.ts new file mode 100644 index 0000000000..38c730f88c --- /dev/null +++ b/packages/telemetry/browser-telemetry/src/api/BrowserTelemetry.ts @@ -0,0 +1,28 @@ +import { LDClient, LDInspection } from 'launchdarkly-js-client-sdk'; + +import { Recorder } from './Recorder'; + +/** + * Interface LaunchDarkly browser telemetry. + */ +export interface BrowserTelemetry extends Recorder { + /** + * Get inspectors to use with the LaunchDarkly client. + */ + inspectors(): LDInspection[]; + + // TODO: Consider hooks as well. Hooks will allow registration to happen in a + // single step. + + /** + * Register the telemetry instance with the LaunchDarkly client. + * + * @param client The LaunchDarkly client. + */ + register(client: LDClient): void; + + /** + * Close the telemetry client. + */ + close(): void; +} diff --git a/packages/telemetry/browser-telemetry/src/api/Collector.ts b/packages/telemetry/browser-telemetry/src/api/Collector.ts new file mode 100644 index 0000000000..cb250aac48 --- /dev/null +++ b/packages/telemetry/browser-telemetry/src/api/Collector.ts @@ -0,0 +1,25 @@ +import { Recorder } from './Recorder'; + +/** + * Interface to be implemented by collectors. + * + * Collectors collect data and inform the client of events. + * + * For instance a collector may notify the telemetry instance of HTTP navigation + * or of UI events. A collector can be created independently of a {@link Recorder} + * and can begin collecting immediately. It may queue information until it can + * be registered with a recorder. + */ +export interface Collector { + /** + * Register the collector with a recorder. + * @param recorder Recorder to report events or breadcrumbs to. + * @param sessionId The current session ID. + */ + register(recorder: Recorder, sessionId: string): void; + + /** + * Unregister the collector. It will stop sending events to the recorder. + */ + unregister(): void; +} diff --git a/packages/telemetry/browser-telemetry/src/api/ErrorData.ts b/packages/telemetry/browser-telemetry/src/api/ErrorData.ts new file mode 100644 index 0000000000..0ed03945a9 --- /dev/null +++ b/packages/telemetry/browser-telemetry/src/api/ErrorData.ts @@ -0,0 +1,32 @@ +import { Breadcrumb } from './Breadcrumb'; +import StackTrace from './stack/StackTrace'; + +/** + * Interface representing error data. + */ +export interface ErrorData { + /** + * The type of the error. + */ + + type: string; + /** + * A message associated with the error. + */ + + message: string; + /** + * The stack trace for the error. + */ + + stack: StackTrace; + /** + * Breadcrumbs leading up to the error. + */ + + breadcrumbs: Breadcrumb[]; + /** + * The ID of the session during which the error occurred. + */ + sessionId: string; +} diff --git a/packages/telemetry/browser-telemetry/src/api/Options.ts b/packages/telemetry/browser-telemetry/src/api/Options.ts new file mode 100644 index 0000000000..4238af19b6 --- /dev/null +++ b/packages/telemetry/browser-telemetry/src/api/Options.ts @@ -0,0 +1,146 @@ +import { Collector } from './Collector'; + +/** + * Interface for URL filters. + * + * Given a URL the filter may return a different string to represent that URL. + * This string will be included in the telemetry events instead of the original. + * + * The URL will be filtered by SDK internal filters before this function is called. + * + * To redact a URL entirely return an empty string. + * + * Example: + * customUrlFilter: (url) => { + * if (url.includes('secret')) { + * return '' + * } + * return url; + * } + */ +export interface UrlFilter { + (url: string): string; +} + +export interface HttpBreadCrumbOptions { + /** + * If fetch should be instrumented and breadcrumbs included for fetch requests. + * + * Defaults to true. + */ + instrumentFetch?: boolean; + + /** + * If XMLHttpRequests should be instrumented and breadcrumbs included for XMLHttpRequests. + * + * Defaults to true. + */ + instrumentXhr?: boolean; + + /** + * Customize URL filtering. This will be applied in addition to some baseline filtering included + * which redacts components of LaunchDarkly URLs. + */ + customUrlFilter?: UrlFilter; +} + +export interface StackOptions { + /** + * Configuration that controls how source is captured. + */ + source?: { + /** + * The number of lines captured before the originating line. + * + * Defaults to 3. + */ + beforeLines?: number; + /** + * The number of lines captured after the originating line. + * + * Defaults to 3. + */ + afterLines?: number; + + /** + * The maximum length of source line to include. Lines longer than this will be + * trimmed. + * + * Defaults to 280. + */ + maxLineLength?: number; + }; +} + +/** + * Options for configuring browser telemetry. + */ +export interface Options { + /** + * The maximum number of pending events. Events may be captured before the LaunchDarkly + * SDK is initialized and these are stored until they can be sent. This only affects the + * events captured during initialization. + */ + maxPendingEvents?: number; + /** + * Properties related to automatic breadcrumb collection. + */ + breadcrumbs?: { + /** + * Set the maximum number of breadcrumbs. Defaults to 50. + */ + maxBreadcrumbs?: number; + + /** + * True to enable automatic evaluation breadcrumbs. Defaults to true. + */ + evaluations?: boolean; + + /** + * True to enable flag change breadcrumbs. Defaults to true. + */ + flagChange?: boolean; + + /** + * True to enable click breadcrumbs. Defaults to true. + */ + click?: boolean; + + /** + * True to enable input breadcrumbs for keypresses. Defaults to true. + * + * Input breadcrumbs do not include entered text, just that text was entered. + */ + keyboardInput?: boolean; + + /** + * Controls instrumentation and breadcrumbs for HTTP requests. + * The default is to instrument XMLHttpRequests and fetch requests. + * + * `false` to disable all HTTP breadcrumbs and instrumentation. + * + * Example: + * ``` + * // This would instrument only XmlHttpRequests + * http: { + * instrumentFetch: false + * instrumentXhr: true + * } + * + * // Disable all HTTP instrumentation: + * http: false + * ``` + */ + http?: HttpBreadCrumbOptions | false; + }; + + /** + * Additional, or custom, collectors. + */ + collectors?: Collector[]; + + /** + * Configuration that controls the capture of the stack trace. + */ + stack?: StackOptions; +} diff --git a/packages/telemetry/browser-telemetry/src/api/Recorder.ts b/packages/telemetry/browser-telemetry/src/api/Recorder.ts new file mode 100644 index 0000000000..dbbf21012c --- /dev/null +++ b/packages/telemetry/browser-telemetry/src/api/Recorder.ts @@ -0,0 +1,28 @@ +import { Breadcrumb } from './Breadcrumb'; + +/** + * Interface for capturing telemetry data. + */ +export interface Recorder { + /** + * Capture an error. + * + * @param exception The exception to capture. + */ + captureError(exception: Error): void; + + /** + * Capture an error event. + * + * @param errorEvent The error event to capture. + */ + captureErrorEvent(errorEvent: ErrorEvent): void; + + /** + * Add a breadcrumb. When a capture is performed breadcrumb data can be + * included with it. + * + * @param breadcrumb The breadcrumb to add. + */ + addBreadcrumb(breadcrumb: Breadcrumb): void; +} diff --git a/packages/telemetry/browser-telemetry/src/api/stack/StackFrame.ts b/packages/telemetry/browser-telemetry/src/api/stack/StackFrame.ts new file mode 100644 index 0000000000..9d12f3b02c --- /dev/null +++ b/packages/telemetry/browser-telemetry/src/api/stack/StackFrame.ts @@ -0,0 +1,45 @@ +/** + * Represents a frame in a stack. + */ +export default interface StackFrame { + /** + * The fileName, relative to the project root, of the stack frame. + */ + fileName?: string; + + /** + * The name of the function the frame occurs in. + */ + function?: string; + + /** + * The line number in the file where the frame originates. + */ + line?: number; + + /** + * The column in the file where the frame originates. + */ + col?: number; + + /** + * A number of source code lines before the line the frame originates from. + * + * The number of lines is configurable. + */ + srcBefore?: string[]; + + /** + * The line of source code the frame originates from. + * + * This line may be partial if the line is too large. + */ + srcLine?: string; + + /** + * A number of source code lines after the line the frame originates from. + * + * The number of lines is configurable. + */ + srcAfter?: string[]; +} diff --git a/packages/telemetry/browser-telemetry/src/api/stack/StackTrace.ts b/packages/telemetry/browser-telemetry/src/api/stack/StackTrace.ts new file mode 100644 index 0000000000..783a900402 --- /dev/null +++ b/packages/telemetry/browser-telemetry/src/api/stack/StackTrace.ts @@ -0,0 +1,12 @@ +import StackFrame from './StackFrame'; + +/** + * Represents a stack trace. + */ +export default interface StackTrace { + /** + * Frames associated with the stack. If no frames can be collected, then this + * will be an empty array. + */ + frames: StackFrame[]; +} diff --git a/packages/telemetry/browser-telemetry/src/index.ts b/packages/telemetry/browser-telemetry/src/index.ts new file mode 100644 index 0000000000..14ce0d7f05 --- /dev/null +++ b/packages/telemetry/browser-telemetry/src/index.ts @@ -0,0 +1,7 @@ +/** + * Empty function for typedoc. + */ +export function empty() { + // eslint-disable-next-line no-console + console.log('Hello'); +} diff --git a/packages/telemetry/browser-telemetry/tsconfig.eslint.json b/packages/telemetry/browser-telemetry/tsconfig.eslint.json new file mode 100644 index 0000000000..8241f86c36 --- /dev/null +++ b/packages/telemetry/browser-telemetry/tsconfig.eslint.json @@ -0,0 +1,5 @@ +{ + "extends": "./tsconfig.json", + "include": ["/**/*.ts", "/**/*.tsx"], + "exclude": ["node_modules"] +} diff --git a/packages/telemetry/browser-telemetry/tsconfig.json b/packages/telemetry/browser-telemetry/tsconfig.json new file mode 100644 index 0000000000..3e0991c951 --- /dev/null +++ b/packages/telemetry/browser-telemetry/tsconfig.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "allowSyntheticDefaultImports": true, + "declaration": true, + "declarationMap": true, + "lib": ["ES2017", "dom"], + "module": "ESNext", + "moduleResolution": "node", + "noImplicitOverride": true, + "resolveJsonModule": true, + "rootDir": ".", + "outDir": "dist", + "skipLibCheck": true, + "sourceMap": false, + "strict": true, + "stripInternal": true, + "target": "ES2017", + "types": ["node", "jest"], + "allowJs": true + }, + "include": ["src"], + "exclude": [ + "__tests__", + "dist", + "docs", + "example", + "node_modules", + "babel.config.js", + "setup-jest.js", + "rollup.config.js", + "**/*.test.ts*" + ] +} diff --git a/packages/telemetry/browser-telemetry/tsconfig.ref.json b/packages/telemetry/browser-telemetry/tsconfig.ref.json new file mode 100644 index 0000000000..3925f645be --- /dev/null +++ b/packages/telemetry/browser-telemetry/tsconfig.ref.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "include": ["src/**/*", "package.json", "__tests__/index.test.ts"], + "compilerOptions": { + "composite": true + } +} diff --git a/packages/telemetry/browser-telemetry/tsconfig.test.json b/packages/telemetry/browser-telemetry/tsconfig.test.json new file mode 100644 index 0000000000..6087e302dd --- /dev/null +++ b/packages/telemetry/browser-telemetry/tsconfig.test.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "rootDir": "src", + "outDir": "dist", + "lib": ["es6", "DOM"], + "module": "CommonJS", + "strict": true, + "noImplicitOverride": true, + "sourceMap": true, + "declaration": true, + "declarationMap": true, + "stripInternal": true + }, + "exclude": [ + "vite.config.ts", + "__tests__", + "dist", + "docs", + "example", + "node_modules", + "contract-tests", + "babel.config.js", + "jest.config.js", + "jestSetupFile.ts", + "**/*.test.ts*" + ] +} diff --git a/packages/telemetry/browser-telemetry/tsup.config.ts b/packages/telemetry/browser-telemetry/tsup.config.ts new file mode 100644 index 0000000000..c6238d8764 --- /dev/null +++ b/packages/telemetry/browser-telemetry/tsup.config.ts @@ -0,0 +1,16 @@ +// It is a dev dependency and the linter doesn't understand. +// eslint-disable-next-line import/no-extraneous-dependencies +import { defineConfig } from 'tsup'; + +export default defineConfig({ + entry: { + index: 'src/index.ts', + }, + minify: true, + format: ['esm', 'cjs'], + splitting: false, + sourcemap: false, + clean: true, + dts: true, + metafile: false, +}); diff --git a/packages/telemetry/browser-telemetry/typedoc.json b/packages/telemetry/browser-telemetry/typedoc.json new file mode 100644 index 0000000000..7ac616b544 --- /dev/null +++ b/packages/telemetry/browser-telemetry/typedoc.json @@ -0,0 +1,5 @@ +{ + "extends": ["../../../typedoc.base.json"], + "entryPoints": ["src/index.ts"], + "out": "docs" +} diff --git a/tsconfig.json b/tsconfig.json index 0215fb8fb3..5110eb7541 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -63,6 +63,9 @@ }, { "path": "./packages/sdk/server-ai/tsconfig.ref.json" + }, + { + "path": "./packages/telemetry/browser-telemetry/tsconfig.ref.json" } ] }