@prisma-next/runtime-executor 0.4.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { AfterExecuteResult, AsyncIterableResult, AsyncIterableResult as AsyncIterableResult$1, RuntimeErrorEnvelope, RuntimeExecutor, RuntimeLog, RuntimeMiddleware, RuntimeMiddlewareContext, runtimeError } from "@prisma-next/framework-components/runtime";
2
- import { ContractMarkerRecord, ExecutionPlan } from "@prisma-next/contract/types";
2
+ import { ContractMarkerRecord, ExecutionPlan, PlanMeta } from "@prisma-next/contract/types";
3
3
 
4
4
  //#region src/fingerprint.d.ts
5
5
  declare function computeSqlFingerprint(sql: string): string;
@@ -40,7 +40,16 @@ type Severity = 'error' | 'warn' | 'info';
40
40
  interface MiddlewareContext<TContract = unknown> extends RuntimeMiddlewareContext {
41
41
  readonly contract: TContract;
42
42
  }
43
+ /**
44
+ * Family-agnostic pre-compile draft. Family runtimes narrow `ast` to their
45
+ * specific AST shape (e.g. `AnyQueryAst` for SQL via `SqlMiddleware.DraftPlan`).
46
+ */
47
+ interface GenericDraftPlan {
48
+ readonly ast: unknown;
49
+ readonly meta: PlanMeta;
50
+ }
43
51
  interface Middleware<TContract = unknown> extends RuntimeMiddleware {
52
+ beforeCompile?(draft: GenericDraftPlan, ctx: MiddlewareContext<TContract>): Promise<GenericDraftPlan | undefined>;
44
53
  beforeExecute?(plan: ExecutionPlan, ctx: MiddlewareContext<TContract>): Promise<void>;
45
54
  onRow?(row: Record<string, unknown>, plan: ExecutionPlan, ctx: MiddlewareContext<TContract>): Promise<void>;
46
55
  afterExecute?(plan: ExecutionPlan, result: AfterExecuteResult, ctx: MiddlewareContext<TContract>): Promise<void>;
@@ -73,17 +82,19 @@ interface RuntimeTelemetryEvent {
73
82
  readonly outcome: TelemetryOutcome;
74
83
  readonly durationMs?: number;
75
84
  }
76
- interface RuntimeCoreOptions<TContract = unknown, TDriver = unknown> {
85
+ interface RuntimeCoreOptions<TContract = unknown, TDriver = unknown, TMiddleware extends Middleware<TContract> = Middleware<TContract>> {
77
86
  readonly familyAdapter: RuntimeFamilyAdapter<TContract>;
78
87
  readonly driver: TDriver;
79
88
  readonly verify: RuntimeVerifyOptions;
80
- readonly middleware?: readonly Middleware<TContract>[];
89
+ readonly middleware?: readonly TMiddleware[];
81
90
  readonly mode?: 'strict' | 'permissive';
82
91
  readonly log?: RuntimeLog;
83
92
  }
84
- interface RuntimeCore<TContract = unknown, TDriver = unknown> extends RuntimeQueryable, RuntimeExecutor<ExecutionPlan> {
93
+ interface RuntimeCore<TContract = unknown, TDriver = unknown, TMiddleware extends Middleware<TContract> = Middleware<TContract>> extends RuntimeQueryable, RuntimeExecutor<ExecutionPlan> {
85
94
  readonly _typeContract?: TContract;
86
95
  readonly _typeDriver?: TDriver;
96
+ readonly middleware: readonly TMiddleware[];
97
+ readonly middlewareContext: MiddlewareContext<TContract>;
87
98
  connection(): Promise<RuntimeConnection>;
88
99
  telemetry(): RuntimeTelemetryEvent | null;
89
100
  close(): Promise<void>;
@@ -133,7 +144,7 @@ interface RuntimeQueryable {
133
144
  readonly _row?: Row;
134
145
  }): AsyncIterableResult$1<Row>;
135
146
  }
136
- declare function createRuntimeCore<TContract = unknown, TDriver = unknown>(options: RuntimeCoreOptions<TContract, TDriver>): RuntimeCore<TContract, TDriver>;
147
+ declare function createRuntimeCore<TContract = unknown, TDriver = unknown, TMiddleware extends Middleware<TContract> = Middleware<TContract>>(options: RuntimeCoreOptions<TContract, TDriver, TMiddleware>): RuntimeCore<TContract, TDriver, TMiddleware>;
137
148
  //#endregion
138
149
  export { type AfterExecuteResult, AsyncIterableResult, type BudgetFinding, type LintFinding, type RuntimeLog as Log, type MarkerReader, type MarkerStatement, type Middleware, type MiddlewareContext, type RawGuardrailResult, type RuntimeConnection, type RuntimeCore, type RuntimeCoreOptions, type RuntimeErrorEnvelope, type RuntimeFamilyAdapter, type RuntimeQueryable, type RuntimeTelemetryEvent, type RuntimeTransaction, type RuntimeVerifyOptions, type Severity, type TelemetryOutcome, computeSqlFingerprint, createRuntimeCore, evaluateRawGuardrails, parseContractMarkerRow, runtimeError };
139
150
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/fingerprint.ts","../src/guardrails/raw.ts","../src/marker.ts","../src/middleware/types.ts","../src/runtime-spi.ts","../src/runtime-core.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/fingerprint.ts","../src/guardrails/raw.ts","../src/marker.ts","../src/middleware/types.ts","../src/runtime-spi.ts","../src/runtime-core.ts"],"sourcesContent":[],"mappings":";;;;iBAMgB,qBAAA;;;KCJJ,YAAA;KACA,cAAA;UAEK,WAAA;EDCD,SAAA,IAAA,EAAA,QAAA,MAAqB,EAAA;qBCChB;;qBAEA;AAPrB;AACY,UASK,aAAA,CATS;EAET,SAAA,IAAA,EAAW,UAEP,MAAA,EAAA;EAKJ,SAAA,QAAa,EAET,cAAA;EAKJ,SAAA,OAAA,EAAA,MAAkB;EAOlB,SAAA,OAAA,CAAA,EAVI,MAUc,CAAA,MACjB,EAAA,OAAA,CAAA;AAWlB;AACQ,UApBS,kBAAA,CAoBT;EACG,SAAA,OAAA,CAAA,EAAA;IACR,SAAA,uBAAA,CAAA,EApBoC,cAoBpC;IAAkB,SAAA,aAAA,CAAA,EAAA,MAAA;;;UAfJ,kBAAA;ECuBD,SAAA,KAAA,EDtBE,WCsBoB,EAAA;oBDrBlB;;;AEpBR,iBF8BI,qBAAA,CE9BI,IAAA,EF+BZ,aE/BY,EAAA,MAAA,CAAA,EFgCT,kBEhCS,CAAA,EFiCjB,kBEjCiB;;;AFHH,iBC4CD,sBAAA,CDxCK,GAAM,EAAA,OAAA,CAAA,ECwC2B,oBDxC3B;;;KEDf,QAAA;AHFI,UGMC,iBHNoB,CAAA,YAAA,OAAA,CAAA,SGM2B,wBHN3B,CAAA;qBGOhB;;;AFXrB;AACA;AAEA;AAOiB,UEQA,gBAAA,CFNI;EAKJ,SAAA,GAAA,EAAA,OAAkB;EAOlB,SAAA,IAAA,EEJA,QFIkB;AAYnC;AACQ,UEdS,UFcT,CAAA,YAAA,OAAA,CAAA,SEdiD,iBFcjD,CAAA;EACG,aAAA,EAAA,KAAA,EEbA,gBFaA,EAAA,GAAA,EEZF,iBFYE,CEZgB,SFYhB,CAAA,CAAA,EEXN,OFWM,CEXE,gBFWF,GAAA,SAAA,CAAA;EACR,aAAA,EAAA,IAAA,EEXoB,aFWpB,EAAA,GAAA,EEXwC,iBFWxC,CEX0D,SFW1D,CAAA,CAAA,EEXuE,OFWvE,CAAA,IAAA,CAAA;EAAkB,KAAA,EAAA,GAAA,EETZ,MFSY,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,IAAA,EERX,aFQW,EAAA,GAAA,EEPZ,iBFOY,CEPM,SFON,CAAA,CAAA,EENhB,OFMgB,CAAA,IAAA,CAAA;sBEJX,uBACE,yBACH,kBAAkB,aACtB;;;;UCtCY,eAAA;;;AJIjB;UICiB,YAAA;yBACQ;;AHNb,UGSK,oBHTO,CAAA,YAAA,OAAA,CAAA,CAAA;EACZ,SAAA,QAAc,EGSL,SHTK;EAET,SAAA,YAAW,EGQH,YHNJ;EAKJ,YAAA,CAAA,IAAa,EGET,aHAA,EAAA,QAAA,EGAyB,SHEnB,CAAA,EAAA,IAAA;AAG3B;;;UIXiB,oBAAA;;;AJNjB;AACY,KIUA,gBAAA,GJVc,SAAA,GAAA,eAAA;AAET,UIUA,qBAAA,CJRI;EAKJ,SAAA,IAAA,EAAA,MAAa;EAOb,SAAA,MAAA,EAAA,MAAkB;EAOlB,SAAA,WAAA,EAAkB,MAAA;EAYnB,SAAA,OAAA,EInBI,gBJmBiB;EAC7B,SAAA,UAAA,CAAA,EAAA,MAAA;;AAEL,UIlBc,kBJkBd,CAAA,YAAA,OAAA,EAAA,UAAA,OAAA,EAAA,oBIfmB,UJenB,CIf8B,SJe9B,CAAA,GIf2C,UJe3C,CIfsD,SJetD,CAAA,CAAA,CAAA;EAAkB,SAAA,aAAA,EIbK,oBJaL,CIb0B,SJa1B,CAAA;mBIZF;mBACA;iCACc;EHkBjB,SAAA,IAAA,CAAA,EAAA,QAAA,GAAsB,YAAgB;iBGhBrC;;UAGA,wEAGK,WAAW,aAAa,WAAW,oBAC/C,kBACN,gBAAgB;EFjCR,SAAA,aAAQ,CAAA,EEkCO,SFlCP;EAIH,SAAA,WAAiB,CAAA,EE+BT,OF/BS;EAQjB,SAAA,UAAgB,EAAA,SEwBD,WFtBP,EAAA;EAGR,SAAA,iBAAU,EEoBG,iBFpBH,CEoBqB,SFpBrB,CAAA;EAEhB,UAAA,EAAA,EEmBK,OFnBL,CEmBa,iBFnBb,CAAA;EACgB,SAAA,EAAA,EEmBZ,qBFnBY,GAAA,IAAA;EAAlB,KAAA,EAAA,EEoBE,OFpBF,CAAA,IAAA,CAAA;;AACJ,UEsBY,iBAAA,SAA0B,gBFtBtC,CAAA;EACkB,WAAA,EAAA,EEsBN,OFtBM,CEsBE,kBFtBF,CAAA;EAAsC;;;;;;EAIpD,OAAA,EAAA,EEyBI,OFzBJ,CAAA,IAAA,CAAA;EACJ;;;;;;;;;;;ACjCL;AAKA;AAIA;EACqB,OAAA,CAAA,MAAA,CAAA,EAAA,OAAA,CAAA,EC8DQ,OD9DR,CAAA,IAAA,CAAA;;AAEA,UC+DJ,kBAAA,SAA2B,gBD/DvB,CAAA;EAAyB,MAAA,EAAA,ECgElC,ODhEkC,CAAA,IAAA,CAAA;EAAS,QAAA,EAAA,ECiEzC,ODjEyC,CAAA,IAAA,CAAA;;;;ACNvD;AAKA;AAEA;AAQA;;;;;;AAK0B,UAiET,gBAAA,CAjES;EACP,OAAA,CAAA,GAAA,CAAA,CAAA,IAAA,EAiEE,aAjEF,GAAA;IACA,SAAA,IAAA,CAAA,EAgEoC,GAhEpC;EACc,CAAA,CAAA,EA+D8B,qBA/D9B,CA+DkD,GA/DlD,CAAA;;AAiBtB,iBAiVK,iBAjVL,CAAA,YAAA,OAAA,EAAA,UAAA,OAAA,EAAA,oBAoVW,UApVX,CAoVsB,SApVtB,CAAA,GAoVmC,UApVnC,CAoV8C,SApV9C,CAAA,CAAA,CAAA,OAAA,EAsVA,kBAtVA,CAsVmB,SAtVnB,EAsV8B,OAtV9B,EAsVuC,WAtVvC,CAAA,CAAA,EAuVR,WAvVQ,CAuVI,SAvVJ,EAuVe,OAvVf,EAuVwB,WAvVxB,CAAA"}
package/dist/index.mjs CHANGED
@@ -149,13 +149,13 @@ function parseContractMarkerRow(row) {
149
149
  var RuntimeCoreImpl = class {
150
150
  _typeContract;
151
151
  _typeDriver;
152
+ middleware;
153
+ middlewareContext;
152
154
  contract;
153
155
  familyAdapter;
154
156
  driver;
155
- middleware;
156
157
  mode;
157
158
  verify;
158
- middlewareContext;
159
159
  verified;
160
160
  startupVerified;
161
161
  _telemetry;
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["lints: LintFinding[]","budgets: BudgetFinding[]","parsed: unknown","runtimeError","#executeWith","latencyMs","AsyncIterableResult"],"sources":["../src/fingerprint.ts","../src/guardrails/raw.ts","../src/marker.ts","../src/runtime-core.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\n\nconst STRING_LITERAL_REGEX = /'(?:''|[^'])*'/g;\nconst NUMERIC_LITERAL_REGEX = /\\b\\d+(?:\\.\\d+)?\\b/g;\nconst WHITESPACE_REGEX = /\\s+/g;\n\nexport function computeSqlFingerprint(sql: string): string {\n const withoutStrings = sql.replace(STRING_LITERAL_REGEX, '?');\n const withoutNumbers = withoutStrings.replace(NUMERIC_LITERAL_REGEX, '?');\n const normalized = withoutNumbers.replace(WHITESPACE_REGEX, ' ').trim().toLowerCase();\n\n const hash = createHash('sha256').update(normalized).digest('hex');\n return `sha256:${hash}`;\n}\n","import type { ExecutionPlan, PlanMeta, PlanRefs } from '@prisma-next/contract/types';\n\nexport type LintSeverity = 'error' | 'warn';\nexport type BudgetSeverity = 'error' | 'warn';\n\nexport interface LintFinding {\n readonly code: `LINT.${string}`;\n readonly severity: LintSeverity;\n readonly message: string;\n readonly details?: Record<string, unknown>;\n}\n\nexport interface BudgetFinding {\n readonly code: `BUDGET.${string}`;\n readonly severity: BudgetSeverity;\n readonly message: string;\n readonly details?: Record<string, unknown>;\n}\n\nexport interface RawGuardrailConfig {\n readonly budgets?: {\n readonly unboundedSelectSeverity?: BudgetSeverity;\n readonly estimatedRows?: number;\n };\n}\n\nexport interface RawGuardrailResult {\n readonly lints: LintFinding[];\n readonly budgets: BudgetFinding[];\n readonly statement: 'select' | 'mutation' | 'other';\n}\n\nconst SELECT_STAR_REGEX = /select\\s+\\*/i;\nconst LIMIT_REGEX = /\\blimit\\b/i;\nconst MUTATION_PREFIX_REGEX = /^(insert|update|delete|create|alter|drop|truncate)\\b/i;\n\nconst READ_ONLY_INTENTS = new Set(['read', 'report', 'readonly']);\n\nexport function evaluateRawGuardrails(\n plan: ExecutionPlan,\n config?: RawGuardrailConfig,\n): RawGuardrailResult {\n const lints: LintFinding[] = [];\n const budgets: BudgetFinding[] = [];\n\n const normalized = normalizeWhitespace(plan.sql);\n const statementType = classifyStatement(normalized);\n\n if (statementType === 'select') {\n if (SELECT_STAR_REGEX.test(normalized)) {\n lints.push(\n createLint('LINT.SELECT_STAR', 'error', 'Raw SQL plan selects all columns via *', {\n sql: snippet(plan.sql),\n }),\n );\n }\n\n if (!LIMIT_REGEX.test(normalized)) {\n const severity = config?.budgets?.unboundedSelectSeverity ?? 'error';\n lints.push(\n createLint('LINT.NO_LIMIT', 'warn', 'Raw SQL plan omits LIMIT clause', {\n sql: snippet(plan.sql),\n }),\n );\n\n budgets.push(\n createBudget(\n 'BUDGET.ROWS_EXCEEDED',\n severity,\n 'Raw SQL plan is unbounded and may exceed row budget',\n {\n sql: snippet(plan.sql),\n ...(config?.budgets?.estimatedRows !== undefined\n ? { estimatedRows: config.budgets.estimatedRows }\n : {}),\n },\n ),\n );\n }\n }\n\n if (isMutationStatement(statementType) && isReadOnlyIntent(plan.meta)) {\n lints.push(\n createLint(\n 'LINT.READ_ONLY_MUTATION',\n 'error',\n 'Raw SQL plan mutates data despite read-only intent',\n {\n sql: snippet(plan.sql),\n intent: plan.meta.annotations?.['intent'],\n },\n ),\n );\n }\n\n const refs = plan.meta.refs;\n if (refs) {\n evaluateIndexCoverage(refs, lints);\n }\n\n return { lints, budgets, statement: statementType };\n}\n\nfunction evaluateIndexCoverage(refs: PlanRefs, lints: LintFinding[]) {\n const predicateColumns = refs.columns ?? [];\n if (predicateColumns.length === 0) {\n return;\n }\n\n const indexes = refs.indexes ?? [];\n\n if (indexes.length === 0) {\n lints.push(\n createLint(\n 'LINT.UNINDEXED_PREDICATE',\n 'warn',\n 'Raw SQL plan predicates lack supporting indexes',\n {\n predicates: predicateColumns,\n },\n ),\n );\n return;\n }\n\n const hasSupportingIndex = predicateColumns.every((column) =>\n indexes.some(\n (index) =>\n index.table === column.table &&\n index.columns.some((col) => col.toLowerCase() === column.column.toLowerCase()),\n ),\n );\n\n if (!hasSupportingIndex) {\n lints.push(\n createLint(\n 'LINT.UNINDEXED_PREDICATE',\n 'warn',\n 'Raw SQL plan predicates lack supporting indexes',\n {\n predicates: predicateColumns,\n },\n ),\n );\n }\n}\n\nfunction classifyStatement(sql: string): 'select' | 'mutation' | 'other' {\n const trimmed = sql.trim();\n const lower = trimmed.toLowerCase();\n\n if (lower.startsWith('with')) {\n if (lower.includes('select')) {\n return 'select';\n }\n }\n\n if (lower.startsWith('select')) {\n return 'select';\n }\n\n if (MUTATION_PREFIX_REGEX.test(trimmed)) {\n return 'mutation';\n }\n\n return 'other';\n}\n\nfunction isMutationStatement(statement: 'select' | 'mutation' | 'other'): boolean {\n return statement === 'mutation';\n}\n\nfunction isReadOnlyIntent(meta: PlanMeta): boolean {\n const annotations = meta.annotations as { intent?: string } | undefined;\n const intent =\n typeof annotations?.intent === 'string' ? annotations.intent.toLowerCase() : undefined;\n return intent !== undefined && READ_ONLY_INTENTS.has(intent);\n}\n\nfunction normalizeWhitespace(value: string): string {\n return value.replace(/\\s+/g, ' ').trim();\n}\n\nfunction snippet(sql: string): string {\n return normalizeWhitespace(sql).slice(0, 200);\n}\n\nfunction createLint(\n code: LintFinding['code'],\n severity: LintFinding['severity'],\n message: string,\n details?: Record<string, unknown>,\n): LintFinding {\n return { code, severity, message, ...(details ? { details } : {}) };\n}\n\nfunction createBudget(\n code: BudgetFinding['code'],\n severity: BudgetFinding['severity'],\n message: string,\n details?: Record<string, unknown>,\n): BudgetFinding {\n return { code, severity, message, ...(details ? { details } : {}) };\n}\n","import type { ContractMarkerRecord } from '@prisma-next/contract/types';\nimport { type } from 'arktype';\n\nexport interface ContractMarkerRow {\n core_hash: string;\n profile_hash: string;\n contract_json: unknown | null;\n canonical_version: number | null;\n updated_at: Date;\n app_tag: string | null;\n meta: unknown | null;\n}\n\nconst MetaSchema = type({ '[string]': 'unknown' });\n\nfunction parseMeta(meta: unknown): Record<string, unknown> {\n if (meta === null || meta === undefined) {\n return {};\n }\n\n let parsed: unknown;\n if (typeof meta === 'string') {\n try {\n parsed = JSON.parse(meta);\n } catch {\n return {};\n }\n } else {\n parsed = meta;\n }\n\n const result = MetaSchema(parsed);\n if (result instanceof type.errors) {\n return {};\n }\n\n return result as Record<string, unknown>;\n}\n\nconst ContractMarkerRowSchema = type({\n core_hash: 'string',\n profile_hash: 'string',\n 'contract_json?': 'unknown | null',\n 'canonical_version?': 'number | null',\n 'updated_at?': 'Date | string',\n 'app_tag?': 'string | null',\n 'meta?': 'unknown | null',\n});\n\nexport function parseContractMarkerRow(row: unknown): ContractMarkerRecord {\n const result = ContractMarkerRowSchema(row);\n if (result instanceof type.errors) {\n const messages = result.map((p: { message: string }) => p.message).join('; ');\n throw new Error(`Invalid contract marker row: ${messages}`);\n }\n\n const validatedRow = result as {\n core_hash: string;\n profile_hash: string;\n contract_json?: unknown | null;\n canonical_version?: number | null;\n updated_at?: Date | string;\n app_tag?: string | null;\n meta?: unknown | null;\n };\n\n const updatedAt = validatedRow.updated_at\n ? validatedRow.updated_at instanceof Date\n ? validatedRow.updated_at\n : new Date(validatedRow.updated_at)\n : new Date();\n\n return {\n storageHash: validatedRow.core_hash,\n profileHash: validatedRow.profile_hash,\n contractJson: validatedRow.contract_json ?? null,\n canonicalVersion: validatedRow.canonical_version ?? null,\n updatedAt,\n appTag: validatedRow.app_tag ?? null,\n meta: parseMeta(validatedRow.meta),\n };\n}\n","import type { ExecutionPlan } from '@prisma-next/contract/types';\nimport type { RuntimeExecutor } from '@prisma-next/framework-components/runtime';\nimport { AsyncIterableResult, runtimeError } from '@prisma-next/framework-components/runtime';\nimport { computeSqlFingerprint } from './fingerprint';\nimport { parseContractMarkerRow } from './marker';\nimport type { Log, Middleware, MiddlewareContext } from './middleware/types';\nimport type { RuntimeFamilyAdapter } from './runtime-spi';\n\nexport interface RuntimeVerifyOptions {\n readonly mode: 'onFirstUse' | 'startup' | 'always';\n readonly requireMarker: boolean;\n}\n\nexport type TelemetryOutcome = 'success' | 'runtime-error';\n\nexport interface RuntimeTelemetryEvent {\n readonly lane: string;\n readonly target: string;\n readonly fingerprint: string;\n readonly outcome: TelemetryOutcome;\n readonly durationMs?: number;\n}\n\nexport interface RuntimeCoreOptions<TContract = unknown, TDriver = unknown> {\n readonly familyAdapter: RuntimeFamilyAdapter<TContract>;\n readonly driver: TDriver;\n readonly verify: RuntimeVerifyOptions;\n readonly middleware?: readonly Middleware<TContract>[];\n readonly mode?: 'strict' | 'permissive';\n readonly log?: Log;\n}\n\nexport interface RuntimeCore<TContract = unknown, TDriver = unknown>\n extends RuntimeQueryable,\n RuntimeExecutor<ExecutionPlan> {\n readonly _typeContract?: TContract;\n readonly _typeDriver?: TDriver;\n connection(): Promise<RuntimeConnection>;\n telemetry(): RuntimeTelemetryEvent | null;\n close(): Promise<void>;\n}\n\nexport interface RuntimeConnection extends RuntimeQueryable {\n transaction(): Promise<RuntimeTransaction>;\n /**\n * Returns the connection to the pool for reuse. Only call this when the\n * connection is known to be in a clean state. If a transaction\n * commit/rollback failed or the connection is otherwise suspect, call\n * `destroy(reason)` instead.\n */\n release(): Promise<void>;\n /**\n * Evicts the connection so it is never reused. Call this when the\n * connection may be in an indeterminate state (e.g. a failed rollback\n * leaving an open transaction, or a broken socket).\n *\n * If teardown fails the error is propagated and the connection remains\n * retryable, so the caller can decide whether to swallow the failure or\n * retry cleanup. Calling destroy() or release() more than once after a\n * successful teardown is caller error.\n *\n * `reason` is advisory context only. It may be surfaced to driver-level\n * observability hooks (e.g. pg-pool's `'release'` event) but does not\n * influence eviction behavior and is not rethrown.\n */\n destroy(reason?: unknown): Promise<void>;\n}\n\nexport interface RuntimeTransaction extends RuntimeQueryable {\n commit(): Promise<void>;\n rollback(): Promise<void>;\n}\n\n/**\n * Shared query execution trait for anything that can run an ExecutionPlan:\n * RuntimeCore, RuntimeConnection, and RuntimeTransaction. This is a\n * SQL-domain internal mixin — it is NOT the cross-family SPI.\n *\n * For the cross-family SPI, see RuntimeExecutor in framework-components.\n * RuntimeCore nominally extends both this interface and RuntimeExecutor.\n *\n * The execute signature uses the same `_row` phantom intersection as\n * RuntimeExecutor so that RuntimeCore can extend both without conflicts.\n */\nexport interface RuntimeQueryable {\n execute<Row>(plan: ExecutionPlan & { readonly _row?: Row }): AsyncIterableResult<Row>;\n}\n\ninterface DriverWithQuery<_TDriver> {\n query(sql: string, params: readonly unknown[]): Promise<{ rows: ReadonlyArray<unknown> }>;\n}\n\ninterface DriverWithConnection<_TDriver> {\n acquireConnection(): Promise<DriverConnection>;\n}\n\nexport interface DriverConnection extends Queryable {\n beginTransaction(): Promise<DriverTransaction>;\n release(): Promise<void>;\n destroy(reason?: unknown): Promise<void>;\n}\n\nexport interface DriverTransaction extends Queryable {\n commit(): Promise<void>;\n rollback(): Promise<void>;\n}\n\nexport interface Queryable {\n execute<Row = Record<string, unknown>>(options: {\n sql: string;\n params: readonly unknown[];\n }): AsyncIterable<Row>;\n}\n\ninterface DriverWithClose<_TDriver> {\n close(): Promise<void>;\n}\n\nclass RuntimeCoreImpl<TContract = unknown, TDriver = unknown>\n implements RuntimeCore<TContract, TDriver>\n{\n readonly _typeContract?: TContract;\n readonly _typeDriver?: TDriver;\n private readonly contract: TContract;\n private readonly familyAdapter: RuntimeFamilyAdapter<TContract>;\n private readonly driver: TDriver;\n private readonly middleware: readonly Middleware<TContract>[];\n private readonly mode: 'strict' | 'permissive';\n private readonly verify: RuntimeVerifyOptions;\n private readonly middlewareContext: MiddlewareContext<TContract>;\n\n private verified: boolean;\n private startupVerified: boolean;\n private _telemetry: RuntimeTelemetryEvent | null;\n\n constructor(options: RuntimeCoreOptions<TContract, TDriver>) {\n const { familyAdapter, driver } = options;\n this.contract = familyAdapter.contract;\n this.familyAdapter = familyAdapter;\n this.driver = driver;\n this.middleware = options.middleware ?? [];\n this.mode = options.mode ?? 'strict';\n this.verify = options.verify;\n this.verified = options.verify.mode === 'startup' ? false : options.verify.mode === 'always';\n this.startupVerified = false;\n this._telemetry = null;\n\n this.middlewareContext = {\n contract: this.contract,\n mode: this.mode,\n now: () => Date.now(),\n log: options.log ?? {\n info: () => {},\n warn: () => {},\n error: () => {},\n },\n };\n }\n\n private async verifyPlanIfNeeded(_plan: ExecutionPlan): Promise<void> {\n void _plan;\n if (this.verify.mode === 'always') {\n this.verified = false;\n }\n\n if (this.verified) {\n return;\n }\n\n const readStatement = this.familyAdapter.markerReader.readMarkerStatement();\n const driver = this.driver as unknown as DriverWithQuery<TDriver>;\n const result = await driver.query(readStatement.sql, readStatement.params);\n\n if (result.rows.length === 0) {\n if (this.verify.requireMarker) {\n throw runtimeError('CONTRACT.MARKER_MISSING', 'Contract marker not found in database');\n }\n\n this.verified = true;\n return;\n }\n\n const marker = parseContractMarkerRow(result.rows[0]);\n\n const contract = this.contract as {\n storage: { storageHash: string };\n execution?: { executionHash?: string | null };\n profileHash?: string | null;\n };\n if (marker.storageHash !== contract.storage.storageHash) {\n throw runtimeError(\n 'CONTRACT.MARKER_MISMATCH',\n 'Database storage hash does not match contract',\n {\n expected: contract.storage.storageHash,\n actual: marker.storageHash,\n },\n );\n }\n\n const expectedProfile = contract.profileHash ?? null;\n if (expectedProfile !== null && marker.profileHash !== expectedProfile) {\n throw runtimeError(\n 'CONTRACT.MARKER_MISMATCH',\n 'Database profile hash does not match contract',\n {\n expectedProfile,\n actualProfile: marker.profileHash,\n },\n );\n }\n\n this.verified = true;\n this.startupVerified = true;\n }\n\n private validatePlan(plan: ExecutionPlan): void {\n this.familyAdapter.validatePlan(plan, this.contract);\n }\n\n private recordTelemetry(\n plan: ExecutionPlan,\n outcome: TelemetryOutcome,\n durationMs?: number,\n ): void {\n const contract = this.contract as { target: string };\n this._telemetry = Object.freeze({\n lane: plan.meta.lane,\n target: contract.target,\n fingerprint: computeSqlFingerprint(plan.sql),\n outcome,\n ...(durationMs !== undefined ? { durationMs } : {}),\n });\n }\n\n execute<Row = Record<string, unknown>>(plan: ExecutionPlan<Row>): AsyncIterableResult<Row> {\n return this.#executeWith(plan, this.driver as Queryable);\n }\n\n async connection(): Promise<RuntimeConnection> {\n const driver = this.driver as unknown as DriverWithConnection<TDriver>;\n const driverConn = await driver.acquireConnection();\n const self = this;\n\n const runtimeConnection: RuntimeConnection = {\n async transaction(): Promise<RuntimeTransaction> {\n const driverTx = await driverConn.beginTransaction();\n const runtimeTx: RuntimeTransaction = {\n async commit(): Promise<void> {\n await driverTx.commit();\n },\n async rollback(): Promise<void> {\n await driverTx.rollback();\n },\n execute<Row = Record<string, unknown>>(\n plan: ExecutionPlan<Row>,\n ): AsyncIterableResult<Row> {\n return self.#executeWith(plan, driverTx);\n },\n };\n return runtimeTx;\n },\n execute<Row = Record<string, unknown>>(plan: ExecutionPlan<Row>): AsyncIterableResult<Row> {\n return self.#executeWith(plan, driverConn);\n },\n async release(): Promise<void> {\n await driverConn.release();\n },\n async destroy(reason?: unknown): Promise<void> {\n await driverConn.destroy(reason);\n },\n };\n\n return runtimeConnection;\n }\n\n telemetry(): RuntimeTelemetryEvent | null {\n return this._telemetry;\n }\n\n close(): Promise<void> {\n const driver = this.driver as unknown as DriverWithClose<TDriver>;\n if (typeof driver.close === 'function') {\n return driver.close();\n }\n return Promise.resolve();\n }\n\n #executeWith<Row = Record<string, unknown>>(\n plan: ExecutionPlan<Row>,\n queryable: Queryable,\n ): AsyncIterableResult<Row> {\n this.validatePlan(plan);\n this._telemetry = null;\n\n const iterator = async function* (\n self: RuntimeCoreImpl<TContract, TDriver>,\n ): AsyncGenerator<Row, void, unknown> {\n const startedAt = Date.now();\n let rowCount = 0;\n let completed = false;\n\n if (!self.startupVerified && self.verify.mode === 'startup') {\n await self.verifyPlanIfNeeded(plan);\n }\n\n if (self.verify.mode === 'onFirstUse') {\n await self.verifyPlanIfNeeded(plan);\n }\n\n try {\n if (self.verify.mode === 'always') {\n await self.verifyPlanIfNeeded(plan);\n }\n\n for (const mw of self.middleware) {\n if (mw.beforeExecute) {\n await mw.beforeExecute(plan, self.middlewareContext);\n }\n }\n\n const encodedParams = plan.params;\n\n for await (const row of queryable.execute<Record<string, unknown>>({\n sql: plan.sql,\n params: encodedParams,\n })) {\n for (const mw of self.middleware) {\n if (mw.onRow) {\n await mw.onRow(row, plan, self.middlewareContext);\n }\n }\n rowCount++;\n yield row as Row;\n }\n\n completed = true;\n self.recordTelemetry(plan, 'success', Date.now() - startedAt);\n } catch (error) {\n if (self._telemetry === null) {\n self.recordTelemetry(plan, 'runtime-error', Date.now() - startedAt);\n }\n\n const latencyMs = Date.now() - startedAt;\n for (const mw of self.middleware) {\n if (mw.afterExecute) {\n try {\n await mw.afterExecute(\n plan,\n { rowCount, latencyMs, completed },\n self.middlewareContext,\n );\n } catch {\n // Ignore errors from afterExecute hooks\n }\n }\n }\n\n throw error;\n }\n\n const latencyMs = Date.now() - startedAt;\n for (const mw of self.middleware) {\n if (mw.afterExecute) {\n await mw.afterExecute(plan, { rowCount, latencyMs, completed }, self.middlewareContext);\n }\n }\n };\n\n return new AsyncIterableResult(iterator(this));\n }\n}\n\nexport function createRuntimeCore<TContract = unknown, TDriver = unknown>(\n options: RuntimeCoreOptions<TContract, TDriver>,\n): RuntimeCore<TContract, TDriver> {\n return new RuntimeCoreImpl(options);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["lints: LintFinding[]","budgets: BudgetFinding[]","parsed: unknown","runtimeError","#executeWith","latencyMs","AsyncIterableResult"],"sources":["../src/fingerprint.ts","../src/guardrails/raw.ts","../src/marker.ts","../src/runtime-core.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\n\nconst STRING_LITERAL_REGEX = /'(?:''|[^'])*'/g;\nconst NUMERIC_LITERAL_REGEX = /\\b\\d+(?:\\.\\d+)?\\b/g;\nconst WHITESPACE_REGEX = /\\s+/g;\n\nexport function computeSqlFingerprint(sql: string): string {\n const withoutStrings = sql.replace(STRING_LITERAL_REGEX, '?');\n const withoutNumbers = withoutStrings.replace(NUMERIC_LITERAL_REGEX, '?');\n const normalized = withoutNumbers.replace(WHITESPACE_REGEX, ' ').trim().toLowerCase();\n\n const hash = createHash('sha256').update(normalized).digest('hex');\n return `sha256:${hash}`;\n}\n","import type { ExecutionPlan, PlanMeta, PlanRefs } from '@prisma-next/contract/types';\n\nexport type LintSeverity = 'error' | 'warn';\nexport type BudgetSeverity = 'error' | 'warn';\n\nexport interface LintFinding {\n readonly code: `LINT.${string}`;\n readonly severity: LintSeverity;\n readonly message: string;\n readonly details?: Record<string, unknown>;\n}\n\nexport interface BudgetFinding {\n readonly code: `BUDGET.${string}`;\n readonly severity: BudgetSeverity;\n readonly message: string;\n readonly details?: Record<string, unknown>;\n}\n\nexport interface RawGuardrailConfig {\n readonly budgets?: {\n readonly unboundedSelectSeverity?: BudgetSeverity;\n readonly estimatedRows?: number;\n };\n}\n\nexport interface RawGuardrailResult {\n readonly lints: LintFinding[];\n readonly budgets: BudgetFinding[];\n readonly statement: 'select' | 'mutation' | 'other';\n}\n\nconst SELECT_STAR_REGEX = /select\\s+\\*/i;\nconst LIMIT_REGEX = /\\blimit\\b/i;\nconst MUTATION_PREFIX_REGEX = /^(insert|update|delete|create|alter|drop|truncate)\\b/i;\n\nconst READ_ONLY_INTENTS = new Set(['read', 'report', 'readonly']);\n\nexport function evaluateRawGuardrails(\n plan: ExecutionPlan,\n config?: RawGuardrailConfig,\n): RawGuardrailResult {\n const lints: LintFinding[] = [];\n const budgets: BudgetFinding[] = [];\n\n const normalized = normalizeWhitespace(plan.sql);\n const statementType = classifyStatement(normalized);\n\n if (statementType === 'select') {\n if (SELECT_STAR_REGEX.test(normalized)) {\n lints.push(\n createLint('LINT.SELECT_STAR', 'error', 'Raw SQL plan selects all columns via *', {\n sql: snippet(plan.sql),\n }),\n );\n }\n\n if (!LIMIT_REGEX.test(normalized)) {\n const severity = config?.budgets?.unboundedSelectSeverity ?? 'error';\n lints.push(\n createLint('LINT.NO_LIMIT', 'warn', 'Raw SQL plan omits LIMIT clause', {\n sql: snippet(plan.sql),\n }),\n );\n\n budgets.push(\n createBudget(\n 'BUDGET.ROWS_EXCEEDED',\n severity,\n 'Raw SQL plan is unbounded and may exceed row budget',\n {\n sql: snippet(plan.sql),\n ...(config?.budgets?.estimatedRows !== undefined\n ? { estimatedRows: config.budgets.estimatedRows }\n : {}),\n },\n ),\n );\n }\n }\n\n if (isMutationStatement(statementType) && isReadOnlyIntent(plan.meta)) {\n lints.push(\n createLint(\n 'LINT.READ_ONLY_MUTATION',\n 'error',\n 'Raw SQL plan mutates data despite read-only intent',\n {\n sql: snippet(plan.sql),\n intent: plan.meta.annotations?.['intent'],\n },\n ),\n );\n }\n\n const refs = plan.meta.refs;\n if (refs) {\n evaluateIndexCoverage(refs, lints);\n }\n\n return { lints, budgets, statement: statementType };\n}\n\nfunction evaluateIndexCoverage(refs: PlanRefs, lints: LintFinding[]) {\n const predicateColumns = refs.columns ?? [];\n if (predicateColumns.length === 0) {\n return;\n }\n\n const indexes = refs.indexes ?? [];\n\n if (indexes.length === 0) {\n lints.push(\n createLint(\n 'LINT.UNINDEXED_PREDICATE',\n 'warn',\n 'Raw SQL plan predicates lack supporting indexes',\n {\n predicates: predicateColumns,\n },\n ),\n );\n return;\n }\n\n const hasSupportingIndex = predicateColumns.every((column) =>\n indexes.some(\n (index) =>\n index.table === column.table &&\n index.columns.some((col) => col.toLowerCase() === column.column.toLowerCase()),\n ),\n );\n\n if (!hasSupportingIndex) {\n lints.push(\n createLint(\n 'LINT.UNINDEXED_PREDICATE',\n 'warn',\n 'Raw SQL plan predicates lack supporting indexes',\n {\n predicates: predicateColumns,\n },\n ),\n );\n }\n}\n\nfunction classifyStatement(sql: string): 'select' | 'mutation' | 'other' {\n const trimmed = sql.trim();\n const lower = trimmed.toLowerCase();\n\n if (lower.startsWith('with')) {\n if (lower.includes('select')) {\n return 'select';\n }\n }\n\n if (lower.startsWith('select')) {\n return 'select';\n }\n\n if (MUTATION_PREFIX_REGEX.test(trimmed)) {\n return 'mutation';\n }\n\n return 'other';\n}\n\nfunction isMutationStatement(statement: 'select' | 'mutation' | 'other'): boolean {\n return statement === 'mutation';\n}\n\nfunction isReadOnlyIntent(meta: PlanMeta): boolean {\n const annotations = meta.annotations as { intent?: string } | undefined;\n const intent =\n typeof annotations?.intent === 'string' ? annotations.intent.toLowerCase() : undefined;\n return intent !== undefined && READ_ONLY_INTENTS.has(intent);\n}\n\nfunction normalizeWhitespace(value: string): string {\n return value.replace(/\\s+/g, ' ').trim();\n}\n\nfunction snippet(sql: string): string {\n return normalizeWhitespace(sql).slice(0, 200);\n}\n\nfunction createLint(\n code: LintFinding['code'],\n severity: LintFinding['severity'],\n message: string,\n details?: Record<string, unknown>,\n): LintFinding {\n return { code, severity, message, ...(details ? { details } : {}) };\n}\n\nfunction createBudget(\n code: BudgetFinding['code'],\n severity: BudgetFinding['severity'],\n message: string,\n details?: Record<string, unknown>,\n): BudgetFinding {\n return { code, severity, message, ...(details ? { details } : {}) };\n}\n","import type { ContractMarkerRecord } from '@prisma-next/contract/types';\nimport { type } from 'arktype';\n\nexport interface ContractMarkerRow {\n core_hash: string;\n profile_hash: string;\n contract_json: unknown | null;\n canonical_version: number | null;\n updated_at: Date;\n app_tag: string | null;\n meta: unknown | null;\n}\n\nconst MetaSchema = type({ '[string]': 'unknown' });\n\nfunction parseMeta(meta: unknown): Record<string, unknown> {\n if (meta === null || meta === undefined) {\n return {};\n }\n\n let parsed: unknown;\n if (typeof meta === 'string') {\n try {\n parsed = JSON.parse(meta);\n } catch {\n return {};\n }\n } else {\n parsed = meta;\n }\n\n const result = MetaSchema(parsed);\n if (result instanceof type.errors) {\n return {};\n }\n\n return result as Record<string, unknown>;\n}\n\nconst ContractMarkerRowSchema = type({\n core_hash: 'string',\n profile_hash: 'string',\n 'contract_json?': 'unknown | null',\n 'canonical_version?': 'number | null',\n 'updated_at?': 'Date | string',\n 'app_tag?': 'string | null',\n 'meta?': 'unknown | null',\n});\n\nexport function parseContractMarkerRow(row: unknown): ContractMarkerRecord {\n const result = ContractMarkerRowSchema(row);\n if (result instanceof type.errors) {\n const messages = result.map((p: { message: string }) => p.message).join('; ');\n throw new Error(`Invalid contract marker row: ${messages}`);\n }\n\n const validatedRow = result as {\n core_hash: string;\n profile_hash: string;\n contract_json?: unknown | null;\n canonical_version?: number | null;\n updated_at?: Date | string;\n app_tag?: string | null;\n meta?: unknown | null;\n };\n\n const updatedAt = validatedRow.updated_at\n ? validatedRow.updated_at instanceof Date\n ? validatedRow.updated_at\n : new Date(validatedRow.updated_at)\n : new Date();\n\n return {\n storageHash: validatedRow.core_hash,\n profileHash: validatedRow.profile_hash,\n contractJson: validatedRow.contract_json ?? null,\n canonicalVersion: validatedRow.canonical_version ?? null,\n updatedAt,\n appTag: validatedRow.app_tag ?? null,\n meta: parseMeta(validatedRow.meta),\n };\n}\n","import type { ExecutionPlan } from '@prisma-next/contract/types';\nimport type { RuntimeExecutor } from '@prisma-next/framework-components/runtime';\nimport { AsyncIterableResult, runtimeError } from '@prisma-next/framework-components/runtime';\nimport { computeSqlFingerprint } from './fingerprint';\nimport { parseContractMarkerRow } from './marker';\nimport type { Log, Middleware, MiddlewareContext } from './middleware/types';\nimport type { RuntimeFamilyAdapter } from './runtime-spi';\n\nexport interface RuntimeVerifyOptions {\n readonly mode: 'onFirstUse' | 'startup' | 'always';\n readonly requireMarker: boolean;\n}\n\nexport type TelemetryOutcome = 'success' | 'runtime-error';\n\nexport interface RuntimeTelemetryEvent {\n readonly lane: string;\n readonly target: string;\n readonly fingerprint: string;\n readonly outcome: TelemetryOutcome;\n readonly durationMs?: number;\n}\n\nexport interface RuntimeCoreOptions<\n TContract = unknown,\n TDriver = unknown,\n TMiddleware extends Middleware<TContract> = Middleware<TContract>,\n> {\n readonly familyAdapter: RuntimeFamilyAdapter<TContract>;\n readonly driver: TDriver;\n readonly verify: RuntimeVerifyOptions;\n readonly middleware?: readonly TMiddleware[];\n readonly mode?: 'strict' | 'permissive';\n readonly log?: Log;\n}\n\nexport interface RuntimeCore<\n TContract = unknown,\n TDriver = unknown,\n TMiddleware extends Middleware<TContract> = Middleware<TContract>,\n> extends RuntimeQueryable,\n RuntimeExecutor<ExecutionPlan> {\n readonly _typeContract?: TContract;\n readonly _typeDriver?: TDriver;\n readonly middleware: readonly TMiddleware[];\n readonly middlewareContext: MiddlewareContext<TContract>;\n connection(): Promise<RuntimeConnection>;\n telemetry(): RuntimeTelemetryEvent | null;\n close(): Promise<void>;\n}\n\nexport interface RuntimeConnection extends RuntimeQueryable {\n transaction(): Promise<RuntimeTransaction>;\n /**\n * Returns the connection to the pool for reuse. Only call this when the\n * connection is known to be in a clean state. If a transaction\n * commit/rollback failed or the connection is otherwise suspect, call\n * `destroy(reason)` instead.\n */\n release(): Promise<void>;\n /**\n * Evicts the connection so it is never reused. Call this when the\n * connection may be in an indeterminate state (e.g. a failed rollback\n * leaving an open transaction, or a broken socket).\n *\n * If teardown fails the error is propagated and the connection remains\n * retryable, so the caller can decide whether to swallow the failure or\n * retry cleanup. Calling destroy() or release() more than once after a\n * successful teardown is caller error.\n *\n * `reason` is advisory context only. It may be surfaced to driver-level\n * observability hooks (e.g. pg-pool's `'release'` event) but does not\n * influence eviction behavior and is not rethrown.\n */\n destroy(reason?: unknown): Promise<void>;\n}\n\nexport interface RuntimeTransaction extends RuntimeQueryable {\n commit(): Promise<void>;\n rollback(): Promise<void>;\n}\n\n/**\n * Shared query execution trait for anything that can run an ExecutionPlan:\n * RuntimeCore, RuntimeConnection, and RuntimeTransaction. This is a\n * SQL-domain internal mixin — it is NOT the cross-family SPI.\n *\n * For the cross-family SPI, see RuntimeExecutor in framework-components.\n * RuntimeCore nominally extends both this interface and RuntimeExecutor.\n *\n * The execute signature uses the same `_row` phantom intersection as\n * RuntimeExecutor so that RuntimeCore can extend both without conflicts.\n */\nexport interface RuntimeQueryable {\n execute<Row>(plan: ExecutionPlan & { readonly _row?: Row }): AsyncIterableResult<Row>;\n}\n\ninterface DriverWithQuery<_TDriver> {\n query(sql: string, params: readonly unknown[]): Promise<{ rows: ReadonlyArray<unknown> }>;\n}\n\ninterface DriverWithConnection<_TDriver> {\n acquireConnection(): Promise<DriverConnection>;\n}\n\nexport interface DriverConnection extends Queryable {\n beginTransaction(): Promise<DriverTransaction>;\n release(): Promise<void>;\n destroy(reason?: unknown): Promise<void>;\n}\n\nexport interface DriverTransaction extends Queryable {\n commit(): Promise<void>;\n rollback(): Promise<void>;\n}\n\nexport interface Queryable {\n execute<Row = Record<string, unknown>>(options: {\n sql: string;\n params: readonly unknown[];\n }): AsyncIterable<Row>;\n}\n\ninterface DriverWithClose<_TDriver> {\n close(): Promise<void>;\n}\n\nclass RuntimeCoreImpl<\n TContract = unknown,\n TDriver = unknown,\n TMiddleware extends Middleware<TContract> = Middleware<TContract>,\n> implements RuntimeCore<TContract, TDriver, TMiddleware>\n{\n readonly _typeContract?: TContract;\n readonly _typeDriver?: TDriver;\n readonly middleware: readonly TMiddleware[];\n readonly middlewareContext: MiddlewareContext<TContract>;\n private readonly contract: TContract;\n private readonly familyAdapter: RuntimeFamilyAdapter<TContract>;\n private readonly driver: TDriver;\n private readonly mode: 'strict' | 'permissive';\n private readonly verify: RuntimeVerifyOptions;\n\n private verified: boolean;\n private startupVerified: boolean;\n private _telemetry: RuntimeTelemetryEvent | null;\n\n constructor(options: RuntimeCoreOptions<TContract, TDriver, TMiddleware>) {\n const { familyAdapter, driver } = options;\n this.contract = familyAdapter.contract;\n this.familyAdapter = familyAdapter;\n this.driver = driver;\n this.middleware = options.middleware ?? [];\n this.mode = options.mode ?? 'strict';\n this.verify = options.verify;\n this.verified = options.verify.mode === 'startup' ? false : options.verify.mode === 'always';\n this.startupVerified = false;\n this._telemetry = null;\n\n this.middlewareContext = {\n contract: this.contract,\n mode: this.mode,\n now: () => Date.now(),\n log: options.log ?? {\n info: () => {},\n warn: () => {},\n error: () => {},\n },\n };\n }\n\n private async verifyPlanIfNeeded(_plan: ExecutionPlan): Promise<void> {\n void _plan;\n if (this.verify.mode === 'always') {\n this.verified = false;\n }\n\n if (this.verified) {\n return;\n }\n\n const readStatement = this.familyAdapter.markerReader.readMarkerStatement();\n const driver = this.driver as unknown as DriverWithQuery<TDriver>;\n const result = await driver.query(readStatement.sql, readStatement.params);\n\n if (result.rows.length === 0) {\n if (this.verify.requireMarker) {\n throw runtimeError('CONTRACT.MARKER_MISSING', 'Contract marker not found in database');\n }\n\n this.verified = true;\n return;\n }\n\n const marker = parseContractMarkerRow(result.rows[0]);\n\n const contract = this.contract as {\n storage: { storageHash: string };\n execution?: { executionHash?: string | null };\n profileHash?: string | null;\n };\n if (marker.storageHash !== contract.storage.storageHash) {\n throw runtimeError(\n 'CONTRACT.MARKER_MISMATCH',\n 'Database storage hash does not match contract',\n {\n expected: contract.storage.storageHash,\n actual: marker.storageHash,\n },\n );\n }\n\n const expectedProfile = contract.profileHash ?? null;\n if (expectedProfile !== null && marker.profileHash !== expectedProfile) {\n throw runtimeError(\n 'CONTRACT.MARKER_MISMATCH',\n 'Database profile hash does not match contract',\n {\n expectedProfile,\n actualProfile: marker.profileHash,\n },\n );\n }\n\n this.verified = true;\n this.startupVerified = true;\n }\n\n private validatePlan(plan: ExecutionPlan): void {\n this.familyAdapter.validatePlan(plan, this.contract);\n }\n\n private recordTelemetry(\n plan: ExecutionPlan,\n outcome: TelemetryOutcome,\n durationMs?: number,\n ): void {\n const contract = this.contract as { target: string };\n this._telemetry = Object.freeze({\n lane: plan.meta.lane,\n target: contract.target,\n fingerprint: computeSqlFingerprint(plan.sql),\n outcome,\n ...(durationMs !== undefined ? { durationMs } : {}),\n });\n }\n\n execute<Row = Record<string, unknown>>(plan: ExecutionPlan<Row>): AsyncIterableResult<Row> {\n return this.#executeWith(plan, this.driver as Queryable);\n }\n\n async connection(): Promise<RuntimeConnection> {\n const driver = this.driver as unknown as DriverWithConnection<TDriver>;\n const driverConn = await driver.acquireConnection();\n const self = this;\n\n const runtimeConnection: RuntimeConnection = {\n async transaction(): Promise<RuntimeTransaction> {\n const driverTx = await driverConn.beginTransaction();\n const runtimeTx: RuntimeTransaction = {\n async commit(): Promise<void> {\n await driverTx.commit();\n },\n async rollback(): Promise<void> {\n await driverTx.rollback();\n },\n execute<Row = Record<string, unknown>>(\n plan: ExecutionPlan<Row>,\n ): AsyncIterableResult<Row> {\n return self.#executeWith(plan, driverTx);\n },\n };\n return runtimeTx;\n },\n execute<Row = Record<string, unknown>>(plan: ExecutionPlan<Row>): AsyncIterableResult<Row> {\n return self.#executeWith(plan, driverConn);\n },\n async release(): Promise<void> {\n await driverConn.release();\n },\n async destroy(reason?: unknown): Promise<void> {\n await driverConn.destroy(reason);\n },\n };\n\n return runtimeConnection;\n }\n\n telemetry(): RuntimeTelemetryEvent | null {\n return this._telemetry;\n }\n\n close(): Promise<void> {\n const driver = this.driver as unknown as DriverWithClose<TDriver>;\n if (typeof driver.close === 'function') {\n return driver.close();\n }\n return Promise.resolve();\n }\n\n #executeWith<Row = Record<string, unknown>>(\n plan: ExecutionPlan<Row>,\n queryable: Queryable,\n ): AsyncIterableResult<Row> {\n this.validatePlan(plan);\n this._telemetry = null;\n\n const iterator = async function* (\n self: RuntimeCoreImpl<TContract, TDriver>,\n ): AsyncGenerator<Row, void, unknown> {\n const startedAt = Date.now();\n let rowCount = 0;\n let completed = false;\n\n if (!self.startupVerified && self.verify.mode === 'startup') {\n await self.verifyPlanIfNeeded(plan);\n }\n\n if (self.verify.mode === 'onFirstUse') {\n await self.verifyPlanIfNeeded(plan);\n }\n\n try {\n if (self.verify.mode === 'always') {\n await self.verifyPlanIfNeeded(plan);\n }\n\n for (const mw of self.middleware) {\n if (mw.beforeExecute) {\n await mw.beforeExecute(plan, self.middlewareContext);\n }\n }\n\n const encodedParams = plan.params;\n\n for await (const row of queryable.execute<Record<string, unknown>>({\n sql: plan.sql,\n params: encodedParams,\n })) {\n for (const mw of self.middleware) {\n if (mw.onRow) {\n await mw.onRow(row, plan, self.middlewareContext);\n }\n }\n rowCount++;\n yield row as Row;\n }\n\n completed = true;\n self.recordTelemetry(plan, 'success', Date.now() - startedAt);\n } catch (error) {\n if (self._telemetry === null) {\n self.recordTelemetry(plan, 'runtime-error', Date.now() - startedAt);\n }\n\n const latencyMs = Date.now() - startedAt;\n for (const mw of self.middleware) {\n if (mw.afterExecute) {\n try {\n await mw.afterExecute(\n plan,\n { rowCount, latencyMs, completed },\n self.middlewareContext,\n );\n } catch {\n // Ignore errors from afterExecute hooks\n }\n }\n }\n\n throw error;\n }\n\n const latencyMs = Date.now() - startedAt;\n for (const mw of self.middleware) {\n if (mw.afterExecute) {\n await mw.afterExecute(plan, { rowCount, latencyMs, completed }, self.middlewareContext);\n }\n }\n };\n\n return new AsyncIterableResult(iterator(this));\n }\n}\n\nexport function createRuntimeCore<\n TContract = unknown,\n TDriver = unknown,\n TMiddleware extends Middleware<TContract> = Middleware<TContract>,\n>(\n options: RuntimeCoreOptions<TContract, TDriver, TMiddleware>,\n): RuntimeCore<TContract, TDriver, TMiddleware> {\n return new RuntimeCoreImpl(options);\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,22 +1,22 @@
1
1
  {
2
2
  "name": "@prisma-next/runtime-executor",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "description": "Target-agnostic execution engine for Prisma Next",
7
7
  "dependencies": {
8
8
  "arktype": "^2.1.25",
9
- "@prisma-next/framework-components": "0.4.1",
10
- "@prisma-next/contract": "0.4.1",
11
- "@prisma-next/operations": "0.4.1"
9
+ "@prisma-next/framework-components": "0.4.2",
10
+ "@prisma-next/contract": "0.4.2",
11
+ "@prisma-next/operations": "0.4.2"
12
12
  },
13
13
  "devDependencies": {
14
14
  "@prisma/dev": "0.19.1",
15
15
  "tsdown": "0.18.4",
16
16
  "typescript": "5.9.3",
17
17
  "vitest": "4.0.17",
18
- "@prisma-next/tsconfig": "0.0.0",
19
18
  "@prisma-next/test-utils": "0.0.1",
19
+ "@prisma-next/tsconfig": "0.0.0",
20
20
  "@prisma-next/tsdown": "0.0.0"
21
21
  },
22
22
  "files": [
@@ -1,4 +1,4 @@
1
- import type { ExecutionPlan } from '@prisma-next/contract/types';
1
+ import type { ExecutionPlan, PlanMeta } from '@prisma-next/contract/types';
2
2
  import type {
3
3
  AfterExecuteResult,
4
4
  RuntimeLog,
@@ -14,7 +14,20 @@ export interface MiddlewareContext<TContract = unknown> extends RuntimeMiddlewar
14
14
  readonly contract: TContract;
15
15
  }
16
16
 
17
+ /**
18
+ * Family-agnostic pre-compile draft. Family runtimes narrow `ast` to their
19
+ * specific AST shape (e.g. `AnyQueryAst` for SQL via `SqlMiddleware.DraftPlan`).
20
+ */
21
+ export interface GenericDraftPlan {
22
+ readonly ast: unknown;
23
+ readonly meta: PlanMeta;
24
+ }
25
+
17
26
  export interface Middleware<TContract = unknown> extends RuntimeMiddleware {
27
+ beforeCompile?(
28
+ draft: GenericDraftPlan,
29
+ ctx: MiddlewareContext<TContract>,
30
+ ): Promise<GenericDraftPlan | undefined>;
18
31
  beforeExecute?(plan: ExecutionPlan, ctx: MiddlewareContext<TContract>): Promise<void>;
19
32
  onRow?(
20
33
  row: Record<string, unknown>,
@@ -21,20 +21,29 @@ export interface RuntimeTelemetryEvent {
21
21
  readonly durationMs?: number;
22
22
  }
23
23
 
24
- export interface RuntimeCoreOptions<TContract = unknown, TDriver = unknown> {
24
+ export interface RuntimeCoreOptions<
25
+ TContract = unknown,
26
+ TDriver = unknown,
27
+ TMiddleware extends Middleware<TContract> = Middleware<TContract>,
28
+ > {
25
29
  readonly familyAdapter: RuntimeFamilyAdapter<TContract>;
26
30
  readonly driver: TDriver;
27
31
  readonly verify: RuntimeVerifyOptions;
28
- readonly middleware?: readonly Middleware<TContract>[];
32
+ readonly middleware?: readonly TMiddleware[];
29
33
  readonly mode?: 'strict' | 'permissive';
30
34
  readonly log?: Log;
31
35
  }
32
36
 
33
- export interface RuntimeCore<TContract = unknown, TDriver = unknown>
34
- extends RuntimeQueryable,
37
+ export interface RuntimeCore<
38
+ TContract = unknown,
39
+ TDriver = unknown,
40
+ TMiddleware extends Middleware<TContract> = Middleware<TContract>,
41
+ > extends RuntimeQueryable,
35
42
  RuntimeExecutor<ExecutionPlan> {
36
43
  readonly _typeContract?: TContract;
37
44
  readonly _typeDriver?: TDriver;
45
+ readonly middleware: readonly TMiddleware[];
46
+ readonly middlewareContext: MiddlewareContext<TContract>;
38
47
  connection(): Promise<RuntimeConnection>;
39
48
  telemetry(): RuntimeTelemetryEvent | null;
40
49
  close(): Promise<void>;
@@ -116,24 +125,27 @@ interface DriverWithClose<_TDriver> {
116
125
  close(): Promise<void>;
117
126
  }
118
127
 
119
- class RuntimeCoreImpl<TContract = unknown, TDriver = unknown>
120
- implements RuntimeCore<TContract, TDriver>
128
+ class RuntimeCoreImpl<
129
+ TContract = unknown,
130
+ TDriver = unknown,
131
+ TMiddleware extends Middleware<TContract> = Middleware<TContract>,
132
+ > implements RuntimeCore<TContract, TDriver, TMiddleware>
121
133
  {
122
134
  readonly _typeContract?: TContract;
123
135
  readonly _typeDriver?: TDriver;
136
+ readonly middleware: readonly TMiddleware[];
137
+ readonly middlewareContext: MiddlewareContext<TContract>;
124
138
  private readonly contract: TContract;
125
139
  private readonly familyAdapter: RuntimeFamilyAdapter<TContract>;
126
140
  private readonly driver: TDriver;
127
- private readonly middleware: readonly Middleware<TContract>[];
128
141
  private readonly mode: 'strict' | 'permissive';
129
142
  private readonly verify: RuntimeVerifyOptions;
130
- private readonly middlewareContext: MiddlewareContext<TContract>;
131
143
 
132
144
  private verified: boolean;
133
145
  private startupVerified: boolean;
134
146
  private _telemetry: RuntimeTelemetryEvent | null;
135
147
 
136
- constructor(options: RuntimeCoreOptions<TContract, TDriver>) {
148
+ constructor(options: RuntimeCoreOptions<TContract, TDriver, TMiddleware>) {
137
149
  const { familyAdapter, driver } = options;
138
150
  this.contract = familyAdapter.contract;
139
151
  this.familyAdapter = familyAdapter;
@@ -371,8 +383,12 @@ class RuntimeCoreImpl<TContract = unknown, TDriver = unknown>
371
383
  }
372
384
  }
373
385
 
374
- export function createRuntimeCore<TContract = unknown, TDriver = unknown>(
375
- options: RuntimeCoreOptions<TContract, TDriver>,
376
- ): RuntimeCore<TContract, TDriver> {
386
+ export function createRuntimeCore<
387
+ TContract = unknown,
388
+ TDriver = unknown,
389
+ TMiddleware extends Middleware<TContract> = Middleware<TContract>,
390
+ >(
391
+ options: RuntimeCoreOptions<TContract, TDriver, TMiddleware>,
392
+ ): RuntimeCore<TContract, TDriver, TMiddleware> {
377
393
  return new RuntimeCoreImpl(options);
378
394
  }