@vibeorm/runtime 2.4.1 → 2.6.0

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 (44) hide show
  1. package/README.md +7 -0
  2. package/dist/adapter-kit/index.d.ts +2 -1
  3. package/dist/adapter-kit/index.d.ts.map +1 -1
  4. package/dist/adapter-kit/index.js +53 -3
  5. package/dist/adapter-kit/index.js.map +5 -4
  6. package/dist/adapter-kit/row-changes.d.ts +29 -0
  7. package/dist/adapter-kit/row-changes.d.ts.map +1 -0
  8. package/dist/adapter-kit/savepoint-gate.d.ts +8 -0
  9. package/dist/adapter-kit/savepoint-gate.d.ts.map +1 -1
  10. package/dist/adapter.d.ts +14 -0
  11. package/dist/adapter.d.ts.map +1 -1
  12. package/dist/advisory-key.d.ts +10 -0
  13. package/dist/advisory-key.d.ts.map +1 -0
  14. package/dist/advisory-lock.d.ts +3 -3
  15. package/dist/client.d.ts +3 -0
  16. package/dist/client.d.ts.map +1 -1
  17. package/dist/codecs.d.ts.map +1 -1
  18. package/dist/database-module.d.ts.map +1 -1
  19. package/dist/find-page.d.ts +35 -0
  20. package/dist/find-page.d.ts.map +1 -0
  21. package/dist/index.d.ts +6 -3
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +544 -276
  24. package/dist/index.js.map +26 -22
  25. package/dist/keyset-iterator.d.ts.map +1 -1
  26. package/dist/keyset-projection.d.ts +12 -0
  27. package/dist/keyset-projection.d.ts.map +1 -0
  28. package/dist/keyset.d.ts +7 -6
  29. package/dist/keyset.d.ts.map +1 -1
  30. package/dist/model-meta.d.ts +5 -1
  31. package/dist/model-meta.d.ts.map +1 -1
  32. package/dist/policy.d.ts.map +1 -1
  33. package/dist/query-builder.d.ts +8 -1
  34. package/dist/query-builder.d.ts.map +1 -1
  35. package/dist/read-only.d.ts +17 -1
  36. package/dist/read-only.d.ts.map +1 -1
  37. package/dist/relation-plan.d.ts +1 -0
  38. package/dist/relation-plan.d.ts.map +1 -1
  39. package/dist/render-cache.d.ts.map +1 -1
  40. package/dist/rls-readiness.d.ts.map +1 -1
  41. package/dist/scoped.d.ts.map +1 -1
  42. package/dist/transaction-row-changes.d.ts +28 -0
  43. package/dist/transaction-row-changes.d.ts.map +1 -0
  44. package/package.json +6 -3
package/dist/index.js CHANGED
@@ -30,7 +30,7 @@ function createSqlModel(params) {
30
30
  if (model === undefined)
31
31
  throw new VibeError({ code: "VIBE_VALIDATION", message: "Unknown SQL model" });
32
32
  const tableName = model.dbName ?? model.name;
33
- const table = sql.ident({ parts: [tableName] });
33
+ const table = sql.ident({ parts: model.namespace === undefined ? [tableName] : [model.namespace, tableName] });
34
34
  const fields = Object.fromEntries(model.fields.filter((field) => field.isUnsupported !== true).map((field) => {
35
35
  let decoder;
36
36
  if (isEnumType(field.type)) {
@@ -199,8 +199,62 @@ function statementFor(params) {
199
199
  key: params.key
200
200
  };
201
201
  }
202
+ // packages/runtime/src/advisory-key.ts
203
+ import { createHash } from "crypto";
204
+ import { VibeError as VibeError5 } from "@vibeorm/schema";
205
+ function advisoryKeyOf(params) {
206
+ const { text } = params;
207
+ const refuse = () => new VibeError5({
208
+ code: "VIBE_VALIDATION",
209
+ message: "advisoryKeyOf text must be a well-formed UTF-16 string",
210
+ meta: { reason: "advisory-key-text" }
211
+ });
212
+ if (typeof text !== "string")
213
+ throw refuse();
214
+ for (let index = 0;index < text.length; index++) {
215
+ const unit = text.charCodeAt(index);
216
+ if (unit >= 55296 && unit <= 56319) {
217
+ const next = text.charCodeAt(index + 1);
218
+ if (!(next >= 56320 && next <= 57343))
219
+ throw refuse();
220
+ index++;
221
+ } else if (unit >= 56320 && unit <= 57343) {
222
+ throw refuse();
223
+ }
224
+ }
225
+ return createHash("sha256").update(text, "utf8").digest().readBigInt64BE(0);
226
+ }
227
+ // packages/runtime/src/transaction-row-changes.ts
228
+ import { VibeError as VibeError6 } from "@vibeorm/schema";
229
+ var observations = new WeakMap;
230
+ function registerTransactionObservation(params) {
231
+ observations.set(params.db, params.observation);
232
+ }
233
+ function inheritTransactionObservation(params) {
234
+ const observation = observations.get(params.from);
235
+ if (observation !== undefined)
236
+ observations.set(params.to, observation);
237
+ }
238
+ function transactionRowChanges(params) {
239
+ const observation = observations.get(params.db);
240
+ if (observation === undefined)
241
+ throw new VibeError6({
242
+ code: "VIBE_CONFIG",
243
+ message: "transactionRowChanges requires a registered handle from this VibeORM runtime installation",
244
+ meta: { reason: "transaction-observation-handle" }
245
+ });
246
+ if (!observation.inTransaction)
247
+ throw new VibeError6({
248
+ code: "VIBE_TRANSACTION",
249
+ message: "transactionRowChanges requires an active transaction handle",
250
+ meta: { reason: "transaction-observation-context" }
251
+ });
252
+ observation.assertActive();
253
+ const count = observation.read();
254
+ return typeof count === "number" && Number.isSafeInteger(count) && count >= 0 ? count : "unknown";
255
+ }
202
256
  // packages/runtime/src/model-meta.ts
203
- import { VibeError as VibeError5, enumStorageOf, isEnumType as isEnumType2, validateComputedConfig } from "@vibeorm/schema";
257
+ import { VibeError as VibeError7, enumStorageOf, isEnumType as isEnumType2, validateComputedConfig } from "@vibeorm/schema";
204
258
  import { enumMembershipCodec } from "@vibeorm/sql";
205
259
  function toClientName(params) {
206
260
  const { name } = params;
@@ -308,6 +362,7 @@ function buildFieldMeta(params) {
308
362
  type: field.type,
309
363
  scalarType: enumName === null ? field.type : null,
310
364
  enumName,
365
+ ...enumStorage !== "database" || enumDef === undefined || enumDef.namespace === undefined && (!isEnumType2(field.type) || field.type.namespace === undefined) ? {} : { enumSqlName: { namespace: enumDef.namespace ?? (isEnumType2(field.type) ? field.type.namespace : undefined) ?? "public", name: enumDef.dbName ?? enumDef.name } },
311
366
  enumStorage,
312
367
  enumCodec: enumStorage === "string" && enumDef !== undefined ? enumMembershipCodec({ model, field: field.name, enum: enumDef.name, members: enumDef.values }) : null,
313
368
  isList: field.isList,
@@ -329,7 +384,7 @@ function buildModelMeta(params) {
329
384
  for (const name of model.primaryKey.fields) {
330
385
  const field = fieldByName.get(name);
331
386
  if (field === undefined) {
332
- throw new VibeError5({
387
+ throw new VibeError7({
333
388
  code: "VIBE_SCHEMA_INVALID",
334
389
  message: `model "${model.name}" declares composite primary-key field "${name}", which does not exist`,
335
390
  meta: { model: model.name, field: name }
@@ -396,6 +451,7 @@ function buildModelMeta(params) {
396
451
  name: model.name,
397
452
  clientName: toClientName({ name: model.name }),
398
453
  tableName: model.dbName ?? model.name,
454
+ ...model.namespace === undefined ? {} : { namespace: model.namespace },
399
455
  fields,
400
456
  fieldByName,
401
457
  fieldByColumn,
@@ -435,7 +491,7 @@ function getModelMeta(params) {
435
491
  const { meta, model } = params;
436
492
  const found = meta.modelByName.get(model);
437
493
  if (found === undefined) {
438
- throw new VibeError5({
494
+ throw new VibeError7({
439
495
  code: "VIBE_VALIDATION",
440
496
  message: `unknown model "${model}"`,
441
497
  meta: { model, known: [...new Set(meta.models.map((entry) => entry.name))] }
@@ -448,20 +504,20 @@ function getFieldMeta(params) {
448
504
  const found = model.fieldByName.get(field);
449
505
  if (found === undefined) {
450
506
  if (model.computed !== null && model.computed.has(field)) {
451
- throw new VibeError5({
507
+ throw new VibeError7({
452
508
  code: "VIBE_VALIDATION",
453
509
  message: `"${field}" on model "${model.name}" is a computed field \u2014 computed fields appear in results (select/omit) only, not in ${context}`,
454
510
  meta: { model: model.name, field, context, computed: true }
455
511
  });
456
512
  }
457
513
  if (model.relationByName.has(field)) {
458
- throw new VibeError5({
514
+ throw new VibeError7({
459
515
  code: "VIBE_VALIDATION",
460
516
  message: `"${field}" on model "${model.name}" is a relation \u2014 not valid in ${context} here (relation writes use nested-write verbs, relation reads use select/include)`,
461
517
  meta: { model: model.name, field, context }
462
518
  });
463
519
  }
464
- throw new VibeError5({
520
+ throw new VibeError7({
465
521
  code: "VIBE_VALIDATION",
466
522
  message: `unknown field "${field}" on model "${model.name}" in ${context}`,
467
523
  meta: { model: model.name, field, context }
@@ -471,8 +527,8 @@ function getFieldMeta(params) {
471
527
  }
472
528
  // packages/runtime/src/codecs.ts
473
529
  import { JSON_TRANSPORT, projectionOutputName, parsePgArrayLiteral, toPgArrayLiteral } from "@vibeorm/sql";
474
- import { VibeError as VibeError6, isEnumType as isEnumType3 } from "@vibeorm/schema";
475
- import { DIALECT_CODECS, decodeIsNoop } from "@vibeorm/sql";
530
+ import { VibeError as VibeError8, isEnumType as isEnumType3 } from "@vibeorm/schema";
531
+ import { DIALECT_CODECS, decodeIsNoop, nativeEnumArrayParameter } from "@vibeorm/sql";
476
532
  import {
477
533
  DIALECT_CODECS as DIALECT_CODECS2,
478
534
  MYSQL_CODECS,
@@ -500,7 +556,10 @@ function encodeValue(params) {
500
556
  const codec = fieldCodec({ dialect, field });
501
557
  if (field.isList && Array.isArray(value)) {
502
558
  const elements = value.map((element) => element === null || element === undefined ? element : codec.encode(element));
503
- return isPostgresEnumList({ dialect, field }) ? toPgArrayLiteral({ values: elements }) : elements;
559
+ if (!isPostgresEnumList({ dialect, field }))
560
+ return elements;
561
+ const literal = toPgArrayLiteral({ values: elements });
562
+ return field.enumSqlName === undefined ? literal : nativeEnumArrayParameter({ value: literal, type: field.enumSqlName });
504
563
  }
505
564
  return codec.encode(value);
506
565
  }
@@ -533,7 +592,7 @@ function validateAtomicOperand(params) {
533
592
  } else if (typeof value === "number" && Number.isFinite(value)) {
534
593
  return value;
535
594
  }
536
- throw new VibeError6({
595
+ throw new VibeError8({
537
596
  code: "VIBE_VALIDATION",
538
597
  message: `Invalid arithmetic operand for ${field.scalarType} field "${field.name}"`,
539
598
  meta: { field: field.name, value }
@@ -542,7 +601,7 @@ function validateAtomicOperand(params) {
542
601
  function toRealNumber(params) {
543
602
  const { field, value } = params;
544
603
  const refuse = () => {
545
- throw new VibeError6({
604
+ throw new VibeError8({
546
605
  code: "VIBE_VALIDATION",
547
606
  message: `"${String(value)}" is not a numeric value for the Decimal field "${field.name}"`,
548
607
  meta: { field: field.name, value }
@@ -782,7 +841,7 @@ function positionalMaterializer(params) {
782
841
  const output = projectionOutputName({ column });
783
842
  const entry = plan.byColumn.get(output);
784
843
  if (entry === undefined)
785
- throw new VibeError6({ code: "VIBE_INTERNAL", message: "positional projection has no schema field", meta: { model: model.name, column: output } });
844
+ throw new VibeError8({ code: "VIBE_INTERNAL", message: "positional projection has no schema field", meta: { model: model.name, column: output } });
786
845
  return entry;
787
846
  });
788
847
  const width = slots.length;
@@ -790,7 +849,7 @@ function positionalMaterializer(params) {
790
849
  const chunked = width > chunkSize;
791
850
  const count = Math.ceil(width / chunkSize);
792
851
  const invalid = () => {
793
- throw new VibeError6({ code: "VIBE_INTERNAL", message: "positional relation payload does not match its SQL projection", meta: { model: model.name, expectedColumns: width } });
852
+ throw new VibeError8({ code: "VIBE_INTERNAL", message: "positional relation payload does not match its SQL projection", meta: { model: model.name, expectedColumns: width } });
794
853
  };
795
854
  if (width === 0 || new Set(slots.map((slot) => slot.name)).size !== width)
796
855
  return invalid();
@@ -832,7 +891,7 @@ function decodeAggregateValue(params) {
832
891
  return field === null ? value : decodeValue({ dialect, field, value });
833
892
  }
834
893
  // packages/runtime/src/lateral-projection.ts
835
- import { VibeError as VibeError7, unsupportedCapability as unsupportedCapability2 } from "@vibeorm/schema";
894
+ import { VibeError as VibeError9, unsupportedCapability as unsupportedCapability2 } from "@vibeorm/schema";
836
895
  function isPlainObject(value) {
837
896
  return value !== null && typeof value === "object" && !Array.isArray(value) && !(value instanceof Date);
838
897
  }
@@ -849,7 +908,7 @@ function lateralProjection(params) {
849
908
  const columns = names.map((name) => {
850
909
  const field = model.fieldByName.get(name);
851
910
  if (field === undefined)
852
- throw new VibeError7({ code: "VIBE_INTERNAL", message: "lateral projection references an unknown field", meta: { model: model.name, field: name } });
911
+ throw new VibeError9({ code: "VIBE_INTERNAL", message: "lateral projection references an unknown field", meta: { model: model.name, field: name } });
853
912
  return Object.freeze(applyLateralTransform({ model, column: { table: LATERAL_CHILD_ALIAS, name: field.columnName } }));
854
913
  });
855
914
  const descriptor = Object.freeze({ columns: Object.freeze(columns), hiddenOrder: Object.freeze(hiddenOrder) });
@@ -898,7 +957,7 @@ function applyLateralTransform(params) {
898
957
 
899
958
  // packages/runtime/src/query-builder.ts
900
959
  import { isSqlFragment, mapConflictColumns } from "@vibeorm/sql";
901
- import { VibeError as VibeError11, unsupportedCapability as unsupportedCapability4 } from "@vibeorm/schema";
960
+ import { VibeError as VibeError13, unsupportedCapability as unsupportedCapability5 } from "@vibeorm/schema";
902
961
  import {
903
962
  SQL_DEFAULT_CELL,
904
963
  containsPattern,
@@ -912,9 +971,9 @@ import {
912
971
  import { describeRowLock } from "@vibeorm/sql";
913
972
 
914
973
  // packages/runtime/src/bulk-upsert.ts
915
- import { VibeError as VibeError8, unsupportedCapability as unsupportedCapability3 } from "@vibeorm/schema";
974
+ import { VibeError as VibeError10, unsupportedCapability as unsupportedCapability3 } from "@vibeorm/schema";
916
975
  function validationError2(params) {
917
- return new VibeError8({
976
+ return new VibeError10({
918
977
  code: "VIBE_VALIDATION",
919
978
  message: params.message,
920
979
  ...params.meta === undefined ? {} : { meta: params.meta }
@@ -1238,7 +1297,7 @@ function assertConflictKeysAreComparable(params) {
1238
1297
  }
1239
1298
 
1240
1299
  // packages/runtime/src/keyset.ts
1241
- import { VibeError as VibeError9 } from "@vibeorm/schema";
1300
+ import { VibeError as VibeError11 } from "@vibeorm/schema";
1242
1301
  var KEYSET_TOKEN_VERSION = 1;
1243
1302
  var KEYSET_TOKEN_PREFIX = "vk1.";
1244
1303
  var KEYSET_MAX_PAGE_SIZE = 1e4;
@@ -1247,11 +1306,12 @@ var DATETIME_NEEDS_PRECISION_ASSERTION = Object.freeze({
1247
1306
  mysql: true,
1248
1307
  sqlite: false
1249
1308
  });
1309
+ var MILLISECOND_EXACT_NATIVE_TYPE = /^(?:timestamptz|timestamp|datetime)\(\s*[0-3]\s*\)$/i;
1250
1310
  function keysetValidation(params) {
1251
- return new VibeError9({ code: "VIBE_VALIDATION", message: params.message, meta: params.meta });
1311
+ return new VibeError11({ code: "VIBE_VALIDATION", message: params.message, meta: params.meta });
1252
1312
  }
1253
1313
  function keysetUnsupported(params) {
1254
- return new VibeError9({
1314
+ return new VibeError11({
1255
1315
  code: "VIBE_UNSUPPORTED_CAPABILITY",
1256
1316
  message: params.message,
1257
1317
  meta: params.meta
@@ -1356,9 +1416,9 @@ function compileKeysetOrderPlan(params) {
1356
1416
  meta: { model: model.name, field: field.name, feature: "keysetOrderKey" }
1357
1417
  });
1358
1418
  }
1359
- if (tag === "t" && DATETIME_NEEDS_PRECISION_ASSERTION[dialect.name] === true && timestampPrecision === undefined) {
1419
+ if (tag === "t" && DATETIME_NEEDS_PRECISION_ASSERTION[dialect.name] === true && timestampPrecision === undefined && (model.isView || !MILLISECOND_EXACT_NATIVE_TYPE.test(field.nativeType ?? ""))) {
1360
1420
  throw keysetUnsupported({
1361
- message: `keyset pagination cannot order by ${model.name}.${field.name} on ${dialect.name}: this engine may store sub-millisecond timestamps, ` + "and a JavaScript Date truncates them, which would re-deliver rows inside the same millisecond. " + 'Pass keyset: { timestampPrecision: "milliseconds" } to assert the column is millisecond-exact, or order by a lossless key.',
1421
+ message: `keyset pagination cannot order by ${model.name}.${field.name} on ${dialect.name}: this engine may store sub-millisecond timestamps, ` + "and a JavaScript Date truncates them, which would re-deliver rows inside the same millisecond. " + "Declare the column millisecond-exact (@db.Timestamptz(3), dsl.datetime().tz({ precision: 3 })), " + 'pass keyset: { timestampPrecision: "milliseconds" } to assert it is, or order by a lossless key.',
1362
1422
  meta: { model: model.name, field: field.name, feature: "keysetTimestampPrecision", dialect: dialect.name }
1363
1423
  });
1364
1424
  }
@@ -1371,7 +1431,7 @@ function compileKeysetOrderPlan(params) {
1371
1431
  meta: { model: model.name, orderFields: [...seen], feature: "keysetTieBreaker" }
1372
1432
  });
1373
1433
  }
1374
- return { model: model.name, keys, signature: signatureOf2({ model: model.name, keys }) };
1434
+ return { model: model.name, keys, signature: signatureOf2({ model: model.name, keys, ...model.namespace === undefined ? {} : { namespace: model.namespace, table: model.tableName } }) };
1375
1435
  }
1376
1436
  function signatureOf2(params) {
1377
1437
  const { model, keys } = params;
@@ -1379,7 +1439,7 @@ function signatureOf2(params) {
1379
1439
  const base = `${key.field.name}:${key.direction}`;
1380
1440
  return key.field.isOptional ? `${base}:nulls=${key.nulls}` : base;
1381
1441
  });
1382
- return [model, ...parts].join("|");
1442
+ return [model, ...params.namespace === undefined ? [] : [`physical=${JSON.stringify([params.namespace, params.table])}`], ...parts].join("|");
1383
1443
  }
1384
1444
  function encodeValueFor(params) {
1385
1445
  const { key, value, model } = params;
@@ -1634,9 +1694,9 @@ function decodeKeysetToken(params) {
1634
1694
  }
1635
1695
 
1636
1696
  // packages/runtime/src/relation-plan.ts
1637
- import { VibeError as VibeError10, implicitJoinTable } from "@vibeorm/schema";
1697
+ import { VibeError as VibeError12, implicitJoinTable, qualifiedSqlName, unsupportedCapability as unsupportedCapability4 } from "@vibeorm/schema";
1638
1698
  function validationError3(params) {
1639
- return new VibeError10({ code: "VIBE_VALIDATION", message: params.message, meta: params.meta });
1699
+ return new VibeError12({ code: "VIBE_VALIDATION", message: params.message, meta: params.meta });
1640
1700
  }
1641
1701
  function isPlainObject2(value) {
1642
1702
  return typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date);
@@ -1661,7 +1721,7 @@ function keyFields(params) {
1661
1721
  return names.map((name) => {
1662
1722
  const field = model.fieldByName.get(name);
1663
1723
  if (field === undefined) {
1664
- throw new VibeError10({
1724
+ throw new VibeError12({
1665
1725
  code: "VIBE_SCHEMA_INVALID",
1666
1726
  message: `relation "${relation.name}" on ${relation.model} names unknown ${what} field "${name}"`,
1667
1727
  meta: { model: relation.model, relation: relation.name }
@@ -1673,7 +1733,7 @@ function keyFields(params) {
1673
1733
  function singleKeyPair(params) {
1674
1734
  const { link, what } = params;
1675
1735
  if (link.parentKeys.length !== 1 || link.childKeys.length !== 1) {
1676
- throw new VibeError10({
1736
+ throw new VibeError12({
1677
1737
  code: "VIBE_UNSUPPORTED_CAPABILITY",
1678
1738
  message: `${what} on relation "${link.relation.name}" of ${link.relation.model} needs a single-column relation key \u2014 this relation links ${link.parentKeys.length} columns; use an explicit junction model`,
1679
1739
  meta: { model: link.relation.model, relation: link.relation.name, arity: link.parentKeys.length }
@@ -1717,12 +1777,15 @@ function resolveRelationLinkUncached(params) {
1717
1777
  const target = getModelMeta({ meta, model: relation.targetModel });
1718
1778
  if (relation.type === "manyToMany") {
1719
1779
  if (relation.model === relation.targetModel) {
1720
- throw new VibeError10({
1780
+ throw new VibeError12({
1721
1781
  code: "VIBE_SCHEMA_INVALID",
1722
1782
  message: `relation "${relation.name}" on ${relation.model} is an implicit self many-to-many: both sides own the ` + `same join-table column, so this field and its inverse would read the same rows. Model each direction ` + `with an explicit junction model.`,
1723
1783
  meta: { model: relation.model, relation: relation.name, targetModel: relation.targetModel }
1724
1784
  });
1725
1785
  }
1786
+ const namespace = qualifiedSqlName({ name: model.tableName, namespace: model.namespace }).namespace;
1787
+ if (namespace !== qualifiedSqlName({ name: target.tableName, namespace: target.namespace }).namespace)
1788
+ throw unsupportedCapability4({ dialect: "postgres", feature: "implicitJoinNamespaces", hint: "Implicit join parents must share one physical namespace" });
1726
1789
  const join = implicitJoinTable({
1727
1790
  modelA: relation.model,
1728
1791
  modelB: relation.targetModel,
@@ -1737,6 +1800,7 @@ function resolveRelationLinkUncached(params) {
1737
1800
  childKeys: [singlePrimaryKey({ model: target, relation })],
1738
1801
  join: {
1739
1802
  tableName: join.tableName,
1803
+ ...model.namespace === undefined && target.namespace === undefined ? {} : { namespace },
1740
1804
  parentColumn: parentIsA ? "A" : "B",
1741
1805
  childColumn: parentIsA ? "B" : "A"
1742
1806
  }
@@ -1759,7 +1823,7 @@ function resolveRelationLinkUncached(params) {
1759
1823
  }
1760
1824
  const reverse = findReverseRelation({ relation, target });
1761
1825
  if (reverse === null || reverse.fields === undefined || reverse.fields.length === 0) {
1762
- throw new VibeError10({
1826
+ throw new VibeError12({
1763
1827
  code: "VIBE_SCHEMA_INVALID",
1764
1828
  message: `relation "${relation.name}" on ${relation.model} has no foreign-key counterpart on ${relation.targetModel}`,
1765
1829
  meta: { model: relation.model, relation: relation.name, target: relation.targetModel }
@@ -1784,7 +1848,7 @@ function pairedKeys(params) {
1784
1848
  const parentKeys = keyFields({ model, names: parentNames, relation, what: "fields" });
1785
1849
  const childKeys = keyFields({ model: target, names: childNames, relation, what: "references" });
1786
1850
  if (parentKeys.length !== childKeys.length) {
1787
- throw new VibeError10({
1851
+ throw new VibeError12({
1788
1852
  code: "VIBE_SCHEMA_INVALID",
1789
1853
  message: `relation "${relation.name}" on ${relation.model} links ${parentKeys.length} field(s) to ${childKeys.length} reference(s) \u2014 a foreign key must pair every column`,
1790
1854
  meta: { model: relation.model, relation: relation.name }
@@ -2134,7 +2198,7 @@ var AGG_FN_BY_KEY = {
2134
2198
  _max: "max"
2135
2199
  };
2136
2200
  function validationError4(params) {
2137
- return new VibeError11({ code: "VIBE_VALIDATION", message: params.message, meta: params.meta });
2201
+ return new VibeError13({ code: "VIBE_VALIDATION", message: params.message, meta: params.meta });
2138
2202
  }
2139
2203
  function isPlainObject3(value) {
2140
2204
  return typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date) && !(value instanceof Uint8Array);
@@ -2238,21 +2302,21 @@ function assertLockIsExpressible(params) {
2238
2302
  if (rowLockStrengths.length === 0) {
2239
2303
  if (lock.strength === "update" && lock.wait === "wait")
2240
2304
  return;
2241
- throw unsupportedCapability4({
2305
+ throw unsupportedCapability5({
2242
2306
  dialect: dialect.name,
2243
2307
  feature: site,
2244
2308
  hint: `${dialect.name} has no locking-read clause at all. Only lock: "update" is accepted there, ` + `as the documented no-op its single-writer transactions already provide`
2245
2309
  });
2246
2310
  }
2247
2311
  if (!rowLockStrengths.includes(lock.strength)) {
2248
- throw unsupportedCapability4({
2312
+ throw unsupportedCapability5({
2249
2313
  dialect: dialect.name,
2250
2314
  feature: site,
2251
2315
  hint: `${dialect.name} has these lock strengths: ${rowLockStrengths.join(", ")}`
2252
2316
  });
2253
2317
  }
2254
2318
  if (!rowLockWaitPolicies.includes(lock.wait)) {
2255
- throw unsupportedCapability4({
2319
+ throw unsupportedCapability5({
2256
2320
  dialect: dialect.name,
2257
2321
  feature: site,
2258
2322
  hint: `${dialect.name} has these lock wait policies: ${rowLockWaitPolicies.join(", ")}`
@@ -2262,7 +2326,7 @@ function assertLockIsExpressible(params) {
2262
2326
  function compileConflictTarget(params) {
2263
2327
  const { dialect, meta, model, method, target, where } = params;
2264
2328
  if ((target !== undefined || where !== undefined) && dialect.doNothingForm === "insertIgnore") {
2265
- throw unsupportedCapability4({
2329
+ throw unsupportedCapability5({
2266
2330
  dialect: dialect.name,
2267
2331
  feature: `a conflict target on ${model.clientName}.${method}()`,
2268
2332
  hint: "mysql's INSERT IGNORE / ON DUPLICATE KEY fire on ANY duplicate key \u2014 no target can be named; gate the call per dialect"
@@ -2280,7 +2344,7 @@ function compileConflictTarget(params) {
2280
2344
  out.columns = target.map((name) => getFieldMeta({ model, field: String(name), context: "onConflict target" }).columnName);
2281
2345
  } else if (isPlainObject3(target) && typeof target.constraint === "string" && target.constraint.length > 0 && Object.keys(target).length === 1) {
2282
2346
  if (!dialect.capabilities.conflictTargetConstraint) {
2283
- throw unsupportedCapability4({
2347
+ throw unsupportedCapability5({
2284
2348
  dialect: dialect.name,
2285
2349
  feature: "a named-constraint conflict target (ON CONFLICT ON CONSTRAINT)",
2286
2350
  hint: "only postgres supports ON CONSTRAINT targets \u2014 name the indexed columns instead"
@@ -2302,7 +2366,7 @@ function compileConflictTarget(params) {
2302
2366
  });
2303
2367
  }
2304
2368
  if (!dialect.capabilities.partialIndexes) {
2305
- throw unsupportedCapability4({
2369
+ throw unsupportedCapability5({
2306
2370
  dialect: dialect.name,
2307
2371
  feature: "a partial-index conflict target",
2308
2372
  hint: "this dialect has no partial indexes to target"
@@ -2388,7 +2452,7 @@ function assertListFilterable(params) {
2388
2452
  const { dialect, model, field, operator } = params;
2389
2453
  if (dialect.capabilities.scalarArrays)
2390
2454
  return;
2391
- throw unsupportedCapability4({
2455
+ throw unsupportedCapability5({
2392
2456
  dialect: dialect.name,
2393
2457
  feature: `scalar list filter "${operator}" on ${model.name}.${field.name}`,
2394
2458
  hint: "only postgres has native array columns \u2014 model the list as a related table instead"
@@ -2398,7 +2462,7 @@ function assertListWritable(params) {
2398
2462
  const { dialect, model, field } = params;
2399
2463
  if (!field.isList || dialect.capabilities.scalarArrays)
2400
2464
  return;
2401
- throw unsupportedCapability4({
2465
+ throw unsupportedCapability5({
2402
2466
  dialect: dialect.name,
2403
2467
  feature: `writing the scalar list ${model.name}.${field.name}`,
2404
2468
  hint: "only postgres has native array columns \u2014 model the list as a related table instead"
@@ -2515,7 +2579,7 @@ function compileJsonFieldFilter(params) {
2515
2579
  const requireOp = (op) => {
2516
2580
  if (dialect.supportedJsonOps.includes(op))
2517
2581
  return;
2518
- throw unsupportedCapability4({
2582
+ throw unsupportedCapability5({
2519
2583
  dialect: dialect.name,
2520
2584
  feature: `json filter "${op}" on ${model.name}.${field.name}`,
2521
2585
  hint: `this dialect can express: ${dialect.supportedJsonOps.join(", ")}`
@@ -2836,7 +2900,7 @@ function buildRelationExists(params) {
2836
2900
  kind: "exists",
2837
2901
  select: {
2838
2902
  kind: "select",
2839
- table: { name: target.tableName, alias: childAlias },
2903
+ table: { name: target.tableName, ...target.namespace === undefined ? {} : { namespace: target.namespace }, alias: childAlias },
2840
2904
  columns: [],
2841
2905
  selectExpr: { kind: "one" },
2842
2906
  where: correlated({
@@ -2852,7 +2916,7 @@ function buildRelationExists(params) {
2852
2916
  ...negate ? { negate: true } : {},
2853
2917
  select: {
2854
2918
  kind: "select",
2855
- table: { name: join.tableName, alias: jtAlias },
2919
+ table: { name: join.tableName, ...join.namespace === undefined ? {} : { namespace: join.namespace }, alias: jtAlias },
2856
2920
  columns: [],
2857
2921
  selectExpr: { kind: "one" },
2858
2922
  where: {
@@ -2875,7 +2939,7 @@ function buildRelationExists(params) {
2875
2939
  ...negate ? { negate: true } : {},
2876
2940
  select: {
2877
2941
  kind: "select",
2878
- table: { name: target.tableName, alias: childAlias },
2942
+ table: { name: target.tableName, ...target.namespace === undefined ? {} : { namespace: target.namespace }, alias: childAlias },
2879
2943
  columns: [],
2880
2944
  selectExpr: { kind: "one" },
2881
2945
  where: correlated(correlateLink({ link, childTable: childAlias, outerTable: outer }))
@@ -3149,7 +3213,7 @@ function compileRelationOrderTerms(params) {
3149
3213
  const alias = `__ord${++aliasSeq.n}`;
3150
3214
  const select = link.kind === "manyToMany" ? {
3151
3215
  kind: "select",
3152
- table: { name: link.join.tableName, alias },
3216
+ table: { name: link.join.tableName, ...link.join?.namespace === undefined ? {} : { namespace: link.join.namespace }, alias },
3153
3217
  columns: [],
3154
3218
  selectExpr: { kind: "countAll" },
3155
3219
  where: {
@@ -3163,7 +3227,7 @@ function compileRelationOrderTerms(params) {
3163
3227
  }
3164
3228
  } : {
3165
3229
  kind: "select",
3166
- table: { name: link.target.tableName, alias },
3230
+ table: { name: link.target.tableName, ...link.target.namespace === undefined ? {} : { namespace: link.target.namespace }, alias },
3167
3231
  columns: [],
3168
3232
  selectExpr: { kind: "countAll" },
3169
3233
  where: correlateLink({ link, childTable: alias, outerTable: outer })
@@ -3183,7 +3247,7 @@ function compileRelationOrderTerms(params) {
3183
3247
  terms.push({
3184
3248
  select: {
3185
3249
  kind: "select",
3186
- table: { name: link.target.tableName, alias },
3250
+ table: { name: link.target.tableName, ...link.target.namespace === undefined ? {} : { namespace: link.target.namespace }, alias },
3187
3251
  columns: [compareColumnRef({ dialect, field, table: alias })],
3188
3252
  where: correlateLink({ link, childTable: alias, outerTable: outer })
3189
3253
  },
@@ -3737,7 +3801,7 @@ function parseCursor(params) {
3737
3801
  function keysetFieldOfTerm(params) {
3738
3802
  const { dialect, model, term } = params;
3739
3803
  if (!("column" in term)) {
3740
- throw unsupportedCapability4({
3804
+ throw unsupportedCapability5({
3741
3805
  dialect: dialect.name,
3742
3806
  feature: `keyset pagination over a relation or aggregate orderBy on model "${model.name}"`,
3743
3807
  hint: "order by scalar columns plus a unique tie-breaker; a correlated subquery value is not on the row, so no position can describe it"
@@ -3745,7 +3809,7 @@ function keysetFieldOfTerm(params) {
3745
3809
  }
3746
3810
  const field = model.fieldByColumn.get(term.column.name);
3747
3811
  if (field === undefined) {
3748
- throw unsupportedCapability4({
3812
+ throw unsupportedCapability5({
3749
3813
  dialect: dialect.name,
3750
3814
  feature: `keyset pagination over a computed order key on model "${model.name}"`,
3751
3815
  hint: "order by scalar columns plus a unique tie-breaker"
@@ -4125,7 +4189,7 @@ function buildFindShape(params) {
4125
4189
  const outerOrder = distinctOuterOrder ?? arranged.slice(0, distinctLeadCount);
4126
4190
  const inner = {
4127
4191
  kind: "select",
4128
- table: { name: model.tableName },
4192
+ table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
4129
4193
  columns: withOuterOrderKeys(columns, outerOrder),
4130
4194
  rowNumber: {
4131
4195
  partitionBy: distinctPartition,
@@ -4149,7 +4213,7 @@ function buildFindShape(params) {
4149
4213
  if (distinctOuterOrder !== null) {
4150
4214
  const inner = {
4151
4215
  kind: "select",
4152
- table: { name: model.tableName },
4216
+ table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
4153
4217
  columns: withOuterOrderKeys(columns, distinctOuterOrder),
4154
4218
  ...lateralJoins.length > 0 ? { lateralJoins } : {},
4155
4219
  ...where === undefined ? {} : { where },
@@ -4177,7 +4241,7 @@ function buildFindShape(params) {
4177
4241
  const innerColumns = withOuterOrderKeys(withKeyColumns(projected, correlationKeys), orderTerms);
4178
4242
  const inner = {
4179
4243
  kind: "select",
4180
- table: { name: model.tableName },
4244
+ table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
4181
4245
  columns: innerColumns,
4182
4246
  ...where === undefined ? {} : { where },
4183
4247
  ...distinctOn === undefined ? {} : { distinctOn },
@@ -4187,7 +4251,7 @@ function buildFindShape(params) {
4187
4251
  };
4188
4252
  const statement = {
4189
4253
  kind: "select",
4190
- table: { name: model.tableName },
4254
+ table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
4191
4255
  columns,
4192
4256
  fromSelect: inner,
4193
4257
  lateralJoins,
@@ -4197,7 +4261,7 @@ function buildFindShape(params) {
4197
4261
  }
4198
4262
  const statement = {
4199
4263
  kind: "select",
4200
- table: { name: model.tableName },
4264
+ table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
4201
4265
  columns,
4202
4266
  ...lateralJoins.length > 0 ? { lateralJoins } : {},
4203
4267
  ...where === undefined ? {} : { where },
@@ -4241,12 +4305,12 @@ function buildLateralCount(params) {
4241
4305
  };
4242
4306
  select = {
4243
4307
  kind: "select",
4244
- table: filter === undefined ? { name: join.tableName, alias: joinAlias } : { name: link.target.tableName, alias: childAlias },
4308
+ table: filter === undefined ? { name: join.tableName, ...join.namespace === undefined ? {} : { namespace: join.namespace }, alias: joinAlias } : { name: link.target.tableName, ...link.target.namespace === undefined ? {} : { namespace: link.target.namespace }, alias: childAlias },
4245
4309
  columns: [],
4246
4310
  selectExpr: { kind: "countAll", alias: columnAlias },
4247
4311
  where: filter === undefined ? correlation : { kind: "and", operands: [correlation, filter] },
4248
4312
  ...filter === undefined ? {} : { innerJoins: [{
4249
- table: { name: join.tableName, alias: joinAlias },
4313
+ table: { name: join.tableName, ...join.namespace === undefined ? {} : { namespace: join.namespace }, alias: joinAlias },
4250
4314
  on: [{ left: { table: joinAlias, name: join.childColumn }, right: { table: childAlias, name: pair.child.columnName } }]
4251
4315
  }] }
4252
4316
  };
@@ -4254,7 +4318,7 @@ function buildLateralCount(params) {
4254
4318
  const correlation = correlateLink({ link, childTable: childAlias, outerTable: model.tableName });
4255
4319
  select = {
4256
4320
  kind: "select",
4257
- table: { name: link.target.tableName, alias: childAlias },
4321
+ table: { name: link.target.tableName, ...link.target.namespace === undefined ? {} : { namespace: link.target.namespace }, alias: childAlias },
4258
4322
  columns: [],
4259
4323
  selectExpr: { kind: "countAll", alias: columnAlias },
4260
4324
  where: filter === undefined ? correlation : { kind: "and", operands: [correlation, filter] }
@@ -4277,7 +4341,7 @@ function buildLateralJoinClause(params) {
4277
4341
  kind: "exists",
4278
4342
  select: {
4279
4343
  kind: "select",
4280
- table: { name: join.tableName, alias: jtAlias },
4344
+ table: { name: join.tableName, ...join.namespace === undefined ? {} : { namespace: join.namespace }, alias: jtAlias },
4281
4345
  columns: [],
4282
4346
  selectExpr: { kind: "one" },
4283
4347
  where: {
@@ -4329,7 +4393,7 @@ function buildLateralJoinClause(params) {
4329
4393
  rowFormat: "positional",
4330
4394
  select: {
4331
4395
  kind: "select",
4332
- table: { name: target.tableName, alias: LATERAL_CHILD_ALIAS },
4396
+ table: { name: target.tableName, ...target.namespace === undefined ? {} : { namespace: target.namespace }, alias: LATERAL_CHILD_ALIAS },
4333
4397
  columns,
4334
4398
  where,
4335
4399
  ...orderBy === undefined || orderBy.length === 0 ? {} : { orderBy },
@@ -4685,7 +4749,7 @@ function resolveStrategy(params) {
4685
4749
  const strategy = explicit ?? defaultRelationStrategy ?? "query";
4686
4750
  if (strategy === "join" && !dialect.capabilities.lateralJoin) {
4687
4751
  if (explicit !== undefined || hasRelations) {
4688
- throw unsupportedCapability4({
4752
+ throw unsupportedCapability5({
4689
4753
  dialect: dialect.name,
4690
4754
  feature: 'relationStrategy "join"',
4691
4755
  hint: 'lateral joins are postgres-only \u2014 use the portable "query" strategy on this dialect'
@@ -4856,7 +4920,7 @@ function buildQuery(params) {
4856
4920
  const bounded = countTake !== undefined || countSkip !== undefined;
4857
4921
  const boundedInner = (innerFields) => ({
4858
4922
  kind: "select",
4859
- table: { name: model.tableName },
4923
+ table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
4860
4924
  columns: projectionColumns({ model, selectedFields: innerFields }),
4861
4925
  ...where === undefined ? {} : { where },
4862
4926
  ...countOrder === undefined || countOrder.length === 0 ? {} : { orderBy: countOrder },
@@ -4915,7 +4979,7 @@ function buildQuery(params) {
4915
4979
  aggregateSpec: { selections, countShorthand: false },
4916
4980
  statement: {
4917
4981
  kind: "select",
4918
- table: { name: model.tableName },
4982
+ table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
4919
4983
  columns: [],
4920
4984
  aggregates: aggSelects,
4921
4985
  ...where === undefined ? {} : { where }
@@ -4940,7 +5004,7 @@ function buildQuery(params) {
4940
5004
  countAlias: COUNT_ALIAS,
4941
5005
  statement: {
4942
5006
  kind: "select",
4943
- table: { name: model.tableName },
5007
+ table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
4944
5008
  columns: [],
4945
5009
  selectExpr: { kind: "countAll", alias: COUNT_ALIAS },
4946
5010
  ...where === undefined ? {} : { where }
@@ -4960,7 +5024,7 @@ function buildQuery(params) {
4960
5024
  aggregateSpec: spec,
4961
5025
  statement: {
4962
5026
  kind: "select",
4963
- table: { name: model.tableName },
5027
+ table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
4964
5028
  columns: [],
4965
5029
  aggregates: aggSelects,
4966
5030
  ...where === undefined ? {} : { where }
@@ -4970,7 +5034,7 @@ function buildQuery(params) {
4970
5034
  const innerFields = referenced.length > 0 ? referenced : model.primaryKey.map((field) => field.name);
4971
5035
  const inner = {
4972
5036
  kind: "select",
4973
- table: { name: model.tableName },
5037
+ table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
4974
5038
  columns: projectionColumns({ model, selectedFields: innerFields }),
4975
5039
  ...where === undefined ? {} : { where },
4976
5040
  ...orderBy === undefined || orderBy.length === 0 ? {} : { orderBy },
@@ -5023,7 +5087,7 @@ function buildQuery(params) {
5023
5087
  groupByFields: byFields.map((field) => field.name),
5024
5088
  statement: {
5025
5089
  kind: "select",
5026
- table: { name: model.tableName },
5090
+ table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
5027
5091
  columns: byColumns,
5028
5092
  ...aggSelects.length === 0 ? {} : { aggregates: aggSelects },
5029
5093
  ...where === undefined ? {} : { where },
@@ -5065,7 +5129,7 @@ function buildQuery(params) {
5065
5129
  throw validationError4({ message: "DO NOTHING cannot carry update expressions" });
5066
5130
  if (spec.action === "update") {
5067
5131
  if (!dialect.capabilities.returning)
5068
- throw unsupportedCapability4({ dialect: dialect.name, feature: "create onConflict update returning", hint: "use upsertMany for a count-only conflict update" });
5132
+ throw unsupportedCapability5({ dialect: dialect.name, feature: "create onConflict update returning", hint: "use upsertMany for a count-only conflict update" });
5069
5133
  if (compiled.columns === undefined && compiled.constraint === undefined)
5070
5134
  throw validationError4({ message: "A conflict update requires an explicit target" });
5071
5135
  const updates = requireObject({ value: spec.update, what: "onConflict.update", model });
@@ -5103,7 +5167,7 @@ function buildQuery(params) {
5103
5167
  refetchWhere: row.knownKey,
5104
5168
  statement: {
5105
5169
  kind: "insert",
5106
- table: { name: model.tableName },
5170
+ table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
5107
5171
  columns,
5108
5172
  rows: [columns.map((column) => row.values[column])],
5109
5173
  ...conflictClause === undefined ? {} : { onConflict: conflictClause },
@@ -5114,7 +5178,7 @@ function buildQuery(params) {
5114
5178
  case "createMany":
5115
5179
  case "createManyAndReturn": {
5116
5180
  if (method === "createManyAndReturn" && !dialect.capabilities.createManyAndReturn) {
5117
- throw unsupportedCapability4({
5181
+ throw unsupportedCapability5({
5118
5182
  dialect: dialect.name,
5119
5183
  feature: "createManyAndReturn",
5120
5184
  hint: "this dialect cannot RETURNING multiple inserted rows \u2014 use createMany then findMany"
@@ -5151,7 +5215,7 @@ function buildQuery(params) {
5151
5215
  }
5152
5216
  const statements = groups.map((group) => ({
5153
5217
  kind: "insert",
5154
- table: { name: model.tableName },
5218
+ table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
5155
5219
  columns: group.columns,
5156
5220
  rows: group.rows,
5157
5221
  ...manyConflict === undefined ? {} : { onConflict: manyConflict },
@@ -5237,7 +5301,7 @@ function buildQuery(params) {
5237
5301
  };
5238
5302
  const upsertStatements = upsertGroups.map((group) => ({
5239
5303
  kind: "insert",
5240
- table: { name: model.tableName },
5304
+ table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
5241
5305
  columns: group.columns,
5242
5306
  rows: group.rows,
5243
5307
  onConflict
@@ -5254,7 +5318,7 @@ function buildQuery(params) {
5254
5318
  case "updateManyAndReturn": {
5255
5319
  const isUnique = method === "update";
5256
5320
  if (method === "updateManyAndReturn" && !dialect.capabilities.returning) {
5257
- throw unsupportedCapability4({
5321
+ throw unsupportedCapability5({
5258
5322
  dialect: dialect.name,
5259
5323
  feature: "updateManyAndReturn",
5260
5324
  hint: "this dialect has no RETURNING \u2014 use updateMany then findMany, accepting that the read is a separate, unprotected statement"
@@ -5276,7 +5340,7 @@ function buildQuery(params) {
5276
5340
  refetchWhere: isUnique ? uniqueRefetchWhere({ model, where, data: args.data }) : null,
5277
5341
  statement: {
5278
5342
  kind: "update",
5279
- table: { name: model.tableName },
5343
+ table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
5280
5344
  set: compileUpdateSet({
5281
5345
  dialect,
5282
5346
  model,
@@ -5299,7 +5363,7 @@ function buildQuery(params) {
5299
5363
  });
5300
5364
  }
5301
5365
  if (!dialect.capabilities.conflictTargetConstraint) {
5302
- throw unsupportedCapability4({
5366
+ throw unsupportedCapability5({
5303
5367
  dialect: dialect.name,
5304
5368
  feature: "a named-constraint conflict target on upsert",
5305
5369
  hint: "only postgres supports ON CONFLICT ON CONSTRAINT \u2014 rely on the where-derived column target instead"
@@ -5317,7 +5381,7 @@ function buildQuery(params) {
5317
5381
  const targetFields = conflictTargetGroup({ model, where }).fields;
5318
5382
  for (const field of targetFields) {
5319
5383
  if (!(field.columnName in row.values)) {
5320
- throw new VibeError11({
5384
+ throw new VibeError13({
5321
5385
  code: "VIBE_INTERNAL",
5322
5386
  message: `upsert on ${model.name}: create data does not bind conflict-target column "${field.columnName}" \u2014 this shape must run the find-then-write fallback flow`,
5323
5387
  meta: { model: model.name, column: field.columnName }
@@ -5328,7 +5392,7 @@ function buildQuery(params) {
5328
5392
  for (const [key, value] of Object.entries(where)) {
5329
5393
  if (value === undefined || nativeTargetNames.has(key))
5330
5394
  continue;
5331
- throw new VibeError11({
5395
+ throw new VibeError13({
5332
5396
  code: "VIBE_INTERNAL",
5333
5397
  message: `upsert on ${model.name}: where field "${key}" is not part of the conflict target \u2014 guarded upserts must run the find-then-write fallback flow`,
5334
5398
  meta: { model: model.name, field: key }
@@ -5343,7 +5407,7 @@ function buildQuery(params) {
5343
5407
  refetchWhereBase: { ...where },
5344
5408
  statement: {
5345
5409
  kind: "insert",
5346
- table: { name: model.tableName },
5410
+ table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
5347
5411
  columns,
5348
5412
  rows: [columns.map((column) => row.values[column])],
5349
5413
  onConflict: {
@@ -5369,7 +5433,7 @@ function buildQuery(params) {
5369
5433
  refetchWhere: isUnique ? where : null,
5370
5434
  statement: {
5371
5435
  kind: "delete",
5372
- table: { name: model.tableName },
5436
+ table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
5373
5437
  ...compiled === undefined ? {} : { where: compiled },
5374
5438
  ...isUnique ? { returning: returningColumns({ model, selectedFields }) } : {}
5375
5439
  }
@@ -5381,7 +5445,7 @@ function buildQuery(params) {
5381
5445
  import { getSqlDialect, renderStatement } from "@vibeorm/sql";
5382
5446
 
5383
5447
  // packages/runtime/src/extensions.ts
5384
- import { VibeError as VibeError12, extensionManifestEntry } from "@vibeorm/schema";
5448
+ import { VibeError as VibeError14, extensionManifestEntry } from "@vibeorm/schema";
5385
5449
  function assertExtensionManifest(params) {
5386
5450
  const { manifest } = params;
5387
5451
  const instances = params.instances ?? [];
@@ -5404,7 +5468,7 @@ function assertExtensionManifest(params) {
5404
5468
  problems.push(`"${name}" is configured but missing from the generated client`);
5405
5469
  }
5406
5470
  if (problems.length > 0) {
5407
- throw new VibeError12({
5471
+ throw new VibeError14({
5408
5472
  code: "VIBE_STALE_CLIENT",
5409
5473
  message: `extension list changed since generate; run vibeorm generate \u2014 ${problems.join("; ")}`,
5410
5474
  meta: { manifest, problems }
@@ -5419,7 +5483,7 @@ function buildExtensionOperatorMap(params) {
5419
5483
  for (const operator of extension.sql?.whereOperators ?? []) {
5420
5484
  const existing = owner.get(operator.name);
5421
5485
  if (existing !== undefined) {
5422
- throw new VibeError12({
5486
+ throw new VibeError14({
5423
5487
  code: "VIBE_CONFIG",
5424
5488
  message: `where operator "${operator.name}" is claimed by both "${existing}" and "${extension.name}"`,
5425
5489
  meta: { operator: operator.name }
@@ -5435,7 +5499,7 @@ function buildExtensionOperatorMap(params) {
5435
5499
  options: extension.options
5436
5500
  });
5437
5501
  if ("error" in compiled) {
5438
- throw new VibeError12({
5502
+ throw new VibeError14({
5439
5503
  code: "VIBE_VALIDATION",
5440
5504
  message: `"${operator.name}" on ${model}.${field}: ${compiled.error}`,
5441
5505
  meta: { model, field, operator: operator.name, extension: extension.name }
@@ -5468,7 +5532,7 @@ function buildConnectHooks(params) {
5468
5532
  }
5469
5533
 
5470
5534
  // packages/runtime/src/relation-key.ts
5471
- import { VibeError as VibeError13 } from "@vibeorm/schema";
5535
+ import { VibeError as VibeError15 } from "@vibeorm/schema";
5472
5536
  function relationValueKey(params) {
5473
5537
  const { value } = params;
5474
5538
  if (value === null || value === undefined)
@@ -5501,7 +5565,7 @@ function relationTupleKey(params) {
5501
5565
  if (value === null || value === undefined)
5502
5566
  return null;
5503
5567
  if (typeof value === "object" && !(value instanceof Date) && !(value instanceof Uint8Array)) {
5504
- throw new VibeError13({
5568
+ throw new VibeError15({
5505
5569
  code: "VIBE_UNSUPPORTED_CAPABILITY",
5506
5570
  message: "a relation key of this type cannot be compared faithfully in memory \u2014 relation links support String, Int, BigInt, Boolean, DateTime and Bytes keys",
5507
5571
  meta: { received: Object.prototype.toString.call(value) }
@@ -5527,7 +5591,7 @@ function assertWriteScope(params) {
5527
5591
  }
5528
5592
 
5529
5593
  // packages/runtime/src/nested-writes.ts
5530
- import { VibeError as VibeError14 } from "@vibeorm/schema";
5594
+ import { VibeError as VibeError16 } from "@vibeorm/schema";
5531
5595
  function parentTupleOf(params) {
5532
5596
  const { link, row } = params;
5533
5597
  return link.parentKeys.map((field) => row[field.name]);
@@ -5574,10 +5638,10 @@ function detachAssignment(params) {
5574
5638
  return out;
5575
5639
  }
5576
5640
  function validationError5(params) {
5577
- return new VibeError14({ code: "VIBE_VALIDATION", message: params.message, meta: params.meta });
5641
+ return new VibeError16({ code: "VIBE_VALIDATION", message: params.message, meta: params.meta });
5578
5642
  }
5579
5643
  function notFound(params) {
5580
- return new VibeError14({ code: "VIBE_NOT_FOUND", message: params.message, meta: params.meta });
5644
+ return new VibeError16({ code: "VIBE_NOT_FOUND", message: params.message, meta: params.meta });
5581
5645
  }
5582
5646
  function isPlainObject4(value) {
5583
5647
  return typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date) && !(value instanceof Uint8Array);
@@ -5744,7 +5808,7 @@ async function insertJoinRows(params) {
5744
5808
  await run.statement({
5745
5809
  statement: {
5746
5810
  kind: "insert",
5747
- table: { name: join.tableName },
5811
+ table: { name: join.tableName, ...join.namespace === undefined ? {} : { namespace: join.namespace } },
5748
5812
  columns: ["A", "B"],
5749
5813
  rows: rows.slice(start, start + perChunk),
5750
5814
  onConflict: { columns: ["A", "B"], doNothing: true }
@@ -5764,7 +5828,7 @@ async function deleteJoinRows(params) {
5764
5828
  await run.statement({
5765
5829
  statement: {
5766
5830
  kind: "delete",
5767
- table: { name: join.tableName },
5831
+ table: { name: join.tableName, ...join.namespace === undefined ? {} : { namespace: join.namespace } },
5768
5832
  where: {
5769
5833
  kind: "and",
5770
5834
  operands: [
@@ -5813,7 +5877,7 @@ async function deleteJoinRowsForChildren(params) {
5813
5877
  await run.statement({
5814
5878
  statement: {
5815
5879
  kind: "delete",
5816
- table: { name: join.tableName },
5880
+ table: { name: join.tableName, ...join.namespace === undefined ? {} : { namespace: join.namespace } },
5817
5881
  where: isSelf ? {
5818
5882
  kind: "or",
5819
5883
  operands: [
@@ -6193,7 +6257,7 @@ async function loadMemberKeys(params) {
6193
6257
  const rows = await run.statement({
6194
6258
  statement: {
6195
6259
  kind: "select",
6196
- table: { name: join.tableName },
6260
+ table: { name: join.tableName, ...join.namespace === undefined ? {} : { namespace: join.namespace } },
6197
6261
  columns: [{ name: join.childColumn }],
6198
6262
  where: narrow === null ? parentMatch : {
6199
6263
  kind: "and",
@@ -6794,7 +6858,7 @@ function previewOperation(params) {
6794
6858
  };
6795
6859
  }
6796
6860
  // packages/runtime/src/diagnostics/plan.ts
6797
- import { VibeError as VibeError15, unsupportedCapability as unsupportedCapability5 } from "@vibeorm/schema";
6861
+ import { VibeError as VibeError17, unsupportedCapability as unsupportedCapability6 } from "@vibeorm/schema";
6798
6862
  import { NATIVE_RLS, getSqlDialect as getSqlDialect2, renderPostgresExplain, renderPostgresWorkload, renderStatement as renderStatement2 } from "@vibeorm/sql";
6799
6863
  var PLAN_DEFAULTS = Object.freeze({ maxNodes: 200, maxConditionLength: 2000 });
6800
6864
  var CONDITION_KEYS = [
@@ -6813,7 +6877,7 @@ var CONDITION_KEYS = [
6813
6877
  "Output"
6814
6878
  ];
6815
6879
  function planError(params) {
6816
- return new VibeError15({ code: "VIBE_ADAPTER", message: params.message, meta: {} });
6880
+ return new VibeError17({ code: "VIBE_ADAPTER", message: params.message, meta: {} });
6817
6881
  }
6818
6882
  function asRecord(value) {
6819
6883
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
@@ -6846,14 +6910,14 @@ function parsePostgresPlan(params) {
6846
6910
  const maxNodes = params.maxNodes ?? PLAN_DEFAULTS.maxNodes;
6847
6911
  const includeLiterals = params.includeLiterals === true;
6848
6912
  if (!Number.isInteger(maxNodes) || maxNodes < 1) {
6849
- throw new VibeError15({ code: "VIBE_CONFIG", message: `maxNodes must be a positive integer, got ${String(maxNodes)}`, meta: { maxNodes } });
6913
+ throw new VibeError17({ code: "VIBE_CONFIG", message: `maxNodes must be a positive integer, got ${String(maxNodes)}`, meta: { maxNodes } });
6850
6914
  }
6851
6915
  let parsed = payload;
6852
6916
  if (typeof payload === "string") {
6853
6917
  try {
6854
6918
  parsed = JSON.parse(payload);
6855
6919
  } catch {
6856
- throw new VibeError15({
6920
+ throw new VibeError17({
6857
6921
  code: "VIBE_ADAPTER",
6858
6922
  message: "EXPLAIN returned malformed JSON",
6859
6923
  meta: { reason: "malformed-plan-json", mode }
@@ -6921,7 +6985,7 @@ function parsePostgresPlan(params) {
6921
6985
  var WRITE_LEADERS = ["INSERT", "UPDATE", "DELETE", "MERGE", "TRUNCATE", "CREATE", "DROP", "ALTER", "GRANT", "REVOKE", "COPY", "CALL", "DO"];
6922
6986
  var SIDE_EFFECT_CALLS = /\bpg_(?:try_)?advisory_(?:xact_)?lock(?:_shared)?\s*\(/i;
6923
6987
  function refuse(params) {
6924
- return new VibeError15({ code: "VIBE_VALIDATION", message: params.message, meta: params.meta ?? {} });
6988
+ return new VibeError17({ code: "VIBE_VALIDATION", message: params.message, meta: params.meta ?? {} });
6925
6989
  }
6926
6990
  function executableReadRefusal(params) {
6927
6991
  const normalized = normalizeSql({ text: params.text });
@@ -6972,7 +7036,7 @@ async function readPlanContext(params) {
6972
7036
  }
6973
7037
  function requirePostgres(params) {
6974
7038
  if (params.dialect !== "postgres") {
6975
- throw unsupportedCapability5({
7039
+ throw unsupportedCapability6({
6976
7040
  dialect: params.dialect,
6977
7041
  feature: "query plan inspection",
6978
7042
  hint: "plan inspection is PostgreSQL-shaped; operation tracing (telemetry) works on every dialect"
@@ -7051,7 +7115,7 @@ async function explainOnSession(params) {
7051
7115
  const context = await readPlanContext({ executor, dialect, rlsContextKeys: contextKeys });
7052
7116
  if (!context.representative) {
7053
7117
  if (params.requireRepresentativeContext === true) {
7054
- throw new VibeError15({
7118
+ throw new VibeError17({
7055
7119
  code: "VIBE_RLS_CONTEXT",
7056
7120
  message: `refusing to report a plan taken under a non-representative identity: ${context.reason ?? "role bypasses row policies"}`,
7057
7121
  meta: { currentUser: context.currentUser, bypassRls: context.bypassRls, superuser: context.superuser }
@@ -7127,7 +7191,7 @@ async function explainOperation(params) {
7127
7191
  });
7128
7192
  }
7129
7193
  // packages/runtime/src/diagnostics/statement-diagnostics.ts
7130
- import { VibeError as VibeError16 } from "@vibeorm/schema";
7194
+ import { VibeError as VibeError18 } from "@vibeorm/schema";
7131
7195
  import { renderPostgresWorkload as renderPostgresWorkload2 } from "@vibeorm/sql";
7132
7196
  var STATEMENT_DIAGNOSTICS_DEFAULTS = Object.freeze({
7133
7197
  slowerThanMs: 0,
@@ -7139,7 +7203,7 @@ var STATEMENT_DIAGNOSTICS_DEFAULTS = Object.freeze({
7139
7203
  });
7140
7204
  var EXPLAIN_MODES = ["off", "estimate", "analyze"];
7141
7205
  function configError(params) {
7142
- return new VibeError16({ code: "VIBE_CONFIG", message: params.message, meta: params.meta ?? {} });
7206
+ return new VibeError18({ code: "VIBE_CONFIG", message: params.message, meta: params.meta ?? {} });
7143
7207
  }
7144
7208
  function isExplainMode(value) {
7145
7209
  return typeof value === "string" && EXPLAIN_MODES.includes(value);
@@ -7265,7 +7329,7 @@ function summarizePlan(params) {
7265
7329
  };
7266
7330
  }
7267
7331
  function errorCode(error) {
7268
- return error instanceof VibeError16 ? error.code : "VIBE_INTERNAL";
7332
+ return error instanceof VibeError18 ? error.code : "VIBE_INTERNAL";
7269
7333
  }
7270
7334
  function createStatementDiagnostics(params) {
7271
7335
  const { config, adapter, dialect } = params;
@@ -7376,7 +7440,7 @@ function createStatementDiagnostics(params) {
7376
7440
  };
7377
7441
  }
7378
7442
  // packages/runtime/src/diagnostics/workload.ts
7379
- import { unsupportedCapability as unsupportedCapability6 } from "@vibeorm/schema";
7443
+ import { unsupportedCapability as unsupportedCapability7 } from "@vibeorm/schema";
7380
7444
  import { getSqlDialect as getSqlDialect3, renderPostgresWorkload as renderPostgresWorkload3 } from "@vibeorm/sql";
7381
7445
  var STATEMENTS_INFO_MIN_VERSION = 140000;
7382
7446
  var STATEMENTS_MIN_VERSION = 130000;
@@ -7409,7 +7473,7 @@ async function readAvailability(params) {
7409
7473
  async function readWorkloadStatistics(params) {
7410
7474
  const { executor } = params;
7411
7475
  if (params.dialect !== "postgres") {
7412
- throw unsupportedCapability6({
7476
+ throw unsupportedCapability7({
7413
7477
  dialect: params.dialect,
7414
7478
  feature: "workload statistics (pg_stat_statements)",
7415
7479
  hint: "server workload statistics are PostgreSQL-only; operation telemetry works on every dialect"
@@ -7487,7 +7551,7 @@ async function readWorkloadStatistics(params) {
7487
7551
  };
7488
7552
  }
7489
7553
  // packages/runtime/src/diagnostics/insight.ts
7490
- import { VibeError as VibeError17 } from "@vibeorm/schema";
7554
+ import { VibeError as VibeError19 } from "@vibeorm/schema";
7491
7555
  var DIAGNOSTIC_THRESHOLDS = Object.freeze({
7492
7556
  repeatThreshold: 5,
7493
7557
  minRepeatThreshold: 2,
@@ -7505,7 +7569,7 @@ function bounded(params) {
7505
7569
  if (value === undefined)
7506
7570
  return fallback;
7507
7571
  if (!Number.isInteger(value) || value < min || value > max) {
7508
- throw new VibeError17({
7572
+ throw new VibeError19({
7509
7573
  code: "VIBE_CONFIG",
7510
7574
  message: `${name} must be an integer between ${min} and ${max}, got ${String(value)}`,
7511
7575
  meta: { [name]: value }
@@ -7728,11 +7792,11 @@ function recommendFromPlan(params) {
7728
7792
  return findings.slice(0, maxFindings);
7729
7793
  }
7730
7794
  // packages/runtime/src/relation-loader.ts
7731
- import { VibeError as VibeError19 } from "@vibeorm/schema";
7795
+ import { VibeError as VibeError21 } from "@vibeorm/schema";
7732
7796
  import { renderStatement as renderStatement3 } from "@vibeorm/sql";
7733
7797
 
7734
7798
  // packages/runtime/src/computed.ts
7735
- import { VibeError as VibeError18 } from "@vibeorm/schema";
7799
+ import { VibeError as VibeError20 } from "@vibeorm/schema";
7736
7800
  function sameNeeds(a, b) {
7737
7801
  if (a.length !== b.length)
7738
7802
  return false;
@@ -7768,7 +7832,7 @@ function assertComputedManifest(params) {
7768
7832
  problems.push(`"${key}" is configured but missing from the generated client`);
7769
7833
  }
7770
7834
  if (problems.length > 0) {
7771
- throw new VibeError18({
7835
+ throw new VibeError20({
7772
7836
  code: "VIBE_STALE_CLIENT",
7773
7837
  message: `computed-field config changed since generate; run vibeorm generate \u2014 ${problems.join("; ")}`,
7774
7838
  meta: { problems }
@@ -7796,7 +7860,7 @@ function resolveRelationConcurrency(params) {
7796
7860
  if (concurrency === undefined)
7797
7861
  return 1;
7798
7862
  if (!Number.isInteger(concurrency) || concurrency < 1) {
7799
- throw new VibeError19({
7863
+ throw new VibeError21({
7800
7864
  code: "VIBE_CONFIG",
7801
7865
  message: `relationLoading.concurrency must be a positive integer \u2014 got ${String(concurrency)}`,
7802
7866
  meta: { concurrency }
@@ -7944,7 +8008,7 @@ function buildChildStatement(params) {
7944
8008
  if (window === undefined) {
7945
8009
  return {
7946
8010
  kind: "select",
7947
- table: { name: target.tableName },
8011
+ table: { name: target.tableName, ...target.namespace === undefined ? {} : { namespace: target.namespace } },
7948
8012
  columns,
7949
8013
  where,
7950
8014
  ...orderBy === undefined || orderBy.length === 0 ? {} : { orderBy }
@@ -7952,7 +8016,7 @@ function buildChildStatement(params) {
7952
8016
  }
7953
8017
  const inner = {
7954
8018
  kind: "select",
7955
- table: { name: target.tableName },
8019
+ table: { name: target.tableName, ...target.namespace === undefined ? {} : { namespace: target.namespace } },
7956
8020
  columns,
7957
8021
  where,
7958
8022
  rowNumber: { partitionBy: [...window.partitionBy], orderBy: orderBy ?? [], alias: WINDOW_ROW_ALIAS }
@@ -7981,7 +8045,7 @@ function chunkKeys(params) {
7981
8045
  const rendered = renderStatement3({ dialect: ctx.dialect, statement: build(keys.slice(0, 1)) });
7982
8046
  fixed = rendered.values.length - (expands ? arity : 1);
7983
8047
  if (fixed + arity > budget) {
7984
- throw new VibeError19({
8048
+ throw new VibeError21({
7985
8049
  code: "VIBE_UNSUPPORTED_CAPABILITY",
7986
8050
  message: `relation "${relation}" needs ${fixed + arity} bound parameters for its own predicate, more than ${ctx.dialect.name}'s ${budget}-parameter statement budget \u2014 narrow the nested filter`,
7987
8051
  meta: { relation, dialect: ctx.dialect.name, required: fixed + arity, budget }
@@ -8111,7 +8175,7 @@ async function loadManyToMany(params) {
8111
8175
  const link = node.link;
8112
8176
  const join = link.join;
8113
8177
  if (join === null) {
8114
- throw new VibeError19({
8178
+ throw new VibeError21({
8115
8179
  code: "VIBE_INTERNAL",
8116
8180
  message: `manyToMany relation "${node.name}" resolved without join-table wiring`
8117
8181
  });
@@ -8156,11 +8220,11 @@ async function loadManyToMany(params) {
8156
8220
  const where = nestedWhere === undefined ? membership : { kind: "and", operands: [membership, nestedWhere] };
8157
8221
  const base = {
8158
8222
  kind: "select",
8159
- table: { name: target.tableName },
8223
+ table: { name: target.tableName, ...target.namespace === undefined ? {} : { namespace: target.namespace } },
8160
8224
  columns: [...childColumns, { table: M2M_JOIN_ALIAS, name: join.parentColumn, alias: M2M_PARENT_ALIAS }],
8161
8225
  innerJoins: [
8162
8226
  {
8163
- table: { name: join.tableName, alias: M2M_JOIN_ALIAS },
8227
+ table: { name: join.tableName, ...join.namespace === undefined ? {} : { namespace: join.namespace }, alias: M2M_JOIN_ALIAS },
8164
8228
  on: [
8165
8229
  {
8166
8230
  left: { table: M2M_JOIN_ALIAS, name: join.childColumn },
@@ -8270,7 +8334,7 @@ async function loadCounts(params) {
8270
8334
  const where = filter === undefined ? membership : { kind: "and", operands: [membership, filter] };
8271
8335
  const base = {
8272
8336
  kind: "select",
8273
- table: { name: joinsChildTable ? target.tableName : table },
8337
+ table: { name: joinsChildTable ? target.tableName : table, ...(joinsChildTable || join === null ? target.namespace : join.namespace) === undefined ? {} : { namespace: joinsChildTable || join === null ? target.namespace : join.namespace } },
8274
8338
  columns: projectedColumns,
8275
8339
  selectExpr: { kind: "countAll", alias: COUNT_VALUE_ALIAS },
8276
8340
  where,
@@ -8282,7 +8346,7 @@ async function loadCounts(params) {
8282
8346
  ...base,
8283
8347
  innerJoins: [
8284
8348
  {
8285
- table: { name: join.tableName, alias: M2M_JOIN_ALIAS },
8349
+ table: { name: join.tableName, ...join?.namespace === undefined ? {} : { namespace: join.namespace }, alias: M2M_JOIN_ALIAS },
8286
8350
  on: [
8287
8351
  {
8288
8352
  left: { table: M2M_JOIN_ALIAS, name: join.childColumn },
@@ -8408,7 +8472,7 @@ async function attachLateralRelations(params) {
8408
8472
  try {
8409
8473
  parsed = JSON.parse(raw);
8410
8474
  } catch (cause) {
8411
- throw new VibeError19({
8475
+ throw new VibeError21({
8412
8476
  code: "VIBE_INTERNAL",
8413
8477
  message: `relation column "${column}" returned text that is not valid JSON`,
8414
8478
  meta: { relation: node.name },
@@ -8418,7 +8482,7 @@ async function attachLateralRelations(params) {
8418
8482
  }
8419
8483
  if (isList) {
8420
8484
  if (!Array.isArray(parsed)) {
8421
- throw new VibeError19({ code: "VIBE_INTERNAL", message: "to-many relation payload must be an array", meta: { relation: node.name } });
8485
+ throw new VibeError21({ code: "VIBE_INTERNAL", message: "to-many relation payload must be an array", meta: { relation: node.name } });
8422
8486
  }
8423
8487
  const children = parsed.map(decodePosition);
8424
8488
  for (const child of children) {
@@ -8459,7 +8523,7 @@ async function attachLateralRelations(params) {
8459
8523
  const raw = row[column];
8460
8524
  const count = typeof raw === "number" || typeof raw === "bigint" || typeof raw === "string" && /^\d+$/.test(raw) ? Number(raw) : NaN;
8461
8525
  if (!Number.isSafeInteger(count) || count < 0) {
8462
- throw new VibeError19({ code: "VIBE_INTERNAL", message: "relation count payload must be a non-negative safe integer", meta: { relation: selection.counts[index]?.name } });
8526
+ throw new VibeError21({ code: "VIBE_INTERNAL", message: "relation count payload must be a non-negative safe integer", meta: { relation: selection.counts[index]?.name } });
8463
8527
  }
8464
8528
  counts[selection.counts[index].name] = count;
8465
8529
  delete row[column];
@@ -8468,11 +8532,11 @@ async function attachLateralRelations(params) {
8468
8532
  }
8469
8533
  }
8470
8534
  // packages/runtime/src/views.ts
8471
- import { VibeError as VibeError21 } from "@vibeorm/schema";
8535
+ import { VibeError as VibeError23 } from "@vibeorm/schema";
8472
8536
 
8473
8537
  // packages/runtime/src/sql-access.ts
8474
8538
  import { Buffer as Buffer2 } from "buffer";
8475
- import { VibeError as VibeError20 } from "@vibeorm/schema";
8539
+ import { VibeError as VibeError22 } from "@vibeorm/schema";
8476
8540
  import { isSqlFragment as isSqlFragment2 } from "@vibeorm/sql";
8477
8541
  function containsSqlFragment(value, seen = new Set) {
8478
8542
  if (isSqlFragment2(value))
@@ -8497,7 +8561,7 @@ function containsSqlFragment(value, seen = new Set) {
8497
8561
  return false;
8498
8562
  }
8499
8563
  function restrictedSqlArgs(params) {
8500
- const refuse = () => params.refusal?.() ?? new VibeError20({ code: "VIBE_VALIDATION", message: `SQL fragments are unavailable through ${params.path}; use the unrestricted client`, meta: { path: params.path } });
8564
+ const refuse = () => params.refusal?.() ?? new VibeError22({ code: "VIBE_VALIDATION", message: `SQL fragments are unavailable through ${params.path}; use the unrestricted client`, meta: { path: params.path } });
8501
8565
  if (containsSqlFragment(params.value))
8502
8566
  throw refuse();
8503
8567
  const seen = new Map;
@@ -8559,13 +8623,13 @@ function restrictConflictPredicates(params) {
8559
8623
  const target = spec.target;
8560
8624
  const declared = conflictSchemas.get(params.meta)?.get(params.model.name)?.some((index) => typeof spec.where === "string" && index.where === spec.where && Array.isArray(target) && target.length === index.fields.length && index.fields.every((field, position) => field === target[position]));
8561
8625
  if (declared !== true)
8562
- throw new VibeError20({ code: "VIBE_VALIDATION", message: `${params.path}: ${key}.where must match a declared unique index and its target fields; free-form SQL requires the unrestricted client`, meta: { model: params.model.name, path: params.path } });
8626
+ throw new VibeError22({ code: "VIBE_VALIDATION", message: `${params.path}: ${key}.where must match a declared unique index and its target fields; free-form SQL requires the unrestricted client`, meta: { model: params.model.name, path: params.path } });
8563
8627
  }
8564
8628
  }
8565
8629
 
8566
8630
  // packages/runtime/src/views.ts
8567
8631
  function validationError6(params) {
8568
- return new VibeError21({ code: "VIBE_VALIDATION", message: params.message, meta: params.meta });
8632
+ return new VibeError23({ code: "VIBE_VALIDATION", message: params.message, meta: params.meta });
8569
8633
  }
8570
8634
 
8571
8635
  class ViewResult {
@@ -8919,7 +8983,7 @@ function createView(params) {
8919
8983
  for (const [clientName, mask] of resolved) {
8920
8984
  const delegate = models[clientName];
8921
8985
  if (delegate === undefined) {
8922
- throw new VibeError21({
8986
+ throw new VibeError23({
8923
8987
  code: "VIBE_INTERNAL",
8924
8988
  message: `view "${name}": no delegate for model "${mask.model.name}"`,
8925
8989
  meta: { view: name, model: mask.model.name }
@@ -8935,9 +8999,9 @@ function attachDefineView(params) {
8935
8999
  Object.defineProperty(client, "$defineView", { value, enumerable: true });
8936
9000
  }
8937
9001
  // packages/runtime/src/validators.ts
8938
- import { VibeError as VibeError22 } from "@vibeorm/schema";
9002
+ import { VibeError as VibeError24 } from "@vibeorm/schema";
8939
9003
  function validationFailed(params) {
8940
- return new VibeError22({
9004
+ return new VibeError24({
8941
9005
  code: "VIBE_VALIDATION",
8942
9006
  message: `validation failed for ${params.model}.${params.field}: ${params.issues[0]?.message ?? "invalid value"}`,
8943
9007
  meta: { model: params.model, field: params.field, issues: params.issues }
@@ -8946,7 +9010,7 @@ function validationFailed(params) {
8946
9010
  function validateValue(params) {
8947
9011
  const result = params.schema["~standard"].validate(params.value);
8948
9012
  if (result instanceof Promise) {
8949
- throw new VibeError22({
9013
+ throw new VibeError24({
8950
9014
  code: "VIBE_VALIDATION",
8951
9015
  message: `async validator on ${params.model}.${params.field} \u2014 write validators must be synchronous (validate before calling the client for async rules)`,
8952
9016
  meta: { model: params.model, field: params.field }
@@ -9069,10 +9133,10 @@ function deferPolicyOperation(params) {
9069
9133
  }
9070
9134
 
9071
9135
  // packages/runtime/src/policy.ts
9072
- import { VibeError as VibeError24 } from "@vibeorm/schema";
9136
+ import { VibeError as VibeError27 } from "@vibeorm/schema";
9073
9137
 
9074
9138
  // packages/runtime/src/module-context.ts
9075
- import { VibeError as VibeError23 } from "@vibeorm/schema";
9139
+ import { VibeError as VibeError25 } from "@vibeorm/schema";
9076
9140
  var binders = new WeakMap;
9077
9141
  function registerModuleBinder(params) {
9078
9142
  binders.set(params.client, params.bind);
@@ -9085,7 +9149,7 @@ function inheritReadOnlyModuleBinder(params) {
9085
9149
  function bindModuleContext(params) {
9086
9150
  const bind = binders.get(params.db);
9087
9151
  if (bind === undefined)
9088
- throw new VibeError23({
9152
+ throw new VibeError25({
9089
9153
  code: "VIBE_CONFIG",
9090
9154
  message: `Module ${params.artifact.manifest.id} needs an unrestricted handle from the same VibeORM runtime installation; scoped and foreign handles cannot attach package models`,
9091
9155
  meta: { reason: "module_handle", moduleId: params.artifact.manifest.id, protocol: params.artifact.manifest.protocol }
@@ -9094,9 +9158,10 @@ function bindModuleContext(params) {
9094
9158
  }
9095
9159
 
9096
9160
  // packages/runtime/src/read-only.ts
9097
- import { ReadOnlyClientError } from "@vibeorm/schema";
9161
+ import { ReadOnlyClientError, VibeError as VibeError26 } from "@vibeorm/schema";
9098
9162
  var READ_DELEGATE_METHODS = Object.freeze([
9099
9163
  "findMany",
9164
+ "findPage",
9100
9165
  "findFirst",
9101
9166
  "findFirstOrThrow",
9102
9167
  "findUnique",
@@ -9124,6 +9189,42 @@ var DELEGATE_METHOD_ACCESS = Object.freeze(Object.fromEntries([
9124
9189
  function delegateMethodAccess(params) {
9125
9190
  return Object.hasOwn(DELEGATE_METHOD_ACCESS, params.method) ? DELEGATE_METHOD_ACCESS[params.method] : undefined;
9126
9191
  }
9192
+ function createDelegateMethodClassifier(params) {
9193
+ const context = contexts.get(params.db);
9194
+ if (context === undefined)
9195
+ throw new VibeError26({
9196
+ code: "VIBE_CONFIG",
9197
+ message: "Configured classification requires a registered VibeORM client handle",
9198
+ meta: { reason: "delegate-classifier-handle" }
9199
+ });
9200
+ context.assertActive?.();
9201
+ return ({ method, model }) => {
9202
+ context.assertActive?.();
9203
+ const target = model === undefined ? undefined : context.meta.models.find((entry) => entry.name === model || entry.clientName === model);
9204
+ if (model !== undefined && target === undefined)
9205
+ return;
9206
+ const core = delegateMethodAccess({ method });
9207
+ if (core !== undefined)
9208
+ return core;
9209
+ const parts = method.split(".");
9210
+ if (parts.length > 2)
9211
+ return;
9212
+ const [property, member] = parts;
9213
+ const mount = context.mounts.find((entry) => entry.property === property && (target === undefined ? entry.scope === "client" : entry.scope === "model" && entry.model === target.name));
9214
+ if (mount === undefined || mount.readOnly === undefined)
9215
+ return;
9216
+ const root = params.db;
9217
+ const owner = target === undefined ? root : root.$models?.[target.name];
9218
+ if (typeof owner !== "object" || owner === null || property === undefined)
9219
+ return;
9220
+ const value = owner[property];
9221
+ if (mount.readOnly === true)
9222
+ return member === undefined && typeof value === "function" ? "read" : undefined;
9223
+ if (member === undefined || !mount.readOnly.includes(member) || typeof value !== "object" || value === null)
9224
+ return;
9225
+ return typeof value[member] === "function" ? "read" : undefined;
9226
+ };
9227
+ }
9127
9228
  var CLIENT_MEMBER_ACCESS = Object.freeze({
9128
9229
  $models: "rebuilt",
9129
9230
  $on: "forwarded",
@@ -9323,8 +9424,11 @@ function readOnlyOver(params) {
9323
9424
  const existing = facades.get(params.client);
9324
9425
  if (existing !== undefined)
9325
9426
  return existing;
9326
- const built = buildReadOnly(params);
9427
+ const context = contexts.get(params.client) ?? params.context;
9428
+ const built = buildReadOnly({ client: params.client, context });
9327
9429
  inheritReadOnlyModuleBinder({ from: params.client, to: built });
9430
+ inheritTransactionObservation({ from: params.client, to: built });
9431
+ contexts.set(built, context);
9328
9432
  facades.set(params.client, built);
9329
9433
  return built;
9330
9434
  }
@@ -9332,7 +9436,8 @@ function attachReadOnly(params) {
9332
9436
  const context = {
9333
9437
  meta: params.meta,
9334
9438
  mounts: params.mounts ?? [],
9335
- operations: params.operations
9439
+ operations: params.operations,
9440
+ ...params.assertActive === undefined ? {} : { assertActive: params.assertActive }
9336
9441
  };
9337
9442
  contexts.set(params.client, context);
9338
9443
  Object.defineProperty(params.client, "$readOnly", {
@@ -9346,6 +9451,7 @@ function inheritReadOnly(params) {
9346
9451
  if (context === undefined)
9347
9452
  return;
9348
9453
  contexts.set(params.to, context);
9454
+ inheritTransactionObservation({ from: params.from, to: params.to });
9349
9455
  Object.defineProperty(params.to, "$readOnly", {
9350
9456
  value: () => readOnlyOver({ client: params.to, context }),
9351
9457
  enumerable: true,
@@ -9355,7 +9461,7 @@ function inheritReadOnly(params) {
9355
9461
 
9356
9462
  // packages/runtime/src/policy.ts
9357
9463
  function policyError(message, meta) {
9358
- return new VibeError24({ code: "VIBE_VALIDATION", message, meta: meta ?? {} });
9464
+ return new VibeError27({ code: "VIBE_VALIDATION", message, meta: meta ?? {} });
9359
9465
  }
9360
9466
  function policiedModels(meta) {
9361
9467
  return meta.models.filter((model) => model.policy !== undefined);
@@ -9705,9 +9811,10 @@ function scopedDelegate(params) {
9705
9811
  const pkWhere = pk.length === 1 ? { [pk[0]]: target[pk[0]] } : { [pkClientKey()]: Object.fromEntries(pk.map((name) => [name, target[name]])) };
9706
9812
  return write(raw, pkWhere);
9707
9813
  };
9708
- const notFound = (method) => new VibeError24({ code: "VIBE_NOT_FOUND", message: `${method} on ${model.name}: no row matches the unique where inside the bound policy context`, meta: { model: model.name, method } });
9814
+ const notFound = (method) => new VibeError27({ code: "VIBE_NOT_FOUND", message: `${method} on ${model.name}: no row matches the unique where inside the bound policy context`, meta: { model: model.name, method } });
9709
9815
  return {
9710
9816
  findMany: (args) => base.findMany(scopeFind(args)),
9817
+ findPage: (args) => base.findPage(scopeFind(args)),
9711
9818
  findFirst: (args) => base.findFirst(scopeFind(args)),
9712
9819
  findFirstOrThrow: (args) => base.findFirstOrThrow(scopeFind(args)),
9713
9820
  findUnique: (args) => base.findFirst(scopeUnique(args)),
@@ -9739,7 +9846,7 @@ function scopedDelegate(params) {
9739
9846
  })
9740
9847
  })),
9741
9848
  upsertMany: () => {
9742
- throw new VibeError24({
9849
+ throw new VibeError27({
9743
9850
  code: "VIBE_UNSUPPORTED_CAPABILITY",
9744
9851
  message: "upsertMany is not available on a policy-bound client: its conflict target is not policy-checked yet",
9745
9852
  meta: { model: model.name }
@@ -9748,7 +9855,7 @@ function scopedDelegate(params) {
9748
9855
  updateManyAndReturn: (args) => deferred(() => {
9749
9856
  const run = base.updateManyAndReturn;
9750
9857
  if (run === undefined) {
9751
- throw new VibeError24({
9858
+ throw new VibeError27({
9752
9859
  code: "VIBE_UNSUPPORTED_CAPABILITY",
9753
9860
  message: "updateManyAndReturn is not available on this delegate",
9754
9861
  meta: { model: model.name }
@@ -9807,6 +9914,7 @@ function globalDelegate(params) {
9807
9914
  const payload = (value, phase) => forceWriteData({ meta, model, data: value ?? {}, context, phase });
9808
9915
  const overrides = {
9809
9916
  findMany: (args) => base.findMany(readArgs(args)),
9917
+ findPage: (args) => base.findPage(readArgs(args)),
9810
9918
  findFirst: (args) => base.findFirst(readArgs(args)),
9811
9919
  findFirstOrThrow: (args) => base.findFirstOrThrow(readArgs(args)),
9812
9920
  findUnique: (args) => base.findUnique(readArgs(args)),
@@ -9822,7 +9930,7 @@ function globalDelegate(params) {
9822
9930
  updateManyAndReturn: (args) => deferred(() => {
9823
9931
  const run = base.updateManyAndReturn;
9824
9932
  if (run === undefined) {
9825
- throw new VibeError24({
9933
+ throw new VibeError27({
9826
9934
  code: "VIBE_UNSUPPORTED_CAPABILITY",
9827
9935
  message: "updateManyAndReturn is not available on this delegate"
9828
9936
  });
@@ -9833,7 +9941,7 @@ function globalDelegate(params) {
9833
9941
  upsertMany: (args) => deferred(() => {
9834
9942
  if (params.policyBound === false)
9835
9943
  return base.upsertMany(args);
9836
- throw new VibeError24({
9944
+ throw new VibeError27({
9837
9945
  code: "VIBE_UNSUPPORTED_CAPABILITY",
9838
9946
  message: "upsertMany is not available on a policy-bound client: its conflict target is not policy-checked yet"
9839
9947
  });
@@ -10004,7 +10112,7 @@ function attachPolicy(params) {
10004
10112
  });
10005
10113
  }
10006
10114
  // packages/runtime/src/scoped.ts
10007
- import { ScopedQueryError, VibeError as VibeError25 } from "@vibeorm/schema";
10115
+ import { ScopedQueryError, VibeError as VibeError28 } from "@vibeorm/schema";
10008
10116
  function refusal(params) {
10009
10117
  return new ScopedQueryError(params);
10010
10118
  }
@@ -10728,7 +10836,7 @@ function createScopeRewriter(params) {
10728
10836
  })
10729
10837
  };
10730
10838
  }
10731
- var FIND_LIKE = ["findMany", "findFirst", "findFirstOrThrow", "count", "aggregate", "groupBy"];
10839
+ var FIND_LIKE = ["findPage", "findMany", "findFirst", "findFirstOrThrow", "count", "aggregate", "groupBy"];
10732
10840
  function rewriteScopedCall(params) {
10733
10841
  const { meta, resolved, scope, preds, method } = params;
10734
10842
  const ctx = { meta, resolved, scope, preds };
@@ -10857,6 +10965,7 @@ function scopedDelegate2(params) {
10857
10965
  };
10858
10966
  return {
10859
10967
  findMany: (args) => run("findMany", args),
10968
+ findPage: (args) => run("findPage", args),
10860
10969
  findFirst: (args) => run("findFirst", args),
10861
10970
  findFirstOrThrow: (args) => run("findFirstOrThrow", args),
10862
10971
  findUnique: (args) => run("findUnique", args),
@@ -10960,7 +11069,7 @@ function attachScoped(params) {
10960
11069
  Object.defineProperty(client, "$scoped", {
10961
11070
  value: (config) => {
10962
11071
  if (!isPlainObject8(config) || !isPlainObject8(config.models)) {
10963
- throw new VibeError25({
11072
+ throw new VibeError28({
10964
11073
  code: "VIBE_VALIDATION",
10965
11074
  message: "$scoped takes { scope: string | number | bigint | null, models: { <Model>: \u2026 } }"
10966
11075
  });
@@ -10976,7 +11085,7 @@ function attachScoped(params) {
10976
11085
  }
10977
11086
  const scope = config.scope;
10978
11087
  if (scope !== null && typeof scope !== "string" && typeof scope !== "number" && typeof scope !== "bigint") {
10979
- throw new VibeError25({
11088
+ throw new VibeError28({
10980
11089
  code: "VIBE_VALIDATION",
10981
11090
  message: `$scoped: scope must be a string, number, bigint or null \u2014 got ${typeof scope}`
10982
11091
  });
@@ -10992,7 +11101,7 @@ function attachScoped(params) {
10992
11101
  });
10993
11102
  }
10994
11103
  // packages/runtime/src/rls-readiness.ts
10995
- import { VibeError as VibeError26, assertValidSchemaIR, unsupportedCapability as unsupportedCapability7 } from "@vibeorm/schema";
11104
+ import { VibeError as VibeError29, assertValidSchemaIR, unsupportedCapability as unsupportedCapability8 } from "@vibeorm/schema";
10996
11105
  import { NATIVE_RLS as NATIVE_RLS2, getSqlDialect as getSqlDialect4, renderRlsPolicy, renderRlsRole, NATIVE_RLS_PROBE_POLICY, renderRlsReadinessQuery, renderRlsProbeTable } from "@vibeorm/sql";
10997
11106
  import { RLS_READINESS_SQL, NATIVE_RLS_PROBE_POLICY as NATIVE_RLS_PROBE_POLICY2 } from "@vibeorm/sql";
10998
11107
  function textOf(params) {
@@ -11016,7 +11125,7 @@ function intOf(params) {
11016
11125
  return Number.parseInt(value, 10);
11017
11126
  }
11018
11127
  function unreadableCatalog(params) {
11019
- return new VibeError26({
11128
+ return new VibeError29({
11020
11129
  code: "VIBE_ADAPTER",
11021
11130
  message: `native RLS readiness could not read the "${params.key}" result of the folded catalog read: ${params.detail}. ` + "The inspection is refused rather than treated as an empty result set.",
11022
11131
  meta: { result: params.key }
@@ -11072,10 +11181,10 @@ function unprotectedTablesOf(params) {
11072
11181
  function requireNativeRls(params) {
11073
11182
  const dialect = getSqlDialect4({ dialect: params.adapter.dialect });
11074
11183
  if (!dialect.capabilities.nativeRowLevelSecurity) {
11075
- throw unsupportedCapability7({ dialect: dialect.name, feature: "nativeRowLevelSecurity" });
11184
+ throw unsupportedCapability8({ dialect: dialect.name, feature: "nativeRowLevelSecurity" });
11076
11185
  }
11077
11186
  if (params.schema.rls === undefined) {
11078
- throw new VibeError26({
11187
+ throw new VibeError29({
11079
11188
  code: "VIBE_CONFIG",
11080
11189
  message: "Native row-level security readiness requires a schema that declares native RLS"
11081
11190
  });
@@ -11092,24 +11201,27 @@ async function probeExpressions(params) {
11092
11201
  if (tables.length === 0)
11093
11202
  return { available: true, expressions: [] };
11094
11203
  return adapter.transaction(async (tx) => {
11095
- const current = await tx.execute(renderRlsReadinessQuery({ dialect, query: "readSearchPath" }));
11204
+ const current = await tx.execute({ ...renderRlsReadinessQuery({ dialect, query: "readSearchPath" }), effect: "read" });
11096
11205
  const searchPath = current[0] === undefined ? "" : textOf({ row: current[0], key: "searchPath" });
11097
- await tx.execute(renderRlsReadinessQuery({ dialect, query: "setSearchPath", searchPath: "" }));
11206
+ await tx.execute({ ...renderRlsReadinessQuery({ dialect, query: "setSearchPath", searchPath: "" }), effect: "read" });
11098
11207
  for (const entry of params.desired === undefined ? tables : []) {
11099
- await tx.executeUnsafe(renderRlsProbeTable({ dialect, table: entry.table, action: "create" }));
11100
- await tx.executeUnsafe(renderRlsPolicy({
11101
- dialect,
11102
- schema,
11103
- model: entry.model,
11104
- policyName: NATIVE_RLS_PROBE_POLICY,
11105
- targetSchema: "pg_temp"
11106
- }));
11208
+ await tx.executeUnsafe({ ...renderRlsProbeTable({ dialect, table: entry.table, action: "create" }), effect: "read" });
11209
+ await tx.executeUnsafe({
11210
+ ...renderRlsPolicy({
11211
+ dialect,
11212
+ schema,
11213
+ model: entry.model,
11214
+ policyName: NATIVE_RLS_PROBE_POLICY,
11215
+ targetSchema: "pg_temp"
11216
+ }),
11217
+ effect: "read"
11218
+ });
11107
11219
  }
11108
- const rows = await tx.execute(renderRlsReadinessQuery({ dialect, query: "expressions" }));
11220
+ const rows = await tx.execute({ ...renderRlsReadinessQuery({ dialect, query: "expressions" }), effect: "read" });
11109
11221
  for (const entry of params.desired === undefined ? tables : []) {
11110
- await tx.executeUnsafe(renderRlsProbeTable({ dialect, table: entry.table, action: "drop" }));
11222
+ await tx.executeUnsafe({ ...renderRlsProbeTable({ dialect, table: entry.table, action: "drop" }), effect: "read" });
11111
11223
  }
11112
- await tx.execute(renderRlsReadinessQuery({ dialect, query: "setSearchPath", searchPath }));
11224
+ await tx.execute({ ...renderRlsReadinessQuery({ dialect, query: "setSearchPath", searchPath }), effect: "read" });
11113
11225
  return {
11114
11226
  available: true,
11115
11227
  expressions: [...rows.filter((row) => params.desired === undefined || row.probe === false).map((row) => ({
@@ -11366,7 +11478,7 @@ async function inspectNativeRlsTransaction(params) {
11366
11478
  const dialect = requireNativeRls({ adapter, schema });
11367
11479
  const protectedTables = protectedTablesOf({ schema });
11368
11480
  const unprotected = unprotectedTablesOf({ schema });
11369
- const catalogRows = await adapter.execute(renderRlsReadinessQuery({ dialect, query: "catalog" }));
11481
+ const catalogRows = await adapter.execute({ ...renderRlsReadinessQuery({ dialect, query: "catalog" }), effect: "read" });
11370
11482
  const catalog = catalogRows[0] ?? {};
11371
11483
  const identityRow = catalogRowsOf({ row: catalog, key: "identity" })[0] ?? {};
11372
11484
  const identity = {
@@ -11476,7 +11588,7 @@ async function inspectNativeRls(params) {
11476
11588
  const embeddedRole = adapter.provider === "pglite" ? requireEmbeddedRole({ role: params.runtimeRole }) : undefined;
11477
11589
  return adapter.transaction(async (tx) => {
11478
11590
  if (embeddedRole !== undefined) {
11479
- await tx.executeUnsafe(renderRlsRole({ dialect: getSqlDialect4({ dialect: adapter.dialect }), role: embeddedRole }));
11591
+ await tx.executeUnsafe({ ...renderRlsRole({ dialect: getSqlDialect4({ dialect: adapter.dialect }), role: embeddedRole }), effect: "read" });
11480
11592
  }
11481
11593
  return inspectNativeRlsTransaction({
11482
11594
  adapter: tx,
@@ -11488,7 +11600,7 @@ async function inspectNativeRls(params) {
11488
11600
  function requireEmbeddedRole(params) {
11489
11601
  const { role } = params;
11490
11602
  if (typeof role !== "string" || role.length === 0 || role.includes("\x00")) {
11491
- throw new VibeError26({
11603
+ throw new VibeError29({
11492
11604
  code: "VIBE_CONFIG",
11493
11605
  message: "PGlite native row-level security requires a pre-existing restricted runtime role (nativeRls.runtimeRole) \u2014 its default embedded session is privileged and bypasses every policy",
11494
11606
  meta: { provider: "pglite" }
@@ -11500,7 +11612,7 @@ function assertNativeRlsReady(params) {
11500
11612
  const { report } = params;
11501
11613
  if (report.ready)
11502
11614
  return;
11503
- throw new VibeError26({
11615
+ throw new VibeError29({
11504
11616
  code: "VIBE_CONFIG",
11505
11617
  message: `Native row-level security is not ready on this database: ${report.problems.map((problem) => `${problem.name} (${problem.status})`).join(", ")}`,
11506
11618
  meta: {
@@ -11525,17 +11637,114 @@ function formatNativeRlsReport(params) {
11525
11637
  return lines;
11526
11638
  }
11527
11639
  // packages/runtime/src/database-module.ts
11528
- import { createHash } from "crypto";
11529
- import { VibeError as VibeError31, assertValidSchemaIR as assertValidSchemaIR3, providerToDialect } from "@vibeorm/schema";
11640
+ import { createHash as createHash2 } from "crypto";
11641
+ import { VibeError as VibeError35, assertValidSchemaIR as assertValidSchemaIR3, prepareDatabaseModuleSchema, providerToDialect } from "@vibeorm/schema";
11642
+
11643
+ // packages/runtime/src/client.ts
11644
+ import { AsyncLocalStorage } from "async_hooks";
11645
+
11646
+ // packages/runtime/src/find-page.ts
11647
+ import { VibeError as VibeError30 } from "@vibeorm/schema";
11648
+
11649
+ // packages/runtime/src/keyset-projection.ts
11650
+ function keysetProjection(params) {
11651
+ const { plan, select, omit } = params;
11652
+ const names = plan.keys.map((key) => key.field.name);
11653
+ if (select !== undefined) {
11654
+ const hidden = names.filter((name) => select[name] !== true);
11655
+ if (hidden.length === 0)
11656
+ return { select, hidden };
11657
+ const widened = { ...select };
11658
+ for (const name of hidden)
11659
+ widened[name] = true;
11660
+ return { select: widened, hidden };
11661
+ }
11662
+ if (omit !== undefined) {
11663
+ const hidden = names.filter((name) => omit[name] === true);
11664
+ if (hidden.length === 0)
11665
+ return { omit, hidden };
11666
+ const narrowed = { ...omit };
11667
+ for (const name of hidden)
11668
+ narrowed[name] = false;
11669
+ return { omit: narrowed, hidden };
11670
+ }
11671
+ return { hidden: [] };
11672
+ }
11673
+
11674
+ // packages/runtime/src/find-page.ts
11675
+ var PAGE_ARGUMENTS = new Set([
11676
+ "where",
11677
+ "orderBy",
11678
+ "take",
11679
+ "after",
11680
+ "select",
11681
+ "include",
11682
+ "omit",
11683
+ "relationStrategy",
11684
+ "keyset"
11685
+ ]);
11686
+ function validatePageArgs(params) {
11687
+ const { model, args } = params;
11688
+ if (typeof args !== "object" || args === null || Array.isArray(args)) {
11689
+ throw new VibeError30({ code: "VIBE_VALIDATION", message: `${model}.findPage requires an argument object`, meta: { model, reason: "keyset-page-args" } });
11690
+ }
11691
+ for (const key of Object.keys(args)) {
11692
+ if (!PAGE_ARGUMENTS.has(key)) {
11693
+ throw new VibeError30({ code: "VIBE_VALIDATION", message: `${model}.findPage does not accept ${key}`, meta: { model, argument: key, reason: "keyset-page-argument" } });
11694
+ }
11695
+ }
11696
+ const take = "take" in args ? args.take : undefined;
11697
+ if (typeof take !== "number" || !Number.isSafeInteger(take) || take < 1 || take > KEYSET_MAX_PAGE_SIZE) {
11698
+ throw new VibeError30({ code: "VIBE_VALIDATION", message: `findPage take must be an integer between 1 and ${KEYSET_MAX_PAGE_SIZE}`, meta: { model, reason: "keyset-page-size" } });
11699
+ }
11700
+ return args;
11701
+ }
11702
+ function preparePage(params) {
11703
+ const { meta, model, dialect, args } = params;
11704
+ const plan = compileKeysetOrderPlan({
11705
+ model,
11706
+ dialect,
11707
+ terms: compileKeysetOrderInputs({ meta, model, dialect, orderBy: args.orderBy }),
11708
+ ...parseKeysetOptions({ model, value: args.keyset })
11709
+ });
11710
+ const projection = keysetProjection({
11711
+ plan,
11712
+ select: args.select,
11713
+ omit: args.omit
11714
+ });
11715
+ return {
11716
+ plan,
11717
+ args: {
11718
+ ...args,
11719
+ take: args.take + 1,
11720
+ ...projection.select === undefined ? {} : { select: projection.select },
11721
+ ...projection.omit === undefined ? {} : { omit: projection.omit }
11722
+ }
11723
+ };
11724
+ }
11725
+ function pageContinuation(params) {
11726
+ const { plan, rows, take, after } = params;
11727
+ const first = rows[0];
11728
+ if (typeof after === "string" && first !== undefined && keysetRowIsAfter({
11729
+ keys: plan.keys,
11730
+ row: keysetRowValues({ plan, row: first }),
11731
+ position: decodeKeysetToken({ plan, token: after })
11732
+ }) === false) {
11733
+ throw new VibeError30({ code: "VIBE_DATA_INVALID", message: `keyset page for ${plan.model} is not advancing; check ordering precision`, meta: { model: plan.model, reason: "keyset-position-not-advancing" } });
11734
+ }
11735
+ const last = rows[take - 1];
11736
+ return rows.length > take && last !== undefined ? encodeKeysetToken({ plan, row: last }) : null;
11737
+ }
11530
11738
 
11531
11739
  // packages/runtime/src/client.ts
11532
11740
  import { compileSql } from "@vibeorm/sql";
11533
- import { RlsContextError as RlsContextError2, VibeError as VibeError30, assertValidSchemaIR as assertValidSchemaIR2, unsupportedCapability as unsupportedCapability8 } from "@vibeorm/schema";
11741
+ import { RlsContextError as RlsContextError2, VibeError as VibeError34, assertValidSchemaIR as assertValidSchemaIR2, unsupportedCapability as unsupportedCapability9 } from "@vibeorm/schema";
11534
11742
  import { ADVISORY_LOCK_RESULT_COLUMN, ParamCollector, getSqlDialect as getSqlDialect5, renderRlsContext, renderRlsPolicy as renderRlsPolicy2, renderRlsRole as renderRlsRole2, renderStatement as renderStatement5 } from "@vibeorm/sql";
11535
11743
 
11536
11744
  // packages/runtime/src/render-cache.ts
11537
11745
  import {
11538
11746
  isSqlFragment as isSqlFragment3,
11747
+ isNativeEnumArrayParameter,
11539
11748
  isDbNowMarker,
11540
11749
  isJsonParamCell,
11541
11750
  isListSetOperation,
@@ -11587,7 +11796,22 @@ function addCol(walk, column) {
11587
11796
  addIdent(walk, column.alias);
11588
11797
  }
11589
11798
  }
11799
+ function addParameter(walk, value) {
11800
+ if (isNativeEnumArrayParameter(value)) {
11801
+ walk.key += "enumArray";
11802
+ addIdent(walk, value.type.namespace);
11803
+ addIdent(walk, value.type.name);
11804
+ walk.values.push(value.value);
11805
+ return;
11806
+ }
11807
+ walk.key += "param";
11808
+ walk.values.push(value);
11809
+ }
11590
11810
  function addTable(walk, table) {
11811
+ if (table.namespace !== undefined) {
11812
+ walk.key += "namespace";
11813
+ addIdent(walk, table.namespace);
11814
+ }
11591
11815
  addIdent(walk, table.name);
11592
11816
  if (table.alias !== undefined) {
11593
11817
  walk.key += "@";
@@ -11609,7 +11833,7 @@ function addSetEntry(walk, name, value) {
11609
11833
  if (isSetOperation(value)) {
11610
11834
  walk.key += `=o${value.__op}`;
11611
11835
  addIdent(walk, name);
11612
- walk.values.push(value.value);
11836
+ addParameter(walk, value.value);
11613
11837
  return;
11614
11838
  }
11615
11839
  if (isDbNowMarker(value)) {
@@ -11622,12 +11846,12 @@ function addSetEntry(walk, name, value) {
11622
11846
  if (isListSetOperation(value)) {
11623
11847
  walk.key += `=l${value.__listOp}`;
11624
11848
  addIdent(walk, name);
11625
- walk.values.push(value.value);
11849
+ addParameter(walk, value.value);
11626
11850
  return;
11627
11851
  }
11628
11852
  walk.key += "=v";
11629
11853
  addIdent(walk, name);
11630
- walk.values.push(value);
11854
+ addParameter(walk, value);
11631
11855
  }
11632
11856
  function addReturning(walk, returning) {
11633
11857
  if (returning === undefined || returning.length === 0) {
@@ -11651,7 +11875,7 @@ function walkExpr(walk, dialect, expr) {
11651
11875
  }
11652
11876
  walk.key += `c${expr.op}`;
11653
11877
  addCol(walk, expr.column);
11654
- walk.values.push(expr.value);
11878
+ addParameter(walk, expr.value);
11655
11879
  return true;
11656
11880
  case "cmpCol":
11657
11881
  walk.key += `k${expr.op}`;
@@ -11670,7 +11894,7 @@ function walkExpr(walk, dialect, expr) {
11670
11894
  walk.key += expr.negate === true ? "i1" : "i0";
11671
11895
  addCol(walk, expr.column);
11672
11896
  if (dialect.inArrayStrategy === "any") {
11673
- walk.values.push([...expr.values]);
11897
+ addParameter(walk, Array.isArray(expr.values) ? [...expr.values] : expr.values);
11674
11898
  } else {
11675
11899
  walk.key += `#${expr.values.length}`;
11676
11900
  for (const value of expr.values)
@@ -11730,22 +11954,22 @@ function walkExpr(walk, dialect, expr) {
11730
11954
  case "aggCmp":
11731
11955
  walk.key += `g${expr.op}`;
11732
11956
  addAgg(walk, expr.agg);
11733
- walk.values.push(expr.value);
11957
+ addParameter(walk, expr.value);
11734
11958
  return true;
11735
11959
  case "arrayHas":
11736
11960
  walk.key += expr.negate === true ? "h1" : "h0";
11737
11961
  addCol(walk, expr.column);
11738
- walk.values.push(expr.value);
11962
+ addParameter(walk, expr.value);
11739
11963
  return true;
11740
11964
  case "arrayContainsAll":
11741
11965
  walk.key += "H";
11742
11966
  addCol(walk, expr.column);
11743
- walk.values.push([...expr.values]);
11967
+ addParameter(walk, Array.isArray(expr.values) ? [...expr.values] : expr.values);
11744
11968
  return true;
11745
11969
  case "arrayOverlaps":
11746
11970
  walk.key += "V";
11747
11971
  addCol(walk, expr.column);
11748
- walk.values.push([...expr.values]);
11972
+ addParameter(walk, Array.isArray(expr.values) ? [...expr.values] : expr.values);
11749
11973
  return true;
11750
11974
  case "arrayIsEmpty":
11751
11975
  walk.key += expr.empty ? "e1" : "e0";
@@ -12041,11 +12265,11 @@ function renderStatementCached(params) {
12041
12265
  }
12042
12266
 
12043
12267
  // packages/runtime/src/strict-args.ts
12044
- import { VibeError as VibeError27 } from "@vibeorm/schema";
12268
+ import { VibeError as VibeError31 } from "@vibeorm/schema";
12045
12269
  var SKIP = Symbol.for("vibeorm.skip");
12046
12270
  function explicitUndefined(params) {
12047
12271
  const { model, method, path } = params;
12048
- return new VibeError27({
12272
+ return new VibeError31({
12049
12273
  code: "VIBE_VALIDATION",
12050
12274
  message: `${model}.${method}(): explicit undefined at ${path} \u2014 an undefined value is refused ` + `because it would silently drop the property (widening a filter or losing a write). ` + `Omit the property, or pass SKIP to omit it deliberately; ` + `VibeClient({ strictArguments: false }) restores the legacy behaviour.`,
12051
12275
  meta: { model, method, path }
@@ -12251,10 +12475,10 @@ function bindRlsContext(params) {
12251
12475
  }
12252
12476
 
12253
12477
  // packages/runtime/src/telemetry/recorder.ts
12254
- import { VibeError as VibeError29 } from "@vibeorm/schema";
12478
+ import { VibeError as VibeError33 } from "@vibeorm/schema";
12255
12479
 
12256
12480
  // packages/runtime/src/telemetry/config.ts
12257
- import { VibeError as VibeError28 } from "@vibeorm/schema";
12481
+ import { VibeError as VibeError32 } from "@vibeorm/schema";
12258
12482
  var TELEMETRY_DEFAULTS = Object.freeze({
12259
12483
  captureSql: false,
12260
12484
  captureParameterValues: false,
@@ -12269,7 +12493,7 @@ var TELEMETRY_DEFAULTS = Object.freeze({
12269
12493
  latencyBucketsMs: Object.freeze([1, 5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000])
12270
12494
  });
12271
12495
  function configError2(params) {
12272
- return new VibeError28({
12496
+ return new VibeError32({
12273
12497
  code: "VIBE_CONFIG",
12274
12498
  message: `telemetry: ${params.message}`,
12275
12499
  ...params.meta === undefined ? {} : { meta: params.meta }
@@ -12357,7 +12581,7 @@ function deriveStage(params) {
12357
12581
  return "decode";
12358
12582
  }
12359
12583
  function errorCodeOf(error) {
12360
- return error instanceof VibeError29 ? error.code : undefined;
12584
+ return error instanceof VibeError33 ? error.code : undefined;
12361
12585
  }
12362
12586
  function newHistogram(bounds) {
12363
12587
  return { counts: new Array(bounds.length + 1).fill(0), sum: 0, count: 0 };
@@ -12740,7 +12964,7 @@ async function instrumentStatement(params) {
12740
12964
  // packages/runtime/src/client.ts
12741
12965
  function notFound2(params) {
12742
12966
  const { model, method } = params;
12743
- return new VibeError30({
12967
+ return new VibeError34({
12744
12968
  code: "VIBE_NOT_FOUND",
12745
12969
  message: `no ${model} record matched the where clause of ${method}()`,
12746
12970
  meta: { model, method }
@@ -12748,7 +12972,7 @@ function notFound2(params) {
12748
12972
  }
12749
12973
  function transactionLifecycleRefusal(params) {
12750
12974
  const { method } = params;
12751
- return new VibeError30({
12975
+ return new VibeError34({
12752
12976
  code: "VIBE_VALIDATION",
12753
12977
  message: `${method}() is not available on a transaction client \u2014 the connection is owned by the open transaction; call it on the client that started the transaction`,
12754
12978
  meta: { method, inTransaction: true }
@@ -12756,7 +12980,7 @@ function transactionLifecycleRefusal(params) {
12756
12980
  }
12757
12981
  function viewIsReadOnly(params) {
12758
12982
  const { model, method } = params;
12759
- return new VibeError30({
12983
+ return new VibeError34({
12760
12984
  code: "VIBE_VALIDATION",
12761
12985
  message: `${model} is a view \u2014 ${method}() is not available on views (they are read-only); write to the underlying table instead`,
12762
12986
  meta: { model, method }
@@ -12863,7 +13087,7 @@ async function engineTransaction(params) {
12863
13087
  const support = engine.adapter.budgets?.transactionDeadline;
12864
13088
  const requested = options.deadline.enforcement ?? "between-statements";
12865
13089
  if (support === undefined || support === "unsupported" || requested === "cancel-running-statements" && support !== "cancel-running-statements") {
12866
- throw new VibeError30({
13090
+ throw new VibeError34({
12867
13091
  code: "VIBE_UNSUPPORTED_CAPABILITY",
12868
13092
  message: "the adapter does not declare support for the requested transaction deadline",
12869
13093
  meta: { provider: engine.adapter.provider, feature: "transactionDeadline", requested, supported: support ?? "undeclared" }
@@ -12876,10 +13100,10 @@ async function engineTransaction(params) {
12876
13100
  const execute = async () => {
12877
13101
  if (engine.rlsSchema !== undefined && engine.inTransaction !== true) {
12878
13102
  if (adapter.provider === "pglite") {
12879
- await adapter.executeUnsafe(renderRlsRole2({ dialect: engine.dialect, role: engine.options.nativeRls.runtimeRole }));
13103
+ await adapter.executeUnsafe({ ...renderRlsRole2({ dialect: engine.dialect, role: engine.options.nativeRls.runtimeRole }), effect: "read" });
12880
13104
  }
12881
13105
  if (engine.context !== undefined && Object.keys(engine.rlsSchema.rls.context).length > 0) {
12882
- await adapter.executeUnsafe(renderRlsContext({ dialect: engine.dialect, context: engine.rlsSchema.rls.context, values: engine.context.settings }));
13106
+ await adapter.executeUnsafe({ ...renderRlsContext({ dialect: engine.dialect, context: engine.rlsSchema.rls.context, values: engine.context.settings }), effect: "read" });
12883
13107
  }
12884
13108
  const readiness = await inspectNativeRlsTransaction({ adapter, schema: engine.rlsSchema, runtimeRole: engine.options.nativeRls?.runtimeRole, cacheKey: engine.rootIdentity });
12885
13109
  assertNativeRlsReady({ report: readiness });
@@ -13052,7 +13276,7 @@ class QueryPromise extends Promise {
13052
13276
  }
13053
13277
  #claim() {
13054
13278
  if (this.#started) {
13055
- throw new VibeError30({
13279
+ throw new VibeError34({
13056
13280
  code: "VIBE_VALIDATION",
13057
13281
  message: "$transaction([...]) needs operations that have not dispatched \u2014 pass delegate calls in the same tick they are created (this one was awaited or created earlier and already executed outside the transaction)"
13058
13282
  });
@@ -13097,6 +13321,21 @@ var LAZY_OPERATIONS = {
13097
13321
  refuseQueryPromise({ value: params.value, reason: params.reason });
13098
13322
  }
13099
13323
  };
13324
+ function statementEffect(params) {
13325
+ if (params.adapter.rowChanges === undefined)
13326
+ return;
13327
+ const { statement, dialect } = params;
13328
+ if (containsSqlFragment(statement))
13329
+ return "unknown";
13330
+ if (statement.kind === "select" || statement.kind === "advisoryLock" || statement.kind === "rlsContext" || statement.kind === "rlsRole")
13331
+ return "read";
13332
+ if (statement.kind === "insert") {
13333
+ if (dialect.upsertForm === "onDuplicateKey" && statement.onConflict !== undefined && !("doNothing" in statement.onConflict))
13334
+ return "unknown";
13335
+ return "write";
13336
+ }
13337
+ return statement.kind === "update" || statement.kind === "delete" ? "write" : "unknown";
13338
+ }
13100
13339
  async function runRows(params) {
13101
13340
  const { engine, plan } = params;
13102
13341
  const renderStarted = renderClock({ engine });
@@ -13116,17 +13355,19 @@ async function runRows(params) {
13116
13355
  rowCount: (value) => value.length,
13117
13356
  run: () => engine.adapter.execute({
13118
13357
  text: rendered.text,
13119
- values: bindValues({ adapter: engine.adapter, values: rendered.values })
13358
+ values: bindValues({ adapter: engine.adapter, values: rendered.values }),
13359
+ effect: statementEffect({ statement: plan.statement, dialect: engine.dialect, adapter: engine.adapter })
13120
13360
  })
13121
13361
  });
13122
13362
  return materializeRows({ dialect: engine.dialect.name, model: plan.model, rows, wire: engine.adapter.wire });
13123
13363
  }
13124
13364
  async function runBoundAffected(params) {
13125
- const { adapter, text, values } = params;
13365
+ const { adapter, text, values, effect } = params;
13366
+ const input = { text, values, ...effect === undefined ? {} : { effect } };
13126
13367
  const bound = adapter.executeAffected;
13127
13368
  if (bound !== undefined)
13128
- return await bound.call(adapter, { text, values });
13129
- return await adapter.executeUnsafe({ text, values });
13369
+ return await bound.call(adapter, input);
13370
+ return await adapter.executeUnsafe(input);
13130
13371
  }
13131
13372
  async function runAffected(params) {
13132
13373
  const { engine, plan } = params;
@@ -13159,7 +13400,8 @@ async function runAffected(params) {
13159
13400
  run: () => runBoundAffected({
13160
13401
  adapter: engine.adapter,
13161
13402
  text: rendered.text,
13162
- values: bindValues({ adapter: engine.adapter, values: rendered.values })
13403
+ values: bindValues({ adapter: engine.adapter, values: rendered.values }),
13404
+ effect: statementEffect({ statement: plan.statement, dialect: engine.dialect, adapter: engine.adapter })
13163
13405
  })
13164
13406
  });
13165
13407
  return result.affectedRows;
@@ -13170,14 +13412,14 @@ function plan(params) {
13170
13412
  const args = engine.readOnlySql === true ? restrictedSqlArgs({ value: params.args, path: "$readOnly", refusal: () => readOnlyRefusal({ path: `${model}.${method}`, reason: "raw" }) }) : params.args;
13171
13413
  if (args !== undefined && args["lock"] !== undefined) {
13172
13414
  if (engine.inTransaction !== true) {
13173
- throw new VibeError30({
13415
+ throw new VibeError34({
13174
13416
  code: "VIBE_VALIDATION",
13175
13417
  message: `lock on ${model}.${method}() requires a transaction \u2014 call it on the client $transaction hands its callback (outside one, the lock would release at statement end)`,
13176
13418
  meta: { model, method }
13177
13419
  });
13178
13420
  }
13179
13421
  if (!LOCKABLE_METHODS.includes(method)) {
13180
- throw new VibeError30({
13422
+ throw new VibeError34({
13181
13423
  code: "VIBE_VALIDATION",
13182
13424
  message: `lock on ${model}.${method}() is not supported \u2014 only ${LOCKABLE_METHODS.join(", ")} take a lock. ` + `Lock the rows with a find inside the transaction, then write them`,
13183
13425
  meta: { model, method }
@@ -13204,7 +13446,7 @@ function readAcquiredVerdict(params) {
13204
13446
  return true;
13205
13447
  if (value === false || value === 0 || value === "f" || value === "false" || value === "0")
13206
13448
  return false;
13207
- throw new VibeError30({
13449
+ throw new VibeError34({
13208
13450
  code: "VIBE_INTERNAL",
13209
13451
  message: `internal: ${params.method}() expected a boolean "${ADVISORY_LOCK_RESULT_COLUMN}" column, got ${String(value)}`,
13210
13452
  meta: { method: params.method, value: String(value) }
@@ -13246,7 +13488,7 @@ async function insertedKeyWhere(params) {
13246
13488
  const keyField = source.model.primaryKey[0];
13247
13489
  const lastInsertIdSql = engine.dialect.lastInsertIdSql;
13248
13490
  if (lastInsertIdSql === null || source.model.primaryKey.length !== 1 || keyField === undefined) {
13249
- throw unsupportedCapability8({
13491
+ throw unsupportedCapability9({
13250
13492
  dialect: engine.dialect.name,
13251
13493
  feature: `${source.method} on ${source.model.name} without RETURNING`,
13252
13494
  hint: "this model's key is assigned by the database and cannot be read back on this dialect"
@@ -13264,11 +13506,11 @@ async function insertedKeyWhere(params) {
13264
13506
  text: lastInsertIdSql,
13265
13507
  values: [],
13266
13508
  rowCount: (value) => value.rows.length,
13267
- run: () => engine.adapter.executeUnsafe({ text: lastInsertIdSql })
13509
+ run: () => engine.adapter.executeUnsafe({ text: lastInsertIdSql, effect: "read" })
13268
13510
  });
13269
13511
  const id = result.rows[0]?.id;
13270
13512
  if (id === undefined || id === null) {
13271
- throw new VibeError30({
13513
+ throw new VibeError34({
13272
13514
  code: "VIBE_INTERNAL",
13273
13515
  message: `could not read back the generated key for ${source.model.name}`,
13274
13516
  meta: { model: source.model.name }
@@ -13303,7 +13545,8 @@ async function runSingleMutation(params) {
13303
13545
  run: () => runBoundAffected({
13304
13546
  adapter: target.adapter,
13305
13547
  text: rendered.text,
13306
- values: bindValues({ adapter: target.adapter, values: rendered.values })
13548
+ values: bindValues({ adapter: target.adapter, values: rendered.values }),
13549
+ effect: statementEffect({ statement, dialect: target.dialect, adapter: target.adapter })
13307
13550
  })
13308
13551
  });
13309
13552
  return result;
@@ -13439,7 +13682,8 @@ function relationExecutor(params) {
13439
13682
  rowCount: (value) => value.length,
13440
13683
  run: () => engine.adapter.execute({
13441
13684
  text: rendered.text,
13442
- values: bindValues({ adapter: engine.adapter, values: rendered.values })
13685
+ values: bindValues({ adapter: engine.adapter, values: rendered.values }),
13686
+ effect: statementEffect({ statement, dialect: engine.dialect, adapter: engine.adapter })
13443
13687
  })
13444
13688
  });
13445
13689
  };
@@ -13521,7 +13765,8 @@ function makeRunner(params) {
13521
13765
  rowCount: (value) => value.length,
13522
13766
  run: () => engine.adapter.execute({
13523
13767
  text: rendered.text,
13524
- values: bindValues({ adapter: engine.adapter, values: rendered.values })
13768
+ values: bindValues({ adapter: engine.adapter, values: rendered.values }),
13769
+ effect: statementEffect({ statement, dialect: engine.dialect, adapter: engine.adapter })
13525
13770
  })
13526
13771
  });
13527
13772
  }
@@ -13575,6 +13820,16 @@ function createDelegate(params) {
13575
13820
  const rows = shapeRows({ plan: built, rows: await runRows({ engine: target, plan: built }) });
13576
13821
  return await finalizeRows({ engine: target, model: built.model, shape: shapeOf(built), rows });
13577
13822
  };
13823
+ const findPage = async (target, input) => {
13824
+ const args = validatePageArgs({ model, args: input });
13825
+ const original = plan({ engine: target, model, method: "findMany", args });
13826
+ const page = preparePage({ meta: target.meta, model: original.model, dialect: target.dialect, args });
13827
+ const built = plan({ engine: target, model, method: "findMany", args: page.args });
13828
+ const rows = await runRows({ engine: target, plan: built });
13829
+ const nextCursor = pageContinuation({ plan: page.plan, rows, take: args.take, after: args.after });
13830
+ const items = await finalizeRows({ engine: target, model: built.model, shape: shapeOf(original), rows: rows.slice(0, args.take) });
13831
+ return { items, nextCursor };
13832
+ };
13578
13833
  const findFirst = async (target, args) => {
13579
13834
  const built = plan({ engine: target, model, method: "findFirst", args });
13580
13835
  const rows = shapeRows({ plan: built, rows: await runRows({ engine: target, plan: built }) });
@@ -13596,7 +13851,7 @@ function createDelegate(params) {
13596
13851
  const skipping = args.onConflict !== undefined;
13597
13852
  if (hasNestedWrites({ model: modelMeta, data: args.data })) {
13598
13853
  if (skipping) {
13599
- throw new VibeError30({
13854
+ throw new VibeError34({
13600
13855
  code: "VIBE_VALIDATION",
13601
13856
  message: `onConflict cannot combine with nested writes on ${modelMeta.name}.create() \u2014 insert the parent row alone, then connect relations`,
13602
13857
  meta: { model: modelMeta.name }
@@ -13697,7 +13952,7 @@ function createDelegate(params) {
13697
13952
  const upsert = async (target, args) => {
13698
13953
  const modelMeta = getModelMeta({ meta: target.meta, model });
13699
13954
  if (hasNestedWrites({ model: modelMeta, data: args.create }) || hasNestedWrites({ model: modelMeta, data: args.update })) {
13700
- throw new VibeError30({
13955
+ throw new VibeError34({
13701
13956
  code: "VIBE_VALIDATION",
13702
13957
  message: `nested writes are not supported inside upsert arms on ${modelMeta.name} \u2014 use create()/update() with nested data`,
13703
13958
  meta: { model: modelMeta.name }
@@ -13705,7 +13960,7 @@ function createDelegate(params) {
13705
13960
  }
13706
13961
  if (!upsertUsesNativeStatement({ model: modelMeta, args })) {
13707
13962
  if (args.onConflict !== undefined) {
13708
- throw new VibeError30({
13963
+ throw new VibeError34({
13709
13964
  code: "VIBE_VALIDATION",
13710
13965
  message: `onConflict on ${modelMeta.name}.upsert() needs the native single-statement path \u2014 this shape (a guard field beyond the conflict target, or create data not binding the where's key) runs the find-then-write fallback, which cannot honor an explicit conflict target`,
13711
13966
  meta: { model: modelMeta.name }
@@ -13763,7 +14018,8 @@ function createDelegate(params) {
13763
14018
  rowCount: (value) => value.length,
13764
14019
  run: () => target.adapter.execute({
13765
14020
  text: rendered.text,
13766
- values: bindValues({ adapter: target.adapter, values: rendered.values })
14021
+ values: bindValues({ adapter: target.adapter, values: rendered.values }),
14022
+ effect: statementEffect({ statement: built.statement, dialect: target.dialect, adapter: target.adapter })
13767
14023
  })
13768
14024
  });
13769
14025
  if (built.aggregateSpec !== null) {
@@ -13803,6 +14059,7 @@ function createDelegate(params) {
13803
14059
  const lazy = (method, run) => createQueryPromise({ engine, run, model, method });
13804
14060
  const delegate = {
13805
14061
  findMany: (args) => lazy("findMany", (target) => findMany(target, args)),
14062
+ findPage: (args) => lazy("findPage", (target) => findPage(target, args)),
13806
14063
  findFirst: (args) => lazy("findFirst", (target) => findFirst(target, args)),
13807
14064
  findUnique: (args) => lazy("findUnique", (target) => findUnique(target, args)),
13808
14065
  findFirstOrThrow: (args) => lazy("findFirstOrThrow", async (target) => {
@@ -13954,7 +14211,8 @@ function buildClient(params) {
13954
14211
  run: () => runBoundAffected({
13955
14212
  adapter: target.adapter,
13956
14213
  text: rendered.text,
13957
- values: bindValues({ adapter: target.adapter, values: rendered.values })
14214
+ values: bindValues({ adapter: target.adapter, values: rendered.values }),
14215
+ effect: statementEffect({ statement, dialect: target.dialect, adapter: target.adapter })
13958
14216
  })
13959
14217
  });
13960
14218
  if (scope !== undefined)
@@ -13983,7 +14241,7 @@ function buildClient(params) {
13983
14241
  }
13984
14242
  for (const operation of operations) {
13985
14243
  if (!isQueryPromise(operation)) {
13986
- claimError = new VibeError30({
14244
+ claimError = new VibeError34({
13987
14245
  code: "VIBE_VALIDATION",
13988
14246
  message: "$transaction([...]) takes query promises from model delegate calls \u2014 a foreign promise is already running and cannot join the transaction"
13989
14247
  });
@@ -14048,7 +14306,7 @@ function buildClient(params) {
14048
14306
  $models: models,
14049
14307
  $on: (event, listener) => {
14050
14308
  if (event !== "query") {
14051
- throw new VibeError30({
14309
+ throw new VibeError34({
14052
14310
  code: "VIBE_VALIDATION",
14053
14311
  message: `unknown client event "${String(event)}" \u2014 supported: "query"`,
14054
14312
  meta: { event }
@@ -14063,7 +14321,7 @@ function buildClient(params) {
14063
14321
  $querySql: async ({ query, decoder }) => {
14064
14322
  assertEngineActive({ engine });
14065
14323
  if (decoder === null || typeof decoder !== "object" || typeof decoder.decode !== "function")
14066
- throw new VibeError30({ code: "VIBE_VALIDATION", message: "$querySql requires an explicit result decoder" });
14324
+ throw new VibeError34({ code: "VIBE_VALIDATION", message: "$querySql requires an explicit result decoder" });
14067
14325
  const statement = compileSql({ dialect: engine.dialect, query });
14068
14326
  let output = [];
14069
14327
  await runRaw("$querySql", statement, (rows) => {
@@ -14086,7 +14344,7 @@ function buildClient(params) {
14086
14344
  $connect: async () => {
14087
14345
  assertEngineActive({ engine, requireContext: false });
14088
14346
  if (engine.borrowedModule === true)
14089
- throw new VibeError30({ code: "VIBE_VALIDATION", message: "A package module borrows its adapter; the application owns connection lifecycle", meta: { reason: "module_borrowed_lifecycle", method: "$connect" } });
14347
+ throw new VibeError34({ code: "VIBE_VALIDATION", message: "A package module borrows its adapter; the application owns connection lifecycle", meta: { reason: "module_borrowed_lifecycle", method: "$connect" } });
14090
14348
  if (engine.inTransaction === true)
14091
14349
  throw transactionLifecycleRefusal({ method: "$connect" });
14092
14350
  if (engine.rlsSchema !== undefined) {
@@ -14108,7 +14366,7 @@ function buildClient(params) {
14108
14366
  $disconnect: async () => {
14109
14367
  assertEngineActive({ engine, requireContext: false });
14110
14368
  if (engine.borrowedModule === true)
14111
- throw new VibeError30({ code: "VIBE_VALIDATION", message: "A package module borrows its adapter; the application owns connection lifecycle", meta: { reason: "module_borrowed_lifecycle", method: "$disconnect" } });
14369
+ throw new VibeError34({ code: "VIBE_VALIDATION", message: "A package module borrows its adapter; the application owns connection lifecycle", meta: { reason: "module_borrowed_lifecycle", method: "$disconnect" } });
14112
14370
  if (engine.inTransaction === true)
14113
14371
  throw transactionLifecycleRefusal({ method: "$disconnect" });
14114
14372
  await engine.diagnostics?.flush();
@@ -14140,11 +14398,12 @@ function buildClient(params) {
14140
14398
  client,
14141
14399
  meta: engine.meta,
14142
14400
  ...engine.extensionMounts === undefined ? {} : { mounts: engine.extensionMounts },
14143
- operations: LAZY_OPERATIONS
14401
+ operations: LAZY_OPERATIONS,
14402
+ assertActive: () => assertEngineActive({ engine })
14144
14403
  });
14145
14404
  } else {
14146
14405
  const refuseLegacy = () => {
14147
- throw new VibeError30({ code: "VIBE_CONFIG", message: "Native row-level security cannot be combined with application policy or tenant scoping" });
14406
+ throw new VibeError34({ code: "VIBE_CONFIG", message: "Native row-level security cannot be combined with application policy or tenant scoping" });
14148
14407
  };
14149
14408
  Object.defineProperties(client, {
14150
14409
  $withContext: { enumerable: true, value: (context) => {
@@ -14162,7 +14421,8 @@ function buildClient(params) {
14162
14421
  client,
14163
14422
  meta: engine.meta,
14164
14423
  ...engine.extensionMounts === undefined ? {} : { mounts: engine.extensionMounts },
14165
- operations: LAZY_OPERATIONS
14424
+ operations: LAZY_OPERATIONS,
14425
+ assertActive: () => assertEngineActive({ engine })
14166
14426
  });
14167
14427
  }
14168
14428
  for (const delegate of Object.values(models))
@@ -14173,12 +14433,12 @@ function buildClient(params) {
14173
14433
  registerModuleBinder({ client, bind: ({ schema, manifest }) => {
14174
14434
  assertEngineActive({ engine, requireContext: false });
14175
14435
  if (engine.rlsSchema !== undefined || engine.meta.models.some((model) => model.policy !== undefined))
14176
- throw new VibeError30({ code: "VIBE_CONFIG", message: `Module ${manifest.id} cannot attach models to a policy or native-RLS context`, meta: { reason: "module_restricted_context", moduleId: manifest.id } });
14436
+ throw new VibeError34({ code: "VIBE_CONFIG", message: `Module ${manifest.id} cannot attach models to a policy or native-RLS context`, meta: { reason: "module_restricted_context", moduleId: manifest.id } });
14177
14437
  if (manifest.dialect !== engine.dialect.name)
14178
- throw new VibeError30({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: `Module ${manifest.id} requires ${manifest.dialect}, received ${engine.dialect.name}`, meta: { reason: "module_dialect", moduleId: manifest.id } });
14438
+ throw new VibeError34({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: `Module ${manifest.id} requires ${manifest.dialect}, received ${engine.dialect.name}`, meta: { reason: "module_dialect", moduleId: manifest.id } });
14179
14439
  const previous = engine.moduleManifests.get(manifest.id);
14180
14440
  if (previous !== undefined && (previous.schemaChecksum !== manifest.schemaChecksum || previous.revision !== manifest.revision || previous.contract !== manifest.contract))
14181
- throw new VibeError30({ code: "VIBE_CONFIG", message: `Module ${manifest.id} was already bound with a different manifest; use compatible package artifacts`, meta: { reason: "module_manifest_conflict", moduleId: manifest.id, revision: manifest.revision } });
14441
+ throw new VibeError34({ code: "VIBE_CONFIG", message: `Module ${manifest.id} was already bound with a different manifest; use compatible package artifacts`, meta: { reason: "module_manifest_conflict", moduleId: manifest.id, revision: manifest.revision } });
14182
14442
  let meta = moduleMetadata.get(schema);
14183
14443
  if (meta === undefined) {
14184
14444
  meta = buildRuntimeMeta({ schema });
@@ -14189,8 +14449,14 @@ function buildClient(params) {
14189
14449
  const { validate: _validate, ...options } = engine.options;
14190
14450
  return buildClient({ engine: { ...engine, meta, options, borrowedModule: true, extensionMounts: [], connectHooks: [], renderCache: new StatementRenderCache } });
14191
14451
  } });
14452
+ registerTransactionObservation({ db: client, observation: {
14453
+ inTransaction: engine.inTransaction === true,
14454
+ assertActive: () => assertEngineActive({ engine }),
14455
+ read: () => engine.adapter.rowChanges?.() ?? "unknown"
14456
+ } });
14192
14457
  return client;
14193
14458
  }
14459
+ var EXTENSION_EFFECT = new AsyncLocalStorage;
14194
14460
  function makeMountContext(params) {
14195
14461
  const { engine, extension, model } = params;
14196
14462
  return {
@@ -14220,7 +14486,8 @@ function makeMountContext(params) {
14220
14486
  rowCount: (value) => value.length,
14221
14487
  run: () => target.adapter.execute({
14222
14488
  text,
14223
- values: bindValues({ adapter: target.adapter, values: [...values] })
14489
+ values: bindValues({ adapter: target.adapter, values: [...values] }),
14490
+ effect: EXTENSION_EFFECT.getStore() ?? "unknown"
14224
14491
  })
14225
14492
  });
14226
14493
  return model === null ? rows : materializeRows({ dialect: target.dialect.name, model, rows, wire: target.adapter.wire });
@@ -14233,7 +14500,7 @@ function makeMountContext(params) {
14233
14500
  compileWhere: ({ where, model: modelName, qualify }) => {
14234
14501
  const target = modelName === undefined ? model : getModelMeta({ meta: engine.meta, model: modelName });
14235
14502
  if (target === null) {
14236
- throw new VibeError30({
14503
+ throw new VibeError34({
14237
14504
  code: "VIBE_INTERNAL",
14238
14505
  message: `extension "${extension}" compiled a where with no model in scope`,
14239
14506
  meta: { extension }
@@ -14253,8 +14520,27 @@ function makeMountContext(params) {
14253
14520
  function createMountSurface(params) {
14254
14521
  const { engine, mount, model } = params;
14255
14522
  const original = mount.create(makeMountContext({ engine, extension: mount.extension, model }));
14523
+ const effectOf = (path, args) => {
14524
+ if (containsSqlFragment(args))
14525
+ return "unknown";
14526
+ return mount.readOnly === true && path.length === 0 || Array.isArray(mount.readOnly) && path.length === 1 && mount.readOnly.includes(String(path[0])) ? "read" : "unknown";
14527
+ };
14528
+ const wrapEffects = (value, path) => {
14529
+ if (typeof value === "function")
14530
+ return function(...args) {
14531
+ return EXTENSION_EFFECT.run(effectOf(path, args), () => Reflect.apply(value, this, args));
14532
+ };
14533
+ if (value === null || typeof value !== "object" || Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null)
14534
+ return value;
14535
+ const result = Object.create(Object.getPrototypeOf(value));
14536
+ for (const key of Reflect.ownKeys(value)) {
14537
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
14538
+ Object.defineProperty(result, key, "value" in descriptor ? { ...descriptor, value: wrapEffects(descriptor.value, [...path, key]) } : descriptor);
14539
+ }
14540
+ return result;
14541
+ };
14256
14542
  if (engine.rlsSchema === undefined)
14257
- return original;
14543
+ return wrapEffects(original, []);
14258
14544
  const wrap = (value, path) => {
14259
14545
  if (typeof value === "function") {
14260
14546
  return (...args) => createQueryPromise({ engine, run: async (target) => {
@@ -14263,24 +14549,24 @@ function createMountSurface(params) {
14263
14549
  for (const key of path) {
14264
14550
  receiver = current;
14265
14551
  if (current === null || typeof current !== "object" && typeof current !== "function")
14266
- throw new VibeError30({ code: "VIBE_CONFIG", message: "Extension mount changed its method shape" });
14552
+ throw new VibeError34({ code: "VIBE_CONFIG", message: "Extension mount changed its method shape" });
14267
14553
  current = Reflect.get(current, key);
14268
14554
  }
14269
14555
  if (typeof current !== "function")
14270
- throw new VibeError30({ code: "VIBE_CONFIG", message: "Extension mount changed its method shape" });
14271
- return Reflect.apply(current, receiver, args);
14556
+ throw new VibeError34({ code: "VIBE_CONFIG", message: "Extension mount changed its method shape" });
14557
+ return EXTENSION_EFFECT.run(effectOf(path, args), () => Reflect.apply(current, receiver, args));
14272
14558
  } });
14273
14559
  }
14274
14560
  if (value === null || typeof value !== "object")
14275
14561
  return value;
14276
14562
  if (Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) {
14277
- throw new VibeError30({ code: "VIBE_CONFIG", message: "Native RLS extension mounts must expose plain objects and methods" });
14563
+ throw new VibeError34({ code: "VIBE_CONFIG", message: "Native RLS extension mounts must expose plain objects and methods" });
14278
14564
  }
14279
14565
  const result = {};
14280
14566
  for (const key of Reflect.ownKeys(value)) {
14281
14567
  const descriptor = Object.getOwnPropertyDescriptor(value, key);
14282
14568
  if (!("value" in descriptor))
14283
- throw new VibeError30({ code: "VIBE_CONFIG", message: "Native RLS extension mount accessors are unsupported" });
14569
+ throw new VibeError34({ code: "VIBE_CONFIG", message: "Native RLS extension mount accessors are unsupported" });
14284
14570
  Object.defineProperty(result, key, { value: wrap(descriptor.value, [...path, key]), enumerable: descriptor.enumerable });
14285
14571
  }
14286
14572
  return Object.freeze(result);
@@ -14297,7 +14583,7 @@ function attachExtensionMounts(params) {
14297
14583
  const model = getModelMeta({ meta: engine.meta, model: mount.model ?? "" });
14298
14584
  const delegate = models[model.name];
14299
14585
  if (delegate === undefined || mount.property in delegate) {
14300
- throw new VibeError30({
14586
+ throw new VibeError34({
14301
14587
  code: "VIBE_CONFIG",
14302
14588
  message: `extension "${mount.extension}" cannot mount "${mount.property}" on ${model.name} \u2014 the name is taken`,
14303
14589
  meta: { extension: mount.extension, model: model.name, property: mount.property }
@@ -14308,7 +14594,7 @@ function attachExtensionMounts(params) {
14308
14594
  continue;
14309
14595
  }
14310
14596
  if (!mount.property.startsWith("$") || mount.property in client) {
14311
- throw new VibeError30({
14597
+ throw new VibeError34({
14312
14598
  code: "VIBE_CONFIG",
14313
14599
  message: `extension "${mount.extension}" cannot mount client property "${mount.property}" \u2014 root mounts are $-prefixed and must not collide`,
14314
14600
  meta: { extension: mount.extension, property: mount.property }
@@ -14334,7 +14620,7 @@ function createClient(params) {
14334
14620
  if (schema.rls !== undefined) {
14335
14621
  const dialect = getSqlDialect5({ dialect: dialectName });
14336
14622
  if (!dialect.capabilities.nativeRowLevelSecurity)
14337
- throw unsupportedCapability8({ dialect: dialectName, feature: "nativeRowLevelSecurity" });
14623
+ throw unsupportedCapability9({ dialect: dialectName, feature: "nativeRowLevelSecurity" });
14338
14624
  assertValidSchemaIR2({ schema });
14339
14625
  for (const model of schema.models) {
14340
14626
  if (model.rls !== "unprotected")
@@ -14343,9 +14629,9 @@ function createClient(params) {
14343
14629
  const role = options?.nativeRls?.runtimeRole;
14344
14630
  if (adapter.provider === "pglite") {
14345
14631
  if (typeof role !== "string" || role.length === 0 || role.includes("\x00"))
14346
- throw new VibeError30({ code: "VIBE_CONFIG", message: "PGlite native row-level security requires a pre-existing restricted runtimeRole; embedded binding is not a boundary against the host process" });
14632
+ throw new VibeError34({ code: "VIBE_CONFIG", message: "PGlite native row-level security requires a pre-existing restricted runtimeRole; embedded binding is not a boundary against the host process" });
14347
14633
  } else if (role !== undefined) {
14348
- throw new VibeError30({ code: "VIBE_CONFIG", message: "Server native row-level security must use the runtime login role, not a runtimeRole switch" });
14634
+ throw new VibeError34({ code: "VIBE_CONFIG", message: "Server native row-level security must use the runtime login role, not a runtimeRole switch" });
14349
14635
  }
14350
14636
  }
14351
14637
  if (extensions?.manifest !== undefined) {
@@ -14355,7 +14641,7 @@ function createClient(params) {
14355
14641
  assertComputedManifest({ manifest: computed.manifest, specs: computed.specs });
14356
14642
  }
14357
14643
  if (computed === undefined && options !== undefined && options["computed"] !== undefined) {
14358
- throw new VibeError30({
14644
+ throw new VibeError34({
14359
14645
  code: "VIBE_CONFIG",
14360
14646
  message: "this client was generated without computed fields \u2014 declare them in vibeorm.config.ts and re-run vibeorm generate",
14361
14647
  meta: {}
@@ -14408,16 +14694,17 @@ function freezeData(params) {
14408
14694
  function defineDatabaseModule(params) {
14409
14695
  for (const key of ["id", "contract", "revision"]) {
14410
14696
  if (typeof params[key] !== "string" || params[key].trim().length === 0 || params[key].includes("\x00"))
14411
- throw new VibeError31({ code: "VIBE_CONFIG", message: `Database module ${key} must be a non-empty identifier`, meta: { reason: "module_manifest", key } });
14697
+ throw new VibeError35({ code: "VIBE_CONFIG", message: `Database module ${key} must be a non-empty identifier`, meta: { reason: "module_manifest", key } });
14412
14698
  }
14413
- assertValidSchemaIR3({ schema: params.schema });
14414
- if (params.schema.rls !== undefined || params.schema.extensions.length > 0 || params.schema.models.some((model) => model.policy !== undefined))
14415
- throw new VibeError31({
14699
+ const preparedSchema = prepareDatabaseModuleSchema({ schema: params.schema, module: params });
14700
+ assertValidSchemaIR3({ schema: preparedSchema });
14701
+ if (preparedSchema.rls !== undefined || preparedSchema.extensions.length > 0 || preparedSchema.models.some((model) => model.policy !== undefined))
14702
+ throw new VibeError35({
14416
14703
  code: "VIBE_UNSUPPORTED_CAPABILITY",
14417
14704
  message: `Module ${params.id} cannot declare extensions, policy or native RLS in this module protocol`,
14418
14705
  meta: { reason: "module_schema_feature", moduleId: params.id }
14419
14706
  });
14420
- const serialized = JSON.stringify(canonicalValue({ value: params.schema }));
14707
+ const serialized = JSON.stringify(canonicalValue({ value: preparedSchema }));
14421
14708
  const schema = JSON.parse(serialized);
14422
14709
  freezeData({ value: schema });
14423
14710
  const manifest = Object.freeze({
@@ -14425,11 +14712,12 @@ function defineDatabaseModule(params) {
14425
14712
  contract: params.contract,
14426
14713
  revision: params.revision,
14427
14714
  protocol: 1,
14715
+ ...params.namespace === undefined ? {} : { namespace: params.namespace },
14428
14716
  dialect: providerToDialect({ provider: schema.datasource.provider }),
14429
- schemaChecksum: createHash("sha256").update(serialized).digest("hex")
14717
+ schemaChecksum: createHash2("sha256").update(serialized).digest("hex")
14430
14718
  });
14431
- if (params.manifest !== undefined && Object.keys(manifest).some((key) => params.manifest[key] !== manifest[key]))
14432
- throw new VibeError31({
14719
+ if (params.manifest !== undefined && (params.manifest.namespace !== manifest.namespace || Object.keys(manifest).some((key) => params.manifest[key] !== manifest[key])))
14720
+ throw new VibeError35({
14433
14721
  code: "VIBE_STALE_CLIENT",
14434
14722
  message: `Module ${params.id} has incompatible or modified generated metadata; regenerate with a compatible runtime`,
14435
14723
  meta: { reason: "module_artifact", moduleId: params.id, revision: params.revision, protocol: params.manifest.protocol }
@@ -14439,32 +14727,9 @@ function defineDatabaseModule(params) {
14439
14727
  return Object.freeze({ ...artifact, bind, create: ({ adapter }) => bind({ db: createClient({ schema, adapter }) }) });
14440
14728
  }
14441
14729
  // packages/runtime/src/keyset-iterator.ts
14442
- import { VibeError as VibeError32 } from "@vibeorm/schema";
14730
+ import { VibeError as VibeError36 } from "@vibeorm/schema";
14443
14731
  function validation(params) {
14444
- return new VibeError32({ code: "VIBE_VALIDATION", message: params.message, meta: params.meta });
14445
- }
14446
- function projectionFor(params) {
14447
- const { plan, select, omit } = params;
14448
- const names = plan.keys.map((key) => key.field.name);
14449
- if (select !== undefined) {
14450
- const hidden = names.filter((name) => select[name] !== true);
14451
- if (hidden.length === 0)
14452
- return { select, hidden };
14453
- const widened = { ...select };
14454
- for (const name of hidden)
14455
- widened[name] = true;
14456
- return { select: widened, hidden };
14457
- }
14458
- if (omit !== undefined) {
14459
- const hidden = names.filter((name) => omit[name] === true);
14460
- if (hidden.length === 0)
14461
- return { omit, hidden };
14462
- const narrowed = { ...omit };
14463
- for (const name of hidden)
14464
- narrowed[name] = false;
14465
- return { omit: narrowed, hidden };
14466
- }
14467
- return { hidden: [] };
14732
+ return new VibeError36({ code: "VIBE_VALIDATION", message: params.message, meta: params.meta });
14468
14733
  }
14469
14734
  function iterateKeyset(options) {
14470
14735
  const { source, meta, dialect, orderBy, pageSize, signal } = options;
@@ -14481,7 +14746,7 @@ function iterateKeyset(options) {
14481
14746
  terms: compileKeysetOrderInputs({ dialect, meta, model, orderBy }),
14482
14747
  ...options.timestampPrecision === undefined ? {} : { timestampPrecision: options.timestampPrecision }
14483
14748
  });
14484
- const projection = projectionFor({ plan, select: options.select, omit: options.omit });
14749
+ const projection = keysetProjection({ plan, select: options.select, omit: options.omit });
14485
14750
  const keysetArg = options.timestampPrecision === undefined ? {} : { keyset: { timestampPrecision: options.timestampPrecision } };
14486
14751
  let buffer = [];
14487
14752
  let position = options.after ?? null;
@@ -14518,7 +14783,7 @@ function iterateKeyset(options) {
14518
14783
  });
14519
14784
  if (advanced === false) {
14520
14785
  stop();
14521
- throw new VibeError32({
14786
+ throw new VibeError36({
14522
14787
  code: "VIBE_DATA_INVALID",
14523
14788
  message: `keyset traversal of "${options.model}" is not advancing: the engine returned a row that does not sort after the previous position. ` + "The ordering is not total, or a cursor value lost precision \u2014 a DateTime column finer than milliseconds asserted as millisecond-exact does this.",
14524
14789
  meta: { model: options.model, order: plan.signature, reason: "keyset-position-not-advancing" }
@@ -14591,7 +14856,7 @@ function iterateKeyset(options) {
14591
14856
  return iterator;
14592
14857
  }
14593
14858
  // packages/runtime/src/telemetry/collector.ts
14594
- import { VibeError as VibeError33 } from "@vibeorm/schema";
14859
+ import { VibeError as VibeError37 } from "@vibeorm/schema";
14595
14860
  function createTelemetryCollector(params) {
14596
14861
  const throwOn = new Set(params?.throwOn ?? []);
14597
14862
  const operations = [];
@@ -14601,7 +14866,7 @@ function createTelemetryCollector(params) {
14601
14866
  let shutdowns = 0;
14602
14867
  const hostile = (phase) => {
14603
14868
  if (throwOn.has(phase)) {
14604
- throw new VibeError33({
14869
+ throw new VibeError37({
14605
14870
  code: "VIBE_INTERNAL",
14606
14871
  message: `telemetry collector: deliberate ${phase} failure`,
14607
14872
  meta: { reason: "telemetry-collector-deliberate-failure", phase }
@@ -14657,7 +14922,7 @@ function createTelemetryCollector(params) {
14657
14922
  operationFor: (lookup) => {
14658
14923
  const matches = operations.filter((event) => event.method === lookup.method && (lookup.model === undefined || event.model === lookup.model));
14659
14924
  if (matches.length > 1) {
14660
- throw new VibeError33({
14925
+ throw new VibeError37({
14661
14926
  code: "VIBE_VALIDATION",
14662
14927
  message: `telemetry collector: ${matches.length} operations match ${lookup.model ?? "*"}.${lookup.method}`,
14663
14928
  meta: {
@@ -14691,6 +14956,7 @@ export {
14691
14956
  TELEMETRY_DEFAULTS,
14692
14957
  ViewResult,
14693
14958
  WRITE_DELEGATE_METHODS,
14959
+ advisoryKeyOf,
14694
14960
  affectedRowsAreRowCounts,
14695
14961
  analyzeOperationTelemetry,
14696
14962
  applyComputedFields,
@@ -14717,6 +14983,7 @@ export {
14717
14983
  compileSelect,
14718
14984
  compileWhere,
14719
14985
  createClient,
14986
+ createDelegateMethodClassifier,
14720
14987
  createScopeRewriter,
14721
14988
  createSqlModel,
14722
14989
  createStatementDiagnostics,
@@ -14780,8 +15047,9 @@ export {
14780
15047
  summarizePlan,
14781
15048
  toClientName,
14782
15049
  toSqlExecutor,
15050
+ transactionRowChanges,
14783
15051
  updateWithNested,
14784
15052
  validateWriteData
14785
15053
  };
14786
15054
 
14787
- //# debugId=BC9380E497613E8D64756E2164756E21
15055
+ //# debugId=F8F07DD9CF6AA47D64756E2164756E21