@btravstack/prisma 0.43.0 → 0.44.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 +4 -4
- package/dist/index.cjs +23 -51
- package/dist/index.d.cts +10 -21
- package/dist/index.d.mts +10 -21
- package/dist/index.mjs +23 -51
- package/package.json +10 -9
package/README.md
CHANGED
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
|
|
10
10
|
```sh
|
|
11
11
|
pnpm add @btravstack/prisma @btravstack/core @btravstack/config @btravstack/di unthrown \
|
|
12
|
-
@prisma/orm-postgres@8.0.0-rc.
|
|
12
|
+
@prisma/orm-postgres@8.0.0-rc.18 temporal-polyfill@1.0.4
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
Install the required peers and Postgres polyfill, so the application holds a single
|
|
16
16
|
copy of each. The `prisma` CLI is yours, as a dev dependency: the client is
|
|
17
17
|
built from _your_ emitted contract, so there is none for this package to ship.
|
|
18
18
|
Node `>=22.12`.
|
|
@@ -96,7 +96,7 @@ the per-query observation below comes from.
|
|
|
96
96
|
lane, folded into the kernel's `GET /healthz` with nothing wired. `/readyz`
|
|
97
97
|
does not read it: failing readiness on a dependency every replica shares
|
|
98
98
|
removes them all at once.
|
|
99
|
-
- **Every query handed to `Observers`**, as one
|
|
99
|
+
- **Every query handed to `Observers`**, as one SQL activity middleware, so
|
|
100
100
|
composing `observability()` writes the failures as lines and `otel()` opens
|
|
101
101
|
the spans and mints the instruments — with no flag here and no port list to
|
|
102
102
|
satisfy when you compose neither. A middleware sees the ORM lane, the SQL
|
|
@@ -188,7 +188,7 @@ rather than the role `DATABASE_URL` carries. An application that migrates itself
|
|
|
188
188
|
at boot races every other replica.
|
|
189
189
|
|
|
190
190
|
**Engine-level tracing.** There is no engine: Prisma 8 is a TypeScript runtime
|
|
191
|
-
and ships no instrumentation package, so the
|
|
191
|
+
and ships no instrumentation package, so the SQL activity middleware is the
|
|
192
192
|
whole seam and it already carries the runtime's own latency.
|
|
193
193
|
|
|
194
194
|
**Transactions.** Commit boundaries belong to the adapter, spelled at the call —
|
package/dist/index.cjs
CHANGED
|
@@ -4,61 +4,33 @@ let _btravstack_core = require("@btravstack/core");
|
|
|
4
4
|
let _btravstack_di = require("@btravstack/di");
|
|
5
5
|
let unthrown = require("unthrown");
|
|
6
6
|
//#region src/instrument.ts
|
|
7
|
-
/**
|
|
8
|
-
* Every query, handed to the graph's observers: a span that spans the query, a
|
|
9
|
-
* count of how it came out, and a log line if it failed.
|
|
10
|
-
*
|
|
11
|
-
* **This is why a client the starter cannot name can be instrumented at all.**
|
|
12
|
-
* `middleware` is a construction option rather than a wrapper, and a hook sees
|
|
13
|
-
* every statement on every lane — the ORM's, the SQL builder's and the raw
|
|
14
|
-
* one — so it never needs to know the contract, which is the thing this package
|
|
15
|
-
* cannot see.
|
|
16
|
-
*
|
|
17
|
-
* **It starts the operation in `beforeQuery` and settles it in `afterQuery`**,
|
|
18
|
-
* paired by `ctx.planExecutionId`, because that is what `Observers` is for: the
|
|
19
|
-
* port is called at the START and answers a finisher, so an observer can open a
|
|
20
|
-
* span the query runs *inside*. Settling a span reconstructed afterwards from a
|
|
21
|
-
* duration would make it the parent of nothing. It is also why the runtime's
|
|
22
|
-
* own `latencyMs` is not reported — the observer started the operation, so the
|
|
23
|
-
* duration is its own measurement rather than something to pass along.
|
|
24
|
-
*
|
|
25
|
-
* **Both lanes, because there are two.** A read settles through
|
|
26
|
-
* `afterQuery`; a write with no `RETURNING` — a SQL-builder `delete()` run
|
|
27
|
-
* through `runtime().execute(plan)` — settles through `afterExecute` and would
|
|
28
|
-
* otherwise go unobserved entirely.
|
|
29
|
-
*
|
|
30
|
-
* `completed` is what settles the outcome, and a failed statement does reach
|
|
31
|
-
* the hook: measured against a real database, a duplicate insert arrives as
|
|
32
|
-
* `afterQuery … completed=false` before the rejection surfaces. That is what
|
|
33
|
-
* keeps the errors half of RED honest.
|
|
34
|
-
*/
|
|
7
|
+
/** Observe both SQL lanes from encoding until their statement activity ends. */
|
|
35
8
|
const queryObserver = (observers) => {
|
|
36
|
-
const
|
|
37
|
-
const start = (plan, ctx) => {
|
|
38
|
-
open.set(ctx.planExecutionId, (0, _btravstack_core.observe)(observers, {
|
|
39
|
-
component: "database",
|
|
40
|
-
name: "query",
|
|
41
|
-
attributes: { scope: ctx.scope ?? "runtime" },
|
|
42
|
-
...plan.sql === void 0 ? {} : { details: { sql: plan.sql } }
|
|
43
|
-
}));
|
|
44
|
-
return Promise.resolve();
|
|
45
|
-
};
|
|
46
|
-
const finish = (_plan, result, ctx) => {
|
|
47
|
-
const settle = open.get(ctx.planExecutionId);
|
|
48
|
-
open.delete(ctx.planExecutionId);
|
|
49
|
-
settle?.({
|
|
50
|
-
outcome: result.completed ? "ok" : "error",
|
|
51
|
-
...result.source === void 0 ? {} : { attributes: { source: result.source } }
|
|
52
|
-
});
|
|
53
|
-
return Promise.resolve();
|
|
54
|
-
};
|
|
9
|
+
const key = Symbol("btravstack-query-observer");
|
|
55
10
|
return {
|
|
56
11
|
name: "btravstack-observers",
|
|
57
12
|
familyId: "sql",
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
13
|
+
beforeEncode: (plan, ctx) => {
|
|
14
|
+
ctx.state(key)["settle"] = (0, _btravstack_core.observe)(observers, {
|
|
15
|
+
component: "database",
|
|
16
|
+
name: "query",
|
|
17
|
+
attributes: { scope: ctx.scope ?? "runtime" },
|
|
18
|
+
...plan.sql === void 0 ? {} : { details: { sql: plan.sql } }
|
|
19
|
+
});
|
|
20
|
+
return Promise.resolve();
|
|
21
|
+
},
|
|
22
|
+
activityEnded: (_activity, result, ctx) => {
|
|
23
|
+
if (result.kind === "statement") {
|
|
24
|
+
const state = ctx.state(key);
|
|
25
|
+
const settle = state["settle"];
|
|
26
|
+
delete state["settle"];
|
|
27
|
+
settle?.({
|
|
28
|
+
outcome: result.outcome === "succeeded" ? "ok" : "error",
|
|
29
|
+
...result.source === void 0 ? {} : { attributes: { source: result.source } }
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
return Promise.resolve();
|
|
33
|
+
}
|
|
62
34
|
};
|
|
63
35
|
};
|
|
64
36
|
//#endregion
|
package/dist/index.d.cts
CHANGED
|
@@ -1,39 +1,28 @@
|
|
|
1
1
|
import { HealthChecks, Observers } from "@btravstack/core";
|
|
2
2
|
import { Module, PortClassOf } from "@btravstack/di";
|
|
3
3
|
//#region src/instrument.d.ts
|
|
4
|
-
/**
|
|
5
|
-
* A Prisma 8 middleware, structurally — `name`, `familyId` and the four hooks
|
|
6
|
-
* this starter implements.
|
|
7
|
-
*
|
|
8
|
-
* Declared here rather than imported from `@prisma/orm-postgres/family-runtime`
|
|
9
|
-
* so the option's type does not drag the target package into a consumer that
|
|
10
|
-
* only reads this module's types. A real `SqlMiddleware` satisfies it.
|
|
11
|
-
*/
|
|
4
|
+
/** Structural Prisma 8 SQL hooks; no target-package import reaches consumers. */
|
|
12
5
|
type SqlMiddlewareLike = {
|
|
13
6
|
readonly name: string;
|
|
14
7
|
readonly familyId: "sql";
|
|
15
|
-
readonly
|
|
16
|
-
readonly
|
|
17
|
-
|
|
18
|
-
|
|
8
|
+
readonly beforeEncode: (plan: Plan, ctx: MiddlewareContext) => Promise<void>;
|
|
9
|
+
readonly activityEnded: (activity: {
|
|
10
|
+
readonly kind: "statement" | "transaction";
|
|
11
|
+
}, result: Settled, ctx: MiddlewareContext) => Promise<void>;
|
|
19
12
|
};
|
|
20
|
-
/** The rendered statement, which both `before` hooks are handed. */
|
|
21
13
|
type Plan = {
|
|
22
14
|
readonly sql?: string;
|
|
23
15
|
};
|
|
24
|
-
/**
|
|
25
|
-
* What every hook is handed. `planExecutionId` is the runtime's own correlation
|
|
26
|
-
* id — its TSDoc names tracing and timing as the reason it exists — and it is
|
|
27
|
-
* what pairs a `before` with its `after`.
|
|
28
|
-
*/
|
|
29
16
|
type MiddlewareContext = {
|
|
30
|
-
readonly planExecutionId: string;
|
|
31
17
|
readonly scope?: "runtime" | "connection" | "transaction";
|
|
18
|
+
readonly state: (key: string | symbol) => Record<string | symbol, unknown>;
|
|
32
19
|
};
|
|
33
|
-
/** What an `after` hook reports. There is no error here: Prisma's shape carries none. */
|
|
34
20
|
type Settled = {
|
|
35
|
-
readonly
|
|
21
|
+
readonly kind: "statement";
|
|
22
|
+
readonly outcome: "succeeded" | "failed" | "stopped";
|
|
36
23
|
readonly source?: string;
|
|
24
|
+
} | {
|
|
25
|
+
readonly kind: "transaction";
|
|
37
26
|
};
|
|
38
27
|
//#endregion
|
|
39
28
|
//#region src/prisma.d.ts
|
package/dist/index.d.mts
CHANGED
|
@@ -1,39 +1,28 @@
|
|
|
1
1
|
import { HealthChecks, Observers } from "@btravstack/core";
|
|
2
2
|
import { Module, PortClassOf } from "@btravstack/di";
|
|
3
3
|
//#region src/instrument.d.ts
|
|
4
|
-
/**
|
|
5
|
-
* A Prisma 8 middleware, structurally — `name`, `familyId` and the four hooks
|
|
6
|
-
* this starter implements.
|
|
7
|
-
*
|
|
8
|
-
* Declared here rather than imported from `@prisma/orm-postgres/family-runtime`
|
|
9
|
-
* so the option's type does not drag the target package into a consumer that
|
|
10
|
-
* only reads this module's types. A real `SqlMiddleware` satisfies it.
|
|
11
|
-
*/
|
|
4
|
+
/** Structural Prisma 8 SQL hooks; no target-package import reaches consumers. */
|
|
12
5
|
type SqlMiddlewareLike = {
|
|
13
6
|
readonly name: string;
|
|
14
7
|
readonly familyId: "sql";
|
|
15
|
-
readonly
|
|
16
|
-
readonly
|
|
17
|
-
|
|
18
|
-
|
|
8
|
+
readonly beforeEncode: (plan: Plan, ctx: MiddlewareContext) => Promise<void>;
|
|
9
|
+
readonly activityEnded: (activity: {
|
|
10
|
+
readonly kind: "statement" | "transaction";
|
|
11
|
+
}, result: Settled, ctx: MiddlewareContext) => Promise<void>;
|
|
19
12
|
};
|
|
20
|
-
/** The rendered statement, which both `before` hooks are handed. */
|
|
21
13
|
type Plan = {
|
|
22
14
|
readonly sql?: string;
|
|
23
15
|
};
|
|
24
|
-
/**
|
|
25
|
-
* What every hook is handed. `planExecutionId` is the runtime's own correlation
|
|
26
|
-
* id — its TSDoc names tracing and timing as the reason it exists — and it is
|
|
27
|
-
* what pairs a `before` with its `after`.
|
|
28
|
-
*/
|
|
29
16
|
type MiddlewareContext = {
|
|
30
|
-
readonly planExecutionId: string;
|
|
31
17
|
readonly scope?: "runtime" | "connection" | "transaction";
|
|
18
|
+
readonly state: (key: string | symbol) => Record<string | symbol, unknown>;
|
|
32
19
|
};
|
|
33
|
-
/** What an `after` hook reports. There is no error here: Prisma's shape carries none. */
|
|
34
20
|
type Settled = {
|
|
35
|
-
readonly
|
|
21
|
+
readonly kind: "statement";
|
|
22
|
+
readonly outcome: "succeeded" | "failed" | "stopped";
|
|
36
23
|
readonly source?: string;
|
|
24
|
+
} | {
|
|
25
|
+
readonly kind: "transaction";
|
|
37
26
|
};
|
|
38
27
|
//#endregion
|
|
39
28
|
//#region src/prisma.d.ts
|
package/dist/index.mjs
CHANGED
|
@@ -3,61 +3,33 @@ import { HealthCheckFailed, HealthChecks, Observers, noObserverMember, observe }
|
|
|
3
3
|
import { Module, Port, Provider } from "@btravstack/di";
|
|
4
4
|
import { TaggedError, fromPromise, fromSafePromise } from "unthrown";
|
|
5
5
|
//#region src/instrument.ts
|
|
6
|
-
/**
|
|
7
|
-
* Every query, handed to the graph's observers: a span that spans the query, a
|
|
8
|
-
* count of how it came out, and a log line if it failed.
|
|
9
|
-
*
|
|
10
|
-
* **This is why a client the starter cannot name can be instrumented at all.**
|
|
11
|
-
* `middleware` is a construction option rather than a wrapper, and a hook sees
|
|
12
|
-
* every statement on every lane — the ORM's, the SQL builder's and the raw
|
|
13
|
-
* one — so it never needs to know the contract, which is the thing this package
|
|
14
|
-
* cannot see.
|
|
15
|
-
*
|
|
16
|
-
* **It starts the operation in `beforeQuery` and settles it in `afterQuery`**,
|
|
17
|
-
* paired by `ctx.planExecutionId`, because that is what `Observers` is for: the
|
|
18
|
-
* port is called at the START and answers a finisher, so an observer can open a
|
|
19
|
-
* span the query runs *inside*. Settling a span reconstructed afterwards from a
|
|
20
|
-
* duration would make it the parent of nothing. It is also why the runtime's
|
|
21
|
-
* own `latencyMs` is not reported — the observer started the operation, so the
|
|
22
|
-
* duration is its own measurement rather than something to pass along.
|
|
23
|
-
*
|
|
24
|
-
* **Both lanes, because there are two.** A read settles through
|
|
25
|
-
* `afterQuery`; a write with no `RETURNING` — a SQL-builder `delete()` run
|
|
26
|
-
* through `runtime().execute(plan)` — settles through `afterExecute` and would
|
|
27
|
-
* otherwise go unobserved entirely.
|
|
28
|
-
*
|
|
29
|
-
* `completed` is what settles the outcome, and a failed statement does reach
|
|
30
|
-
* the hook: measured against a real database, a duplicate insert arrives as
|
|
31
|
-
* `afterQuery … completed=false` before the rejection surfaces. That is what
|
|
32
|
-
* keeps the errors half of RED honest.
|
|
33
|
-
*/
|
|
6
|
+
/** Observe both SQL lanes from encoding until their statement activity ends. */
|
|
34
7
|
const queryObserver = (observers) => {
|
|
35
|
-
const
|
|
36
|
-
const start = (plan, ctx) => {
|
|
37
|
-
open.set(ctx.planExecutionId, observe(observers, {
|
|
38
|
-
component: "database",
|
|
39
|
-
name: "query",
|
|
40
|
-
attributes: { scope: ctx.scope ?? "runtime" },
|
|
41
|
-
...plan.sql === void 0 ? {} : { details: { sql: plan.sql } }
|
|
42
|
-
}));
|
|
43
|
-
return Promise.resolve();
|
|
44
|
-
};
|
|
45
|
-
const finish = (_plan, result, ctx) => {
|
|
46
|
-
const settle = open.get(ctx.planExecutionId);
|
|
47
|
-
open.delete(ctx.planExecutionId);
|
|
48
|
-
settle?.({
|
|
49
|
-
outcome: result.completed ? "ok" : "error",
|
|
50
|
-
...result.source === void 0 ? {} : { attributes: { source: result.source } }
|
|
51
|
-
});
|
|
52
|
-
return Promise.resolve();
|
|
53
|
-
};
|
|
8
|
+
const key = Symbol("btravstack-query-observer");
|
|
54
9
|
return {
|
|
55
10
|
name: "btravstack-observers",
|
|
56
11
|
familyId: "sql",
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
12
|
+
beforeEncode: (plan, ctx) => {
|
|
13
|
+
ctx.state(key)["settle"] = observe(observers, {
|
|
14
|
+
component: "database",
|
|
15
|
+
name: "query",
|
|
16
|
+
attributes: { scope: ctx.scope ?? "runtime" },
|
|
17
|
+
...plan.sql === void 0 ? {} : { details: { sql: plan.sql } }
|
|
18
|
+
});
|
|
19
|
+
return Promise.resolve();
|
|
20
|
+
},
|
|
21
|
+
activityEnded: (_activity, result, ctx) => {
|
|
22
|
+
if (result.kind === "statement") {
|
|
23
|
+
const state = ctx.state(key);
|
|
24
|
+
const settle = state["settle"];
|
|
25
|
+
delete state["settle"];
|
|
26
|
+
settle?.({
|
|
27
|
+
outcome: result.outcome === "succeeded" ? "ok" : "error",
|
|
28
|
+
...result.source === void 0 ? {} : { attributes: { source: result.source } }
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
return Promise.resolve();
|
|
32
|
+
}
|
|
61
33
|
};
|
|
62
34
|
};
|
|
63
35
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@btravstack/prisma",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.44.0",
|
|
4
4
|
"description": "The Prisma starter for @btravstack/core: DATABASE_URL through Config, the Postgres driver adapter, and a client whose pool is the application scope's",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"database",
|
|
@@ -63,14 +63,15 @@
|
|
|
63
63
|
"./package.json": "./package.json"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
|
-
"@btravstack/config": "0.
|
|
67
|
-
"@btravstack/core": "0.
|
|
68
|
-
"@btravstack/di": "0.
|
|
66
|
+
"@btravstack/config": "0.44.0",
|
|
67
|
+
"@btravstack/core": "0.44.0",
|
|
68
|
+
"@btravstack/di": "0.44.0",
|
|
69
69
|
"@btravstack/tsconfig": "0.4.0",
|
|
70
|
-
"@prisma/orm-postgres": "8.0.0-rc.
|
|
70
|
+
"@prisma/orm-postgres": "8.0.0-rc.18",
|
|
71
71
|
"@types/node": "26.6.5",
|
|
72
72
|
"@unthrown/vitest": "5.12.1",
|
|
73
73
|
"@vitest/coverage-v8": "5.0.3",
|
|
74
|
+
"temporal-polyfill": "1.0.4",
|
|
74
75
|
"tsdown": "0.23.1",
|
|
75
76
|
"typescript": "7.0.2",
|
|
76
77
|
"typescript-consumer": "npm:typescript@5.9.3",
|
|
@@ -78,10 +79,10 @@
|
|
|
78
79
|
"vitest": "5.0.3"
|
|
79
80
|
},
|
|
80
81
|
"peerDependencies": {
|
|
81
|
-
"@btravstack/config": "^0.
|
|
82
|
-
"@btravstack/core": "^0.
|
|
83
|
-
"@btravstack/di": "^0.
|
|
84
|
-
"@prisma/orm-postgres": "^8.0.0-rc.
|
|
82
|
+
"@btravstack/config": "^0.44.0",
|
|
83
|
+
"@btravstack/core": "^0.44.0",
|
|
84
|
+
"@btravstack/di": "^0.44.0",
|
|
85
|
+
"@prisma/orm-postgres": "^8.0.0-rc.18",
|
|
85
86
|
"unthrown": "^5.0.0"
|
|
86
87
|
},
|
|
87
88
|
"engines": {
|