@prisma/orm-extension-supabase 8.0.0-rc.2-dev.3 → 8.0.0-rc.20

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/runtime.mjs CHANGED
@@ -1,22 +1,22 @@
1
- import { n as version, t as contract_default } from "./contract-DFQ5w0dT-ewVq9BvG.mjs";
2
- import { a as isSupabaseRole, n as SupabaseRole, t as SUPABASE_JWT_ROLE_CLAIM } from "./roles-D5vC3rNp-tYQlvifU.mjs";
1
+ import { n as version, t as contract_default } from "./contract-BT1LXEGv-BCF6iBts.mjs";
2
+ import { a as isSupabaseRole, n as SupabaseRole, t as SUPABASE_JWT_ROLE_CLAIM } from "./roles-9Ql17Kbb-p1cF6Jlt.mjs";
3
3
  import { blindCast } from "@prisma/orm-framework/utils/casts";
4
4
  import postgresAdapter from "@prisma/orm-target-postgres/adapter/runtime";
5
- import postgresDriver from "@prisma/orm-target-postgres/driver/runtime";
6
- import { instantiateExecutionStack } from "@prisma/orm-framework/components/execution";
7
- import { PostgresRuntimeImpl, buildNamespacedNativeEnums, isPgPool } from "@prisma/orm-postgres/runtime";
8
- import { sql } from "@prisma/orm-family-sql/builder/runtime";
9
- import { orm } from "@prisma/orm-family-sql/orm-client";
10
- import { createRawSql } from "@prisma/orm-family-sql/relational-core/expression";
11
- import { createExecutionContext, createSqlExecutionStack, withTransaction } from "@prisma/orm-family-sql/runtime";
5
+ import postgresDriver, { suppressIdleConnectionErrors } from "@prisma/orm-target-postgres/driver/runtime";
6
+ import { buildPostgresStaticContext } from "@prisma/orm-postgres/internal/static-context";
7
+ import { buildPostgresQueryMembers } from "@prisma/orm-postgres/internal/transaction-members";
8
+ import { validatePostgresContract } from "@prisma/orm-postgres/internal/validate-contract";
9
+ import { PostgresRuntimeImpl, isPgPool } from "@prisma/orm-postgres/runtime";
10
+ import { checkCollectionClasses, orm, prepareQuery } from "@prisma/orm-family-sql/orm-client";
11
+ import { activitySource, createExecutionContext, createSqlExecutionStack, withTransaction, withTransactionMembers } from "@prisma/orm-family-sql/runtime";
12
+ import { createTransactionStart, preparedStatementExecute, preparedStatementQuery, transactionStart } from "@prisma/orm-family-sql/runtime/internal/prepared-query";
12
13
  import postgresTarget, { PostgresContractSerializer } from "@prisma/orm-target-postgres/target/runtime";
13
14
  import { ifDefined } from "@prisma/orm-framework/utils/defined";
14
15
  import { InternalError } from "@prisma/orm-framework/utils/internal-error";
16
+ import { structuredError } from "@prisma/orm-framework/utils/structured-error";
15
17
  import { createRemoteJWKSet, decodeProtectedHeader, jwtVerify } from "jose";
16
18
  import { Pool } from "pg";
17
- import { structuredError } from "@prisma/orm-framework/utils/structured-error";
18
19
  import { AsyncIterableResult } from "@prisma/orm-framework/components/runtime";
19
- import { preparedStatementExecute, preparedStatementQuery } from "@prisma/orm-family-sql/runtime/internal/prepared-query";
20
20
  //#region ../../../3-extensions/supabase/dist/runtime.mjs
21
21
  /**
22
22
  * Tells the runtime that the Supabase pack's runtime component is available.
@@ -44,14 +44,22 @@ const supabaseRuntimeDescriptor = {
44
44
  function supabaseError(code, message, options) {
45
45
  return structuredError(code, message, options);
46
46
  }
47
+ let buildRoleScope;
48
+ /**
49
+ * The operations under `binding` of the runtime `runtime()` returns. Each operation calls `runtime()` when it runs, so a client can build its role scope before its runtime exists; when `runtime()` throws, the operation rejects. For the facade only; the package entry does not export it.
50
+ */
51
+ function roleScope(runtime, binding) {
52
+ return buildRoleScope(runtime, binding);
53
+ }
47
54
  var SupabaseRuntimeImpl = class extends PostgresRuntimeImpl {
48
55
  /**
49
- * Opens a raw connection and applies role + JWT claims via session-scoped set_config.
50
- * On bind failure, destroys the connection before rethrowing — no leaked connections.
51
- * Not on the `SupabaseRuntime` interface; consumed by the facade, not by app code.
56
+ * Opens a raw connection and applies role + JWT claims via session-scoped set_config. On bind failure, destroys the connection before rethrowing — no leaked connections. Every operation of `forRole(binding)` runs on a session opened here.
52
57
  */
53
58
  async openRoleSession(binding) {
54
- const conn = await this.acquireRawConnection();
59
+ return (await this.openRoleConnection(binding)).session;
60
+ }
61
+ async openRoleConnection(binding, options) {
62
+ const conn = await this.acquireRawConnection(options);
55
63
  try {
56
64
  await conn.execute({
57
65
  sql: "SELECT set_config($1, $2, false)",
@@ -66,7 +74,9 @@ var SupabaseRuntimeImpl = class extends PostgresRuntimeImpl {
66
74
  throw err;
67
75
  }
68
76
  const self = this;
69
- return {
77
+ const session = {
78
+ [transactionStart]: createTransactionStart(),
79
+ [activitySource]: self.connectionActivitySource(conn, () => session),
70
80
  query(plan, options) {
71
81
  return self.queryAgainstQueryable(plan, conn, {
72
82
  ...options,
@@ -80,39 +90,13 @@ var SupabaseRuntimeImpl = class extends PostgresRuntimeImpl {
80
90
  });
81
91
  },
82
92
  [preparedStatementQuery](prepared, params, options) {
83
- return self.runPreparedQueryAgainstRoleQueryable(prepared, params, conn, options, "connection");
93
+ return self.runPreparedQueryAgainstRoleQueryable(prepared, params, conn, options);
84
94
  },
85
95
  [preparedStatementExecute](prepared, params, options) {
86
- return self.runPreparedExecuteAgainstRoleQueryable(prepared, params, conn, options, "connection");
96
+ return self.runPreparedExecuteAgainstRoleQueryable(prepared, params, conn, options);
87
97
  },
88
98
  async transaction() {
89
- const tx = await conn.beginTransaction();
90
- return {
91
- async commit() {
92
- await tx.commit();
93
- },
94
- async rollback() {
95
- await tx.rollback();
96
- },
97
- query(plan, options) {
98
- return self.queryAgainstQueryable(plan, tx, {
99
- ...options,
100
- scope: "transaction"
101
- });
102
- },
103
- execute(plan, options) {
104
- return self.executeStatisticsAgainstQueryable(plan, tx, {
105
- ...options,
106
- scope: "transaction"
107
- });
108
- },
109
- [preparedStatementQuery](prepared, params, options) {
110
- return self.runPreparedQueryAgainstRoleQueryable(prepared, params, tx, options, "transaction");
111
- },
112
- [preparedStatementExecute](prepared, params, options) {
113
- return self.runPreparedExecuteAgainstRoleQueryable(prepared, params, tx, options, "transaction");
114
- }
115
- };
99
+ return self.beginTransactionOn(conn, session, void 0);
116
100
  },
117
101
  /**
118
102
  * Resets all session-local config then releases the connection back to the pool.
@@ -130,59 +114,100 @@ var SupabaseRuntimeImpl = class extends PostgresRuntimeImpl {
130
114
  await conn.destroy(reason);
131
115
  }
132
116
  };
117
+ return {
118
+ conn,
119
+ session
120
+ };
133
121
  }
134
- /**
135
- * Opens a role session, queries the plan, then releases after the stream drains.
136
- * On mid-stream error, destroys the session instead of releasing.
137
- */
138
- queryWithRole(plan, binding, options) {
139
- const self = this;
140
- const generator = async function* () {
141
- const session = await self.openRoleSession(binding);
142
- let errored = false;
143
- try {
144
- for await (const row of session.query(plan, options)) yield row;
145
- } catch (err) {
146
- errored = true;
147
- await session.destroy(err).catch(() => void 0);
148
- throw err;
149
- } finally {
150
- if (!errored) await session.release();
151
- }
122
+ forRole(binding) {
123
+ return buildRoleScope(() => this, binding);
124
+ }
125
+ static {
126
+ buildRoleScope = (runtime, binding) => {
127
+ const open = (options) => async () => (await runtime().openRoleConnection(binding, options)).session;
128
+ const scope = {
129
+ query(plan, options) {
130
+ return streamOnSession(open(options), (session) => session.query(plan, options));
131
+ },
132
+ execute(plan, options) {
133
+ return executeOnSession(open(options), (session) => session.execute(plan, options));
134
+ },
135
+ [preparedStatementQuery](statement, params, options) {
136
+ return streamOnSession(open(options), (session) => session[preparedStatementQuery](statement, params, options));
137
+ },
138
+ [preparedStatementExecute](statement, params, options) {
139
+ return executeOnSession(open(options), (session) => session[preparedStatementExecute](statement, params, options));
140
+ },
141
+ connection: open(void 0),
142
+ [activitySource]: {
143
+ startActivity: async (activity) => runtime().startActivityOnRoute(route, activity, void 0),
144
+ planContentHash: async (plan) => runtime().planContentHashFor(plan, "connection", void 0)
145
+ }
146
+ };
147
+ const route = {
148
+ scope: "connection",
149
+ parent: () => void 0,
150
+ runtimeWork: true,
151
+ query: (plan, options) => scope.query(plan, options),
152
+ execute: (plan, options) => scope.execute(plan, options),
153
+ preparedQuery: (statement, params, options) => scope[preparedStatementQuery](statement, params, options),
154
+ preparedExecute: (statement, params, options) => scope[preparedStatementExecute](statement, params, options),
155
+ transaction: (parent) => runtime().beginRoleTransaction(binding, parent)
156
+ };
157
+ return scope;
152
158
  };
153
- return new AsyncIterableResult(generator());
154
159
  }
155
- async executeWithRole(plan, binding, options) {
156
- const session = await this.openRoleSession(binding);
157
- try {
158
- const stats = await session.execute(plan, options);
159
- await session.release();
160
- return stats;
161
- } catch (err) {
162
- await session.destroy(err).catch(() => void 0);
163
- throw err;
164
- }
160
+ async beginRoleTransaction(binding, parent) {
161
+ const { conn, session } = await this.openRoleConnection(binding, { activityParent: parent });
162
+ return this.ownTransaction(session, () => this.beginTransactionOn(conn, session, parent));
165
163
  }
166
- runPreparedExecuteAgainstRoleQueryable(prepared, params, queryable, options, scope) {
164
+ runPreparedExecuteAgainstRoleQueryable(prepared, params, queryable, options) {
167
165
  return this.runPreparedExecuteAgainstQueryable(blindCast(prepared), blindCast(params), queryable, {
168
166
  ...options,
169
- scope
167
+ scope: "connection"
170
168
  });
171
169
  }
172
- runPreparedQueryAgainstRoleQueryable(prepared, params, queryable, options, scope) {
170
+ runPreparedQueryAgainstRoleQueryable(prepared, params, queryable, options) {
173
171
  return this.runPreparedQueryAgainstQueryable(blindCast(prepared), blindCast(params), queryable, {
174
172
  ...options,
175
- scope
173
+ scope: "connection"
176
174
  });
177
175
  }
178
176
  };
179
- function hasContractJson(options) {
180
- return "contractJson" in options;
177
+ function streamOnSession(open, rows) {
178
+ const generator = async function* () {
179
+ const session = await open();
180
+ let errored = false;
181
+ try {
182
+ for await (const row of rows(session)) yield row;
183
+ } catch (err) {
184
+ errored = true;
185
+ await session.destroy(err).catch(() => void 0);
186
+ throw err;
187
+ } finally {
188
+ if (!errored) await session.release();
189
+ }
190
+ };
191
+ return new AsyncIterableResult(generator());
192
+ }
193
+ async function executeOnSession(open, run) {
194
+ const session = await open();
195
+ try {
196
+ const stats = await run(session);
197
+ await session.release();
198
+ return stats;
199
+ } catch (err) {
200
+ await session.destroy(err).catch(() => void 0);
201
+ throw err;
202
+ }
181
203
  }
182
204
  const contractSerializer = new PostgresContractSerializer();
183
- function resolveContract(options) {
184
- const contractJson = hasContractJson(options) ? options.contractJson : contractSerializer.serializeContract(options.contract);
185
- return blindCast(contractSerializer.deserializeContract(contractJson));
205
+ function closedClientError() {
206
+ return structuredError("DRIVER.NOT_CONNECTED", "Runtime is closed", {
207
+ why: "close() was called on this client.",
208
+ fix: "Create a new supabase(...) client.",
209
+ meta: { extension: "supabase" }
210
+ });
186
211
  }
187
212
  function resolveKeyMaterial(options) {
188
213
  const jwtSecret = "jwtSecret" in options ? options.jwtSecret : void 0;
@@ -220,17 +245,25 @@ function algKeyMismatchReason(jwt, kind) {
220
245
  if (kind === "secret" && asymmetric) return `token is signed with ${alg} but this client is configured with jwtSecret (HS256). Current Supabase projects sign with asymmetric keys by default — configure jwksUrl (https://<project>/auth/v1/.well-known/jwks.json) instead of jwtSecret.`;
221
246
  if (kind === "jwks" && alg.startsWith("HS")) return `token is signed with ${alg} (a symmetric algorithm) but this client is configured with jwksUrl. A legacy HS256 Supabase project needs jwtSecret (the JWT_SECRET from \`supabase status\`) instead of jwksUrl.`;
222
247
  }
248
+ function checkPgOption(pg) {
249
+ if (pg === void 0 || typeof pg === "object" && pg !== null && isPgPool(pg)) return;
250
+ throw supabaseError("SUPABASE.CONFIG_INVALID", "The pg option takes a pg.Pool", {
251
+ why: "Each role-bound query needs a connection of its own, which a single pg.Client cannot give.",
252
+ fix: "Pass a pg.Pool as pg, or pass url.",
253
+ meta: { reason: "pg is not a pg.Pool" }
254
+ });
255
+ }
223
256
  function toPool(options) {
224
257
  if (options.pg !== void 0 && isPgPool(options.pg)) return {
225
258
  pool: options.pg,
226
259
  owned: false
227
260
  };
228
261
  if (typeof options.url === "string") return {
229
- pool: new Pool({
262
+ pool: suppressIdleConnectionErrors(new Pool({
230
263
  connectionString: options.url,
231
264
  connectionTimeoutMillis: options.poolOptions?.connectionTimeoutMillis ?? 2e4,
232
265
  idleTimeoutMillis: options.poolOptions?.idleTimeoutMillis ?? 3e4
233
- }),
266
+ })),
234
267
  owned: true
235
268
  };
236
269
  }
@@ -241,16 +274,34 @@ function withSupabaseDescriptor(extensions) {
241
274
  /**
242
275
  * Deserializes the Supabase extension's own emitted contract into a runtime
243
276
  * contract: namespaces hydrate into `PostgresSchema` instances (with
244
- * `qualifyTable`), and `typeRef` columns (`Timestamptz`, `Uuid`) resolve
245
- * through the codec registry. Exposed only via `service_role`'s `.supabase`
277
+ * `qualifyTable`), and each column resolves its codec through the codec
278
+ * registry. Exposed only via `service_role`'s `.supabase`
246
279
  * secondary root — never merged into the app contract.
247
280
  */
248
281
  function buildExtensionContract() {
249
282
  return blindCast(contractSerializer.deserializeContract(contract_default));
250
283
  }
284
+ /**
285
+ * Creates a Supabase client whose queries run as the role a JWT names. The client infers its
286
+ * contract type from `contract`: a value from `contractFromJson` of `@prisma/orm-postgres/static`
287
+ * for an emitted contract, or a TypeScript-authored contract. A contract is validated once, however
288
+ * many clients are built from it. The pool is created on the first query.
289
+ *
290
+ * @example
291
+ * ```ts
292
+ * import { contractFromJson } from '@prisma/orm-postgres/static';
293
+ * import { supabase } from '@prisma/orm-extension-supabase/runtime';
294
+ * import type { Contract } from './contract.d';
295
+ * import contractJson from './contract.json' with { type: 'json' };
296
+ *
297
+ * export const contract = contractFromJson<Contract>(contractJson);
298
+ * export const db = await supabase({ contract, url, jwtSecret });
299
+ * ```
300
+ */
251
301
  async function supabase(options) {
252
302
  const keyMaterial = resolveKeyMaterial(options);
253
- const contract = resolveContract(options);
303
+ checkPgOption(options.pg);
304
+ const contract = validatePostgresContract(options.contract);
254
305
  const stack = createSqlExecutionStack({
255
306
  target: postgresTarget,
256
307
  adapter: postgresAdapter,
@@ -261,25 +312,63 @@ async function supabase(options) {
261
312
  contract,
262
313
  stack
263
314
  });
264
- const rawCodecInferer = stack.adapter.rawCodecInferer;
265
- const rawSqlTag = createRawSql(rawCodecInferer);
266
- const poolEntry = toPool(options);
267
- let closed = false;
268
- const stackInstance = instantiateExecutionStack(stack);
269
- const driverDescriptor = stack.driver;
270
- if (!driverDescriptor) throw new InternalError("Driver descriptor missing from execution stack");
271
- const driver = driverDescriptor.create({ cursor: { disabled: true } });
272
- if (poolEntry) await driver.connect({
273
- kind: "pgPool",
274
- pool: poolEntry.pool
275
- });
276
- const runtime = new SupabaseRuntimeImpl({
277
- context,
278
- adapter: stackInstance.adapter,
279
- driver,
280
- ...ifDefined("verifyMarker", options.verifyMarker),
281
- ...ifDefined("middleware", options.middleware)
315
+ checkCollectionClasses(contract, options.collections);
316
+ const { sql: appSql, raw, toSql, enums, nativeEnums } = buildPostgresStaticContext(contract, context, stack);
317
+ const extContract = buildExtensionContract();
318
+ const extContext = createExecutionContext({
319
+ contract: extContract,
320
+ stack
282
321
  });
322
+ const extStatic = buildPostgresStaticContext(extContract, extContext, stack);
323
+ let runtimes;
324
+ let connectError;
325
+ let closed = false;
326
+ function getRuntimes() {
327
+ if (connectError !== void 0) throw connectError.error;
328
+ if (runtimes !== void 0) return runtimes;
329
+ if (closed) throw closedClientError();
330
+ const driverDescriptor = stack.driver;
331
+ if (!driverDescriptor) throw new InternalError("Driver descriptor missing from execution stack");
332
+ const adapter = stack.adapter.create(stack);
333
+ const driver = driverDescriptor.create({ cursor: { disabled: true } });
334
+ const sharedOptions = {
335
+ adapter,
336
+ driver,
337
+ ...ifDefined("middleware", options.middleware),
338
+ ...ifDefined("log", options.log),
339
+ ...ifDefined("mode", options.mode),
340
+ closeRefusal: "at-once",
341
+ ownsDriver: false
342
+ };
343
+ const runtime = new SupabaseRuntimeImpl({
344
+ context,
345
+ ...sharedOptions,
346
+ ...ifDefined("verifyMarker", options.verifyMarker)
347
+ });
348
+ const extRuntime = new SupabaseRuntimeImpl({
349
+ context: extContext,
350
+ ...sharedOptions,
351
+ verifyMarker: false
352
+ });
353
+ const poolEntry = toPool(options);
354
+ const ownedPool = poolEntry?.owned ? poolEntry.pool : void 0;
355
+ if (poolEntry) driver.connect({
356
+ kind: "pgPool",
357
+ pool: poolEntry.pool
358
+ }).catch(async (err) => {
359
+ connectError = { error: err };
360
+ await ownedPool?.end().catch(() => void 0);
361
+ });
362
+ runtimes = {
363
+ runtime,
364
+ extRuntime,
365
+ driver,
366
+ ownedPool
367
+ };
368
+ return runtimes;
369
+ }
370
+ const runtime = () => getRuntimes().runtime;
371
+ const extRuntime = () => getRuntimes().extRuntime;
283
372
  async function verifyJwt(jwt) {
284
373
  const mismatch = algKeyMismatchReason(jwt, keyMaterial.kind);
285
374
  if (mismatch !== void 0) throw supabaseError("SUPABASE.JWT_INVALID", `Invalid JWT: ${mismatch}`, { meta: { reason: mismatch } });
@@ -294,86 +383,71 @@ async function supabase(options) {
294
383
  });
295
384
  }
296
385
  }
297
- function buildRoleBoundDbWithContext(binding, roleContext, roleRuntime) {
298
- return {
299
- sql: sql({
300
- context: roleContext,
301
- rawCodecInferer
302
- }),
303
- orm: orm({
304
- runtime: {
305
- query(plan) {
306
- return roleRuntime.queryWithRole(plan, binding);
307
- },
308
- execute(plan) {
309
- return roleRuntime.executeWithRole(plan, binding);
310
- },
311
- connection: () => roleRuntime.openRoleSession(binding)
312
- },
313
- context: roleContext
314
- }),
315
- raw: rawSqlTag,
316
- query(plan, execOptions) {
317
- return roleRuntime.queryWithRole(plan, binding, execOptions);
318
- },
319
- execute(plan, execOptions) {
320
- return roleRuntime.executeWithRole(plan, binding, execOptions);
386
+ function buildRoleBoundDb(binding) {
387
+ const role = roleScope(runtime, binding);
388
+ const roleOrm = orm({
389
+ runtime: role,
390
+ context,
391
+ ...ifDefined("collections", options.collections)
392
+ });
393
+ const roleBound = {
394
+ sql: appSql,
395
+ orm: roleOrm,
396
+ raw,
397
+ toSql,
398
+ enums,
399
+ nativeEnums,
400
+ prepare(declaration, callback) {
401
+ return prepareQuery(runtime(), declaration, callback);
321
402
  },
403
+ query: role.query,
404
+ execute: role.execute,
405
+ [preparedStatementQuery]: role[preparedStatementQuery],
406
+ [preparedStatementExecute]: role[preparedStatementExecute],
322
407
  transaction(fn) {
323
- return withTransaction({ connection: () => roleRuntime.openRoleSession(binding) }, fn);
408
+ return withTransaction(role, (txCtx) => fn(withTransactionMembers(txCtx, {
409
+ ...buildPostgresQueryMembers({
410
+ context,
411
+ collections: options.collections,
412
+ sql: appSql,
413
+ raw,
414
+ toSql,
415
+ prepareRuntime: runtime
416
+ }, txCtx),
417
+ enums,
418
+ nativeEnums
419
+ })));
324
420
  }
325
421
  };
326
- }
327
- function buildRoleBoundDb(binding) {
328
- return buildRoleBoundDbWithContext(binding, context, runtime);
422
+ return Object.assign(roleBound, { [activitySource]: role[activitySource] });
329
423
  }
330
424
  const serviceRoleBinding = {
331
425
  role: SupabaseRole.members.ServiceRole,
332
426
  claims: {}
333
427
  };
334
- const extContract = buildExtensionContract();
335
- const extContext = createExecutionContext({
336
- contract: extContract,
337
- stack
338
- });
339
- const extRuntime = new SupabaseRuntimeImpl({
340
- context: extContext,
341
- adapter: stackInstance.adapter,
342
- driver,
343
- verifyMarker: false,
344
- ...ifDefined("middleware", options.middleware)
345
- });
346
- const extNativeEnums = blindCast(Object.freeze(buildNamespacedNativeEnums(extContract.storage)));
428
+ const serviceRole = roleScope(extRuntime, serviceRoleBinding);
347
429
  const supabaseInternal = {
348
- sql: sql({
349
- context: extContext,
350
- rawCodecInferer
351
- }),
430
+ sql: extStatic.sql,
431
+ toSql: extStatic.toSql,
352
432
  orm: orm({
353
- runtime: {
354
- query(plan) {
355
- return extRuntime.queryWithRole(plan, serviceRoleBinding);
356
- },
357
- execute(plan) {
358
- return extRuntime.executeWithRole(plan, serviceRoleBinding);
359
- },
360
- connection: () => extRuntime.openRoleSession(serviceRoleBinding)
361
- },
433
+ runtime: serviceRole,
362
434
  context: extContext
363
435
  }),
364
- nativeEnums: extNativeEnums,
365
- query(plan, execOptions) {
366
- return extRuntime.queryWithRole(plan, serviceRoleBinding, execOptions);
367
- },
368
- execute(plan, execOptions) {
369
- return extRuntime.executeWithRole(plan, serviceRoleBinding, execOptions);
370
- }
436
+ nativeEnums: extStatic.nativeEnums,
437
+ query: serviceRole.query,
438
+ execute: serviceRole.execute
371
439
  };
372
- async function closeDb() {
373
- if (closed) return;
440
+ let closePromise;
441
+ async function closeRuntimes() {
442
+ if (runtimes === void 0) return;
443
+ const { runtime, extRuntime, driver, ownedPool } = runtimes;
444
+ await Promise.all([runtime.close(), extRuntime.close()]);
445
+ if (ownedPool !== void 0) await driver.close();
446
+ }
447
+ function closeDb() {
374
448
  closed = true;
375
- await runtime.close();
376
- if (poolEntry?.owned) await poolEntry.pool.end().catch(() => void 0);
449
+ closePromise ??= closeRuntimes();
450
+ return closePromise;
377
451
  }
378
452
  return {
379
453
  context,
@@ -395,7 +469,7 @@ async function supabase(options) {
395
469
  },
396
470
  asServiceRole() {
397
471
  return {
398
- ...buildRoleBoundDbWithContext(serviceRoleBinding, context, runtime),
472
+ ...buildRoleBoundDb(serviceRoleBinding),
399
473
  supabase: supabaseInternal
400
474
  };
401
475
  },