prisma-pglite-bridge 0.3.0 → 0.3.2
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 +36 -26
- package/dist/index.cjs +655 -592
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +195 -234
- package/dist/index.d.mts +207 -0
- package/dist/index.mjs +653 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +12 -12
- package/dist/index.d.ts +0 -246
- package/dist/index.js +0 -578
- package/dist/index.js.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,246 +1,207 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import pg from
|
|
5
|
-
import {
|
|
1
|
+
import * as _$_electric_sql_pglite0 from "@electric-sql/pglite";
|
|
2
|
+
import { Extensions, PGlite } from "@electric-sql/pglite";
|
|
3
|
+
import { PrismaPg } from "@prisma/adapter-pg";
|
|
4
|
+
import pg from "pg";
|
|
5
|
+
import { Duplex } from "node:stream";
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
*/
|
|
22
|
-
/** Opaque bridge identity token */
|
|
23
|
-
type BridgeId = symbol;
|
|
24
|
-
declare class SessionLock {
|
|
25
|
-
private owner;
|
|
26
|
-
private waitQueue;
|
|
27
|
-
/**
|
|
28
|
-
* Acquire access to PGlite. Resolves immediately if no transaction is
|
|
29
|
-
* active or if this bridge owns the current transaction. Queues otherwise.
|
|
30
|
-
*/
|
|
31
|
-
acquire(id: BridgeId): Promise<void>;
|
|
32
|
-
/**
|
|
33
|
-
* Update session state based on the ReadyForQuery status byte.
|
|
34
|
-
* Call after every PGlite response that contains RFQ.
|
|
35
|
-
*/
|
|
36
|
-
updateStatus(id: BridgeId, status: number): void;
|
|
37
|
-
/**
|
|
38
|
-
* Release ownership (e.g., when a bridge is destroyed mid-transaction).
|
|
39
|
-
*/
|
|
40
|
-
release(id: BridgeId): void;
|
|
41
|
-
private drainWaitQueue;
|
|
7
|
+
//#region src/create-pglite-adapter.d.ts
|
|
8
|
+
interface CreatePgliteAdapterOptions {
|
|
9
|
+
/** Path to prisma/migrations/ directory (auto-discovered via prisma.config.ts if omitted) */
|
|
10
|
+
migrationsPath?: string;
|
|
11
|
+
/** Pre-generated SQL to apply instead of auto-generating from schema */
|
|
12
|
+
sql?: string;
|
|
13
|
+
/** Root directory for prisma.config.ts discovery (default: process.cwd()). Set this in monorepos where tests run from the workspace root. */
|
|
14
|
+
configRoot?: string;
|
|
15
|
+
/** PGlite data directory. Omit for in-memory. */
|
|
16
|
+
dataDir?: string;
|
|
17
|
+
/** PGlite extensions (e.g., `{ uuid_ossp: uuidOssp() }`) */
|
|
18
|
+
extensions?: _$_electric_sql_pglite0.Extensions;
|
|
19
|
+
/** Maximum pool connections (default: 5) */
|
|
20
|
+
max?: number;
|
|
42
21
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
* keeping only the final ReadyForQuery after Sync.
|
|
61
|
-
*/
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Duplex stream that bridges `pg.Client` to an in-process PGlite instance.
|
|
65
|
-
*
|
|
66
|
-
* Replaces the TCP socket in `pg.Client` via the `stream` option. Speaks
|
|
67
|
-
* PostgreSQL wire protocol directly to PGlite — no TCP, no serialization
|
|
68
|
-
* overhead beyond what the wire protocol requires.
|
|
69
|
-
*
|
|
70
|
-
* Pass to `pg.Client` or use via `createPool()` / `createPgliteAdapter()`:
|
|
71
|
-
*
|
|
72
|
-
* ```typescript
|
|
73
|
-
* const client = new pg.Client({
|
|
74
|
-
* stream: () => new PGliteBridge(pglite),
|
|
75
|
-
* });
|
|
76
|
-
* ```
|
|
77
|
-
*/
|
|
78
|
-
declare class PGliteBridge extends Duplex {
|
|
79
|
-
private readonly pglite;
|
|
80
|
-
private readonly sessionLock;
|
|
81
|
-
private readonly bridgeId;
|
|
82
|
-
/** Incoming bytes not yet compacted into buf */
|
|
83
|
-
private pending;
|
|
84
|
-
private pendingLen;
|
|
85
|
-
/** Compacted input buffer for message framing */
|
|
86
|
-
private buf;
|
|
87
|
-
private phase;
|
|
88
|
-
private draining;
|
|
89
|
-
private tornDown;
|
|
90
|
-
/** Callbacks waiting for drain to process their data */
|
|
91
|
-
private drainQueue;
|
|
92
|
-
/** Buffered EQP messages awaiting Sync */
|
|
93
|
-
private pipeline;
|
|
94
|
-
private pipelineLen;
|
|
95
|
-
constructor(pglite: PGlite, sessionLock?: SessionLock);
|
|
96
|
-
connect(): this;
|
|
97
|
-
setKeepAlive(): this;
|
|
98
|
-
setNoDelay(): this;
|
|
99
|
-
setTimeout(): this;
|
|
100
|
-
ref(): this;
|
|
101
|
-
unref(): this;
|
|
102
|
-
_read(): void;
|
|
103
|
-
_write(chunk: Buffer, _encoding: BufferEncoding, callback: (error?: Error | null) => void): void;
|
|
104
|
-
/** Handles corked batches — pg.Client corks during prepared queries (P+B+D+E+S) */
|
|
105
|
-
_writev(chunks: Array<{
|
|
106
|
-
chunk: Buffer;
|
|
107
|
-
encoding: BufferEncoding;
|
|
108
|
-
}>, callback: (error?: Error | null) => void): void;
|
|
109
|
-
_final(callback: (error?: Error | null) => void): void;
|
|
110
|
-
_destroy(error: Error | null, callback: (error?: Error | null) => void): void;
|
|
111
|
-
/** Merge pending chunks into buf only when needed for framing */
|
|
112
|
-
private compact;
|
|
113
|
-
/**
|
|
114
|
-
* Enqueue a write callback and start draining if not already running.
|
|
115
|
-
* The callback is NOT called until drain has processed the data.
|
|
116
|
-
*/
|
|
117
|
-
private enqueue;
|
|
118
|
-
/**
|
|
119
|
-
* Process all pending data, looping until no new data arrives.
|
|
120
|
-
* Fires all queued callbacks on completion or error.
|
|
121
|
-
*/
|
|
122
|
-
private drain;
|
|
123
|
-
/**
|
|
124
|
-
* Frames and processes the startup message.
|
|
125
|
-
*
|
|
126
|
-
* Format: [4 bytes: total length] [4 bytes: protocol version] [key\0value\0 pairs]
|
|
127
|
-
* No type byte — length includes itself.
|
|
128
|
-
*/
|
|
129
|
-
private processPreStartup;
|
|
130
|
-
/**
|
|
131
|
-
* Frames and processes regular wire protocol messages.
|
|
132
|
-
*
|
|
133
|
-
* Extended Query Protocol messages (Parse, Bind, Describe, Execute, Close,
|
|
134
|
-
* Flush) are buffered in `this.pipeline`. When Sync arrives, the entire
|
|
135
|
-
* pipeline is concatenated and sent to PGlite as one atomic
|
|
136
|
-
* execProtocolRawStream call within one runExclusive.
|
|
137
|
-
*
|
|
138
|
-
* SimpleQuery messages are sent directly (they're self-contained).
|
|
139
|
-
*/
|
|
140
|
-
private processMessages;
|
|
141
|
-
/**
|
|
142
|
-
* Sends the accumulated EQP pipeline as one atomic operation.
|
|
143
|
-
*
|
|
144
|
-
* All buffered messages are concatenated into a single buffer and sent
|
|
145
|
-
* as one execProtocolRawStream call. This is both correct (prevents
|
|
146
|
-
* portal interleaving) and fast (1 WASM call + 1 async boundary instead
|
|
147
|
-
* of 5). Intermediate ReadyForQuery messages are stripped from the
|
|
148
|
-
* combined response.
|
|
149
|
-
*/
|
|
150
|
-
private flushPipeline;
|
|
151
|
-
/**
|
|
152
|
-
* Sends a message to PGlite and pushes response chunks directly to the
|
|
153
|
-
* stream as they arrive. Avoids collecting and concatenating for large
|
|
154
|
-
* multi-row responses (e.g., findMany 500 rows = ~503 onRawData chunks).
|
|
155
|
-
*
|
|
156
|
-
* Must be called inside runExclusive.
|
|
157
|
-
*/
|
|
158
|
-
private execAndPush;
|
|
159
|
-
private acquireSession;
|
|
160
|
-
private trackSessionStatus;
|
|
22
|
+
/** Clear all user tables. Call in `beforeEach` for per-test isolation. */
|
|
23
|
+
type ResetDbFn = () => Promise<void>;
|
|
24
|
+
type SnapshotDbFn = () => Promise<void>;
|
|
25
|
+
type ResetSnapshotFn = () => Promise<void>;
|
|
26
|
+
interface PgliteAdapter {
|
|
27
|
+
/** Prisma adapter — pass directly to `new PrismaClient({ adapter })` */
|
|
28
|
+
adapter: PrismaPg;
|
|
29
|
+
/** The underlying PGlite instance for direct SQL, snapshots, or extensions. */
|
|
30
|
+
pglite: _$_electric_sql_pglite0.PGlite;
|
|
31
|
+
/** Clear all user tables. Call in `beforeEach` for per-test isolation. */
|
|
32
|
+
resetDb: ResetDbFn;
|
|
33
|
+
/** Snapshot current DB state. Subsequent `resetDb` calls restore to this snapshot. */
|
|
34
|
+
snapshotDb: SnapshotDbFn;
|
|
35
|
+
/** Discard the current snapshot. Subsequent `resetDb` calls truncate to empty. */
|
|
36
|
+
resetSnapshot: ResetSnapshotFn;
|
|
37
|
+
/** Shut down pool and PGlite. Not needed in tests (process exit handles it). */
|
|
38
|
+
close: () => Promise<void>;
|
|
161
39
|
}
|
|
162
|
-
|
|
163
40
|
/**
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
41
|
+
* Creates a Prisma adapter backed by an in-process PGlite instance.
|
|
42
|
+
*
|
|
43
|
+
* Applies the schema and returns a ready-to-use adapter + a `resetDb`
|
|
44
|
+
* function for clearing tables between tests.
|
|
45
|
+
*/
|
|
46
|
+
declare const createPgliteAdapter: (options?: CreatePgliteAdapterOptions) => Promise<PgliteAdapter>;
|
|
47
|
+
//#endregion
|
|
48
|
+
//#region src/create-pool.d.ts
|
|
173
49
|
interface CreatePoolOptions {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
50
|
+
/** PGlite data directory. Omit for in-memory. */
|
|
51
|
+
dataDir?: string;
|
|
52
|
+
/** PGlite extensions (e.g., `{ uuid_ossp: uuidOssp() }`) */
|
|
53
|
+
extensions?: Extensions;
|
|
54
|
+
/** Maximum pool connections (default: 5) */
|
|
55
|
+
max?: number;
|
|
56
|
+
/** Existing PGlite instance to use instead of creating one */
|
|
57
|
+
pglite?: PGlite;
|
|
182
58
|
}
|
|
183
59
|
interface PoolResult {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
60
|
+
/** pg.Pool backed by PGlite — pass to PrismaPg */
|
|
61
|
+
pool: pg.Pool;
|
|
62
|
+
/** The underlying PGlite instance */
|
|
63
|
+
pglite: PGlite;
|
|
64
|
+
/** Shut down pool and PGlite */
|
|
65
|
+
close: () => Promise<void>;
|
|
190
66
|
}
|
|
191
67
|
/**
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
68
|
+
* Creates a pg.Pool where every connection is an in-process PGlite bridge.
|
|
69
|
+
*
|
|
70
|
+
* ```typescript
|
|
71
|
+
* import { createPool } from 'prisma-pglite-bridge';
|
|
72
|
+
* import { PrismaPg } from '@prisma/adapter-pg';
|
|
73
|
+
* import { PrismaClient } from '@prisma/client';
|
|
74
|
+
*
|
|
75
|
+
* const { pool, close } = await createPool();
|
|
76
|
+
* const adapter = new PrismaPg(pool);
|
|
77
|
+
* const prisma = new PrismaClient({ adapter });
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
204
80
|
declare const createPool: (options?: CreatePoolOptions) => Promise<PoolResult>;
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
/** The underlying PGlite instance for direct SQL, snapshots, or extensions. */
|
|
228
|
-
pglite: _electric_sql_pglite.PGlite;
|
|
229
|
-
/** Clear all user tables. Call in `beforeEach` for per-test isolation. */
|
|
230
|
-
resetDb: ResetDbFn;
|
|
231
|
-
/** Snapshot current DB state. Subsequent `resetDb` calls restore to this snapshot. */
|
|
232
|
-
snapshotDb: SnapshotDbFn;
|
|
233
|
-
/** Discard the current snapshot. Subsequent `resetDb` calls truncate to empty. */
|
|
234
|
-
resetSnapshot: ResetSnapshotFn;
|
|
235
|
-
/** Shut down pool and PGlite. Not needed in tests (process exit handles it). */
|
|
236
|
-
close: () => Promise<void>;
|
|
81
|
+
//#endregion
|
|
82
|
+
//#region src/session-lock.d.ts
|
|
83
|
+
/** Opaque bridge identity token */
|
|
84
|
+
type BridgeId = symbol;
|
|
85
|
+
declare class SessionLock {
|
|
86
|
+
private owner;
|
|
87
|
+
private waitQueue;
|
|
88
|
+
/**
|
|
89
|
+
* Acquire access to PGlite. Resolves immediately if no transaction is
|
|
90
|
+
* active or if this bridge owns the current transaction. Queues otherwise.
|
|
91
|
+
*/
|
|
92
|
+
acquire(id: BridgeId): Promise<void>;
|
|
93
|
+
/**
|
|
94
|
+
* Update session state based on the ReadyForQuery status byte.
|
|
95
|
+
* Call after every PGlite response that contains RFQ.
|
|
96
|
+
*/
|
|
97
|
+
updateStatus(id: BridgeId, status: number): void;
|
|
98
|
+
/**
|
|
99
|
+
* Release ownership (e.g., when a bridge is destroyed mid-transaction).
|
|
100
|
+
*/
|
|
101
|
+
release(id: BridgeId): void;
|
|
102
|
+
private drainWaitQueue;
|
|
237
103
|
}
|
|
104
|
+
//#endregion
|
|
105
|
+
//#region src/pglite-bridge.d.ts
|
|
238
106
|
/**
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
107
|
+
* Duplex stream that bridges `pg.Client` to an in-process PGlite instance.
|
|
108
|
+
*
|
|
109
|
+
* Replaces the TCP socket in `pg.Client` via the `stream` option. Speaks
|
|
110
|
+
* PostgreSQL wire protocol directly to PGlite — no TCP, no serialization
|
|
111
|
+
* overhead beyond what the wire protocol requires.
|
|
112
|
+
*
|
|
113
|
+
* Pass to `pg.Client` or use via `createPool()` / `createPgliteAdapter()`:
|
|
114
|
+
*
|
|
115
|
+
* ```typescript
|
|
116
|
+
* const client = new pg.Client({
|
|
117
|
+
* stream: () => new PGliteBridge(pglite),
|
|
118
|
+
* });
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
declare class PGliteBridge extends Duplex {
|
|
122
|
+
private readonly pglite;
|
|
123
|
+
private readonly sessionLock;
|
|
124
|
+
private readonly bridgeId;
|
|
125
|
+
/** Incoming bytes not yet compacted into buf */
|
|
126
|
+
private pending;
|
|
127
|
+
private pendingLen;
|
|
128
|
+
/** Compacted input buffer for message framing */
|
|
129
|
+
private buf;
|
|
130
|
+
private phase;
|
|
131
|
+
private draining;
|
|
132
|
+
private tornDown;
|
|
133
|
+
/** Callbacks waiting for drain to process their data */
|
|
134
|
+
private drainQueue;
|
|
135
|
+
/** Buffered EQP messages awaiting Sync */
|
|
136
|
+
private pipeline;
|
|
137
|
+
private pipelineLen;
|
|
138
|
+
constructor(pglite: PGlite, sessionLock?: SessionLock);
|
|
139
|
+
connect(): this;
|
|
140
|
+
setKeepAlive(): this;
|
|
141
|
+
setNoDelay(): this;
|
|
142
|
+
setTimeout(): this;
|
|
143
|
+
ref(): this;
|
|
144
|
+
unref(): this;
|
|
145
|
+
override _read(): void;
|
|
146
|
+
override _write(chunk: Buffer, _encoding: BufferEncoding, callback: (error?: Error | null) => void): void;
|
|
147
|
+
/** Handles corked batches — pg.Client corks during prepared queries (P+B+D+E+S) */
|
|
148
|
+
override _writev(chunks: Array<{
|
|
149
|
+
chunk: Buffer;
|
|
150
|
+
encoding: BufferEncoding;
|
|
151
|
+
}>, callback: (error?: Error | null) => void): void;
|
|
152
|
+
override _final(callback: (error?: Error | null) => void): void;
|
|
153
|
+
override _destroy(error: Error | null, callback: (error?: Error | null) => void): void;
|
|
154
|
+
/** Merge pending chunks into buf only when needed for framing */
|
|
155
|
+
private compact;
|
|
156
|
+
/**
|
|
157
|
+
* Enqueue a write callback and start draining if not already running.
|
|
158
|
+
* The callback is NOT called until drain has processed the data.
|
|
159
|
+
*/
|
|
160
|
+
private enqueue;
|
|
161
|
+
/**
|
|
162
|
+
* Process all pending data, looping until no new data arrives.
|
|
163
|
+
* Fires all queued callbacks on completion or error.
|
|
164
|
+
*/
|
|
165
|
+
private drain;
|
|
166
|
+
/**
|
|
167
|
+
* Frames and processes the startup message.
|
|
168
|
+
*
|
|
169
|
+
* Format: [4 bytes: total length] [4 bytes: protocol version] [key\0value\0 pairs]
|
|
170
|
+
* No type byte — length includes itself.
|
|
171
|
+
*/
|
|
172
|
+
private processPreStartup;
|
|
173
|
+
/**
|
|
174
|
+
* Frames and processes regular wire protocol messages.
|
|
175
|
+
*
|
|
176
|
+
* Extended Query Protocol messages (Parse, Bind, Describe, Execute, Close,
|
|
177
|
+
* Flush) are buffered in `this.pipeline`. When Sync arrives, the entire
|
|
178
|
+
* pipeline is concatenated and sent to PGlite as one atomic
|
|
179
|
+
* execProtocolRawStream call within one runExclusive.
|
|
180
|
+
*
|
|
181
|
+
* SimpleQuery messages are sent directly (they're self-contained).
|
|
182
|
+
*/
|
|
183
|
+
private processMessages;
|
|
184
|
+
/**
|
|
185
|
+
* Sends the accumulated EQP pipeline as one atomic operation.
|
|
186
|
+
*
|
|
187
|
+
* All buffered messages are concatenated into a single buffer and sent
|
|
188
|
+
* as one execProtocolRawStream call. This is both correct (prevents
|
|
189
|
+
* portal interleaving) and fast (1 WASM call + 1 async boundary instead
|
|
190
|
+
* of 5). Intermediate ReadyForQuery messages are stripped from the
|
|
191
|
+
* combined response.
|
|
192
|
+
*/
|
|
193
|
+
private flushPipeline;
|
|
194
|
+
/**
|
|
195
|
+
* Sends a message to PGlite and pushes response chunks directly to the
|
|
196
|
+
* stream as they arrive. Avoids collecting and concatenating for large
|
|
197
|
+
* multi-row responses (e.g., findMany 500 rows = ~503 onRawData chunks).
|
|
198
|
+
*
|
|
199
|
+
* Must be called inside runExclusive.
|
|
200
|
+
*/
|
|
201
|
+
private execAndPush;
|
|
202
|
+
private acquireSession;
|
|
203
|
+
private trackSessionStatus;
|
|
204
|
+
}
|
|
205
|
+
//#endregion
|
|
206
|
+
export { type CreatePgliteAdapterOptions, type CreatePoolOptions, PGliteBridge, type PgliteAdapter, type PoolResult, type ResetDbFn, type ResetSnapshotFn, SessionLock, type SnapshotDbFn, createPgliteAdapter, createPool };
|
|
207
|
+
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { PrismaPg } from "@prisma/adapter-pg";
|
|
2
|
+
import * as _$_electric_sql_pglite0 from "@electric-sql/pglite";
|
|
3
|
+
import { Extensions, PGlite } from "@electric-sql/pglite";
|
|
4
|
+
import pg from "pg";
|
|
5
|
+
import { Duplex } from "node:stream";
|
|
6
|
+
|
|
7
|
+
//#region src/create-pglite-adapter.d.ts
|
|
8
|
+
interface CreatePgliteAdapterOptions {
|
|
9
|
+
/** Path to prisma/migrations/ directory (auto-discovered via prisma.config.ts if omitted) */
|
|
10
|
+
migrationsPath?: string;
|
|
11
|
+
/** Pre-generated SQL to apply instead of auto-generating from schema */
|
|
12
|
+
sql?: string;
|
|
13
|
+
/** Root directory for prisma.config.ts discovery (default: process.cwd()). Set this in monorepos where tests run from the workspace root. */
|
|
14
|
+
configRoot?: string;
|
|
15
|
+
/** PGlite data directory. Omit for in-memory. */
|
|
16
|
+
dataDir?: string;
|
|
17
|
+
/** PGlite extensions (e.g., `{ uuid_ossp: uuidOssp() }`) */
|
|
18
|
+
extensions?: _$_electric_sql_pglite0.Extensions;
|
|
19
|
+
/** Maximum pool connections (default: 5) */
|
|
20
|
+
max?: number;
|
|
21
|
+
}
|
|
22
|
+
/** Clear all user tables. Call in `beforeEach` for per-test isolation. */
|
|
23
|
+
type ResetDbFn = () => Promise<void>;
|
|
24
|
+
type SnapshotDbFn = () => Promise<void>;
|
|
25
|
+
type ResetSnapshotFn = () => Promise<void>;
|
|
26
|
+
interface PgliteAdapter {
|
|
27
|
+
/** Prisma adapter — pass directly to `new PrismaClient({ adapter })` */
|
|
28
|
+
adapter: PrismaPg;
|
|
29
|
+
/** The underlying PGlite instance for direct SQL, snapshots, or extensions. */
|
|
30
|
+
pglite: _$_electric_sql_pglite0.PGlite;
|
|
31
|
+
/** Clear all user tables. Call in `beforeEach` for per-test isolation. */
|
|
32
|
+
resetDb: ResetDbFn;
|
|
33
|
+
/** Snapshot current DB state. Subsequent `resetDb` calls restore to this snapshot. */
|
|
34
|
+
snapshotDb: SnapshotDbFn;
|
|
35
|
+
/** Discard the current snapshot. Subsequent `resetDb` calls truncate to empty. */
|
|
36
|
+
resetSnapshot: ResetSnapshotFn;
|
|
37
|
+
/** Shut down pool and PGlite. Not needed in tests (process exit handles it). */
|
|
38
|
+
close: () => Promise<void>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Creates a Prisma adapter backed by an in-process PGlite instance.
|
|
42
|
+
*
|
|
43
|
+
* Applies the schema and returns a ready-to-use adapter + a `resetDb`
|
|
44
|
+
* function for clearing tables between tests.
|
|
45
|
+
*/
|
|
46
|
+
declare const createPgliteAdapter: (options?: CreatePgliteAdapterOptions) => Promise<PgliteAdapter>;
|
|
47
|
+
//#endregion
|
|
48
|
+
//#region src/create-pool.d.ts
|
|
49
|
+
interface CreatePoolOptions {
|
|
50
|
+
/** PGlite data directory. Omit for in-memory. */
|
|
51
|
+
dataDir?: string;
|
|
52
|
+
/** PGlite extensions (e.g., `{ uuid_ossp: uuidOssp() }`) */
|
|
53
|
+
extensions?: Extensions;
|
|
54
|
+
/** Maximum pool connections (default: 5) */
|
|
55
|
+
max?: number;
|
|
56
|
+
/** Existing PGlite instance to use instead of creating one */
|
|
57
|
+
pglite?: PGlite;
|
|
58
|
+
}
|
|
59
|
+
interface PoolResult {
|
|
60
|
+
/** pg.Pool backed by PGlite — pass to PrismaPg */
|
|
61
|
+
pool: pg.Pool;
|
|
62
|
+
/** The underlying PGlite instance */
|
|
63
|
+
pglite: PGlite;
|
|
64
|
+
/** Shut down pool and PGlite */
|
|
65
|
+
close: () => Promise<void>;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Creates a pg.Pool where every connection is an in-process PGlite bridge.
|
|
69
|
+
*
|
|
70
|
+
* ```typescript
|
|
71
|
+
* import { createPool } from 'prisma-pglite-bridge';
|
|
72
|
+
* import { PrismaPg } from '@prisma/adapter-pg';
|
|
73
|
+
* import { PrismaClient } from '@prisma/client';
|
|
74
|
+
*
|
|
75
|
+
* const { pool, close } = await createPool();
|
|
76
|
+
* const adapter = new PrismaPg(pool);
|
|
77
|
+
* const prisma = new PrismaClient({ adapter });
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
declare const createPool: (options?: CreatePoolOptions) => Promise<PoolResult>;
|
|
81
|
+
//#endregion
|
|
82
|
+
//#region src/session-lock.d.ts
|
|
83
|
+
/** Opaque bridge identity token */
|
|
84
|
+
type BridgeId = symbol;
|
|
85
|
+
declare class SessionLock {
|
|
86
|
+
private owner;
|
|
87
|
+
private waitQueue;
|
|
88
|
+
/**
|
|
89
|
+
* Acquire access to PGlite. Resolves immediately if no transaction is
|
|
90
|
+
* active or if this bridge owns the current transaction. Queues otherwise.
|
|
91
|
+
*/
|
|
92
|
+
acquire(id: BridgeId): Promise<void>;
|
|
93
|
+
/**
|
|
94
|
+
* Update session state based on the ReadyForQuery status byte.
|
|
95
|
+
* Call after every PGlite response that contains RFQ.
|
|
96
|
+
*/
|
|
97
|
+
updateStatus(id: BridgeId, status: number): void;
|
|
98
|
+
/**
|
|
99
|
+
* Release ownership (e.g., when a bridge is destroyed mid-transaction).
|
|
100
|
+
*/
|
|
101
|
+
release(id: BridgeId): void;
|
|
102
|
+
private drainWaitQueue;
|
|
103
|
+
}
|
|
104
|
+
//#endregion
|
|
105
|
+
//#region src/pglite-bridge.d.ts
|
|
106
|
+
/**
|
|
107
|
+
* Duplex stream that bridges `pg.Client` to an in-process PGlite instance.
|
|
108
|
+
*
|
|
109
|
+
* Replaces the TCP socket in `pg.Client` via the `stream` option. Speaks
|
|
110
|
+
* PostgreSQL wire protocol directly to PGlite — no TCP, no serialization
|
|
111
|
+
* overhead beyond what the wire protocol requires.
|
|
112
|
+
*
|
|
113
|
+
* Pass to `pg.Client` or use via `createPool()` / `createPgliteAdapter()`:
|
|
114
|
+
*
|
|
115
|
+
* ```typescript
|
|
116
|
+
* const client = new pg.Client({
|
|
117
|
+
* stream: () => new PGliteBridge(pglite),
|
|
118
|
+
* });
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
declare class PGliteBridge extends Duplex {
|
|
122
|
+
private readonly pglite;
|
|
123
|
+
private readonly sessionLock;
|
|
124
|
+
private readonly bridgeId;
|
|
125
|
+
/** Incoming bytes not yet compacted into buf */
|
|
126
|
+
private pending;
|
|
127
|
+
private pendingLen;
|
|
128
|
+
/** Compacted input buffer for message framing */
|
|
129
|
+
private buf;
|
|
130
|
+
private phase;
|
|
131
|
+
private draining;
|
|
132
|
+
private tornDown;
|
|
133
|
+
/** Callbacks waiting for drain to process their data */
|
|
134
|
+
private drainQueue;
|
|
135
|
+
/** Buffered EQP messages awaiting Sync */
|
|
136
|
+
private pipeline;
|
|
137
|
+
private pipelineLen;
|
|
138
|
+
constructor(pglite: PGlite, sessionLock?: SessionLock);
|
|
139
|
+
connect(): this;
|
|
140
|
+
setKeepAlive(): this;
|
|
141
|
+
setNoDelay(): this;
|
|
142
|
+
setTimeout(): this;
|
|
143
|
+
ref(): this;
|
|
144
|
+
unref(): this;
|
|
145
|
+
override _read(): void;
|
|
146
|
+
override _write(chunk: Buffer, _encoding: BufferEncoding, callback: (error?: Error | null) => void): void;
|
|
147
|
+
/** Handles corked batches — pg.Client corks during prepared queries (P+B+D+E+S) */
|
|
148
|
+
override _writev(chunks: Array<{
|
|
149
|
+
chunk: Buffer;
|
|
150
|
+
encoding: BufferEncoding;
|
|
151
|
+
}>, callback: (error?: Error | null) => void): void;
|
|
152
|
+
override _final(callback: (error?: Error | null) => void): void;
|
|
153
|
+
override _destroy(error: Error | null, callback: (error?: Error | null) => void): void;
|
|
154
|
+
/** Merge pending chunks into buf only when needed for framing */
|
|
155
|
+
private compact;
|
|
156
|
+
/**
|
|
157
|
+
* Enqueue a write callback and start draining if not already running.
|
|
158
|
+
* The callback is NOT called until drain has processed the data.
|
|
159
|
+
*/
|
|
160
|
+
private enqueue;
|
|
161
|
+
/**
|
|
162
|
+
* Process all pending data, looping until no new data arrives.
|
|
163
|
+
* Fires all queued callbacks on completion or error.
|
|
164
|
+
*/
|
|
165
|
+
private drain;
|
|
166
|
+
/**
|
|
167
|
+
* Frames and processes the startup message.
|
|
168
|
+
*
|
|
169
|
+
* Format: [4 bytes: total length] [4 bytes: protocol version] [key\0value\0 pairs]
|
|
170
|
+
* No type byte — length includes itself.
|
|
171
|
+
*/
|
|
172
|
+
private processPreStartup;
|
|
173
|
+
/**
|
|
174
|
+
* Frames and processes regular wire protocol messages.
|
|
175
|
+
*
|
|
176
|
+
* Extended Query Protocol messages (Parse, Bind, Describe, Execute, Close,
|
|
177
|
+
* Flush) are buffered in `this.pipeline`. When Sync arrives, the entire
|
|
178
|
+
* pipeline is concatenated and sent to PGlite as one atomic
|
|
179
|
+
* execProtocolRawStream call within one runExclusive.
|
|
180
|
+
*
|
|
181
|
+
* SimpleQuery messages are sent directly (they're self-contained).
|
|
182
|
+
*/
|
|
183
|
+
private processMessages;
|
|
184
|
+
/**
|
|
185
|
+
* Sends the accumulated EQP pipeline as one atomic operation.
|
|
186
|
+
*
|
|
187
|
+
* All buffered messages are concatenated into a single buffer and sent
|
|
188
|
+
* as one execProtocolRawStream call. This is both correct (prevents
|
|
189
|
+
* portal interleaving) and fast (1 WASM call + 1 async boundary instead
|
|
190
|
+
* of 5). Intermediate ReadyForQuery messages are stripped from the
|
|
191
|
+
* combined response.
|
|
192
|
+
*/
|
|
193
|
+
private flushPipeline;
|
|
194
|
+
/**
|
|
195
|
+
* Sends a message to PGlite and pushes response chunks directly to the
|
|
196
|
+
* stream as they arrive. Avoids collecting and concatenating for large
|
|
197
|
+
* multi-row responses (e.g., findMany 500 rows = ~503 onRawData chunks).
|
|
198
|
+
*
|
|
199
|
+
* Must be called inside runExclusive.
|
|
200
|
+
*/
|
|
201
|
+
private execAndPush;
|
|
202
|
+
private acquireSession;
|
|
203
|
+
private trackSessionStatus;
|
|
204
|
+
}
|
|
205
|
+
//#endregion
|
|
206
|
+
export { type CreatePgliteAdapterOptions, type CreatePoolOptions, PGliteBridge, type PgliteAdapter, type PoolResult, type ResetDbFn, type ResetSnapshotFn, SessionLock, type SnapshotDbFn, createPgliteAdapter, createPool };
|
|
207
|
+
//# sourceMappingURL=index.d.mts.map
|