@reprova/sdk 0.2.0 → 0.4.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 +206 -11
- package/dist/context.d.ts +3 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js.map +1 -1
- package/dist/drizzle.d.ts +11 -0
- package/dist/drizzle.d.ts.map +1 -0
- package/dist/drizzle.js +72 -0
- package/dist/drizzle.js.map +1 -0
- package/dist/index.d.ts +10 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/knex.d.ts +5 -0
- package/dist/knex.d.ts.map +1 -0
- package/dist/knex.js +83 -0
- package/dist/knex.js.map +1 -0
- package/dist/kysely.d.ts +22 -0
- package/dist/kysely.d.ts.map +1 -0
- package/dist/kysely.js +172 -0
- package/dist/kysely.js.map +1 -0
- package/dist/proto.gen.d.ts +65 -1
- package/dist/proto.gen.d.ts.map +1 -1
- package/dist/registry.d.ts +22 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +70 -0
- package/dist/registry.js.map +1 -0
- package/dist/sdk.d.ts +24 -4
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +424 -15
- package/dist/sdk.js.map +1 -1
- package/dist/sequelize.d.ts +5 -0
- package/dist/sequelize.d.ts.map +1 -0
- package/dist/sequelize.js +105 -0
- package/dist/sequelize.js.map +1 -0
- package/dist/typeorm.d.ts +2 -0
- package/dist/typeorm.d.ts.map +1 -0
- package/dist/typeorm.js +65 -0
- package/dist/typeorm.js.map +1 -0
- package/package.json +13 -1
package/README.md
CHANGED
|
@@ -1,28 +1,223 @@
|
|
|
1
1
|
# @reprova/sdk
|
|
2
2
|
|
|
3
|
-
Node.js/TypeScript SDK
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
Node.js/TypeScript SDK for **any Node app** — vanilla `node:http`, Koa, Fastify,
|
|
4
|
+
Express, background workers. `Reprova.init()` instruments Node's own HTTP servers,
|
|
5
|
+
so every request gets capture context (errors, silent 5xxs, headers, trace ids,
|
|
6
|
+
outbound HTTP calls) with zero framework code. Express and Prisma integrations are
|
|
7
|
+
optional enrichments: Express adds async-rejection forwarding and parsed request
|
|
8
|
+
bodies; Prisma adds automatic data footprints (which tables/rows each request
|
|
9
|
+
touched — what makes an error *reproducible*, not just visible). The batched,
|
|
10
|
+
fire-and-forget transport never adds meaningful latency, even when the control
|
|
11
|
+
plane is unreachable (`transport.test.ts`; `chaos.spec.ts` proves it against the
|
|
12
|
+
real running control plane).
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
```bash
|
|
16
|
+
npm install @reprova/sdk
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Usage — any Node app
|
|
10
20
|
|
|
11
|
-
## Usage
|
|
12
21
|
```ts
|
|
13
|
-
import { Reprova
|
|
22
|
+
import { Reprova } from '@reprova/sdk';
|
|
23
|
+
|
|
24
|
+
Reprova.init({ dsn: process.env.REPROVA_DSN, release: gitSha });
|
|
25
|
+
// That's it. A plain http.createServer / Koa / Fastify app now captures
|
|
26
|
+
// errors, silent 5xx responses, request context, trace ids, outbound calls.
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`init` instruments `http.Server`/`https.Server` directly and attaches
|
|
30
|
+
process-level error handlers (opt-outs: `instrumentHttp: false`,
|
|
31
|
+
`processHandlers: false`; `uncaughtException` flushes then exits 1). A missing
|
|
32
|
+
`dsn` puts the SDK in disabled mode: everything mounts, nothing records.
|
|
33
|
+
|
|
34
|
+
### Background jobs and scripts
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
await sdk.runJob('nightly-sync', async () => { ... }); // failures ingest as job_failure
|
|
38
|
+
await sdk.runWithContext({ name: 'csv-import' }, doImport); // generic wrapper: capture + rethrow
|
|
39
|
+
```
|
|
14
40
|
|
|
41
|
+
### Data footprints without Prisma (knex, raw SQL, any DAO)
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
const rows = await knex('invoices').where({ id }).select();
|
|
45
|
+
sdk.recordFootprint({ model: 'Invoice', op: 'select', pks: rows.map(r => r.id), count: rows.length });
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Reproductions need footprints. Six ORMs record them automatically (below);
|
|
49
|
+
anything else records them with one `recordFootprint` call per query site.
|
|
50
|
+
|
|
51
|
+
| ORM | Helper | Auto PKs | where_shape |
|
|
52
|
+
| --- | --- | --- | --- |
|
|
53
|
+
| Prisma | `instrumentPrisma` / `createPrismaExtension` | ✅ exact (DMMF) | ✅ |
|
|
54
|
+
| Kysely | `createKyselyPlugin` | ✅ (`primaryKey` opt for composite) | ✅ |
|
|
55
|
+
| Sequelize | `installSequelizeHooks` | ✅ exact (model metadata) | ✅ |
|
|
56
|
+
| TypeORM | `installTypeOrmSubscriber` | ✅ exact (entity metadata) | ➖ |
|
|
57
|
+
| Knex / Objection | `installKnexHooks` | ✅ SELECT; INSERT depends on driver RETURNING | ➖ |
|
|
58
|
+
| Drizzle | `createDrizzleLogger` | ❌ shape-only (no result hook) | ✅ |
|
|
59
|
+
|
|
60
|
+
## Express (optional enrichment)
|
|
61
|
+
|
|
62
|
+
```ts
|
|
15
63
|
const sdk = Reprova.init({ dsn: process.env.REPROVA_DSN, release: gitSha });
|
|
64
|
+
sdk.setupExpress(app); // async-rejection forwarding + error-middleware capture + parsed bodies
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Prisma (optional enrichment — automatic footprints)
|
|
68
|
+
|
|
69
|
+
One call wires both automatic footprints and `migration_id`:
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
const sdk = Reprova.init({ dsn: process.env.REPROVA_DSN, release: gitSha });
|
|
73
|
+
await sdk.instrumentPrisma(prisma, { dmmf: Prisma.dmmf });
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`instrumentPrisma` splices the footprint extension onto your existing client
|
|
77
|
+
in place (so the shared singleton keeps recording) and best-effort reads the
|
|
78
|
+
latest row of `_prisma_migrations` into `migration_id`. It's a no-op when the
|
|
79
|
+
SDK is disabled (no `dsn` / replay), so no `if (dsn)` guard is needed, and it
|
|
80
|
+
never imports `@prisma/client` — Prisma stays an optional peer. A missing or
|
|
81
|
+
unreadable migrations table is non-fatal: `migration_id` stays `'unknown'`.
|
|
82
|
+
Pass `{ readMigrationId: false }` to set it yourself via `sdk.setMigrationId`.
|
|
83
|
+
|
|
84
|
+
Prefer to own the wiring? The extension is still exported directly:
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
import { createPrismaExtension } from '@reprova/sdk';
|
|
88
|
+
const prisma = new PrismaClient().$extends(createPrismaExtension(Prisma.dmmf));
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Kysely (optional enrichment — automatic footprints)
|
|
92
|
+
|
|
93
|
+
Add the plugin at construction; every query then records a footprint:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
import { createKyselyPlugin } from '@reprova/sdk';
|
|
97
|
+
const db = new Kysely<DB>({ dialect, plugins: [createKyselyPlugin()] });
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The plugin reads the compiled AST for the table(s) and operation, the WHERE
|
|
101
|
+
clause's referenced **column names** (never values — PII-safe by
|
|
102
|
+
construction), and the returned rows for primary keys. Joined/subquery tables
|
|
103
|
+
are recorded as referenced (without PKs). It's a no-op outside a captured
|
|
104
|
+
request, never imports `kysely`, and can never break a query (every path is
|
|
105
|
+
guarded).
|
|
106
|
+
|
|
107
|
+
Kysely carries no schema metadata at runtime, so PK detection defaults to
|
|
108
|
+
`['id']`. Override for composite or non-`id` keys:
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
createKyselyPlugin({ primaryKey: (table) => table === 'membership' ? ['tenantId', 'userId'] : ['id'] });
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
`migration_id` is independent of the ORM: read your migration tool's version
|
|
115
|
+
table (Kysely's default is `kysely_migration`) and call
|
|
116
|
+
`sdk.setMigrationId(latest)`, or leave it `'unknown'`.
|
|
117
|
+
|
|
118
|
+
## Sequelize (optional enrichment — automatic footprints)
|
|
119
|
+
|
|
120
|
+
Install once after your models are defined; every query records a footprint:
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
import { installSequelizeHooks } from '@reprova/sdk';
|
|
124
|
+
installSequelizeHooks(sequelize);
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Uses Sequelize's lifecycle hooks (`afterFind`, `afterCreate`, …) plus each
|
|
128
|
+
model's `tableName` / `primaryKeyAttributes`, so PKs are exact. Hooks are
|
|
129
|
+
registered per model (and on `afterDefine` for later ones), so the table is
|
|
130
|
+
known even when a query returns 0 rows. `where_shape` = the WHERE object's
|
|
131
|
+
top-level keys (names only).
|
|
132
|
+
|
|
133
|
+
## TypeORM (optional enrichment — automatic footprints)
|
|
134
|
+
|
|
135
|
+
Attach the subscriber after `dataSource.initialize()`:
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
import { installTypeOrmSubscriber } from '@reprova/sdk';
|
|
139
|
+
await dataSource.initialize();
|
|
140
|
+
installTypeOrmSubscriber(dataSource);
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Uses entity lifecycle events (`afterLoad`, `afterInsert`, …) and each entity's
|
|
144
|
+
metadata for exact PKs. TypeORM fires these per entity with no WHERE context,
|
|
145
|
+
so entries are **merged by (table, op)** within a request (union of distinct
|
|
146
|
+
PKs), and there is no `where_shape`.
|
|
147
|
+
|
|
148
|
+
## Knex / Objection (optional enrichment — automatic footprints)
|
|
149
|
+
|
|
150
|
+
One listener covers raw Knex **and** Objection.js (which runs through the same
|
|
151
|
+
Knex instance):
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
import { installKnexHooks } from '@reprova/sdk';
|
|
155
|
+
installKnexHooks(knex);
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Reads the table and operation from Knex's `query-response` event. SELECT rows
|
|
159
|
+
yield PKs (via `primaryKey(table)`, default `['id']`); UPDATE/DELETE record an
|
|
160
|
+
affected-row count; INSERT PK fidelity depends on the driver's RETURNING
|
|
161
|
+
support (full on Postgres, last-id only on sqlite/mysql). No `where_shape`
|
|
162
|
+
(Knex has no query AST).
|
|
163
|
+
|
|
164
|
+
## Drizzle (optional enrichment — shape-only)
|
|
165
|
+
|
|
166
|
+
Drizzle has no result-aware hook, only a logger — so this adapter records the
|
|
167
|
+
table, operation, and WHERE column names, but **cannot extract PKs**:
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
import { createDrizzleLogger } from '@reprova/sdk';
|
|
171
|
+
const db = drizzle(client, { logger: createDrizzleLogger() });
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
For PK-level fidelity with Drizzle, add `sdk.recordFootprint(...)` at the query
|
|
175
|
+
sites that matter; the logger gives cheap table-level coverage on top.
|
|
176
|
+
|
|
177
|
+
## Express (continued)
|
|
178
|
+
|
|
179
|
+
`setupExpress(app)` can be called before or after your routes; it wires the
|
|
180
|
+
request-context middleware (repositioned to run first), error capture, the
|
|
181
|
+
HTTP-5xx hook, and async rejection forwarding in one call. A missing `dsn`
|
|
182
|
+
puts the SDK in disabled mode: nothing is recorded or sent, but Express-5
|
|
183
|
+
rejection semantics still apply — so apps can call `init` unconditionally.
|
|
184
|
+
|
|
185
|
+
Prefer manual control? `sdk.requestHandler()` / `sdk.errorHandler()` /
|
|
186
|
+
`wrapResponse` are still exported and behave exactly as before:
|
|
187
|
+
|
|
188
|
+
```ts
|
|
16
189
|
app.use(sdk.requestHandler());
|
|
17
190
|
// ... your routes ...
|
|
18
191
|
app.use(sdk.errorHandler());
|
|
19
|
-
|
|
20
|
-
const prisma = new PrismaClient().$extends(createPrismaExtension(Prisma.dmmf));
|
|
21
192
|
```
|
|
22
193
|
|
|
23
194
|
Every capture carries a W3C `trace_id`, the git `release` sha, and the latest applied
|
|
24
195
|
Prisma `migration_id` — non-negotiable schema fields the rest of the pipeline depends on.
|
|
25
196
|
|
|
197
|
+
## Async handlers just work
|
|
198
|
+
|
|
199
|
+
Existing route code needs **no changes** — no `asyncHandler` wrapper, no
|
|
200
|
+
`try/catch → next(err)`:
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
app.get('/invoices/:id', async (req, res) => {
|
|
204
|
+
const invoice = await db.invoice.find(req.params.id); // a rejection here is
|
|
205
|
+
res.json(invoice); // captured automatically
|
|
206
|
+
});
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Express 4 normally discards the promise an async handler returns, so a rejection
|
|
210
|
+
never reaches error middleware. On the first request, the SDK transparently patches
|
|
211
|
+
the router's dispatch so rejected handler promises are forwarded down the error
|
|
212
|
+
chain — the exact semantics Express 5 ships natively — with the full request
|
|
213
|
+
context (headers, body, data footprint, trace id) intact on the capture. Your own
|
|
214
|
+
error middleware still runs and the client still gets its response; nothing is
|
|
215
|
+
swallowed. On Express 5 the SDK detects native forwarding and does nothing.
|
|
216
|
+
|
|
217
|
+
One limitation: a router imported from a *different* physical copy of `express`
|
|
218
|
+
in `node_modules` (rare — npm normally dedupes to one) isn't covered by the outer
|
|
219
|
+
app's patch; mount `sdk.requestHandler()` inside that sub-app to cover its copy too.
|
|
220
|
+
|
|
26
221
|
## Commands
|
|
27
222
|
```bash
|
|
28
223
|
npm run build
|
package/dist/context.d.ts
CHANGED
|
@@ -21,6 +21,8 @@ export interface OutboundCall {
|
|
|
21
21
|
status: number;
|
|
22
22
|
response_body?: string;
|
|
23
23
|
recorded_for_replay: boolean;
|
|
24
|
+
duration_ms?: number;
|
|
25
|
+
outcome?: 'success' | 'timeout' | 'network_error';
|
|
24
26
|
}
|
|
25
27
|
export interface ReprovaContext {
|
|
26
28
|
traceId: string;
|
|
@@ -29,6 +31,7 @@ export interface ReprovaContext {
|
|
|
29
31
|
footprint: FootprintQuery[];
|
|
30
32
|
outboundCalls: OutboundCall[];
|
|
31
33
|
captured?: boolean;
|
|
34
|
+
rawRequest?: unknown;
|
|
32
35
|
}
|
|
33
36
|
export declare const contextStorage: AsyncLocalStorage<ReprovaContext>;
|
|
34
37
|
export declare function currentContext(): ReprovaContext | undefined;
|
package/dist/context.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,EAAE,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,EAAE,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB,EAAE,OAAO,CAAC;IAG7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,eAAe,CAAC;CACnD;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,IAAI,CAAC;IACjB,OAAO,EAAE,eAAe,CAAC;IACzB,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,QAAQ,CAAC,EAAE,OAAO,CAAC;IAKnB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,cAAc,mCAA0C,CAAC;AAEtE,wBAAgB,cAAc,IAAI,cAAc,GAAG,SAAS,CAE3D"}
|
package/dist/context.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AA8ChD,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,iBAAiB,EAAkB,CAAC;AAEtE,MAAM,UAAU,cAAc;IAC5B,OAAO,cAAc,CAAC,QAAQ,EAAE,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface DrizzleLoggerOptions {
|
|
2
|
+
captureWhereShape?: boolean;
|
|
3
|
+
forward?: {
|
|
4
|
+
logQuery(query: string, params: unknown[]): void;
|
|
5
|
+
};
|
|
6
|
+
}
|
|
7
|
+
export interface DrizzleLogger {
|
|
8
|
+
logQuery(query: string, params: unknown[]): void;
|
|
9
|
+
}
|
|
10
|
+
export declare function createDrizzleLogger(opts?: DrizzleLoggerOptions): DrizzleLogger;
|
|
11
|
+
//# sourceMappingURL=drizzle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drizzle.d.ts","sourceRoot":"","sources":["../src/drizzle.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,oBAAoB;IAEnC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;KAAE,CAAC;CAChE;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;CAClD;AAuCD,wBAAgB,mBAAmB,CAAC,IAAI,GAAE,oBAAyB,GAAG,aAAa,CA2BlF"}
|
package/dist/drizzle.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { contextStorage } from './context.js';
|
|
2
|
+
const OP_BY_KEYWORD = {
|
|
3
|
+
select: 'select',
|
|
4
|
+
insert: 'insert',
|
|
5
|
+
update: 'update',
|
|
6
|
+
delete: 'delete',
|
|
7
|
+
};
|
|
8
|
+
// First SQL keyword → operation.
|
|
9
|
+
function opOf(sql) {
|
|
10
|
+
const m = /^\s*(select|insert|update|delete)\b/i.exec(sql);
|
|
11
|
+
return m ? OP_BY_KEYWORD[m[1].toLowerCase()] : undefined;
|
|
12
|
+
}
|
|
13
|
+
// The principal table, from the op-appropriate clause.
|
|
14
|
+
function tableOf(sql, op) {
|
|
15
|
+
let m = null;
|
|
16
|
+
if (op === 'select' || op === 'delete')
|
|
17
|
+
m = /\bfrom\s+"?([A-Za-z0-9_]+)"?/i.exec(sql);
|
|
18
|
+
else if (op === 'insert')
|
|
19
|
+
m = /\binto\s+"?([A-Za-z0-9_]+)"?/i.exec(sql);
|
|
20
|
+
else if (op === 'update')
|
|
21
|
+
m = /\bupdate\s+"?([A-Za-z0-9_]+)"?/i.exec(sql);
|
|
22
|
+
return m ? m[1] : undefined;
|
|
23
|
+
}
|
|
24
|
+
// Column names referenced in the WHERE clause — the right-hand identifier of
|
|
25
|
+
// each `"table"."col"` (or a bare `"col"`). Names only; values are `?`.
|
|
26
|
+
function whereColumns(sql) {
|
|
27
|
+
const wIdx = sql.search(/\bwhere\b/i);
|
|
28
|
+
if (wIdx < 0)
|
|
29
|
+
return [];
|
|
30
|
+
const tail = sql.slice(wIdx + 5);
|
|
31
|
+
const cols = new Set();
|
|
32
|
+
const re = /"([A-Za-z0-9_]+)"(?:\s*\.\s*"([A-Za-z0-9_]+)")?/g;
|
|
33
|
+
let m;
|
|
34
|
+
while ((m = re.exec(tail)) !== null)
|
|
35
|
+
cols.add(m[2] ?? m[1]);
|
|
36
|
+
return [...cols].sort();
|
|
37
|
+
}
|
|
38
|
+
// Creates a Drizzle-compatible logger that records footprints.
|
|
39
|
+
// Usage: drizzle(client, { logger: createDrizzleLogger() })
|
|
40
|
+
export function createDrizzleLogger(opts = {}) {
|
|
41
|
+
const captureWhereShape = opts.captureWhereShape !== false;
|
|
42
|
+
const forward = opts.forward;
|
|
43
|
+
return {
|
|
44
|
+
logQuery(query, params) {
|
|
45
|
+
try {
|
|
46
|
+
const ctx = contextStorage.getStore();
|
|
47
|
+
if (ctx) {
|
|
48
|
+
const op = opOf(query);
|
|
49
|
+
const table = op ? tableOf(query, op) : undefined;
|
|
50
|
+
if (op && table) {
|
|
51
|
+
const where = captureWhereShape ? whereColumns(query).join(',') || undefined : undefined;
|
|
52
|
+
const entry = {
|
|
53
|
+
model: table,
|
|
54
|
+
op,
|
|
55
|
+
pks: [],
|
|
56
|
+
where_shape: where,
|
|
57
|
+
count: 0,
|
|
58
|
+
note: 'drizzle: shape-only (no result access — PKs/count unavailable)',
|
|
59
|
+
};
|
|
60
|
+
ctx.footprint.push(entry);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch { /* never break a query */ }
|
|
65
|
+
try {
|
|
66
|
+
forward?.logQuery(query, params);
|
|
67
|
+
}
|
|
68
|
+
catch { /* ignore */ }
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=drizzle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drizzle.js","sourceRoot":"","sources":["../src/drizzle.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
|
-
export { Reprova, wrapResponse } from './sdk.js';
|
|
1
|
+
export { Reprova, wrapResponse, forwardAsyncErrors, replayErrorHandler } from './sdk.js';
|
|
2
2
|
export { contextStorage, currentContext } from './context.js';
|
|
3
3
|
export { createPrismaExtension } from './prisma.js';
|
|
4
|
+
export { createKyselyPlugin } from './kysely.js';
|
|
5
|
+
export type { KyselyPluginOptions, KyselyFootprintPlugin } from './kysely.js';
|
|
6
|
+
export { installSequelizeHooks } from './sequelize.js';
|
|
7
|
+
export type { SequelizeAdapterOptions } from './sequelize.js';
|
|
8
|
+
export { installTypeOrmSubscriber } from './typeorm.js';
|
|
9
|
+
export { installKnexHooks } from './knex.js';
|
|
10
|
+
export type { KnexAdapterOptions } from './knex.js';
|
|
11
|
+
export { createDrizzleLogger } from './drizzle.js';
|
|
12
|
+
export type { DrizzleLoggerOptions, DrizzleLogger } from './drizzle.js';
|
|
4
13
|
export type { ReprovaOptions } from './sdk.js';
|
|
5
14
|
export type { ReprovaContext, FootprintQuery, OutboundCall, RequestSnapshot } from './context.js';
|
|
6
15
|
export * from './proto.gen.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AACzF,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,YAAY,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACvD,YAAY,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,YAAY,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,YAAY,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACxE,YAAY,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC/C,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAClG,cAAc,gBAAgB,CAAC;AAE/B,eAAO,MAAM,WAAW,UAAU,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
export { Reprova, wrapResponse } from './sdk.js';
|
|
1
|
+
export { Reprova, wrapResponse, forwardAsyncErrors, replayErrorHandler } from './sdk.js';
|
|
2
2
|
export { contextStorage, currentContext } from './context.js';
|
|
3
3
|
export { createPrismaExtension } from './prisma.js';
|
|
4
|
+
export { createKyselyPlugin } from './kysely.js';
|
|
5
|
+
export { installSequelizeHooks } from './sequelize.js';
|
|
6
|
+
export { installTypeOrmSubscriber } from './typeorm.js';
|
|
7
|
+
export { installKnexHooks } from './knex.js';
|
|
8
|
+
export { createDrizzleLogger } from './drizzle.js';
|
|
4
9
|
export * from './proto.gen.js';
|
|
5
10
|
export const SDK_VERSION = '0.1.0';
|
|
6
11
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AACzF,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAInD,cAAc,gBAAgB,CAAC;AAE/B,MAAM,CAAC,MAAM,WAAW,GAAG,OAAO,CAAC"}
|
package/dist/knex.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"knex.d.ts","sourceRoot":"","sources":["../src/knex.ts"],"names":[],"mappings":"AAuBA,MAAM,WAAW,kBAAkB;IAEjC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,EAAE,CAAC;CAC1C;AAsCD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,GAAE,kBAAuB,GAAG,IAAI,CAqCnF"}
|
package/dist/knex.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { contextStorage } from './context.js';
|
|
2
|
+
const OP_BY_METHOD = {
|
|
3
|
+
select: 'select',
|
|
4
|
+
first: 'select',
|
|
5
|
+
pluck: 'select',
|
|
6
|
+
insert: 'insert',
|
|
7
|
+
update: 'update',
|
|
8
|
+
del: 'delete',
|
|
9
|
+
delete: 'delete',
|
|
10
|
+
};
|
|
11
|
+
function isRowArray(v) {
|
|
12
|
+
return Array.isArray(v) && v.length > 0 && typeof v[0] === 'object' && v[0] !== null;
|
|
13
|
+
}
|
|
14
|
+
function distinct(values) {
|
|
15
|
+
const seen = new Set();
|
|
16
|
+
const out = [];
|
|
17
|
+
for (const v of values) {
|
|
18
|
+
if (!seen.has(v)) {
|
|
19
|
+
seen.add(v);
|
|
20
|
+
out.push(v);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return out;
|
|
24
|
+
}
|
|
25
|
+
function extractRowPks(rows, pkCols) {
|
|
26
|
+
if (pkCols.length === 0)
|
|
27
|
+
return [];
|
|
28
|
+
const out = [];
|
|
29
|
+
for (const row of rows) {
|
|
30
|
+
const vals = pkCols.map((c) => row[c]);
|
|
31
|
+
if (vals.some((v) => v === undefined || v === null))
|
|
32
|
+
continue;
|
|
33
|
+
out.push(vals.map((v) => String(v)).join(':'));
|
|
34
|
+
}
|
|
35
|
+
return distinct(out);
|
|
36
|
+
}
|
|
37
|
+
// Installs a footprint listener on a Knex instance. Also covers Objection.js
|
|
38
|
+
// models bound to this same instance.
|
|
39
|
+
export function installKnexHooks(knex, opts = {}) {
|
|
40
|
+
const primaryKey = opts.primaryKey ?? (() => ['id']);
|
|
41
|
+
try {
|
|
42
|
+
knex.on('query-response', (response, obj, builder) => {
|
|
43
|
+
try {
|
|
44
|
+
const ctx = contextStorage.getStore();
|
|
45
|
+
if (!ctx)
|
|
46
|
+
return;
|
|
47
|
+
const method = obj?.method ?? builder?._method;
|
|
48
|
+
const op = method ? OP_BY_METHOD[method] : undefined;
|
|
49
|
+
if (!op)
|
|
50
|
+
return; // schema/DDL/raw — skip
|
|
51
|
+
const table = builder?._single?.table;
|
|
52
|
+
if (typeof table !== 'string' || !table)
|
|
53
|
+
return;
|
|
54
|
+
let pks = [];
|
|
55
|
+
let count = 0;
|
|
56
|
+
if (isRowArray(response)) {
|
|
57
|
+
pks = extractRowPks(response, primaryKey(table));
|
|
58
|
+
count = response.length;
|
|
59
|
+
}
|
|
60
|
+
else if (Array.isArray(response)) {
|
|
61
|
+
// Primitive array — insert returning ids (partial on sqlite/mysql).
|
|
62
|
+
if (op === 'insert')
|
|
63
|
+
pks = distinct(response.filter((v) => v != null).map((v) => String(v)));
|
|
64
|
+
count = response.length;
|
|
65
|
+
}
|
|
66
|
+
else if (typeof response === 'number') {
|
|
67
|
+
count = response; // affected-row count from update/delete
|
|
68
|
+
}
|
|
69
|
+
const entry = {
|
|
70
|
+
model: table,
|
|
71
|
+
op,
|
|
72
|
+
pks,
|
|
73
|
+
count,
|
|
74
|
+
note: count === 0 ? 'returned 0 rows' : undefined,
|
|
75
|
+
};
|
|
76
|
+
ctx.footprint.push(entry);
|
|
77
|
+
}
|
|
78
|
+
catch { /* never break the query pipeline */ }
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
catch { /* never throw from install */ }
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=knex.js.map
|
package/dist/knex.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"knex.js","sourceRoot":"","sources":["../src/knex.ts"],"names":[],"mappings":"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"}
|
package/dist/kysely.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
interface KyselyQueryId {
|
|
2
|
+
readonly queryId: string;
|
|
3
|
+
}
|
|
4
|
+
export interface KyselyPluginOptions {
|
|
5
|
+
primaryKey?: (table: string) => string[];
|
|
6
|
+
captureWhereShape?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface KyselyFootprintPlugin {
|
|
9
|
+
transformQuery<N extends {
|
|
10
|
+
kind: string;
|
|
11
|
+
}>(args: {
|
|
12
|
+
node: N;
|
|
13
|
+
queryId: KyselyQueryId;
|
|
14
|
+
}): N;
|
|
15
|
+
transformResult<R>(args: {
|
|
16
|
+
result: R;
|
|
17
|
+
queryId: KyselyQueryId;
|
|
18
|
+
}): Promise<R>;
|
|
19
|
+
}
|
|
20
|
+
export declare function createKyselyPlugin(opts?: KyselyPluginOptions): KyselyFootprintPlugin;
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=kysely.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kysely.d.ts","sourceRoot":"","sources":["../src/kysely.ts"],"names":[],"mappings":"AAmBA,UAAU,aAAa;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAOD,MAAM,WAAW,mBAAmB;IAKlC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,EAAE,CAAC;IAIzC,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAKD,MAAM,WAAW,qBAAqB;IACpC,cAAc,CAAC,CAAC,SAAS;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,IAAI,EAAE;QAAE,IAAI,EAAE,CAAC,CAAC;QAAC,OAAO,EAAE,aAAa,CAAA;KAAE,GAAG,CAAC,CAAC;IACzF,eAAe,CAAC,CAAC,EAAE,IAAI,EAAE;QAAE,MAAM,EAAE,CAAC,CAAC;QAAC,OAAO,EAAE,aAAa,CAAA;KAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAC7E;AA6GD,wBAAgB,kBAAkB,CAAC,IAAI,GAAE,mBAAwB,GAAG,qBAAqB,CAmExF"}
|