@threadplane/telemetry 0.0.47 → 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.
- package/README.md +160 -79
- package/browser/README.md +160 -79
- 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
|
|
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
|
-
|
|
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
|
-
|
|
9
|
-
// Browser (Angular DI provider)
|
|
10
|
-
import { provideThreadplaneTelemetry } from '@threadplane/telemetry/browser';
|
|
17
|
+
## What it does
|
|
11
18
|
|
|
12
|
-
|
|
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
|
-
|
|
23
|
-
|
|
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
|
-
|
|
38
|
+
### Browser events (opt-in, off by default)
|
|
27
39
|
|
|
28
|
-
|
|
40
|
+
Nothing fires unless `provideThreadplaneTelemetry({ enabled: true, ... })` is called in root providers.
|
|
29
41
|
|
|
30
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
70
|
+
Node telemetry is on by default. Any one of the following turns it off entirely.
|
|
71
|
+
|
|
72
|
+
### Environment variables
|
|
50
73
|
|
|
51
|
-
|
|
|
52
|
-
|
|
53
|
-
|
|
|
54
|
-
|
|
|
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
|
-
|
|
79
|
+
### CI auto-disable
|
|
59
80
|
|
|
60
|
-
|
|
81
|
+
The following CI environment variables are detected automatically — no configuration needed:
|
|
61
82
|
|
|
62
|
-
|
|
83
|
+
`CI=1`, `GITHUB_ACTIONS=1`, `CONTINUOUS_INTEGRATION=1`, `BUILDKITE=1`, `CIRCLECI=1`
|
|
63
84
|
|
|
64
|
-
|
|
85
|
+
Any of these being set (truthy) is treated as an opt-out.
|
|
65
86
|
|
|
66
|
-
|
|
87
|
+
### Programmatic opt-out
|
|
67
88
|
|
|
68
|
-
|
|
89
|
+
Call `disableTelemetry()` before any other `@threadplane/*` import in your Node process:
|
|
69
90
|
|
|
70
91
|
```ts
|
|
71
|
-
|
|
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
|
-
|
|
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
|
-
|
|
88
|
-
{
|
|
89
|
-
|
|
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
|
-
|
|
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
|
-
|
|
166
|
+
### Shared utilities
|
|
103
167
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
168
|
+
```ts
|
|
169
|
+
import {
|
|
170
|
+
isTelemetryDisabled,
|
|
171
|
+
getDisableReason,
|
|
172
|
+
getAnonId,
|
|
173
|
+
shouldSample,
|
|
174
|
+
sha256,
|
|
175
|
+
} from '@threadplane/telemetry';
|
|
176
|
+
```
|
|
107
177
|
|
|
108
|
-
|
|
178
|
+
`getDisableReason()` returns `'DO_NOT_TRACK' | 'NGAF_TELEMETRY_DISABLED' | 'CI' | null`.
|
|
109
179
|
|
|
110
|
-
|
|
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
|
-
|
|
182
|
+
### Debugging
|
|
115
183
|
|
|
116
|
-
|
|
184
|
+
Inspect payloads locally without sending them:
|
|
117
185
|
|
|
118
186
|
```bash
|
|
119
|
-
|
|
187
|
+
DEBUG=ngaf:telemetry npm install
|
|
120
188
|
```
|
|
121
189
|
|
|
122
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
207
|
+
### What is intentionally absent
|
|
135
208
|
|
|
136
|
-
- Session replay.
|
|
209
|
+
- Session replay.
|
|
137
210
|
- Cross-session identity stitching.
|
|
138
|
-
- Heuristic PII detection.
|
|
139
|
-
- Default browser writes to
|
|
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
|
-
##
|
|
222
|
+
## License
|
|
142
223
|
|
|
143
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
9
|
-
// Browser (Angular DI provider)
|
|
10
|
-
import { provideThreadplaneTelemetry } from '@threadplane/telemetry/browser';
|
|
17
|
+
## What it does
|
|
11
18
|
|
|
12
|
-
|
|
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
|
-
|
|
23
|
-
|
|
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
|
-
|
|
38
|
+
### Browser events (opt-in, off by default)
|
|
27
39
|
|
|
28
|
-
|
|
40
|
+
Nothing fires unless `provideThreadplaneTelemetry({ enabled: true, ... })` is called in root providers.
|
|
29
41
|
|
|
30
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
70
|
+
Node telemetry is on by default. Any one of the following turns it off entirely.
|
|
71
|
+
|
|
72
|
+
### Environment variables
|
|
50
73
|
|
|
51
|
-
|
|
|
52
|
-
|
|
53
|
-
|
|
|
54
|
-
|
|
|
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
|
-
|
|
79
|
+
### CI auto-disable
|
|
59
80
|
|
|
60
|
-
|
|
81
|
+
The following CI environment variables are detected automatically — no configuration needed:
|
|
61
82
|
|
|
62
|
-
|
|
83
|
+
`CI=1`, `GITHUB_ACTIONS=1`, `CONTINUOUS_INTEGRATION=1`, `BUILDKITE=1`, `CIRCLECI=1`
|
|
63
84
|
|
|
64
|
-
|
|
85
|
+
Any of these being set (truthy) is treated as an opt-out.
|
|
65
86
|
|
|
66
|
-
|
|
87
|
+
### Programmatic opt-out
|
|
67
88
|
|
|
68
|
-
|
|
89
|
+
Call `disableTelemetry()` before any other `@threadplane/*` import in your Node process:
|
|
69
90
|
|
|
70
91
|
```ts
|
|
71
|
-
|
|
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
|
-
|
|
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
|
-
|
|
88
|
-
{
|
|
89
|
-
|
|
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
|
-
|
|
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
|
-
|
|
166
|
+
### Shared utilities
|
|
103
167
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
168
|
+
```ts
|
|
169
|
+
import {
|
|
170
|
+
isTelemetryDisabled,
|
|
171
|
+
getDisableReason,
|
|
172
|
+
getAnonId,
|
|
173
|
+
shouldSample,
|
|
174
|
+
sha256,
|
|
175
|
+
} from '@threadplane/telemetry';
|
|
176
|
+
```
|
|
107
177
|
|
|
108
|
-
|
|
178
|
+
`getDisableReason()` returns `'DO_NOT_TRACK' | 'NGAF_TELEMETRY_DISABLED' | 'CI' | null`.
|
|
109
179
|
|
|
110
|
-
|
|
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
|
-
|
|
182
|
+
### Debugging
|
|
115
183
|
|
|
116
|
-
|
|
184
|
+
Inspect payloads locally without sending them:
|
|
117
185
|
|
|
118
186
|
```bash
|
|
119
|
-
|
|
187
|
+
DEBUG=ngaf:telemetry npm install
|
|
120
188
|
```
|
|
121
189
|
|
|
122
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
207
|
+
### What is intentionally absent
|
|
135
208
|
|
|
136
|
-
- Session replay.
|
|
209
|
+
- Session replay.
|
|
137
210
|
- Cross-session identity stitching.
|
|
138
|
-
- Heuristic PII detection.
|
|
139
|
-
- Default browser writes to
|
|
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
|
-
##
|
|
222
|
+
## License
|
|
142
223
|
|
|
143
|
-
|
|
224
|
+
MIT. See [LICENSE](../../LICENSE).
|