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/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" } ] }