@prisma/client-engine-runtime 7.10.0-dev.3 → 7.10.0-dev.31

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(
@@ -1612,17 +1623,27 @@ var QueryInterpreter = class _QueryInterpreter {
1612
1623
  });
1613
1624
  }
1614
1625
  async run(queryPlan, options) {
1615
- const { value } = await this.interpretNode(queryPlan, {
1616
- ...options,
1617
- generators: this.#generators.snapshot()
1618
- }).catch((e) => rethrowAsUserFacing(e));
1626
+ const generators = this.#generators.snapshot();
1627
+ const context = { ...options, generators };
1628
+ const purified = purifyQueryPlan(queryPlan, (node) => this.interpretNode(node, context))?.catch(
1629
+ (e) => rethrowAsUserFacing(e)
1630
+ );
1631
+ if (purified) {
1632
+ try {
1633
+ return this.#interpretPureNode(await purified, context.scope, generators).value;
1634
+ } catch (e) {
1635
+ rethrowAsUserFacing(e);
1636
+ }
1637
+ }
1638
+ const { value } = await this.interpretNode(queryPlan, context).catch((e) => rethrowAsUserFacing(e));
1619
1639
  return value;
1620
1640
  }
1621
1641
  async interpretNode(node, context) {
1622
1642
  switch (node.type) {
1623
1643
  case "value": {
1624
1644
  return {
1625
- value: evaluateArg(node.args, context.scope, context.generators)
1645
+ value: evaluateArg(node.args, context.scope, context.generators),
1646
+ lastInsertId: node.lastInsertId
1626
1647
  };
1627
1648
  }
1628
1649
  case "seq": {
@@ -1632,9 +1653,6 @@ var QueryInterpreter = class _QueryInterpreter {
1632
1653
  }
1633
1654
  return result ?? { value: void 0 };
1634
1655
  }
1635
- case "get": {
1636
- return { value: context.scope[node.args.name] };
1637
- }
1638
1656
  case "let": {
1639
1657
  const nestedScope = Object.create(context.scope);
1640
1658
  for (const binding of node.args.bindings) {
@@ -1643,15 +1661,6 @@ var QueryInterpreter = class _QueryInterpreter {
1643
1661
  }
1644
1662
  return this.interpretNode(node.args.expr, { ...context, scope: nestedScope });
1645
1663
  }
1646
- case "getFirstNonEmpty": {
1647
- for (const name of node.args.names) {
1648
- const value = context.scope[name];
1649
- if (!isEmpty(value)) {
1650
- return { value };
1651
- }
1652
- }
1653
- return { value: [] };
1654
- }
1655
1664
  case "concat": {
1656
1665
  const parts = await Promise.all(
1657
1666
  node.args.map((arg) => this.interpretNode(arg, context).then((res) => res.value))
@@ -1698,7 +1707,7 @@ var QueryInterpreter = class _QueryInterpreter {
1698
1707
  if (results === void 0) {
1699
1708
  results = result;
1700
1709
  } else {
1701
- results.rows.push(...result.rows);
1710
+ appendToArray(results.rows, result.rows);
1702
1711
  results.lastInsertId = result.lastInsertId;
1703
1712
  }
1704
1713
  }
@@ -1778,9 +1787,6 @@ var QueryInterpreter = class _QueryInterpreter {
1778
1787
  return await this.interpretNode(node.args.else, context);
1779
1788
  }
1780
1789
  }
1781
- case "unit": {
1782
- return { value: void 0 };
1783
- }
1784
1790
  case "diff": {
1785
1791
  const { value: from } = await this.interpretNode(node.args.from, context);
1786
1792
  const { value: to } = await this.interpretNode(node.args.to, context);
@@ -1810,6 +1816,139 @@ var QueryInterpreter = class _QueryInterpreter {
1810
1816
  }
1811
1817
  return { value: record, lastInsertId };
1812
1818
  }
1819
+ default:
1820
+ return this.#interpretPureNode(node, context.scope, context.generators);
1821
+ }
1822
+ }
1823
+ #interpretPureNode(node, scope, generators) {
1824
+ switch (node.type) {
1825
+ case "value": {
1826
+ return { value: evaluateArg(node.args, scope, generators), lastInsertId: node.lastInsertId };
1827
+ }
1828
+ case "seq": {
1829
+ let result;
1830
+ for (const arg of node.args) {
1831
+ result = this.#interpretPureNode(arg, scope, generators);
1832
+ }
1833
+ return result ?? { value: void 0 };
1834
+ }
1835
+ case "get": {
1836
+ return { value: scope[node.args.name] };
1837
+ }
1838
+ case "let": {
1839
+ const nestedScope = Object.create(scope);
1840
+ for (const binding of node.args.bindings) {
1841
+ const { value } = this.#interpretPureNode(binding.expr, nestedScope, generators);
1842
+ nestedScope[binding.name] = value;
1843
+ }
1844
+ return this.#interpretPureNode(node.args.expr, nestedScope, generators);
1845
+ }
1846
+ case "getFirstNonEmpty": {
1847
+ for (const name of node.args.names) {
1848
+ const value = scope[name];
1849
+ if (!isEmpty(value)) {
1850
+ return { value };
1851
+ }
1852
+ }
1853
+ return { value: [] };
1854
+ }
1855
+ case "concat": {
1856
+ const parts = node.args.map((arg) => this.#interpretPureNode(arg, scope, generators).value);
1857
+ return {
1858
+ value: parts.length > 0 ? parts.reduce((acc, part) => acc.concat(asList(part)), []) : []
1859
+ };
1860
+ }
1861
+ case "sum": {
1862
+ const parts = node.args.map((arg) => this.#interpretPureNode(arg, scope, generators).value);
1863
+ return {
1864
+ value: parts.length > 0 ? parts.reduce((acc, part) => asNumber2(acc) + asNumber2(part)) : 0
1865
+ };
1866
+ }
1867
+ case "reverse": {
1868
+ const { value, lastInsertId } = this.#interpretPureNode(node.args, scope, generators);
1869
+ return { value: Array.isArray(value) ? value.reverse() : value, lastInsertId };
1870
+ }
1871
+ case "unique": {
1872
+ const { value, lastInsertId } = this.#interpretPureNode(node.args, scope, generators);
1873
+ if (!Array.isArray(value)) {
1874
+ return { value, lastInsertId };
1875
+ }
1876
+ if (value.length > 1) {
1877
+ throw new Error(`Expected zero or one element, got ${value.length}`);
1878
+ }
1879
+ return { value: value[0] ?? null, lastInsertId };
1880
+ }
1881
+ case "required": {
1882
+ const { value, lastInsertId } = this.#interpretPureNode(node.args, scope, generators);
1883
+ if (isEmpty(value)) {
1884
+ throw new Error("Required value is empty");
1885
+ }
1886
+ return { value, lastInsertId };
1887
+ }
1888
+ case "mapField": {
1889
+ const { value, lastInsertId } = this.#interpretPureNode(node.args.records, scope, generators);
1890
+ return { value: mapField2(value, node.args.field), lastInsertId };
1891
+ }
1892
+ case "join": {
1893
+ const { value: parent, lastInsertId } = this.#interpretPureNode(node.args.parent, scope, generators);
1894
+ if (parent === null) {
1895
+ return { value: null, lastInsertId };
1896
+ }
1897
+ const children = node.args.children.map((joinExpr) => ({
1898
+ joinExpr,
1899
+ childRecords: this.#interpretPureNode(joinExpr.child, scope, generators).value
1900
+ }));
1901
+ return { value: attachChildrenToParents(parent, children, node.args.canAssumeStrictEquality), lastInsertId };
1902
+ }
1903
+ case "dataMap": {
1904
+ const { value, lastInsertId } = this.#interpretPureNode(node.args.expr, scope, generators);
1905
+ return { value: applyDataMap(value, node.args.structure, node.args.enums), lastInsertId };
1906
+ }
1907
+ case "validate": {
1908
+ const { value, lastInsertId } = this.#interpretPureNode(node.args.expr, scope, generators);
1909
+ performValidation(value, node.args.rules, node.args);
1910
+ return { value, lastInsertId };
1911
+ }
1912
+ case "if": {
1913
+ const { value } = this.#interpretPureNode(node.args.value, scope, generators);
1914
+ if (doesSatisfyRule(value, node.args.rule)) {
1915
+ return this.#interpretPureNode(node.args.then, scope, generators);
1916
+ } else {
1917
+ return this.#interpretPureNode(node.args.else, scope, generators);
1918
+ }
1919
+ }
1920
+ case "unit": {
1921
+ return { value: void 0 };
1922
+ }
1923
+ case "diff": {
1924
+ const { value: from } = this.#interpretPureNode(node.args.from, scope, generators);
1925
+ const { value: to } = this.#interpretPureNode(node.args.to, scope, generators);
1926
+ const keyGetter = (item) => item !== null ? getRecordKey(asRecord(item), node.args.fields) : null;
1927
+ const toSet = new Set(asList(to).map(keyGetter));
1928
+ return { value: asList(from).filter((item) => !toSet.has(keyGetter(item))) };
1929
+ }
1930
+ case "process": {
1931
+ const { value, lastInsertId } = this.#interpretPureNode(node.args.expr, scope, generators);
1932
+ const ops = cloneObject(node.args.operations);
1933
+ evaluateProcessingParameters(ops, scope, generators);
1934
+ return { value: processRecords(value, ops), lastInsertId };
1935
+ }
1936
+ case "initializeRecord": {
1937
+ const { lastInsertId } = this.#interpretPureNode(node.args.expr, scope, generators);
1938
+ const record = {};
1939
+ for (const [key, initializer] of Object.entries(node.args.fields)) {
1940
+ record[key] = evalFieldInitializer(initializer, lastInsertId, scope, generators);
1941
+ }
1942
+ return { value: record, lastInsertId };
1943
+ }
1944
+ case "mapRecord": {
1945
+ const { value, lastInsertId } = this.#interpretPureNode(node.args.expr, scope, generators);
1946
+ const record = value === null ? {} : asRecord(value);
1947
+ for (const [key, entry] of Object.entries(node.args.fields)) {
1948
+ record[key] = evalFieldOperation(entry, record[key], scope, generators);
1949
+ }
1950
+ return { value: record, lastInsertId };
1951
+ }
1813
1952
  default:
1814
1953
  assertNever(node, `Unexpected node type: ${node.type}`);
1815
1954
  }
@@ -1987,6 +2126,112 @@ function evalFieldOperation(op, value, scope, generators) {
1987
2126
  assertNever(op, `Unexpected field operation type: ${op["type"]}`);
1988
2127
  }
1989
2128
  }
2129
+ function purifyQueryPlan(node, evalNode) {
2130
+ const impureNode = findUniqueUnconditionalImpureNode(node);
2131
+ if (!impureNode) {
2132
+ return void 0;
2133
+ }
2134
+ return evalNode(impureNode).then((result) => {
2135
+ const evaluated = {
2136
+ type: "value",
2137
+ args: result.value,
2138
+ lastInsertId: result.lastInsertId
2139
+ };
2140
+ const purified = replaceImpureNode(node, impureNode, evaluated);
2141
+ if (!purified) {
2142
+ throw new Error("Could not substitute the evaluated impure node into the query plan");
2143
+ }
2144
+ return purified;
2145
+ });
2146
+ }
2147
+ function replaceImpureNode(node, target, replacement) {
2148
+ if (node === target) {
2149
+ return replacement;
2150
+ }
2151
+ switch (node.type) {
2152
+ case "seq":
2153
+ case "sum":
2154
+ case "concat": {
2155
+ for (let i = 0; i < node.args.length; i++) {
2156
+ const child = replaceImpureNode(node.args[i], target, replacement);
2157
+ if (child) {
2158
+ return { ...node, args: node.args.map((arg, j) => j === i ? child : arg) };
2159
+ }
2160
+ }
2161
+ return void 0;
2162
+ }
2163
+ case "dataMap":
2164
+ case "validate":
2165
+ case "initializeRecord":
2166
+ case "mapRecord":
2167
+ case "process": {
2168
+ const expr = replaceImpureNode(node.args.expr, target, replacement);
2169
+ return expr && { ...node, args: { ...node.args, expr } };
2170
+ }
2171
+ case "mapField": {
2172
+ const records = replaceImpureNode(node.args.records, target, replacement);
2173
+ return records && { ...node, args: { ...node.args, records } };
2174
+ }
2175
+ case "reverse":
2176
+ case "unique":
2177
+ case "required": {
2178
+ const args = replaceImpureNode(node.args, target, replacement);
2179
+ return args && { ...node, args };
2180
+ }
2181
+ default:
2182
+ return void 0;
2183
+ }
2184
+ }
2185
+ function findUniqueUnconditionalImpureNode(node) {
2186
+ switch (node.type) {
2187
+ case "query":
2188
+ case "execute":
2189
+ return node;
2190
+ case "seq":
2191
+ case "sum":
2192
+ case "concat": {
2193
+ let found = void 0;
2194
+ for (const child of node.args) {
2195
+ const childFound = findUniqueUnconditionalImpureNode(child);
2196
+ if (childFound === null) {
2197
+ return null;
2198
+ }
2199
+ if (childFound) {
2200
+ if (found) {
2201
+ return null;
2202
+ }
2203
+ found = childFound;
2204
+ }
2205
+ }
2206
+ return found;
2207
+ }
2208
+ case "dataMap":
2209
+ case "validate":
2210
+ case "initializeRecord":
2211
+ case "mapRecord":
2212
+ case "process":
2213
+ return findUniqueUnconditionalImpureNode(node.args.expr);
2214
+ case "mapField":
2215
+ return findUniqueUnconditionalImpureNode(node.args.records);
2216
+ case "reverse":
2217
+ case "unique":
2218
+ case "required":
2219
+ return findUniqueUnconditionalImpureNode(node.args);
2220
+ case "let":
2221
+ case "join":
2222
+ case "diff":
2223
+ case "if":
2224
+ case "transaction":
2225
+ return null;
2226
+ case "value":
2227
+ case "get":
2228
+ case "getFirstNonEmpty":
2229
+ case "unit":
2230
+ return void 0;
2231
+ default:
2232
+ assertNever(node, `Unexpected node type: ${node.type}`);
2233
+ }
2234
+ }
1990
2235
  function applyComments(query, sqlCommenter) {
1991
2236
  if (!sqlCommenter || sqlCommenter.plugins.length === 0) {
1992
2237
  return query;
@@ -2553,6 +2798,14 @@ var InvalidTransactionIsolationLevelError = class extends TransactionManagerErro
2553
2798
 
2554
2799
  // src/transaction-manager/transaction-manager.ts
2555
2800
  var MAX_CLOSED_TRANSACTIONS = 100;
2801
+ var CANCEL_ROLLBACK_GRACE_MS = 2e3;
2802
+ function trackStartingTransaction() {
2803
+ let markSettled;
2804
+ const settled = new Promise((resolve) => {
2805
+ markSettled = resolve;
2806
+ });
2807
+ return { abortController: new AbortController(), settled, markSettled };
2808
+ }
2556
2809
  var debug = (0, import_debug.Debug)("prisma:client:transactionManager");
2557
2810
  var COMMIT_QUERY = () => ({ sql: "COMMIT", args: [], argTypes: [] });
2558
2811
  var ROLLBACK_QUERY = () => ({ sql: "ROLLBACK", args: [], argTypes: [] });
@@ -2572,6 +2825,9 @@ var TransactionManager = class {
2572
2825
  // List of last closed transactions. Max MAX_CLOSED_TRANSACTIONS entries.
2573
2826
  // Used to provide better error messages than a generic "transaction not found".
2574
2827
  closedTransactions = [];
2828
+ // Transactions that are still being started. Tracked separately so that
2829
+ // `cancelAllTransactions` can reach them: they are not in `transactions` yet.
2830
+ #startingTransactions = /* @__PURE__ */ new Set();
2575
2831
  driverAdapter;
2576
2832
  transactionOptions;
2577
2833
  tracingHelper;
@@ -2635,56 +2891,91 @@ var TransactionManager = class {
2635
2891
  return { id: existing.id };
2636
2892
  });
2637
2893
  }
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();
2894
+ const starting = trackStartingTransaction();
2895
+ const { abortController } = starting;
2896
+ this.#startingTransactions.add(starting);
2897
+ let discarding;
2898
+ try {
2899
+ const transaction = {
2900
+ id: await randomUUID(),
2901
+ status: "waiting",
2902
+ timer: void 0,
2903
+ timeout: options.timeout,
2904
+ startedAt: Date.now(),
2905
+ transaction: void 0,
2906
+ operationQueue: Promise.resolve(),
2907
+ depth: 1,
2908
+ savepoints: [],
2909
+ savepointCounter: 0
2910
+ };
2911
+ if (abortController.signal.aborted) {
2912
+ throw new TransactionStartTimeoutError();
2913
+ }
2914
+ const startTimer = createTimeoutIfDefined(() => abortController.abort(), options.maxWait);
2915
+ startTimer?.unref?.();
2916
+ const startTransactionPromise = this.driverAdapter.startTransaction(options.isolationLevel).catch(rethrowAsUserFacing);
2917
+ transaction.transaction = await Promise.race([
2918
+ startTransactionPromise.finally(() => clearTimeout(startTimer)),
2919
+ once(abortController.signal, "abort").then(() => void 0)
2920
+ ]);
2921
+ this.transactions.set(transaction.id, transaction);
2922
+ switch (transaction.status) {
2923
+ case "waiting":
2924
+ if (abortController.signal.aborted) {
2925
+ transaction.transaction = void 0;
2926
+ discarding = this.#discardStartedTransaction(startTransactionPromise);
2927
+ await this.#closeTransaction(transaction, "timed_out");
2928
+ throw new TransactionStartTimeoutError();
2929
+ }
2930
+ transaction.status = "running";
2931
+ transaction.startedAt = Date.now();
2932
+ transaction.timer = this.#startTransactionTimeout(transaction.id, options.timeout);
2933
+ return { id: transaction.id };
2934
+ case "timed_out":
2935
+ case "running":
2936
+ case "committed":
2937
+ case "rolled_back":
2938
+ throw new TransactionInternalConsistencyError(
2939
+ `Transaction in invalid state ${transaction.status} although it just finished startup.`
2940
+ );
2941
+ default:
2942
+ return assertNever(transaction["status"], "Unknown transaction status.");
2943
+ }
2944
+ } finally {
2945
+ this.#startingTransactions.delete(starting);
2946
+ if (discarding) {
2947
+ void discarding.finally(starting.markSettled);
2948
+ } else {
2949
+ starting.markSettled();
2950
+ }
2951
+ }
2952
+ }
2953
+ /**
2954
+ * Rolls back a transaction whose start was abandoned, and releases its connection.
2955
+ *
2956
+ * The `startTransaction` promise may still be running in the background. If it eventually
2957
+ * succeeds, we need to roll back and release the connection to avoid leaking it and
2958
+ * exhausting the connection pool. For adapters that don't use phantom queries (e.g. pg/neon),
2959
+ * `rollback()` only releases the connection without sending SQL, so we send an explicit
2960
+ * ROLLBACK first; otherwise the connection returns to the pool mid-transaction because
2961
+ * `BEGIN` already ran on the wire during startup.
2962
+ *
2963
+ * Errors are only logged: the caller has already reported the failure that led here.
2964
+ */
2965
+ async #discardStartedTransaction(startTransactionPromise) {
2966
+ try {
2967
+ const tx = await startTransactionPromise;
2968
+ if (tx.options.usePhantomQuery) {
2969
+ await tx.rollback();
2970
+ } else {
2971
+ try {
2972
+ await tx.executeRaw(ROLLBACK_QUERY());
2973
+ } finally {
2974
+ await tx.rollback();
2675
2975
  }
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.");
2976
+ }
2977
+ } catch (e) {
2978
+ debug("error in discarded transaction:", e);
2688
2979
  }
2689
2980
  }
2690
2981
  async commitTransaction(transactionId) {
@@ -2775,16 +3066,21 @@ var TransactionManager = class {
2775
3066
  return transaction;
2776
3067
  }
2777
3068
  async cancelAllTransactions() {
2778
- await Promise.allSettled(
2779
- [...this.transactions.values()].map(
3069
+ const starting = [...this.#startingTransactions];
3070
+ for (const { abortController } of starting) {
3071
+ abortController.abort();
3072
+ }
3073
+ await Promise.allSettled([
3074
+ ...[...this.transactions.values()].map(
2780
3075
  (tx) => this.#runSerialized(tx, async () => {
2781
3076
  const current = this.transactions.get(tx.id);
2782
3077
  if (current) {
2783
3078
  await this.#closeTransaction(current, "rolled_back");
2784
3079
  }
2785
3080
  })
2786
- )
2787
- );
3081
+ ),
3082
+ ...starting.map(({ settled }) => settleWithin(settled, CANCEL_ROLLBACK_GRACE_MS))
3083
+ ]);
2788
3084
  }
2789
3085
  #nextSavepointName(transaction) {
2790
3086
  return `prisma_sp_${transaction.savepointCounter++}`;
@@ -2937,6 +3233,14 @@ var TransactionManager = class {
2937
3233
  function createTimeoutIfDefined(cb, ms) {
2938
3234
  return ms !== void 0 ? setTimeout(cb, ms) : void 0;
2939
3235
  }
3236
+ function settleWithin(promise, timeout) {
3237
+ let timer;
3238
+ const deadline = new Promise((resolve) => {
3239
+ timer = setTimeout(resolve, timeout);
3240
+ timer?.unref?.();
3241
+ });
3242
+ return Promise.race([promise, deadline]).finally(() => clearTimeout(timer));
3243
+ }
2940
3244
  // Annotate the CommonJS export names for ESM import in node:
2941
3245
  0 && (module.exports = {
2942
3246
  DataMapperError,