@scope-analytics/node 0.1.0
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 +129 -0
- package/dist/index.cjs +921 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +211 -0
- package/dist/index.d.ts +211 -0
- package/dist/index.js +893 -0
- package/dist/index.js.map +1 -0
- package/dist/register.cjs +895 -0
- package/dist/register.cjs.map +1 -0
- package/dist/register.d.cts +2 -0
- package/dist/register.d.ts +2 -0
- package/dist/register.js +892 -0
- package/dist/register.js.map +1 -0
- package/package.json +58 -0
package/README.md
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# @scope-analytics/node — Scope Node.js backend SDK
|
|
2
|
+
|
|
3
|
+
Zero-code analytics for AI products. Captures your server-side LLM calls (and ships them to
|
|
4
|
+
Scope as universal events) by **wrapping OpenTelemetry + Arize OpenInference** rather than
|
|
5
|
+
reinventing provider patching. Wire-compatible with the Python SDK (`scope_analytics`) — both
|
|
6
|
+
emit the same universal event schema, so one Scope project can mix Python and Node services.
|
|
7
|
+
|
|
8
|
+
> **Status: in development — not yet published to npm.** Auto-captures **four providers** today:
|
|
9
|
+
> **OpenAI** + **Anthropic** (Arize OpenInference drop-ins), **Google Gemini** (`@google/genai`, a
|
|
10
|
+
> Scope-authored instrumentation — no drop-in exists), and the **Vercel AI SDK** (`ai`, zero-code — Scope
|
|
11
|
+
> auto-enables its telemetry and translates the native spans; see "Supported providers"). Also shipped: the
|
|
12
|
+
> OpenTelemetry → Scope exporter (handles chat-completions, the Responses API, and multimodal content
|
|
13
|
+
> shapes), the `--import` bootstrap, config + deploy/`git_sha` resolution, `AsyncLocalStorage`
|
|
14
|
+
> session/user/thread/url context, raw-by-default capture with an opt-in credential scrub (Python
|
|
15
|
+
> parity), and live call-and-capture + version-pin tests per provider, plus dual ESM+CJS builds.
|
|
16
|
+
> **Coming next:** framework middleware (Express/Fastify/Hono/Nest/Next route handlers), the
|
|
17
|
+
> Edge-runtime manual wrapper, an `identify()` helper, per-field size caps, and npm publish.
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install @scope-analytics/node
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Set your project **secret** key (from the Scope dashboard) in the environment:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
export SCOPE_API_KEY="sk_live_…" # or sk_test_…
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Use it (two paths, both zero app-code for capture)
|
|
32
|
+
|
|
33
|
+
### 1. Zero-code bootstrap (recommended)
|
|
34
|
+
|
|
35
|
+
Start your server with the tracer pre-loaded — no code change, just a flag. The bootstrap must
|
|
36
|
+
load before your app imports `openai`, which `--import` guarantees:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
NODE_OPTIONS="--import @scope-analytics/node/register" node server.js
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 2. Explicit init
|
|
43
|
+
|
|
44
|
+
Call `init()` once at the very top of your entrypoint, **before** importing `openai`:
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import { init } from '@scope-analytics/node';
|
|
48
|
+
init(); // reads SCOPE_API_KEY / SCOPE_ENDPOINT from the env (or pass { apiKey, endpoint })
|
|
49
|
+
|
|
50
|
+
import OpenAI from 'openai';
|
|
51
|
+
// …every OpenAI call from here on is captured and shipped to Scope.
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Session stitching (optional, recommended)
|
|
55
|
+
|
|
56
|
+
Wrap each request so the LLM calls inside it are attributed to a user/session — this is what
|
|
57
|
+
lets Scope stitch a user's activity across your frontend, backend, and LLM layers:
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import { runWithContext } from '@scope-analytics/node';
|
|
61
|
+
|
|
62
|
+
app.use((req, res, next) => {
|
|
63
|
+
runWithContext({ sessionId: req.headers['x-scope-session-id'], userId: req.user?.id }, next);
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Without it, backend LLM calls get a `temp_…` session (captured, but not tied to a user).
|
|
68
|
+
|
|
69
|
+
## Supported providers
|
|
70
|
+
|
|
71
|
+
Auto-captured with no app-code change: **OpenAI** (`openai`), **Anthropic** (`@anthropic-ai/sdk`), and
|
|
72
|
+
**Google Gemini** (`@google/genai`) — plus the entire **OpenAI-compatible ecosystem** (Groq, Together,
|
|
73
|
+
OpenRouter, DeepSeek, xAI, Azure OpenAI, Ollama, vLLM, …) reached through the `openai` SDK with a custom
|
|
74
|
+
`base_url`, captured at the call site so the base URL is irrelevant.
|
|
75
|
+
|
|
76
|
+
**Vercel AI SDK (`ai`)** is also captured, **zero-code** — `generateText`, `streamText`, `generateObject`,
|
|
77
|
+
`streamObject`. The AI SDK emits telemetry only when it's enabled per call, so `@scope-analytics/node` enables it
|
|
78
|
+
for you: it injects `experimental_telemetry: { isEnabled: true }` into those calls, **deep-merged** with any
|
|
79
|
+
telemetry config you already pass (your `functionId`/`metadata`/`recordInputs`/… are preserved). To opt a
|
|
80
|
+
specific call out, set `experimental_telemetry: { isEnabled: false }` yourself — that's respected. If you
|
|
81
|
+
pass your **own** `tracer` in `experimental_telemetry`, those spans go to your tracer rather than Scope.
|
|
82
|
+
|
|
83
|
+
### Module systems (CommonJS & ESM)
|
|
84
|
+
|
|
85
|
+
Auto-capture hooks your module loader, so it must be in place before your app imports its LLM SDKs — which
|
|
86
|
+
is exactly what the `--import @scope-analytics/node/register` bootstrap guarantees (it also registers the ESM loader
|
|
87
|
+
needed to instrument `import`s). **On that bootstrap, all four providers are captured under both CommonJS
|
|
88
|
+
and ESM.** The explicit `init()` path covers CommonJS (where you control `require` order); for ESM, use the
|
|
89
|
+
bootstrap, since `import`s are hoisted and a loader can't retroactively hook modules already imported.
|
|
90
|
+
|
|
91
|
+
## Privacy
|
|
92
|
+
|
|
93
|
+
**Raw by default** (full-fidelity capture). Opt in to a best-effort credential scrub with
|
|
94
|
+
`init({ redactPatterns: CREDENTIAL_REDACT_PATTERNS })` (exported from this package) — it keeps the key and
|
|
95
|
+
drops the value over `key=value` free text in prompts/responses/messages. Not a structural guarantee.
|
|
96
|
+
|
|
97
|
+
## Configuration
|
|
98
|
+
|
|
99
|
+
| Option (`init({…})`) | Env var | Default | Notes |
|
|
100
|
+
|---|---|---|---|
|
|
101
|
+
| `apiKey` | `SCOPE_API_KEY` | — (required) | Project **secret** key (`sk_live_…`/`sk_test_…`). A public `pk_…` key is rejected. |
|
|
102
|
+
| `endpoint` | `SCOPE_ENDPOINT` | `https://api.scopeai.dev` | Scope ingest base URL. |
|
|
103
|
+
| `environment` | `SCOPE_ENVIRONMENT` | `production` | Tag on every event. |
|
|
104
|
+
| `debug` | `SCOPE_DEBUG` | `false` | Verbose logging. |
|
|
105
|
+
| `serviceName` | `SCOPE_SERVICE_NAME` | `scope-app` | OTel `service.name`. |
|
|
106
|
+
|
|
107
|
+
Deploy metadata (`git_sha`, `deployment_id`) is read once at startup from your platform's commit
|
|
108
|
+
env var (Railway / Vercel / Render / Heroku / Cloud Run / Lambda / `GIT_COMMIT_SHA`) and stamped
|
|
109
|
+
on every event — so the analyst can reason about "what changed before the drop?". Nothing is
|
|
110
|
+
invented when no env var is present (honest non-coverage).
|
|
111
|
+
|
|
112
|
+
## Design
|
|
113
|
+
|
|
114
|
+
`@scope-analytics/node` is a thin Scope layer over OpenTelemetry:
|
|
115
|
+
|
|
116
|
+
- Provider instrumentations produce OpenInference GenAI spans — Arize drop-ins for OpenAI/Anthropic, a
|
|
117
|
+
Scope-authored instrumentation for `@google/genai`, and the `@arizeai/openinference-vercel` span
|
|
118
|
+
processor that translates the Vercel AI SDK's native spans into the same shape.
|
|
119
|
+
- `ScopeSpanExporter` translates each LLM span into a Scope universal event and POSTs
|
|
120
|
+
`{ events, source: "backend_sdk" }` to `${endpoint}/api/events` with `Authorization: Bearer <secret>`.
|
|
121
|
+
- Telemetry is best-effort and **never throws** — a Scope outage can't crash or slow your app.
|
|
122
|
+
|
|
123
|
+
## Development
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
npm install
|
|
127
|
+
npm test # vitest (unit + a real-use pipeline → local HTTP collector)
|
|
128
|
+
npm run build # tsup → dual ESM + CJS + .d.ts
|
|
129
|
+
```
|