@prisma/client-engine-runtime 7.10.0-dev.2 → 7.10.0-dev.21

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/index.js CHANGED
@@ -145,6 +145,16 @@ function safeJsonStringify(obj) {
145
145
  return val;
146
146
  });
147
147
  }
148
+ var MAX_PUSH_SPREAD_ARGS = 8192;
149
+ function appendToArray(target, source) {
150
+ if (source.length <= MAX_PUSH_SPREAD_ARGS) {
151
+ target.push(...source);
152
+ return;
153
+ }
154
+ for (let i = 0; i < source.length; i += MAX_PUSH_SPREAD_ARGS) {
155
+ target.push(...source.slice(i, i + MAX_PUSH_SPREAD_ARGS));
156
+ }
157
+ }
148
158
 
149
159
  // src/json-protocol.ts
150
160
  function normalizeJsonProtocolValues(result) {
@@ -226,10 +236,8 @@ function deserializeTaggedValue({ $type, value }) {
226
236
  switch ($type) {
227
237
  case "BigInt":
228
238
  return BigInt(value);
229
- case "Bytes": {
230
- const { buffer, byteOffset, byteLength } = Buffer.from(value, "base64");
231
- return new Uint8Array(buffer, byteOffset, byteLength);
232
- }
239
+ case "Bytes":
240
+ return new Uint8Array(Buffer.from(value, "base64"));
233
241
  case "DateTime":
234
242
  return new Date(value);
235
243
  case "Decimal":
@@ -343,6 +351,7 @@ function getErrorCode(err) {
343
351
  case "UniqueConstraintViolation":
344
352
  return "P2002";
345
353
  case "ForeignKeyConstraintViolation":
354
+ case "RestrictViolation":
346
355
  return "P2003";
347
356
  case "InvalidInputValue":
348
357
  return "P2007";
@@ -415,6 +424,7 @@ function renderErrorMessage(err) {
415
424
  case "UniqueConstraintViolation":
416
425
  return `Unique constraint failed on the ${renderConstraint(err.cause.constraint)}`;
417
426
  case "ForeignKeyConstraintViolation":
427
+ case "RestrictViolation":
418
428
  return `Foreign key constraint violated on the ${renderConstraint(err.cause.constraint)}`;
419
429
  case "UnsupportedNativeDataType":
420
430
  return `Failed to deserialize column of type '${err.cause.type}'. If you're using $queryRaw and this column is explicitly marked as \`Unsupported\` in your Prisma schema, try casting this column to any supported Prisma type such as \`String\`.`;
@@ -1148,8 +1158,9 @@ function renderTemplateSql(fragments, placeholderFormat, params, argTypes) {
1148
1158
  if (fragment.type === "stringChunk") {
1149
1159
  continue;
1150
1160
  }
1151
- const length = flattenedParams.length;
1152
- const added = flattenedParams.push(...flattenedFragmentParams(fragment)) - length;
1161
+ const fragmentParams = Array.from(flattenedFragmentParams(fragment));
1162
+ const added = fragmentParams.length;
1163
+ appendToArray(flattenedParams, fragmentParams);
1153
1164
  if (fragment.argType.arity === "tuple") {
1154
1165
  if (added % fragment.argType.elements.length !== 0) {
1155
1166
  throw new Error(
@@ -1698,7 +1709,7 @@ var QueryInterpreter = class _QueryInterpreter {
1698
1709
  if (results === void 0) {
1699
1710
  results = result;
1700
1711
  } else {
1701
- results.rows.push(...result.rows);
1712
+ appendToArray(results.rows, result.rows);
1702
1713
  results.lastInsertId = result.lastInsertId;
1703
1714
  }
1704
1715
  }
@@ -2553,6 +2564,14 @@ var InvalidTransactionIsolationLevelError = class extends TransactionManagerErro
2553
2564
 
2554
2565
  // src/transaction-manager/transaction-manager.ts
2555
2566
  var MAX_CLOSED_TRANSACTIONS = 100;
2567
+ var CANCEL_ROLLBACK_GRACE_MS = 2e3;
2568
+ function trackStartingTransaction() {
2569
+ let markSettled;
2570
+ const settled = new Promise((resolve) => {
2571
+ markSettled = resolve;
2572
+ });
2573
+ return { abortController: new AbortController(), settled, markSettled };
2574
+ }
2556
2575
  var debug = (0, import_debug.Debug)("prisma:client:transactionManager");
2557
2576
  var COMMIT_QUERY = () => ({ sql: "COMMIT", args: [], argTypes: [] });
2558
2577
  var ROLLBACK_QUERY = () => ({ sql: "ROLLBACK", args: [], argTypes: [] });
@@ -2572,6 +2591,9 @@ var TransactionManager = class {
2572
2591
  // List of last closed transactions. Max MAX_CLOSED_TRANSACTIONS entries.
2573
2592
  // Used to provide better error messages than a generic "transaction not found".
2574
2593
  closedTransactions = [];
2594
+ // Transactions that are still being started. Tracked separately so that
2595
+ // `cancelAllTransactions` can reach them: they are not in `transactions` yet.
2596
+ #startingTransactions = /* @__PURE__ */ new Set();
2575
2597
  driverAdapter;
2576
2598
  transactionOptions;
2577
2599
  tracingHelper;
@@ -2635,56 +2657,91 @@ var TransactionManager = class {
2635
2657
  return { id: existing.id };
2636
2658
  });
2637
2659
  }
2638
- const transaction = {
2639
- id: await randomUUID(),
2640
- status: "waiting",
2641
- timer: void 0,
2642
- timeout: options.timeout,
2643
- startedAt: Date.now(),
2644
- transaction: void 0,
2645
- operationQueue: Promise.resolve(),
2646
- depth: 1,
2647
- savepoints: [],
2648
- savepointCounter: 0
2649
- };
2650
- const abortController = new AbortController();
2651
- const startTimer = createTimeoutIfDefined(() => abortController.abort(), options.maxWait);
2652
- startTimer?.unref?.();
2653
- const startTransactionPromise = this.driverAdapter.startTransaction(options.isolationLevel).catch(rethrowAsUserFacing);
2654
- transaction.transaction = await Promise.race([
2655
- startTransactionPromise.finally(() => clearTimeout(startTimer)),
2656
- once(abortController.signal, "abort").then(() => void 0)
2657
- ]);
2658
- this.transactions.set(transaction.id, transaction);
2659
- switch (transaction.status) {
2660
- case "waiting":
2661
- if (abortController.signal.aborted) {
2662
- void startTransactionPromise.then(async (tx) => {
2663
- if (tx.options.usePhantomQuery) {
2664
- await tx.rollback();
2665
- } else {
2666
- try {
2667
- await tx.executeRaw(ROLLBACK_QUERY());
2668
- } finally {
2669
- await tx.rollback();
2670
- }
2671
- }
2672
- }).catch((e) => debug("error in discarded transaction:", e));
2673
- await this.#closeTransaction(transaction, "timed_out");
2674
- throw new TransactionStartTimeoutError();
2660
+ const starting = trackStartingTransaction();
2661
+ const { abortController } = starting;
2662
+ this.#startingTransactions.add(starting);
2663
+ let discarding;
2664
+ try {
2665
+ const transaction = {
2666
+ id: await randomUUID(),
2667
+ status: "waiting",
2668
+ timer: void 0,
2669
+ timeout: options.timeout,
2670
+ startedAt: Date.now(),
2671
+ transaction: void 0,
2672
+ operationQueue: Promise.resolve(),
2673
+ depth: 1,
2674
+ savepoints: [],
2675
+ savepointCounter: 0
2676
+ };
2677
+ if (abortController.signal.aborted) {
2678
+ throw new TransactionStartTimeoutError();
2679
+ }
2680
+ const startTimer = createTimeoutIfDefined(() => abortController.abort(), options.maxWait);
2681
+ startTimer?.unref?.();
2682
+ const startTransactionPromise = this.driverAdapter.startTransaction(options.isolationLevel).catch(rethrowAsUserFacing);
2683
+ transaction.transaction = await Promise.race([
2684
+ startTransactionPromise.finally(() => clearTimeout(startTimer)),
2685
+ once(abortController.signal, "abort").then(() => void 0)
2686
+ ]);
2687
+ this.transactions.set(transaction.id, transaction);
2688
+ switch (transaction.status) {
2689
+ case "waiting":
2690
+ if (abortController.signal.aborted) {
2691
+ transaction.transaction = void 0;
2692
+ discarding = this.#discardStartedTransaction(startTransactionPromise);
2693
+ await this.#closeTransaction(transaction, "timed_out");
2694
+ throw new TransactionStartTimeoutError();
2695
+ }
2696
+ transaction.status = "running";
2697
+ transaction.startedAt = Date.now();
2698
+ transaction.timer = this.#startTransactionTimeout(transaction.id, options.timeout);
2699
+ return { id: transaction.id };
2700
+ case "timed_out":
2701
+ case "running":
2702
+ case "committed":
2703
+ case "rolled_back":
2704
+ throw new TransactionInternalConsistencyError(
2705
+ `Transaction in invalid state ${transaction.status} although it just finished startup.`
2706
+ );
2707
+ default:
2708
+ return assertNever(transaction["status"], "Unknown transaction status.");
2709
+ }
2710
+ } finally {
2711
+ this.#startingTransactions.delete(starting);
2712
+ if (discarding) {
2713
+ void discarding.finally(starting.markSettled);
2714
+ } else {
2715
+ starting.markSettled();
2716
+ }
2717
+ }
2718
+ }
2719
+ /**
2720
+ * Rolls back a transaction whose start was abandoned, and releases its connection.
2721
+ *
2722
+ * The `startTransaction` promise may still be running in the background. If it eventually
2723
+ * succeeds, we need to roll back and release the connection to avoid leaking it and
2724
+ * exhausting the connection pool. For adapters that don't use phantom queries (e.g. pg/neon),
2725
+ * `rollback()` only releases the connection without sending SQL, so we send an explicit
2726
+ * ROLLBACK first; otherwise the connection returns to the pool mid-transaction because
2727
+ * `BEGIN` already ran on the wire during startup.
2728
+ *
2729
+ * Errors are only logged: the caller has already reported the failure that led here.
2730
+ */
2731
+ async #discardStartedTransaction(startTransactionPromise) {
2732
+ try {
2733
+ const tx = await startTransactionPromise;
2734
+ if (tx.options.usePhantomQuery) {
2735
+ await tx.rollback();
2736
+ } else {
2737
+ try {
2738
+ await tx.executeRaw(ROLLBACK_QUERY());
2739
+ } finally {
2740
+ await tx.rollback();
2675
2741
  }
2676
- transaction.status = "running";
2677
- transaction.timer = this.#startTransactionTimeout(transaction.id, options.timeout);
2678
- return { id: transaction.id };
2679
- case "timed_out":
2680
- case "running":
2681
- case "committed":
2682
- case "rolled_back":
2683
- throw new TransactionInternalConsistencyError(
2684
- `Transaction in invalid state ${transaction.status} although it just finished startup.`
2685
- );
2686
- default:
2687
- assertNever(transaction["status"], "Unknown transaction status.");
2742
+ }
2743
+ } catch (e) {
2744
+ debug("error in discarded transaction:", e);
2688
2745
  }
2689
2746
  }
2690
2747
  async commitTransaction(transactionId) {
@@ -2775,16 +2832,21 @@ var TransactionManager = class {
2775
2832
  return transaction;
2776
2833
  }
2777
2834
  async cancelAllTransactions() {
2778
- await Promise.allSettled(
2779
- [...this.transactions.values()].map(
2835
+ const starting = [...this.#startingTransactions];
2836
+ for (const { abortController } of starting) {
2837
+ abortController.abort();
2838
+ }
2839
+ await Promise.allSettled([
2840
+ ...[...this.transactions.values()].map(
2780
2841
  (tx) => this.#runSerialized(tx, async () => {
2781
2842
  const current = this.transactions.get(tx.id);
2782
2843
  if (current) {
2783
2844
  await this.#closeTransaction(current, "rolled_back");
2784
2845
  }
2785
2846
  })
2786
- )
2787
- );
2847
+ ),
2848
+ ...starting.map(({ settled }) => settleWithin(settled, CANCEL_ROLLBACK_GRACE_MS))
2849
+ ]);
2788
2850
  }
2789
2851
  #nextSavepointName(transaction) {
2790
2852
  return `prisma_sp_${transaction.savepointCounter++}`;
@@ -2937,6 +2999,14 @@ var TransactionManager = class {
2937
2999
  function createTimeoutIfDefined(cb, ms) {
2938
3000
  return ms !== void 0 ? setTimeout(cb, ms) : void 0;
2939
3001
  }
3002
+ function settleWithin(promise, timeout) {
3003
+ let timer;
3004
+ const deadline = new Promise((resolve) => {
3005
+ timer = setTimeout(resolve, timeout);
3006
+ timer?.unref?.();
3007
+ });
3008
+ return Promise.race([promise, deadline]).finally(() => clearTimeout(timer));
3009
+ }
2940
3010
  // Annotate the CommonJS export names for ESM import in node:
2941
3011
  0 && (module.exports = {
2942
3012
  DataMapperError,
package/dist/index.mjs CHANGED
@@ -92,6 +92,16 @@ function safeJsonStringify(obj) {
92
92
  return val;
93
93
  });
94
94
  }
95
+ var MAX_PUSH_SPREAD_ARGS = 8192;
96
+ function appendToArray(target, source) {
97
+ if (source.length <= MAX_PUSH_SPREAD_ARGS) {
98
+ target.push(...source);
99
+ return;
100
+ }
101
+ for (let i = 0; i < source.length; i += MAX_PUSH_SPREAD_ARGS) {
102
+ target.push(...source.slice(i, i + MAX_PUSH_SPREAD_ARGS));
103
+ }
104
+ }
95
105
 
96
106
  // src/json-protocol.ts
97
107
  function normalizeJsonProtocolValues(result) {
@@ -173,10 +183,8 @@ function deserializeTaggedValue({ $type, value }) {
173
183
  switch ($type) {
174
184
  case "BigInt":
175
185
  return BigInt(value);
176
- case "Bytes": {
177
- const { buffer, byteOffset, byteLength } = Buffer.from(value, "base64");
178
- return new Uint8Array(buffer, byteOffset, byteLength);
179
- }
186
+ case "Bytes":
187
+ return new Uint8Array(Buffer.from(value, "base64"));
180
188
  case "DateTime":
181
189
  return new Date(value);
182
190
  case "Decimal":
@@ -290,6 +298,7 @@ function getErrorCode(err) {
290
298
  case "UniqueConstraintViolation":
291
299
  return "P2002";
292
300
  case "ForeignKeyConstraintViolation":
301
+ case "RestrictViolation":
293
302
  return "P2003";
294
303
  case "InvalidInputValue":
295
304
  return "P2007";
@@ -362,6 +371,7 @@ function renderErrorMessage(err) {
362
371
  case "UniqueConstraintViolation":
363
372
  return `Unique constraint failed on the ${renderConstraint(err.cause.constraint)}`;
364
373
  case "ForeignKeyConstraintViolation":
374
+ case "RestrictViolation":
365
375
  return `Foreign key constraint violated on the ${renderConstraint(err.cause.constraint)}`;
366
376
  case "UnsupportedNativeDataType":
367
377
  return `Failed to deserialize column of type '${err.cause.type}'. If you're using $queryRaw and this column is explicitly marked as \`Unsupported\` in your Prisma schema, try casting this column to any supported Prisma type such as \`String\`.`;
@@ -1095,8 +1105,9 @@ function renderTemplateSql(fragments, placeholderFormat, params, argTypes) {
1095
1105
  if (fragment.type === "stringChunk") {
1096
1106
  continue;
1097
1107
  }
1098
- const length = flattenedParams.length;
1099
- const added = flattenedParams.push(...flattenedFragmentParams(fragment)) - length;
1108
+ const fragmentParams = Array.from(flattenedFragmentParams(fragment));
1109
+ const added = fragmentParams.length;
1110
+ appendToArray(flattenedParams, fragmentParams);
1100
1111
  if (fragment.argType.arity === "tuple") {
1101
1112
  if (added % fragment.argType.elements.length !== 0) {
1102
1113
  throw new Error(
@@ -1645,7 +1656,7 @@ var QueryInterpreter = class _QueryInterpreter {
1645
1656
  if (results === void 0) {
1646
1657
  results = result;
1647
1658
  } else {
1648
- results.rows.push(...result.rows);
1659
+ appendToArray(results.rows, result.rows);
1649
1660
  results.lastInsertId = result.lastInsertId;
1650
1661
  }
1651
1662
  }
@@ -2500,6 +2511,14 @@ var InvalidTransactionIsolationLevelError = class extends TransactionManagerErro
2500
2511
 
2501
2512
  // src/transaction-manager/transaction-manager.ts
2502
2513
  var MAX_CLOSED_TRANSACTIONS = 100;
2514
+ var CANCEL_ROLLBACK_GRACE_MS = 2e3;
2515
+ function trackStartingTransaction() {
2516
+ let markSettled;
2517
+ const settled = new Promise((resolve) => {
2518
+ markSettled = resolve;
2519
+ });
2520
+ return { abortController: new AbortController(), settled, markSettled };
2521
+ }
2503
2522
  var debug = Debug("prisma:client:transactionManager");
2504
2523
  var COMMIT_QUERY = () => ({ sql: "COMMIT", args: [], argTypes: [] });
2505
2524
  var ROLLBACK_QUERY = () => ({ sql: "ROLLBACK", args: [], argTypes: [] });
@@ -2519,6 +2538,9 @@ var TransactionManager = class {
2519
2538
  // List of last closed transactions. Max MAX_CLOSED_TRANSACTIONS entries.
2520
2539
  // Used to provide better error messages than a generic "transaction not found".
2521
2540
  closedTransactions = [];
2541
+ // Transactions that are still being started. Tracked separately so that
2542
+ // `cancelAllTransactions` can reach them: they are not in `transactions` yet.
2543
+ #startingTransactions = /* @__PURE__ */ new Set();
2522
2544
  driverAdapter;
2523
2545
  transactionOptions;
2524
2546
  tracingHelper;
@@ -2582,56 +2604,91 @@ var TransactionManager = class {
2582
2604
  return { id: existing.id };
2583
2605
  });
2584
2606
  }
2585
- const transaction = {
2586
- id: await randomUUID(),
2587
- status: "waiting",
2588
- timer: void 0,
2589
- timeout: options.timeout,
2590
- startedAt: Date.now(),
2591
- transaction: void 0,
2592
- operationQueue: Promise.resolve(),
2593
- depth: 1,
2594
- savepoints: [],
2595
- savepointCounter: 0
2596
- };
2597
- const abortController = new AbortController();
2598
- const startTimer = createTimeoutIfDefined(() => abortController.abort(), options.maxWait);
2599
- startTimer?.unref?.();
2600
- const startTransactionPromise = this.driverAdapter.startTransaction(options.isolationLevel).catch(rethrowAsUserFacing);
2601
- transaction.transaction = await Promise.race([
2602
- startTransactionPromise.finally(() => clearTimeout(startTimer)),
2603
- once(abortController.signal, "abort").then(() => void 0)
2604
- ]);
2605
- this.transactions.set(transaction.id, transaction);
2606
- switch (transaction.status) {
2607
- case "waiting":
2608
- if (abortController.signal.aborted) {
2609
- void startTransactionPromise.then(async (tx) => {
2610
- if (tx.options.usePhantomQuery) {
2611
- await tx.rollback();
2612
- } else {
2613
- try {
2614
- await tx.executeRaw(ROLLBACK_QUERY());
2615
- } finally {
2616
- await tx.rollback();
2617
- }
2618
- }
2619
- }).catch((e) => debug("error in discarded transaction:", e));
2620
- await this.#closeTransaction(transaction, "timed_out");
2621
- throw new TransactionStartTimeoutError();
2607
+ const starting = trackStartingTransaction();
2608
+ const { abortController } = starting;
2609
+ this.#startingTransactions.add(starting);
2610
+ let discarding;
2611
+ try {
2612
+ const transaction = {
2613
+ id: await randomUUID(),
2614
+ status: "waiting",
2615
+ timer: void 0,
2616
+ timeout: options.timeout,
2617
+ startedAt: Date.now(),
2618
+ transaction: void 0,
2619
+ operationQueue: Promise.resolve(),
2620
+ depth: 1,
2621
+ savepoints: [],
2622
+ savepointCounter: 0
2623
+ };
2624
+ if (abortController.signal.aborted) {
2625
+ throw new TransactionStartTimeoutError();
2626
+ }
2627
+ const startTimer = createTimeoutIfDefined(() => abortController.abort(), options.maxWait);
2628
+ startTimer?.unref?.();
2629
+ const startTransactionPromise = this.driverAdapter.startTransaction(options.isolationLevel).catch(rethrowAsUserFacing);
2630
+ transaction.transaction = await Promise.race([
2631
+ startTransactionPromise.finally(() => clearTimeout(startTimer)),
2632
+ once(abortController.signal, "abort").then(() => void 0)
2633
+ ]);
2634
+ this.transactions.set(transaction.id, transaction);
2635
+ switch (transaction.status) {
2636
+ case "waiting":
2637
+ if (abortController.signal.aborted) {
2638
+ transaction.transaction = void 0;
2639
+ discarding = this.#discardStartedTransaction(startTransactionPromise);
2640
+ await this.#closeTransaction(transaction, "timed_out");
2641
+ throw new TransactionStartTimeoutError();
2642
+ }
2643
+ transaction.status = "running";
2644
+ transaction.startedAt = Date.now();
2645
+ transaction.timer = this.#startTransactionTimeout(transaction.id, options.timeout);
2646
+ return { id: transaction.id };
2647
+ case "timed_out":
2648
+ case "running":
2649
+ case "committed":
2650
+ case "rolled_back":
2651
+ throw new TransactionInternalConsistencyError(
2652
+ `Transaction in invalid state ${transaction.status} although it just finished startup.`
2653
+ );
2654
+ default:
2655
+ return assertNever(transaction["status"], "Unknown transaction status.");
2656
+ }
2657
+ } finally {
2658
+ this.#startingTransactions.delete(starting);
2659
+ if (discarding) {
2660
+ void discarding.finally(starting.markSettled);
2661
+ } else {
2662
+ starting.markSettled();
2663
+ }
2664
+ }
2665
+ }
2666
+ /**
2667
+ * Rolls back a transaction whose start was abandoned, and releases its connection.
2668
+ *
2669
+ * The `startTransaction` promise may still be running in the background. If it eventually
2670
+ * succeeds, we need to roll back and release the connection to avoid leaking it and
2671
+ * exhausting the connection pool. For adapters that don't use phantom queries (e.g. pg/neon),
2672
+ * `rollback()` only releases the connection without sending SQL, so we send an explicit
2673
+ * ROLLBACK first; otherwise the connection returns to the pool mid-transaction because
2674
+ * `BEGIN` already ran on the wire during startup.
2675
+ *
2676
+ * Errors are only logged: the caller has already reported the failure that led here.
2677
+ */
2678
+ async #discardStartedTransaction(startTransactionPromise) {
2679
+ try {
2680
+ const tx = await startTransactionPromise;
2681
+ if (tx.options.usePhantomQuery) {
2682
+ await tx.rollback();
2683
+ } else {
2684
+ try {
2685
+ await tx.executeRaw(ROLLBACK_QUERY());
2686
+ } finally {
2687
+ await tx.rollback();
2622
2688
  }
2623
- transaction.status = "running";
2624
- transaction.timer = this.#startTransactionTimeout(transaction.id, options.timeout);
2625
- return { id: transaction.id };
2626
- case "timed_out":
2627
- case "running":
2628
- case "committed":
2629
- case "rolled_back":
2630
- throw new TransactionInternalConsistencyError(
2631
- `Transaction in invalid state ${transaction.status} although it just finished startup.`
2632
- );
2633
- default:
2634
- assertNever(transaction["status"], "Unknown transaction status.");
2689
+ }
2690
+ } catch (e) {
2691
+ debug("error in discarded transaction:", e);
2635
2692
  }
2636
2693
  }
2637
2694
  async commitTransaction(transactionId) {
@@ -2722,16 +2779,21 @@ var TransactionManager = class {
2722
2779
  return transaction;
2723
2780
  }
2724
2781
  async cancelAllTransactions() {
2725
- await Promise.allSettled(
2726
- [...this.transactions.values()].map(
2782
+ const starting = [...this.#startingTransactions];
2783
+ for (const { abortController } of starting) {
2784
+ abortController.abort();
2785
+ }
2786
+ await Promise.allSettled([
2787
+ ...[...this.transactions.values()].map(
2727
2788
  (tx) => this.#runSerialized(tx, async () => {
2728
2789
  const current = this.transactions.get(tx.id);
2729
2790
  if (current) {
2730
2791
  await this.#closeTransaction(current, "rolled_back");
2731
2792
  }
2732
2793
  })
2733
- )
2734
- );
2794
+ ),
2795
+ ...starting.map(({ settled }) => settleWithin(settled, CANCEL_ROLLBACK_GRACE_MS))
2796
+ ]);
2735
2797
  }
2736
2798
  #nextSavepointName(transaction) {
2737
2799
  return `prisma_sp_${transaction.savepointCounter++}`;
@@ -2884,6 +2946,14 @@ var TransactionManager = class {
2884
2946
  function createTimeoutIfDefined(cb, ms) {
2885
2947
  return ms !== void 0 ? setTimeout(cb, ms) : void 0;
2886
2948
  }
2949
+ function settleWithin(promise, timeout) {
2950
+ let timer;
2951
+ const deadline = new Promise((resolve) => {
2952
+ timer = setTimeout(resolve, timeout);
2953
+ timer?.unref?.();
2954
+ });
2955
+ return Promise.race([promise, deadline]).finally(() => clearTimeout(timer));
2956
+ }
2887
2957
  export {
2888
2958
  DataMapperError,
2889
2959
  QueryInterpreter,
@@ -0,0 +1 @@
1
+ export {};
package/dist/utils.d.ts CHANGED
@@ -20,3 +20,8 @@ export declare function doKeysMatch(lhs: {}, rhs: {}): boolean;
20
20
  * BigInt and Uint8Array values.
21
21
  */
22
22
  export declare function safeJsonStringify(obj: unknown): string;
23
+ /**
24
+ * Appends all elements of `source` to `target` without spreading the whole
25
+ * array as call arguments, which overflows the stack for large arrays.
26
+ */
27
+ export declare function appendToArray<T>(target: T[], source: readonly T[]): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prisma/client-engine-runtime",
3
- "version": "7.10.0-dev.2",
3
+ "version": "7.10.0-dev.21",
4
4
  "description": "This package is intended for Prisma's internal use",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -31,20 +31,20 @@
31
31
  "nanoid": "5.1.5",
32
32
  "ulid": "3.0.0",
33
33
  "uuid": "14.0.0",
34
- "@prisma/client-runtime-utils": "7.10.0-dev.2",
35
- "@prisma/debug": "7.10.0-dev.2",
36
- "@prisma/driver-adapter-utils": "7.10.0-dev.2",
37
- "@prisma/sqlcommenter": "7.10.0-dev.2",
38
- "@prisma/param-graph": "7.10.0-dev.2",
39
- "@prisma/json-protocol": "7.10.0-dev.2"
34
+ "@prisma/debug": "7.10.0-dev.21",
35
+ "@prisma/driver-adapter-utils": "7.10.0-dev.21",
36
+ "@prisma/sqlcommenter": "7.10.0-dev.21",
37
+ "@prisma/param-graph": "7.10.0-dev.21",
38
+ "@prisma/client-runtime-utils": "7.10.0-dev.21",
39
+ "@prisma/json-protocol": "7.10.0-dev.21"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@codspeed/benchmark.js-plugin": "4.0.0",
43
43
  "@types/benchmark": "2.1.5",
44
44
  "@types/node": "~20.19.24",
45
45
  "benchmark": "2.1.4",
46
- "@prisma/param-graph-builder": "7.10.0-dev.2",
47
- "@prisma/get-dmmf": "7.10.0-dev.2"
46
+ "@prisma/get-dmmf": "7.10.0-dev.21",
47
+ "@prisma/param-graph-builder": "7.10.0-dev.21"
48
48
  },
49
49
  "files": [
50
50
  "dist"