@threadplane/telemetry 0.0.46 → 0.0.49

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 (3) hide show
  1. package/README.md +160 -79
  2. package/browser/README.md +160 -79
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,143 +1,224 @@
1
1
  # @threadplane/telemetry
2
2
 
3
- This README is the public trust contract for `@threadplane/*` telemetry. It is linked
4
- from package install notices and should stay aligned with implementation.
3
+ Transparent, opt-out anonymous usage telemetry for the Threadplane framework. Isomorphic — a Node path (server adapters, postinstall) and a browser path (Angular DI). This README is the public trust contract; it is linked from package install notices and stays aligned with implementation.
5
4
 
6
- ## Imports
5
+ <p align="center">
6
+ <a href="https://www.npmjs.com/package/@threadplane/telemetry">
7
+ <img alt="npm version" src="https://img.shields.io/npm/v/@threadplane%2Ftelemetry?color=6C8EFF&labelColor=080B14&style=flat-square" />
8
+ </a>
9
+ <a href="https://angular.dev">
10
+ <img alt="Angular 20+ | 21" src="https://img.shields.io/badge/Angular-20%2B%20%7C%2021-6C8EFF?labelColor=080B14&style=flat-square" />
11
+ </a>
12
+ <a href="https://opensource.org/licenses/MIT">
13
+ <img alt="MIT" src="https://img.shields.io/badge/License-MIT-6C8EFF?labelColor=080B14&style=flat-square" />
14
+ </a>
15
+ </p>
7
16
 
8
- ```typescript
9
- // Browser (Angular DI provider)
10
- import { provideThreadplaneTelemetry } from '@threadplane/telemetry/browser';
17
+ ## What it does
11
18
 
12
- // Node (server adapters)
13
- import {
14
- captureRuntimeInstanceCreated,
15
- captureRuntimeRequestCreated,
16
- captureStreamStarted,
17
- captureStreamEnded,
18
- captureStreamErrored,
19
- disableTelemetry,
20
- } from '@threadplane/telemetry/node';
19
+ `@threadplane/telemetry` is the single telemetry surface for all `@threadplane/*` packages. It exists so the project can answer "how is Threadplane being used?" without instrumenting browser bundles that ship to end-users.
21
20
 
22
- // Shared utilities (events, env detection, hashing)
23
- import { isTelemetryDisabled, sha256, getAnonId } from '@threadplane/telemetry';
24
- ```
21
+ - **Node telemetry** on by default, opt-out. Fires on install and on server-adapter lifecycle events.
22
+ - **Browser telemetry** — off by default. Never fires unless the consumer explicitly calls `provideThreadplaneTelemetry({ enabled: true })` in their Angular app.
23
+ - **Full opt-out** — one env var or one function call silences everything before any network call occurs.
24
+
25
+ ## What is and is not collected
26
+
27
+ ### Node events (opt-out, on by default)
28
+
29
+ | Event | What is sent |
30
+ |-------|-------------|
31
+ | `ngaf:postinstall` | Package name, package version, Node version, OS, CPU architecture, package manager name/version, workspace/global install flags when npm exposes them, sample weight. Per-process anonymous id. No project path, no raw environment variables, no dependency tree, no installer IP address. |
32
+ | `ngaf:runtime_instance_created` | Which transport, which model provider (string), Angular peer version. No API keys, no endpoint hostnames, no user data. |
33
+ | `ngaf:runtime_request_created` | Transport, request type, provider, model. No prompts, thread IDs, assistant IDs, endpoint URLs, or headers. |
34
+ | `ngaf:stream_started` | Provider, model name. No prompts, no message content. |
35
+ | `ngaf:stream_ended` | Provider, model name, duration. No prompts, no completions, no message content. |
36
+ | `ngaf:stream_errored` | Provider, model name, error class. No prompts, no completions, no message content. |
25
37
 
26
- ## What this package is
38
+ ### Browser events (opt-in, off by default)
27
39
 
28
- The single telemetry surface for `@threadplane/*`. It exists so we can answer "how is Threadplane being used?" without instrumenting browser packages that ship to end-users.
40
+ Nothing fires unless `provideThreadplaneTelemetry({ enabled: true, ... })` is called in root providers.
29
41
 
30
- ## What is and isn't telemetered
42
+ | Event | What is sent |
43
+ |-------|-------------|
44
+ | `ngaf:browser_provided` | Telemetry initialized; surface name, sample weight. Anonymous, no user data. |
45
+ | `ngaf:browser_chat_init` | Chat component initialized; surface name, sample weight. Anonymous, no message content. |
31
46
 
32
- **Telemetered by default (Node, opt-out):**
33
- - `ngaf:postinstall` — fires once per dependency/global install of a published `@threadplane/*` package. Properties: package name, package version, Node version, OS, CPU architecture, package manager name/version, installer-reported Node/OS/architecture, workspace/global install flags when npm exposes them, sample weight. It uses a per-process anonymous id. No project path, no raw environment variables, no dependency tree, no installer IP address.
34
- - `ngaf:runtime_instance_created` — server adapters (LangGraph, AG-UI) call this when they spin up. Properties: which transport, which model provider (string), Angular peer version. **No API keys**, no endpoint hostnames, no user data.
35
- - `ngaf:runtime_request_created` — server adapters call this when they create a transport request. Properties: transport, request type, provider, model. No prompts, thread IDs, assistant IDs, endpoint URLs, or headers.
36
- - `ngaf:stream_started` / `ngaf:stream_ended` / `ngaf:stream_errored` — per-request lifecycle on server adapters. Properties: provider, model name, duration, error class. No prompts, no completions, no message content.
47
+ Browser-side runtime lifecycle events (`ngaf:runtime_instance_created`, `ngaf:runtime_request_created`, `ngaf:stream_started`, `ngaf:stream_ended`, `ngaf:stream_errored`) may also be sent when the app captures them explicitly. Same payload constraints as Node.
37
48
 
38
- **Telemetered only on explicit opt-in (Browser):**
39
- - Nothing fires unless the consumer calls `provideThreadplaneTelemetry({ enabled: true, sink })` or `provideThreadplaneTelemetry({ enabled: true, endpoint })` in their root providers.
40
- - When opted in: `ngaf:browser_provided`, `ngaf:browser_chat_init`, and browser-side runtime lifecycle events explicitly captured by the app (`ngaf:runtime_instance_created`, `ngaf:runtime_request_created`, `ngaf:stream_started`, `ngaf:stream_ended`, `ngaf:stream_errored`). Anonymous, no message content.
49
+ ### Never collected by anyone, at any time
41
50
 
42
- **Never telemetered (by anyone, at any time):**
43
51
  - Message content (user prompts, model completions, tool call inputs/outputs).
44
- - Personally identifiable information beyond `email_domain` on explicit server conversion events on the website.
52
+ - Personally identifiable information.
45
53
  - API keys, vendor credentials, project paths, environment variables.
46
54
 
55
+ ## Install
56
+
57
+ ```bash
58
+ npm install @threadplane/telemetry
59
+ ```
60
+
61
+ Both peer dependencies are optional:
62
+
63
+ ```
64
+ @angular/core ^20.0.0 || ^21.0.0 # required only for the ./browser Angular service
65
+ posthog-js ^1.372.0 # required only when using PostHog capture
66
+ ```
67
+
47
68
  ## Opt-out
48
69
 
49
- Node telemetry is on by default. Three ways to opt out — any one turns it off.
70
+ Node telemetry is on by default. Any one of the following turns it off entirely.
71
+
72
+ ### Environment variables
50
73
 
51
- | Method | How |
52
- |--------|-----|
53
- | Cross-vendor env var | `DO_NOT_TRACK=1` or `DO_NOT_TRACK=true` |
54
- | npm config env var | `npm_config_do_not_track=true` |
55
- | Package env var | `NGAF_TELEMETRY_DISABLED=1` or `NGAF_TELEMETRY_DISABLED=true` |
56
- | Programmatic | `import { disableTelemetry } from '@threadplane/telemetry/node'; disableTelemetry();` before any other `@threadplane/*` import |
74
+ | Variable | Value | Notes |
75
+ |----------|-------|-------|
76
+ | `NGAF_TELEMETRY_DISABLED` | `1` or `true` | Package-level kill-switch |
77
+ | `DO_NOT_TRACK` | `1` or `true` | Cross-vendor standard; `npm_config_do_not_track` and `NPM_CONFIG_DO_NOT_TRACK` are also respected |
57
78
 
58
- CI environments (`CI=true`, `GITHUB_ACTIONS=true`, etc.) are auto-detected and treated as opt-out by default.
79
+ ### CI auto-disable
59
80
 
60
- Local top-level installs are skipped by default. Dependency installs and global installs are eligible unless opted out.
81
+ The following CI environment variables are detected automatically no configuration needed:
61
82
 
62
- The postinstall script prints a single line on stdout only when the install ping was actually accepted by the ingest endpoint. The line is suppressed in CI.
83
+ `CI=1`, `GITHUB_ACTIONS=1`, `CONTINUOUS_INTEGRATION=1`, `BUILDKITE=1`, `CIRCLECI=1`
63
84
 
64
- To inspect the install payload locally, run with `DEBUG=ngaf:telemetry`.
85
+ Any of these being set (truthy) is treated as an opt-out.
65
86
 
66
- ## Opt-in (browser)
87
+ ### Programmatic opt-out
67
88
 
68
- Browser telemetry is **off by default** and never fires from the library itself. To enable in your Angular app:
89
+ Call `disableTelemetry()` before any other `@threadplane/*` import in your Node process:
69
90
 
70
91
  ```ts
71
- // app.config.ts (or wherever you bootstrap)
92
+ import { disableTelemetry } from '@threadplane/telemetry/node';
93
+ disableTelemetry();
94
+ ```
95
+
96
+ ### Sampling
97
+
98
+ Default sample rate is **1.0** (100%). Reduce it via:
99
+
100
+ ```bash
101
+ NGAF_TELEMETRY_SAMPLE_RATE=0.1 # sample 10% of events
102
+ ```
103
+
104
+ Every event carries a `sample_weight` property so de-sampling at query time works correctly.
105
+
106
+ ### Ingest endpoint override
107
+
108
+ Redirect all Node telemetry to your own endpoint:
109
+
110
+ ```bash
111
+ NGAF_TELEMETRY_INGEST_URL=https://telemetry.acme-internal.example.com/api/ingest
112
+ ```
113
+
114
+ The default ingest (when unset) is a thin proxy at `https://threadplane.ai/api/ingest` that accepts the `@threadplane/telemetry` JSON payload, forwards `ngaf:*` events to the project PostHog instance, and does not forward installer IP addresses. Source lives in `apps/website/src/app/api/ingest/`.
115
+
116
+ ## Usage
117
+
118
+ ### Node — server adapters
119
+
120
+ ```ts
121
+ import {
122
+ captureRuntimeInstanceCreated,
123
+ captureRuntimeRequestCreated,
124
+ captureStreamStarted,
125
+ captureStreamEnded,
126
+ captureStreamErrored,
127
+ captureEvent,
128
+ capturePostinstall,
129
+ disableTelemetry,
130
+ } from '@threadplane/telemetry/node';
131
+ ```
132
+
133
+ ### Browser — Angular DI
134
+
135
+ Enable browser telemetry in your Angular root providers:
136
+
137
+ ```ts
138
+ // app.config.ts
72
139
  import { provideThreadplaneTelemetry } from '@threadplane/telemetry/browser';
73
140
 
74
141
  export const appConfig: ApplicationConfig = {
75
142
  providers: [
76
- // ...
77
143
  provideThreadplaneTelemetry({
78
144
  enabled: true,
79
- endpoint: '/api/telemetry',
145
+ endpoint: '/api/telemetry', // route through your own backend
80
146
  }),
81
147
  ],
82
148
  };
83
149
  ```
84
150
 
85
- The endpoint receives neutral JSON:
151
+ You can also pass `sink: async ({ event, properties }) => { ... }` to route events through your own analytics client. Legacy `posthogKey` / `posthogHost` options still work for existing adopters, but new code should prefer `sink` or `endpoint` to keep the API vendor-neutral.
152
+
153
+ Inject the service directly when you need to capture events:
154
+
155
+ ```ts
156
+ import { ThreadplaneTelemetryService } from '@threadplane/telemetry/browser';
86
157
 
87
- ```json
88
- {
89
- "event": "ngaf:stream_started",
90
- "distinctId": "browser:<ephemeral-id>",
91
- "properties": {
92
- "surface": "my_app",
93
- "sample_weight": 1
94
- }
158
+ @Injectable()
159
+ export class MyService {
160
+ private telemetry = inject(ThreadplaneTelemetryService);
95
161
  }
96
162
  ```
97
163
 
98
- You can also pass `sink: async ({ event, properties }) => { ... }` and route events through your own analytics client. Legacy `posthogKey` / `posthogHost` options still work for existing adopters, but new app code should prefer `sink` or `endpoint` so the public API is vendor-neutral.
99
-
100
- If you don't call `provideThreadplaneTelemetry({ enabled: true })`, every telemetry helper in `@threadplane/*` browser packages no-ops. No network calls, ever.
164
+ If `provideThreadplaneTelemetry({ enabled: true })` is never called, every telemetry helper in `@threadplane/*` browser packages no-ops. No network calls, ever.
101
165
 
102
- ## Sampling
166
+ ### Shared utilities
103
167
 
104
- - Default sample rate: **1.0** (100%) at current scale.
105
- - Configurable via `NGAF_TELEMETRY_SAMPLE_RATE` env var (Node).
106
- - Every event carries a `sample_weight` property so future de-sampling at query time works correctly.
168
+ ```ts
169
+ import {
170
+ isTelemetryDisabled,
171
+ getDisableReason,
172
+ getAnonId,
173
+ shouldSample,
174
+ sha256,
175
+ } from '@threadplane/telemetry';
176
+ ```
107
177
 
108
- ## Anonymous id strategy
178
+ `getDisableReason()` returns `'DO_NOT_TRACK' | 'NGAF_TELEMETRY_DISABLED' | 'CI' | null`.
109
179
 
110
- - Per-process UUID (`anon_<uuid>`), regenerated every Node process boot.
111
- - No persistence across restarts. No persistent identifier.
112
- - Browser opt-in endpoint delivery uses an ephemeral per-service-instance id (`browser:<uuid>`). It is not written to localStorage or cookies.
180
+ ## Reliability and transparency
113
181
 
114
- ## Self-hosting
182
+ ### Debugging
115
183
 
116
- Enterprise users can redirect Node telemetry to their own ingest:
184
+ Inspect payloads locally without sending them:
117
185
 
118
186
  ```bash
119
- NGAF_TELEMETRY_INGEST_URL=https://telemetry.acme-internal.example.com/api/ingest
187
+ DEBUG=ngaf:telemetry npm install
120
188
  ```
121
189
 
122
- Default ingest (when env var is unset) is a thin proxy on the Threadplane website (`https://threadplane.ai/api/ingest`) that accepts the `@threadplane/telemetry` JSON payload and forwards `ngaf:*` events to our PostHog project without forwarding installer IP addresses. Source of the proxy lives in `apps/website/src/app/api/ingest/`.
190
+ `ngaf:telemetry` is the debug namespace it is not an event name and is never sent to the ingest endpoint.
191
+
192
+ ### Anonymous id strategy
193
+
194
+ - Node: per-process UUID (`anon_<uuid>`), regenerated every process boot. No persistence across restarts.
195
+ - Browser: ephemeral per-service-instance id (`browser:<uuid>`). Not written to localStorage or cookies.
123
196
 
124
- ## Verifying telemetry is silent
197
+ ### Trust test
125
198
 
126
199
  The `@threadplane/telemetry/browser` unit test suite includes a permanent trust test:
127
200
 
128
201
  ```
129
- test('no network call occurs when provideThreadplaneTelemetry is never called', ...)
202
+ test('no posthog-js import when provideThreadplaneTelemetry is never called', ...)
130
203
  ```
131
204
 
132
205
  If this test ever fails, the trust contract has been violated and the build blocks.
133
206
 
134
- ## What's intentionally not in this package
207
+ ### What is intentionally absent
135
208
 
136
- - Session replay. (Not in Phase 0–1.)
209
+ - Session replay.
137
210
  - Cross-session identity stitching.
138
- - Heuristic PII detection. (Redaction is explicit and config-driven only.)
139
- - Default browser writes to anyone's PostHog instance — including ours — without explicit configuration.
211
+ - Heuristic PII detection. Redaction is explicit and config-driven only.
212
+ - Default browser writes to any PostHog instance — including the project's — without explicit configuration.
213
+
214
+ ### Reporting a security issue
215
+
216
+ If you observe telemetry that contradicts this contract, open an issue at https://github.com/cacheplane/angular-agent-framework/issues tagged `security`. It is treated as P0.
217
+
218
+ ## Release cadence
219
+
220
+ This package follows patch-only releases (`0.0.x`). Even breaking changes increment the patch version at current scale.
140
221
 
141
- ## Reporting an issue
222
+ ## License
142
223
 
143
- If you observe telemetry that you believe contradicts this contract, please open an issue at https://github.com/cacheplane/angular-agent-framework/issues security-tagged. We treat it as a P0.
224
+ MIT. See [LICENSE](../../LICENSE).
package/browser/README.md CHANGED
@@ -1,143 +1,224 @@
1
1
  # @threadplane/telemetry
2
2
 
3
- This README is the public trust contract for `@threadplane/*` telemetry. It is linked
4
- from package install notices and should stay aligned with implementation.
3
+ Transparent, opt-out anonymous usage telemetry for the Threadplane framework. Isomorphic — a Node path (server adapters, postinstall) and a browser path (Angular DI). This README is the public trust contract; it is linked from package install notices and stays aligned with implementation.
5
4
 
6
- ## Imports
5
+ <p align="center">
6
+ <a href="https://www.npmjs.com/package/@threadplane/telemetry">
7
+ <img alt="npm version" src="https://img.shields.io/npm/v/@threadplane%2Ftelemetry?color=6C8EFF&labelColor=080B14&style=flat-square" />
8
+ </a>
9
+ <a href="https://angular.dev">
10
+ <img alt="Angular 20+ | 21" src="https://img.shields.io/badge/Angular-20%2B%20%7C%2021-6C8EFF?labelColor=080B14&style=flat-square" />
11
+ </a>
12
+ <a href="https://opensource.org/licenses/MIT">
13
+ <img alt="MIT" src="https://img.shields.io/badge/License-MIT-6C8EFF?labelColor=080B14&style=flat-square" />
14
+ </a>
15
+ </p>
7
16
 
8
- ```typescript
9
- // Browser (Angular DI provider)
10
- import { provideThreadplaneTelemetry } from '@threadplane/telemetry/browser';
17
+ ## What it does
11
18
 
12
- // Node (server adapters)
13
- import {
14
- captureRuntimeInstanceCreated,
15
- captureRuntimeRequestCreated,
16
- captureStreamStarted,
17
- captureStreamEnded,
18
- captureStreamErrored,
19
- disableTelemetry,
20
- } from '@threadplane/telemetry/node';
19
+ `@threadplane/telemetry` is the single telemetry surface for all `@threadplane/*` packages. It exists so the project can answer "how is Threadplane being used?" without instrumenting browser bundles that ship to end-users.
21
20
 
22
- // Shared utilities (events, env detection, hashing)
23
- import { isTelemetryDisabled, sha256, getAnonId } from '@threadplane/telemetry';
24
- ```
21
+ - **Node telemetry** on by default, opt-out. Fires on install and on server-adapter lifecycle events.
22
+ - **Browser telemetry** — off by default. Never fires unless the consumer explicitly calls `provideThreadplaneTelemetry({ enabled: true })` in their Angular app.
23
+ - **Full opt-out** — one env var or one function call silences everything before any network call occurs.
24
+
25
+ ## What is and is not collected
26
+
27
+ ### Node events (opt-out, on by default)
28
+
29
+ | Event | What is sent |
30
+ |-------|-------------|
31
+ | `ngaf:postinstall` | Package name, package version, Node version, OS, CPU architecture, package manager name/version, workspace/global install flags when npm exposes them, sample weight. Per-process anonymous id. No project path, no raw environment variables, no dependency tree, no installer IP address. |
32
+ | `ngaf:runtime_instance_created` | Which transport, which model provider (string), Angular peer version. No API keys, no endpoint hostnames, no user data. |
33
+ | `ngaf:runtime_request_created` | Transport, request type, provider, model. No prompts, thread IDs, assistant IDs, endpoint URLs, or headers. |
34
+ | `ngaf:stream_started` | Provider, model name. No prompts, no message content. |
35
+ | `ngaf:stream_ended` | Provider, model name, duration. No prompts, no completions, no message content. |
36
+ | `ngaf:stream_errored` | Provider, model name, error class. No prompts, no completions, no message content. |
25
37
 
26
- ## What this package is
38
+ ### Browser events (opt-in, off by default)
27
39
 
28
- The single telemetry surface for `@threadplane/*`. It exists so we can answer "how is Threadplane being used?" without instrumenting browser packages that ship to end-users.
40
+ Nothing fires unless `provideThreadplaneTelemetry({ enabled: true, ... })` is called in root providers.
29
41
 
30
- ## What is and isn't telemetered
42
+ | Event | What is sent |
43
+ |-------|-------------|
44
+ | `ngaf:browser_provided` | Telemetry initialized; surface name, sample weight. Anonymous, no user data. |
45
+ | `ngaf:browser_chat_init` | Chat component initialized; surface name, sample weight. Anonymous, no message content. |
31
46
 
32
- **Telemetered by default (Node, opt-out):**
33
- - `ngaf:postinstall` — fires once per dependency/global install of a published `@threadplane/*` package. Properties: package name, package version, Node version, OS, CPU architecture, package manager name/version, installer-reported Node/OS/architecture, workspace/global install flags when npm exposes them, sample weight. It uses a per-process anonymous id. No project path, no raw environment variables, no dependency tree, no installer IP address.
34
- - `ngaf:runtime_instance_created` — server adapters (LangGraph, AG-UI) call this when they spin up. Properties: which transport, which model provider (string), Angular peer version. **No API keys**, no endpoint hostnames, no user data.
35
- - `ngaf:runtime_request_created` — server adapters call this when they create a transport request. Properties: transport, request type, provider, model. No prompts, thread IDs, assistant IDs, endpoint URLs, or headers.
36
- - `ngaf:stream_started` / `ngaf:stream_ended` / `ngaf:stream_errored` — per-request lifecycle on server adapters. Properties: provider, model name, duration, error class. No prompts, no completions, no message content.
47
+ Browser-side runtime lifecycle events (`ngaf:runtime_instance_created`, `ngaf:runtime_request_created`, `ngaf:stream_started`, `ngaf:stream_ended`, `ngaf:stream_errored`) may also be sent when the app captures them explicitly. Same payload constraints as Node.
37
48
 
38
- **Telemetered only on explicit opt-in (Browser):**
39
- - Nothing fires unless the consumer calls `provideThreadplaneTelemetry({ enabled: true, sink })` or `provideThreadplaneTelemetry({ enabled: true, endpoint })` in their root providers.
40
- - When opted in: `ngaf:browser_provided`, `ngaf:browser_chat_init`, and browser-side runtime lifecycle events explicitly captured by the app (`ngaf:runtime_instance_created`, `ngaf:runtime_request_created`, `ngaf:stream_started`, `ngaf:stream_ended`, `ngaf:stream_errored`). Anonymous, no message content.
49
+ ### Never collected by anyone, at any time
41
50
 
42
- **Never telemetered (by anyone, at any time):**
43
51
  - Message content (user prompts, model completions, tool call inputs/outputs).
44
- - Personally identifiable information beyond `email_domain` on explicit server conversion events on the website.
52
+ - Personally identifiable information.
45
53
  - API keys, vendor credentials, project paths, environment variables.
46
54
 
55
+ ## Install
56
+
57
+ ```bash
58
+ npm install @threadplane/telemetry
59
+ ```
60
+
61
+ Both peer dependencies are optional:
62
+
63
+ ```
64
+ @angular/core ^20.0.0 || ^21.0.0 # required only for the ./browser Angular service
65
+ posthog-js ^1.372.0 # required only when using PostHog capture
66
+ ```
67
+
47
68
  ## Opt-out
48
69
 
49
- Node telemetry is on by default. Three ways to opt out — any one turns it off.
70
+ Node telemetry is on by default. Any one of the following turns it off entirely.
71
+
72
+ ### Environment variables
50
73
 
51
- | Method | How |
52
- |--------|-----|
53
- | Cross-vendor env var | `DO_NOT_TRACK=1` or `DO_NOT_TRACK=true` |
54
- | npm config env var | `npm_config_do_not_track=true` |
55
- | Package env var | `NGAF_TELEMETRY_DISABLED=1` or `NGAF_TELEMETRY_DISABLED=true` |
56
- | Programmatic | `import { disableTelemetry } from '@threadplane/telemetry/node'; disableTelemetry();` before any other `@threadplane/*` import |
74
+ | Variable | Value | Notes |
75
+ |----------|-------|-------|
76
+ | `NGAF_TELEMETRY_DISABLED` | `1` or `true` | Package-level kill-switch |
77
+ | `DO_NOT_TRACK` | `1` or `true` | Cross-vendor standard; `npm_config_do_not_track` and `NPM_CONFIG_DO_NOT_TRACK` are also respected |
57
78
 
58
- CI environments (`CI=true`, `GITHUB_ACTIONS=true`, etc.) are auto-detected and treated as opt-out by default.
79
+ ### CI auto-disable
59
80
 
60
- Local top-level installs are skipped by default. Dependency installs and global installs are eligible unless opted out.
81
+ The following CI environment variables are detected automatically no configuration needed:
61
82
 
62
- The postinstall script prints a single line on stdout only when the install ping was actually accepted by the ingest endpoint. The line is suppressed in CI.
83
+ `CI=1`, `GITHUB_ACTIONS=1`, `CONTINUOUS_INTEGRATION=1`, `BUILDKITE=1`, `CIRCLECI=1`
63
84
 
64
- To inspect the install payload locally, run with `DEBUG=ngaf:telemetry`.
85
+ Any of these being set (truthy) is treated as an opt-out.
65
86
 
66
- ## Opt-in (browser)
87
+ ### Programmatic opt-out
67
88
 
68
- Browser telemetry is **off by default** and never fires from the library itself. To enable in your Angular app:
89
+ Call `disableTelemetry()` before any other `@threadplane/*` import in your Node process:
69
90
 
70
91
  ```ts
71
- // app.config.ts (or wherever you bootstrap)
92
+ import { disableTelemetry } from '@threadplane/telemetry/node';
93
+ disableTelemetry();
94
+ ```
95
+
96
+ ### Sampling
97
+
98
+ Default sample rate is **1.0** (100%). Reduce it via:
99
+
100
+ ```bash
101
+ NGAF_TELEMETRY_SAMPLE_RATE=0.1 # sample 10% of events
102
+ ```
103
+
104
+ Every event carries a `sample_weight` property so de-sampling at query time works correctly.
105
+
106
+ ### Ingest endpoint override
107
+
108
+ Redirect all Node telemetry to your own endpoint:
109
+
110
+ ```bash
111
+ NGAF_TELEMETRY_INGEST_URL=https://telemetry.acme-internal.example.com/api/ingest
112
+ ```
113
+
114
+ The default ingest (when unset) is a thin proxy at `https://threadplane.ai/api/ingest` that accepts the `@threadplane/telemetry` JSON payload, forwards `ngaf:*` events to the project PostHog instance, and does not forward installer IP addresses. Source lives in `apps/website/src/app/api/ingest/`.
115
+
116
+ ## Usage
117
+
118
+ ### Node — server adapters
119
+
120
+ ```ts
121
+ import {
122
+ captureRuntimeInstanceCreated,
123
+ captureRuntimeRequestCreated,
124
+ captureStreamStarted,
125
+ captureStreamEnded,
126
+ captureStreamErrored,
127
+ captureEvent,
128
+ capturePostinstall,
129
+ disableTelemetry,
130
+ } from '@threadplane/telemetry/node';
131
+ ```
132
+
133
+ ### Browser — Angular DI
134
+
135
+ Enable browser telemetry in your Angular root providers:
136
+
137
+ ```ts
138
+ // app.config.ts
72
139
  import { provideThreadplaneTelemetry } from '@threadplane/telemetry/browser';
73
140
 
74
141
  export const appConfig: ApplicationConfig = {
75
142
  providers: [
76
- // ...
77
143
  provideThreadplaneTelemetry({
78
144
  enabled: true,
79
- endpoint: '/api/telemetry',
145
+ endpoint: '/api/telemetry', // route through your own backend
80
146
  }),
81
147
  ],
82
148
  };
83
149
  ```
84
150
 
85
- The endpoint receives neutral JSON:
151
+ You can also pass `sink: async ({ event, properties }) => { ... }` to route events through your own analytics client. Legacy `posthogKey` / `posthogHost` options still work for existing adopters, but new code should prefer `sink` or `endpoint` to keep the API vendor-neutral.
152
+
153
+ Inject the service directly when you need to capture events:
154
+
155
+ ```ts
156
+ import { ThreadplaneTelemetryService } from '@threadplane/telemetry/browser';
86
157
 
87
- ```json
88
- {
89
- "event": "ngaf:stream_started",
90
- "distinctId": "browser:<ephemeral-id>",
91
- "properties": {
92
- "surface": "my_app",
93
- "sample_weight": 1
94
- }
158
+ @Injectable()
159
+ export class MyService {
160
+ private telemetry = inject(ThreadplaneTelemetryService);
95
161
  }
96
162
  ```
97
163
 
98
- You can also pass `sink: async ({ event, properties }) => { ... }` and route events through your own analytics client. Legacy `posthogKey` / `posthogHost` options still work for existing adopters, but new app code should prefer `sink` or `endpoint` so the public API is vendor-neutral.
99
-
100
- If you don't call `provideThreadplaneTelemetry({ enabled: true })`, every telemetry helper in `@threadplane/*` browser packages no-ops. No network calls, ever.
164
+ If `provideThreadplaneTelemetry({ enabled: true })` is never called, every telemetry helper in `@threadplane/*` browser packages no-ops. No network calls, ever.
101
165
 
102
- ## Sampling
166
+ ### Shared utilities
103
167
 
104
- - Default sample rate: **1.0** (100%) at current scale.
105
- - Configurable via `NGAF_TELEMETRY_SAMPLE_RATE` env var (Node).
106
- - Every event carries a `sample_weight` property so future de-sampling at query time works correctly.
168
+ ```ts
169
+ import {
170
+ isTelemetryDisabled,
171
+ getDisableReason,
172
+ getAnonId,
173
+ shouldSample,
174
+ sha256,
175
+ } from '@threadplane/telemetry';
176
+ ```
107
177
 
108
- ## Anonymous id strategy
178
+ `getDisableReason()` returns `'DO_NOT_TRACK' | 'NGAF_TELEMETRY_DISABLED' | 'CI' | null`.
109
179
 
110
- - Per-process UUID (`anon_<uuid>`), regenerated every Node process boot.
111
- - No persistence across restarts. No persistent identifier.
112
- - Browser opt-in endpoint delivery uses an ephemeral per-service-instance id (`browser:<uuid>`). It is not written to localStorage or cookies.
180
+ ## Reliability and transparency
113
181
 
114
- ## Self-hosting
182
+ ### Debugging
115
183
 
116
- Enterprise users can redirect Node telemetry to their own ingest:
184
+ Inspect payloads locally without sending them:
117
185
 
118
186
  ```bash
119
- NGAF_TELEMETRY_INGEST_URL=https://telemetry.acme-internal.example.com/api/ingest
187
+ DEBUG=ngaf:telemetry npm install
120
188
  ```
121
189
 
122
- Default ingest (when env var is unset) is a thin proxy on the Threadplane website (`https://threadplane.ai/api/ingest`) that accepts the `@threadplane/telemetry` JSON payload and forwards `ngaf:*` events to our PostHog project without forwarding installer IP addresses. Source of the proxy lives in `apps/website/src/app/api/ingest/`.
190
+ `ngaf:telemetry` is the debug namespace it is not an event name and is never sent to the ingest endpoint.
191
+
192
+ ### Anonymous id strategy
193
+
194
+ - Node: per-process UUID (`anon_<uuid>`), regenerated every process boot. No persistence across restarts.
195
+ - Browser: ephemeral per-service-instance id (`browser:<uuid>`). Not written to localStorage or cookies.
123
196
 
124
- ## Verifying telemetry is silent
197
+ ### Trust test
125
198
 
126
199
  The `@threadplane/telemetry/browser` unit test suite includes a permanent trust test:
127
200
 
128
201
  ```
129
- test('no network call occurs when provideThreadplaneTelemetry is never called', ...)
202
+ test('no posthog-js import when provideThreadplaneTelemetry is never called', ...)
130
203
  ```
131
204
 
132
205
  If this test ever fails, the trust contract has been violated and the build blocks.
133
206
 
134
- ## What's intentionally not in this package
207
+ ### What is intentionally absent
135
208
 
136
- - Session replay. (Not in Phase 0–1.)
209
+ - Session replay.
137
210
  - Cross-session identity stitching.
138
- - Heuristic PII detection. (Redaction is explicit and config-driven only.)
139
- - Default browser writes to anyone's PostHog instance — including ours — without explicit configuration.
211
+ - Heuristic PII detection. Redaction is explicit and config-driven only.
212
+ - Default browser writes to any PostHog instance — including the project's — without explicit configuration.
213
+
214
+ ### Reporting a security issue
215
+
216
+ If you observe telemetry that contradicts this contract, open an issue at https://github.com/cacheplane/angular-agent-framework/issues tagged `security`. It is treated as P0.
217
+
218
+ ## Release cadence
219
+
220
+ This package follows patch-only releases (`0.0.x`). Even breaking changes increment the patch version at current scale.
140
221
 
141
- ## Reporting an issue
222
+ ## License
142
223
 
143
- If you observe telemetry that you believe contradicts this contract, please open an issue at https://github.com/cacheplane/angular-agent-framework/issues security-tagged. We treat it as a P0.
224
+ MIT. See [LICENSE](../../LICENSE).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@threadplane/telemetry",
3
- "version": "0.0.46",
3
+ "version": "0.0.49",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public"