@prisma/dev 0.24.17 → 0.25.1

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/dist/vite.d.ts ADDED
@@ -0,0 +1,204 @@
1
+ import { Plugin } from 'vite';
2
+ import { P as PersistenceMode } from './state-CNKFAMiX.js';
3
+ import 'valibot';
4
+
5
+ /**
6
+ * Names of the environment variables the plugin writes.
7
+ *
8
+ * Set an entry to `false` to skip that variable, or to a string to rename it.
9
+ */
10
+ interface PrismaDevEnvOptions {
11
+ /**
12
+ * Direct TCP connection string for the main database.
13
+ *
14
+ * Defaults to `DATABASE_URL`.
15
+ */
16
+ databaseUrl?: false | string;
17
+ /**
18
+ * The `prisma+postgres://` HTTP connection string, matching how a deployed
19
+ * Prisma Postgres database is addressed.
20
+ *
21
+ * Disabled by default, because it embeds an API key. Set a name to opt in.
22
+ */
23
+ prismaPostgresUrl?: false | string;
24
+ /**
25
+ * Direct TCP connection string for the shadow database, used by
26
+ * `prisma migrate`.
27
+ *
28
+ * Defaults to `SHADOW_DATABASE_URL`.
29
+ */
30
+ shadowDatabaseUrl?: false | string;
31
+ }
32
+
33
+ /**
34
+ * The running database, handed to {@link PrismaDevPluginOptions.onDatabaseReady}.
35
+ */
36
+ interface PrismaDevDatabase {
37
+ /**
38
+ * Direct TCP connection string for the main database.
39
+ */
40
+ readonly databaseUrl: string;
41
+ /**
42
+ * The variables this plugin manages, mapped to the local database, ready to
43
+ * spread into a subprocess environment.
44
+ *
45
+ * ```ts
46
+ * await execa("prisma", ["migrate", "deploy"], { env: { ...process.env, ...database.env } });
47
+ * ```
48
+ *
49
+ * Variables disabled through the `env` option are absent here.
50
+ */
51
+ readonly env: Readonly<Record<string, string>>;
52
+ /**
53
+ * The server name, matching the `name` option.
54
+ */
55
+ readonly name: string;
56
+ /**
57
+ * Whether this process started the database, as opposed to attaching to one
58
+ * that `prisma dev` was already running.
59
+ */
60
+ readonly owned: boolean;
61
+ /**
62
+ * The `prisma+postgres://` HTTP connection string. Carries an API key.
63
+ */
64
+ readonly prismaPostgresUrl: string;
65
+ /**
66
+ * Direct TCP connection string for the shadow database, which
67
+ * `prisma migrate dev` requires.
68
+ */
69
+ readonly shadowDatabaseUrl: string;
70
+ }
71
+ interface PrismaDevPluginOptions {
72
+ /**
73
+ * The port the database server listens on.
74
+ *
75
+ * Defaults to `51214`. Only the default falls back to another free port when
76
+ * taken; a port passed here is bound or the start fails, because a caller who
77
+ * names a port has something outside this process depending on it.
78
+ *
79
+ * A named `stateful` server records the ports it settled on and reuses them on
80
+ * the next start, so pinning is not required for a stable address.
81
+ */
82
+ databasePort?: number;
83
+ /**
84
+ * Whether to log the runtime's own debug output.
85
+ *
86
+ * Defaults to `false`.
87
+ */
88
+ debug?: boolean;
89
+ /**
90
+ * Which environment variables to write, and under what names.
91
+ *
92
+ * The plugin owns the variables named here and overwrites whatever the
93
+ * environment already holds, warning when it displaces a different value. Set
94
+ * an entry to `false` to keep your own value for that variable.
95
+ */
96
+ env?: PrismaDevEnvOptions;
97
+ /**
98
+ * Name of the server, which determines where its data is persisted.
99
+ *
100
+ * Defaults to `default`. Set this per project to keep data isolated.
101
+ */
102
+ name?: string;
103
+ /**
104
+ * Prepares the database before Vite finishes starting, typically by applying
105
+ * migrations and seeding.
106
+ *
107
+ * Runs after the environment variables have been written, and before any
108
+ * application or framework code has executed, so nothing can observe an
109
+ * unprepared database. `vite dev` waits for it, so a slow migration delays
110
+ * startup.
111
+ *
112
+ * Runs once per database, not once per dev server. A config restart that does
113
+ * not change this plugin's options keeps the running database, and so does not
114
+ * re-run this hook. It does run when the plugin attached to a database
115
+ * `prisma dev` already had running. Make it idempotent -- `prisma migrate
116
+ * deploy` already is.
117
+ *
118
+ * If it rejects, the database is shut down and Vite fails to start rather than
119
+ * serving against a half-prepared database.
120
+ *
121
+ * Prefer `database.env` over the ambient `process.env` when spawning a
122
+ * subprocess. See {@link PrismaDevDatabase.env} for why.
123
+ */
124
+ onDatabaseReady?: (this: void, database: PrismaDevDatabase) => Promise<void> | void;
125
+ /**
126
+ * Whether the database survives between runs.
127
+ *
128
+ * Defaults to `stateful`: data is persisted under `name` and survives dev
129
+ * server restarts.
130
+ *
131
+ * `stateless` keeps the database in memory and discards it on every shutdown,
132
+ * which gives a clean database on each start. Useful under `test`. Be aware
133
+ * that editing `vite.config.ts` or an `.env` file restarts the dev server, so
134
+ * it also discards the data.
135
+ *
136
+ * A `stateless` database is invisible to `prisma dev ls`, cannot be shared with
137
+ * a running `prisma dev`, and takes any free port rather than the documented
138
+ * defaults unless you set the port options explicitly.
139
+ */
140
+ persistenceMode?: PersistenceMode;
141
+ /**
142
+ * The port the Prisma Dev HTTP server listens on.
143
+ *
144
+ * Defaults to `51213`. See {@link databasePort} for how an explicitly
145
+ * requested port differs from the default.
146
+ */
147
+ port?: number;
148
+ /**
149
+ * The port the shadow database server listens on.
150
+ *
151
+ * Defaults to `51215`. See {@link databasePort} for how an explicitly
152
+ * requested port differs from the default.
153
+ */
154
+ shadowDatabasePort?: number;
155
+ /**
156
+ * The port the colocated Prisma Streams server listens on.
157
+ *
158
+ * Defaults to `51216`. See {@link databasePort} for how an explicitly
159
+ * requested port differs from the default.
160
+ */
161
+ streamsPort?: number;
162
+ /**
163
+ * Options to use when Vitest loaded the config, layered over the options here.
164
+ *
165
+ * Defaults to `false`, which starts no database under Vitest. Vitest reads the
166
+ * same `vite.config.ts`, so an opt-in keeps a plain test run from starting a
167
+ * database as a config side effect.
168
+ *
169
+ * Set it to an object to opt in. Each entry replaces the corresponding option
170
+ * above, which is how a test run gets its own database rather than sharing the
171
+ * one `vite dev` uses:
172
+ *
173
+ * ```ts
174
+ * prismaDev({
175
+ * name: "my-app",
176
+ * test: { name: "my-app-test", persistenceMode: "stateless" },
177
+ * });
178
+ * ```
179
+ *
180
+ * `test: {}` opts in with the options above unchanged.
181
+ */
182
+ test?: false | PrismaDevTestOptions;
183
+ }
184
+ /**
185
+ * The options {@link PrismaDevPluginOptions.test} may override.
186
+ *
187
+ * Every plugin option except `test` itself, so the override cannot nest.
188
+ */
189
+ type PrismaDevTestOptions = Omit<PrismaDevPluginOptions, "test">;
190
+ /**
191
+ * Runs a local Prisma Postgres database for the lifetime of the Vite dev server
192
+ * and exposes its connection strings through `process.env`.
193
+ *
194
+ * The database runs in the Vite process, so it cannot outlive it. Production
195
+ * builds and `vite preview` are unaffected.
196
+ *
197
+ * Connection strings are never exposed to client code. They are written to
198
+ * `process.env` only, which is what server-side code and Prisma Client read.
199
+ * Routing them through `define` or `import.meta.env` would inline database
200
+ * credentials into browser assets.
201
+ */
202
+ declare function prismaDev(options?: PrismaDevPluginOptions): Plugin;
203
+
204
+ export { type PrismaDevDatabase, type PrismaDevEnvOptions, type PrismaDevPluginOptions, type PrismaDevTestOptions, prismaDev as default, prismaDev };
package/dist/vite.js ADDED
@@ -0,0 +1 @@
1
+ import{a as P,b as u}from"./chunk-VSS2IOVU.js";import"./chunk-662IKR3V.js";import"./chunk-QDQPFKGQ.js";import"./chunk-KWCQYPJI.js";import{h as y,i as S,l as E}from"./chunk-HFONW2ZS.js";import"./chunk-ANHBRJRZ.js";import"./chunk-EDFHV3AK.js";import"./chunk-DWY47FQV.js";import"./chunk-DOJAPHLY.js";var L="DATABASE_URL",q="SHADOW_DATABASE_URL";function w(e,r={}){let{databaseUrl:t=L,prismaPostgresUrl:n=!1,shadowDatabaseUrl:s=q}=r,a=u(e);return[["databaseUrl",t,a.databaseUrl],["shadowDatabaseUrl",s,a.shadowDatabaseUrl],["prismaPostgresUrl",n,a.prismaPostgresUrl]].filter(i=>typeof i[1]=="string"&&i[1].length>0).map(([i,l,d])=>({key:i,name:l,value:d}))}function A(e,r){let t=[];for(let n of e){let s=r[n.name];s!==n.value&&(s!=null&&s!==""&&t.push({...n,previous:s}),r[n.name]=n.value)}return t}import{setTimeout as k}from"timers/promises";var N="default",V=15e3,B=250;async function O(e){let{lockRetryTimeoutMillis:r=V,persistenceMode:t="stateful",...n}=e??{};if(t==="stateless"){let{server:a}=await P({...n,persistenceMode:t});return b(a)}let s=Date.now()+r;for(;;)try{let{server:a}=await P({...n,persistenceMode:"stateful"});return b(a)}catch(a){if(!(a instanceof E))throw a;let o=await C(n.name,n.debug);if(o)return o;if(Date.now()>=s)throw a;await k(B)}}function b(e){return{close:()=>e.close(),database:e.database,http:e.http,name:e.name,owned:!0,ppg:e.ppg,server:e,shadowDatabase:e.shadowDatabase}}async function C(e,r){let t=await y(e??N,{debug:r});return!S(t)||!t.exports?null:{...t.exports,close:()=>Promise.resolve(),experimental:t.experimental,name:t.name,owned:!1}}var v=new Map;async function R(e){let{name:r}=e,t=G(e),n=v.get(r);if(n&&n.signature===t)return n.holders+=1,await h(r,n,!1);let s={holders:1,pending:$(e,n),signature:t};return v.set(r,s),await h(r,s,!0)}async function D(){await Promise.allSettled([...v.keys()].map(e=>F(e)))}async function h(e,r,t){let n;try{n=await r.pending}catch(a){throw x(e,r),a}let s=!1;return{release:async()=>{s||(s=!0,x(e,r)&&await n.close())},server:n,started:t}}function x(e,r){return r.holders-=1,r.holders>0||v.get(e)!==r?!1:(v.delete(e),!0)}async function $(e,r){return await T(r),await O(e)}async function F(e){let r=v.get(e);r&&(v.delete(e),await T(r))}async function T(e){if(!e)return;await(await e.pending.catch(()=>null))?.close()}function G(e){return JSON.stringify(e,Object.keys(e).sort())}var H=["SIGINT","SIGTERM"],U=!1;function _(){if(!U){U=!0,process.once("beforeExit",()=>{D()});for(let e of H)process.once(e,()=>{D().finally(()=>{process.kill(process.pid,e)})})}}var c="prisma-dev",W="default";function j(e={}){let r=J(e,z());if(r===null)return{apply:()=>!1,name:c};let{debug:t,env:n,name:s,onDatabaseReady:a,persistenceMode:o}=r,i=null;return{apply(d,m){return m.command==="serve"&&m.isPreview!==!0},async closeBundle(){await l()},async configureServer(d){let{logger:m}=d.config;_(),i=await R({databasePort:r.databasePort,debug:t,name:s,persistenceMode:o,port:r.port,shadowDatabasePort:r.shadowDatabasePort,streamsPort:r.streamsPort}),d.httpServer?.once("close",()=>{l()});let g=w(i.server,n),M=A(g,process.env);Q(m,i,g,M),a&&i.started&&await Y(a,K(i.server,g),m,l)},name:c};async function l(){let d=i;i=null,await d?.release()}}var Pe=j;function K(e,r){return{...u(e),env:Object.fromEntries(r.map(({name:t,value:n})=>[t,n])),name:e.name,owned:e.owned}}async function Y(e,r,t,n){try{await e(r)}catch(s){throw t.warn(`[${c}] \`onDatabaseReady\` failed, shutting the database down`,{timestamp:!0}),await n(),s}}function J(e,r){let{test:t=!1,...n}=e;return r?t===!1?null:I({...n,...t}):I(n)}function I(e){return{...e,name:e.name??W,persistenceMode:e.persistenceMode??"stateful"}}function z(){return process.env.VITEST!=null||process.env.VITEST_WORKER_ID!=null}function Q(e,r,t,n){let{server:s}=r,a=X(r),o=t.length>0?t.map(({name:i})=>i).join(", "):"no environment variables";e.info(`[${c}] ${a} database "${s.name}", set ${o}`,{timestamp:!0});for(let{key:i,name:l}of n)e.warn(`[${c}] ${l} pointed somewhere else, replaced it with the local database. Pass \`env: { ${i}: false }\` to keep your own value.`,{timestamp:!0})}function X({server:e,started:r}){return e.owned?r?"started":"reusing":"attached to already-running"}export{Pe as default,j as prismaDev};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prisma/dev",
3
- "version": "0.24.17",
3
+ "version": "0.25.1",
4
4
  "description": "A local Prisma Postgres server for development and testing",
5
5
  "type": "module",
6
6
  "author": "Igal Klebanov <igalklebanov@gmail.com> (https://github.com/igalklebanov)",
@@ -50,6 +50,16 @@
50
50
  "types": "./dist/state.d.cts",
51
51
  "default": "./dist/state.cjs"
52
52
  }
53
+ },
54
+ "./vite": {
55
+ "import": {
56
+ "types": "./dist/vite.d.ts",
57
+ "default": "./dist/vite.js"
58
+ },
59
+ "require": {
60
+ "types": "./dist/vite.d.cts",
61
+ "default": "./dist/vite.cjs"
62
+ }
53
63
  }
54
64
  },
55
65
  "keywords": [
@@ -62,6 +72,14 @@
62
72
  "testing"
63
73
  ],
64
74
  "license": "ISC",
75
+ "peerDependencies": {
76
+ "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
77
+ },
78
+ "peerDependenciesMeta": {
79
+ "vite": {
80
+ "optional": true
81
+ }
82
+ },
65
83
  "devDependencies": {
66
84
  "@arethetypeswrong/cli": "0.18.2",
67
85
  "@electric-sql/pglite-prepopulatedfs": "0.0.3",
@@ -74,6 +92,7 @@
74
92
  "pkg-types": "2.3.0",
75
93
  "tsup": "8.5.1",
76
94
  "typescript": "5.9.3",
95
+ "vite": "8.1.5",
77
96
  "vitest": "4.0.17",
78
97
  "common-stuff": "^0.0.0"
79
98
  },
@@ -1 +0,0 @@
1
- import{a as D}from"./chunk-662IKR3V.js";import{a as q,b as W,f as x}from"./chunk-PP43TGA5.js";import{a as N,b as R,c as M,d as I,e as v,f as $}from"./chunk-HFONW2ZS.js";import{d as _,j as y}from"./chunk-DWY47FQV.js";import{b as O}from"./chunk-DOJAPHLY.js";import X from"find-my-way";async function C(r,e){let{port:t}=e;if(e.dryRun)return{async close(){},port:t,url:`http://localhost:${t}`};let n=!!e.debug,[{registerAccelerateRoutes:s},{registerUtilityRoutes:i},{createHTTPServer:l}]=await Promise.all([import("./accelerate-45DUGMGZ.js"),import("./utility-YEFNU35E.js"),import("./server-QR7P25DP.js")]),a={databaseDumpPath:e.databaseDumpPath,db:r,debug:n,name:e.name,port:t,shadowDBPort:e.shadowDatabasePort},o=X({defaultRoute(m,d){O(d,"Not Found",404)},ignoreTrailingSlash:!1});s(o,a,n),i(o,a,n);let c=await l({router:o}).listen(t);return e.port=c.port,a.port=c.port,{async close(){let{Engine:m}=await import("./engine-YTEOPVUP.js");await Promise.allSettled([c.close(),m.stopAll()])},port:c.port,url:c.url}}import{isDeepStrictEqual as U}from"util";var Z="application/json",P={connection:"close","content-type":Z},T={apiVersion:"durable.streams/schema-registry/v1",schema:{additionalProperties:!0,properties:{applicationName:{type:["string","null"]},durationMs:{type:"number"},groupKey:{type:["string","null"]},query:{type:"string"},queryId:{type:"string"},reads:{type:"number"},rowsReturned:{type:"number"},tables:{items:{type:"string"},type:"array"},timestamp:{format:"date-time",type:"string"}},required:["durationMs","query","queryId","reads","rowsReturned","tables","timestamp"],type:"object"},search:{aliases:{applicationName:"applicationName",groupKey:"groupKey",queryId:"queryId"},fields:{applicationName:{bindings:[{jsonPointer:"/applicationName",version:1}],exact:!0,exists:!0,kind:"keyword"},eventTime:{bindings:[{jsonPointer:"/timestamp",version:1}],column:!0,exact:!0,exists:!0,kind:"date",sortable:!0},groupKey:{bindings:[{jsonPointer:"/groupKey",version:1}],exact:!0,exists:!0,kind:"keyword"},queryId:{bindings:[{jsonPointer:"/queryId",version:1}],exact:!0,exists:!0,kind:"keyword"}},primaryTimestampField:"eventTime"}};function F(r){return{...r,snapshot:async e=>await ee(r.url,e)}}async function j(r){let e={serverUrl:r.serverUrl,sqlitePath:r.sqlitePath,streamName:R,url:v(r.serverUrl,R)};await te(e);let t=new k({debug:r.debug,streamUrl:e.url}),n=r.bridge.subscribe(s=>{t.enqueue(s)});return{close:async()=>{n(),await t.close()},experimental:e}}async function ee(r,e){if(!r)return q();let t=await re(r);return W(t,e)}async function re(r){let e=await fetch(`${r}?offset=-1&format=json`,{headers:{connection:"close"}});if(!e.ok)throw new Error(`Failed to read ${r}: HTTP ${e.status}`);return await e.json()}var k=class{#t;#r;#e;constructor(e){this.#t=e.debug,this.#r=Promise.resolve(),this.#e=e.streamUrl}enqueue(e){e.length!==0&&(this.#r=this.#r.then(async()=>{await ae(this.#e,e),this.#t&&console.debug(`[streams] appended ${e.length} query insight record(s) to ${this.#e}`)}).catch(t=>{console.error("[streams] failed to ingest query insights into prisma-queries",t)}))}async close(){await this.#r}};async function te(r){let e=await fetch(r.url,{headers:P,method:"PUT"});if(!e.ok)throw await b(e,`Failed to create ${r.streamName}`);let t=await se(r);if(ne(t,r.streamName))return;if(t.currentVersion>0)throw new Error(`Failed to install schema for ${r.streamName}: existing schema registry is incompatible and requires a lens migration`);let n=await fetch(`${r.url}/_schema`,{body:JSON.stringify(T),headers:P,method:"POST"});if(!n.ok)throw await b(n,`Failed to install schema for ${r.streamName}`)}function ne(r,e){if(r.currentVersion<=0||r.schema!==e)return!1;let t=r.schemas[String(r.currentVersion)];return U(t,T.schema)&&U(r.search,T.search)}async function se(r){let e=await fetch(`${r.url}/_schema`,{headers:P,method:"GET"});if(!e.ok)throw await b(e,`Failed to inspect schema for ${r.streamName}`);return await e.json()}async function ae(r,e){let t=await fetch(r,{body:JSON.stringify(e),headers:P,method:"POST"});if(!t.ok)throw await b(t,"Failed to append to prisma-queries")}async function b(r,e){let t=await r.text().catch(()=>"");return new Error(`${e}: HTTP ${r.status}${t?` ${t}`:""}`)}import{randomUUID as ie}from"crypto";import{setTimeout as H}from"timers/promises";import{isDeepStrictEqual as L}from"util";import{process as oe}from"std-env";var le="application/json",S={connection:"close","content-type":le},ce={apiVersion:"durable.streams/profile/v1",profile:{kind:"state-protocol",touch:{enabled:!0,onMissingBefore:"coarse"}}},A={apiVersion:"durable.streams/schema-registry/v1",schema:{additionalProperties:!0,properties:{headers:{properties:{operation:{type:"string"},timestamp:{format:"date-time",type:"string"}},required:["timestamp","operation"],type:"object"},key:{type:"string"},type:{type:"string"}},required:["type","key","headers"],type:"object"},search:{aliases:{rowKey:"key",table:"type"},fields:{eventTime:{bindings:[{jsonPointer:"/headers/timestamp",version:1}],column:!0,exact:!0,exists:!0,kind:"date",sortable:!0},key:{bindings:[{jsonPointer:"/key",version:1}],exact:!0,exists:!0,kind:"keyword"},operation:{bindings:[{jsonPointer:"/headers/operation",version:1}],exact:!0,exists:!0,kind:"keyword"},type:{bindings:[{jsonPointer:"/type",version:1}],exact:!0,exists:!0,kind:"keyword"}},primaryTimestampField:"eventTime"}};async function V(r){let{dbServer:e,debug:t,name:n,persistenceMode:s,port:i,queryInsightsBridge:l,walBridge:a}=r,o=s==="stateless",c=o?we(n):n,m=I(c),d=!o&&await _(m);oe.env.DS_LOCAL_DATA_ROOT=M(),o&&await y(m);let u=await ue({debug:t,hadExistingStreamsData:d,name:c,port:i}),h={serverUrl:u.exports.http.url,sqlitePath:u.exports.sqlite.path,streamName:N,url:v(u.exports.http.url)};try{await he(h);let p=await j({bridge:l,debug:t,serverUrl:u.exports.http.url,sqlitePath:u.exports.sqlite.path}),g=new Q({dbServer:e,debug:t,streamUrl:h.url}),Y=a.subscribe(z=>{g.enqueue(z)});return{close:async()=>{Y(),await g.close(),await p.close(),await u.close(),await H(100),o&&await y(m)},experimental:h,experimentalQueryInsights:p.experimental}}catch(p){throw await u.close().catch(()=>{}),await H(100),o&&await y(m).catch(()=>{}),p}}var me=["database disk image is malformed","duplicate column name:","file is not a database","malformed database schema","no such column:","no such table:","schema_version row missing after migration","unexpected schema version:"];async function ue(r){let{debug:e,hadExistingStreamsData:t,name:n,port:s}=r,{startLocalDurableStreamsServer:i}=await import("@prisma/streams-local"),l=()=>i({hostname:"127.0.0.1",name:n,port:s});try{return await l()}catch(a){if(!t||!pe(a))throw a;return console.warn(`[streams] resetting incompatible durable streams data for "${n}"`),e&&console.debug(`[streams] original durable streams startup error for "${n}"`,a),await y(I(n)),await l()}}function pe(r){return de(r).map(t=>t.toLowerCase()).some(t=>me.some(n=>t.includes(n)))}function de(r){let e=[],t=[r],n=new Set;for(;t.length>0;){let s=t.shift();if(!(s==null||n.has(s))){if(n.add(s),typeof s=="string"){e.push(s);continue}if(s instanceof AggregateError)for(let i of s.errors)t.push(i);if(s instanceof Error){e.push(s.message);let i=s.cause;i!==void 0&&t.push(i)}}}return e}var Q=class{#t;#r;#e;#n;#s;constructor(e){this.#t=e.dbServer,this.#r=e.debug,this.#e=Promise.resolve(),this.#n=e.streamUrl,this.#s=new Set}enqueue(e){e.length!==0&&(this.#e=this.#e.then(async()=>{let t=await this.#i(e);t.length!==0&&(await Se(this.#n,t),this.#r&&console.debug(`[streams] appended ${t.length} state-protocol record(s) to ${this.#n}`))}).catch(t=>{console.error("[streams] failed to ingest WAL events into prisma-wal",t)}))}async close(){await this.#e}async#i(e){let t=[],n=new Date().toISOString();for(let s of e)t.push(...await this.#o(s,n));return t}async#o(e,t){let n=`${e.schema}.${e.table}`,s=await this.#t.getPrimaryKeyColumns(e.schema,e.table),i=K(e.record),l=K(e.oldRecord),a=this.#a(n,s,l),o=this.#a(n,s,i),c=e.txid===""?void 0:e.txid;return e.type==="insert"?i&&o?[{headers:{operation:"insert",timestamp:t,txid:c},key:o,old_value:null,type:n,value:i}]:[]:e.type==="delete"?l&&a?[{headers:{operation:"delete",timestamp:t,txid:c},key:a,old_value:l,type:n,value:null}]:[]:!i||!l||!a||!o?[]:a!==o?[{headers:{operation:"delete",timestamp:t,txid:c},key:a,old_value:l,type:n,value:null},{headers:{operation:"insert",timestamp:t,txid:c},key:o,old_value:null,type:n,value:i}]:[{headers:{operation:"update",timestamp:t,txid:c},key:o,old_value:l,type:n,value:i}]}#a(e,t,n){if(!n)return null;let s=fe(n,t);return s||(this.#s.has(e)||(this.#s.add(e),console.warn(`[streams] falling back to full-row keys for ${e} because no primary key could be resolved`)),ve(n))}};async function he(r){let e=await fetch(r.url,{headers:S,method:"PUT"});if(!e.ok)throw await f(e,`Failed to create ${r.streamName}`);let t=await fetch(`${r.url}/_profile`,{body:JSON.stringify(ce),headers:S,method:"POST"});if(!t.ok)throw await f(t,`Failed to configure ${r.streamName}`);let n=await ge(r);if(ye(n,r.streamName))return;if(n.currentVersion>0)throw new Error(`Failed to install schema for ${r.streamName}: existing schema registry is incompatible and requires a lens migration`);let s=await fetch(`${r.url}/_schema`,{body:JSON.stringify(A),headers:S,method:"POST"});if(!s.ok)throw await f(s,`Failed to install schema for ${r.streamName}`)}async function ge(r){let e=await fetch(`${r.url}/_schema`,{headers:S,method:"GET"});if(!e.ok)throw await f(e,`Failed to inspect schema for ${r.streamName}`);return await e.json()}function ye(r,e){if(r.currentVersion<=0||r.schema!==e)return!1;let t=r.schemas[String(r.currentVersion)];return L(t,A.schema)&&L(r.search,A.search)}async function Se(r,e){let t=await fetch(r,{body:JSON.stringify(e),headers:S,method:"POST"});if(!t.ok)throw await f(t,"Failed to append to prisma-wal")}async function f(r,e){let t=await r.text().catch(()=>"");return new Error(`${e}: HTTP ${r.status}${t?` ${t}`:""}`)}function fe(r,e){if(e.length===0)return null;let t=[];for(let n of e){if(!Object.prototype.hasOwnProperty.call(r,n))return null;let s=Ee(r[n]);if(s==null)return null;t.push(e.length===1?s:`${n}=${s}`)}return t.join("|")}function ve(r){return JSON.stringify(B(r))}function B(r){return Array.isArray(r)?r.map(e=>B(e)):r&&typeof r=="object"?Object.fromEntries(Object.entries(r).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>[e,B(t)])):r}function K(r){return r?structuredClone(r):null}function Ee(r){if(r===null)return"null";if(r===void 0)return"undefined";if(typeof r=="string")return r;if(typeof r=="number")return Number.isFinite(r)?String(r):null;if(typeof r=="bigint")return r.toString();if(typeof r=="boolean")return r?"true":"false";try{return JSON.stringify(r)}catch{return null}}function we(r){return`${r}.${ie().replaceAll("-","")}`}async function J(r){let e=await $.createExclusively(r),t=null,n=null,s=null,i=null;try{[t,s]=await Promise.all([x("database",e),x("shadow_database",e)]);let l,a;e.dryRun?(l=Re(),a=Ie(),i=Te()):(l=await t.attachWalEventBridge(),a=await t.attachQueryInsightsBridge(),i=await V({dbServer:t,debug:e.debug,name:e.name,port:e.streamsPort,persistenceMode:e.persistenceMode,queryInsightsBridge:a,walBridge:l})),n=await C(t,e);let o=Pe(t,s,n,e);await e.writeServerDump(o,e.dryRun?{}:{queryInsights:i.experimentalQueryInsights,streams:i.experimental});let c=xe(l),m=F(i.experimentalQueryInsights),d=t,u=s,h=n,p=i,g=async()=>{c.close(),await G(e,[h,p,d,u])};return{close:g,dbServer:t,httpServer:n,server:{...o,close:g,experimental:{queryInsights:m,streams:i.experimental,wal:c.api},name:e.name},serverState:e,shadowDbServer:s,streamsServer:i,queryInsightsBridge:a,walBridge:l}}catch(l){return await be(e,[n,i,t,s],l)}}function Pe(r,e,t,n){let s=`prisma+postgres://localhost:${t.port}/?${new URLSearchParams({api_key:D({databaseUrl:r.prismaORMConnectionString,name:n.name,shadowDatabaseUrl:e.prismaORMConnectionString})}).toString()}`;return{database:{connectionString:r.connectionString,prismaORMConnectionString:r.prismaORMConnectionString,terminalCommand:r.terminalCommand},http:{url:t.url},ppg:{url:s},shadowDatabase:{connectionString:e.prismaORMConnectionString,prismaORMConnectionString:e.prismaORMConnectionString,terminalCommand:e.terminalCommand}}}async function G(r,e){let t=[];for(let n of e)try{await n.close()}catch(s){t.push(s)}try{await r.close()}catch(n){t.push(n)}if(t.length>0)throw new AggregateError(t,"Failed to close some servers")}async function be(r,e,t){try{await G(r,e.filter(n=>n!==null))}catch(n){throw new AggregateError([t,n],"Failed to start Prisma Dev server cleanly")}throw t}function xe(r){let e=new Set;return{api:{stream:()=>{let t=()=>{},n=ke(r,()=>{e.delete(t)});return t=()=>n.close(),e.add(t),n.stream},subscribe:t=>r.subscribe(t)},close:()=>{for(let t of[...e])t();e.clear()}}}function Re(){return{async close(){},async poll(){},subscribe(){return()=>{}}}}function Ie(){return{async close(){},subscribe(){return()=>{}}}}function Te(){return{async close(){},experimental:{serverUrl:"",sqlitePath:"",streamName:"",url:""},experimentalQueryInsights:{serverUrl:"",sqlitePath:"",streamName:"",url:""}}}function ke(r,e){let t=[],n=!1,s=null,i=r.subscribe(a=>{if(!n){if(s){let o=s;s=null,o.resolve({done:!1,value:a});return}t.push(a)}}),l=()=>{if(!n&&(n=!0,i(),t.length=0,e(),s)){let a=s;s=null,a.resolve({done:!0,value:void 0})}};return{close:l,stream:{[Symbol.asyncIterator](){return this},next(){return t.length>0?Promise.resolve({done:!1,value:t.shift()}):n?Promise.resolve({done:!0,value:void 0}):new Promise((a,o)=>{s={reject:o,resolve:a}})},return(){return l(),Promise.resolve({done:!0,value:void 0})},throw(a){let o=s;return l(),o&&o.reject(a),Promise.reject(a instanceof Error?a:new Error(String(a)))}}}}async function Ae(r){let{server:e}=await J(r);return e}async function pr(r){return await Ae(r)}export{Ae as a,pr as b};
@@ -1,107 +0,0 @@
1
- import{c as I}from"./chunk-KWCQYPJI.js";import{h as T}from"./chunk-EDFHV3AK.js";import{d as L,f as O}from"./chunk-DWY47FQV.js";import{createConnection as ke,createServer as qe}from"net";import{join as Fe}from"path";import{filename as Ue}from"pathe/utils";import{performance as W}from"perf_hooks";import{protocol as we}from"@electric-sql/pglite";import{Buffer as de}from"buffer";var C=500,Q=/(?:"[^"]+"|`[^`]+`|\[[^\]]+\]|\w+)/,me=new RegExp(`(?:${Q.source}\\.)*${Q.source}`),pe=new RegExp(`(?:FROM|JOIN|UPDATE|INTO|TABLE)\\s+(${me.source})`,"gi"),ge=/"([^"]+)"|`([^`]+)`|\[([^\]]+)\]|(\w+)/g,$=/prismaQuery='([^']+)'/,fe=new Set([S(`
2
- select b.oid, b.typarray
3
- from pg_catalog.pg_type a
4
- left join pg_catalog.pg_type b on b.oid = a.typelem
5
- where a.typcategory = $1
6
- group by b.oid, b.typarray
7
- order by b.oid
8
- `),S('GRANT "pg_write_all_data" TO "prisma_application"'),S("SELECT SUM(reads)::BIGINT AS reads, SUM(writes)::BIGINT AS writes, SUM(COALESCE(extends, $1))::BIGINT AS extends FROM pg_stat_io"),S("SELECT pg_database_size(current_database())::BIGINT, SUM(pg_total_relation_size(relid))::BIGINT AS pg_total_relation_size FROM pg_stat_user_tables"),S("SELECT COUNT(*) AS cnt FROM pg_stat_activity WHERE pid <> pg_backend_pid() and xact_start notnull")]),ye=[/^BEGIN\b/i,/^COMMIT\b/i,/^ROLLBACK\b/i,/^SAVEPOINT\b/i,/^RELEASE\b/i,/^SET\b/i,/^SHOW\b/i,/^DISCARD\b/i,/^DEALLOCATE\b/i,/^CLOSE\b/i,/^CREATE EXTENSION\b/i,/^WITH state_assign\b/i];function Ze(){return{generatedAt:Date.now(),queries:[]}}function S(e){return e.replace(/\s+/g," ").trim()}function G(e){return U(S(e))}function k(e){if(!e?.action||!e.model&&/raw/i.test(e.action))return null;let t=e.payload?U(JSON.stringify(e.payload)):"0";return`${e.model??""}.${e.action}:${t}`}function Ee(e){let t=new Set;for(let r of e.matchAll(pe)){let n=r[1];if(!n)continue;let a;for(let s of n.matchAll(ge))a=s[1]??s[2]??s[3]??s[4];a&&!a.startsWith("pg_")&&t.add(a)}return Array.from(t)}function Se(e){return fe.has(e)?!0:ye.some(t=>t.test(e))}function q(e){if(Se(S(e)))return null;let t=Ee(e);return t.length===0&&/\bpg_\w+/i.test(e)?null:t}function N(e){if(Array.isArray(e))return e.map(N);if(e!==null&&typeof e=="object"){let t=e;return t.$type==="Param"?"<<redacted>>":Object.fromEntries(Object.entries(t).map(([r,n])=>[r,N(n)]))}return e}function F(e){let t=e.match($);if(!t?.[1])return{cleanedSql:S(e),prismaQueryInfo:null};let r=e.replace($,"");r=r.replace(/,\s*,/g,",").replace(/\/\*\s*,/g,"/*").replace(/,\s*\*\//g,"*/").replace(/\/\*\s*\*\//g,"").replace(/\s+/g," ").trim();let n=decodeURIComponent(t[1]),a=n.indexOf(":");if(a===-1)return{cleanedSql:r,prismaQueryInfo:{action:n,isRaw:!0}};let s=n.slice(0,a),d=n.slice(a+1),o=s.indexOf("."),u=o===-1?void 0:s.slice(0,o),c=o===-1?s:s.slice(o+1);if(!c)return{cleanedSql:r,prismaQueryInfo:null};let l;try{l=N(JSON.parse(de.from(d,"base64url").toString("utf8")))}catch{l=void 0}return{cleanedSql:r,prismaQueryInfo:{action:c,isRaw:!1,model:u,payload:l}}}function et(e,t={}){let r=new Set(t.excludeApplications??[]),n=be(t.limit),a=typeof t.since=="number"&&Number.isFinite(t.since)?t.since:null,s=new Map;for(let o of e){if(o.applicationName&&r.has(o.applicationName))continue;let u=Date.parse(o.timestamp);if(!Number.isFinite(u))continue;let c=`${o.queryId}:${o.groupKey??""}`,l=s.get(c);if(!l){s.set(c,{count:1,duration:o.durationMs,groupKey:o.groupKey,id:c,lastSeen:u,maxDurationMs:o.durationMs,minDurationMs:o.durationMs,prismaQueryInfo:o.prismaQueryInfo,query:o.query,queryId:o.queryId,reads:o.reads,rowsReturned:o.rowsReturned,tables:o.tables,totalDurationMs:o.durationMs});continue}l.count+=1,l.lastSeen=Math.max(l.lastSeen,u),l.maxDurationMs=Math.max(l.maxDurationMs??o.durationMs,o.durationMs),l.minDurationMs=Math.min(l.minDurationMs??o.durationMs,o.durationMs),l.reads+=o.reads,l.rowsReturned+=o.rowsReturned,l.totalDurationMs+=o.durationMs,l.duration=l.totalDurationMs/l.count,!l.prismaQueryInfo&&o.prismaQueryInfo&&(l.prismaQueryInfo=o.prismaQueryInfo),l.tables.length===0&&o.tables.length>0&&(l.tables=o.tables)}let d=Array.from(s.values()).filter(o=>a===null||o.lastSeen>=a).sort((o,u)=>u.lastSeen-o.lastSeen).slice(0,n).map(({totalDurationMs:o,...u})=>u);return{generatedAt:Date.now(),queries:d}}function be(e){return typeof e=="number"&&Number.isInteger(e)&&Number.isSafeInteger(e)&&e>0?Math.min(e,C):C}function U(e){let t=5381;for(let r=0;r<e.length;r++)t=(t<<5)+t+e.charCodeAt(r)&4294967295;return(t>>>0).toString(36)}var P=new WeakMap;function H(e){let t=P.get(e);if(t&&!t.closed)return t.bridge;let r=Pe(e),n={bridge:{close:()=>(n.closed||(n.closed=!0,n.sessions.clear(),n.subscribers.clear(),n.queryQueue.enqueue=n.originalEnqueue,n.queryQueue.clearQueueForHandler=n.originalClearQueueForHandler,P.delete(e)),Promise.resolve()),subscribe:a=>(n.subscribers.add(a),()=>{n.subscribers.delete(a)})},closed:!1,originalClearQueueForHandler:r.clearQueueForHandler.bind(r),originalEnqueue:r.enqueue.bind(r),queryQueue:r,sessions:new Map,subscribers:new Set};return r.clearQueueForHandler=a=>{n.sessions.delete(a),n.originalClearQueueForHandler(a)},r.enqueue=async(a,s,d)=>{let o=he(n,a),u=Ne(s);Te(o,u);let c=Ie(o,u);if(!c)return await n.originalEnqueue(a,s,d);let l={commandTags:[],dataRowCount:0},f=new we.Parser,i=W.now(),m=await n.originalEnqueue(a,s,b=>{f.parse(b,ce=>{Me(l,ce)}),d(b)}),g=Math.max(0,W.now()-i);return Be(n,{applicationName:c.applicationName,durationMs:g,query:c.query,responseStats:l}),m},P.set(e,n),n.bridge}async function K(e){await P.get(e)?.bridge.close()}function Pe(e){let t=e.queryQueue;if(!t||typeof t.enqueue!="function"||typeof t.clearQueueForHandler!="function")throw new Error("PGLiteSocketServer query queue is unavailable for query insights capture");return t}function he(e,t){let r=e.sessions.get(t);if(r)return r;let n={applicationName:null,portals:new Map,statements:new Map};return e.sessions.set(t,n),n}function Te(e,t){if(t)switch(t.kind){case"startup":e.applicationName=t.applicationName;return;case"parse":e.statements.set(t.statementName,t.query);return;case"bind":{let r=e.statements.get(t.statementName);r&&e.portals.set(t.portalName,r);return}case"close":t.target==="portal"?e.portals.delete(t.name):e.statements.delete(t.name);return;default:return}}function Ie(e,t){if(!t)return null;if(t.kind==="query")return{applicationName:e.applicationName,query:t.query};if(t.kind==="execute"){let r=e.portals.get(t.portalName);return r?{applicationName:e.applicationName,query:r}:null}return null}function Ne(e){let t=Buffer.from(e);if(t.length<4)return null;let r=t.readInt32BE(0);if(t.length>=8&&r===t.length){let a=t.readInt32BE(4);if(a===196608||a===196608)return Re(t)}if(t.length<5)return null;switch(String.fromCharCode(t[0]??0)){case"Q":return _e(t);case"P":return xe(t);case"B":return Ae(t);case"E":return De(t);case"C":return ve(t);default:return null}}function Re(e){let t=8,r=null;for(;t<e.length-1;){let n=E(e,t);if(!n||n.value==="")break;t=n.nextOffset;let a=E(e,t);if(!a)break;t=a.nextOffset,n.value==="application_name"&&(r=a.value)}return{applicationName:r,kind:"startup"}}function _e(e){let t=E(e,5);return t?{kind:"query",query:t.value}:null}function xe(e){let t=E(e,5);if(!t)return null;let r=E(e,t.nextOffset);return r?{kind:"parse",query:r.value,statementName:t.value}:null}function Ae(e){let t=E(e,5);if(!t)return null;let r=E(e,t.nextOffset);return r?{kind:"bind",portalName:t.value,statementName:r.value}:null}function De(e){let t=E(e,5);return t?{kind:"execute",portalName:t.value}:null}function ve(e){if(e.length<7)return null;let t=e[5];if(t===void 0)return null;let r=E(e,6);return r?{kind:"close",name:r.value,target:t===80?"portal":"statement"}:null}function E(e,t){let r=e.indexOf(0,t);return r===-1?null:{nextOffset:r+1,value:e.toString("utf8",t,r)}}function Me(e,t){if(t.name==="dataRow"){e.dataRowCount+=1;return}t.name==="commandComplete"&&typeof t.text=="string"&&t.text.length>0&&e.commandTags.push(t.text)}function Be(e,t){let r=F(t.query),n=q(r.cleanedSql);if(!n)return;let a=G(r.cleanedSql),s={applicationName:t.applicationName,durationMs:t.durationMs,groupKey:k(r.prismaQueryInfo),prismaQueryInfo:r.prismaQueryInfo,query:r.cleanedSql,queryId:a,reads:0,rowsReturned:Le(t.responseStats),tables:n,timestamp:new Date().toISOString()};for(let d of e.subscribers)d([s])}function Le(e){let t=e.commandTags.reduce((r,n)=>r+Oe(n),0);return Math.max(t,e.dataRowCount)}function Oe(e){let t=e.trim().split(/\s+/).at(-1);return!t||!/^\d+$/.test(t)?0:Number(t)}import{protocol as J}from"@electric-sql/pglite";var y="_prisma_dev_wal",A="events",X="install_all_triggers",Y="capture_event",z="prisma_dev_wal_capture",w=new WeakMap,Ce=new Set(["ALTER","COMMIT","COPY","CREATE","DELETE","DROP","INSERT","MERGE","TRUNCATE","UPDATE"]);async function D(e,t){let r=w.get(e);if(r&&!r.closed)return r.bridge;let n=e.execProtocolRaw.bind(e),a=e.execProtocolRawStream.bind(e),s={bridge:{close:async()=>{s.closed||(s.closed=!0,s.subscribers.clear(),e.execProtocolRaw===d&&(e.execProtocolRaw=n),e.execProtocolRawStream===o&&(e.execProtocolRawStream=a),await s.pollPromise,w.delete(e))},poll:async()=>{await x(s,e)},subscribe:u=>(s.subscribers.add(u),()=>{s.subscribers.delete(u)})},closed:!1,ensureInfrastructurePromise:null,pendingPoll:!1,pollPromise:null,subscribers:new Set,suppressDepth:0},d=async(u,c)=>{let l=await n(u,c);return!s.closed&&s.suppressDepth===0&&V(l)&&x(s,e),l},o=async(u,c)=>{let l=[],f=new J.Parser,i=c?.onRawData;await a(u,{...c,onRawData:m=>{f.parse(m,g=>{l.push(g)}),i?.(m)}}),!s.closed&&s.suppressDepth===0&&v(l)&&x(s,e)};return e.execProtocolRaw=d,e.execProtocolRawStream=o,w.set(e,s),await Z(s,e),s.bridge}async function j(e){let t=w.get(e);t&&await t.bridge.close()}function v(e){for(let t of e){if(t.name!=="commandComplete"||typeof t.text!="string")continue;let r=t.text.split(/\s+/,1)[0]?.toUpperCase();if(r&&Ce.has(r))return!0}return!1}function V(e){if(e.length===0)return!1;let t=[];return new J.Parser().parse(e,n=>{t.push(n)}),v(t)}async function Z(e,t){e.ensureInfrastructurePromise??=M(e,t,async()=>{await t.exec(`CREATE SCHEMA IF NOT EXISTS "${y}"`),await t.exec(`
9
- CREATE TABLE IF NOT EXISTS "${y}"."${A}" (
10
- id BIGSERIAL PRIMARY KEY,
11
- txid BIGINT NOT NULL DEFAULT txid_current(),
12
- schema_name TEXT NOT NULL,
13
- table_name TEXT NOT NULL,
14
- op TEXT NOT NULL,
15
- row_data JSONB,
16
- old_row_data JSONB,
17
- created_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp()
18
- )
19
- `),await t.exec(`
20
- CREATE OR REPLACE FUNCTION "${y}"."${Y}"()
21
- RETURNS trigger
22
- LANGUAGE plpgsql
23
- AS $$
24
- BEGIN
25
- IF TG_TABLE_SCHEMA = '${y}' THEN
26
- RETURN COALESCE(NEW, OLD);
27
- END IF;
28
-
29
- INSERT INTO "${y}"."${A}" (
30
- txid,
31
- schema_name,
32
- table_name,
33
- op,
34
- row_data,
35
- old_row_data
36
- )
37
- VALUES (
38
- txid_current(),
39
- TG_TABLE_SCHEMA,
40
- TG_TABLE_NAME,
41
- lower(TG_OP),
42
- CASE WHEN TG_OP IN ('INSERT', 'UPDATE') THEN to_jsonb(NEW) ELSE NULL END,
43
- CASE WHEN TG_OP IN ('UPDATE', 'DELETE') THEN to_jsonb(OLD) ELSE NULL END
44
- );
45
-
46
- RETURN COALESCE(NEW, OLD);
47
- END;
48
- $$;
49
- `),await t.exec(`
50
- CREATE OR REPLACE FUNCTION "${y}"."${X}"()
51
- RETURNS void
52
- LANGUAGE plpgsql
53
- AS $$
54
- DECLARE
55
- target REGCLASS;
56
- BEGIN
57
- FOR target IN
58
- SELECT c.oid::regclass
59
- FROM pg_class AS c
60
- JOIN pg_namespace AS n ON n.oid = c.relnamespace
61
- WHERE c.relkind IN ('r', 'p')
62
- AND n.nspname NOT IN ('${y}', 'information_schema', 'pg_catalog')
63
- AND n.nspname NOT LIKE 'pg_temp_%'
64
- AND n.nspname NOT LIKE 'pg_toast%'
65
- LOOP
66
- IF EXISTS (
67
- SELECT 1
68
- FROM pg_trigger
69
- WHERE tgrelid = target
70
- AND tgname = '${z}'
71
- ) THEN
72
- CONTINUE;
73
- END IF;
74
-
75
- EXECUTE format(
76
- 'CREATE TRIGGER %I AFTER INSERT OR UPDATE OR DELETE ON %s FOR EACH ROW EXECUTE FUNCTION "${y}"."${Y}"()',
77
- '${z}',
78
- target::text
79
- );
80
- END LOOP;
81
- END;
82
- $$;
83
- `),await ee(e,t)}),await e.ensureInfrastructurePromise}async function ee(e,t){await M(e,t,async()=>{await t.query(`SELECT "${y}"."${X}"()`)})}async function Qe(e,t){await Z(e,t),await ee(e,t);let r=await M(e,t,async()=>await t.query(`
84
- WITH drained AS (
85
- DELETE FROM "${y}"."${A}"
86
- RETURNING txid, schema_name, table_name, op, row_data, old_row_data, id
87
- )
88
- SELECT txid, schema_name, table_name, op, row_data, old_row_data
89
- FROM drained
90
- ORDER BY id
91
- `));if(r.rows.length===0||e.subscribers.size===0)return;let n=r.rows.map($e);for(let a of e.subscribers)queueMicrotask(()=>{if(!e.closed&&e.subscribers.has(a))try{a(n)}catch(s){console.error("[WAL bridge] subscriber failed",s)}})}async function x(e,t){if(!e.closed){if(e.pollPromise){e.pendingPoll=!0,await e.pollPromise;return}e.pollPromise=(async()=>{do e.pendingPoll=!1,await Qe(e,t);while(e.pendingPoll&&!e.closed)})().finally(()=>{e.pollPromise=null}),await e.pollPromise}}async function M(e,t,r){e.suppressDepth+=1;try{return await r()}finally{e.suppressDepth-=1,e.suppressDepth===0&&!e.closed&&w.get(t)!==e&&(e.closed=!0)}}function $e(e){return{oldRecord:e.old_row_data,record:e.row_data,schema:e.schema_name,table:e.table_name,txid:String(e.txid),type:Ge(e.op)}}function Ge(e){switch(e.toLowerCase()){case"delete":return"delete";case"insert":return"insert";case"update":return"update";default:throw new Error(`Unsupported WAL bridge operation: ${e}`)}}var We=10,re="127.0.0.1",ne=128*1024*1024,ae=["-c","shared_buffers=16MB","-c","temp_buffers=1MB","-c","work_mem=1MB","-c","maintenance_work_mem=16MB","-c","wal_buffers=1MB"],p={connectionLimit:We,connectTimeout:0,database:"template1",maxIdleConnectionLifetime:0,password:"postgres",poolTimeout:0,socketTimeout:0,sslMode:"disable",username:"postgres"},He=`postgres://${p.username}:${p.password}@localhost`,B=new URLSearchParams({sslmode:p.sslMode}),oe=new URLSearchParams({...Object.fromEntries(B.entries()),connection_limit:String(p.connectionLimit),connect_timeout:String(p.connectTimeout),max_idle_connection_lifetime:String(p.maxIdleConnectionLifetime),pool_timeout:String(p.poolTimeout),socket_timeout:String(p.socketTimeout)});async function se(e){let{rows:t}=await e.query("SELECT EXISTS(SELECT 1 FROM pg_roles WHERE rolname = 'postgres') AS exists");t[0]?.exists?await e.exec(`ALTER ROLE ${p.username} WITH LOGIN SUPERUSER PASSWORD '${p.password}'`):await e.exec(`CREATE ROLE ${p.username} WITH LOGIN SUPERUSER PASSWORD '${p.password}'`),await e.exec(`SET ROLE ${p.username}`)}async function bt(e,t){if(e==="shadow_database"&&!t.dryRun)return await Ke(t);let r=e==="database"?t.databasePort:t.shadowDatabasePort;return t.dryRun?le(e,t,{db:null,port:r,server:null}):await ie(e,t,{port:r,updateServerStatePort:!0})}async function Ke(e,t=async()=>await ie("shadow_database",e,{port:0,updateServerStatePort:!1})){let{debug:r}=e,n=null,a=null,s=!1,d=new Set,o=qe(c),u=await Ye(o,e.shadowDatabasePort);return e.shadowDatabasePort=u,r&&console.debug(`[shadow_database] lazy proxy listening on port ${u}`),{...p,attachWalEventBridge:()=>Promise.reject(new Error("WAL bridge is only available for the primary database server")),attachQueryInsightsBridge:()=>Promise.reject(new Error("Query insights are only available for the primary database server")),close:async()=>{s=!0;for(let m of d)m.destroy();d.clear();let i=[];try{await ze(o),r&&console.debug(`[shadow_database] lazy proxy stopped on port ${u}`)}catch(m){console.error("[shadow_database] lazy proxy stop error",m),i.push(m)}try{await a?.catch(()=>null),await n?.close()}catch(m){console.error("[shadow_database] backend close error",m),i.push(m)}if(i.length>0)throw new AggregateError(i,"Failed to close shadow_database properly")},connectionString:h(u,B),dump:async()=>{},getPrimaryKeyColumns:()=>Promise.reject(new Error("Primary key resolution is only available for the primary database server")),port:u,prismaORMConnectionString:h(u,oe),terminalCommand:`PGPASSWORD=${p.password} PGSSLMODE=${p.sslMode} psql -h localhost -p ${u} -U ${p.username} -d ${p.database}`};function c(i){d.add(i);let m=()=>{d.delete(i)};i.once("close",m),i.once("error",m),i.pause(),l(i)}async function l(i){try{let m=await f();if(s){i.destroy();return}let g=ke({host:re,port:m.port});d.add(g);let b=()=>{d.delete(g)};g.once("close",b),g.once("error",b),i.once("close",()=>g.destroy()),i.once("error",()=>g.destroy()),g.once("error",()=>i.destroy()),g.once("connect",()=>{r&&console.debug(`[shadow_database] proxying connection to lazy backend on port ${m.port}`),i.resume(),i.pipe(g),g.pipe(i)})}catch(m){r&&console.error("[shadow_database] failed to start lazy backend",m),i.destroy(m instanceof Error?m:void 0)}}async function f(){if(n)return n;if(s)throw new Error("shadow_database is closed");return a||(r&&console.debug("[shadow_database] starting lazy backend..."),a=t().then(i=>(n=i,r&&console.debug(`[shadow_database] lazy backend started on port ${i.port}`),i)).catch(i=>{throw a=null,i})),await a}}async function ie(e,t,r){let{debug:n}=t,{port:a,updateServerStatePort:s}=r,o=await(e==="shadow_database"?Je:ue)(t.pgliteDataDirPath,n);n&&o.onNotification((i,m)=>{console.debug(`[${e}][${i}] ${m}`)});let{PGLiteSocketServer:u}=await import("@electric-sql/pglite-socket"),c=e==="shadow_database"?t.shadowDatabaseIdleTimeoutMillis:t.databaseIdleTimeoutMillis,l=new u({db:o,debug:n,idleTimeout:Number.isFinite(c)?c:0,inspect:n,maxConnections:p.connectionLimit,port:a});n&&(l.addEventListener("listening",i=>{let{detail:m}=i;console.debug(`[${e}] server listening on ${JSON.stringify(m)}`)}),l.addEventListener("connection",i=>{let{clientAddress:m,clientPort:g}=i.detail;console.debug(`[${e}] client connected from ${m}:${g}`)}),l.addEventListener("error",i=>{let{detail:m}=i;console.error(`[${e}] server error:`,m)}));try{await l.start()}catch(i){throw i instanceof Error&&"code"in i&&i.code==="EADDRINUSE"?new T(a):i}let f=Number(l.getServerConn().split(":").at(1));return s&&(t[e==="database"?"databasePort":"shadowDatabasePort"]=f),le(e,t,{db:o,port:f,server:l})}function le(e,t,r){let{debug:n}=t,{db:a,port:s,server:d}=r||{},o=new Map;return n&&console.debug(`[${e}] server started on port ${s}`),{...p,attachWalEventBridge:async()=>{if(e!=="database"||!a)throw new Error("WAL bridge is only available for the primary database server");return await D(a)},attachQueryInsightsBridge:()=>{if(e!=="database"||!d)throw new Error("Query insights are only available for the primary database server");return Promise.resolve(H(d))},close:async()=>{let u=[];try{await d?.stop(),n&&console.debug(`[${e}] server stopped on port ${s}`)}catch(c){console.error(`[${e}] server stop error`,c),u.push(c)}if(e==="database"){try{d&&await K(d),n&&console.debug(`[${e}] closed query insights bridge`)}catch(c){console.error(`[${e}] query insights bridge close error`,c),u.push(c)}try{a&&await j(a),n&&console.debug(`[${e}] closed WAL bridge`)}catch(c){console.error(`[${e}] WAL bridge close error`,c),u.push(c)}try{await a?.syncToFs(),n&&console.debug(`[${e}] synced to filesystem`)}catch(c){console.error(`[${e}] sync error`,c),u.push(c)}}try{await a?.close(),n&&console.debug(`[${e}] closed`)}catch(c){console.error(`[${e}] close error`,c),u.push(c)}if(u.length>0)throw new AggregateError(u,`Failed to close ${e} properly`)},connectionString:h(s,B),dump:async u=>{e==="shadow_database"||!a||await je({db:a,debug:n,destinationPath:u})},getPrimaryKeyColumns:async(u,c)=>{if(e==="shadow_database"||!a)throw new Error("Primary key resolution is only available for the primary database server");let l=`${u}.${c}`,f=o.get(l);return f||(f=Xe(a,u,c).catch(i=>{throw o.delete(l),i}),o.set(l,f)),await f},port:s,prismaORMConnectionString:h(s,oe),terminalCommand:`PGPASSWORD=${p.password} PGSSLMODE=${p.sslMode} psql -h localhost -p ${s} -U ${p.username} -d ${p.database}`}}function h(e,t){return`${He}:${e}/${p.database}?${t.toString()}`}async function ue(e,t){let{PGlite:r}=await import("@electric-sql/pglite"),n=await I(),a=e==="memory://"||!await L(Fe(e,"PG_VERSION")),s=await r.create({database:p.database,dataDir:e,debug:t?5:void 0,extensions:n.extensions,fsBundle:n.fsBundle,initialMemory:ne,loadDataDir:a?n.loadDataDir:void 0,relaxedDurability:!1,startParams:[...r.defaultStartParams,...ae],wasmModule:n.wasmModule});return await se(s),s}async function Ye(e,t){return await new Promise((r,n)=>{let a=o=>{if(d(),o.code==="EADDRINUSE"){n(new T(t));return}n(o)},s=()=>{let o=e.address();if(d(),!o||typeof o=="string"){n(new Error("Failed to determine TCP server port"));return}r(o.port)},d=()=>{e.off("error",a),e.off("listening",s)};e.once("error",a),e.once("listening",s),e.listen(t,re)})}async function ze(e){await new Promise((t,r)=>{e.close(n=>{let a=n;if(a&&a.code!=="ERR_SERVER_NOT_RUNNING"){r(a);return}t()})})}async function Je(e,t){let{PGlite:r}=await import("@electric-sql/pglite"),n=await I(),a=await r.create({database:p.database,dataDir:"memory://",debug:t?5:void 0,extensions:n.extensions,fsBundle:n.fsBundle,initialMemory:ne,loadDataDir:n.loadDataDir,relaxedDurability:!1,startParams:[...r.defaultStartParams,...ae],wasmModule:n.wasmModule});return await se(a),a}async function Xe(e,t,r){let{rows:n}=await e.query(`
92
- SELECT attribute.attname AS column_name
93
- FROM pg_constraint pk_constraint
94
- INNER JOIN pg_class relation
95
- ON relation.oid = pk_constraint.conrelid
96
- INNER JOIN pg_namespace namespace
97
- ON namespace.oid = relation.relnamespace
98
- INNER JOIN unnest(pk_constraint.conkey) WITH ORDINALITY AS keys(attnum, ordinality)
99
- ON TRUE
100
- INNER JOIN pg_attribute attribute
101
- ON attribute.attrelid = relation.oid
102
- AND attribute.attnum = keys.attnum
103
- WHERE pk_constraint.contype = 'p'
104
- AND namespace.nspname = ${te(t)}
105
- AND relation.relname = ${te(r)}
106
- ORDER BY keys.ordinality
107
- `);return n.map(a=>a.column_name)}function te(e){return`'${e.replaceAll("'","''")}'`}async function je(e){let{dataDir:t,db:r,debug:n,destinationPath:a}=e,s=r||await ue(t,n),{pgDump:d}=await import("@electric-sql/pglite-tools/pg_dump"),o=await d({args:["--schema-only","--no-owner"],fileName:a?Ue(a):void 0,pg:await s.clone()});return a?(n&&console.debug(`[DB] Dumping database to ${a}`),await O(o,a)):(n&&console.debug("[DB] Dumping database to memory"),await o.text())}export{Ze as a,et as b,D as c,v as d,V as e,bt as f,Ke as g,je as h};