@prisma-next/sql-runtime 0.11.0-dev.3 → 0.11.0-dev.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -27,7 +27,7 @@ Execute SQL query Plans with deterministic verification, guardrails, and feedbac
27
27
  - **Codec Encoding/Decoding**: Encode parameters and decode rows using SQL codec registries
28
28
  - **Codec Validation**: Validate that codec registries contain all required codecs
29
29
  - **SQL Family Adapter**: Implement `RuntimeFamilyAdapter` for SQL contracts (defined in `runtime-spi.ts`)
30
- - **Marker Verification**: Parse contract-marker rows from the database (`marker.ts`) and gate execution on hash equality
30
+ - **Marker Verification**: Read contract-marker rows from the database (`marker.ts`) on first execute and compare storage/profile hashes against the contract. On the first `execute()` call, any drift — hash mismatch, absent row, or missing marker table — is reported via a single `warn`-level structured log line through the runtime's `Log` interface (payload includes `code`, `scope`, `expected`, `actual`, `message`) and the query proceeds normally. The check runs once per runtime lifetime; subsequent queries skip the marker read. Pass `verifyMarker: false` to skip the marker read entirely.
31
31
  - **Telemetry Fingerprinting**: Compute SQL fingerprints for telemetry events (`fingerprint.ts`)
32
32
  - **Raw-SQL Guardrails**: Heuristic safety checks for raw SQL plans (`guardrails/raw.ts`)
33
33
  - **`beforeCompile` Chain**: AST-rewrite middleware chain run pre-lowering (`middleware/before-compile-chain.ts`)
@@ -72,7 +72,6 @@ const runtime = createRuntime({
72
72
  stackInstance,
73
73
  context,
74
74
  driver,
75
- verify: { mode: 'onFirstUse', requireMarker: false },
76
75
  middleware: [budgets()],
77
76
  });
78
77
 
@@ -81,6 +80,18 @@ for await (const row of runtime.execute(plan)) {
81
80
  }
82
81
  ```
83
82
 
83
+ Use `verifyMarker: false` to skip the marker read entirely — e.g. during a known-skewed deploy window where contract drift is expected and tolerated.
84
+
85
+ ```typescript
86
+ const runtime = createRuntime({
87
+ stackInstance,
88
+ context,
89
+ driver,
90
+ verifyMarker: false,
91
+ middleware: [budgets()],
92
+ });
93
+ ```
94
+
84
95
  ## Exports
85
96
 
86
97
  ### Runtime
@@ -88,7 +99,7 @@ for await (const row of runtime.execute(plan)) {
88
99
  - `createRuntime` - Create a SQL runtime instance
89
100
  - `Runtime` - Runtime instance type
90
101
  - `CreateRuntimeOptions` - Options for `createRuntime`
91
- - `RuntimeVerifyOptions` - Verification mode configuration
102
+ - `VerifyMarkerOption` - Marker-verification option (`'onFirstUse'` default; `false` to skip)
92
103
  - `RuntimeTelemetryEvent`, `TelemetryOutcome` - Telemetry event types
93
104
 
94
105
  ### Context
@@ -1324,14 +1324,13 @@ var SqlRuntimeImpl = class extends RuntimeCore {
1324
1324
  contractCodecs;
1325
1325
  codecDescriptors;
1326
1326
  sqlCtx;
1327
- verify;
1327
+ verifyMarkerOption;
1328
+ verifyMarkerPromise;
1328
1329
  #preparedStatementHandles = /* @__PURE__ */ new WeakMap();
1329
1330
  codecRegistryValidated;
1330
- verified;
1331
- startupVerified;
1332
1331
  _telemetry;
1333
1332
  constructor(options) {
1334
- const { context, adapter, driver, verify, middleware, mode, log } = options;
1333
+ const { context, adapter, driver, verifyMarker, middleware, mode, log } = options;
1335
1334
  if (middleware) for (const mw of middleware) checkMiddlewareCompatibility(mw, "sql", context.contract.target);
1336
1335
  const sqlCtx = {
1337
1336
  contract: context.contract,
@@ -1352,15 +1351,10 @@ var SqlRuntimeImpl = class extends RuntimeCore {
1352
1351
  this.contractCodecs = context.contractCodecs;
1353
1352
  this.codecDescriptors = context.codecDescriptors;
1354
1353
  this.sqlCtx = sqlCtx;
1355
- this.verify = verify;
1354
+ this.verifyMarkerOption = verifyMarker ?? "onFirstUse";
1356
1355
  this.codecRegistryValidated = false;
1357
- this.verified = verify.mode === "startup" ? false : verify.mode === "always";
1358
- this.startupVerified = false;
1356
+ this.verifyMarkerPromise = this.verifyMarkerOption === false ? Promise.resolve() : null;
1359
1357
  this._telemetry = null;
1360
- if (verify.mode === "startup") {
1361
- validateCodecRegistryCompleteness(this.codecDescriptors, context.contract);
1362
- this.codecRegistryValidated = true;
1363
- }
1364
1358
  }
1365
1359
  /**
1366
1360
  * Lower a `SqlQueryPlan` (AST + meta) into a `SqlExecutionPlan`
@@ -1442,12 +1436,11 @@ var SqlRuntimeImpl = class extends RuntimeCore {
1442
1436
  async *streamRows(exec, decodeContext, driverCall, codecCtx, execMiddlewareCtx) {
1443
1437
  this.familyAdapter.validatePlan(exec, this.contract);
1444
1438
  this._telemetry = null;
1445
- if (!this.startupVerified && this.verify.mode === "startup") await this.verifyMarker();
1446
- if (!this.verified && this.verify.mode === "onFirstUse") await this.verifyMarker();
1439
+ if (this.verifyMarkerPromise === null) this.verifyMarkerPromise = this.verifyMarker();
1440
+ await this.verifyMarkerPromise;
1447
1441
  const startedAt = Date.now();
1448
1442
  let outcome = null;
1449
1443
  try {
1450
- if (this.verify.mode === "always") await this.verifyMarker();
1451
1444
  const iterator = runWithMiddleware(exec, this.middleware, execMiddlewareCtx, driverCall)[Symbol.asyncIterator]();
1452
1445
  try {
1453
1446
  while (true) {
@@ -1643,24 +1636,35 @@ var SqlRuntimeImpl = class extends RuntimeCore {
1643
1636
  }
1644
1637
  async verifyMarker() {
1645
1638
  const readResult = await this.familyAdapter.markerReader.readMarker(this.driver);
1639
+ const expectedStorageHash = this.contract.storage.storageHash;
1640
+ const expectedProfileHash = this.contract.profileHash ?? null;
1641
+ const expected = {
1642
+ storageHash: expectedStorageHash,
1643
+ profileHash: expectedProfileHash
1644
+ };
1646
1645
  if (readResult.kind !== "present") {
1647
- if (this.verify.requireMarker) throw runtimeError("CONTRACT.MARKER_MISSING", "Contract marker not found in database");
1648
- this.verified = true;
1646
+ this.sqlCtx.log.warn({
1647
+ code: "CONTRACT.MARKER_MISSING",
1648
+ scope: "marker-verification",
1649
+ expected,
1650
+ actual: null,
1651
+ message: "Contract marker not found in database"
1652
+ });
1649
1653
  return;
1650
1654
  }
1651
1655
  const marker = readResult.record;
1652
- const contract = this.contract;
1653
- if (marker.storageHash !== contract.storage.storageHash) throw runtimeError("CONTRACT.MARKER_MISMATCH", "Database storage hash does not match contract", {
1654
- expected: contract.storage.storageHash,
1655
- actual: marker.storageHash
1656
- });
1657
- const expectedProfile = contract.profileHash ?? null;
1658
- if (expectedProfile !== null && marker.profileHash !== expectedProfile) throw runtimeError("CONTRACT.MARKER_MISMATCH", "Database profile hash does not match contract", {
1659
- expectedProfile,
1660
- actualProfile: marker.profileHash
1656
+ const storageHashMatch = marker.storageHash === expectedStorageHash;
1657
+ const profileHashMatch = expectedProfileHash === null || marker.profileHash === expectedProfileHash;
1658
+ if (!storageHashMatch || !profileHashMatch) this.sqlCtx.log.warn({
1659
+ code: "CONTRACT.MARKER_MISMATCH",
1660
+ scope: "marker-verification",
1661
+ expected,
1662
+ actual: {
1663
+ storageHash: marker.storageHash,
1664
+ profileHash: marker.profileHash ?? null
1665
+ },
1666
+ message: "Contract marker hash does not match runtime contract"
1661
1667
  });
1662
- this.verified = true;
1663
- this.startupVerified = true;
1664
1668
  }
1665
1669
  recordTelemetry(plan, outcome, durationMs) {
1666
1670
  const contract = this.contract;
@@ -1748,12 +1752,12 @@ async function withTransaction(runtime, fn) {
1748
1752
  }
1749
1753
  }
1750
1754
  function createRuntime(options) {
1751
- const { stackInstance, context, driver, verify, middleware, mode, log } = options;
1755
+ const { stackInstance, context, driver, verifyMarker, middleware, mode, log } = options;
1752
1756
  return new SqlRuntimeImpl({
1753
1757
  context,
1754
1758
  adapter: stackInstance.adapter,
1755
1759
  driver,
1756
- verify,
1760
+ ...ifDefined("verifyMarker", verifyMarker),
1757
1761
  ...ifDefined("middleware", middleware),
1758
1762
  ...ifDefined("mode", mode),
1759
1763
  ...ifDefined("log", log)
@@ -1762,4 +1766,4 @@ function createRuntime(options) {
1762
1766
  //#endregion
1763
1767
  export { ensureTableStatement as a, createExecutionContext as c, budgets as d, parseContractMarkerRow as f, validateContractCodecMappings as g, validateCodecRegistryCompleteness as h, ensureSchemaStatement as i, createSqlExecutionStack as l, extractCodecIds as m, withTransaction as n, readContractMarker as o, lowerSqlPlan as p, APP_SPACE_ID as r, writeContractMarker as s, createRuntime as t, lints as u };
1764
1768
 
1765
- //# sourceMappingURL=exports-BsRNNJxU.mjs.map
1769
+ //# sourceMappingURL=exports-pTQTXnEr.mjs.map