@fitzzero/quickdraw-core 5.1.0 → 5.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/README.md +533 -180
  2. package/dist/{admin-DKwkIh5i.d.ts → admin-DWWrT1h6.d.ts} +2 -2
  3. package/dist/{adminSchemas-2DUA_hZ8.d.ts → adminSchemas-D4bFKsrb.d.ts} +6 -4
  4. package/dist/{auth-BhWqdyb-.d.ts → auth-DXiSJZaf.d.ts} +42 -16
  5. package/dist/{caller-CXTFswBO.d.ts → caller-BT-Mv4bD.d.ts} +117 -22
  6. package/dist/{chunk-RT6OILOI.js → chunk-4D2DOGAW.js} +2 -14
  7. package/dist/chunk-4D2DOGAW.js.map +1 -0
  8. package/dist/chunk-5CGO426C.js +15 -0
  9. package/dist/chunk-5CGO426C.js.map +1 -0
  10. package/dist/{chunk-A6DJBGOG.js → chunk-6K5BY47X.js} +4594 -3481
  11. package/dist/chunk-6K5BY47X.js.map +1 -0
  12. package/dist/{chunk-VJTFXHOK.js → chunk-753VJIUP.js} +13 -15
  13. package/dist/chunk-753VJIUP.js.map +1 -0
  14. package/dist/{chunk-JZBCLNDU.js → chunk-7QCUX4TK.js} +4 -4
  15. package/dist/chunk-7QCUX4TK.js.map +1 -0
  16. package/dist/chunk-AK23XSWD.js +16 -0
  17. package/dist/chunk-AK23XSWD.js.map +1 -0
  18. package/dist/{chunk-3674EIRT.js → chunk-AONAFOYU.js} +14 -5
  19. package/dist/{chunk-3674EIRT.js.map → chunk-AONAFOYU.js.map} +1 -1
  20. package/dist/chunk-DKE6QO26.js +136 -0
  21. package/dist/chunk-DKE6QO26.js.map +1 -0
  22. package/dist/{chunk-H23KEFBA.js → chunk-DUBU3BB3.js} +30 -1
  23. package/dist/chunk-DUBU3BB3.js.map +1 -0
  24. package/dist/{chunk-CDKG4TFA.js → chunk-GKH3LJ7N.js} +1 -1
  25. package/dist/chunk-GKH3LJ7N.js.map +1 -0
  26. package/dist/{chunk-KNDDCVQJ.js → chunk-GSIPUNJL.js} +49 -9
  27. package/dist/chunk-GSIPUNJL.js.map +1 -0
  28. package/dist/{chunk-DD4SKCNO.js → chunk-LCC7HNFP.js} +12 -1
  29. package/dist/chunk-LCC7HNFP.js.map +1 -0
  30. package/dist/{chunk-2PWMUVC7.js → chunk-MBH6IDSM.js} +480 -12
  31. package/dist/chunk-MBH6IDSM.js.map +1 -0
  32. package/dist/{chunk-2UELNHDD.js → chunk-NMXYENH4.js} +10 -10
  33. package/dist/{chunk-2UELNHDD.js.map → chunk-NMXYENH4.js.map} +1 -1
  34. package/dist/chunk-NO4M6PO5.js +101 -0
  35. package/dist/chunk-NO4M6PO5.js.map +1 -0
  36. package/dist/{chunk-TBMKJ26R.js → chunk-NW6U45HX.js} +3 -1
  37. package/dist/chunk-NW6U45HX.js.map +1 -0
  38. package/dist/{chunk-REX5YPHX.js → chunk-RJ5I2VO3.js} +74 -19
  39. package/dist/chunk-RJ5I2VO3.js.map +1 -0
  40. package/dist/{chunk-QEKVYG5F.js → chunk-RL4VKLBX.js} +1 -1
  41. package/dist/{chunk-QEKVYG5F.js.map → chunk-RL4VKLBX.js.map} +1 -1
  42. package/dist/chunk-XH2IZVLT.js +62 -0
  43. package/dist/chunk-XH2IZVLT.js.map +1 -0
  44. package/dist/{chunk-4DIQHASK.js → chunk-Z5ILULF2.js} +26 -7
  45. package/dist/chunk-Z5ILULF2.js.map +1 -0
  46. package/dist/cli/quickdraw-docs.js +5 -3
  47. package/dist/cli/quickdraw-docs.js.map +1 -1
  48. package/dist/client/index.d.ts +30 -18
  49. package/dist/client/index.js +8 -6
  50. package/dist/client/index.js.map +1 -1
  51. package/dist/{clientTypes-Bc-G8n-U.d.ts → clientTypes-hWcPUVS9.d.ts} +3 -3
  52. package/dist/{connection-Cr1BU07W.d.ts → connection-CgijdGpT.d.ts} +8 -4
  53. package/dist/{createServer-CP9eDHZZ.d.ts → createServer-Cp-Wk500.d.ts} +36 -14
  54. package/dist/{createTestApp-UKVGEmOf.d.ts → createTestApp-BB_PkqQ7.d.ts} +16 -10
  55. package/dist/{envelope-Cp3YcVxC.d.ts → envelope-DzWyIXjj.d.ts} +18 -4
  56. package/dist/{http-Djj2Inuu.d.ts → http-DotQ5bj8.d.ts} +68 -17
  57. package/dist/index.d.ts +7 -7
  58. package/dist/index.js +37 -13
  59. package/dist/index.js.map +1 -1
  60. package/dist/{infer-Teo1xpsd.d.ts → infer-BmoZsL9a.d.ts} +43 -10
  61. package/dist/logger-Yz93KzdV.d.ts +30 -0
  62. package/dist/{metrics-BdBu5o8G.d.ts → metrics-DW80Exve.d.ts} +2 -2
  63. package/dist/origins-kvpxnVcW.d.ts +8 -0
  64. package/dist/prisma/index.d.ts +5 -5
  65. package/dist/prisma/index.js +130 -67
  66. package/dist/prisma/index.js.map +1 -1
  67. package/dist/{rateLimit-ZMIZJUZF.js → rateLimit-5RKBFLUR.js} +2 -2
  68. package/dist/server/auth/index.d.ts +82 -33
  69. package/dist/server/auth/index.js +273 -268
  70. package/dist/server/auth/index.js.map +1 -1
  71. package/dist/server/express/index.d.ts +9 -2
  72. package/dist/server/express/index.js +1 -1
  73. package/dist/server/index.d.ts +147 -67
  74. package/dist/server/index.js +520 -381
  75. package/dist/server/index.js.map +1 -1
  76. package/dist/server/mcp/index.d.ts +63 -17
  77. package/dist/server/mcp/index.js +256 -54
  78. package/dist/server/mcp/index.js.map +1 -1
  79. package/dist/server/otel.d.ts +3 -3
  80. package/dist/{sharing-DVa8W-yR.d.ts → sharing-UDLn1049.d.ts} +3 -3
  81. package/dist/testing/client.d.ts +14 -14
  82. package/dist/testing/client.js +9 -7
  83. package/dist/testing/client.js.map +1 -1
  84. package/dist/testing/index.d.ts +12 -12
  85. package/dist/testing/index.js +21 -12
  86. package/dist/testing/index.js.map +1 -1
  87. package/dist/testing/mock.d.ts +5 -5
  88. package/dist/testing/mock.js +8 -6
  89. package/dist/{types-Cu0vmx7c.d.ts → types-CYliTP65.d.ts} +1 -1
  90. package/dist/utils/index.d.ts +1 -1
  91. package/package.json +1 -1
  92. package/dist/chunk-2PWMUVC7.js.map +0 -1
  93. package/dist/chunk-4DIQHASK.js.map +0 -1
  94. package/dist/chunk-A6DJBGOG.js.map +0 -1
  95. package/dist/chunk-CDKG4TFA.js.map +0 -1
  96. package/dist/chunk-DD4SKCNO.js.map +0 -1
  97. package/dist/chunk-H23KEFBA.js.map +0 -1
  98. package/dist/chunk-JZBCLNDU.js.map +0 -1
  99. package/dist/chunk-KNDDCVQJ.js.map +0 -1
  100. package/dist/chunk-REX5YPHX.js.map +0 -1
  101. package/dist/chunk-RT6OILOI.js.map +0 -1
  102. package/dist/chunk-TBMKJ26R.js.map +0 -1
  103. package/dist/chunk-VJTFXHOK.js.map +0 -1
  104. package/dist/chunk-YSWH776Y.js +0 -13
  105. package/dist/chunk-YSWH776Y.js.map +0 -1
  106. package/dist/logger-BY28acW-.d.ts +0 -16
  107. /package/dist/{rateLimit-ZMIZJUZF.js.map → rateLimit-5RKBFLUR.js.map} +0 -0
@@ -1,75 +1,83 @@
1
+ import {
2
+ findNestedWrites
3
+ } from "../chunk-XH2IZVLT.js";
1
4
  import {
2
5
  createWriteTracker,
3
6
  quietly
4
- } from "../chunk-4DIQHASK.js";
5
- import "../chunk-DD4SKCNO.js";
7
+ } from "../chunk-Z5ILULF2.js";
8
+ import "../chunk-LCC7HNFP.js";
6
9
  import {
7
10
  STORAGE_KEY,
8
11
  createInterestRegistry,
12
+ createLinkRegistry,
9
13
  modelKey,
10
14
  storageOf
11
- } from "../chunk-H23KEFBA.js";
15
+ } from "../chunk-DUBU3BB3.js";
12
16
  import {
13
17
  consoleLogger
14
- } from "../chunk-YSWH776Y.js";
18
+ } from "../chunk-DKE6QO26.js";
15
19
  import "../chunk-4YO5H5ON.js";
16
20
 
17
- // src/prisma/nested.ts
18
- var NESTED_KEYS = [
19
- "create",
20
- "createMany",
21
- "connect",
22
- "connectOrCreate",
23
- "disconnect",
24
- "set",
25
- "update",
26
- "updateMany",
27
- "upsert",
28
- "delete",
29
- "deleteMany"
30
- ];
31
- var FLAG_KEYS = /* @__PURE__ */ new Set(["delete", "disconnect"]);
32
- function isPlainObject(value) {
33
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
34
- return false;
35
- }
36
- const prototype = Object.getPrototypeOf(value);
37
- return prototype === Object.prototype || prototype === null;
38
- }
39
- function isRows(value) {
40
- return Array.isArray(value) || isPlainObject(value);
41
- }
42
- function isRelationSet(value) {
43
- return Array.isArray(value) ? value.some(isPlainObject) : isPlainObject(value);
44
- }
45
- function writesRelation(value, key) {
46
- if (!Object.hasOwn(value, key)) {
47
- return false;
48
- }
49
- const operand = value[key];
50
- if (key === "set") {
51
- return isRelationSet(operand);
21
+ // src/prisma/links.ts
22
+ var UNREAD = /* @__PURE__ */ new WeakMap();
23
+ function warnUnread(runtime, model, junction) {
24
+ const warned = UNREAD.get(runtime) ?? /* @__PURE__ */ new Set();
25
+ UNREAD.set(runtime, warned);
26
+ const key = `${model}\0${junction}`;
27
+ if (warned.has(key)) {
28
+ return;
52
29
  }
53
- return isRows(operand) || FLAG_KEYS.has(key) && operand === true;
30
+ warned.add(key);
31
+ runtime.tracker.logger.warn(
32
+ `Reading the ${junction} rows that link a deleted ${model} failed, so its deletes tell every subscribed scope of its via lists, as for a row nobody can place`,
33
+ { category: "quickdraw.writes", model, junction }
34
+ );
54
35
  }
55
- function nestedKey(value) {
56
- if (!isPlainObject(value)) {
36
+ async function readLinks(runtime, model, ids) {
37
+ const links = runtime.linksOf(model);
38
+ if (links.length === 0 || ids.length === 0) {
57
39
  return void 0;
58
40
  }
59
- return NESTED_KEYS.find((key) => writesRelation(value, key));
60
- }
61
- function findNestedWrites(data) {
62
- if (!isPlainObject(data)) {
63
- return [];
64
- }
65
- const found = [];
66
- for (const [field, value] of Object.entries(data)) {
67
- const operation = nestedKey(value);
68
- if (operation !== void 0) {
69
- found.push({ field, operation });
41
+ const byId = new Map(
42
+ ids.map((id) => [id, Object.fromEntries(links.map((link) => [link.model, []]))])
43
+ );
44
+ for (const link of links) {
45
+ const select = Object.fromEntries(
46
+ [link.entry, ...link.columns].map((column) => [column, true])
47
+ );
48
+ let delegate;
49
+ try {
50
+ delegate = runtime.delegate(link.model);
51
+ } catch {
52
+ warnUnread(runtime, model, link.model);
53
+ return void 0;
54
+ }
55
+ let rows;
56
+ try {
57
+ rows = await quietly(
58
+ () => delegate.findMany({ where: { [link.entry]: { in: [...ids] } }, select })
59
+ );
60
+ } catch (error) {
61
+ if (error instanceof Error && error.name === "PrismaClientValidationError") {
62
+ warnUnread(runtime, model, link.model);
63
+ return void 0;
64
+ }
65
+ throw error;
66
+ }
67
+ for (const row of rows) {
68
+ const entry = row[link.entry];
69
+ if (typeof entry === "string") {
70
+ byId.get(entry)?.[link.model]?.push(row);
71
+ }
70
72
  }
71
73
  }
72
- return found;
74
+ return byId;
75
+ }
76
+ function withLinks(writes, links) {
77
+ return writes.map((write) => {
78
+ const own = links?.get(write.id);
79
+ return own === void 0 ? write : { ...write, links: own };
80
+ });
73
81
  }
74
82
 
75
83
  // src/prisma/operations.ts
@@ -131,14 +139,19 @@ function countOwn(op, operation, args) {
131
139
  op.runtime.tracker.observe({ model: op.model, operation, args });
132
140
  }
133
141
  function warnNested(op, data) {
134
- for (const { field, operation } of findNestedWrites(data)) {
142
+ const nested = findNestedWrites(data);
143
+ for (const { field, operation } of nested) {
135
144
  op.runtime.tracker.warn({
136
145
  kind: "nested-write",
137
146
  subject: `${op.model}.${field}.${operation}`,
138
- message: `A nested write (${op.model}.${field}: { ${operation} }) is not tracked; only the ${op.model} row is. Write related rows through their own model`,
147
+ message: `A nested write (${op.model}.${field}: { ${operation} }) is not tracked: the related rows it creates, changes or deletes send no frames and revoke nothing. The ${op.model} row is tracked, and an update of it reads its access and scope columns first, so a foreign key a to-one connect or disconnect sets on it is seen. Write related rows through their own model, or set the foreign key column`,
139
148
  meta: { model: op.model, field, operation }
140
149
  });
141
150
  }
151
+ return nested.length > 0;
152
+ }
153
+ function withColumns(data, columns) {
154
+ return [.../* @__PURE__ */ new Set([...keysOf(data), ...columns])];
142
155
  }
143
156
  function touchedInterest(op, data) {
144
157
  const keys = new Set(keysOf(data));
@@ -289,12 +302,13 @@ async function upsert(op) {
289
302
  return upsertWithoutUpdate(op);
290
303
  }
291
304
  warnNested(op, op.args.create);
292
- warnNested(op, op.args.update);
293
- const touched = touchedInterest(op, op.args.update);
305
+ const nested = warnNested(op, op.args.update);
306
+ const touched = nested ? [...op.runtime.interestOf(op.model)] : touchedInterest(op, op.args.update);
294
307
  const before = touched.length === 0 ? void 0 : await readBefore(op, op.args.where, touched, { unique: true });
295
308
  const { result, rows } = await runWidened(op);
296
309
  if (before !== void 0 && before.size > 0) {
297
- record(op, writesOf(op, "update", rows, keysOf(op.args.update), before));
310
+ const fields = nested ? withColumns(op.args.update, touched) : keysOf(op.args.update);
311
+ record(op, writesOf(op, "update", rows, fields, before));
298
312
  } else if (before === void 0) {
299
313
  const writes = writesOf(op, "create", rows, keysOf([op.args.create, op.args.update]));
300
314
  record(
@@ -310,16 +324,27 @@ async function update(op) {
310
324
  if (writesNothing(op.args.data)) {
311
325
  return op.query(op.args);
312
326
  }
313
- warnNested(op, op.args.data);
314
- const touched = touchedInterest(op, op.args.data);
327
+ const nested = warnNested(op, op.args.data);
328
+ const touched = nested ? [...op.runtime.interestOf(op.model)] : touchedInterest(op, op.args.data);
315
329
  const before = touched.length === 0 ? void 0 : await readBefore(op, op.args.where, touched, { unique: true });
316
330
  const { result, rows } = await runWidened(op);
317
- record(op, writesOf(op, "update", rows, keysOf(op.args.data), before));
331
+ const fields = nested ? withColumns(op.args.data, touched) : keysOf(op.args.data);
332
+ record(op, writesOf(op, "update", rows, fields, before));
318
333
  return result;
319
334
  }
335
+ async function linksOfDelete(op) {
336
+ if (op.runtime.linksOf(op.model).length === 0) {
337
+ return void 0;
338
+ }
339
+ warnBatchRead(op);
340
+ const { where } = op.args;
341
+ const ids = isRecord(where) && typeof where.id === "string" ? [where.id] : [...(await readBefore(op, where, [], { unique: true })).keys()];
342
+ return await readLinks(op.runtime, op.model, ids);
343
+ }
320
344
  async function remove(op) {
345
+ const links = await linksOfDelete(op);
321
346
  const { result, rows } = await runWidened(op);
322
- record(op, writesOf(op, "delete", rows, []));
347
+ record(op, withLinks(writesOf(op, "delete", rows, []), links));
323
348
  return result;
324
349
  }
325
350
  async function createManyAndReturn(op) {
@@ -401,10 +426,11 @@ async function deleteMany(op) {
401
426
  const interest = op.runtime.interestOf(op.model);
402
427
  const before = await readBefore(op, where, interest, { unique: false, take: limit });
403
428
  const ids = [...before.keys()];
429
+ const links = await readLinks(op.runtime, op.model, ids);
404
430
  const args = limit === void 0 ? op.args : { ...op.args, where: { AND: [where ?? {}, { id: { in: ids } }] } };
405
431
  const result = await op.query(args);
406
432
  const rows = ids.map((id) => ({ id, ...before.get(id) }));
407
- record(op, writesOf(op, "delete", rows, []));
433
+ record(op, withLinks(writesOf(op, "delete", rows, []), links));
408
434
  return result;
409
435
  }
410
436
  var WRITE_OPERATIONS = Object.freeze({
@@ -508,7 +534,34 @@ function createNullability(delegate) {
508
534
  return nullable;
509
535
  };
510
536
  }
511
- function createStorage(tracker, interest, delegate) {
537
+ function createTrackability(delegate) {
538
+ const known = /* @__PURE__ */ new Map();
539
+ const probe = async (key) => {
540
+ try {
541
+ const rows = await quietly(() => delegate(key).findMany({ select: { id: true }, take: 1 }));
542
+ const [row] = Array.isArray(rows) ? rows : [];
543
+ return row === void 0 || idOf(row) !== void 0;
544
+ } catch (error) {
545
+ if (error instanceof Error && error.name === "PrismaClientValidationError") {
546
+ return false;
547
+ }
548
+ throw error;
549
+ }
550
+ };
551
+ return async (model) => {
552
+ const key = modelKey(model);
553
+ let answer = known.get(key);
554
+ if (answer === void 0) {
555
+ answer = probe(key);
556
+ known.set(key, answer);
557
+ answer.catch(() => {
558
+ known.delete(key);
559
+ });
560
+ }
561
+ return await answer;
562
+ };
563
+ }
564
+ function createStorage(tracker, [interest, links], delegate) {
512
565
  return Object.freeze({
513
566
  findMany: (model, args = {}) => quietly(() => delegate(modelKey(model)).findMany(args)),
514
567
  count: (model, args = {}) => quietly(() => delegate(modelKey(model)).count(args)),
@@ -516,8 +569,11 @@ function createStorage(tracker, interest, delegate) {
516
569
  countStatements: tracker.countStatements,
517
570
  registerInterest: interest.register,
518
571
  interestOf: interest.of,
572
+ registerLinks: links.register,
573
+ linksOf: links.of,
519
574
  inTransaction: () => tracker.transactionClient() !== void 0 || tracker.inBatch(),
520
575
  nullable: createNullability(delegate),
576
+ trackable: createTrackability(delegate),
521
577
  unitOfWork: tracker.unitOfWork
522
578
  });
523
579
  }
@@ -535,7 +591,14 @@ function trackPrisma(client, options = {}) {
535
591
  const interest = createInterestRegistry(options.interest);
536
592
  let root;
537
593
  const delegate = (model) => delegateOf(tracker.transactionClient() ?? root, model);
538
- const runtime = { tracker, delegate, interestOf: interest.of, untracked: /* @__PURE__ */ new Set() };
594
+ const links = createLinkRegistry();
595
+ const runtime = {
596
+ tracker,
597
+ delegate,
598
+ interestOf: interest.of,
599
+ linksOf: links.of,
600
+ untracked: /* @__PURE__ */ new Set()
601
+ };
539
602
  const hooked = client.$extends({
540
603
  name: "quickdraw-tracking",
541
604
  query: { $allOperations: createHook(runtime) }
@@ -545,7 +608,7 @@ function trackPrisma(client, options = {}) {
545
608
  name: "quickdraw-transactions",
546
609
  client: {
547
610
  $transaction: (arg, txOptions) => transaction(tracker, hooked, arg, txOptions),
548
- [STORAGE_KEY]: createStorage(tracker, interest, delegate)
611
+ [STORAGE_KEY]: createStorage(tracker, [interest, links], delegate)
549
612
  }
550
613
  });
551
614
  return tracked;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/prisma/nested.ts","../../src/prisma/operations.ts","../../src/prisma/trackPrisma.ts"],"sourcesContent":["// Nested writes (RFC 0003 section 5.2): a `data` value that writes a related\n// row, such as `{ labels: { create: [...] } }`, reaches Prisma's query hook\n// only as the parent operation, so the related rows' writes are not tracked.\n// They are found by shape and reported as a development warning; the lint\n// rule `no-nested-write` catches them before they run.\n//\n// The check reads shapes, not the schema, so it also looks at each key's\n// value: a relation operation takes rows (an object or a list), and `delete`\n// and `disconnect` on a to-one relation take `true`. A JSON column's value\n// such as `{ create: true, update: false, delete: false }` is therefore not a\n// nested write; one whose keys hold objects still is.\n\n/** The keys of a relation operation, in the order a warning names them. */\nconst NESTED_KEYS = [\n \"create\",\n \"createMany\",\n \"connect\",\n \"connectOrCreate\",\n \"disconnect\",\n \"set\",\n \"update\",\n \"updateMany\",\n \"upsert\",\n \"delete\",\n \"deleteMany\",\n] as const;\n\n/** Relation operations that also take `true` (a to-one relation); the rest take rows. */\nconst FLAG_KEYS: ReadonlySet<string> = new Set([\"delete\", \"disconnect\"]);\n\nfunction isPlainObject(value: unknown): value is Readonly<Record<string, unknown>> {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n return false;\n }\n const prototype: unknown = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n}\n\nfunction isRows(value: unknown): boolean {\n return Array.isArray(value) || isPlainObject(value);\n}\n\n/**\n * `set` also sets a scalar (`{ title: { set: \"x\" } }`) or a scalar list; on a\n * relation it takes the rows to connect, which are objects.\n */\nfunction isRelationSet(value: unknown): boolean {\n return Array.isArray(value) ? value.some(isPlainObject) : isPlainObject(value);\n}\n\n/**\n * Whether `value[key]` is a relation operation, judged by what the key\n * holds: rows (an object or a list) for every operation, `true` for\n * `delete` and `disconnect`, rows given as objects for `set`.\n */\nfunction writesRelation(value: Readonly<Record<string, unknown>>, key: string): boolean {\n if (!Object.hasOwn(value, key)) {\n return false;\n }\n const operand = value[key];\n if (key === \"set\") {\n return isRelationSet(operand);\n }\n return isRows(operand) || (FLAG_KEYS.has(key) && operand === true);\n}\n\nfunction nestedKey(value: unknown): string | undefined {\n if (!isPlainObject(value)) {\n return undefined;\n }\n return NESTED_KEYS.find((key) => writesRelation(value, key));\n}\n\n/** One nested write found in a write's `data`. */\nexport interface NestedWrite {\n /** The relation field, for example `\"labels\"`. */\n readonly field: string;\n /** The nested operation, for example `\"create\"`. */\n readonly operation: string;\n}\n\n/** The nested writes in `data`, one per relation field that has one. */\nexport function findNestedWrites(data: unknown): NestedWrite[] {\n if (!isPlainObject(data)) {\n return [];\n }\n const found: NestedWrite[] = [];\n for (const [field, value] of Object.entries(data)) {\n const operation = nestedKey(value);\n if (operation !== undefined) {\n found.push({ field, operation });\n }\n }\n return found;\n}\n","// The Prisma operation table (RFC 0003 section 5.2): for each write, how the\n// tracking hook learns the ids it touched, the fields it set, and the\n// interested columns' values before and after, and what that costs.\n//\n// | Operation | Recorded as | Ids and values from | Extra statements |\n// |---------------------|-------------|------------------------------------|------------------------------|\n// | create | create | the result | none |\n// | upsert | create, or | the result; old values from a read | one read, only when `update` |\n// | | update when | that also says the row existed | sets an interested column |\n// | | read found | | |\n// | update | update | the result; old values from a read | one read, only when `data` |\n// | | | | sets an interested column |\n// | delete | delete | the result (the deleted row) | none |\n// | createMany | create | rewritten to createManyAndReturn | none |\n// | updateMany | update | rewritten to updateManyAndReturn | as updateManyAndReturn |\n// | createManyAndReturn | create | the result | none |\n// | updateManyAndReturn | update | the result; old values from a read | one read, only when `data` |\n// | | | | sets an interested column |\n// | deleteMany | delete | a read with the same `where` | one read |\n//\n// `fields` are the keys of `data` (for upsert, of `update` when the row\n// existed, of `create` when it did not, and of both when no read told; such\n// a create is marked `mayHaveExisted`).\n// When a `select` (or `omit`) would hide the `id` or an interested column,\n// the hook adds it and strips it from the result again, so the caller gets\n// exactly what it asked for. Reads go through the open interactive\n// transaction's client, so they see its uncommitted rows. A `deleteMany`\n// with a `limit` deletes exactly the rows its read found.\n//\n// Inside an array-form `$transaction([...])` an operation cannot be replaced\n// by another one, so `createMany` and `updateMany` run as they are there:\n// `updateMany` reads its ids first, and `createMany` is tracked only when\n// every row it creates has an explicit `id`. A batch has no transaction\n// client, so every read made first there (`deleteMany`'s and `updateMany`'s\n// ids, an `update`'s old values) runs on the root client, outside the batch,\n// and misses what the batch's earlier statements changed: a development\n// warning says so once per model and operation.\n//\n// A write that certainly changed nothing records nothing (finding F7.2 of\n// the quickdraw-chat review), so no frame, delta, topic change,\n// `refreshEntry` or `affects` hop follows it. Only the write itself tells:\n//\n// - a write that matched no row (`updateMany`, `updateManyAndReturn` or\n// `deleteMany`; in a batch, an `updateMany` answering count 0);\n// - a `data` (or an upsert's `update`) with nothing to write, `{}` or only\n// `undefined` values, for which Prisma writes nothing at all.\n//\n// A write that sets a column to the value it held is recorded like any\n// other. Comparing the values the hook read before the write with the ones\n// it returned cannot tell: that read is not atomic with the write (in an\n// array-form batch it runs before the whole batch, and elsewhere another\n// write may land between the two), so a real change would be lost and its\n// subscribers left on a value the database no longer holds. rc.5 skipped\n// such writes; the final review of the release candidates showed both.\n//\n// An upsert whose `update` sets nothing changes a row only when it creates\n// one, and nothing it returns tells which it did. Its read replaces it:\n// `findUnique` with its `where` and selection answers for a row that exists\n// (one statement, as the upsert was), and only a missing row runs the upsert\n// after it, recorded as a create (one statement more). In a batch, where no\n// operation can be replaced, it is still recorded as a create that may have\n// found its row.\n\nimport { quietly } from \"../server/devWarnings\";\nimport type { WriteRecord } from \"../server/uow/types\";\nimport type { WriteTracker } from \"../server/uow/unitOfWork\";\nimport { findNestedWrites } from \"./nested\";\n\n/** A Prisma operation's arguments. */\nexport type Args = Readonly<Record<string, unknown>>;\n\n/** A row a Prisma operation returned. */\nexport type Row = Readonly<Record<string, unknown>>;\n\ntype Values = Readonly<Record<string, unknown>>;\n\n/** The model methods the hook's own queries use. */\nexport interface Delegate {\n findMany(args: Args): Promise<Row[]>;\n findUnique(args: Args): Promise<Row | null>;\n count(args: Args): Promise<number>;\n createManyAndReturn(args: Args): Promise<Row[]>;\n updateManyAndReturn(args: Args): Promise<Row[]>;\n}\n\n/** What every operation handler shares. */\nexport interface Runtime {\n readonly tracker: WriteTracker;\n /** The model's delegate on the open interactive transaction's client, or else the root client's. */\n delegate(model: string): Delegate;\n interestOf(model: string): readonly string[];\n /** Models whose writes run untracked: no usable `id` column. */\n readonly untracked: Set<string>;\n}\n\n/** One write operation, as the hook received it. */\nexport interface Operation {\n readonly runtime: Runtime;\n /** The model, named as the client names it: `\"task\"`. */\n readonly model: string;\n /** The Prisma operation: `\"deleteMany\"`. */\n readonly operation: string;\n readonly args: Args;\n readonly query: (args: Args) => Promise<unknown>;\n}\n\n/**\n * Thrown when the hook's own read failed validation before the write ran;\n * the hook then runs the write as the caller wrote it (`runUntracked`).\n */\nexport class Untrackable extends Error {\n override readonly name = \"Untrackable\";\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isValidationError(error: unknown): boolean {\n return error instanceof Error && error.name === \"PrismaClientValidationError\";\n}\n\n/** Stops tracking `model` for the life of the process, and says why once. */\nfunction untrack(op: Operation, reason: string): void {\n if (op.runtime.untracked.has(op.model)) {\n return;\n }\n op.runtime.untracked.add(op.model);\n op.runtime.tracker.logger.warn(\n `Writes to ${op.model} are not tracked: ${reason}. Tracked models need a string id column named \"id\"`,\n { category: \"quickdraw.writes\", model: op.model },\n );\n}\n\n/**\n * Runs the operation as the caller wrote it, after a query the hook built\n * failed validation (a model without an `id` column, or an interested column\n * it does not have). The hook stops tracking the model only when the\n * caller's own query then works: an error in the caller's arguments is\n * theirs, and reaches them.\n */\nexport async function runUntracked(op: Operation, reason: string): Promise<unknown> {\n const result = await op.query(op.args);\n untrack(op, reason);\n return result;\n}\n\nfunction idOf(row: Row): string | undefined {\n const { id } = row;\n if (typeof id === \"string\") {\n return id;\n }\n return typeof id === \"number\" || typeof id === \"bigint\" ? String(id) : undefined;\n}\n\nfunction pick(row: Row, columns: readonly string[]): Values | undefined {\n const present = columns.filter((column) => Object.hasOwn(row, column));\n return present.length === 0\n ? undefined\n : Object.fromEntries(present.map((column) => [column, row[column]]));\n}\n\nfunction keysOf(data: unknown): string[] {\n if (Array.isArray(data)) {\n return [...new Set(data.flatMap((item) => keysOf(item)))];\n }\n return isRecord(data) ? Object.keys(data) : [];\n}\n\nfunction rowsOf(result: unknown): Row[] {\n if (Array.isArray(result)) {\n return result.filter(isRecord);\n }\n return isRecord(result) ? [result] : [];\n}\n\n/** The keys of `data` Prisma writes: those whose value is not `undefined`. */\nfunction writtenKeys(data: unknown): string[] {\n return isRecord(data)\n ? Object.entries(data)\n .filter(([, value]) => value !== undefined)\n .map(([key]) => key)\n : [];\n}\n\n/** True for a `data` Prisma writes nothing for: an object with no key whose value is set. */\nexport function writesNothing(data: unknown): boolean {\n return isRecord(data) && writtenKeys(data).length === 0;\n}\n\n/** Counts a statement the hook runs past itself (`op.query`), and hands it to the development checks. */\nfunction countOwn(op: Operation, operation: string, args: Args): void {\n op.runtime.tracker.countStatement();\n op.runtime.tracker.observe({ model: op.model, operation, args });\n}\n\nfunction warnNested(op: Operation, data: unknown): void {\n for (const { field, operation } of findNestedWrites(data)) {\n op.runtime.tracker.warn({\n kind: \"nested-write\",\n subject: `${op.model}.${field}.${operation}`,\n message: `A nested write (${op.model}.${field}: { ${operation} }) is not tracked; only the ${op.model} row is. Write related rows through their own model`,\n meta: { model: op.model, field, operation },\n });\n }\n}\n\n/** The interested columns `data` sets. */\nfunction touchedInterest(op: Operation, data: unknown): string[] {\n const keys = new Set(keysOf(data));\n return op.runtime.interestOf(op.model).filter((column) => keys.has(column));\n}\n\n/** `args` with `columns` added to its `select`, or no longer omitted, and the columns that were added. */\nfunction widen(args: Args, columns: readonly string[]): { args: Args; added: string[] } {\n const { select, omit } = args;\n if (isRecord(select)) {\n const added = columns.filter((column) => select[column] !== true);\n const widened = { ...select, ...Object.fromEntries(added.map((column) => [column, true])) };\n return { args: added.length === 0 ? args : { ...args, select: widened }, added };\n }\n if (isRecord(omit)) {\n const added = columns.filter((column) => omit[column] === true);\n const widened = { ...omit, ...Object.fromEntries(added.map((column) => [column, false])) };\n return { args: added.length === 0 ? args : { ...args, omit: widened }, added };\n }\n return { args, added: [] };\n}\n\nfunction strip(result: unknown, added: readonly string[]): unknown {\n const without = (row: unknown): unknown =>\n isRecord(row)\n ? Object.fromEntries(Object.entries(row).filter(([key]) => !added.includes(key)))\n : row;\n return Array.isArray(result) ? result.map(without) : without(result);\n}\n\n/**\n * Runs the operation with the `id` and interested columns in its result,\n * and returns the caller's result plus the rows to record. When adding them\n * fails validation (a model without an `id` column), the operation runs as\n * the caller wrote it and its rows are not recorded.\n */\nasync function runWidened(op: Operation): Promise<{ result: unknown; rows: Row[] }> {\n const { args, added } = widen(op.args, [\"id\", ...op.runtime.interestOf(op.model)]);\n if (added.length === 0) {\n const result = await op.query(op.args);\n return { result, rows: rowsOf(result) };\n }\n let result: unknown;\n try {\n result = await op.query(args);\n } catch (error) {\n if (!isValidationError(error)) {\n throw error;\n }\n return { result: await runUntracked(op, \"selecting its id failed\"), rows: [] };\n }\n return { result: strip(result, added), rows: rowsOf(result) };\n}\n\n/**\n * Warns once per model and operation that a read made first inside an\n * array-form `$transaction` runs on the root client: an array-form batch\n * has no transaction client to read through, so the read does not see what\n * the batch's earlier statements changed.\n */\nfunction warnBatchRead(op: Operation): void {\n if (!op.runtime.tracker.inBatch()) {\n return;\n }\n op.runtime.tracker.warn({\n kind: \"batch-read\",\n subject: `${op.model}.${op.operation}`,\n message: `${op.operation} on ${op.model} inside an array-form $transaction reads its rows first on the root client, outside the batch, so rows the batch's earlier statements changed may be missed; use an interactive transaction to read inside it`,\n meta: { model: op.model, operation: op.operation },\n });\n}\n\n/**\n * Reads `columns` of the rows `where` matches, by id, through the transaction\n * when one is open. The read is the tracker's own, not the app's, so the\n * development checks of statements leave it alone.\n */\nasync function readBefore(\n op: Operation,\n where: unknown,\n columns: readonly string[],\n options: { readonly unique: boolean; readonly take?: unknown },\n): Promise<Map<string, Values>> {\n warnBatchRead(op);\n const select = Object.fromEntries([\"id\", ...columns].map((column) => [column, true]));\n const delegate = op.runtime.delegate(op.model);\n let rows: Row[];\n try {\n if (options.unique) {\n const row = await quietly(() => delegate.findUnique({ where, select }));\n rows = row === null ? [] : [row];\n } else {\n rows = await quietly(() =>\n delegate.findMany({\n where,\n select,\n ...(options.take === undefined ? {} : { take: options.take }),\n }),\n );\n }\n } catch (error) {\n if (isValidationError(error)) {\n throw new Untrackable(\"reading its id failed\", { cause: error });\n }\n throw error;\n }\n const before = new Map<string, Values>();\n for (const row of rows) {\n const id = idOf(row);\n if (id !== undefined) {\n before.set(id, pick(row, columns) ?? {});\n }\n }\n return before;\n}\n\nfunction writesOf(\n op: Operation,\n kind: WriteRecord[\"op\"],\n rows: readonly Row[],\n fields: readonly string[],\n before?: ReadonlyMap<string, Values>,\n): WriteRecord[] {\n const interest = op.runtime.interestOf(op.model);\n const writes: WriteRecord[] = [];\n for (const row of rows) {\n const id = idOf(row);\n if (id === undefined) {\n untrack(op, \"its rows have no id\");\n return [];\n }\n const values = pick(row, interest);\n const old = kind === \"delete\" ? values : before?.get(id);\n const after = kind === \"delete\" ? undefined : values;\n writes.push({\n model: op.model,\n id,\n op: kind,\n fields,\n ...(old === undefined || Object.keys(old).length === 0 ? {} : { before: old }),\n ...(after === undefined ? {} : { after }),\n });\n }\n return writes;\n}\n\nfunction record(op: Operation, writes: readonly WriteRecord[]): void {\n op.runtime.tracker.record(writes);\n}\n\nasync function create(op: Operation): Promise<unknown> {\n warnNested(op, op.args.data);\n const { result, rows } = await runWidened(op);\n record(op, writesOf(op, \"create\", rows, keysOf(op.args.data)));\n return result;\n}\n\n/** The selection of a read that returns what `args` (an upsert's) would: its `select`, `include` and `omit`. */\nfunction selectionOf(args: Args): Args {\n return Object.fromEntries(\n [\"select\", \"include\", \"omit\"]\n .filter((key) => args[key] !== undefined)\n .map((key) => [key, args[key]]),\n );\n}\n\n/**\n * An upsert whose `update` sets nothing (see the top of this file): the\n * read that tells whether its row exists takes its place, and answers it\n * when the row is there; only a missing row runs the upsert.\n */\nasync function upsertWithoutUpdate(op: Operation): Promise<unknown> {\n warnNested(op, op.args.create);\n const { args, added } = widen(op.args, [\"id\", ...op.runtime.interestOf(op.model)]);\n let found: Row | null;\n try {\n // Through the hook, which counts it as this call's one statement.\n found = await op.runtime\n .delegate(op.model)\n .findUnique({ where: op.args.where, ...selectionOf(args) });\n } catch (error) {\n if (!isValidationError(error)) {\n throw error;\n }\n // The hook counted the read that failed; the upsert runs in its place.\n return runUntracked(op, \"reading its id failed\");\n }\n if (found !== null) {\n // Prisma writes nothing to a row that exists when `update` sets nothing: no change.\n return strip(found, added);\n }\n countOwn(op, op.operation, op.args);\n const { result, rows } = await runWidened(op);\n // Created, unless another transaction created the row in between: then it may have existed.\n const writes = writesOf(op, \"create\", rows, keysOf(op.args.create));\n record(\n op,\n writes.map((write) => ({ ...write, mayHaveExisted: true as const })),\n );\n return result;\n}\n\nasync function upsert(op: Operation): Promise<unknown> {\n if (writesNothing(op.args.update) && !op.runtime.tracker.inBatch()) {\n return upsertWithoutUpdate(op);\n }\n warnNested(op, op.args.create);\n warnNested(op, op.args.update);\n const touched = touchedInterest(op, op.args.update);\n // Reading the interested columns first also tells whether the row existed.\n const before =\n touched.length === 0\n ? undefined\n : await readBefore(op, op.args.where, touched, { unique: true });\n const { result, rows } = await runWidened(op);\n if (before !== undefined && before.size > 0) {\n record(op, writesOf(op, \"update\", rows, keysOf(op.args.update), before));\n } else if (before === undefined) {\n // Nothing read: the row may have existed, and been updated.\n const writes = writesOf(op, \"create\", rows, keysOf([op.args.create, op.args.update]));\n record(\n op,\n writes.map((write) => ({ ...write, mayHaveExisted: true as const })),\n );\n } else {\n record(op, writesOf(op, \"create\", rows, keysOf(op.args.create)));\n }\n return result;\n}\n\nasync function update(op: Operation): Promise<unknown> {\n if (writesNothing(op.args.data)) {\n // Prisma only reads the row (and answers NOT_FOUND without one): nothing to record.\n return op.query(op.args);\n }\n warnNested(op, op.args.data);\n const touched = touchedInterest(op, op.args.data);\n const before =\n touched.length === 0\n ? undefined\n : await readBefore(op, op.args.where, touched, { unique: true });\n const { result, rows } = await runWidened(op);\n record(op, writesOf(op, \"update\", rows, keysOf(op.args.data), before));\n return result;\n}\n\nasync function remove(op: Operation): Promise<unknown> {\n const { result, rows } = await runWidened(op);\n record(op, writesOf(op, \"delete\", rows, []));\n return result;\n}\n\nasync function createManyAndReturn(op: Operation): Promise<unknown> {\n const { result, rows } = await runWidened(op);\n record(op, writesOf(op, \"create\", rows, keysOf(op.args.data)));\n return result;\n}\n\nasync function updateManyAndReturn(op: Operation): Promise<unknown> {\n if (writesNothing(op.args.data)) {\n // Prisma only reads the rows `where` matches: nothing to record.\n return op.query(op.args);\n }\n const touched = touchedInterest(op, op.args.data);\n const before =\n touched.length === 0\n ? undefined\n : await readBefore(op, op.args.where, touched, { unique: false });\n const { result, rows } = await runWidened(op);\n // Matching no row, it returns none, and records nothing.\n record(op, writesOf(op, \"update\", rows, keysOf(op.args.data), before));\n return result;\n}\n\n/** `createMany` inside an array-form transaction: tracked when every row names its id. */\nasync function createManyInBatch(op: Operation): Promise<unknown> {\n const items = (Array.isArray(op.args.data) ? op.args.data : [op.args.data]).filter(isRecord);\n const result = await op.query(op.args);\n const rows = items.filter((item) => idOf(item) !== undefined);\n if (rows.length === items.length) {\n record(op, writesOf(op, \"create\", rows, keysOf(op.args.data)));\n } else {\n op.runtime.tracker.warn({\n kind: \"batch-create-many\",\n subject: op.model,\n message: `createMany on ${op.model} inside an array-form $transaction cannot report the rows it created, so they are not tracked; give each row an id, or use an interactive transaction`,\n meta: { model: op.model },\n });\n }\n return result;\n}\n\n/**\n * `updateMany` inside an array-form transaction: its ids are read first,\n * before the batch runs. With a `limit`, every row the read found is\n * recorded, which may be more rows than were updated.\n */\nasync function updateManyInBatch(op: Operation): Promise<unknown> {\n if (writesNothing(op.args.data)) {\n return op.query(op.args);\n }\n const before = await readBefore(op, op.args.where, touchedInterest(op, op.args.data), {\n unique: false,\n });\n const result = await op.query(op.args);\n // Only a count comes back: 0 means it updated nothing, whatever the read found.\n if (isRecord(result) && result.count === 0) {\n return result;\n }\n const rows = [...before.keys()].map((id) => ({ id }));\n record(op, writesOf(op, \"update\", rows, keysOf(op.args.data), before));\n return result;\n}\n\n/**\n * `createMany` and `updateMany` outside a batch: the `...AndReturn` form,\n * through the transaction's client when one is open, which the hook then\n * records like any other call of it.\n */\nasync function rewrite(\n op: Operation,\n run: (delegate: Delegate, args: Args) => Promise<Row[]>,\n): Promise<unknown> {\n let rows: Row[];\n try {\n rows = await run(op.runtime.delegate(op.model), { ...op.args, select: { id: true } });\n } catch (error) {\n if (!isValidationError(error)) {\n throw error;\n }\n op.runtime.tracker.countStatement();\n return runUntracked(op, \"selecting its id failed\");\n }\n return { count: rows.length };\n}\n\nfunction createMany(op: Operation): Promise<unknown> {\n if (op.runtime.tracker.inBatch()) {\n return createManyInBatch(op);\n }\n return rewrite(op, (delegate, args) => delegate.createManyAndReturn(args));\n}\n\nfunction updateMany(op: Operation): Promise<unknown> {\n if (op.runtime.tracker.inBatch()) {\n return updateManyInBatch(op);\n }\n if (writesNothing(op.args.data)) {\n // As it is: Prisma writes nothing and answers count 0, which the rewrite would not.\n return op.query(op.args);\n }\n return rewrite(op, (delegate, args) => delegate.updateManyAndReturn(args));\n}\n\nasync function deleteMany(op: Operation): Promise<unknown> {\n const { where, limit } = op.args;\n const interest = op.runtime.interestOf(op.model);\n const before = await readBefore(op, where, interest, { unique: false, take: limit });\n const ids = [...before.keys()];\n // With a limit, which rows go is up to the database: delete the rows read.\n const args =\n limit === undefined\n ? op.args\n : { ...op.args, where: { AND: [where ?? {}, { id: { in: ids } }] } };\n const result = await op.query(args);\n const rows = ids.map((id) => ({ id, ...before.get(id) }));\n record(op, writesOf(op, \"delete\", rows, []));\n return result;\n}\n\n/**\n * The write operations the hook tracks, by Prisma operation name. Every\n * other operation passes through untouched.\n */\nexport const WRITE_OPERATIONS: Readonly<Record<string, (op: Operation) => Promise<unknown>>> =\n Object.freeze({\n create,\n upsert,\n update,\n delete: remove,\n createMany,\n createManyAndReturn,\n updateMany,\n updateManyAndReturn,\n deleteMany,\n });\n\n/**\n * Whether a tracked operation hands its work to another one, which then\n * counts the statement (`createMany` and `updateMany` outside a batch, an\n * `upsert` whose `update` sets nothing outside a batch: its read): the hook\n * counts every other operation itself.\n */\nexport function delegates(runtime: Runtime, operation: string, args: Args | undefined): boolean {\n if (runtime.tracker.inBatch()) {\n return false;\n }\n switch (operation) {\n case \"createMany\":\n return true;\n case \"updateMany\":\n return !writesNothing(args?.data);\n case \"upsert\":\n return writesNothing(args?.update);\n default:\n return false;\n }\n}\n","// `trackPrisma` (RFC 0003 sections 5.2 and 5.4): wraps an app's Prisma\n// client so every write made through it is recorded into the unit of work it\n// runs in. In 4.1 only `BaseService.create/update/delete` were observed\n// (4.1 `src/server/BaseService.ts:769-827`); a raw `prisma.task.update`\n// was invisible, and every live update needed a hand-written emit.\n//\n// Two client extensions, both public Prisma API:\n//\n// 1. a `query` hook on every operation records writes (`operations.ts`) and\n// counts statements;\n// 2. a `client` extension replaces `$transaction`, so writes inside a\n// transaction are buffered and join the unit of work only once it commits.\n// It calls the `$transaction` of the client from step 1, so the\n// transaction's client carries the hook. Transactions are found through\n// that wrapper and `AsyncLocalStorage`, never through Prisma internals.\n//\n// Make it the last extension applied: an extension added after it still\n// runs outside transactions, but not on a transaction's client.\n\nimport { consoleLogger, type Logger } from \"../contract/logger\";\nimport { quietly } from \"../server/devWarnings\";\nimport {\n createInterestRegistry,\n modelKey,\n STORAGE_KEY,\n storageOf,\n type CountArgs,\n type FindManyArgs,\n type StorageAdapter,\n} from \"../server/storage\";\nimport { createWriteTracker, type WriteTracker } from \"../server/uow/unitOfWork\";\nimport {\n delegates,\n runUntracked,\n Untrackable,\n WRITE_OPERATIONS,\n type Args,\n type Delegate,\n type Operation,\n type Runtime,\n} from \"./operations\";\n\n/** Options of {@link trackPrisma}. */\nexport interface TrackPrismaOptions {\n /**\n * Interested columns per model, whose values writes report in `before`\n * and `after`: `{ task: [\"projectId\", \"status\"] }`. The framework adds the\n * columns its collections and access policies need with\n * `storage.registerInterest`; this is for the app's own sinks.\n */\n readonly interest?: Readonly<Record<string, readonly string[]>>;\n /**\n * Receives warnings until a dispatcher is created with this client; then\n * the dispatcher's logger does. Default: the console logger.\n */\n readonly logger?: Logger;\n /**\n * Warn about writes outside any unit of work and about nested writes.\n * Default: on unless `NODE_ENV` is `\"production\"`.\n */\n readonly development?: boolean;\n}\n\n/** The part of a Prisma client `trackPrisma` relies on: client extensions. */\nexport interface PrismaClientLike {\n $extends(extension: never): unknown;\n}\n\n/** The client as `trackPrisma` calls it. */\ninterface ExtendableClient {\n $extends(extension: object): ExtendedClient;\n}\n\ninterface ExtendedClient extends ExtendableClient {\n $transaction(arg: unknown, options?: unknown): Promise<unknown>;\n}\n\n/** What a query extension's `$allOperations` hook receives. */\ninterface QueryHookArgs {\n readonly model?: string;\n readonly operation: string;\n readonly args: Args | undefined;\n readonly query: (args: Args | undefined) => Promise<unknown>;\n}\n\nfunction isClient(value: unknown): value is ExtendableClient {\n return (\n (typeof value === \"object\" || typeof value === \"function\") &&\n value !== null &&\n typeof Reflect.get(value, \"$extends\") === \"function\"\n );\n}\n\nfunction delegateOf(client: unknown, model: string): Delegate {\n const delegate: unknown =\n typeof client === \"object\" && client !== null ? Reflect.get(client, model) : undefined;\n if (typeof delegate !== \"object\" || delegate === null) {\n throw new TypeError(`The tracked Prisma client has no model \"${model}\"`);\n }\n return delegate as Delegate;\n}\n\n/** Counts one statement the hook is about to run, and hands a model's to the development checks. */\nfunction count(\n runtime: Runtime,\n model: string | undefined,\n operation: string,\n args: Args | undefined,\n): void {\n runtime.tracker.countStatement();\n if (model !== undefined) {\n runtime.tracker.observe({ model: modelKey(model), operation, args });\n }\n}\n\nfunction createHook(runtime: Runtime) {\n return async function track({ model, operation, args, query }: QueryHookArgs): Promise<unknown> {\n const handler = model === undefined ? undefined : WRITE_OPERATIONS[operation];\n if (model === undefined || handler === undefined || runtime.untracked.has(modelKey(model))) {\n count(runtime, model, operation, args);\n return query(args);\n }\n if (!delegates(runtime, operation, args)) {\n count(runtime, model, operation, args);\n }\n const op: Operation = { runtime, model: modelKey(model), operation, args: args ?? {}, query };\n try {\n return await handler(op);\n } catch (error) {\n if (error instanceof Untrackable) {\n return runUntracked(op, error.message);\n }\n throw error;\n }\n };\n}\n\n/** `$transaction`, in both forms, inside a transaction frame of the tracker. */\nasync function transaction(\n tracker: WriteTracker,\n hooked: ExtendedClient,\n arg: unknown,\n options: unknown,\n): Promise<unknown> {\n const interactive = typeof arg === \"function\";\n const frame = tracker.openTransaction(interactive ? \"interactive\" : \"batch\");\n try {\n const result = interactive\n ? await hooked.$transaction((client: unknown) => {\n frame.setClient(client);\n return frame.run(() => (arg as (client: unknown) => unknown)(client));\n }, options)\n : await frame.run(() => hooked.$transaction(arg, options));\n frame.commit();\n return result;\n } catch (error) {\n frame.rollback();\n throw error;\n }\n}\n\n/**\n * `StorageAdapter.nullable`: Prisma validates a filter against the schema\n * before sending it, and refuses `{ column: null }` on a required column. The\n * answer is kept for the life of the client: one statement per optional\n * column, none for a required one.\n */\nfunction createNullability(\n delegate: (model: string) => Delegate,\n): (model: string, column: string) => Promise<boolean> {\n const known = new Map<string, boolean>();\n return async (model, column) => {\n const key = `${modelKey(model)}\\u0000${column}`;\n const kept = known.get(key);\n if (kept !== undefined) {\n return kept;\n }\n let nullable = true;\n try {\n await quietly(() => delegate(modelKey(model)).count({ where: { [column]: null } }));\n } catch (error) {\n if (!(error instanceof Error && error.name === \"PrismaClientValidationError\")) {\n throw error;\n }\n nullable = false;\n }\n known.set(key, nullable);\n return nullable;\n };\n}\n\n/**\n * The adapter the framework reads through. Its reads are the framework's own\n * (access checks, subscriptions, flushes, kits), so the development checks\n * of statements leave them alone.\n */\nfunction createStorage(\n tracker: WriteTracker,\n interest: ReturnType<typeof createInterestRegistry>,\n delegate: (model: string) => Delegate,\n): StorageAdapter {\n return Object.freeze({\n findMany: (model: string, args: FindManyArgs = {}) =>\n quietly(() => delegate(modelKey(model)).findMany(args as Args)),\n count: (model: string, args: CountArgs = {}) =>\n quietly(() => delegate(modelKey(model)).count(args as Args)),\n onWrite: tracker.onWrite,\n countStatements: tracker.countStatements,\n registerInterest: interest.register,\n interestOf: interest.of,\n inTransaction: () => tracker.transactionClient() !== undefined || tracker.inBatch(),\n nullable: createNullability(delegate),\n unitOfWork: tracker.unitOfWork,\n });\n}\n\n/**\n * Wraps a Prisma client so the framework sees every write made through it:\n * `create`, `update`, `upsert`, `delete` and their `Many` forms, inside and\n * outside transactions. Pass the result as `db` to `initQuickdraw`'s app and\n * to `createServer`, which find its storage adapter on it (`storageOf`).\n * Nested writes, raw SQL and database cascades are not seen; record those\n * with `ctx.touch`.\n *\n * Prefer interactive transactions (`db.$transaction(async (tx) => ...)`). An\n * array-form `db.$transaction([...])` has no transaction client, so the rows\n * a `deleteMany` or `updateMany` there reads first (and an `update`'s old\n * values) are read on the root client, outside the batch: rows the batch's\n * earlier statements created or changed may be missed, and their frames\n * with them. A development warning names the model and operation once.\n *\n * @example\n * export const db = trackPrisma(new PrismaClient({ adapter }));\n * export const qd = initQuickdraw<{ db: typeof db; principal: AppPrincipal }>();\n * const server = qd.createServer({ app, services, db, auth });\n */\nexport function trackPrisma<C extends PrismaClientLike>(\n client: C,\n options: TrackPrismaOptions = {},\n): C {\n if (!isClient(client)) {\n throw new TypeError(\"trackPrisma: client must be a Prisma client\");\n }\n if (storageOf(client) !== undefined) {\n throw new TypeError(\"trackPrisma: this client is tracked already; pass the untracked client\");\n }\n const tracker = createWriteTracker({\n logger: options.logger ?? consoleLogger,\n development: options.development,\n });\n const interest = createInterestRegistry(options.interest);\n // The client with the hook; the hook's own reads use it outside transactions.\n let root: ExtendedClient | undefined;\n const delegate = (model: string): Delegate =>\n delegateOf(tracker.transactionClient() ?? root, model);\n const runtime: Runtime = { tracker, delegate, interestOf: interest.of, untracked: new Set() };\n const hooked = client.$extends({\n name: \"quickdraw-tracking\",\n query: { $allOperations: createHook(runtime) },\n });\n root = hooked;\n const tracked = hooked.$extends({\n name: \"quickdraw-transactions\",\n client: {\n $transaction: (arg: unknown, txOptions?: unknown) =>\n transaction(tracker, hooked, arg, txOptions),\n [STORAGE_KEY]: createStorage(tracker, interest, delegate),\n },\n });\n return tracked as unknown as C;\n}\n"],"mappings":"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","names":["result"]}
1
+ {"version":3,"sources":["../../src/prisma/links.ts","../../src/prisma/operations.ts","../../src/prisma/trackPrisma.ts"],"sourcesContent":["// The junction links a tracked delete of a via entry model reads first (RFC\n// 0003 sections 5.2 and 7.2; the 5.1 audit's COLL-3). A `via` collection\n// registers its junction as its entries' links (`registerLinks`); a `delete`\n// or `deleteMany` of an entry then reads the junction rows that link the\n// rows it deletes, through the open transaction, and records them in each\n// write's `links`, possibly none, so its flush tells only the scopes a\n// deleted entry was linked to. A junction the client does not have, or a\n// read that fails validation (a column it does not have), leaves the links\n// unknown, and warns once: such a delete's collections are told as for a\n// row nobody can place, and the model stays tracked.\n//\n// The links are read in a statement of their own just before the delete,\n// as `deleteMany` reads its ids: under the database's default isolation\n// (read committed), and always outside an interactive transaction, a link\n// another unit commits in between is removed by the delete's cascade\n// without being read, so the scope it put the entry in keeps the entry\n// until that scope is read again.\n\nimport { quietly } from \"../server/devWarnings\";\nimport type { WriteRecord } from \"../server/uow/types\";\nimport type { Delegate, Row, Runtime } from \"./operations\";\n\n/** Per entry id, per junction model: the junction rows linking it. */\nexport type Links = ReadonlyMap<string, Record<string, Row[]>>;\n\nconst UNREAD = new WeakMap<Runtime, Set<string>>();\n\n/** Says once per model and junction that a delete's links could not be read. */\nfunction warnUnread(runtime: Runtime, model: string, junction: string): void {\n const warned = UNREAD.get(runtime) ?? new Set<string>();\n UNREAD.set(runtime, warned);\n const key = `${model}\\u0000${junction}`;\n if (warned.has(key)) {\n return;\n }\n warned.add(key);\n runtime.tracker.logger.warn(\n `Reading the ${junction} rows that link a deleted ${model} failed, so its deletes tell every subscribed scope of its via lists, as for a row nobody can place`,\n { category: \"quickdraw.writes\", model, junction },\n );\n}\n\n/**\n * The junction rows that link each of `ids`, rows of `model` about to be\n * deleted: per id, per registered junction, possibly none. One statement\n * per junction. `undefined` when `model` has no links or `ids` is empty\n * (nothing is read), or when a read failed validation.\n */\nexport async function readLinks(\n runtime: Runtime,\n model: string,\n ids: readonly string[],\n): Promise<Links | undefined> {\n const links = runtime.linksOf(model);\n if (links.length === 0 || ids.length === 0) {\n return undefined;\n }\n const byId = new Map(\n ids.map((id) => [id, Object.fromEntries(links.map((link) => [link.model, [] as Row[]]))]),\n );\n for (const link of links) {\n const select = Object.fromEntries(\n [link.entry, ...link.columns].map((column) => [column, true]),\n );\n let delegate: Delegate;\n try {\n delegate = runtime.delegate(link.model);\n } catch {\n // A junction model the client does not have.\n warnUnread(runtime, model, link.model);\n return undefined;\n }\n let rows: Row[];\n try {\n rows = await quietly(() =>\n delegate.findMany({ where: { [link.entry]: { in: [...ids] } }, select }),\n );\n } catch (error) {\n if (error instanceof Error && error.name === \"PrismaClientValidationError\") {\n warnUnread(runtime, model, link.model);\n return undefined;\n }\n throw error;\n }\n for (const row of rows) {\n const entry = row[link.entry];\n if (typeof entry === \"string\") {\n byId.get(entry)?.[link.model]?.push(row);\n }\n }\n }\n return byId;\n}\n\n/** `writes`, each with its row's links when they were read. */\nexport function withLinks(writes: readonly WriteRecord[], links: Links | undefined): WriteRecord[] {\n return writes.map((write) => {\n const own = links?.get(write.id);\n return own === undefined ? write : { ...write, links: own };\n });\n}\n","// The Prisma operation table (RFC 0003 section 5.2): for each write, how the\n// tracking hook learns the ids it touched, the fields it set, and the\n// interested columns' values before and after, and what that costs.\n//\n// | Operation | Recorded as | Ids and values from | Extra statements |\n// |---------------------|-------------|------------------------------------|------------------------------|\n// | create | create | the result | none |\n// | upsert | create, or | the result; old values from a read | one read, only when `update` |\n// | | update when | that also says the row existed | sets an interested column or |\n// | | read found | | holds a nested write |\n// | update | update | the result; old values from a read | one read, only when `data` |\n// | | | | sets an interested column or |\n// | | | | holds a nested write |\n// | delete | delete | the result (the deleted row) | none; for a via entry model, |\n// | | | | one read per junction, and |\n// | | | | one for the id when `where` |\n// | | | | names no `id` |\n// | createMany | create | rewritten to createManyAndReturn | none |\n// | updateMany | update | rewritten to updateManyAndReturn | as updateManyAndReturn |\n// | createManyAndReturn | create | the result | none |\n// | updateManyAndReturn | update | the result; old values from a read | one read, only when `data` |\n// | | | | sets an interested column |\n// | deleteMany | delete | a read with the same `where` | one read; for a via entry |\n// | | | | model, one per junction more |\n// | | | | when the read found rows |\n//\n// A `delete` or `deleteMany` of a via entry model (one whose junction a\n// `via` collection registered: `registerLinks`) reads the junction rows that\n// link the rows it deletes first, through the open transaction, and records\n// them in each write's `links` (possibly none), so its flush tells only the\n// scopes the row was linked to (the 5.1 audit's COLL-3; `links.ts`).\n//\n// `fields` are the keys of `data` (for upsert, of `update` when the row\n// existed, of `create` when it did not, and of both when no read told; such\n// a create is marked `mayHaveExisted`). An `update` (or an upsert's\n// `update`) whose `data` holds a nested write may set a foreign key through\n// a relation (`project: { connect }`, `parent: { disconnect: true }`), which\n// its keys do not name: it reads every interested column first and lists\n// them all in `fields`, so an access change it makes is seen (the 5.1\n// audit's DATA-1). The rows the nested write itself creates, changes or\n// deletes are not seen.\n// When a `select` (or `omit`) would hide the `id` or an interested column,\n// the hook adds it and strips it from the result again, so the caller gets\n// exactly what it asked for. Reads go through the open interactive\n// transaction's client, so they see its uncommitted rows. A `deleteMany`\n// with a `limit` deletes exactly the rows its read found.\n//\n// Inside an array-form `$transaction([...])` an operation cannot be replaced\n// by another one, so `createMany` and `updateMany` run as they are there:\n// `updateMany` reads its ids first, and `createMany` is tracked only when\n// every row it creates has an explicit `id`. A batch has no transaction\n// client, so every read made first there (`deleteMany`'s and `updateMany`'s\n// ids, an `update`'s old values) runs on the root client, outside the batch,\n// and misses what the batch's earlier statements changed: a development\n// warning says so once per model and operation.\n//\n// A write that certainly changed nothing records nothing (finding F7.2 of\n// the quickdraw-chat review), so no frame, delta, topic change,\n// `refreshEntry` or `affects` hop follows it. Only the write itself tells:\n//\n// - a write that matched no row (`updateMany`, `updateManyAndReturn` or\n// `deleteMany`; in a batch, an `updateMany` answering count 0);\n// - a `data` (or an upsert's `update`) with nothing to write, `{}` or only\n// `undefined` values, for which Prisma writes nothing at all.\n//\n// A write that sets a column to the value it held is recorded like any\n// other. Comparing the values the hook read before the write with the ones\n// it returned cannot tell: that read is not atomic with the write (in an\n// array-form batch it runs before the whole batch, and elsewhere another\n// write may land between the two), so a real change would be lost and its\n// subscribers left on a value the database no longer holds. rc.5 skipped\n// such writes; the final review of the release candidates showed both.\n//\n// An upsert whose `update` sets nothing changes a row only when it creates\n// one, and nothing it returns tells which it did. Its read replaces it:\n// `findUnique` with its `where` and selection answers for a row that exists\n// (one statement, as the upsert was), and only a missing row runs the upsert\n// after it, recorded as a create (one statement more). In a batch, where no\n// operation can be replaced, it is still recorded as a create that may have\n// found its row.\n\nimport { quietly } from \"../server/devWarnings\";\nimport type { LinkInterest } from \"../server/storage\";\nimport type { WriteRecord } from \"../server/uow/types\";\nimport type { WriteTracker } from \"../server/uow/unitOfWork\";\nimport { readLinks, withLinks, type Links } from \"./links\";\nimport { findNestedWrites } from \"./nested\";\n\n/** A Prisma operation's arguments. */\nexport type Args = Readonly<Record<string, unknown>>;\n\n/** A row a Prisma operation returned. */\nexport type Row = Readonly<Record<string, unknown>>;\n\ntype Values = Readonly<Record<string, unknown>>;\n\n/** The model methods the hook's own queries use. */\nexport interface Delegate {\n findMany(args: Args): Promise<Row[]>;\n findUnique(args: Args): Promise<Row | null>;\n count(args: Args): Promise<number>;\n createManyAndReturn(args: Args): Promise<Row[]>;\n updateManyAndReturn(args: Args): Promise<Row[]>;\n}\n\n/** What every operation handler shares. */\nexport interface Runtime {\n readonly tracker: WriteTracker;\n /** The model's delegate on the open interactive transaction's client, or else the root client's. */\n delegate(model: string): Delegate;\n interestOf(model: string): readonly string[];\n /** The junctions whose links a delete of `model` reads first (`registerLinks`). */\n linksOf(model: string): readonly LinkInterest[];\n /** Models whose writes run untracked: no usable `id` column. */\n readonly untracked: Set<string>;\n}\n\n/** One write operation, as the hook received it. */\nexport interface Operation {\n readonly runtime: Runtime;\n /** The model, named as the client names it: `\"task\"`. */\n readonly model: string;\n /** The Prisma operation: `\"deleteMany\"`. */\n readonly operation: string;\n readonly args: Args;\n readonly query: (args: Args) => Promise<unknown>;\n}\n\n/**\n * Thrown when the hook's own read failed validation before the write ran;\n * the hook then runs the write as the caller wrote it (`runUntracked`).\n */\nexport class Untrackable extends Error {\n override readonly name = \"Untrackable\";\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isValidationError(error: unknown): boolean {\n return error instanceof Error && error.name === \"PrismaClientValidationError\";\n}\n\n/** Stops tracking `model` for the life of the process, and says why once. */\nfunction untrack(op: Operation, reason: string): void {\n if (op.runtime.untracked.has(op.model)) {\n return;\n }\n op.runtime.untracked.add(op.model);\n op.runtime.tracker.logger.warn(\n `Writes to ${op.model} are not tracked: ${reason}. Tracked models need a string id column named \"id\"`,\n { category: \"quickdraw.writes\", model: op.model },\n );\n}\n\n/**\n * Runs the operation as the caller wrote it, after a query the hook built\n * failed validation (a model without an `id` column, or an interested column\n * it does not have). The hook stops tracking the model only when the\n * caller's own query then works: an error in the caller's arguments is\n * theirs, and reaches them.\n */\nexport async function runUntracked(op: Operation, reason: string): Promise<unknown> {\n const result = await op.query(op.args);\n untrack(op, reason);\n return result;\n}\n\n/** A row's id as the tracker keys it: a string, or a number or bigint as a string. */\nexport function idOf(row: Row): string | undefined {\n const { id } = row;\n if (typeof id === \"string\") {\n return id;\n }\n return typeof id === \"number\" || typeof id === \"bigint\" ? String(id) : undefined;\n}\n\nfunction pick(row: Row, columns: readonly string[]): Values | undefined {\n const present = columns.filter((column) => Object.hasOwn(row, column));\n return present.length === 0\n ? undefined\n : Object.fromEntries(present.map((column) => [column, row[column]]));\n}\n\nfunction keysOf(data: unknown): string[] {\n if (Array.isArray(data)) {\n return [...new Set(data.flatMap((item) => keysOf(item)))];\n }\n return isRecord(data) ? Object.keys(data) : [];\n}\n\nfunction rowsOf(result: unknown): Row[] {\n if (Array.isArray(result)) {\n return result.filter(isRecord);\n }\n return isRecord(result) ? [result] : [];\n}\n\n/** The keys of `data` Prisma writes: those whose value is not `undefined`. */\nfunction writtenKeys(data: unknown): string[] {\n return isRecord(data)\n ? Object.entries(data)\n .filter(([, value]) => value !== undefined)\n .map(([key]) => key)\n : [];\n}\n\n/** True for a `data` Prisma writes nothing for: an object with no key whose value is set. */\nexport function writesNothing(data: unknown): boolean {\n return isRecord(data) && writtenKeys(data).length === 0;\n}\n\n/** Counts a statement the hook runs past itself (`op.query`), and hands it to the development checks. */\nfunction countOwn(op: Operation, operation: string, args: Args): void {\n op.runtime.tracker.countStatement();\n op.runtime.tracker.observe({ model: op.model, operation, args });\n}\n\n/**\n * Whether `data` holds a nested write, warning (in development) once per\n * write that the related rows are not tracked. It is found in every\n * environment: such a `data` may set a foreign key the tracker must read.\n */\nfunction warnNested(op: Operation, data: unknown): boolean {\n const nested = findNestedWrites(data);\n for (const { field, operation } of nested) {\n op.runtime.tracker.warn({\n kind: \"nested-write\",\n subject: `${op.model}.${field}.${operation}`,\n message: `A nested write (${op.model}.${field}: { ${operation} }) is not tracked: the related rows it creates, changes or deletes send no frames and revoke nothing. The ${op.model} row is tracked, and an update of it reads its access and scope columns first, so a foreign key a to-one connect or disconnect sets on it is seen. Write related rows through their own model, or set the foreign key column`,\n meta: { model: op.model, field, operation },\n });\n }\n return nested.length > 0;\n}\n\n/** The keys of `data` and `columns`, each once: the fields of a write that holds a nested write. */\nfunction withColumns(data: unknown, columns: readonly string[]): string[] {\n return [...new Set([...keysOf(data), ...columns])];\n}\n\n/** The interested columns `data` sets. */\nfunction touchedInterest(op: Operation, data: unknown): string[] {\n const keys = new Set(keysOf(data));\n return op.runtime.interestOf(op.model).filter((column) => keys.has(column));\n}\n\n/** `args` with `columns` added to its `select`, or no longer omitted, and the columns that were added. */\nfunction widen(args: Args, columns: readonly string[]): { args: Args; added: string[] } {\n const { select, omit } = args;\n if (isRecord(select)) {\n const added = columns.filter((column) => select[column] !== true);\n const widened = { ...select, ...Object.fromEntries(added.map((column) => [column, true])) };\n return { args: added.length === 0 ? args : { ...args, select: widened }, added };\n }\n if (isRecord(omit)) {\n const added = columns.filter((column) => omit[column] === true);\n const widened = { ...omit, ...Object.fromEntries(added.map((column) => [column, false])) };\n return { args: added.length === 0 ? args : { ...args, omit: widened }, added };\n }\n return { args, added: [] };\n}\n\nfunction strip(result: unknown, added: readonly string[]): unknown {\n const without = (row: unknown): unknown =>\n isRecord(row)\n ? Object.fromEntries(Object.entries(row).filter(([key]) => !added.includes(key)))\n : row;\n return Array.isArray(result) ? result.map(without) : without(result);\n}\n\n/**\n * Runs the operation with the `id` and interested columns in its result,\n * and returns the caller's result plus the rows to record. When adding them\n * fails validation (a model without an `id` column), the operation runs as\n * the caller wrote it and its rows are not recorded.\n */\nasync function runWidened(op: Operation): Promise<{ result: unknown; rows: Row[] }> {\n const { args, added } = widen(op.args, [\"id\", ...op.runtime.interestOf(op.model)]);\n if (added.length === 0) {\n const result = await op.query(op.args);\n return { result, rows: rowsOf(result) };\n }\n let result: unknown;\n try {\n result = await op.query(args);\n } catch (error) {\n if (!isValidationError(error)) {\n throw error;\n }\n return { result: await runUntracked(op, \"selecting its id failed\"), rows: [] };\n }\n return { result: strip(result, added), rows: rowsOf(result) };\n}\n\n/**\n * Warns once per model and operation that a read made first inside an\n * array-form `$transaction` runs on the root client: an array-form batch\n * has no transaction client to read through, so the read does not see what\n * the batch's earlier statements changed.\n */\nfunction warnBatchRead(op: Operation): void {\n if (!op.runtime.tracker.inBatch()) {\n return;\n }\n op.runtime.tracker.warn({\n kind: \"batch-read\",\n subject: `${op.model}.${op.operation}`,\n message: `${op.operation} on ${op.model} inside an array-form $transaction reads its rows first on the root client, outside the batch, so rows the batch's earlier statements changed may be missed; use an interactive transaction to read inside it`,\n meta: { model: op.model, operation: op.operation },\n });\n}\n\n/**\n * Reads `columns` of the rows `where` matches, by id, through the transaction\n * when one is open. The read is the tracker's own, not the app's, so the\n * development checks of statements leave it alone.\n */\nasync function readBefore(\n op: Operation,\n where: unknown,\n columns: readonly string[],\n options: { readonly unique: boolean; readonly take?: unknown },\n): Promise<Map<string, Values>> {\n warnBatchRead(op);\n const select = Object.fromEntries([\"id\", ...columns].map((column) => [column, true]));\n const delegate = op.runtime.delegate(op.model);\n let rows: Row[];\n try {\n if (options.unique) {\n const row = await quietly(() => delegate.findUnique({ where, select }));\n rows = row === null ? [] : [row];\n } else {\n rows = await quietly(() =>\n delegate.findMany({\n where,\n select,\n ...(options.take === undefined ? {} : { take: options.take }),\n }),\n );\n }\n } catch (error) {\n if (isValidationError(error)) {\n throw new Untrackable(\"reading its id failed\", { cause: error });\n }\n throw error;\n }\n const before = new Map<string, Values>();\n for (const row of rows) {\n const id = idOf(row);\n if (id !== undefined) {\n before.set(id, pick(row, columns) ?? {});\n }\n }\n return before;\n}\n\nfunction writesOf(\n op: Operation,\n kind: WriteRecord[\"op\"],\n rows: readonly Row[],\n fields: readonly string[],\n before?: ReadonlyMap<string, Values>,\n): WriteRecord[] {\n const interest = op.runtime.interestOf(op.model);\n const writes: WriteRecord[] = [];\n for (const row of rows) {\n const id = idOf(row);\n if (id === undefined) {\n untrack(op, \"its rows have no id\");\n return [];\n }\n const values = pick(row, interest);\n const old = kind === \"delete\" ? values : before?.get(id);\n const after = kind === \"delete\" ? undefined : values;\n writes.push({\n model: op.model,\n id,\n op: kind,\n fields,\n ...(old === undefined || Object.keys(old).length === 0 ? {} : { before: old }),\n ...(after === undefined ? {} : { after }),\n });\n }\n return writes;\n}\n\nfunction record(op: Operation, writes: readonly WriteRecord[]): void {\n op.runtime.tracker.record(writes);\n}\n\nasync function create(op: Operation): Promise<unknown> {\n warnNested(op, op.args.data);\n const { result, rows } = await runWidened(op);\n record(op, writesOf(op, \"create\", rows, keysOf(op.args.data)));\n return result;\n}\n\n/** The selection of a read that returns what `args` (an upsert's) would: its `select`, `include` and `omit`. */\nfunction selectionOf(args: Args): Args {\n return Object.fromEntries(\n [\"select\", \"include\", \"omit\"]\n .filter((key) => args[key] !== undefined)\n .map((key) => [key, args[key]]),\n );\n}\n\n/**\n * An upsert whose `update` sets nothing (see the top of this file): the\n * read that tells whether its row exists takes its place, and answers it\n * when the row is there; only a missing row runs the upsert.\n */\nasync function upsertWithoutUpdate(op: Operation): Promise<unknown> {\n warnNested(op, op.args.create);\n const { args, added } = widen(op.args, [\"id\", ...op.runtime.interestOf(op.model)]);\n let found: Row | null;\n try {\n // Through the hook, which counts it as this call's one statement.\n found = await op.runtime\n .delegate(op.model)\n .findUnique({ where: op.args.where, ...selectionOf(args) });\n } catch (error) {\n if (!isValidationError(error)) {\n throw error;\n }\n // The hook counted the read that failed; the upsert runs in its place.\n return runUntracked(op, \"reading its id failed\");\n }\n if (found !== null) {\n // Prisma writes nothing to a row that exists when `update` sets nothing: no change.\n return strip(found, added);\n }\n countOwn(op, op.operation, op.args);\n const { result, rows } = await runWidened(op);\n // Created, unless another transaction created the row in between: then it may have existed.\n const writes = writesOf(op, \"create\", rows, keysOf(op.args.create));\n record(\n op,\n writes.map((write) => ({ ...write, mayHaveExisted: true as const })),\n );\n return result;\n}\n\nasync function upsert(op: Operation): Promise<unknown> {\n if (writesNothing(op.args.update) && !op.runtime.tracker.inBatch()) {\n return upsertWithoutUpdate(op);\n }\n warnNested(op, op.args.create);\n // A nested write may set a foreign key through a relation: read every interested column.\n const nested = warnNested(op, op.args.update);\n const touched = nested\n ? [...op.runtime.interestOf(op.model)]\n : touchedInterest(op, op.args.update);\n // Reading the interested columns first also tells whether the row existed.\n const before =\n touched.length === 0\n ? undefined\n : await readBefore(op, op.args.where, touched, { unique: true });\n const { result, rows } = await runWidened(op);\n if (before !== undefined && before.size > 0) {\n const fields = nested ? withColumns(op.args.update, touched) : keysOf(op.args.update);\n record(op, writesOf(op, \"update\", rows, fields, before));\n } else if (before === undefined) {\n // Nothing read: the row may have existed, and been updated.\n const writes = writesOf(op, \"create\", rows, keysOf([op.args.create, op.args.update]));\n record(\n op,\n writes.map((write) => ({ ...write, mayHaveExisted: true as const })),\n );\n } else {\n record(op, writesOf(op, \"create\", rows, keysOf(op.args.create)));\n }\n return result;\n}\n\nasync function update(op: Operation): Promise<unknown> {\n if (writesNothing(op.args.data)) {\n // Prisma only reads the row (and answers NOT_FOUND without one): nothing to record.\n return op.query(op.args);\n }\n // A nested write may set a foreign key through a relation: read every interested column.\n const nested = warnNested(op, op.args.data);\n const touched = nested ? [...op.runtime.interestOf(op.model)] : touchedInterest(op, op.args.data);\n const before =\n touched.length === 0\n ? undefined\n : await readBefore(op, op.args.where, touched, { unique: true });\n const { result, rows } = await runWidened(op);\n const fields = nested ? withColumns(op.args.data, touched) : keysOf(op.args.data);\n record(op, writesOf(op, \"update\", rows, fields, before));\n return result;\n}\n\n/** The links of the row a `delete` names (`readLinks`): by its `where.id`, or a read of its id first. */\nasync function linksOfDelete(op: Operation): Promise<Links | undefined> {\n if (op.runtime.linksOf(op.model).length === 0) {\n return undefined;\n }\n warnBatchRead(op);\n const { where } = op.args;\n const ids =\n isRecord(where) && typeof where.id === \"string\"\n ? [where.id]\n : [...(await readBefore(op, where, [], { unique: true })).keys()];\n return await readLinks(op.runtime, op.model, ids);\n}\n\nasync function remove(op: Operation): Promise<unknown> {\n const links = await linksOfDelete(op);\n const { result, rows } = await runWidened(op);\n record(op, withLinks(writesOf(op, \"delete\", rows, []), links));\n return result;\n}\n\nasync function createManyAndReturn(op: Operation): Promise<unknown> {\n const { result, rows } = await runWidened(op);\n record(op, writesOf(op, \"create\", rows, keysOf(op.args.data)));\n return result;\n}\n\nasync function updateManyAndReturn(op: Operation): Promise<unknown> {\n if (writesNothing(op.args.data)) {\n // Prisma only reads the rows `where` matches: nothing to record.\n return op.query(op.args);\n }\n const touched = touchedInterest(op, op.args.data);\n const before =\n touched.length === 0\n ? undefined\n : await readBefore(op, op.args.where, touched, { unique: false });\n const { result, rows } = await runWidened(op);\n // Matching no row, it returns none, and records nothing.\n record(op, writesOf(op, \"update\", rows, keysOf(op.args.data), before));\n return result;\n}\n\n/** `createMany` inside an array-form transaction: tracked when every row names its id. */\nasync function createManyInBatch(op: Operation): Promise<unknown> {\n const items = (Array.isArray(op.args.data) ? op.args.data : [op.args.data]).filter(isRecord);\n const result = await op.query(op.args);\n const rows = items.filter((item) => idOf(item) !== undefined);\n if (rows.length === items.length) {\n record(op, writesOf(op, \"create\", rows, keysOf(op.args.data)));\n } else {\n op.runtime.tracker.warn({\n kind: \"batch-create-many\",\n subject: op.model,\n message: `createMany on ${op.model} inside an array-form $transaction cannot report the rows it created, so they are not tracked; give each row an id, or use an interactive transaction`,\n meta: { model: op.model },\n });\n }\n return result;\n}\n\n/**\n * `updateMany` inside an array-form transaction: its ids are read first,\n * before the batch runs. With a `limit`, every row the read found is\n * recorded, which may be more rows than were updated.\n */\nasync function updateManyInBatch(op: Operation): Promise<unknown> {\n if (writesNothing(op.args.data)) {\n return op.query(op.args);\n }\n const before = await readBefore(op, op.args.where, touchedInterest(op, op.args.data), {\n unique: false,\n });\n const result = await op.query(op.args);\n // Only a count comes back: 0 means it updated nothing, whatever the read found.\n if (isRecord(result) && result.count === 0) {\n return result;\n }\n const rows = [...before.keys()].map((id) => ({ id }));\n record(op, writesOf(op, \"update\", rows, keysOf(op.args.data), before));\n return result;\n}\n\n/**\n * `createMany` and `updateMany` outside a batch: the `...AndReturn` form,\n * through the transaction's client when one is open, which the hook then\n * records like any other call of it.\n */\nasync function rewrite(\n op: Operation,\n run: (delegate: Delegate, args: Args) => Promise<Row[]>,\n): Promise<unknown> {\n let rows: Row[];\n try {\n rows = await run(op.runtime.delegate(op.model), { ...op.args, select: { id: true } });\n } catch (error) {\n if (!isValidationError(error)) {\n throw error;\n }\n op.runtime.tracker.countStatement();\n return runUntracked(op, \"selecting its id failed\");\n }\n return { count: rows.length };\n}\n\nfunction createMany(op: Operation): Promise<unknown> {\n if (op.runtime.tracker.inBatch()) {\n return createManyInBatch(op);\n }\n return rewrite(op, (delegate, args) => delegate.createManyAndReturn(args));\n}\n\nfunction updateMany(op: Operation): Promise<unknown> {\n if (op.runtime.tracker.inBatch()) {\n return updateManyInBatch(op);\n }\n if (writesNothing(op.args.data)) {\n // As it is: Prisma writes nothing and answers count 0, which the rewrite would not.\n return op.query(op.args);\n }\n return rewrite(op, (delegate, args) => delegate.updateManyAndReturn(args));\n}\n\nasync function deleteMany(op: Operation): Promise<unknown> {\n const { where, limit } = op.args;\n const interest = op.runtime.interestOf(op.model);\n const before = await readBefore(op, where, interest, { unique: false, take: limit });\n const ids = [...before.keys()];\n const links = await readLinks(op.runtime, op.model, ids);\n // With a limit, which rows go is up to the database: delete the rows read.\n const args =\n limit === undefined\n ? op.args\n : { ...op.args, where: { AND: [where ?? {}, { id: { in: ids } }] } };\n const result = await op.query(args);\n const rows = ids.map((id) => ({ id, ...before.get(id) }));\n record(op, withLinks(writesOf(op, \"delete\", rows, []), links));\n return result;\n}\n\n/**\n * The write operations the hook tracks, by Prisma operation name. Every\n * other operation passes through untouched.\n */\nexport const WRITE_OPERATIONS: Readonly<Record<string, (op: Operation) => Promise<unknown>>> =\n Object.freeze({\n create,\n upsert,\n update,\n delete: remove,\n createMany,\n createManyAndReturn,\n updateMany,\n updateManyAndReturn,\n deleteMany,\n });\n\n/**\n * Whether a tracked operation hands its work to another one, which then\n * counts the statement (`createMany` and `updateMany` outside a batch, an\n * `upsert` whose `update` sets nothing outside a batch: its read): the hook\n * counts every other operation itself.\n */\nexport function delegates(runtime: Runtime, operation: string, args: Args | undefined): boolean {\n if (runtime.tracker.inBatch()) {\n return false;\n }\n switch (operation) {\n case \"createMany\":\n return true;\n case \"updateMany\":\n return !writesNothing(args?.data);\n case \"upsert\":\n return writesNothing(args?.update);\n default:\n return false;\n }\n}\n","// `trackPrisma` (RFC 0003 sections 5.2 and 5.4): wraps an app's Prisma\n// client so every write made through it is recorded into the unit of work it\n// runs in. In 4.1 only `BaseService.create/update/delete` were observed\n// (4.1 `src/server/BaseService.ts:769-827`); a raw `prisma.task.update`\n// was invisible, and every live update needed a hand-written emit.\n//\n// Two client extensions, both public Prisma API:\n//\n// 1. a `query` hook on every operation records writes (`operations.ts`) and\n// counts statements;\n// 2. a `client` extension replaces `$transaction`, so writes inside a\n// transaction are buffered and join the unit of work only once it commits.\n// It calls the `$transaction` of the client from step 1, so the\n// transaction's client carries the hook. Transactions are found through\n// that wrapper and `AsyncLocalStorage`, never through Prisma internals.\n//\n// Make it the last extension applied: an extension added after it still\n// runs outside transactions, but not on a transaction's client.\n\nimport { consoleLogger, type Logger } from \"../contract/logger\";\nimport { quietly } from \"../server/devWarnings\";\nimport {\n createInterestRegistry,\n createLinkRegistry,\n modelKey,\n STORAGE_KEY,\n storageOf,\n type CountArgs,\n type FindManyArgs,\n type StorageAdapter,\n} from \"../server/storage\";\nimport { createWriteTracker, type WriteTracker } from \"../server/uow/unitOfWork\";\nimport {\n delegates,\n idOf,\n runUntracked,\n Untrackable,\n WRITE_OPERATIONS,\n type Args,\n type Delegate,\n type Operation,\n type Runtime,\n} from \"./operations\";\n\n/** Options of {@link trackPrisma}. */\nexport interface TrackPrismaOptions {\n /**\n * Interested columns per model, whose values writes report in `before`\n * and `after`: `{ task: [\"projectId\", \"status\"] }`. The framework adds the\n * columns its collections and access policies need with\n * `storage.registerInterest`; this is for the app's own sinks.\n */\n readonly interest?: Readonly<Record<string, readonly string[]>>;\n /**\n * Receives warnings until a dispatcher is created with this client; then\n * the dispatcher's logger does. Default: the console logger.\n */\n readonly logger?: Logger;\n /**\n * Warn about writes outside any unit of work and about nested writes.\n * Default: on unless `NODE_ENV` is `\"production\"`.\n */\n readonly development?: boolean;\n}\n\n/** The part of a Prisma client `trackPrisma` relies on: client extensions. */\nexport interface PrismaClientLike {\n $extends(extension: never): unknown;\n}\n\n/** The client as `trackPrisma` calls it. */\ninterface ExtendableClient {\n $extends(extension: object): ExtendedClient;\n}\n\ninterface ExtendedClient extends ExtendableClient {\n $transaction(arg: unknown, options?: unknown): Promise<unknown>;\n}\n\n/** What a query extension's `$allOperations` hook receives. */\ninterface QueryHookArgs {\n readonly model?: string;\n readonly operation: string;\n readonly args: Args | undefined;\n readonly query: (args: Args | undefined) => Promise<unknown>;\n}\n\nfunction isClient(value: unknown): value is ExtendableClient {\n return (\n (typeof value === \"object\" || typeof value === \"function\") &&\n value !== null &&\n typeof Reflect.get(value, \"$extends\") === \"function\"\n );\n}\n\nfunction delegateOf(client: unknown, model: string): Delegate {\n const delegate: unknown =\n typeof client === \"object\" && client !== null ? Reflect.get(client, model) : undefined;\n if (typeof delegate !== \"object\" || delegate === null) {\n throw new TypeError(`The tracked Prisma client has no model \"${model}\"`);\n }\n return delegate as Delegate;\n}\n\n/** Counts one statement the hook is about to run, and hands a model's to the development checks. */\nfunction count(\n runtime: Runtime,\n model: string | undefined,\n operation: string,\n args: Args | undefined,\n): void {\n runtime.tracker.countStatement();\n if (model !== undefined) {\n runtime.tracker.observe({ model: modelKey(model), operation, args });\n }\n}\n\nfunction createHook(runtime: Runtime) {\n return async function track({ model, operation, args, query }: QueryHookArgs): Promise<unknown> {\n const handler = model === undefined ? undefined : WRITE_OPERATIONS[operation];\n if (model === undefined || handler === undefined || runtime.untracked.has(modelKey(model))) {\n count(runtime, model, operation, args);\n return query(args);\n }\n if (!delegates(runtime, operation, args)) {\n count(runtime, model, operation, args);\n }\n const op: Operation = { runtime, model: modelKey(model), operation, args: args ?? {}, query };\n try {\n return await handler(op);\n } catch (error) {\n if (error instanceof Untrackable) {\n return runUntracked(op, error.message);\n }\n throw error;\n }\n };\n}\n\n/** `$transaction`, in both forms, inside a transaction frame of the tracker. */\nasync function transaction(\n tracker: WriteTracker,\n hooked: ExtendedClient,\n arg: unknown,\n options: unknown,\n): Promise<unknown> {\n const interactive = typeof arg === \"function\";\n const frame = tracker.openTransaction(interactive ? \"interactive\" : \"batch\");\n try {\n const result = interactive\n ? await hooked.$transaction((client: unknown) => {\n frame.setClient(client);\n return frame.run(() => (arg as (client: unknown) => unknown)(client));\n }, options)\n : await frame.run(() => hooked.$transaction(arg, options));\n frame.commit();\n return result;\n } catch (error) {\n frame.rollback();\n throw error;\n }\n}\n\n/**\n * `StorageAdapter.nullable`: Prisma validates a filter against the schema\n * before sending it, and refuses `{ column: null }` on a required column. The\n * answer is kept for the life of the client: one statement per optional\n * column, none for a required one.\n */\nfunction createNullability(\n delegate: (model: string) => Delegate,\n): (model: string, column: string) => Promise<boolean> {\n const known = new Map<string, boolean>();\n return async (model, column) => {\n const key = `${modelKey(model)}\\u0000${column}`;\n const kept = known.get(key);\n if (kept !== undefined) {\n return kept;\n }\n let nullable = true;\n try {\n await quietly(() => delegate(modelKey(model)).count({ where: { [column]: null } }));\n } catch (error) {\n if (!(error instanceof Error && error.name === \"PrismaClientValidationError\")) {\n throw error;\n }\n nullable = false;\n }\n known.set(key, nullable);\n return nullable;\n };\n}\n\n/**\n * `StorageAdapter.trackable`: whether the tracker can key `model`'s writes,\n * that is whether its rows have an `id`. One read of one row's id per model,\n * kept for the life of the client: Prisma refuses the select of a model\n * without an `id` column (a composite `@@id`). Any other failure (the\n * database down) is thrown, and asked again next time.\n */\nfunction createTrackability(\n delegate: (model: string) => Delegate,\n): (model: string) => Promise<boolean> {\n const known = new Map<string, Promise<boolean>>();\n const probe = async (key: string): Promise<boolean> => {\n try {\n const rows = await quietly(() => delegate(key).findMany({ select: { id: true }, take: 1 }));\n const [row] = Array.isArray(rows) ? (rows as Readonly<Record<string, unknown>>[]) : [];\n return row === undefined || idOf(row) !== undefined;\n } catch (error) {\n if (error instanceof Error && error.name === \"PrismaClientValidationError\") {\n return false;\n }\n throw error;\n }\n };\n return async (model) => {\n const key = modelKey(model);\n let answer = known.get(key);\n if (answer === undefined) {\n answer = probe(key);\n known.set(key, answer);\n answer.catch(() => {\n known.delete(key);\n });\n }\n return await answer;\n };\n}\n\n/**\n * The adapter the framework reads through. Its reads are the framework's own\n * (access checks, subscriptions, flushes, kits), so the development checks\n * of statements leave them alone.\n */\nfunction createStorage(\n tracker: WriteTracker,\n [interest, links]: readonly [\n ReturnType<typeof createInterestRegistry>,\n ReturnType<typeof createLinkRegistry>,\n ],\n delegate: (model: string) => Delegate,\n): StorageAdapter {\n return Object.freeze({\n findMany: (model: string, args: FindManyArgs = {}) =>\n quietly(() => delegate(modelKey(model)).findMany(args as Args)),\n count: (model: string, args: CountArgs = {}) =>\n quietly(() => delegate(modelKey(model)).count(args as Args)),\n onWrite: tracker.onWrite,\n countStatements: tracker.countStatements,\n registerInterest: interest.register,\n interestOf: interest.of,\n registerLinks: links.register,\n linksOf: links.of,\n inTransaction: () => tracker.transactionClient() !== undefined || tracker.inBatch(),\n nullable: createNullability(delegate),\n trackable: createTrackability(delegate),\n unitOfWork: tracker.unitOfWork,\n });\n}\n\n/**\n * Wraps a Prisma client so the framework sees every write made through it:\n * `create`, `update`, `upsert`, `delete` and their `Many` forms, inside and\n * outside transactions. Pass the result as `db` to `initQuickdraw`'s app and\n * to `createServer`, which find its storage adapter on it (`storageOf`).\n * Nested writes, raw SQL and database cascades are not seen; record those\n * with `ctx.touch`.\n *\n * Prefer interactive transactions (`db.$transaction(async (tx) => ...)`). An\n * array-form `db.$transaction([...])` has no transaction client, so the rows\n * a `deleteMany` or `updateMany` there reads first (and an `update`'s old\n * values) are read on the root client, outside the batch: rows the batch's\n * earlier statements created or changed may be missed, and their frames\n * with them. A development warning names the model and operation once.\n *\n * @example\n * export const db = trackPrisma(new PrismaClient({ adapter }));\n * export const qd = initQuickdraw<{ db: typeof db; principal: AppPrincipal }>();\n * const server = qd.createServer({ app, services, db, auth });\n */\nexport function trackPrisma<C extends PrismaClientLike>(\n client: C,\n options: TrackPrismaOptions = {},\n): C {\n if (!isClient(client)) {\n throw new TypeError(\"trackPrisma: client must be a Prisma client\");\n }\n if (storageOf(client) !== undefined) {\n throw new TypeError(\"trackPrisma: this client is tracked already; pass the untracked client\");\n }\n const tracker = createWriteTracker({\n logger: options.logger ?? consoleLogger,\n development: options.development,\n });\n const interest = createInterestRegistry(options.interest);\n // The client with the hook; the hook's own reads use it outside transactions.\n let root: ExtendedClient | undefined;\n const delegate = (model: string): Delegate =>\n delegateOf(tracker.transactionClient() ?? root, model);\n const links = createLinkRegistry();\n const runtime: Runtime = {\n tracker,\n delegate,\n interestOf: interest.of,\n linksOf: links.of,\n untracked: new Set(),\n };\n const hooked = client.$extends({\n name: \"quickdraw-tracking\",\n query: { $allOperations: createHook(runtime) },\n });\n root = hooked;\n const tracked = hooked.$extends({\n name: \"quickdraw-transactions\",\n client: {\n $transaction: (arg: unknown, txOptions?: unknown) =>\n transaction(tracker, hooked, arg, txOptions),\n [STORAGE_KEY]: createStorage(tracker, [interest, links], delegate),\n },\n });\n return tracked as unknown as C;\n}\n"],"mappings":"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","names":["result"]}
@@ -7,7 +7,7 @@ import {
7
7
  createPublicApiLimiter,
8
8
  createWebhookLimiter,
9
9
  stripIp
10
- } from "./chunk-TBMKJ26R.js";
10
+ } from "./chunk-NW6U45HX.js";
11
11
  export {
12
12
  bearerOrIp,
13
13
  createAuthLimiter,
@@ -18,4 +18,4 @@ export {
18
18
  createWebhookLimiter,
19
19
  stripIp
20
20
  };
21
- //# sourceMappingURL=rateLimit-ZMIZJUZF.js.map
21
+ //# sourceMappingURL=rateLimit-5RKBFLUR.js.map