@stacknext/prisma 0.8.0 → 0.10.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.
@@ -0,0 +1,81 @@
1
+ ---
2
+ title: Configuration
3
+ description: Configure Prisma query events and the StackNext adapter.
4
+ ---
5
+
6
+ # Configuration
7
+
8
+ ## Prisma Client
9
+
10
+ Query events must be enabled when the client is created:
11
+
12
+ ```ts
13
+ import { PrismaClient } from '@prisma/client'
14
+
15
+ const prisma = new PrismaClient({
16
+ log: [{ emit: 'event', level: 'query' }],
17
+ })
18
+ ```
19
+
20
+ Prisma's default logging does not emit these events.
21
+
22
+ ## Adapter
23
+
24
+ ```ts
25
+ import { instrumentPrismaClient } from '@stacknext/prisma'
26
+
27
+ const stop = instrumentPrismaClient(prisma, {
28
+ databaseSystem: 'postgresql',
29
+ })
30
+ ```
31
+
32
+ | Option | Required | Default | Notes |
33
+ | --- | --- | --- | --- |
34
+ | `databaseSystem` | No | `'prisma'` | Use the engine name, for example `sqlite` or `postgresql`. |
35
+ | `transport` | No | Process-wide transport | Must expose `enqueueDatabaseQuery`. |
36
+ | `onError` | No | none | Receives telemetry failures; they never reach Prisma. |
37
+
38
+ ## Lifecycle
39
+
40
+ <!-- coderabbit-ai-generated:v1 -->
41
+
42
+ <!-- coderabbit-ai-generated-section:v1:28f70536dac55a5bf479d919dd7e163c76b9148c7a914e348e3b8decef5a2e95 -->
43
+
44
+ `instrumentPrismaClient` returns a cleanup function. Calling it deactivates the
45
+ listener and clears the idempotency guard. Calling `instrumentPrismaClient`
46
+ again for the same client before cleanup returns a no-op cleanup.
47
+
48
+ <!-- /coderabbit-ai-generated:v1 -->
49
+
50
+ Register the adapter once per Prisma client, after the client is created and
51
+ before the first request.
52
+
53
+ ## `stacknext.config.json`
54
+
55
+ ```json
56
+ {
57
+ "database": { "drizzle": false, "prisma": true }
58
+ }
59
+ ```
60
+
61
+ `database.prisma` is setup intent used by `stacknext init` and
62
+ `stacknext doctor`. It does not attach the listener; the adapter must be called
63
+ explicitly.
64
+
65
+ ## Duration
66
+
67
+ Prisma query events include a duration in milliseconds. StackNext uses it when
68
+ it is a finite number, otherwise `durationMs` is `null`. Null is unmeasured, not
69
+ zero.
70
+
71
+ ## Privacy
72
+
73
+ The adapter never reads `event.params`. SQL is redacted and capped. No
74
+ configuration option can enable bind-parameter capture.
75
+
76
+ ## Verify
77
+
78
+ 1. Start `stacknext dev` and exercise a Prisma query.
79
+ 2. Run `stacknext coverage`; database evidence should be observed.
80
+ 3. Check that the query duration is measured for Prisma.
81
+ 4. Open the dashboard Database page or use `list_database_queries` through MCP.
package/docs/index.md ADDED
@@ -0,0 +1,84 @@
1
+ ---
2
+ title: "@stacknext/prisma"
3
+ description: Prisma Client query event instrumentation for StackNext.
4
+ ---
5
+
6
+ # @stacknext/prisma
7
+
8
+ `@stacknext/prisma` subscribes to Prisma `query` events and sends redacted query
9
+ evidence to the active StackNext transport.
10
+
11
+ ## Who should read this
12
+
13
+ Applications using Prisma. This is a **public, optional integration package**.
14
+ It is not required unless the project uses Prisma.
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ pnpm add @stacknext/prisma
20
+ ```
21
+
22
+ `@prisma/client >=5.0.0` is an optional peer dependency. The adapter accepts a
23
+ structural subset of the client and does not import Prisma at runtime.
24
+
25
+ ## Usage
26
+
27
+ ```ts
28
+ import { PrismaClient } from '@prisma/client'
29
+ import { instrumentPrismaClient } from '@stacknext/prisma'
30
+
31
+ const prisma = new PrismaClient({
32
+ log: [{ emit: 'event', level: 'query' }],
33
+ })
34
+
35
+ const stop = instrumentPrismaClient(prisma, {
36
+ databaseSystem: 'postgresql',
37
+ })
38
+
39
+ // Optional: call stop() during shutdown.
40
+ ```
41
+
42
+ Prisma must be configured to emit query events. Without the `log` event
43
+ configuration, the adapter receives nothing.
44
+
45
+ ## API
46
+
47
+ ### `instrumentPrismaClient(client, options?)`
48
+
49
+ Subscribes to `$on('query', listener)` and returns a cleanup function. It is
50
+ idempotent for the same client instance: a second call returns a no-op cleanup
51
+ and does not attach a second listener.
52
+
53
+ `StackNextPrismaOptions`:
54
+
55
+ | Option | Type | Default | Meaning |
56
+ | --- | --- | --- | --- |
57
+ | `databaseSystem` | string | `'prisma'` | Reported as `db.system.name`. |
58
+ | `transport` | `Pick<StackNextTransport, 'enqueueDatabaseQuery'>` | global transport | Override for tests or custom setups. |
59
+ | `onError` | `(error: unknown) => void` | none | Called when the sink throws. |
60
+
61
+ ## What is recorded
62
+
63
+ - redacted SQL text (capped at 20,000 characters);
64
+ - inferred operation;
65
+ - `durationMs` when Prisma supplies a finite, non-negative duration;
66
+ - active trace/span ids when a valid OTel context exists;
67
+ - `databaseSystem`, `source: 'prisma'`, `success: true`;
68
+ - `db.duration.measured`;
69
+ - `db.prisma.target` (bounded to 200 characters), when present.
70
+
71
+ ## Privacy
72
+
73
+ `event.params` is typed as a JSON string but is **never read**. SQL text passes
74
+ through `redactSql`. Query events do not include request bodies or headers.
75
+
76
+ ## Documentation map
77
+
78
+ - [Configuration](configuration.md)
79
+ - [Troubleshooting](troubleshooting.md)
80
+
81
+ ## Related packages
82
+
83
+ - `@stacknext/core` owns the transport and redaction.
84
+ - `@stacknext/cli` runs the collector.
@@ -0,0 +1,49 @@
1
+ ---
2
+ title: Troubleshooting
3
+ description: Diagnose missing Prisma query events, duplicate listeners and unmeasured durations.
4
+ ---
5
+
6
+ # Troubleshooting
7
+
8
+ ## No Prisma queries appear
9
+
10
+ 1. Confirm `PrismaClient` is created with
11
+ `log: [{ emit: 'event', level: 'query' }]`.
12
+ 2. Confirm `instrumentPrismaClient(prisma, ...)` is called on that same client.
13
+ 3. Confirm the app runs under `stacknext dev`.
14
+ 4. Exercise a query, then check `stacknext coverage`.
15
+ 5. Run `stacknext doctor` for adapter and config warnings.
16
+
17
+ ## The listener is not attached
18
+
19
+ The adapter requires `client.$on('query', callback)`. A mock, a wrapper or a
20
+ different client type may not satisfy the structural contract. Use the real
21
+ Prisma Client.
22
+
23
+ ## I called the adapter twice
24
+
25
+ It is idempotent for the same client. The second call returns a no-op cleanup
26
+ and does not attach another listener.
27
+
28
+ ## Duration is null
29
+
30
+ The event duration was missing or not a finite number. StackNext never
31
+ fabricates a duration. Check the Prisma event payload and version.
32
+
33
+ ## Queries are not linked to a request
34
+
35
+ Trace/span ids are recorded only when a valid OTel context is active. Queries
36
+ from scripts, workers or background jobs may have no request root.
37
+
38
+ ## Params are missing
39
+
40
+ By design. `event.params` is never read, logged or transmitted. The redacted SQL
41
+ text is the only query body StackNext stores.
42
+
43
+ ## Verify
44
+
45
+ ```bash
46
+ stacknext status --json
47
+ stacknext coverage --json
48
+ stacknext diagnose --category database
49
+ ```
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@stacknext/prisma",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "description": "Prisma Client query instrumentation adapter for StackNext",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "files": [
8
- "dist"
8
+ "dist",
9
+ "docs"
9
10
  ],
10
11
  "main": "./dist/index.js",
11
12
  "types": "./dist/index.d.ts",
@@ -18,7 +19,7 @@
18
19
  "./package.json": "./package.json"
19
20
  },
20
21
  "dependencies": {
21
- "@stacknext/core": "0.8.0",
22
+ "@stacknext/core": "0.10.0",
22
23
  "@opentelemetry/api": "1.9.0"
23
24
  },
24
25
  "devDependencies": {