@prisma-next/sql-runtime 0.11.0-dev.3 → 0.11.0-dev.4
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 +14 -3
- package/dist/{exports-BsRNNJxU.mjs → exports-pTQTXnEr.mjs} +34 -30
- package/dist/{exports-BsRNNJxU.mjs.map → exports-pTQTXnEr.mjs.map} +1 -1
- package/dist/{index-B2sP_QGE.d.mts → index-BtHe0Ay1.d.mts} +22 -8
- package/dist/index-BtHe0Ay1.d.mts.map +1 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +1 -1
- package/dist/test/utils.d.mts +1 -1
- package/dist/test/utils.mjs +1 -1
- package/package.json +12 -12
- package/src/exports/index.ts +1 -1
- package/src/runtime-spi.ts +19 -5
- package/src/sql-runtime.ts +38 -64
- package/dist/index-B2sP_QGE.d.mts.map +0 -1
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**:
|
|
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
|
-
- `
|
|
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
|
-
|
|
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,
|
|
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.
|
|
1354
|
+
this.verifyMarkerOption = verifyMarker ?? "onFirstUse";
|
|
1356
1355
|
this.codecRegistryValidated = false;
|
|
1357
|
-
this.
|
|
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 (
|
|
1446
|
-
|
|
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
|
-
|
|
1648
|
-
|
|
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
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
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,
|
|
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
|
-
|
|
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-
|
|
1769
|
+
//# sourceMappingURL=exports-pTQTXnEr.mjs.map
|