@btravstack/prisma 0.24.0 → 0.25.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 +5 -0
- package/dist/index.cjs +18 -2
- package/dist/index.d.cts +15 -1
- package/dist/index.d.mts +15 -1
- package/dist/index.mjs +19 -4
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -74,6 +74,11 @@ the per-query observation below comes from.
|
|
|
74
74
|
first query.
|
|
75
75
|
- **The pool's lifetime.** The provider is _resourceful_, so `release` closes it
|
|
76
76
|
on every exit path, including a boot that fails after it ran.
|
|
77
|
+
- **A database that answers before any work runs.** Opening the scope runs the
|
|
78
|
+
health check's probe, so a fresh pool is verified before its first burst of
|
|
79
|
+
transactions, and a database that does not answer fails the boot with
|
|
80
|
+
`DatabaseUnreachable` — the database's name and the driver's cause, never the
|
|
81
|
+
URL.
|
|
77
82
|
- **A health check**, named after the starter — `SELECT 1` through the raw
|
|
78
83
|
lane, folded into the kernel's `GET /healthz` with nothing wired. `/readyz`
|
|
79
84
|
does not read it: failing readiness on a dependency every replica shares
|
package/dist/index.cjs
CHANGED
|
@@ -65,6 +65,12 @@ const queryObserver = (observers) => {
|
|
|
65
65
|
//#region src/prisma.ts
|
|
66
66
|
/** The one place the cast above is spelled. */
|
|
67
67
|
const probeable = (db) => db;
|
|
68
|
+
const probe = (db) => probeable(db).runtime().query(probeable(db).raw.sql`SELECT 1`.affectedCount().build());
|
|
69
|
+
/**
|
|
70
|
+
* The database did not answer when the scope opened. Carries the database's
|
|
71
|
+
* name and the driver's own failure, never the URL, which holds credentials.
|
|
72
|
+
*/
|
|
73
|
+
var DatabaseUnreachable = class extends (0, unthrown.TaggedError)("DatabaseUnreachable") {};
|
|
68
74
|
/**
|
|
69
75
|
* A Prisma client whose pool is the application scope's.
|
|
70
76
|
*
|
|
@@ -73,6 +79,11 @@ const probeable = (db) => db;
|
|
|
73
79
|
* the client is reached through, and the resourceful provider that opens it and
|
|
74
80
|
* closes it again.
|
|
75
81
|
*
|
|
82
|
+
* **The database answers before the scope is handed out**: opening runs the
|
|
83
|
+
* health check's probe, so a pool is verified before any unit uses it, and a
|
|
84
|
+
* database that does not answer fails the boot with
|
|
85
|
+
* {@link DatabaseUnreachable}.
|
|
86
|
+
*
|
|
76
87
|
* **The pool closes on every exit path**, including a boot that fails after
|
|
77
88
|
* this provider ran — that is what makes it resourceful rather than a plain
|
|
78
89
|
* value. `runtime().close()` ends the pool; Prisma dials again lazily on the
|
|
@@ -86,6 +97,10 @@ const probeable = (db) => db;
|
|
|
86
97
|
const prismaDatabase = (name) => ({ client }) => {
|
|
87
98
|
const config = _btravstack_config.Config.provider(`${name}Config`)(_btravstack_config.Config.object({ url: _btravstack_config.Config.string("DATABASE_URL") }));
|
|
88
99
|
const DatabasePort = (0, _btravstack_di.Port)(name);
|
|
100
|
+
const verified = (db) => (0, unthrown.fromPromise)(probe(db).then(() => db, (cause) => probeable(db).runtime().close().finally(() => Promise.reject(cause))), (cause) => new DatabaseUnreachable({
|
|
101
|
+
database: name,
|
|
102
|
+
cause
|
|
103
|
+
}));
|
|
89
104
|
const port = DatabasePort;
|
|
90
105
|
const clientProvider = (0, _btravstack_di.Provider)(port)({
|
|
91
106
|
inject: {
|
|
@@ -95,14 +110,14 @@ const prismaDatabase = (name) => ({ client }) => {
|
|
|
95
110
|
acquire: ({ settings, observers }) => (0, unthrown.fromSafePromise)(Promise.resolve().then(() => client({
|
|
96
111
|
url: settings.url,
|
|
97
112
|
middleware: [queryObserver(observers)]
|
|
98
|
-
}))),
|
|
113
|
+
}))).flatMap(verified),
|
|
99
114
|
release: (db) => probeable(db).runtime().close()
|
|
100
115
|
});
|
|
101
116
|
const healthCheck = _btravstack_di.Provider.member(_btravstack_core.HealthChecks)({
|
|
102
117
|
inject: { db: port },
|
|
103
118
|
sync: ({ db }) => ({
|
|
104
119
|
name,
|
|
105
|
-
check: () => (0, unthrown.fromPromise)(
|
|
120
|
+
check: () => (0, unthrown.fromPromise)(probe(db), (cause) => new _btravstack_core.HealthCheckFailed({ reason: cause instanceof Error ? cause.message : "database unreachable" })).map(() => void 0)
|
|
106
121
|
})
|
|
107
122
|
});
|
|
108
123
|
const database = (0, _btravstack_di.Module)(name)({
|
|
@@ -118,4 +133,5 @@ const prismaDatabase = (name) => ({ client }) => {
|
|
|
118
133
|
return Object.assign(database, { port: DatabasePort });
|
|
119
134
|
};
|
|
120
135
|
//#endregion
|
|
136
|
+
exports.DatabaseUnreachable = DatabaseUnreachable;
|
|
121
137
|
exports.prismaDatabase = prismaDatabase;
|
package/dist/index.d.cts
CHANGED
|
@@ -67,6 +67,15 @@ type PrismaLike = {
|
|
|
67
67
|
*/
|
|
68
68
|
readonly runtime: unknown;
|
|
69
69
|
};
|
|
70
|
+
declare const DatabaseUnreachable_base: import("unthrown").TaggedErrorConstructor<"DatabaseUnreachable">;
|
|
71
|
+
/**
|
|
72
|
+
* The database did not answer when the scope opened. Carries the database's
|
|
73
|
+
* name and the driver's own failure, never the URL, which holds credentials.
|
|
74
|
+
*/
|
|
75
|
+
export declare class DatabaseUnreachable extends DatabaseUnreachable_base<{
|
|
76
|
+
readonly database: string;
|
|
77
|
+
readonly cause: unknown;
|
|
78
|
+
}> {}
|
|
70
79
|
/** What the starter hands {@link PrismaOptions.client}. */
|
|
71
80
|
type PrismaBinding = {
|
|
72
81
|
/** `DATABASE_URL`, read through `Config` rather than by the application. */
|
|
@@ -106,6 +115,11 @@ type PrismaOptions<C extends PrismaLike> = {
|
|
|
106
115
|
* the client is reached through, and the resourceful provider that opens it and
|
|
107
116
|
* closes it again.
|
|
108
117
|
*
|
|
118
|
+
* **The database answers before the scope is handed out**: opening runs the
|
|
119
|
+
* health check's probe, so a pool is verified before any unit uses it, and a
|
|
120
|
+
* database that does not answer fails the boot with
|
|
121
|
+
* {@link DatabaseUnreachable}.
|
|
122
|
+
*
|
|
109
123
|
* **The pool closes on every exit path**, including a boot that fails after
|
|
110
124
|
* this provider ran — that is what makes it resourceful rather than a plain
|
|
111
125
|
* value. `runtime().close()` ends the pool; Prisma dials again lazily on the
|
|
@@ -116,7 +130,7 @@ type PrismaOptions<C extends PrismaLike> = {
|
|
|
116
130
|
* against this same URL *before the process starts*; an application that
|
|
117
131
|
* migrates itself at boot races every other replica.
|
|
118
132
|
*/
|
|
119
|
-
export declare const prismaDatabase: <const N extends string>(name: N) => <C extends PrismaLike>({ client }: PrismaOptions<C>) => Module<HealthChecks | (PortClassOf<N, C> extends (infer T) ? T extends PortClassOf<N, C> ? T extends import("@btravstack/di").AnyPort ? InstanceType<T> : T extends import("@btravstack/di").AnyProvider ? InstanceType<T["port"]> : never : never : never), import("@btravstack/config").ConfigInvalid, Exclude<Env, HealthChecks | Observers | import("@btravstack/di").PortInstance<string, C> | import("@btravstack/di").PortInstance<`${N}Config`, {
|
|
133
|
+
export declare const prismaDatabase: <const N extends string>(name: N) => <C extends PrismaLike>({ client }: PrismaOptions<C>) => Module<HealthChecks | (PortClassOf<N, C> extends (infer T) ? T extends PortClassOf<N, C> ? T extends import("@btravstack/di").AnyPort ? InstanceType<T> : T extends import("@btravstack/di").AnyProvider ? InstanceType<T["port"]> : never : never : never), import("@btravstack/config").ConfigInvalid | DatabaseUnreachable, Exclude<Env, HealthChecks | Observers | import("@btravstack/di").PortInstance<string, C> | import("@btravstack/di").PortInstance<`${N}Config`, {
|
|
120
134
|
readonly url: string;
|
|
121
135
|
}>>> & {
|
|
122
136
|
readonly port: PortClassOf<N, C>;
|
package/dist/index.d.mts
CHANGED
|
@@ -67,6 +67,15 @@ type PrismaLike = {
|
|
|
67
67
|
*/
|
|
68
68
|
readonly runtime: unknown;
|
|
69
69
|
};
|
|
70
|
+
declare const DatabaseUnreachable_base: import("unthrown").TaggedErrorConstructor<"DatabaseUnreachable">;
|
|
71
|
+
/**
|
|
72
|
+
* The database did not answer when the scope opened. Carries the database's
|
|
73
|
+
* name and the driver's own failure, never the URL, which holds credentials.
|
|
74
|
+
*/
|
|
75
|
+
export declare class DatabaseUnreachable extends DatabaseUnreachable_base<{
|
|
76
|
+
readonly database: string;
|
|
77
|
+
readonly cause: unknown;
|
|
78
|
+
}> {}
|
|
70
79
|
/** What the starter hands {@link PrismaOptions.client}. */
|
|
71
80
|
type PrismaBinding = {
|
|
72
81
|
/** `DATABASE_URL`, read through `Config` rather than by the application. */
|
|
@@ -106,6 +115,11 @@ type PrismaOptions<C extends PrismaLike> = {
|
|
|
106
115
|
* the client is reached through, and the resourceful provider that opens it and
|
|
107
116
|
* closes it again.
|
|
108
117
|
*
|
|
118
|
+
* **The database answers before the scope is handed out**: opening runs the
|
|
119
|
+
* health check's probe, so a pool is verified before any unit uses it, and a
|
|
120
|
+
* database that does not answer fails the boot with
|
|
121
|
+
* {@link DatabaseUnreachable}.
|
|
122
|
+
*
|
|
109
123
|
* **The pool closes on every exit path**, including a boot that fails after
|
|
110
124
|
* this provider ran — that is what makes it resourceful rather than a plain
|
|
111
125
|
* value. `runtime().close()` ends the pool; Prisma dials again lazily on the
|
|
@@ -116,7 +130,7 @@ type PrismaOptions<C extends PrismaLike> = {
|
|
|
116
130
|
* against this same URL *before the process starts*; an application that
|
|
117
131
|
* migrates itself at boot races every other replica.
|
|
118
132
|
*/
|
|
119
|
-
export declare const prismaDatabase: <const N extends string>(name: N) => <C extends PrismaLike>({ client }: PrismaOptions<C>) => Module<HealthChecks | (PortClassOf<N, C> extends (infer T) ? T extends PortClassOf<N, C> ? T extends import("@btravstack/di").AnyPort ? InstanceType<T> : T extends import("@btravstack/di").AnyProvider ? InstanceType<T["port"]> : never : never : never), import("@btravstack/config").ConfigInvalid, Exclude<Env, HealthChecks | Observers | import("@btravstack/di").PortInstance<string, C> | import("@btravstack/di").PortInstance<`${N}Config`, {
|
|
133
|
+
export declare const prismaDatabase: <const N extends string>(name: N) => <C extends PrismaLike>({ client }: PrismaOptions<C>) => Module<HealthChecks | (PortClassOf<N, C> extends (infer T) ? T extends PortClassOf<N, C> ? T extends import("@btravstack/di").AnyPort ? InstanceType<T> : T extends import("@btravstack/di").AnyProvider ? InstanceType<T["port"]> : never : never : never), import("@btravstack/config").ConfigInvalid | DatabaseUnreachable, Exclude<Env, HealthChecks | Observers | import("@btravstack/di").PortInstance<string, C> | import("@btravstack/di").PortInstance<`${N}Config`, {
|
|
120
134
|
readonly url: string;
|
|
121
135
|
}>>> & {
|
|
122
136
|
readonly port: PortClassOf<N, C>;
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Config, Env } from "@btravstack/config";
|
|
2
2
|
import { HealthCheckFailed, HealthChecks, Observers, noObserverMember, observe } from "@btravstack/core";
|
|
3
3
|
import { Module, Port, Provider } from "@btravstack/di";
|
|
4
|
-
import { fromPromise, fromSafePromise } from "unthrown";
|
|
4
|
+
import { TaggedError, fromPromise, fromSafePromise } from "unthrown";
|
|
5
5
|
//#region src/instrument.ts
|
|
6
6
|
/**
|
|
7
7
|
* Every query, handed to the graph's observers: a span that spans the query, a
|
|
@@ -64,6 +64,12 @@ const queryObserver = (observers) => {
|
|
|
64
64
|
//#region src/prisma.ts
|
|
65
65
|
/** The one place the cast above is spelled. */
|
|
66
66
|
const probeable = (db) => db;
|
|
67
|
+
const probe = (db) => probeable(db).runtime().query(probeable(db).raw.sql`SELECT 1`.affectedCount().build());
|
|
68
|
+
/**
|
|
69
|
+
* The database did not answer when the scope opened. Carries the database's
|
|
70
|
+
* name and the driver's own failure, never the URL, which holds credentials.
|
|
71
|
+
*/
|
|
72
|
+
var DatabaseUnreachable = class extends TaggedError("DatabaseUnreachable") {};
|
|
67
73
|
/**
|
|
68
74
|
* A Prisma client whose pool is the application scope's.
|
|
69
75
|
*
|
|
@@ -72,6 +78,11 @@ const probeable = (db) => db;
|
|
|
72
78
|
* the client is reached through, and the resourceful provider that opens it and
|
|
73
79
|
* closes it again.
|
|
74
80
|
*
|
|
81
|
+
* **The database answers before the scope is handed out**: opening runs the
|
|
82
|
+
* health check's probe, so a pool is verified before any unit uses it, and a
|
|
83
|
+
* database that does not answer fails the boot with
|
|
84
|
+
* {@link DatabaseUnreachable}.
|
|
85
|
+
*
|
|
75
86
|
* **The pool closes on every exit path**, including a boot that fails after
|
|
76
87
|
* this provider ran — that is what makes it resourceful rather than a plain
|
|
77
88
|
* value. `runtime().close()` ends the pool; Prisma dials again lazily on the
|
|
@@ -85,6 +96,10 @@ const probeable = (db) => db;
|
|
|
85
96
|
const prismaDatabase = (name) => ({ client }) => {
|
|
86
97
|
const config = Config.provider(`${name}Config`)(Config.object({ url: Config.string("DATABASE_URL") }));
|
|
87
98
|
const DatabasePort = Port(name);
|
|
99
|
+
const verified = (db) => fromPromise(probe(db).then(() => db, (cause) => probeable(db).runtime().close().finally(() => Promise.reject(cause))), (cause) => new DatabaseUnreachable({
|
|
100
|
+
database: name,
|
|
101
|
+
cause
|
|
102
|
+
}));
|
|
88
103
|
const port = DatabasePort;
|
|
89
104
|
const clientProvider = Provider(port)({
|
|
90
105
|
inject: {
|
|
@@ -94,14 +109,14 @@ const prismaDatabase = (name) => ({ client }) => {
|
|
|
94
109
|
acquire: ({ settings, observers }) => fromSafePromise(Promise.resolve().then(() => client({
|
|
95
110
|
url: settings.url,
|
|
96
111
|
middleware: [queryObserver(observers)]
|
|
97
|
-
}))),
|
|
112
|
+
}))).flatMap(verified),
|
|
98
113
|
release: (db) => probeable(db).runtime().close()
|
|
99
114
|
});
|
|
100
115
|
const healthCheck = Provider.member(HealthChecks)({
|
|
101
116
|
inject: { db: port },
|
|
102
117
|
sync: ({ db }) => ({
|
|
103
118
|
name,
|
|
104
|
-
check: () => fromPromise(
|
|
119
|
+
check: () => fromPromise(probe(db), (cause) => new HealthCheckFailed({ reason: cause instanceof Error ? cause.message : "database unreachable" })).map(() => void 0)
|
|
105
120
|
})
|
|
106
121
|
});
|
|
107
122
|
const database = Module(name)({
|
|
@@ -117,4 +132,4 @@ const prismaDatabase = (name) => ({ client }) => {
|
|
|
117
132
|
return Object.assign(database, { port: DatabasePort });
|
|
118
133
|
};
|
|
119
134
|
//#endregion
|
|
120
|
-
export { prismaDatabase };
|
|
135
|
+
export { DatabaseUnreachable, prismaDatabase };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@btravstack/prisma",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.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,9 +63,9 @@
|
|
|
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.25.0",
|
|
67
|
+
"@btravstack/core": "0.25.0",
|
|
68
|
+
"@btravstack/di": "0.25.0",
|
|
69
69
|
"@btravstack/tsconfig": "0.4.0",
|
|
70
70
|
"@prisma/orm-postgres": "8.0.0-rc.11",
|
|
71
71
|
"@types/node": "26.6.4",
|
|
@@ -77,9 +77,9 @@
|
|
|
77
77
|
"vitest": "5.0.3"
|
|
78
78
|
},
|
|
79
79
|
"peerDependencies": {
|
|
80
|
-
"@btravstack/config": "^0.
|
|
81
|
-
"@btravstack/core": "^0.
|
|
82
|
-
"@btravstack/di": "^0.
|
|
80
|
+
"@btravstack/config": "^0.25.0",
|
|
81
|
+
"@btravstack/core": "^0.25.0",
|
|
82
|
+
"@btravstack/di": "^0.25.0",
|
|
83
83
|
"@prisma/orm-postgres": "^8.0.0-rc.11",
|
|
84
84
|
"unthrown": "^5.0.0"
|
|
85
85
|
},
|