@happyvertical/smrt-core 0.57.32 → 0.57.34
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 +2 -1
- package/agents/data-query.md +21 -0
- package/agents/schema-paths.md +24 -0
- package/dist/browser.d.ts +2 -2
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +3 -3
- package/dist/data-query.d.ts +16 -1
- package/dist/data-query.d.ts.map +1 -1
- package/dist/data-query.js +104 -4
- package/dist/data-query.js.map +1 -1
- package/dist/db-errors.d.ts +7 -0
- package/dist/db-errors.d.ts.map +1 -1
- package/dist/db-errors.js +34 -1
- package/dist/db-errors.js.map +1 -1
- package/dist/dispatch/bus.d.ts +3 -0
- package/dist/dispatch/bus.d.ts.map +1 -1
- package/dist/dispatch/bus.js +27 -4
- package/dist/dispatch/bus.js.map +1 -1
- package/dist/dispatch/index.d.ts +1 -1
- package/dist/dispatch/index.d.ts.map +1 -1
- package/dist/dispatch/types.d.ts +17 -0
- package/dist/dispatch/types.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/manifest/static-manifest.js +1 -1
- package/dist/manifest/static-manifest.js.map +1 -1
- package/dist/manifest/store.js +1 -1
- package/dist/manifest.json +1 -1
- package/dist/migrations/differ.d.ts +3 -2
- package/dist/migrations/differ.d.ts.map +1 -1
- package/dist/migrations/differ.js +4 -3
- package/dist/migrations/differ.js.map +1 -1
- package/dist/migrations/orchestrate.d.ts +4 -0
- package/dist/migrations/orchestrate.d.ts.map +1 -1
- package/dist/migrations/orchestrate.js +4 -2
- package/dist/migrations/orchestrate.js.map +1 -1
- package/dist/migrations/sqlite-rebuild.d.ts +11 -0
- package/dist/migrations/sqlite-rebuild.d.ts.map +1 -1
- package/dist/migrations/sqlite-rebuild.js +92 -9
- package/dist/migrations/sqlite-rebuild.js.map +1 -1
- package/dist/migrations/tracker.d.ts +7 -0
- package/dist/migrations/tracker.d.ts.map +1 -1
- package/dist/migrations/tracker.js +44 -0
- package/dist/migrations/tracker.js.map +1 -1
- package/dist/smrt-knowledge.json +7 -8
- package/dist/testing/database.d.ts.map +1 -1
- package/dist/testing/database.js +18 -0
- package/dist/testing/database.js.map +1 -1
- package/package.json +4 -5
package/dist/data-query.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-query.js","names":[],"sources":["../src/data-query.ts"],"sourcesContent":["/**\n * Canonical bounded data-query normalization (#2444).\n *\n * The shared package supplies only portable types. This server/runtime module\n * makes the contract executable at every trust boundary: it accepts only an\n * adapter-declared field/operator allowlist, canonicalizes equivalent\n * requests, creates a collision-resistant match fingerprint, and validates\n * that adapters return bounded, policy-filtered rows. It deliberately does\n * not execute SQL or resolve tenant/principal state; authenticated domain\n * adapters supply the schema and perform those responsibilities separately.\n */\n\nimport type {\n DataQueryCondition,\n DataQueryConsistency,\n DataQueryFacetRequest,\n DataQueryFacetResult,\n DataQueryFieldDescriptor,\n DataQueryFilter,\n DataQueryFilterOperator,\n DataQueryFreshness,\n DataQueryPage,\n DataQueryRequest,\n DataQueryResult,\n DataQueryRow,\n DataQueryScalar,\n DataQuerySchema,\n DataQuerySort,\n DataQueryTotal,\n} from '@happyvertical/smrt-types';\nimport { ValidationError } from './errors';\nimport { sha256Base64Url } from './utils/sha256.js';\n\n/** Default and hard ceilings for normalized data-query input and output. */\nexport const DEFAULT_DATA_QUERY_PAGE_LIMIT = 50;\nexport const MAX_DATA_QUERY_PAGE_LIMIT = 1_000;\nexport const DEFAULT_DATA_QUERY_RESULT_BYTES = 1_000_000;\nexport const MAX_DATA_QUERY_RESULT_BYTES = 10_000_000;\nexport const MAX_DATA_QUERY_REQUEST_BYTES = 100_000;\nexport const MAX_DATA_QUERY_OFFSET = 1_000_000;\nexport const MAX_DATA_QUERY_FILTER_DEPTH = 8;\nexport const MAX_DATA_QUERY_FILTERS = 50;\nexport const MAX_DATA_QUERY_IN_VALUES = 100;\nexport const MAX_DATA_QUERY_FACETS = 20;\nexport const MAX_DATA_QUERY_WARNINGS = 100;\nexport const MAX_DATA_QUERY_CURSOR_LENGTH = 2_048;\nexport const MAX_DATA_QUERY_JSON_DEPTH = 16;\nexport const MAX_DATA_QUERY_JSON_CONTAINER_ITEMS = 1_000;\nexport const MAX_DATA_QUERY_JSON_STRING_LENGTH = 65_536;\n\nconst FILTER_OPERATORS = new Set<DataQueryFilterOperator>([\n 'eq',\n 'ne',\n 'gt',\n 'gte',\n 'lt',\n 'lte',\n 'in',\n 'notIn',\n 'like',\n]);\nconst FORBIDDEN_KEYS = new Set(['__proto__', 'constructor', 'prototype']);\n\n/** A typed 400-class failure for malformed or policy-disallowed data queries. */\nexport class DataQueryValidationError extends ValidationError {\n readonly status = 400;\n readonly publicMessage: string;\n\n constructor(\n message: string,\n code = 'INVALID_DATA_QUERY',\n details?: Record<string, unknown>,\n ) {\n super(message, code, details);\n this.name = 'DataQueryValidationError';\n this.publicMessage = message;\n }\n}\n\ntype JsonObject = Record<string, unknown>;\n\ninterface JsonBudget {\n remaining: number;\n failureCode: string;\n}\n\nconst encoder = new TextEncoder();\nconst RFC_3339_INSTANT =\n /^(\\d{4})-(\\d{2})-(\\d{2})T([01]\\d|2[0-3]):([0-5]\\d):([0-5]\\d)(?:\\.\\d{1,9})?(?:Z|[+-](?:[01]\\d|2[0-3]):[0-5]\\d)$/;\n\nfunction fail(\n message: string,\n code = 'INVALID_DATA_QUERY',\n details?: Record<string, unknown>,\n): never {\n throw new DataQueryValidationError(message, code, details);\n}\n\nfunction plainObject(value: unknown, label: string): JsonObject {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return fail(`${label} must be an object`);\n }\n const prototype = Object.getPrototypeOf(value);\n if (prototype !== Object.prototype && prototype !== null) {\n return fail(`${label} must be a plain object`);\n }\n for (const key of Object.keys(value)) {\n if (FORBIDDEN_KEYS.has(key)) {\n return fail(`${label} contains a forbidden key`, 'FORBIDDEN_DATA_QUERY');\n }\n }\n return value as JsonObject;\n}\n\nfunction exactKeys(\n object: JsonObject,\n allowed: readonly string[],\n label: string,\n): void {\n const allowedKeys = new Set(allowed);\n for (const key of Object.keys(object)) {\n if (!allowedKeys.has(key)) {\n fail(\n `${label} contains unsupported key \"${key}\"`,\n 'FORBIDDEN_DATA_QUERY',\n );\n }\n }\n}\n\nfunction stringValue(value: unknown, label: string, maxLength = 256): string {\n if (\n typeof value !== 'string' ||\n value.length === 0 ||\n value.length > maxLength\n ) {\n return fail(\n `${label} must be a non-empty string up to ${maxLength} characters`,\n );\n }\n return value;\n}\n\nfunction nonNegativeInteger(value: unknown, label: string): number {\n if (!Number.isSafeInteger(value) || (value as number) < 0) {\n return fail(`${label} must be a non-negative safe integer`);\n }\n return value as number;\n}\n\nfunction positiveInteger(value: unknown, label: string): number {\n const normalized = nonNegativeInteger(value, label);\n if (normalized === 0) return fail(`${label} must be a positive safe integer`);\n return normalized;\n}\n\nfunction normalizedInstant(value: unknown, label: string): string {\n const input = stringValue(value, label, 128);\n const match = RFC_3339_INSTANT.exec(input);\n if (!match) return fail(`${label} must be an RFC 3339 instant`);\n const [year, month, day] = match.slice(1, 4).map(Number);\n const calendar = new Date(0);\n calendar.setUTCFullYear(year, month - 1, day);\n calendar.setUTCHours(0, 0, 0, 0);\n if (\n calendar.getUTCFullYear() !== year ||\n calendar.getUTCMonth() !== month - 1 ||\n calendar.getUTCDate() !== day\n ) {\n return fail(`${label} must be an RFC 3339 instant`);\n }\n const milliseconds = Date.parse(input);\n if (!Number.isFinite(milliseconds)) {\n return fail(`${label} must be an RFC 3339 instant`);\n }\n return new Date(milliseconds).toISOString();\n}\n\nfunction dataQueryScalar(value: unknown, label: string): DataQueryScalar {\n if (value === null || typeof value === 'boolean') {\n return value;\n }\n if (typeof value === 'string') {\n if (value.length > 4_096) {\n return fail(`${label} cannot exceed 4096 characters`);\n }\n return value;\n }\n if (typeof value === 'number' && Number.isFinite(value)) return value;\n return fail(`${label} must be a JSON scalar`);\n}\n\nfunction consumeJsonSegment(\n budget: JsonBudget | undefined,\n text: string,\n label: string,\n): void {\n if (!budget) return;\n if (text.length > budget.remaining) {\n fail(`${label} exceeds the maximum byte limit`, budget.failureCode);\n }\n const bytes = encoder.encode(text).byteLength;\n if (bytes > budget.remaining) {\n fail(`${label} exceeds the maximum byte limit`, budget.failureCode);\n }\n budget.remaining -= bytes;\n}\n\nfunction canonicalJson(\n value: unknown,\n label = 'Data query JSON',\n budget?: JsonBudget,\n depth = 0,\n ancestors = new Set<object>(),\n): unknown {\n if (depth > MAX_DATA_QUERY_JSON_DEPTH) {\n return fail(`${label} exceeds the JSON depth limit`);\n }\n if (value === null || typeof value === 'boolean') {\n consumeJsonSegment(budget, JSON.stringify(value), label);\n return value;\n }\n if (typeof value === 'string') {\n if (value.length > MAX_DATA_QUERY_JSON_STRING_LENGTH) {\n return fail(`${label} exceeds the JSON string limit`);\n }\n consumeJsonSegment(budget, JSON.stringify(value), label);\n return value;\n }\n if (typeof value === 'number') {\n if (!Number.isFinite(value))\n return fail(`${label} cannot contain a non-finite number`);\n const normalized = value === 0 ? 0 : value;\n consumeJsonSegment(budget, JSON.stringify(normalized), label);\n return normalized;\n }\n if (Array.isArray(value)) {\n if (value.length > MAX_DATA_QUERY_JSON_CONTAINER_ITEMS) {\n return fail(`${label} exceeds the JSON container-item limit`);\n }\n if (ancestors.has(value)) return fail(`${label} cannot contain a cycle`);\n ancestors.add(value);\n try {\n const result: unknown[] = [];\n consumeJsonSegment(budget, '[', label);\n for (const [index, entry] of value.entries()) {\n if (index > 0) consumeJsonSegment(budget, ',', label);\n result.push(\n canonicalJson(\n entry,\n `${label}[${index}]`,\n budget,\n depth + 1,\n ancestors,\n ),\n );\n }\n consumeJsonSegment(budget, ']', label);\n return result;\n } finally {\n ancestors.delete(value);\n }\n }\n const object = plainObject(value, label);\n const keys = Object.keys(object).sort(compareCanonicalStrings);\n if (keys.length > MAX_DATA_QUERY_JSON_CONTAINER_ITEMS) {\n return fail(`${label} exceeds the JSON container-item limit`);\n }\n if (ancestors.has(object)) return fail(`${label} cannot contain a cycle`);\n ancestors.add(object);\n try {\n const result: JsonObject = Object.create(null) as JsonObject;\n consumeJsonSegment(budget, '{', label);\n for (const [index, key] of keys.entries()) {\n if (key.length > MAX_DATA_QUERY_JSON_STRING_LENGTH) {\n return fail(`${label}.${key} exceeds the JSON string limit`);\n }\n if (index > 0) consumeJsonSegment(budget, ',', label);\n consumeJsonSegment(budget, JSON.stringify(key), `${label}.${key}`);\n consumeJsonSegment(budget, ':', label);\n Object.defineProperty(result, key, {\n value: canonicalJson(\n object[key],\n `${label}.${key}`,\n budget,\n depth + 1,\n ancestors,\n ),\n enumerable: true,\n configurable: true,\n writable: true,\n });\n }\n consumeJsonSegment(budget, '}', label);\n return result;\n } finally {\n ancestors.delete(object);\n }\n}\n\nfunction signature(value: unknown): string {\n return JSON.stringify(canonicalJson(value));\n}\n\n/** Reject an over-limit raw request before canonicalization can collapse it. */\nfunction assertBoundedRawRequest(value: unknown): void {\n const budget: JsonBudget = {\n remaining: MAX_DATA_QUERY_REQUEST_BYTES,\n failureCode: 'DATA_QUERY_REQUEST_TOO_LARGE',\n };\n const ancestors = new Set<object>();\n\n const measure = (candidate: unknown, label: string, depth = 0): void => {\n if (depth > MAX_DATA_QUERY_JSON_DEPTH) {\n fail(`${label} exceeds the JSON depth limit`);\n }\n if (candidate === null || typeof candidate === 'boolean') {\n consumeJsonSegment(budget, JSON.stringify(candidate), label);\n return;\n }\n if (typeof candidate === 'string') {\n consumeJsonSegment(budget, JSON.stringify(candidate), label);\n return;\n }\n if (typeof candidate === 'number') {\n if (!Number.isFinite(candidate)) {\n fail(`${label} cannot contain a non-finite number`);\n }\n consumeJsonSegment(\n budget,\n JSON.stringify(candidate === 0 ? 0 : candidate),\n label,\n );\n return;\n }\n if (Array.isArray(candidate)) {\n if (ancestors.has(candidate)) fail(`${label} cannot contain a cycle`);\n ancestors.add(candidate);\n try {\n consumeJsonSegment(budget, '[', label);\n for (const [index, entry] of candidate.entries()) {\n if (index > 0) consumeJsonSegment(budget, ',', label);\n measure(entry, `${label}[${index}]`, depth + 1);\n }\n consumeJsonSegment(budget, ']', label);\n } finally {\n ancestors.delete(candidate);\n }\n return;\n }\n const object = plainObject(candidate, label);\n if (ancestors.has(object)) fail(`${label} cannot contain a cycle`);\n ancestors.add(object);\n try {\n consumeJsonSegment(budget, '{', label);\n for (const [index, key] of Object.keys(object).entries()) {\n if (index > 0) consumeJsonSegment(budget, ',', label);\n consumeJsonSegment(budget, JSON.stringify(key), `${label}.${key}`);\n consumeJsonSegment(budget, ':', label);\n measure(object[key], `${label}.${key}`, depth + 1);\n }\n consumeJsonSegment(budget, '}', label);\n } finally {\n ancestors.delete(object);\n }\n };\n\n measure(value, 'Data query request');\n}\n\n/** Locale-independent ordering for canonical envelopes and fingerprints. */\nfunction compareCanonicalStrings(left: string, right: string): number {\n if (left === right) return 0;\n return left < right ? -1 : 1;\n}\n\nfunction normalizeFieldDescriptor(value: unknown): DataQueryFieldDescriptor {\n const object = plainObject(value, 'Data query schema field');\n exactKeys(\n object,\n ['id', 'type', 'projectable', 'sortable', 'facetable', 'filterOperators'],\n 'Data query schema field',\n );\n const id = stringValue(object.id, 'Data query field id');\n const type = stringValue(object.type, `Data query field ${id} type`);\n if (!['string', 'number', 'boolean', 'datetime', 'json'].includes(type)) {\n return fail(`Unsupported data query field type: ${type}`);\n }\n for (const flag of ['projectable', 'sortable', 'facetable'] as const) {\n if (object[flag] !== undefined && typeof object[flag] !== 'boolean') {\n fail(`Data query field ${id} ${flag} must be boolean`);\n }\n }\n let filterOperators: DataQueryFilterOperator[] | undefined;\n if (object.filterOperators !== undefined) {\n if (!Array.isArray(object.filterOperators)) {\n return fail(`Data query field ${id} filterOperators must be an array`);\n }\n filterOperators = [\n ...new Set(\n object.filterOperators.map((operator) => {\n const normalized = stringValue(\n operator,\n `Data query field ${id} filter operator`,\n ) as DataQueryFilterOperator;\n if (!FILTER_OPERATORS.has(normalized)) {\n fail(`Unsupported data query filter operator: ${normalized}`);\n }\n return normalized;\n }),\n ),\n ].sort();\n }\n const projectable =\n typeof object.projectable === 'boolean' ? object.projectable : undefined;\n const sortable =\n typeof object.sortable === 'boolean' ? object.sortable : undefined;\n const facetable =\n typeof object.facetable === 'boolean' ? object.facetable : undefined;\n return {\n id,\n type: type as DataQueryFieldDescriptor['type'],\n ...(projectable === undefined ? {} : { projectable }),\n ...(sortable === undefined ? {} : { sortable }),\n ...(facetable === undefined ? {} : { facetable }),\n ...(filterOperators ? { filterOperators } : {}),\n };\n}\n\n/** Validate and canonicalize trusted adapter query policy before use. */\nexport function normalizeDataQuerySchema(value: unknown): DataQuerySchema {\n const object = plainObject(value, 'Data query schema');\n exactKeys(\n object,\n [\n 'version',\n 'identityField',\n 'fields',\n 'defaultPageLimit',\n 'maxPageLimit',\n 'maxResultBytes',\n 'defaultSort',\n 'supports',\n ],\n 'Data query schema',\n );\n if (object.version !== 1)\n return fail('Unsupported data query schema version');\n if (!Array.isArray(object.fields) || object.fields.length === 0) {\n return fail('Data query schema fields must be a non-empty array');\n }\n const fields = object.fields\n .map(normalizeFieldDescriptor)\n .sort((left, right) => compareCanonicalStrings(left.id, right.id));\n if (new Set(fields.map((field) => field.id)).size !== fields.length) {\n return fail('Data query schema field ids must be unique');\n }\n const identityField = stringValue(\n object.identityField,\n 'Data query identity field',\n );\n const identity = fields.find((field) => field.id === identityField);\n if (!identity) return fail('Data query identity field must be declared');\n if (identity.projectable === false) {\n return fail('Data query identity field must be projectable');\n }\n if (!['string', 'number', 'datetime'].includes(identity.type)) {\n return fail(\n 'Data query identity field must use a string, number, or datetime type',\n );\n }\n const maxPageLimit =\n object.maxPageLimit === undefined\n ? MAX_DATA_QUERY_PAGE_LIMIT\n : positiveInteger(object.maxPageLimit, 'Data query maximum page limit');\n if (maxPageLimit > MAX_DATA_QUERY_PAGE_LIMIT) {\n return fail(\n `Data query maximum page limit cannot exceed ${MAX_DATA_QUERY_PAGE_LIMIT}`,\n );\n }\n const defaultPageLimit =\n object.defaultPageLimit === undefined\n ? Math.min(DEFAULT_DATA_QUERY_PAGE_LIMIT, maxPageLimit)\n : positiveInteger(\n object.defaultPageLimit,\n 'Data query default page limit',\n );\n if (defaultPageLimit > maxPageLimit) {\n return fail(\n 'Data query default page limit cannot exceed the maximum page limit',\n );\n }\n const maxResultBytes =\n object.maxResultBytes === undefined\n ? DEFAULT_DATA_QUERY_RESULT_BYTES\n : positiveInteger(\n object.maxResultBytes,\n 'Data query maximum result bytes',\n );\n if (maxResultBytes > MAX_DATA_QUERY_RESULT_BYTES) {\n return fail(\n `Data query maximum result bytes cannot exceed ${MAX_DATA_QUERY_RESULT_BYTES}`,\n );\n }\n let supports: DataQuerySchema['supports'];\n if (object.supports !== undefined) {\n const supportObject = plainObject(\n object.supports,\n 'Data query schema supports',\n );\n exactKeys(\n supportObject,\n ['cursorPagination', 'consistency', 'facets'],\n 'Data query schema supports',\n );\n for (const key of ['cursorPagination', 'consistency', 'facets'] as const) {\n if (\n supportObject[key] !== undefined &&\n typeof supportObject[key] !== 'boolean'\n ) {\n fail(`Data query schema supports.${key} must be boolean`);\n }\n }\n const cursorPagination =\n typeof supportObject.cursorPagination === 'boolean'\n ? supportObject.cursorPagination\n : undefined;\n const consistency =\n typeof supportObject.consistency === 'boolean'\n ? supportObject.consistency\n : undefined;\n const facets =\n typeof supportObject.facets === 'boolean'\n ? supportObject.facets\n : undefined;\n supports = {\n ...(cursorPagination === undefined ? {} : { cursorPagination }),\n ...(consistency === undefined ? {} : { consistency }),\n ...(facets === undefined ? {} : { facets }),\n };\n }\n const fieldMap = new Map(fields.map((field) => [field.id, field]));\n const defaultSort = normalizeSort(\n object.defaultSort,\n fieldMap,\n identityField,\n 'Data query default sort',\n false,\n );\n return {\n version: 1,\n identityField,\n fields,\n defaultPageLimit,\n maxPageLimit,\n maxResultBytes,\n ...(defaultSort.length > 0 ? { defaultSort } : {}),\n ...(supports ? { supports } : {}),\n };\n}\n\ninterface FilterBudget {\n nodes: number;\n}\n\nfunction scalarForField(\n value: unknown,\n descriptor: DataQueryFieldDescriptor,\n label: string,\n): DataQueryScalar {\n const scalar = dataQueryScalar(value, label);\n if (scalar === null) return scalar;\n if (descriptor.type === 'number' && typeof scalar !== 'number') {\n return fail(`${label} must be a number for ${descriptor.id}`);\n }\n if (descriptor.type === 'boolean' && typeof scalar !== 'boolean') {\n return fail(`${label} must be a boolean for ${descriptor.id}`);\n }\n if (descriptor.type === 'string' && typeof scalar !== 'string') {\n return fail(`${label} must be a string for ${descriptor.id}`);\n }\n if (descriptor.type === 'datetime') {\n if (typeof scalar !== 'string') {\n return fail(`${label} must be an RFC 3339 instant for ${descriptor.id}`);\n }\n return normalizedInstant(scalar, label);\n }\n return scalar;\n}\n\nfunction normalizeFilter(\n value: unknown,\n fields: Map<string, DataQueryFieldDescriptor>,\n depth = 0,\n budget: FilterBudget = { nodes: 0 },\n): DataQueryFilter {\n if (depth > MAX_DATA_QUERY_FILTER_DEPTH) {\n return fail(\n `Data query filter cannot exceed depth ${MAX_DATA_QUERY_FILTER_DEPTH}`,\n );\n }\n budget.nodes += 1;\n if (budget.nodes > MAX_DATA_QUERY_FILTERS) {\n return fail(\n `Data query filter cannot exceed ${MAX_DATA_QUERY_FILTERS} expressions`,\n );\n }\n const object = plainObject(value, 'Data query filter');\n const kind = stringValue(object.kind, 'Data query filter kind');\n if (kind === 'condition') {\n exactKeys(\n object,\n ['kind', 'field', 'operator', 'value'],\n 'Data query condition',\n );\n const field = stringValue(object.field, 'Data query condition field');\n const descriptor = fields.get(field);\n if (!descriptor)\n return fail(\n `Data query field is not declared: ${field}`,\n 'DATA_QUERY_FIELD_NOT_ALLOWED',\n );\n const operator = stringValue(\n object.operator,\n 'Data query condition operator',\n ) as DataQueryFilterOperator;\n if (\n !FILTER_OPERATORS.has(operator) ||\n !descriptor.filterOperators?.includes(operator)\n ) {\n return fail(\n `Data query operator ${operator} is not allowed for ${field}`,\n 'DATA_QUERY_OPERATOR_NOT_ALLOWED',\n );\n }\n if (operator === 'in' || operator === 'notIn') {\n if (!Array.isArray(object.value) || object.value.length === 0) {\n return fail(`Data query ${operator} value must be a non-empty array`);\n }\n if (object.value.length > MAX_DATA_QUERY_IN_VALUES) {\n return fail(\n `Data query ${operator} value cannot exceed ${MAX_DATA_QUERY_IN_VALUES} items`,\n );\n }\n const values = object.value.map((entry, index) =>\n scalarForField(\n entry,\n descriptor,\n `Data query ${operator} value ${index}`,\n ),\n );\n const canonicalValues = [\n ...new Map(values.map((entry) => [signature(entry), entry])).values(),\n ].sort((left, right) =>\n compareCanonicalStrings(signature(left), signature(right)),\n );\n return { kind: 'condition', field, operator, value: canonicalValues };\n }\n if (Array.isArray(object.value)) {\n return fail(`Data query ${operator} value must be a scalar`);\n }\n const scalar = scalarForField(\n object.value,\n descriptor,\n `Data query ${operator} value`,\n );\n if (operator === 'like' && descriptor.type !== 'string') {\n return fail('Data query like is only available for string fields');\n }\n if (operator === 'like' && typeof scalar !== 'string') {\n return fail('Data query like value must be a string');\n }\n if (\n ['gt', 'gte', 'lt', 'lte'].includes(operator) &&\n !['number', 'string', 'datetime'].includes(descriptor.type)\n ) {\n return fail(\n `Data query ${operator} is not available for ${descriptor.type} fields`,\n );\n }\n if (\n ['gt', 'gte', 'lt', 'lte', 'like'].includes(operator) &&\n scalar === null\n ) {\n return fail(`Data query ${operator} value cannot be null`);\n }\n return {\n kind: 'condition',\n field,\n operator,\n value: scalar,\n } as DataQueryCondition;\n }\n if (kind === 'all' || kind === 'any') {\n exactKeys(object, ['kind', 'filters'], `Data query ${kind} filter`);\n if (!Array.isArray(object.filters) || object.filters.length === 0) {\n return fail(`Data query ${kind} filter must contain at least one child`);\n }\n if (object.filters.length > MAX_DATA_QUERY_FILTERS) {\n return fail(\n `Data query ${kind} filter cannot exceed ${MAX_DATA_QUERY_FILTERS} children`,\n );\n }\n const filters = object.filters\n .map((filter) => normalizeFilter(filter, fields, depth + 1, budget))\n .sort((left, right) =>\n compareCanonicalStrings(signature(left), signature(right)),\n );\n return { kind, filters };\n }\n if (kind === 'not') {\n exactKeys(object, ['kind', 'filter'], 'Data query not filter');\n return {\n kind: 'not',\n filter: normalizeFilter(object.filter, fields, depth + 1, budget),\n };\n }\n return fail(`Unsupported data query filter kind: ${kind}`);\n}\n\nfunction normalizeSort(\n value: unknown,\n fields: Map<string, DataQueryFieldDescriptor>,\n identityField: string,\n label: string,\n appendIdentity: boolean,\n): DataQuerySort[] {\n if (value === undefined)\n return appendIdentity ? [{ field: identityField, direction: 'asc' }] : [];\n if (!Array.isArray(value)) return fail(`${label} must be an array`);\n if (value.length > MAX_DATA_QUERY_FILTERS) {\n return fail(`${label} cannot exceed ${MAX_DATA_QUERY_FILTERS} terms`);\n }\n const sort = value.map((entry) => {\n const object = plainObject(entry, label);\n exactKeys(object, ['field', 'direction'], label);\n const field = stringValue(object.field, `${label} field`);\n if (!fields.get(field)?.sortable && field !== identityField) {\n fail(\n `Data query sort field is not allowed: ${field}`,\n 'DATA_QUERY_SORT_NOT_ALLOWED',\n );\n }\n const direction = stringValue(object.direction, `${label} direction`);\n if (direction !== 'asc' && direction !== 'desc') {\n fail(`Data query sort direction must be asc or desc`);\n }\n return { field, direction } as DataQuerySort;\n });\n if (new Set(sort.map((term) => term.field)).size !== sort.length) {\n return fail(`${label} field ids must be unique`);\n }\n if (appendIdentity && !sort.some((term) => term.field === identityField)) {\n sort.push({ field: identityField, direction: 'asc' });\n }\n return sort;\n}\n\nfunction normalizePage(value: unknown, schema: DataQuerySchema): DataQueryPage {\n if (value === undefined) {\n return {\n kind: 'offset',\n offset: 0,\n limit: schema.defaultPageLimit ?? DEFAULT_DATA_QUERY_PAGE_LIMIT,\n };\n }\n const object = plainObject(value, 'Data query page');\n const kind = stringValue(object.kind, 'Data query page kind');\n if (kind === 'offset') {\n exactKeys(object, ['kind', 'offset', 'limit'], 'Data query offset page');\n const offset = nonNegativeInteger(object.offset, 'Data query offset');\n if (offset > MAX_DATA_QUERY_OFFSET) {\n return fail(`Data query offset cannot exceed ${MAX_DATA_QUERY_OFFSET}`);\n }\n return {\n kind,\n offset,\n limit: Math.min(\n positiveInteger(object.limit, 'Data query page limit'),\n schema.maxPageLimit ?? MAX_DATA_QUERY_PAGE_LIMIT,\n ),\n };\n }\n if (kind === 'cursor') {\n if (!schema.supports?.cursorPagination) {\n return fail(\n 'Data query cursor pagination is not supported',\n 'DATA_QUERY_UNSUPPORTED',\n );\n }\n exactKeys(object, ['kind', 'after', 'limit'], 'Data query cursor page');\n const after =\n object.after === undefined\n ? undefined\n : stringValue(\n object.after,\n 'Data query cursor',\n MAX_DATA_QUERY_CURSOR_LENGTH,\n );\n return {\n kind,\n ...(after === undefined ? {} : { after }),\n limit: Math.min(\n positiveInteger(object.limit, 'Data query page limit'),\n schema.maxPageLimit ?? MAX_DATA_QUERY_PAGE_LIMIT,\n ),\n };\n }\n return fail(`Unsupported data query page kind: ${kind}`);\n}\n\nfunction normalizeConsistency(\n value: unknown,\n schema: DataQuerySchema,\n): DataQueryConsistency | undefined {\n if (value === undefined) return undefined;\n if (!schema.supports?.consistency) {\n return fail(\n 'Data query consistency options are not supported',\n 'DATA_QUERY_UNSUPPORTED',\n );\n }\n const object = plainObject(value, 'Data query consistency');\n exactKeys(object, ['mode', 'asOf'], 'Data query consistency');\n if (object.mode !== 'eventual' && object.mode !== 'snapshot')\n return fail('Unsupported data query consistency mode');\n const asOf =\n object.asOf === undefined\n ? undefined\n : normalizedInstant(object.asOf, 'Data query consistency asOf');\n return {\n mode: object.mode,\n ...(asOf === undefined ? {} : { asOf }),\n } as DataQueryConsistency;\n}\n\nfunction normalizeFacets(\n value: unknown,\n schema: DataQuerySchema,\n fields: Map<string, DataQueryFieldDescriptor>,\n): DataQueryFacetRequest[] {\n if (!schema.supports?.facets) {\n return fail(\n 'Data query facets are not supported',\n 'DATA_QUERY_UNSUPPORTED',\n );\n }\n if (!Array.isArray(value) || value.length === 0) {\n return fail('Data query facets must be a non-empty array');\n }\n if (value.length > MAX_DATA_QUERY_FACETS) {\n return fail(`Data query facets cannot exceed ${MAX_DATA_QUERY_FACETS}`);\n }\n const facets = value.map((entry) => {\n const object = plainObject(entry, 'Data query facet request');\n exactKeys(object, ['field', 'limit'], 'Data query facet request');\n const field = stringValue(object.field, 'Data query facet field');\n if (!fields.get(field)?.facetable) {\n fail(\n `Data query facet field is not allowed: ${field}`,\n 'DATA_QUERY_FACET_NOT_ALLOWED',\n );\n }\n return {\n field,\n limit: Math.min(\n positiveInteger(object.limit, 'Data query facet limit'),\n schema.maxPageLimit ?? MAX_DATA_QUERY_PAGE_LIMIT,\n ),\n };\n });\n if (new Set(facets.map((facet) => facet.field)).size !== facets.length) {\n return fail('Data query facet fields must be unique');\n }\n return facets.sort((left, right) =>\n compareCanonicalStrings(left.field, right.field),\n );\n}\n\nfunction boundRequestSize(request: DataQueryRequest): DataQueryRequest {\n const bytes = new TextEncoder().encode(JSON.stringify(request)).byteLength;\n if (bytes > MAX_DATA_QUERY_REQUEST_BYTES) {\n return fail(\n 'Data query request exceeds its maximum byte limit',\n 'DATA_QUERY_REQUEST_TOO_LARGE',\n );\n }\n return request;\n}\n\n/**\n * Normalize an untrusted request against its trusted adapter schema. Equivalent\n * projection/filter/facet orderings produce byte-identical output; sort order\n * remains intact because it is semantically meaningful. The identity field is\n * always projected even when a caller omits it.\n */\nexport function normalizeDataQueryRequest(\n value: unknown,\n inputSchema: unknown,\n): DataQueryRequest {\n const schema = normalizeDataQuerySchema(inputSchema);\n const fields = new Map(schema.fields.map((field) => [field.id, field]));\n const object = plainObject(value, 'Data query request');\n assertBoundedRawRequest(value);\n exactKeys(\n object,\n [\n 'version',\n 'requestId',\n 'mode',\n 'projection',\n 'filter',\n 'sort',\n 'page',\n 'consistency',\n 'facets',\n ],\n 'Data query request',\n );\n if (object.version !== 1)\n return fail('Unsupported data query request version');\n const requestId = stringValue(object.requestId, 'Data query request id', 128);\n const mode = stringValue(object.mode, 'Data query mode');\n if (!['rows', 'count', 'facets'].includes(mode))\n return fail(`Unsupported data query mode: ${mode}`);\n const filter =\n object.filter === undefined\n ? undefined\n : normalizeFilter(object.filter, fields);\n const consistency = normalizeConsistency(object.consistency, schema);\n if (mode === 'rows') {\n if (object.facets !== undefined)\n return fail('Rows queries cannot request facets');\n if (object.projection !== undefined && !Array.isArray(object.projection)) {\n return fail('Data query projection must be an array');\n }\n if (\n Array.isArray(object.projection) &&\n object.projection.length > MAX_DATA_QUERY_FILTERS\n ) {\n return fail(\n `Data query projection cannot exceed ${MAX_DATA_QUERY_FILTERS} fields`,\n );\n }\n const requestedProjection = (object.projection ?? []).map((field) =>\n stringValue(field, 'Data query projection field'),\n );\n for (const field of requestedProjection) {\n if (!fields.get(field)?.projectable && field !== schema.identityField) {\n fail(\n `Data query projection field is not allowed: ${field}`,\n 'DATA_QUERY_PROJECTION_NOT_ALLOWED',\n );\n }\n }\n const projection = [\n ...new Set([...requestedProjection, schema.identityField]),\n ].sort();\n const sort = normalizeSort(\n object.sort === undefined ? schema.defaultSort : object.sort,\n fields,\n schema.identityField,\n 'Data query sort',\n true,\n );\n return boundRequestSize({\n version: 1,\n requestId,\n mode,\n projection,\n ...(filter === undefined ? {} : { filter }),\n sort,\n page: normalizePage(object.page, schema),\n ...(consistency === undefined ? {} : { consistency }),\n });\n }\n if (\n object.projection !== undefined ||\n object.sort !== undefined ||\n object.page !== undefined\n ) {\n return fail(`${mode} data queries cannot carry projection, sort, or page`);\n }\n if (mode === 'facets') {\n return boundRequestSize({\n version: 1,\n requestId,\n mode,\n ...(filter === undefined ? {} : { filter }),\n ...(consistency === undefined ? {} : { consistency }),\n facets: normalizeFacets(object.facets, schema, fields),\n });\n }\n if (object.facets !== undefined)\n return fail('Count data queries cannot request facets');\n return boundRequestSize({\n version: 1,\n requestId,\n mode: 'count',\n ...(filter === undefined ? {} : { filter }),\n ...(consistency === undefined ? {} : { consistency }),\n });\n}\n\n/** Canonical match/query form used for stable fingerprints (no request id/page). */\nexport function canonicalizeDataQuery(value: unknown, schema: unknown): string {\n const request = normalizeDataQueryRequest(value, schema);\n const { requestId: _requestId, page: _page, ...semanticQuery } = request;\n return signature(semanticQuery);\n}\n\n/** Collision-resistant canonical fingerprint for result correlation and selection scope. */\nexport function createDataQueryFingerprint(\n value: unknown,\n schema: unknown,\n): string {\n return `dq1_${sha256Base64Url(canonicalizeDataQuery(value, schema))}`;\n}\n\nfunction normalizeResultFieldValue(\n value: unknown,\n descriptor: DataQueryFieldDescriptor,\n label: string,\n budget: JsonBudget,\n): unknown {\n if (descriptor.type === 'json') return canonicalJson(value, label, budget);\n const normalized = scalarForField(value, descriptor, label);\n consumeJsonSegment(budget, JSON.stringify(normalized), label);\n return normalized;\n}\n\nfunction normalizeRow(\n value: unknown,\n projection: readonly string[],\n identityField: string,\n fields: Map<string, DataQueryFieldDescriptor>,\n budget: JsonBudget,\n): DataQueryRow {\n const object = plainObject(value, 'Data query row');\n const allowed = new Set(projection);\n const normalized: JsonObject = Object.create(null) as JsonObject;\n consumeJsonSegment(budget, '{', 'Data query row');\n for (const [index, key] of Object.keys(object).entries()) {\n if (!allowed.has(key)) {\n fail(\n `Data query row returned a non-projected field: ${key}`,\n 'DATA_QUERY_RESULT_NOT_ALLOWED',\n );\n }\n const descriptor = fields.get(key);\n if (!descriptor) {\n return fail(\n `Data query row returned an undeclared field: ${key}`,\n 'DATA_QUERY_RESULT_NOT_ALLOWED',\n );\n }\n if (index > 0) consumeJsonSegment(budget, ',', 'Data query row');\n consumeJsonSegment(budget, JSON.stringify(key), `Data query row ${key}`);\n consumeJsonSegment(budget, ':', `Data query row ${key}`);\n normalized[key] = normalizeResultFieldValue(\n object[key],\n descriptor,\n `Data query row ${key}`,\n budget,\n );\n }\n consumeJsonSegment(budget, '}', 'Data query row');\n const identity = normalized[identityField];\n if (\n (typeof identity !== 'string' && typeof identity !== 'number') ||\n identity === ''\n ) {\n fail(\n 'Data query row must return a string or number identity field',\n 'DATA_QUERY_RESULT_INVALID',\n );\n }\n return normalized as DataQueryRow;\n}\n\nfunction normalizeTotal(value: unknown): DataQueryTotal {\n const object = plainObject(value, 'Data query total');\n const kind = stringValue(object.kind, 'Data query total kind');\n if (kind === 'unavailable') {\n exactKeys(object, ['kind', 'reason'], 'Data query unavailable total');\n const reason =\n object.reason === undefined\n ? undefined\n : stringValue(object.reason, 'Data query total reason');\n return { kind, ...(reason === undefined ? {} : { reason }) };\n }\n if (kind !== 'exact' && kind !== 'estimated') {\n return fail(`Unsupported data query total kind: ${kind}`);\n }\n exactKeys(object, ['kind', 'value', 'asOf'], 'Data query total');\n const asOf =\n object.asOf === undefined\n ? undefined\n : normalizedInstant(object.asOf, 'Data query total asOf');\n return {\n kind,\n value: nonNegativeInteger(object.value, 'Data query total value'),\n ...(asOf === undefined ? {} : { asOf }),\n };\n}\n\nfunction normalizeFreshness(value: unknown): DataQueryFreshness {\n const object = plainObject(value, 'Data query freshness');\n exactKeys(object, ['state', 'asOf'], 'Data query freshness');\n const state = stringValue(object.state, 'Data query freshness state');\n if (!['fresh', 'stale', 'unknown'].includes(state)) {\n return fail(`Unsupported data query freshness state: ${state}`);\n }\n const asOf =\n object.asOf === undefined\n ? undefined\n : normalizedInstant(object.asOf, 'Data query freshness asOf');\n return {\n state: state as DataQueryFreshness['state'],\n ...(asOf === undefined ? {} : { asOf }),\n };\n}\n\nfunction normalizeFacetsResult(\n value: unknown,\n requested: readonly DataQueryFacetRequest[],\n fields: Map<string, DataQueryFieldDescriptor>,\n budget: JsonBudget,\n): DataQueryFacetResult[] {\n if (!Array.isArray(value))\n return fail('Data query result facets must be an array');\n if (value.length > requested.length) {\n return fail('Data query result returned too many facets');\n }\n const limits = new Map(requested.map((facet) => [facet.field, facet.limit]));\n consumeJsonSegment(budget, '[', 'Data query result facets');\n const results = value.map((entry, index) => {\n if (index > 0) consumeJsonSegment(budget, ',', 'Data query result facets');\n const object = plainObject(entry, 'Data query facet result');\n exactKeys(\n object,\n ['field', 'values', 'truncated'],\n 'Data query facet result',\n );\n const field = stringValue(object.field, 'Data query facet result field');\n const limit = limits.get(field);\n if (limit === undefined)\n return fail(`Data query returned an unrequested facet: ${field}`);\n if (!Array.isArray(object.values) || object.values.length > limit) {\n return fail(`Data query facet ${field} exceeds its requested limit`);\n }\n if (typeof object.truncated !== 'boolean')\n return fail('Data query facet truncated must be boolean');\n const descriptor = fields.get(field);\n if (!descriptor)\n return fail(`Data query facet field is not declared: ${field}`);\n consumeJsonSegment(budget, '{\"field\":', `Data query facet ${field}`);\n consumeJsonSegment(\n budget,\n JSON.stringify(field),\n `Data query facet ${field}`,\n );\n consumeJsonSegment(budget, ',\"values\":[', `Data query facet ${field}`);\n const values = object.values.map((candidate, valueIndex) => {\n if (valueIndex > 0)\n consumeJsonSegment(budget, ',', `Data query facet ${field}`);\n const facet = plainObject(candidate, 'Data query facet value');\n exactKeys(facet, ['value', 'count'], 'Data query facet value');\n const normalizedValue = scalarForField(\n facet.value,\n descriptor,\n `Data query facet ${field} value`,\n );\n const count = nonNegativeInteger(facet.count, 'Data query facet count');\n consumeJsonSegment(\n budget,\n `{\"value\":${JSON.stringify(normalizedValue)},\"count\":${JSON.stringify(count)}}`,\n `Data query facet ${field} value`,\n );\n return {\n value: normalizedValue,\n count,\n };\n });\n consumeJsonSegment(\n budget,\n `],\"truncated\":${object.truncated}}`,\n `Data query facet ${field}`,\n );\n return { field, values, truncated: object.truncated };\n });\n consumeJsonSegment(budget, ']', 'Data query result facets');\n if (new Set(results.map((facet) => facet.field)).size !== results.length) {\n return fail('Data query result facet fields must be unique');\n }\n return results.sort((left, right) =>\n compareCanonicalStrings(left.field, right.field),\n );\n}\n\n/**\n * Validate an adapter result against the normalized request and its schema.\n * This is the final projection boundary: undeclared fields, malformed totals,\n * forged fingerprints, oversized rows, and authority-shaped prototype payloads\n * cannot cross into REST, MCP, WebMCP, or browser consumers unnoticed.\n */\nexport function normalizeDataQueryResult(\n value: unknown,\n inputRequest: unknown,\n inputSchema: unknown,\n): DataQueryResult {\n const schema = normalizeDataQuerySchema(inputSchema);\n const request = normalizeDataQueryRequest(inputRequest, schema);\n const fields = new Map(schema.fields.map((field) => [field.id, field]));\n const object = plainObject(value, 'Data query result');\n exactKeys(\n object,\n [\n 'version',\n 'requestId',\n 'queryFingerprint',\n 'identityField',\n 'rows',\n 'page',\n 'total',\n 'facets',\n 'freshness',\n 'warnings',\n 'truncated',\n ],\n 'Data query result',\n );\n if (object.version !== 1)\n return fail('Unsupported data query result version');\n if (\n stringValue(object.requestId, 'Data query result request id', 128) !==\n request.requestId\n ) {\n return fail(\n 'Data query result request id does not match its request',\n 'DATA_QUERY_RESULT_INVALID',\n );\n }\n const fingerprint = createDataQueryFingerprint(request, schema);\n if (\n stringValue(\n object.queryFingerprint,\n 'Data query result fingerprint',\n 128,\n ) !== fingerprint\n ) {\n return fail(\n 'Data query result fingerprint does not match its request',\n 'DATA_QUERY_RESULT_INVALID',\n );\n }\n if (\n stringValue(object.identityField, 'Data query result identity field') !==\n schema.identityField\n ) {\n return fail(\n 'Data query result identity field does not match its schema',\n 'DATA_QUERY_RESULT_INVALID',\n );\n }\n if (!Array.isArray(object.rows))\n return fail('Data query result rows must be an array');\n const projection =\n request.mode === 'rows'\n ? (request.projection ?? [schema.identityField])\n : [];\n const page = request.mode === 'rows' ? request.page : undefined;\n if (request.mode !== 'rows' && object.rows.length > 0) {\n return fail(`${request.mode} data query results cannot return rows`);\n }\n if (page && object.rows.length > page.limit) {\n return fail('Data query result rows exceed its requested page limit');\n }\n const budget: JsonBudget = {\n remaining: schema.maxResultBytes ?? DEFAULT_DATA_QUERY_RESULT_BYTES,\n failureCode: 'DATA_QUERY_RESULT_TOO_LARGE',\n };\n consumeJsonSegment(budget, '[', 'Data query result rows');\n const rows = object.rows.map((row, index) => {\n if (index > 0) consumeJsonSegment(budget, ',', 'Data query result rows');\n return normalizeRow(row, projection, schema.identityField, fields, budget);\n });\n consumeJsonSegment(budget, ']', 'Data query result rows');\n let normalizedPage: DataQueryResult['page'];\n if (page) {\n const pageObject = plainObject(object.page, 'Data query result page');\n exactKeys(\n pageObject,\n ['kind', 'limit', 'offset', 'nextCursor', 'hasMore'],\n 'Data query result page',\n );\n if (\n pageObject.kind !== page.kind ||\n nonNegativeInteger(pageObject.limit, 'Data query result page limit') !==\n page.limit\n ) {\n return fail('Data query result page does not match its request');\n }\n if (typeof pageObject.hasMore !== 'boolean')\n return fail('Data query result page hasMore must be boolean');\n if (page.kind === 'offset') {\n if (\n nonNegativeInteger(pageObject.offset, 'Data query result offset') !==\n page.offset\n ) {\n return fail('Data query result offset does not match its request');\n }\n if (pageObject.nextCursor !== undefined)\n return fail('Offset data query results cannot return a cursor');\n normalizedPage = {\n kind: 'offset',\n limit: page.limit,\n offset: page.offset,\n hasMore: pageObject.hasMore,\n };\n } else {\n if (pageObject.offset !== undefined) {\n return fail('Cursor data query results cannot return an offset');\n }\n const nextCursor =\n pageObject.nextCursor === undefined\n ? undefined\n : stringValue(\n pageObject.nextCursor,\n 'Data query result next cursor',\n MAX_DATA_QUERY_CURSOR_LENGTH,\n );\n if (pageObject.hasMore !== Boolean(nextCursor)) {\n return fail('Data query cursor result hasMore must match nextCursor');\n }\n normalizedPage = {\n kind: 'cursor',\n limit: page.limit,\n hasMore: pageObject.hasMore,\n ...(nextCursor === undefined ? {} : { nextCursor }),\n };\n }\n } else if (object.page !== undefined) {\n return fail(`${request.mode} data query results cannot return a page`);\n }\n const total = normalizeTotal(object.total);\n const freshness = normalizeFreshness(object.freshness);\n if (\n !Array.isArray(object.warnings) ||\n object.warnings.length > MAX_DATA_QUERY_WARNINGS ||\n object.warnings.some(\n (warning) =>\n typeof warning !== 'string' ||\n warning.length === 0 ||\n warning.length > 512,\n )\n ) {\n return fail('Data query result warnings must be at most 100 short strings');\n }\n if (typeof object.truncated !== 'boolean')\n return fail('Data query result truncated must be boolean');\n const facets =\n request.mode === 'facets'\n ? normalizeFacetsResult(\n object.facets,\n request.facets ?? [],\n fields,\n budget,\n )\n : object.facets === undefined\n ? undefined\n : fail(`${request.mode} data query results cannot return facets`);\n const normalized: DataQueryResult = {\n version: 1,\n requestId: request.requestId,\n queryFingerprint: fingerprint,\n identityField: schema.identityField,\n rows,\n ...(normalizedPage === undefined ? {} : { page: normalizedPage }),\n total,\n ...(facets === undefined ? {} : { facets }),\n freshness,\n warnings: [...new Set(object.warnings)].sort(),\n truncated: object.truncated,\n };\n const bytes = new TextEncoder().encode(JSON.stringify(normalized)).byteLength;\n if (bytes > (schema.maxResultBytes ?? DEFAULT_DATA_QUERY_RESULT_BYTES)) {\n return fail(\n 'Data query result exceeds its maximum byte limit',\n 'DATA_QUERY_RESULT_TOO_LARGE',\n );\n }\n return normalized;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"data-query.js","names":[],"sources":["../src/data-query.ts"],"sourcesContent":["/**\n * Canonical bounded data-query normalization (#2444).\n *\n * The shared package supplies only portable types. This server/runtime module\n * makes the contract executable at every trust boundary: it accepts only an\n * adapter-declared field/operator allowlist, canonicalizes equivalent\n * requests, creates a collision-resistant match fingerprint, and validates\n * that adapters return bounded, policy-filtered rows. It deliberately does\n * not execute SQL or resolve tenant/principal state; authenticated domain\n * adapters supply the schema and perform those responsibilities separately.\n */\n\nimport type {\n DataQueryAllowedValue,\n DataQueryCondition,\n DataQueryConsistency,\n DataQueryFacetRequest,\n DataQueryFacetResult,\n DataQueryFieldDescriptor,\n DataQueryFilter,\n DataQueryFilterOperator,\n DataQueryFreshness,\n DataQueryPage,\n DataQueryRequest,\n DataQueryResult,\n DataQueryRow,\n DataQueryScalar,\n DataQuerySchema,\n DataQuerySort,\n DataQueryTotal,\n} from '@happyvertical/smrt-types';\nimport { ValidationError } from './errors';\nimport { sha256Base64Url } from './utils/sha256.js';\n\n/** Default and hard ceilings for normalized data-query input and output. */\nexport const DEFAULT_DATA_QUERY_PAGE_LIMIT = 50;\nexport const MAX_DATA_QUERY_PAGE_LIMIT = 1_000;\nexport const DEFAULT_DATA_QUERY_RESULT_BYTES = 1_000_000;\nexport const MAX_DATA_QUERY_RESULT_BYTES = 10_000_000;\nexport const MAX_DATA_QUERY_REQUEST_BYTES = 100_000;\nexport const MAX_DATA_QUERY_OFFSET = 1_000_000;\nexport const MAX_DATA_QUERY_FILTER_DEPTH = 8;\nexport const MAX_DATA_QUERY_FILTERS = 50;\nexport const MAX_DATA_QUERY_IN_VALUES = 100;\nexport const MAX_DATA_QUERY_FACETS = 20;\nexport const MAX_DATA_QUERY_WARNINGS = 100;\nexport const MAX_DATA_QUERY_CURSOR_LENGTH = 2_048;\nexport const MAX_DATA_QUERY_JSON_DEPTH = 16;\nexport const MAX_DATA_QUERY_JSON_CONTAINER_ITEMS = 1_000;\nexport const MAX_DATA_QUERY_JSON_STRING_LENGTH = 65_536;\n/**\n * Bounds for host-declared allowed field values (#4381). The count matches\n * {@link MAX_DATA_QUERY_IN_VALUES} so a whole declared set fits one `in`.\n */\nexport const MAX_DATA_QUERY_FIELD_VALUES = 100;\nexport const MAX_DATA_QUERY_FIELD_VALUE_LENGTH = 256;\nexport const MAX_DATA_QUERY_FIELD_VALUE_LABEL_LENGTH = 128;\nexport const MAX_DATA_QUERY_FIELD_VALUE_DESCRIPTION_LENGTH = 512;\n/**\n * Allowed values listed in a rejected-filter message and its\n * `details.allowedValues` before truncation, so neither grows with the set.\n */\nconst MAX_LISTED_ALLOWED_VALUES = 20;\n/**\n * Control (C0/C1/DEL), format (bidi overrides/isolates, zero-width, BOM),\n * lone-surrogate, and line/paragraph-separator characters: none belongs in\n * schema text an agent reads, and bidi controls can disguise a value.\n */\nconst UNSAFE_SCHEMA_TEXT = /[\\p{Cc}\\p{Cf}\\p{Cs}\\p{Zl}\\p{Zp}]/u;\n\nconst FILTER_OPERATORS = new Set<DataQueryFilterOperator>([\n 'eq',\n 'ne',\n 'gt',\n 'gte',\n 'lt',\n 'lte',\n 'in',\n 'notIn',\n 'like',\n]);\nconst FORBIDDEN_KEYS = new Set(['__proto__', 'constructor', 'prototype']);\n\n/** A typed 400-class failure for malformed or policy-disallowed data queries. */\nexport class DataQueryValidationError extends ValidationError {\n readonly status = 400;\n readonly publicMessage: string;\n\n constructor(\n message: string,\n code = 'INVALID_DATA_QUERY',\n details?: Record<string, unknown>,\n ) {\n super(message, code, details);\n this.name = 'DataQueryValidationError';\n this.publicMessage = message;\n }\n}\n\ntype JsonObject = Record<string, unknown>;\n\ninterface JsonBudget {\n remaining: number;\n failureCode: string;\n}\n\nconst encoder = new TextEncoder();\nconst RFC_3339_INSTANT =\n /^(\\d{4})-(\\d{2})-(\\d{2})T([01]\\d|2[0-3]):([0-5]\\d):([0-5]\\d)(?:\\.\\d{1,9})?(?:Z|[+-](?:[01]\\d|2[0-3]):[0-5]\\d)$/;\n\nfunction fail(\n message: string,\n code = 'INVALID_DATA_QUERY',\n details?: Record<string, unknown>,\n): never {\n throw new DataQueryValidationError(message, code, details);\n}\n\nfunction plainObject(value: unknown, label: string): JsonObject {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return fail(`${label} must be an object`);\n }\n const prototype = Object.getPrototypeOf(value);\n if (prototype !== Object.prototype && prototype !== null) {\n return fail(`${label} must be a plain object`);\n }\n for (const key of Object.keys(value)) {\n if (FORBIDDEN_KEYS.has(key)) {\n return fail(`${label} contains a forbidden key`, 'FORBIDDEN_DATA_QUERY');\n }\n }\n return value as JsonObject;\n}\n\nfunction exactKeys(\n object: JsonObject,\n allowed: readonly string[],\n label: string,\n): void {\n const allowedKeys = new Set(allowed);\n for (const key of Object.keys(object)) {\n if (!allowedKeys.has(key)) {\n fail(\n `${label} contains unsupported key \"${key}\"`,\n 'FORBIDDEN_DATA_QUERY',\n );\n }\n }\n}\n\nfunction stringValue(value: unknown, label: string, maxLength = 256): string {\n if (\n typeof value !== 'string' ||\n value.length === 0 ||\n value.length > maxLength\n ) {\n return fail(\n `${label} must be a non-empty string up to ${maxLength} characters`,\n );\n }\n return value;\n}\n\nfunction nonNegativeInteger(value: unknown, label: string): number {\n if (!Number.isSafeInteger(value) || (value as number) < 0) {\n return fail(`${label} must be a non-negative safe integer`);\n }\n return value as number;\n}\n\nfunction positiveInteger(value: unknown, label: string): number {\n const normalized = nonNegativeInteger(value, label);\n if (normalized === 0) return fail(`${label} must be a positive safe integer`);\n return normalized;\n}\n\nfunction normalizedInstant(value: unknown, label: string): string {\n const input = stringValue(value, label, 128);\n const match = RFC_3339_INSTANT.exec(input);\n if (!match) return fail(`${label} must be an RFC 3339 instant`);\n const [year, month, day] = match.slice(1, 4).map(Number);\n const calendar = new Date(0);\n calendar.setUTCFullYear(year, month - 1, day);\n calendar.setUTCHours(0, 0, 0, 0);\n if (\n calendar.getUTCFullYear() !== year ||\n calendar.getUTCMonth() !== month - 1 ||\n calendar.getUTCDate() !== day\n ) {\n return fail(`${label} must be an RFC 3339 instant`);\n }\n const milliseconds = Date.parse(input);\n if (!Number.isFinite(milliseconds)) {\n return fail(`${label} must be an RFC 3339 instant`);\n }\n return new Date(milliseconds).toISOString();\n}\n\nfunction dataQueryScalar(value: unknown, label: string): DataQueryScalar {\n if (value === null || typeof value === 'boolean') {\n return value;\n }\n if (typeof value === 'string') {\n if (value.length > 4_096) {\n return fail(`${label} cannot exceed 4096 characters`);\n }\n return value;\n }\n if (typeof value === 'number' && Number.isFinite(value)) return value;\n return fail(`${label} must be a JSON scalar`);\n}\n\nfunction consumeJsonSegment(\n budget: JsonBudget | undefined,\n text: string,\n label: string,\n): void {\n if (!budget) return;\n if (text.length > budget.remaining) {\n fail(`${label} exceeds the maximum byte limit`, budget.failureCode);\n }\n const bytes = encoder.encode(text).byteLength;\n if (bytes > budget.remaining) {\n fail(`${label} exceeds the maximum byte limit`, budget.failureCode);\n }\n budget.remaining -= bytes;\n}\n\nfunction canonicalJson(\n value: unknown,\n label = 'Data query JSON',\n budget?: JsonBudget,\n depth = 0,\n ancestors = new Set<object>(),\n): unknown {\n if (depth > MAX_DATA_QUERY_JSON_DEPTH) {\n return fail(`${label} exceeds the JSON depth limit`);\n }\n if (value === null || typeof value === 'boolean') {\n consumeJsonSegment(budget, JSON.stringify(value), label);\n return value;\n }\n if (typeof value === 'string') {\n if (value.length > MAX_DATA_QUERY_JSON_STRING_LENGTH) {\n return fail(`${label} exceeds the JSON string limit`);\n }\n consumeJsonSegment(budget, JSON.stringify(value), label);\n return value;\n }\n if (typeof value === 'number') {\n if (!Number.isFinite(value))\n return fail(`${label} cannot contain a non-finite number`);\n const normalized = value === 0 ? 0 : value;\n consumeJsonSegment(budget, JSON.stringify(normalized), label);\n return normalized;\n }\n if (Array.isArray(value)) {\n if (value.length > MAX_DATA_QUERY_JSON_CONTAINER_ITEMS) {\n return fail(`${label} exceeds the JSON container-item limit`);\n }\n if (ancestors.has(value)) return fail(`${label} cannot contain a cycle`);\n ancestors.add(value);\n try {\n const result: unknown[] = [];\n consumeJsonSegment(budget, '[', label);\n for (const [index, entry] of value.entries()) {\n if (index > 0) consumeJsonSegment(budget, ',', label);\n result.push(\n canonicalJson(\n entry,\n `${label}[${index}]`,\n budget,\n depth + 1,\n ancestors,\n ),\n );\n }\n consumeJsonSegment(budget, ']', label);\n return result;\n } finally {\n ancestors.delete(value);\n }\n }\n const object = plainObject(value, label);\n const keys = Object.keys(object).sort(compareCanonicalStrings);\n if (keys.length > MAX_DATA_QUERY_JSON_CONTAINER_ITEMS) {\n return fail(`${label} exceeds the JSON container-item limit`);\n }\n if (ancestors.has(object)) return fail(`${label} cannot contain a cycle`);\n ancestors.add(object);\n try {\n const result: JsonObject = Object.create(null) as JsonObject;\n consumeJsonSegment(budget, '{', label);\n for (const [index, key] of keys.entries()) {\n if (key.length > MAX_DATA_QUERY_JSON_STRING_LENGTH) {\n return fail(`${label}.${key} exceeds the JSON string limit`);\n }\n if (index > 0) consumeJsonSegment(budget, ',', label);\n consumeJsonSegment(budget, JSON.stringify(key), `${label}.${key}`);\n consumeJsonSegment(budget, ':', label);\n Object.defineProperty(result, key, {\n value: canonicalJson(\n object[key],\n `${label}.${key}`,\n budget,\n depth + 1,\n ancestors,\n ),\n enumerable: true,\n configurable: true,\n writable: true,\n });\n }\n consumeJsonSegment(budget, '}', label);\n return result;\n } finally {\n ancestors.delete(object);\n }\n}\n\nfunction signature(value: unknown): string {\n return JSON.stringify(canonicalJson(value));\n}\n\n/** Reject an over-limit raw request before canonicalization can collapse it. */\nfunction assertBoundedRawRequest(value: unknown): void {\n const budget: JsonBudget = {\n remaining: MAX_DATA_QUERY_REQUEST_BYTES,\n failureCode: 'DATA_QUERY_REQUEST_TOO_LARGE',\n };\n const ancestors = new Set<object>();\n\n const measure = (candidate: unknown, label: string, depth = 0): void => {\n if (depth > MAX_DATA_QUERY_JSON_DEPTH) {\n fail(`${label} exceeds the JSON depth limit`);\n }\n if (candidate === null || typeof candidate === 'boolean') {\n consumeJsonSegment(budget, JSON.stringify(candidate), label);\n return;\n }\n if (typeof candidate === 'string') {\n consumeJsonSegment(budget, JSON.stringify(candidate), label);\n return;\n }\n if (typeof candidate === 'number') {\n if (!Number.isFinite(candidate)) {\n fail(`${label} cannot contain a non-finite number`);\n }\n consumeJsonSegment(\n budget,\n JSON.stringify(candidate === 0 ? 0 : candidate),\n label,\n );\n return;\n }\n if (Array.isArray(candidate)) {\n if (ancestors.has(candidate)) fail(`${label} cannot contain a cycle`);\n ancestors.add(candidate);\n try {\n consumeJsonSegment(budget, '[', label);\n for (const [index, entry] of candidate.entries()) {\n if (index > 0) consumeJsonSegment(budget, ',', label);\n measure(entry, `${label}[${index}]`, depth + 1);\n }\n consumeJsonSegment(budget, ']', label);\n } finally {\n ancestors.delete(candidate);\n }\n return;\n }\n const object = plainObject(candidate, label);\n if (ancestors.has(object)) fail(`${label} cannot contain a cycle`);\n ancestors.add(object);\n try {\n consumeJsonSegment(budget, '{', label);\n for (const [index, key] of Object.keys(object).entries()) {\n if (index > 0) consumeJsonSegment(budget, ',', label);\n consumeJsonSegment(budget, JSON.stringify(key), `${label}.${key}`);\n consumeJsonSegment(budget, ':', label);\n measure(object[key], `${label}.${key}`, depth + 1);\n }\n consumeJsonSegment(budget, '}', label);\n } finally {\n ancestors.delete(object);\n }\n };\n\n measure(value, 'Data query request');\n}\n\n/** Locale-independent ordering for canonical envelopes and fingerprints. */\nfunction compareCanonicalStrings(left: string, right: string): number {\n if (left === right) return 0;\n return left < right ? -1 : 1;\n}\n\nfunction normalizeFieldDescriptor(value: unknown): DataQueryFieldDescriptor {\n const object = plainObject(value, 'Data query schema field');\n exactKeys(\n object,\n [\n 'id',\n 'type',\n 'projectable',\n 'sortable',\n 'facetable',\n 'filterOperators',\n 'values',\n 'valuesEnforced',\n ],\n 'Data query schema field',\n );\n const id = stringValue(object.id, 'Data query field id');\n const type = stringValue(object.type, `Data query field ${id} type`);\n if (!['string', 'number', 'boolean', 'datetime', 'json'].includes(type)) {\n return fail(`Unsupported data query field type: ${type}`);\n }\n for (const flag of ['projectable', 'sortable', 'facetable'] as const) {\n if (object[flag] !== undefined && typeof object[flag] !== 'boolean') {\n fail(`Data query field ${id} ${flag} must be boolean`);\n }\n }\n let filterOperators: DataQueryFilterOperator[] | undefined;\n if (object.filterOperators !== undefined) {\n if (!Array.isArray(object.filterOperators)) {\n return fail(`Data query field ${id} filterOperators must be an array`);\n }\n filterOperators = [\n ...new Set(\n object.filterOperators.map((operator) => {\n const normalized = stringValue(\n operator,\n `Data query field ${id} filter operator`,\n ) as DataQueryFilterOperator;\n if (!FILTER_OPERATORS.has(normalized)) {\n fail(`Unsupported data query filter operator: ${normalized}`);\n }\n return normalized;\n }),\n ),\n ].sort();\n }\n const projectable =\n typeof object.projectable === 'boolean' ? object.projectable : undefined;\n const sortable =\n typeof object.sortable === 'boolean' ? object.sortable : undefined;\n const facetable =\n typeof object.facetable === 'boolean' ? object.facetable : undefined;\n const values =\n object.values === undefined\n ? undefined\n : normalizeDataQueryFieldValues(\n object.values,\n type as DataQueryFieldDescriptor['type'],\n id,\n );\n if (object.valuesEnforced !== undefined) {\n if (typeof object.valuesEnforced !== 'boolean') {\n return fail(`Data query field ${id} valuesEnforced must be boolean`);\n }\n if (!values) {\n return fail(`Data query field ${id} valuesEnforced requires values`);\n }\n }\n // Enforcement is the default, so only the advisory form is kept.\n const advisory = values !== undefined && object.valuesEnforced === false;\n return {\n id,\n type: type as DataQueryFieldDescriptor['type'],\n ...(projectable === undefined ? {} : { projectable }),\n ...(sortable === undefined ? {} : { sortable }),\n ...(facetable === undefined ? {} : { facetable }),\n ...(filterOperators ? { filterOperators } : {}),\n ...(values ? { values } : {}),\n ...(advisory ? { valuesEnforced: false } : {}),\n };\n}\n\nfunction schemaText(value: unknown, label: string, maxLength: number): string {\n const text = stringValue(value, label, maxLength);\n if (UNSAFE_SCHEMA_TEXT.test(text)) {\n return fail(\n `${label} cannot contain control, format, or bidirectional characters`,\n );\n }\n return text;\n}\n\n/**\n * Validate a field's host-declared allowed values (#4381): a non-empty,\n * bounded, duplicate-free list whose values match the field type, with\n * optional label/description text free of control and bidi characters.\n * Declaration order is preserved. Throws {@link DataQueryValidationError}.\n */\nexport function normalizeDataQueryFieldValues(\n value: unknown,\n type: DataQueryFieldDescriptor['type'],\n fieldId: string,\n): DataQueryAllowedValue[] {\n const label = `Data query field ${fieldId} values`;\n if (type !== 'string' && type !== 'number' && type !== 'boolean') {\n return fail(\n `${label} are only supported on string, number, or boolean fields`,\n );\n }\n if (!Array.isArray(value) || value.length === 0) {\n return fail(`${label} must be a non-empty array`);\n }\n if (value.length > MAX_DATA_QUERY_FIELD_VALUES) {\n return fail(\n `${label} cannot exceed ${MAX_DATA_QUERY_FIELD_VALUES} entries`,\n );\n }\n const seen = new Set<string>();\n return value.map((entry, index) => {\n const entryLabel = `${label}[${index}]`;\n const object = plainObject(entry, entryLabel);\n exactKeys(object, ['value', 'label', 'description'], entryLabel);\n const raw = object.value;\n let allowed: string | number | boolean;\n if (type === 'string') {\n allowed = schemaText(\n raw,\n `${entryLabel} value`,\n MAX_DATA_QUERY_FIELD_VALUE_LENGTH,\n );\n } else if (type === 'number') {\n if (typeof raw !== 'number' || !Number.isFinite(raw)) {\n return fail(`${entryLabel} value must be a finite number`);\n }\n allowed = raw;\n } else {\n if (typeof raw !== 'boolean') {\n return fail(`${entryLabel} value must be a boolean`);\n }\n allowed = raw;\n }\n const key = signature(allowed);\n if (seen.has(key)) return fail(`${label} must be unique`);\n seen.add(key);\n const valueLabel =\n object.label === undefined\n ? undefined\n : schemaText(\n object.label,\n `${entryLabel} label`,\n MAX_DATA_QUERY_FIELD_VALUE_LABEL_LENGTH,\n );\n const description =\n object.description === undefined\n ? undefined\n : schemaText(\n object.description,\n `${entryLabel} description`,\n MAX_DATA_QUERY_FIELD_VALUE_DESCRIPTION_LENGTH,\n );\n return {\n value: allowed,\n ...(valueLabel === undefined ? {} : { label: valueLabel }),\n ...(description === undefined ? {} : { description }),\n };\n });\n}\n\n/**\n * Reject an equality-family filter value outside a field's enforced closed\n * set with a message the caller can act on. `null` stays allowed, and an\n * advisory set (`valuesEnforced: false`) accepts any value.\n */\nfunction assertDeclaredValue(\n scalar: DataQueryScalar,\n descriptor: DataQueryFieldDescriptor,\n label: string,\n): void {\n if (\n scalar === null ||\n !descriptor.values ||\n descriptor.valuesEnforced === false\n ) {\n return;\n }\n if (descriptor.values.some((entry) => entry.value === scalar)) return;\n const allowed = descriptor.values.map((entry) => entry.value);\n const shown = allowed.slice(0, MAX_LISTED_ALLOWED_VALUES);\n const listed = shown.map((entry) => JSON.stringify(entry)).join(', ');\n const more =\n allowed.length > MAX_LISTED_ALLOWED_VALUES\n ? `, and ${allowed.length - MAX_LISTED_ALLOWED_VALUES} more`\n : '';\n fail(\n `${label} is not an allowed value for ${descriptor.id}; use one of: ${listed}${more}`,\n 'DATA_QUERY_VALUE_NOT_ALLOWED',\n {\n field: descriptor.id,\n allowedValues: shown,\n allowedValueCount: allowed.length,\n },\n );\n}\n\n/** Validate and canonicalize trusted adapter query policy before use. */\nexport function normalizeDataQuerySchema(value: unknown): DataQuerySchema {\n const object = plainObject(value, 'Data query schema');\n exactKeys(\n object,\n [\n 'version',\n 'identityField',\n 'fields',\n 'defaultPageLimit',\n 'maxPageLimit',\n 'maxResultBytes',\n 'defaultSort',\n 'supports',\n ],\n 'Data query schema',\n );\n if (object.version !== 1)\n return fail('Unsupported data query schema version');\n if (!Array.isArray(object.fields) || object.fields.length === 0) {\n return fail('Data query schema fields must be a non-empty array');\n }\n const fields = object.fields\n .map(normalizeFieldDescriptor)\n .sort((left, right) => compareCanonicalStrings(left.id, right.id));\n if (new Set(fields.map((field) => field.id)).size !== fields.length) {\n return fail('Data query schema field ids must be unique');\n }\n const identityField = stringValue(\n object.identityField,\n 'Data query identity field',\n );\n const identity = fields.find((field) => field.id === identityField);\n if (!identity) return fail('Data query identity field must be declared');\n if (identity.projectable === false) {\n return fail('Data query identity field must be projectable');\n }\n if (!['string', 'number', 'datetime'].includes(identity.type)) {\n return fail(\n 'Data query identity field must use a string, number, or datetime type',\n );\n }\n const maxPageLimit =\n object.maxPageLimit === undefined\n ? MAX_DATA_QUERY_PAGE_LIMIT\n : positiveInteger(object.maxPageLimit, 'Data query maximum page limit');\n if (maxPageLimit > MAX_DATA_QUERY_PAGE_LIMIT) {\n return fail(\n `Data query maximum page limit cannot exceed ${MAX_DATA_QUERY_PAGE_LIMIT}`,\n );\n }\n const defaultPageLimit =\n object.defaultPageLimit === undefined\n ? Math.min(DEFAULT_DATA_QUERY_PAGE_LIMIT, maxPageLimit)\n : positiveInteger(\n object.defaultPageLimit,\n 'Data query default page limit',\n );\n if (defaultPageLimit > maxPageLimit) {\n return fail(\n 'Data query default page limit cannot exceed the maximum page limit',\n );\n }\n const maxResultBytes =\n object.maxResultBytes === undefined\n ? DEFAULT_DATA_QUERY_RESULT_BYTES\n : positiveInteger(\n object.maxResultBytes,\n 'Data query maximum result bytes',\n );\n if (maxResultBytes > MAX_DATA_QUERY_RESULT_BYTES) {\n return fail(\n `Data query maximum result bytes cannot exceed ${MAX_DATA_QUERY_RESULT_BYTES}`,\n );\n }\n let supports: DataQuerySchema['supports'];\n if (object.supports !== undefined) {\n const supportObject = plainObject(\n object.supports,\n 'Data query schema supports',\n );\n exactKeys(\n supportObject,\n ['cursorPagination', 'consistency', 'facets'],\n 'Data query schema supports',\n );\n for (const key of ['cursorPagination', 'consistency', 'facets'] as const) {\n if (\n supportObject[key] !== undefined &&\n typeof supportObject[key] !== 'boolean'\n ) {\n fail(`Data query schema supports.${key} must be boolean`);\n }\n }\n const cursorPagination =\n typeof supportObject.cursorPagination === 'boolean'\n ? supportObject.cursorPagination\n : undefined;\n const consistency =\n typeof supportObject.consistency === 'boolean'\n ? supportObject.consistency\n : undefined;\n const facets =\n typeof supportObject.facets === 'boolean'\n ? supportObject.facets\n : undefined;\n supports = {\n ...(cursorPagination === undefined ? {} : { cursorPagination }),\n ...(consistency === undefined ? {} : { consistency }),\n ...(facets === undefined ? {} : { facets }),\n };\n }\n const fieldMap = new Map(fields.map((field) => [field.id, field]));\n const defaultSort = normalizeSort(\n object.defaultSort,\n fieldMap,\n identityField,\n 'Data query default sort',\n false,\n );\n return {\n version: 1,\n identityField,\n fields,\n defaultPageLimit,\n maxPageLimit,\n maxResultBytes,\n ...(defaultSort.length > 0 ? { defaultSort } : {}),\n ...(supports ? { supports } : {}),\n };\n}\n\ninterface FilterBudget {\n nodes: number;\n}\n\nfunction scalarForField(\n value: unknown,\n descriptor: DataQueryFieldDescriptor,\n label: string,\n): DataQueryScalar {\n const scalar = dataQueryScalar(value, label);\n if (scalar === null) return scalar;\n if (descriptor.type === 'number' && typeof scalar !== 'number') {\n return fail(`${label} must be a number for ${descriptor.id}`);\n }\n if (descriptor.type === 'boolean' && typeof scalar !== 'boolean') {\n return fail(`${label} must be a boolean for ${descriptor.id}`);\n }\n if (descriptor.type === 'string' && typeof scalar !== 'string') {\n return fail(`${label} must be a string for ${descriptor.id}`);\n }\n if (descriptor.type === 'datetime') {\n if (typeof scalar !== 'string') {\n return fail(`${label} must be an RFC 3339 instant for ${descriptor.id}`);\n }\n return normalizedInstant(scalar, label);\n }\n return scalar;\n}\n\nfunction normalizeFilter(\n value: unknown,\n fields: Map<string, DataQueryFieldDescriptor>,\n depth = 0,\n budget: FilterBudget = { nodes: 0 },\n): DataQueryFilter {\n if (depth > MAX_DATA_QUERY_FILTER_DEPTH) {\n return fail(\n `Data query filter cannot exceed depth ${MAX_DATA_QUERY_FILTER_DEPTH}`,\n );\n }\n budget.nodes += 1;\n if (budget.nodes > MAX_DATA_QUERY_FILTERS) {\n return fail(\n `Data query filter cannot exceed ${MAX_DATA_QUERY_FILTERS} expressions`,\n );\n }\n const object = plainObject(value, 'Data query filter');\n const kind = stringValue(object.kind, 'Data query filter kind');\n if (kind === 'condition') {\n exactKeys(\n object,\n ['kind', 'field', 'operator', 'value'],\n 'Data query condition',\n );\n const field = stringValue(object.field, 'Data query condition field');\n const descriptor = fields.get(field);\n if (!descriptor)\n return fail(\n `Data query field is not declared: ${field}`,\n 'DATA_QUERY_FIELD_NOT_ALLOWED',\n );\n const operator = stringValue(\n object.operator,\n 'Data query condition operator',\n ) as DataQueryFilterOperator;\n if (\n !FILTER_OPERATORS.has(operator) ||\n !descriptor.filterOperators?.includes(operator)\n ) {\n return fail(\n `Data query operator ${operator} is not allowed for ${field}`,\n 'DATA_QUERY_OPERATOR_NOT_ALLOWED',\n );\n }\n if (operator === 'in' || operator === 'notIn') {\n if (!Array.isArray(object.value) || object.value.length === 0) {\n return fail(`Data query ${operator} value must be a non-empty array`);\n }\n if (object.value.length > MAX_DATA_QUERY_IN_VALUES) {\n return fail(\n `Data query ${operator} value cannot exceed ${MAX_DATA_QUERY_IN_VALUES} items`,\n );\n }\n const values = object.value.map((entry, index) => {\n const entryLabel = `Data query ${operator} value ${index}`;\n const scalar = scalarForField(entry, descriptor, entryLabel);\n assertDeclaredValue(scalar, descriptor, entryLabel);\n return scalar;\n });\n const canonicalValues = [\n ...new Map(values.map((entry) => [signature(entry), entry])).values(),\n ].sort((left, right) =>\n compareCanonicalStrings(signature(left), signature(right)),\n );\n return { kind: 'condition', field, operator, value: canonicalValues };\n }\n if (Array.isArray(object.value)) {\n return fail(`Data query ${operator} value must be a scalar`);\n }\n const scalar = scalarForField(\n object.value,\n descriptor,\n `Data query ${operator} value`,\n );\n if (operator === 'eq' || operator === 'ne') {\n assertDeclaredValue(scalar, descriptor, `Data query ${operator} value`);\n }\n if (operator === 'like' && descriptor.type !== 'string') {\n return fail('Data query like is only available for string fields');\n }\n if (operator === 'like' && typeof scalar !== 'string') {\n return fail('Data query like value must be a string');\n }\n if (\n ['gt', 'gte', 'lt', 'lte'].includes(operator) &&\n !['number', 'string', 'datetime'].includes(descriptor.type)\n ) {\n return fail(\n `Data query ${operator} is not available for ${descriptor.type} fields`,\n );\n }\n if (\n ['gt', 'gte', 'lt', 'lte', 'like'].includes(operator) &&\n scalar === null\n ) {\n return fail(`Data query ${operator} value cannot be null`);\n }\n return {\n kind: 'condition',\n field,\n operator,\n value: scalar,\n } as DataQueryCondition;\n }\n if (kind === 'all' || kind === 'any') {\n exactKeys(object, ['kind', 'filters'], `Data query ${kind} filter`);\n if (!Array.isArray(object.filters) || object.filters.length === 0) {\n return fail(`Data query ${kind} filter must contain at least one child`);\n }\n if (object.filters.length > MAX_DATA_QUERY_FILTERS) {\n return fail(\n `Data query ${kind} filter cannot exceed ${MAX_DATA_QUERY_FILTERS} children`,\n );\n }\n const filters = object.filters\n .map((filter) => normalizeFilter(filter, fields, depth + 1, budget))\n .sort((left, right) =>\n compareCanonicalStrings(signature(left), signature(right)),\n );\n return { kind, filters };\n }\n if (kind === 'not') {\n exactKeys(object, ['kind', 'filter'], 'Data query not filter');\n return {\n kind: 'not',\n filter: normalizeFilter(object.filter, fields, depth + 1, budget),\n };\n }\n return fail(`Unsupported data query filter kind: ${kind}`);\n}\n\nfunction normalizeSort(\n value: unknown,\n fields: Map<string, DataQueryFieldDescriptor>,\n identityField: string,\n label: string,\n appendIdentity: boolean,\n): DataQuerySort[] {\n if (value === undefined)\n return appendIdentity ? [{ field: identityField, direction: 'asc' }] : [];\n if (!Array.isArray(value)) return fail(`${label} must be an array`);\n if (value.length > MAX_DATA_QUERY_FILTERS) {\n return fail(`${label} cannot exceed ${MAX_DATA_QUERY_FILTERS} terms`);\n }\n const sort = value.map((entry) => {\n const object = plainObject(entry, label);\n exactKeys(object, ['field', 'direction'], label);\n const field = stringValue(object.field, `${label} field`);\n if (!fields.get(field)?.sortable && field !== identityField) {\n fail(\n `Data query sort field is not allowed: ${field}`,\n 'DATA_QUERY_SORT_NOT_ALLOWED',\n );\n }\n const direction = stringValue(object.direction, `${label} direction`);\n if (direction !== 'asc' && direction !== 'desc') {\n fail(`Data query sort direction must be asc or desc`);\n }\n return { field, direction } as DataQuerySort;\n });\n if (new Set(sort.map((term) => term.field)).size !== sort.length) {\n return fail(`${label} field ids must be unique`);\n }\n if (appendIdentity && !sort.some((term) => term.field === identityField)) {\n sort.push({ field: identityField, direction: 'asc' });\n }\n return sort;\n}\n\nfunction normalizePage(value: unknown, schema: DataQuerySchema): DataQueryPage {\n if (value === undefined) {\n return {\n kind: 'offset',\n offset: 0,\n limit: schema.defaultPageLimit ?? DEFAULT_DATA_QUERY_PAGE_LIMIT,\n };\n }\n const object = plainObject(value, 'Data query page');\n const kind = stringValue(object.kind, 'Data query page kind');\n if (kind === 'offset') {\n exactKeys(object, ['kind', 'offset', 'limit'], 'Data query offset page');\n const offset = nonNegativeInteger(object.offset, 'Data query offset');\n if (offset > MAX_DATA_QUERY_OFFSET) {\n return fail(`Data query offset cannot exceed ${MAX_DATA_QUERY_OFFSET}`);\n }\n return {\n kind,\n offset,\n limit: Math.min(\n positiveInteger(object.limit, 'Data query page limit'),\n schema.maxPageLimit ?? MAX_DATA_QUERY_PAGE_LIMIT,\n ),\n };\n }\n if (kind === 'cursor') {\n if (!schema.supports?.cursorPagination) {\n return fail(\n 'Data query cursor pagination is not supported',\n 'DATA_QUERY_UNSUPPORTED',\n );\n }\n exactKeys(object, ['kind', 'after', 'limit'], 'Data query cursor page');\n const after =\n object.after === undefined\n ? undefined\n : stringValue(\n object.after,\n 'Data query cursor',\n MAX_DATA_QUERY_CURSOR_LENGTH,\n );\n return {\n kind,\n ...(after === undefined ? {} : { after }),\n limit: Math.min(\n positiveInteger(object.limit, 'Data query page limit'),\n schema.maxPageLimit ?? MAX_DATA_QUERY_PAGE_LIMIT,\n ),\n };\n }\n return fail(`Unsupported data query page kind: ${kind}`);\n}\n\nfunction normalizeConsistency(\n value: unknown,\n schema: DataQuerySchema,\n): DataQueryConsistency | undefined {\n if (value === undefined) return undefined;\n if (!schema.supports?.consistency) {\n return fail(\n 'Data query consistency options are not supported',\n 'DATA_QUERY_UNSUPPORTED',\n );\n }\n const object = plainObject(value, 'Data query consistency');\n exactKeys(object, ['mode', 'asOf'], 'Data query consistency');\n if (object.mode !== 'eventual' && object.mode !== 'snapshot')\n return fail('Unsupported data query consistency mode');\n const asOf =\n object.asOf === undefined\n ? undefined\n : normalizedInstant(object.asOf, 'Data query consistency asOf');\n return {\n mode: object.mode,\n ...(asOf === undefined ? {} : { asOf }),\n } as DataQueryConsistency;\n}\n\nfunction normalizeFacets(\n value: unknown,\n schema: DataQuerySchema,\n fields: Map<string, DataQueryFieldDescriptor>,\n): DataQueryFacetRequest[] {\n if (!schema.supports?.facets) {\n return fail(\n 'Data query facets are not supported',\n 'DATA_QUERY_UNSUPPORTED',\n );\n }\n if (!Array.isArray(value) || value.length === 0) {\n return fail('Data query facets must be a non-empty array');\n }\n if (value.length > MAX_DATA_QUERY_FACETS) {\n return fail(`Data query facets cannot exceed ${MAX_DATA_QUERY_FACETS}`);\n }\n const facets = value.map((entry) => {\n const object = plainObject(entry, 'Data query facet request');\n exactKeys(object, ['field', 'limit'], 'Data query facet request');\n const field = stringValue(object.field, 'Data query facet field');\n if (!fields.get(field)?.facetable) {\n fail(\n `Data query facet field is not allowed: ${field}`,\n 'DATA_QUERY_FACET_NOT_ALLOWED',\n );\n }\n return {\n field,\n limit: Math.min(\n positiveInteger(object.limit, 'Data query facet limit'),\n schema.maxPageLimit ?? MAX_DATA_QUERY_PAGE_LIMIT,\n ),\n };\n });\n if (new Set(facets.map((facet) => facet.field)).size !== facets.length) {\n return fail('Data query facet fields must be unique');\n }\n return facets.sort((left, right) =>\n compareCanonicalStrings(left.field, right.field),\n );\n}\n\nfunction boundRequestSize(request: DataQueryRequest): DataQueryRequest {\n const bytes = new TextEncoder().encode(JSON.stringify(request)).byteLength;\n if (bytes > MAX_DATA_QUERY_REQUEST_BYTES) {\n return fail(\n 'Data query request exceeds its maximum byte limit',\n 'DATA_QUERY_REQUEST_TOO_LARGE',\n );\n }\n return request;\n}\n\n/**\n * Normalize an untrusted request against its trusted adapter schema. Equivalent\n * projection/filter/facet orderings produce byte-identical output; sort order\n * remains intact because it is semantically meaningful. The identity field is\n * always projected even when a caller omits it.\n */\nexport function normalizeDataQueryRequest(\n value: unknown,\n inputSchema: unknown,\n): DataQueryRequest {\n const schema = normalizeDataQuerySchema(inputSchema);\n const fields = new Map(schema.fields.map((field) => [field.id, field]));\n const object = plainObject(value, 'Data query request');\n assertBoundedRawRequest(value);\n exactKeys(\n object,\n [\n 'version',\n 'requestId',\n 'mode',\n 'projection',\n 'filter',\n 'sort',\n 'page',\n 'consistency',\n 'facets',\n ],\n 'Data query request',\n );\n if (object.version !== 1)\n return fail('Unsupported data query request version');\n const requestId = stringValue(object.requestId, 'Data query request id', 128);\n const mode = stringValue(object.mode, 'Data query mode');\n if (!['rows', 'count', 'facets'].includes(mode))\n return fail(`Unsupported data query mode: ${mode}`);\n const filter =\n object.filter === undefined\n ? undefined\n : normalizeFilter(object.filter, fields);\n const consistency = normalizeConsistency(object.consistency, schema);\n if (mode === 'rows') {\n if (object.facets !== undefined)\n return fail('Rows queries cannot request facets');\n if (object.projection !== undefined && !Array.isArray(object.projection)) {\n return fail('Data query projection must be an array');\n }\n if (\n Array.isArray(object.projection) &&\n object.projection.length > MAX_DATA_QUERY_FILTERS\n ) {\n return fail(\n `Data query projection cannot exceed ${MAX_DATA_QUERY_FILTERS} fields`,\n );\n }\n const requestedProjection = (object.projection ?? []).map((field) =>\n stringValue(field, 'Data query projection field'),\n );\n for (const field of requestedProjection) {\n if (!fields.get(field)?.projectable && field !== schema.identityField) {\n fail(\n `Data query projection field is not allowed: ${field}`,\n 'DATA_QUERY_PROJECTION_NOT_ALLOWED',\n );\n }\n }\n const projection = [\n ...new Set([...requestedProjection, schema.identityField]),\n ].sort();\n const sort = normalizeSort(\n object.sort === undefined ? schema.defaultSort : object.sort,\n fields,\n schema.identityField,\n 'Data query sort',\n true,\n );\n return boundRequestSize({\n version: 1,\n requestId,\n mode,\n projection,\n ...(filter === undefined ? {} : { filter }),\n sort,\n page: normalizePage(object.page, schema),\n ...(consistency === undefined ? {} : { consistency }),\n });\n }\n if (\n object.projection !== undefined ||\n object.sort !== undefined ||\n object.page !== undefined\n ) {\n return fail(`${mode} data queries cannot carry projection, sort, or page`);\n }\n if (mode === 'facets') {\n return boundRequestSize({\n version: 1,\n requestId,\n mode,\n ...(filter === undefined ? {} : { filter }),\n ...(consistency === undefined ? {} : { consistency }),\n facets: normalizeFacets(object.facets, schema, fields),\n });\n }\n if (object.facets !== undefined)\n return fail('Count data queries cannot request facets');\n return boundRequestSize({\n version: 1,\n requestId,\n mode: 'count',\n ...(filter === undefined ? {} : { filter }),\n ...(consistency === undefined ? {} : { consistency }),\n });\n}\n\n/** Canonical match/query form used for stable fingerprints (no request id/page). */\nexport function canonicalizeDataQuery(value: unknown, schema: unknown): string {\n const request = normalizeDataQueryRequest(value, schema);\n const { requestId: _requestId, page: _page, ...semanticQuery } = request;\n return signature(semanticQuery);\n}\n\n/** Collision-resistant canonical fingerprint for result correlation and selection scope. */\nexport function createDataQueryFingerprint(\n value: unknown,\n schema: unknown,\n): string {\n return `dq1_${sha256Base64Url(canonicalizeDataQuery(value, schema))}`;\n}\n\nfunction normalizeResultFieldValue(\n value: unknown,\n descriptor: DataQueryFieldDescriptor,\n label: string,\n budget: JsonBudget,\n): unknown {\n if (descriptor.type === 'json') return canonicalJson(value, label, budget);\n const normalized = scalarForField(value, descriptor, label);\n consumeJsonSegment(budget, JSON.stringify(normalized), label);\n return normalized;\n}\n\nfunction normalizeRow(\n value: unknown,\n projection: readonly string[],\n identityField: string,\n fields: Map<string, DataQueryFieldDescriptor>,\n budget: JsonBudget,\n): DataQueryRow {\n const object = plainObject(value, 'Data query row');\n const allowed = new Set(projection);\n const normalized: JsonObject = Object.create(null) as JsonObject;\n consumeJsonSegment(budget, '{', 'Data query row');\n for (const [index, key] of Object.keys(object).entries()) {\n if (!allowed.has(key)) {\n fail(\n `Data query row returned a non-projected field: ${key}`,\n 'DATA_QUERY_RESULT_NOT_ALLOWED',\n );\n }\n const descriptor = fields.get(key);\n if (!descriptor) {\n return fail(\n `Data query row returned an undeclared field: ${key}`,\n 'DATA_QUERY_RESULT_NOT_ALLOWED',\n );\n }\n if (index > 0) consumeJsonSegment(budget, ',', 'Data query row');\n consumeJsonSegment(budget, JSON.stringify(key), `Data query row ${key}`);\n consumeJsonSegment(budget, ':', `Data query row ${key}`);\n normalized[key] = normalizeResultFieldValue(\n object[key],\n descriptor,\n `Data query row ${key}`,\n budget,\n );\n }\n consumeJsonSegment(budget, '}', 'Data query row');\n const identity = normalized[identityField];\n if (\n (typeof identity !== 'string' && typeof identity !== 'number') ||\n identity === ''\n ) {\n fail(\n 'Data query row must return a string or number identity field',\n 'DATA_QUERY_RESULT_INVALID',\n );\n }\n return normalized as DataQueryRow;\n}\n\nfunction normalizeTotal(value: unknown): DataQueryTotal {\n const object = plainObject(value, 'Data query total');\n const kind = stringValue(object.kind, 'Data query total kind');\n if (kind === 'unavailable') {\n exactKeys(object, ['kind', 'reason'], 'Data query unavailable total');\n const reason =\n object.reason === undefined\n ? undefined\n : stringValue(object.reason, 'Data query total reason');\n return { kind, ...(reason === undefined ? {} : { reason }) };\n }\n if (kind !== 'exact' && kind !== 'estimated') {\n return fail(`Unsupported data query total kind: ${kind}`);\n }\n exactKeys(object, ['kind', 'value', 'asOf'], 'Data query total');\n const asOf =\n object.asOf === undefined\n ? undefined\n : normalizedInstant(object.asOf, 'Data query total asOf');\n return {\n kind,\n value: nonNegativeInteger(object.value, 'Data query total value'),\n ...(asOf === undefined ? {} : { asOf }),\n };\n}\n\nfunction normalizeFreshness(value: unknown): DataQueryFreshness {\n const object = plainObject(value, 'Data query freshness');\n exactKeys(object, ['state', 'asOf'], 'Data query freshness');\n const state = stringValue(object.state, 'Data query freshness state');\n if (!['fresh', 'stale', 'unknown'].includes(state)) {\n return fail(`Unsupported data query freshness state: ${state}`);\n }\n const asOf =\n object.asOf === undefined\n ? undefined\n : normalizedInstant(object.asOf, 'Data query freshness asOf');\n return {\n state: state as DataQueryFreshness['state'],\n ...(asOf === undefined ? {} : { asOf }),\n };\n}\n\nfunction normalizeFacetsResult(\n value: unknown,\n requested: readonly DataQueryFacetRequest[],\n fields: Map<string, DataQueryFieldDescriptor>,\n budget: JsonBudget,\n): DataQueryFacetResult[] {\n if (!Array.isArray(value))\n return fail('Data query result facets must be an array');\n if (value.length > requested.length) {\n return fail('Data query result returned too many facets');\n }\n const limits = new Map(requested.map((facet) => [facet.field, facet.limit]));\n consumeJsonSegment(budget, '[', 'Data query result facets');\n const results = value.map((entry, index) => {\n if (index > 0) consumeJsonSegment(budget, ',', 'Data query result facets');\n const object = plainObject(entry, 'Data query facet result');\n exactKeys(\n object,\n ['field', 'values', 'truncated'],\n 'Data query facet result',\n );\n const field = stringValue(object.field, 'Data query facet result field');\n const limit = limits.get(field);\n if (limit === undefined)\n return fail(`Data query returned an unrequested facet: ${field}`);\n if (!Array.isArray(object.values) || object.values.length > limit) {\n return fail(`Data query facet ${field} exceeds its requested limit`);\n }\n if (typeof object.truncated !== 'boolean')\n return fail('Data query facet truncated must be boolean');\n const descriptor = fields.get(field);\n if (!descriptor)\n return fail(`Data query facet field is not declared: ${field}`);\n consumeJsonSegment(budget, '{\"field\":', `Data query facet ${field}`);\n consumeJsonSegment(\n budget,\n JSON.stringify(field),\n `Data query facet ${field}`,\n );\n consumeJsonSegment(budget, ',\"values\":[', `Data query facet ${field}`);\n const values = object.values.map((candidate, valueIndex) => {\n if (valueIndex > 0)\n consumeJsonSegment(budget, ',', `Data query facet ${field}`);\n const facet = plainObject(candidate, 'Data query facet value');\n exactKeys(facet, ['value', 'count'], 'Data query facet value');\n const normalizedValue = scalarForField(\n facet.value,\n descriptor,\n `Data query facet ${field} value`,\n );\n const count = nonNegativeInteger(facet.count, 'Data query facet count');\n consumeJsonSegment(\n budget,\n `{\"value\":${JSON.stringify(normalizedValue)},\"count\":${JSON.stringify(count)}}`,\n `Data query facet ${field} value`,\n );\n return {\n value: normalizedValue,\n count,\n };\n });\n consumeJsonSegment(\n budget,\n `],\"truncated\":${object.truncated}}`,\n `Data query facet ${field}`,\n );\n return { field, values, truncated: object.truncated };\n });\n consumeJsonSegment(budget, ']', 'Data query result facets');\n if (new Set(results.map((facet) => facet.field)).size !== results.length) {\n return fail('Data query result facet fields must be unique');\n }\n return results.sort((left, right) =>\n compareCanonicalStrings(left.field, right.field),\n );\n}\n\n/**\n * Validate an adapter result against the normalized request and its schema.\n * This is the final projection boundary: undeclared fields, malformed totals,\n * forged fingerprints, oversized rows, and authority-shaped prototype payloads\n * cannot cross into REST, MCP, WebMCP, or browser consumers unnoticed.\n */\nexport function normalizeDataQueryResult(\n value: unknown,\n inputRequest: unknown,\n inputSchema: unknown,\n): DataQueryResult {\n const schema = normalizeDataQuerySchema(inputSchema);\n const request = normalizeDataQueryRequest(inputRequest, schema);\n const fields = new Map(schema.fields.map((field) => [field.id, field]));\n const object = plainObject(value, 'Data query result');\n exactKeys(\n object,\n [\n 'version',\n 'requestId',\n 'queryFingerprint',\n 'identityField',\n 'rows',\n 'page',\n 'total',\n 'facets',\n 'freshness',\n 'warnings',\n 'truncated',\n ],\n 'Data query result',\n );\n if (object.version !== 1)\n return fail('Unsupported data query result version');\n if (\n stringValue(object.requestId, 'Data query result request id', 128) !==\n request.requestId\n ) {\n return fail(\n 'Data query result request id does not match its request',\n 'DATA_QUERY_RESULT_INVALID',\n );\n }\n const fingerprint = createDataQueryFingerprint(request, schema);\n if (\n stringValue(\n object.queryFingerprint,\n 'Data query result fingerprint',\n 128,\n ) !== fingerprint\n ) {\n return fail(\n 'Data query result fingerprint does not match its request',\n 'DATA_QUERY_RESULT_INVALID',\n );\n }\n if (\n stringValue(object.identityField, 'Data query result identity field') !==\n schema.identityField\n ) {\n return fail(\n 'Data query result identity field does not match its schema',\n 'DATA_QUERY_RESULT_INVALID',\n );\n }\n if (!Array.isArray(object.rows))\n return fail('Data query result rows must be an array');\n const projection =\n request.mode === 'rows'\n ? (request.projection ?? [schema.identityField])\n : [];\n const page = request.mode === 'rows' ? request.page : undefined;\n if (request.mode !== 'rows' && object.rows.length > 0) {\n return fail(`${request.mode} data query results cannot return rows`);\n }\n if (page && object.rows.length > page.limit) {\n return fail('Data query result rows exceed its requested page limit');\n }\n const budget: JsonBudget = {\n remaining: schema.maxResultBytes ?? DEFAULT_DATA_QUERY_RESULT_BYTES,\n failureCode: 'DATA_QUERY_RESULT_TOO_LARGE',\n };\n consumeJsonSegment(budget, '[', 'Data query result rows');\n const rows = object.rows.map((row, index) => {\n if (index > 0) consumeJsonSegment(budget, ',', 'Data query result rows');\n return normalizeRow(row, projection, schema.identityField, fields, budget);\n });\n consumeJsonSegment(budget, ']', 'Data query result rows');\n let normalizedPage: DataQueryResult['page'];\n if (page) {\n const pageObject = plainObject(object.page, 'Data query result page');\n exactKeys(\n pageObject,\n ['kind', 'limit', 'offset', 'nextCursor', 'hasMore'],\n 'Data query result page',\n );\n if (\n pageObject.kind !== page.kind ||\n nonNegativeInteger(pageObject.limit, 'Data query result page limit') !==\n page.limit\n ) {\n return fail('Data query result page does not match its request');\n }\n if (typeof pageObject.hasMore !== 'boolean')\n return fail('Data query result page hasMore must be boolean');\n if (page.kind === 'offset') {\n if (\n nonNegativeInteger(pageObject.offset, 'Data query result offset') !==\n page.offset\n ) {\n return fail('Data query result offset does not match its request');\n }\n if (pageObject.nextCursor !== undefined)\n return fail('Offset data query results cannot return a cursor');\n normalizedPage = {\n kind: 'offset',\n limit: page.limit,\n offset: page.offset,\n hasMore: pageObject.hasMore,\n };\n } else {\n if (pageObject.offset !== undefined) {\n return fail('Cursor data query results cannot return an offset');\n }\n const nextCursor =\n pageObject.nextCursor === undefined\n ? undefined\n : stringValue(\n pageObject.nextCursor,\n 'Data query result next cursor',\n MAX_DATA_QUERY_CURSOR_LENGTH,\n );\n if (pageObject.hasMore !== Boolean(nextCursor)) {\n return fail('Data query cursor result hasMore must match nextCursor');\n }\n normalizedPage = {\n kind: 'cursor',\n limit: page.limit,\n hasMore: pageObject.hasMore,\n ...(nextCursor === undefined ? {} : { nextCursor }),\n };\n }\n } else if (object.page !== undefined) {\n return fail(`${request.mode} data query results cannot return a page`);\n }\n const total = normalizeTotal(object.total);\n const freshness = normalizeFreshness(object.freshness);\n if (\n !Array.isArray(object.warnings) ||\n object.warnings.length > MAX_DATA_QUERY_WARNINGS ||\n object.warnings.some(\n (warning) =>\n typeof warning !== 'string' ||\n warning.length === 0 ||\n warning.length > 512,\n )\n ) {\n return fail('Data query result warnings must be at most 100 short strings');\n }\n if (typeof object.truncated !== 'boolean')\n return fail('Data query result truncated must be boolean');\n const facets =\n request.mode === 'facets'\n ? normalizeFacetsResult(\n object.facets,\n request.facets ?? [],\n fields,\n budget,\n )\n : object.facets === undefined\n ? undefined\n : fail(`${request.mode} data query results cannot return facets`);\n const normalized: DataQueryResult = {\n version: 1,\n requestId: request.requestId,\n queryFingerprint: fingerprint,\n identityField: schema.identityField,\n rows,\n ...(normalizedPage === undefined ? {} : { page: normalizedPage }),\n total,\n ...(facets === undefined ? {} : { facets }),\n freshness,\n warnings: [...new Set(object.warnings)].sort(),\n truncated: object.truncated,\n };\n const bytes = new TextEncoder().encode(JSON.stringify(normalized)).byteLength;\n if (bytes > (schema.maxResultBytes ?? DEFAULT_DATA_QUERY_RESULT_BYTES)) {\n return fail(\n 'Data query result exceeds its maximum byte limit',\n 'DATA_QUERY_RESULT_TOO_LARGE',\n );\n }\n return normalized;\n}\n"],"mappings":"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"}
|
package/dist/db-errors.d.ts
CHANGED
|
@@ -90,6 +90,13 @@ export declare function classifyDatabaseError(error: unknown): DatabaseErrorClas
|
|
|
90
90
|
export declare function isDeterministicDatabaseError(error: unknown): boolean;
|
|
91
91
|
/** True when the failure is contention or availability and may clear. */
|
|
92
92
|
export declare function isTransientDatabaseError(error: unknown): boolean;
|
|
93
|
+
/**
|
|
94
|
+
* True when the failure is a transient *connection* failure: the database
|
|
95
|
+
* dropped, refused or could not yet accept the connection (#3657). Narrower
|
|
96
|
+
* than {@link isTransientDatabaseError}, which also covers contention
|
|
97
|
+
* (deadlocks, serialization, locks). Used to retry startup bootstrap only.
|
|
98
|
+
*/
|
|
99
|
+
export declare function isTransientConnectionError(error: unknown): boolean;
|
|
93
100
|
/** True when a unique or primary-key constraint was violated. */
|
|
94
101
|
export declare function isUniqueViolationError(error: unknown): boolean;
|
|
95
102
|
/** True when a NOT NULL constraint was violated. */
|
package/dist/db-errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db-errors.d.ts","sourceRoot":"","sources":["../src/db-errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,0DAA0D;AAC1D,MAAM,MAAM,iBAAiB,GACzB,kBAAkB,GAClB,oBAAoB,GACpB,uBAAuB,GACvB,iBAAiB,GACjB,qBAAqB,GACrB,eAAe,GACf,qBAAqB,GACrB,kBAAkB,GAClB,wBAAwB,GACxB,cAAc,GACd,WAAW,GACX,SAAS,CAAC;AAEd,0DAA0D;AAC1D,MAAM,WAAW,2BAA2B;IAC1C,yEAAyE;IACzE,IAAI,EAAE,iBAAiB,CAAC;IACxB,oDAAoD;IACpD,aAAa,EAAE,OAAO,CAAC;IACvB,gDAAgD;IAChD,SAAS,EAAE,OAAO,CAAC;IACnB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B;;;;;OAKG;IACH,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAgWD;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,CAMzE;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,GACb,2BAA2B,CA6G7B;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAEpE;AAED,yEAAyE;AACzE,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAEhE;AAED,iEAAiE;AACjE,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE9D;AAED,oDAAoD;AACpD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE/D;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAWjE"}
|
|
1
|
+
{"version":3,"file":"db-errors.d.ts","sourceRoot":"","sources":["../src/db-errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,0DAA0D;AAC1D,MAAM,MAAM,iBAAiB,GACzB,kBAAkB,GAClB,oBAAoB,GACpB,uBAAuB,GACvB,iBAAiB,GACjB,qBAAqB,GACrB,eAAe,GACf,qBAAqB,GACrB,kBAAkB,GAClB,wBAAwB,GACxB,cAAc,GACd,WAAW,GACX,SAAS,CAAC;AAEd,0DAA0D;AAC1D,MAAM,WAAW,2BAA2B;IAC1C,yEAAyE;IACzE,IAAI,EAAE,iBAAiB,CAAC;IACxB,oDAAoD;IACpD,aAAa,EAAE,OAAO,CAAC;IACvB,gDAAgD;IAChD,SAAS,EAAE,OAAO,CAAC;IACnB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B;;;;;OAKG;IACH,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAgWD;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,CAMzE;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,GACb,2BAA2B,CA6G7B;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAEpE;AAED,yEAAyE;AACzE,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAEhE;AAqBD;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAclE;AAED,iEAAiE;AACjE,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE9D;AAED,oDAAoD;AACpD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE/D;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAWjE"}
|
package/dist/db-errors.js
CHANGED
|
@@ -356,6 +356,39 @@ function isDeterministicDatabaseError(error) {
|
|
|
356
356
|
function isTransientDatabaseError(error) {
|
|
357
357
|
return classifyDatabaseError(error).retryable;
|
|
358
358
|
}
|
|
359
|
+
/**
|
|
360
|
+
* Codes that mean the connection itself failed or the server would not take
|
|
361
|
+
* it yet: SQLSTATE class `08`, server shutdown/startup `57P01`–`57P03`,
|
|
362
|
+
* `53300 too_many_connections`, and the socket codes a server that is still
|
|
363
|
+
* starting or settling produces. Deliberately narrower than
|
|
364
|
+
* `TRANSIENT_NETWORK_CODES`: an unresolvable or unreachable host
|
|
365
|
+
* (`ENOTFOUND`, `EHOSTUNREACH`, `ENETUNREACH`) is a configuration error and
|
|
366
|
+
* must fail at once (#3657).
|
|
367
|
+
*/
|
|
368
|
+
var CONNECTION_SQLSTATES = /* @__PURE__ */ new Set([
|
|
369
|
+
"53300",
|
|
370
|
+
"57P01",
|
|
371
|
+
"57P02",
|
|
372
|
+
"57P03"
|
|
373
|
+
]);
|
|
374
|
+
var CONNECTION_SOCKET_CODES = /* @__PURE__ */ new Set([
|
|
375
|
+
"ECONNREFUSED",
|
|
376
|
+
"ECONNRESET",
|
|
377
|
+
"ETIMEDOUT",
|
|
378
|
+
"EAI_AGAIN"
|
|
379
|
+
]);
|
|
380
|
+
var CONNECTION_MESSAGE = /connection terminated|server closed the connection|too many clients|the database system is (?:starting up|shutting down|in recovery mode)/i;
|
|
381
|
+
/**
|
|
382
|
+
* True when the failure is a transient *connection* failure: the database
|
|
383
|
+
* dropped, refused or could not yet accept the connection (#3657). Narrower
|
|
384
|
+
* than {@link isTransientDatabaseError}, which also covers contention
|
|
385
|
+
* (deadlocks, serialization, locks). Used to retry startup bootstrap only.
|
|
386
|
+
*/
|
|
387
|
+
function isTransientConnectionError(error) {
|
|
388
|
+
const classification = classifyDatabaseError(error);
|
|
389
|
+
if (classification.deterministic) return false;
|
|
390
|
+
return classification.driverCodes.some((code) => CONNECTION_SQLSTATES.has(code) || CONNECTION_SOCKET_CODES.has(code) || /^08[0-9A-Z]{3}$/.test(code)) || classification.driverMessages.some((message) => CONNECTION_MESSAGE.test(message));
|
|
391
|
+
}
|
|
359
392
|
/** True when a unique or primary-key constraint was violated. */
|
|
360
393
|
function isUniqueViolationError(error) {
|
|
361
394
|
return classifyDatabaseError(error).kind === "unique_violation";
|
|
@@ -377,6 +410,6 @@ function isAbortedTransactionError(error) {
|
|
|
377
410
|
return signals.messages.some((message) => /current transaction is aborted/i.test(message));
|
|
378
411
|
}
|
|
379
412
|
//#endregion
|
|
380
|
-
export { classifyDatabaseError, classifyDialectMessage, isAbortedTransactionError, isDeterministicDatabaseError, isNotNullViolationError, isTransientDatabaseError, isUniqueViolationError };
|
|
413
|
+
export { classifyDatabaseError, classifyDialectMessage, isAbortedTransactionError, isDeterministicDatabaseError, isNotNullViolationError, isTransientConnectionError, isTransientDatabaseError, isUniqueViolationError };
|
|
381
414
|
|
|
382
415
|
//# sourceMappingURL=db-errors.js.map
|
package/dist/db-errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db-errors.js","names":[],"sources":["../src/db-errors.ts"],"sourcesContent":["/**\n * Driver-error classification for the persistence path (#2366).\n *\n * `@happyvertical/sql` does not normalize driver errors: every adapter catches\n * the driver failure and rethrows\n * `DatabaseError('Failed to upsert record into table', { …, originalError })`,\n * where `originalError` is the **string** produced by the SDK's `formatDbError`\n * (`\"<driver message>, code=<driver code>, detail=…, hint=…\"`). The typed\n * message therefore carries none of the constraint wording, which is why\n * matching on `error.message` alone silently stopped recognizing constraint\n * violations and let {@link ErrorUtils.withRetry} retry them.\n *\n * This module walks the whole causal chain — `cause`, `context.originalError`\n * (Error *or* formatted string), `originalError`, `details.causeMessages`, and\n * `AggregateError.errors` — collecting every driver code and message it finds,\n * then classifies on the codes first (PostgreSQL SQLSTATE, SQLite result\n * codes, Node network errno) and only falls back to dialect wording for DuckDB,\n * which reports no machine-readable code.\n *\n * The classification separates two independent questions:\n * - `deterministic` — a retry cannot change the outcome (constraint violation,\n * bad input syntax, aborted transaction, missing table). Fail fast.\n * - `retryable` — a retry plausibly can succeed (serialization failure,\n * deadlock, lock timeout, connection loss, `SQLITE_BUSY`).\n *\n * They are not complements: `kind: 'unknown'` means \"no opinion\", leaving the\n * caller's own default policy in charge.\n *\n * @module\n */\n\n/** Coarse classification of a database driver failure. */\nexport type DatabaseErrorKind =\n | 'unique_violation'\n | 'not_null_violation'\n | 'foreign_key_violation'\n | 'check_violation'\n | 'exclusion_violation'\n | 'invalid_input'\n | 'aborted_transaction'\n | 'undefined_object'\n | 'insufficient_privilege'\n | 'syntax_error'\n | 'transient'\n | 'unknown';\n\n/** Structured result of {@link classifyDatabaseError}. */\nexport interface DatabaseErrorClassification {\n /** What kind of failure this is, or `'unknown'` when nothing matched. */\n kind: DatabaseErrorKind;\n /** True when retrying cannot change the outcome. */\n deterministic: boolean;\n /** True when retrying plausibly can succeed. */\n retryable: boolean;\n /** PostgreSQL SQLSTATE recovered from the chain, when present. */\n sqlstate?: string;\n /** Raw driver code that produced the classification, when present. */\n driverCode?: string;\n /** Every driver code found anywhere in the chain, in discovery order. */\n driverCodes: readonly string[];\n /**\n * Every message found anywhere in the chain, in discovery order. Includes\n * the SDK's formatted `originalError` strings and the driver's own\n * `detail`/`hint` fields, which carry the PostgreSQL\n * `Key (col)=(value) already exists.` line used for column recovery.\n */\n driverMessages: readonly string[];\n /**\n * Column named directly by the driver (`node-postgres` sets `error.column`\n * on a `23502`), when one was reported. More reliable than parsing it back\n * out of the message.\n */\n column?: string;\n /** Constraint named directly by the driver (`error.constraint`). */\n constraint?: string;\n}\n\n/** Maximum chain depth walked, guarding against pathological nesting. */\nconst MAX_CHAIN_DEPTH = 12;\n\n/** `formatDbError` renders driver codes as `code=<value>` inside its string. */\nconst FORMATTED_CODE_PATTERN = /(?:^|[\\s,;([{])code=([A-Za-z0-9_]+)/g;\n\n/**\n * PostgreSQL SQLSTATE codes whose failure is fully determined by the statement\n * and its data. Retrying re-executes the same deterministic rejection.\n */\nconst DETERMINISTIC_SQLSTATES = new Map<string, DatabaseErrorKind>([\n // Class 23 — integrity constraint violation\n ['23000', 'check_violation'], // integrity_constraint_violation (generic)\n ['23001', 'foreign_key_violation'], // restrict_violation\n ['23502', 'not_null_violation'],\n ['23503', 'foreign_key_violation'],\n ['23505', 'unique_violation'],\n ['23514', 'check_violation'],\n // An EXCLUDE constraint is not a unique index: the conflicting rows differ on\n // the constrained columns and merely overlap under the operator. Reporting it\n // as `unique_violation` would make `save()` raise\n // VALIDATION_UNIQUE_CONSTRAINT naming a field that did not collide, so it\n // keeps its own kind and stays on the generic DatabaseError path.\n ['23P01', 'exclusion_violation'],\n // Class 22 — data exception (bad literal, overflow, bad uuid cast)\n ['22001', 'invalid_input'], // string_data_right_truncation\n ['22003', 'invalid_input'], // numeric_value_out_of_range\n ['22007', 'invalid_input'], // invalid_datetime_format\n ['22008', 'invalid_input'], // datetime_field_overflow\n ['22023', 'invalid_input'], // invalid_parameter_value\n ['22P02', 'invalid_input'], // invalid_text_representation — the bad-uuid case\n ['22P03', 'invalid_input'], // invalid_binary_representation\n // Class 25 — invalid transaction state. Only `25P02` belongs here:\n // `25P03 idle_in_transaction_session_timeout` means the server *terminated\n // the session*, which is a connection-level failure a fresh connection can\n // survive, so it lives in TRANSIENT_SQLSTATES instead. Calling it\n // deterministic would both block that retry and make\n // `isAbortedTransactionError()` report a timed-out session as an OIDC race\n // conflict in the profiles coordinator.\n ['25P02', 'aborted_transaction'], // in_failed_sql_transaction\n // Class 42 — syntax error or access rule violation\n ['42501', 'insufficient_privilege'],\n ['42601', 'syntax_error'],\n ['42703', 'undefined_object'], // undefined_column\n ['42804', 'invalid_input'], // datatype_mismatch\n ['42883', 'undefined_object'], // undefined_function\n ['42P01', 'undefined_object'], // undefined_table\n ['42P07', 'undefined_object'], // duplicate_table\n // invalid_column_reference — \"no unique or exclusion constraint matching the\n // ON CONFLICT specification\". A conflict target that does not match a real\n // unique index is a schema defect, not contention; retrying it four times\n // only delays the report (see epic #2382 finding A4).\n ['42P10', 'undefined_object'],\n ['3D000', 'undefined_object'], // invalid_catalog_name\n ['3F000', 'undefined_object'], // invalid_schema_name\n]);\n\n/**\n * PostgreSQL SQLSTATE codes describing a contention or availability failure.\n * The same statement may well succeed on a later attempt.\n */\nconst TRANSIENT_SQLSTATES = new Set([\n '25P03', // idle_in_transaction_session_timeout — the session was terminated\n '40001', // serialization_failure\n '40003', // statement_completion_unknown\n '40P01', // deadlock_detected\n '53200', // out_of_memory\n '53300', // too_many_connections\n '55P03', // lock_not_available\n '57014', // query_canceled\n '57P01', // admin_shutdown\n '57P02', // crash_shutdown\n '57P03', // cannot_connect_now\n '58030', // io_error\n '08000', // connection_exception\n '08001', // sqlclient_unable_to_establish_sqlconnection\n '08003', // connection_does_not_exist\n '08004', // sqlserver_rejected_establishment_of_sqlconnection\n '08006', // connection_failure\n '08007', // transaction_resolution_unknown\n '08P01', // protocol_violation\n]);\n\n/**\n * SQLite extended result codes. `better-sqlite3`/`node:sqlite` frequently\n * report the bare `SQLITE_CONSTRAINT` parent code, so the constraint sub-kind\n * is resolved from the message instead (see {@link classifyDialectMessage}).\n */\nconst DETERMINISTIC_SQLITE_CODES = new Map<string, DatabaseErrorKind>([\n ['SQLITE_CONSTRAINT_UNIQUE', 'unique_violation'],\n ['SQLITE_CONSTRAINT_PRIMARYKEY', 'unique_violation'],\n ['SQLITE_CONSTRAINT_ROWID', 'unique_violation'],\n ['SQLITE_CONSTRAINT_NOTNULL', 'not_null_violation'],\n ['SQLITE_CONSTRAINT_FOREIGNKEY', 'foreign_key_violation'],\n ['SQLITE_CONSTRAINT_CHECK', 'check_violation'],\n ['SQLITE_CONSTRAINT_TRIGGER', 'check_violation'],\n ['SQLITE_MISMATCH', 'invalid_input'],\n ['SQLITE_RANGE', 'invalid_input'],\n ['SQLITE_TOOBIG', 'invalid_input'],\n ['SQLITE_READONLY', 'insufficient_privilege'],\n ['SQLITE_AUTH', 'insufficient_privilege'],\n]);\n\n/** SQLite result codes that clear once contention or a lock resolves. */\nconst TRANSIENT_SQLITE_CODES = new Set([\n 'SQLITE_BUSY',\n 'SQLITE_BUSY_SNAPSHOT',\n 'SQLITE_BUSY_TIMEOUT',\n 'SQLITE_LOCKED',\n 'SQLITE_LOCKED_SHAREDCACHE',\n 'SQLITE_PROTOCOL',\n]);\n\n/** Node/libuv socket errno values raised when a pooled connection drops. */\nconst TRANSIENT_NETWORK_CODES = new Set([\n 'ECONNRESET',\n 'ECONNREFUSED',\n 'ECONNABORTED',\n 'EPIPE',\n 'ETIMEDOUT',\n 'ENETUNREACH',\n 'ENETRESET',\n 'EHOSTUNREACH',\n 'EAI_AGAIN',\n 'ENOTFOUND',\n]);\n\n/**\n * Dialect wording, in precedence order. Only DuckDB has no machine-readable\n * code, but SQLite's bare `SQLITE_CONSTRAINT` and PostgreSQL errors that have\n * lost their code through string formatting are recovered here too.\n *\n * NOT NULL is tested before UNIQUE because DuckDB phrases both with the same\n * `Constraint Error … violates` shape, and foreign-key/check wording must not\n * be mistaken for a unique violation (#1578).\n */\nconst DIALECT_MESSAGE_RULES: ReadonlyArray<{\n kind: DatabaseErrorKind;\n pattern: RegExp;\n}> = [\n {\n kind: 'aborted_transaction',\n pattern: /current transaction is aborted/i,\n },\n {\n kind: 'not_null_violation',\n pattern:\n /NOT NULL constraint failed|null value in column .* violates not-null/i,\n },\n {\n // SQLite reports `FOREIGN KEY constraint failed` under the bare\n // `SQLITE_CONSTRAINT` parent code, so without this arm the sub-kind\n // recovery below would mislabel every SQLite FK failure.\n kind: 'foreign_key_violation',\n pattern: /violates foreign key constraint|FOREIGN KEY constraint failed/i,\n },\n {\n kind: 'check_violation',\n pattern: /violates check constraint|CHECK constraint failed/i,\n },\n {\n kind: 'unique_violation',\n pattern:\n /UNIQUE constraint failed|violates unique constraint|violates primary key constraint|duplicate key value violates|PRIMARY KEY or UNIQUE constraint violation/i,\n },\n {\n kind: 'invalid_input',\n pattern: /invalid input syntax for type|value too long for type/i,\n },\n {\n // Deliberately narrow: a bare /does not exist/ matches far too much to be\n // safe as a fail-fast signal.\n kind: 'undefined_object',\n pattern:\n /no such table|no such column|(?:relation|column|table|function) \"[^\"]*\" does not exist/i,\n },\n {\n kind: 'transient',\n pattern:\n /database is locked|database table is locked|connection terminated|server closed the connection|too many clients|deadlock detected|could not serialize access/i,\n },\n];\n\n/** SMRT-level codes that already express a driver classification. */\nconst SMRT_CODE_KINDS = new Map<string, DatabaseErrorKind>([\n ['VALIDATION_UNIQUE_CONSTRAINT', 'unique_violation'],\n ['DB_CONSTRAINT_VIOLATION', 'check_violation'],\n]);\n\n/**\n * Reporting precedence among deterministic kinds, most specific first.\n *\n * `aborted_transaction` ranks last on purpose: PostgreSQL reports `25P02` for\n * every statement issued after the transaction already failed, so a chain\n * carrying both it and the constraint that caused the abort must name the\n * constraint. Every kind here is non-retryable, so ranking changes only what\n * is reported, never whether the operation is retried.\n */\nconst DETERMINISTIC_KIND_RANK = new Map<DatabaseErrorKind, number>([\n ['unique_violation', 0],\n ['not_null_violation', 1],\n ['foreign_key_violation', 2],\n ['check_violation', 3],\n ['exclusion_violation', 4],\n ['invalid_input', 5],\n ['undefined_object', 6],\n ['insufficient_privilege', 7],\n ['syntax_error', 8],\n ['aborted_transaction', 9],\n]);\n\nfunction rankKind(kind: DatabaseErrorKind): number {\n return DETERMINISTIC_KIND_RANK.get(kind) ?? Number.MAX_SAFE_INTEGER;\n}\n\ninterface ChainSignals {\n codes: string[];\n messages: string[];\n columns: string[];\n constraints: string[];\n}\n\nfunction pushUnique(collection: string[], value: unknown): void {\n if (typeof value !== 'string') return;\n const entry = value.trim();\n if (entry && !collection.includes(entry)) {\n collection.push(entry);\n }\n}\n\nfunction pushCode(signals: ChainSignals, value: unknown): void {\n pushUnique(signals.codes, value);\n}\n\nfunction pushMessage(signals: ChainSignals, value: unknown): void {\n if (typeof value !== 'string') return;\n const message = value.trim();\n if (!message || signals.messages.includes(message)) return;\n signals.messages.push(message);\n\n // `formatDbError` folds the driver's own `code` into its string, so the\n // machine-readable classification survives even after stringification.\n FORMATTED_CODE_PATTERN.lastIndex = 0;\n let match = FORMATTED_CODE_PATTERN.exec(message);\n while (match) {\n pushCode(signals, match[1]);\n match = FORMATTED_CODE_PATTERN.exec(message);\n }\n}\n\n/**\n * Walks an error's causal chain, collecting every driver code and message.\n *\n * Visits `cause`, `context.originalError`, `originalError`,\n * `details.causeMessage`/`details.causeMessages` and `AggregateError.errors`,\n * because the SDK, core and consumer wrappers each nest the driver error\n * differently. Cycles and depth are bounded.\n */\nfunction collectChainSignals(error: unknown): ChainSignals {\n const signals: ChainSignals = {\n codes: [],\n messages: [],\n columns: [],\n constraints: [],\n };\n const seen = new Set<unknown>();\n const pending: Array<{ value: unknown; depth: number }> = [\n { value: error, depth: 0 },\n ];\n\n while (pending.length > 0) {\n const entry = pending.pop();\n if (!entry) break;\n const { value, depth } = entry;\n if (value === null || value === undefined || depth > MAX_CHAIN_DEPTH) {\n continue;\n }\n\n if (typeof value === 'string') {\n pushMessage(signals, value);\n continue;\n }\n if (typeof value !== 'object' || seen.has(value)) continue;\n seen.add(value);\n\n const node = value as {\n code?: unknown;\n sqlState?: unknown;\n sqlstate?: unknown;\n message?: unknown;\n detail?: unknown;\n hint?: unknown;\n column?: unknown;\n constraint?: unknown;\n cause?: unknown;\n context?: { originalError?: unknown } | unknown;\n originalError?: unknown;\n details?: unknown;\n errors?: unknown;\n };\n\n pushCode(signals, node.code);\n pushCode(signals, node.sqlState);\n pushCode(signals, node.sqlstate);\n pushMessage(signals, node.message);\n // `node-postgres` surfaces the PostgreSQL error fields as properties. On\n // the direct INSERT path nothing stringifies them into the message, so the\n // column would otherwise be unrecoverable (`error.detail` carries\n // \"Key (sku)=(s1) already exists.\" for a 23505; `error.column` names the\n // column outright for a 23502).\n pushMessage(signals, node.detail);\n pushMessage(signals, node.hint);\n pushUnique(signals.columns, node.column);\n pushUnique(signals.constraints, node.constraint);\n\n const details = node.details as\n | { causeMessage?: unknown; causeMessages?: unknown }\n | undefined;\n if (details && typeof details === 'object') {\n pushMessage(signals, details.causeMessage);\n if (Array.isArray(details.causeMessages)) {\n for (const causeMessage of details.causeMessages) {\n pushMessage(signals, causeMessage);\n }\n }\n }\n\n const context = node.context as { originalError?: unknown } | undefined;\n const next = [\n node.cause,\n node.originalError,\n context && typeof context === 'object'\n ? context.originalError\n : undefined,\n ];\n for (const child of next) {\n if (child !== null && child !== undefined) {\n pending.push({ value: child, depth: depth + 1 });\n }\n }\n if (Array.isArray(node.errors)) {\n for (const child of node.errors) {\n pending.push({ value: child, depth: depth + 1 });\n }\n }\n }\n\n return signals;\n}\n\n/**\n * Classifies a raw dialect message. Exposed so\n * `SmrtObject.classifyConstraintError()` and this module share one set of\n * regexes rather than drifting apart.\n */\nexport function classifyDialectMessage(message: string): DatabaseErrorKind {\n if (!message) return 'unknown';\n for (const rule of DIALECT_MESSAGE_RULES) {\n if (rule.pattern.test(message)) return rule.kind;\n }\n return 'unknown';\n}\n\nfunction isSqlState(code: string): boolean {\n return /^[0-9A-Z]{5}$/.test(code);\n}\n\n/**\n * Classifies a database failure by walking its causal chain.\n *\n * Codes win over wording: a PostgreSQL SQLSTATE or SQLite result code is\n * authoritative, and dialect message matching only runs when no code in the\n * chain was recognized (DuckDB, or an error already flattened to a string).\n *\n * Constraint violations are reported ahead of `aborted_transaction` so a chain\n * carrying both surfaces the root cause rather than the downstream symptom;\n * both are deterministic, so retry behavior is identical either way.\n *\n * @param error - Any thrown value. Non-database errors classify as `'unknown'`.\n * @returns The structured classification; never throws.\n */\nexport function classifyDatabaseError(\n error: unknown,\n): DatabaseErrorClassification {\n const signals = collectChainSignals(error);\n const sqlstate = signals.codes.find(\n (code) =>\n isSqlState(code) &&\n (DETERMINISTIC_SQLSTATES.has(code) || TRANSIENT_SQLSTATES.has(code)),\n );\n\n const base = {\n driverCodes: signals.codes,\n driverMessages: signals.messages,\n ...(sqlstate ? { sqlstate } : {}),\n ...(signals.columns[0] ? { column: signals.columns[0] } : {}),\n ...(signals.constraints[0] ? { constraint: signals.constraints[0] } : {}),\n };\n\n // Deterministic codes first: a chain that carries both a constraint code and\n // a downstream contention code must fail fast, not retry.\n const deterministicCandidates: Array<{\n code: string;\n kind: DatabaseErrorKind;\n }> = [];\n for (const code of signals.codes) {\n const kind =\n DETERMINISTIC_SQLSTATES.get(code) ??\n DETERMINISTIC_SQLITE_CODES.get(code) ??\n // SMRT's own typed codes: a `ValidationError` already carrying\n // `VALIDATION_UNIQUE_CONSTRAINT` is the classified form of the same\n // driver failure.\n SMRT_CODE_KINDS.get(code) ??\n // A bare `SQLITE_CONSTRAINT` carries no sub-kind; recover it from the\n // message, which SQLite always phrases explicitly.\n (code === 'SQLITE_CONSTRAINT'\n ? (signals.messages\n .map(classifyDialectMessage)\n .find((candidate) => DETERMINISTIC_KIND_RANK.has(candidate)) ??\n 'check_violation')\n : undefined);\n if (kind) deterministicCandidates.push({ code, kind });\n }\n\n if (deterministicCandidates.length > 0) {\n // Rank rather than take the first discovered: an error whose chain holds\n // both `23505` and the `25P02` it caused must report the root constraint,\n // not the downstream symptom.\n const best = deterministicCandidates.reduce((winner, candidate) =>\n rankKind(candidate.kind) < rankKind(winner.kind) ? candidate : winner,\n );\n return {\n ...base,\n kind: best.kind,\n deterministic: true,\n retryable: false,\n driverCode: best.code,\n };\n }\n\n for (const code of signals.codes) {\n if (TRANSIENT_SQLSTATES.has(code) || TRANSIENT_SQLITE_CODES.has(code)) {\n return {\n ...base,\n kind: 'transient',\n deterministic: false,\n retryable: true,\n driverCode: code,\n };\n }\n if (TRANSIENT_NETWORK_CODES.has(code)) {\n return {\n ...base,\n kind: 'transient',\n deterministic: false,\n retryable: true,\n driverCode: code,\n };\n }\n }\n\n // No recognized code anywhere — fall back to dialect wording. This is the\n // only path DuckDB ever takes.\n const messageKinds = signals.messages\n .map(classifyDialectMessage)\n .filter((kind) => kind !== 'unknown');\n const deterministicFromMessage = messageKinds\n .filter((kind) => DETERMINISTIC_KIND_RANK.has(kind))\n .sort((left, right) => rankKind(left) - rankKind(right))[0];\n if (deterministicFromMessage) {\n return {\n ...base,\n kind: deterministicFromMessage,\n deterministic: true,\n retryable: false,\n };\n }\n if (messageKinds.includes('transient')) {\n return {\n ...base,\n kind: 'transient',\n deterministic: false,\n retryable: true,\n };\n }\n\n return {\n ...base,\n kind: 'unknown',\n deterministic: false,\n retryable: false,\n };\n}\n\n/**\n * True when retrying the statement cannot change the outcome.\n *\n * Used by {@link ErrorUtils.withRetry} to fail fast instead of burning the\n * full 500 + 1000 + 2000 ms backoff on a constraint violation.\n */\nexport function isDeterministicDatabaseError(error: unknown): boolean {\n return classifyDatabaseError(error).deterministic;\n}\n\n/** True when the failure is contention or availability and may clear. */\nexport function isTransientDatabaseError(error: unknown): boolean {\n return classifyDatabaseError(error).retryable;\n}\n\n/** True when a unique or primary-key constraint was violated. */\nexport function isUniqueViolationError(error: unknown): boolean {\n return classifyDatabaseError(error).kind === 'unique_violation';\n}\n\n/** True when a NOT NULL constraint was violated. */\nexport function isNotNullViolationError(error: unknown): boolean {\n return classifyDatabaseError(error).kind === 'not_null_violation';\n}\n\n/**\n * True when the failure came from running inside an already-aborted\n * PostgreSQL transaction (SQLSTATE `25P02`).\n *\n * Detected independently of {@link DatabaseErrorKind} so a chain that also\n * carries the root constraint code still answers `true` here.\n */\nexport function isAbortedTransactionError(error: unknown): boolean {\n const signals = collectChainSignals(error);\n // `25P02` only. `25P03` is a terminated session, not a failed transaction,\n // and reporting it here would make the profiles coordinator treat an\n // idle-timeout disconnect as a provisioning race conflict.\n if (signals.codes.includes('25P02')) {\n return true;\n }\n return signals.messages.some((message) =>\n /current transaction is aborted/i.test(message),\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"db-errors.js","names":[],"sources":["../src/db-errors.ts"],"sourcesContent":["/**\n * Driver-error classification for the persistence path (#2366).\n *\n * `@happyvertical/sql` does not normalize driver errors: every adapter catches\n * the driver failure and rethrows\n * `DatabaseError('Failed to upsert record into table', { …, originalError })`,\n * where `originalError` is the **string** produced by the SDK's `formatDbError`\n * (`\"<driver message>, code=<driver code>, detail=…, hint=…\"`). The typed\n * message therefore carries none of the constraint wording, which is why\n * matching on `error.message` alone silently stopped recognizing constraint\n * violations and let {@link ErrorUtils.withRetry} retry them.\n *\n * This module walks the whole causal chain — `cause`, `context.originalError`\n * (Error *or* formatted string), `originalError`, `details.causeMessages`, and\n * `AggregateError.errors` — collecting every driver code and message it finds,\n * then classifies on the codes first (PostgreSQL SQLSTATE, SQLite result\n * codes, Node network errno) and only falls back to dialect wording for DuckDB,\n * which reports no machine-readable code.\n *\n * The classification separates two independent questions:\n * - `deterministic` — a retry cannot change the outcome (constraint violation,\n * bad input syntax, aborted transaction, missing table). Fail fast.\n * - `retryable` — a retry plausibly can succeed (serialization failure,\n * deadlock, lock timeout, connection loss, `SQLITE_BUSY`).\n *\n * They are not complements: `kind: 'unknown'` means \"no opinion\", leaving the\n * caller's own default policy in charge.\n *\n * @module\n */\n\n/** Coarse classification of a database driver failure. */\nexport type DatabaseErrorKind =\n | 'unique_violation'\n | 'not_null_violation'\n | 'foreign_key_violation'\n | 'check_violation'\n | 'exclusion_violation'\n | 'invalid_input'\n | 'aborted_transaction'\n | 'undefined_object'\n | 'insufficient_privilege'\n | 'syntax_error'\n | 'transient'\n | 'unknown';\n\n/** Structured result of {@link classifyDatabaseError}. */\nexport interface DatabaseErrorClassification {\n /** What kind of failure this is, or `'unknown'` when nothing matched. */\n kind: DatabaseErrorKind;\n /** True when retrying cannot change the outcome. */\n deterministic: boolean;\n /** True when retrying plausibly can succeed. */\n retryable: boolean;\n /** PostgreSQL SQLSTATE recovered from the chain, when present. */\n sqlstate?: string;\n /** Raw driver code that produced the classification, when present. */\n driverCode?: string;\n /** Every driver code found anywhere in the chain, in discovery order. */\n driverCodes: readonly string[];\n /**\n * Every message found anywhere in the chain, in discovery order. Includes\n * the SDK's formatted `originalError` strings and the driver's own\n * `detail`/`hint` fields, which carry the PostgreSQL\n * `Key (col)=(value) already exists.` line used for column recovery.\n */\n driverMessages: readonly string[];\n /**\n * Column named directly by the driver (`node-postgres` sets `error.column`\n * on a `23502`), when one was reported. More reliable than parsing it back\n * out of the message.\n */\n column?: string;\n /** Constraint named directly by the driver (`error.constraint`). */\n constraint?: string;\n}\n\n/** Maximum chain depth walked, guarding against pathological nesting. */\nconst MAX_CHAIN_DEPTH = 12;\n\n/** `formatDbError` renders driver codes as `code=<value>` inside its string. */\nconst FORMATTED_CODE_PATTERN = /(?:^|[\\s,;([{])code=([A-Za-z0-9_]+)/g;\n\n/**\n * PostgreSQL SQLSTATE codes whose failure is fully determined by the statement\n * and its data. Retrying re-executes the same deterministic rejection.\n */\nconst DETERMINISTIC_SQLSTATES = new Map<string, DatabaseErrorKind>([\n // Class 23 — integrity constraint violation\n ['23000', 'check_violation'], // integrity_constraint_violation (generic)\n ['23001', 'foreign_key_violation'], // restrict_violation\n ['23502', 'not_null_violation'],\n ['23503', 'foreign_key_violation'],\n ['23505', 'unique_violation'],\n ['23514', 'check_violation'],\n // An EXCLUDE constraint is not a unique index: the conflicting rows differ on\n // the constrained columns and merely overlap under the operator. Reporting it\n // as `unique_violation` would make `save()` raise\n // VALIDATION_UNIQUE_CONSTRAINT naming a field that did not collide, so it\n // keeps its own kind and stays on the generic DatabaseError path.\n ['23P01', 'exclusion_violation'],\n // Class 22 — data exception (bad literal, overflow, bad uuid cast)\n ['22001', 'invalid_input'], // string_data_right_truncation\n ['22003', 'invalid_input'], // numeric_value_out_of_range\n ['22007', 'invalid_input'], // invalid_datetime_format\n ['22008', 'invalid_input'], // datetime_field_overflow\n ['22023', 'invalid_input'], // invalid_parameter_value\n ['22P02', 'invalid_input'], // invalid_text_representation — the bad-uuid case\n ['22P03', 'invalid_input'], // invalid_binary_representation\n // Class 25 — invalid transaction state. Only `25P02` belongs here:\n // `25P03 idle_in_transaction_session_timeout` means the server *terminated\n // the session*, which is a connection-level failure a fresh connection can\n // survive, so it lives in TRANSIENT_SQLSTATES instead. Calling it\n // deterministic would both block that retry and make\n // `isAbortedTransactionError()` report a timed-out session as an OIDC race\n // conflict in the profiles coordinator.\n ['25P02', 'aborted_transaction'], // in_failed_sql_transaction\n // Class 42 — syntax error or access rule violation\n ['42501', 'insufficient_privilege'],\n ['42601', 'syntax_error'],\n ['42703', 'undefined_object'], // undefined_column\n ['42804', 'invalid_input'], // datatype_mismatch\n ['42883', 'undefined_object'], // undefined_function\n ['42P01', 'undefined_object'], // undefined_table\n ['42P07', 'undefined_object'], // duplicate_table\n // invalid_column_reference — \"no unique or exclusion constraint matching the\n // ON CONFLICT specification\". A conflict target that does not match a real\n // unique index is a schema defect, not contention; retrying it four times\n // only delays the report (see epic #2382 finding A4).\n ['42P10', 'undefined_object'],\n ['3D000', 'undefined_object'], // invalid_catalog_name\n ['3F000', 'undefined_object'], // invalid_schema_name\n]);\n\n/**\n * PostgreSQL SQLSTATE codes describing a contention or availability failure.\n * The same statement may well succeed on a later attempt.\n */\nconst TRANSIENT_SQLSTATES = new Set([\n '25P03', // idle_in_transaction_session_timeout — the session was terminated\n '40001', // serialization_failure\n '40003', // statement_completion_unknown\n '40P01', // deadlock_detected\n '53200', // out_of_memory\n '53300', // too_many_connections\n '55P03', // lock_not_available\n '57014', // query_canceled\n '57P01', // admin_shutdown\n '57P02', // crash_shutdown\n '57P03', // cannot_connect_now\n '58030', // io_error\n '08000', // connection_exception\n '08001', // sqlclient_unable_to_establish_sqlconnection\n '08003', // connection_does_not_exist\n '08004', // sqlserver_rejected_establishment_of_sqlconnection\n '08006', // connection_failure\n '08007', // transaction_resolution_unknown\n '08P01', // protocol_violation\n]);\n\n/**\n * SQLite extended result codes. `better-sqlite3`/`node:sqlite` frequently\n * report the bare `SQLITE_CONSTRAINT` parent code, so the constraint sub-kind\n * is resolved from the message instead (see {@link classifyDialectMessage}).\n */\nconst DETERMINISTIC_SQLITE_CODES = new Map<string, DatabaseErrorKind>([\n ['SQLITE_CONSTRAINT_UNIQUE', 'unique_violation'],\n ['SQLITE_CONSTRAINT_PRIMARYKEY', 'unique_violation'],\n ['SQLITE_CONSTRAINT_ROWID', 'unique_violation'],\n ['SQLITE_CONSTRAINT_NOTNULL', 'not_null_violation'],\n ['SQLITE_CONSTRAINT_FOREIGNKEY', 'foreign_key_violation'],\n ['SQLITE_CONSTRAINT_CHECK', 'check_violation'],\n ['SQLITE_CONSTRAINT_TRIGGER', 'check_violation'],\n ['SQLITE_MISMATCH', 'invalid_input'],\n ['SQLITE_RANGE', 'invalid_input'],\n ['SQLITE_TOOBIG', 'invalid_input'],\n ['SQLITE_READONLY', 'insufficient_privilege'],\n ['SQLITE_AUTH', 'insufficient_privilege'],\n]);\n\n/** SQLite result codes that clear once contention or a lock resolves. */\nconst TRANSIENT_SQLITE_CODES = new Set([\n 'SQLITE_BUSY',\n 'SQLITE_BUSY_SNAPSHOT',\n 'SQLITE_BUSY_TIMEOUT',\n 'SQLITE_LOCKED',\n 'SQLITE_LOCKED_SHAREDCACHE',\n 'SQLITE_PROTOCOL',\n]);\n\n/** Node/libuv socket errno values raised when a pooled connection drops. */\nconst TRANSIENT_NETWORK_CODES = new Set([\n 'ECONNRESET',\n 'ECONNREFUSED',\n 'ECONNABORTED',\n 'EPIPE',\n 'ETIMEDOUT',\n 'ENETUNREACH',\n 'ENETRESET',\n 'EHOSTUNREACH',\n 'EAI_AGAIN',\n 'ENOTFOUND',\n]);\n\n/**\n * Dialect wording, in precedence order. Only DuckDB has no machine-readable\n * code, but SQLite's bare `SQLITE_CONSTRAINT` and PostgreSQL errors that have\n * lost their code through string formatting are recovered here too.\n *\n * NOT NULL is tested before UNIQUE because DuckDB phrases both with the same\n * `Constraint Error … violates` shape, and foreign-key/check wording must not\n * be mistaken for a unique violation (#1578).\n */\nconst DIALECT_MESSAGE_RULES: ReadonlyArray<{\n kind: DatabaseErrorKind;\n pattern: RegExp;\n}> = [\n {\n kind: 'aborted_transaction',\n pattern: /current transaction is aborted/i,\n },\n {\n kind: 'not_null_violation',\n pattern:\n /NOT NULL constraint failed|null value in column .* violates not-null/i,\n },\n {\n // SQLite reports `FOREIGN KEY constraint failed` under the bare\n // `SQLITE_CONSTRAINT` parent code, so without this arm the sub-kind\n // recovery below would mislabel every SQLite FK failure.\n kind: 'foreign_key_violation',\n pattern: /violates foreign key constraint|FOREIGN KEY constraint failed/i,\n },\n {\n kind: 'check_violation',\n pattern: /violates check constraint|CHECK constraint failed/i,\n },\n {\n kind: 'unique_violation',\n pattern:\n /UNIQUE constraint failed|violates unique constraint|violates primary key constraint|duplicate key value violates|PRIMARY KEY or UNIQUE constraint violation/i,\n },\n {\n kind: 'invalid_input',\n pattern: /invalid input syntax for type|value too long for type/i,\n },\n {\n // Deliberately narrow: a bare /does not exist/ matches far too much to be\n // safe as a fail-fast signal.\n kind: 'undefined_object',\n pattern:\n /no such table|no such column|(?:relation|column|table|function) \"[^\"]*\" does not exist/i,\n },\n {\n kind: 'transient',\n pattern:\n /database is locked|database table is locked|connection terminated|server closed the connection|too many clients|deadlock detected|could not serialize access/i,\n },\n];\n\n/** SMRT-level codes that already express a driver classification. */\nconst SMRT_CODE_KINDS = new Map<string, DatabaseErrorKind>([\n ['VALIDATION_UNIQUE_CONSTRAINT', 'unique_violation'],\n ['DB_CONSTRAINT_VIOLATION', 'check_violation'],\n]);\n\n/**\n * Reporting precedence among deterministic kinds, most specific first.\n *\n * `aborted_transaction` ranks last on purpose: PostgreSQL reports `25P02` for\n * every statement issued after the transaction already failed, so a chain\n * carrying both it and the constraint that caused the abort must name the\n * constraint. Every kind here is non-retryable, so ranking changes only what\n * is reported, never whether the operation is retried.\n */\nconst DETERMINISTIC_KIND_RANK = new Map<DatabaseErrorKind, number>([\n ['unique_violation', 0],\n ['not_null_violation', 1],\n ['foreign_key_violation', 2],\n ['check_violation', 3],\n ['exclusion_violation', 4],\n ['invalid_input', 5],\n ['undefined_object', 6],\n ['insufficient_privilege', 7],\n ['syntax_error', 8],\n ['aborted_transaction', 9],\n]);\n\nfunction rankKind(kind: DatabaseErrorKind): number {\n return DETERMINISTIC_KIND_RANK.get(kind) ?? Number.MAX_SAFE_INTEGER;\n}\n\ninterface ChainSignals {\n codes: string[];\n messages: string[];\n columns: string[];\n constraints: string[];\n}\n\nfunction pushUnique(collection: string[], value: unknown): void {\n if (typeof value !== 'string') return;\n const entry = value.trim();\n if (entry && !collection.includes(entry)) {\n collection.push(entry);\n }\n}\n\nfunction pushCode(signals: ChainSignals, value: unknown): void {\n pushUnique(signals.codes, value);\n}\n\nfunction pushMessage(signals: ChainSignals, value: unknown): void {\n if (typeof value !== 'string') return;\n const message = value.trim();\n if (!message || signals.messages.includes(message)) return;\n signals.messages.push(message);\n\n // `formatDbError` folds the driver's own `code` into its string, so the\n // machine-readable classification survives even after stringification.\n FORMATTED_CODE_PATTERN.lastIndex = 0;\n let match = FORMATTED_CODE_PATTERN.exec(message);\n while (match) {\n pushCode(signals, match[1]);\n match = FORMATTED_CODE_PATTERN.exec(message);\n }\n}\n\n/**\n * Walks an error's causal chain, collecting every driver code and message.\n *\n * Visits `cause`, `context.originalError`, `originalError`,\n * `details.causeMessage`/`details.causeMessages` and `AggregateError.errors`,\n * because the SDK, core and consumer wrappers each nest the driver error\n * differently. Cycles and depth are bounded.\n */\nfunction collectChainSignals(error: unknown): ChainSignals {\n const signals: ChainSignals = {\n codes: [],\n messages: [],\n columns: [],\n constraints: [],\n };\n const seen = new Set<unknown>();\n const pending: Array<{ value: unknown; depth: number }> = [\n { value: error, depth: 0 },\n ];\n\n while (pending.length > 0) {\n const entry = pending.pop();\n if (!entry) break;\n const { value, depth } = entry;\n if (value === null || value === undefined || depth > MAX_CHAIN_DEPTH) {\n continue;\n }\n\n if (typeof value === 'string') {\n pushMessage(signals, value);\n continue;\n }\n if (typeof value !== 'object' || seen.has(value)) continue;\n seen.add(value);\n\n const node = value as {\n code?: unknown;\n sqlState?: unknown;\n sqlstate?: unknown;\n message?: unknown;\n detail?: unknown;\n hint?: unknown;\n column?: unknown;\n constraint?: unknown;\n cause?: unknown;\n context?: { originalError?: unknown } | unknown;\n originalError?: unknown;\n details?: unknown;\n errors?: unknown;\n };\n\n pushCode(signals, node.code);\n pushCode(signals, node.sqlState);\n pushCode(signals, node.sqlstate);\n pushMessage(signals, node.message);\n // `node-postgres` surfaces the PostgreSQL error fields as properties. On\n // the direct INSERT path nothing stringifies them into the message, so the\n // column would otherwise be unrecoverable (`error.detail` carries\n // \"Key (sku)=(s1) already exists.\" for a 23505; `error.column` names the\n // column outright for a 23502).\n pushMessage(signals, node.detail);\n pushMessage(signals, node.hint);\n pushUnique(signals.columns, node.column);\n pushUnique(signals.constraints, node.constraint);\n\n const details = node.details as\n | { causeMessage?: unknown; causeMessages?: unknown }\n | undefined;\n if (details && typeof details === 'object') {\n pushMessage(signals, details.causeMessage);\n if (Array.isArray(details.causeMessages)) {\n for (const causeMessage of details.causeMessages) {\n pushMessage(signals, causeMessage);\n }\n }\n }\n\n const context = node.context as { originalError?: unknown } | undefined;\n const next = [\n node.cause,\n node.originalError,\n context && typeof context === 'object'\n ? context.originalError\n : undefined,\n ];\n for (const child of next) {\n if (child !== null && child !== undefined) {\n pending.push({ value: child, depth: depth + 1 });\n }\n }\n if (Array.isArray(node.errors)) {\n for (const child of node.errors) {\n pending.push({ value: child, depth: depth + 1 });\n }\n }\n }\n\n return signals;\n}\n\n/**\n * Classifies a raw dialect message. Exposed so\n * `SmrtObject.classifyConstraintError()` and this module share one set of\n * regexes rather than drifting apart.\n */\nexport function classifyDialectMessage(message: string): DatabaseErrorKind {\n if (!message) return 'unknown';\n for (const rule of DIALECT_MESSAGE_RULES) {\n if (rule.pattern.test(message)) return rule.kind;\n }\n return 'unknown';\n}\n\nfunction isSqlState(code: string): boolean {\n return /^[0-9A-Z]{5}$/.test(code);\n}\n\n/**\n * Classifies a database failure by walking its causal chain.\n *\n * Codes win over wording: a PostgreSQL SQLSTATE or SQLite result code is\n * authoritative, and dialect message matching only runs when no code in the\n * chain was recognized (DuckDB, or an error already flattened to a string).\n *\n * Constraint violations are reported ahead of `aborted_transaction` so a chain\n * carrying both surfaces the root cause rather than the downstream symptom;\n * both are deterministic, so retry behavior is identical either way.\n *\n * @param error - Any thrown value. Non-database errors classify as `'unknown'`.\n * @returns The structured classification; never throws.\n */\nexport function classifyDatabaseError(\n error: unknown,\n): DatabaseErrorClassification {\n const signals = collectChainSignals(error);\n const sqlstate = signals.codes.find(\n (code) =>\n isSqlState(code) &&\n (DETERMINISTIC_SQLSTATES.has(code) || TRANSIENT_SQLSTATES.has(code)),\n );\n\n const base = {\n driverCodes: signals.codes,\n driverMessages: signals.messages,\n ...(sqlstate ? { sqlstate } : {}),\n ...(signals.columns[0] ? { column: signals.columns[0] } : {}),\n ...(signals.constraints[0] ? { constraint: signals.constraints[0] } : {}),\n };\n\n // Deterministic codes first: a chain that carries both a constraint code and\n // a downstream contention code must fail fast, not retry.\n const deterministicCandidates: Array<{\n code: string;\n kind: DatabaseErrorKind;\n }> = [];\n for (const code of signals.codes) {\n const kind =\n DETERMINISTIC_SQLSTATES.get(code) ??\n DETERMINISTIC_SQLITE_CODES.get(code) ??\n // SMRT's own typed codes: a `ValidationError` already carrying\n // `VALIDATION_UNIQUE_CONSTRAINT` is the classified form of the same\n // driver failure.\n SMRT_CODE_KINDS.get(code) ??\n // A bare `SQLITE_CONSTRAINT` carries no sub-kind; recover it from the\n // message, which SQLite always phrases explicitly.\n (code === 'SQLITE_CONSTRAINT'\n ? (signals.messages\n .map(classifyDialectMessage)\n .find((candidate) => DETERMINISTIC_KIND_RANK.has(candidate)) ??\n 'check_violation')\n : undefined);\n if (kind) deterministicCandidates.push({ code, kind });\n }\n\n if (deterministicCandidates.length > 0) {\n // Rank rather than take the first discovered: an error whose chain holds\n // both `23505` and the `25P02` it caused must report the root constraint,\n // not the downstream symptom.\n const best = deterministicCandidates.reduce((winner, candidate) =>\n rankKind(candidate.kind) < rankKind(winner.kind) ? candidate : winner,\n );\n return {\n ...base,\n kind: best.kind,\n deterministic: true,\n retryable: false,\n driverCode: best.code,\n };\n }\n\n for (const code of signals.codes) {\n if (TRANSIENT_SQLSTATES.has(code) || TRANSIENT_SQLITE_CODES.has(code)) {\n return {\n ...base,\n kind: 'transient',\n deterministic: false,\n retryable: true,\n driverCode: code,\n };\n }\n if (TRANSIENT_NETWORK_CODES.has(code)) {\n return {\n ...base,\n kind: 'transient',\n deterministic: false,\n retryable: true,\n driverCode: code,\n };\n }\n }\n\n // No recognized code anywhere — fall back to dialect wording. This is the\n // only path DuckDB ever takes.\n const messageKinds = signals.messages\n .map(classifyDialectMessage)\n .filter((kind) => kind !== 'unknown');\n const deterministicFromMessage = messageKinds\n .filter((kind) => DETERMINISTIC_KIND_RANK.has(kind))\n .sort((left, right) => rankKind(left) - rankKind(right))[0];\n if (deterministicFromMessage) {\n return {\n ...base,\n kind: deterministicFromMessage,\n deterministic: true,\n retryable: false,\n };\n }\n if (messageKinds.includes('transient')) {\n return {\n ...base,\n kind: 'transient',\n deterministic: false,\n retryable: true,\n };\n }\n\n return {\n ...base,\n kind: 'unknown',\n deterministic: false,\n retryable: false,\n };\n}\n\n/**\n * True when retrying the statement cannot change the outcome.\n *\n * Used by {@link ErrorUtils.withRetry} to fail fast instead of burning the\n * full 500 + 1000 + 2000 ms backoff on a constraint violation.\n */\nexport function isDeterministicDatabaseError(error: unknown): boolean {\n return classifyDatabaseError(error).deterministic;\n}\n\n/** True when the failure is contention or availability and may clear. */\nexport function isTransientDatabaseError(error: unknown): boolean {\n return classifyDatabaseError(error).retryable;\n}\n\n/**\n * Codes that mean the connection itself failed or the server would not take\n * it yet: SQLSTATE class `08`, server shutdown/startup `57P01`–`57P03`,\n * `53300 too_many_connections`, and the socket codes a server that is still\n * starting or settling produces. Deliberately narrower than\n * `TRANSIENT_NETWORK_CODES`: an unresolvable or unreachable host\n * (`ENOTFOUND`, `EHOSTUNREACH`, `ENETUNREACH`) is a configuration error and\n * must fail at once (#3657).\n */\nconst CONNECTION_SQLSTATES = new Set(['53300', '57P01', '57P02', '57P03']);\nconst CONNECTION_SOCKET_CODES = new Set([\n 'ECONNREFUSED',\n 'ECONNRESET',\n 'ETIMEDOUT',\n 'EAI_AGAIN',\n]);\nconst CONNECTION_MESSAGE =\n /connection terminated|server closed the connection|too many clients|the database system is (?:starting up|shutting down|in recovery mode)/i;\n\n/**\n * True when the failure is a transient *connection* failure: the database\n * dropped, refused or could not yet accept the connection (#3657). Narrower\n * than {@link isTransientDatabaseError}, which also covers contention\n * (deadlocks, serialization, locks). Used to retry startup bootstrap only.\n */\nexport function isTransientConnectionError(error: unknown): boolean {\n const classification = classifyDatabaseError(error);\n if (classification.deterministic) return false;\n return (\n classification.driverCodes.some(\n (code) =>\n CONNECTION_SQLSTATES.has(code) ||\n CONNECTION_SOCKET_CODES.has(code) ||\n /^08[0-9A-Z]{3}$/.test(code),\n ) ||\n classification.driverMessages.some((message) =>\n CONNECTION_MESSAGE.test(message),\n )\n );\n}\n\n/** True when a unique or primary-key constraint was violated. */\nexport function isUniqueViolationError(error: unknown): boolean {\n return classifyDatabaseError(error).kind === 'unique_violation';\n}\n\n/** True when a NOT NULL constraint was violated. */\nexport function isNotNullViolationError(error: unknown): boolean {\n return classifyDatabaseError(error).kind === 'not_null_violation';\n}\n\n/**\n * True when the failure came from running inside an already-aborted\n * PostgreSQL transaction (SQLSTATE `25P02`).\n *\n * Detected independently of {@link DatabaseErrorKind} so a chain that also\n * carries the root constraint code still answers `true` here.\n */\nexport function isAbortedTransactionError(error: unknown): boolean {\n const signals = collectChainSignals(error);\n // `25P02` only. `25P03` is a terminated session, not a failed transaction,\n // and reporting it here would make the profiles coordinator treat an\n // idle-timeout disconnect as a provisioning race conflict.\n if (signals.codes.includes('25P02')) {\n return true;\n }\n return signals.messages.some((message) =>\n /current transaction is aborted/i.test(message),\n );\n}\n"],"mappings":"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"}
|