export const QUERY_KEY_SCHEMA_VERSION = 2 as const; export const QUERY_NAMESPACE_ID_MAX_BYTES = 80 as const; export type QueryNamespaceIdentity = Readonly<{ namespaceId: string; namespaceVersion: number; }>; function hasControlCharacter(value: string): boolean { for (const character of value) { const codePoint = character.codePointAt(0) ?? 0; if ( codePoint <= 0x1f || (codePoint >= 0x7f && codePoint <= 0x9f) ) { return true; } } return false; } function assertQueryNamespaceIdentity( namespace: QueryNamespaceIdentity, ): void { if ( !namespace || typeof namespace !== "object" || typeof namespace.namespaceId !== "string" || namespace.namespaceId.length === 0 || hasControlCharacter(namespace.namespaceId) || new TextEncoder().encode(namespace.namespaceId).byteLength > QUERY_NAMESPACE_ID_MAX_BYTES || !Number.isSafeInteger(namespace.namespaceVersion) || namespace.namespaceVersion < 1 ) { throw new TypeError("Query namespace identity is invalid."); } } export function defineQueryNamespaceIdentity( namespaceId: string, namespaceVersion: number, ): QueryNamespaceIdentity { const namespace = { namespaceId, namespaceVersion }; assertQueryNamespaceIdentity(namespace); return Object.freeze(namespace); } export function queryNamespaceIdentityKey( namespace: QueryNamespaceIdentity, ): string { assertQueryNamespaceIdentity(namespace); return JSON.stringify([namespace.namespaceId, namespace.namespaceVersion]); } export function createQueryInvalidationPrefix( namespace: QueryNamespaceIdentity, ) { assertQueryNamespaceIdentity(namespace); return Object.freeze([ "query", QUERY_KEY_SCHEMA_VERSION, namespace.namespaceId, namespace.namespaceVersion, ] as const); } export function createBoundQueryKey( namespace: QueryNamespaceIdentity, scopeFingerprint: string, definitionVersion: number, identityToken: string, ) { if (!Number.isSafeInteger(definitionVersion) || definitionVersion < 1) { throw new TypeError("Query definition version is invalid."); } return Object.freeze([ ...createQueryInvalidationPrefix(namespace), scopeFingerprint, definitionVersion, identityToken, ] as const); } export type CanonicalValue = | null | boolean | number | string | readonly CanonicalValue[] | Readonly<{ [key: string]: CanonicalValue }>; const DEFAULT_LIMITS = Object.freeze({ maxDepth: 12, maxNodes: 512, maxStringBytes: 2_048, maxEncodedBytes: 16_384, }); export function canonicalize(value: unknown): CanonicalValue { const seen = new WeakSet(); let nodes = 0; const encoder = new TextEncoder(); function visit(candidate: unknown, depth: number): CanonicalValue { nodes += 1; if (nodes > DEFAULT_LIMITS.maxNodes || depth > DEFAULT_LIMITS.maxDepth) { throw new TypeError("Query identity exceeds its structural budget."); } if ( candidate === null || typeof candidate === "boolean" || (typeof candidate === "number" && Number.isFinite(candidate) && !Object.is(candidate, -0)) ) { return candidate; } if (typeof candidate === "string") { if (encoder.encode(candidate).byteLength > DEFAULT_LIMITS.maxStringBytes) { throw new TypeError("Query identity string exceeds its byte budget."); } return candidate; } if (!candidate || typeof candidate !== "object") { throw new TypeError("Query identity contains a non-canonical value."); } if (seen.has(candidate)) { throw new TypeError("Query identity contains a cycle or shared reference."); } seen.add(candidate); if (Array.isArray(candidate)) { for (let index = 0; index < candidate.length; index += 1) { if (!Object.hasOwn(candidate, index)) { throw new TypeError("Query identity contains a sparse array."); } } return Object.freeze(candidate.map((item) => visit(item, depth + 1))); } const prototype = Object.getPrototypeOf(candidate); if (prototype !== Object.prototype && prototype !== null) { throw new TypeError("Query identity requires plain objects."); } const descriptors = Object.getOwnPropertyDescriptors(candidate); const output: Record = Object.create(null); for (const key of Object.keys(descriptors).sort()) { if (key === "__proto__" || key === "prototype" || key === "constructor") { throw new TypeError("Query identity contains a forbidden key."); } const descriptor = descriptors[key]; if (!descriptor || !("value" in descriptor)) { throw new TypeError("Query identity contains an accessor."); } output[key] = visit(descriptor.value, depth + 1); } return Object.freeze(output); } const result = visit(value, 0); if (encoder.encode(JSON.stringify(result)).byteLength > DEFAULT_LIMITS.maxEncodedBytes) { throw new TypeError("Query identity exceeds its encoded byte budget."); } return result; } export type RuntimeIdentityBinding = Readonly<{ token: string; acquire(): void; release(): void; }>; export type RuntimeIdentityRegistry = Readonly<{ intern(value: unknown): RuntimeIdentityBinding; close(): void; inspect(): Readonly<{ entries: number; canonicalBytes: number; activeLeases: number; closed: boolean; }>; }>; type IdentityRow = { canonical: string; canonicalBytes: number; token: string; refCount: number; touched: number; }; export function createRuntimeIdentityRegistry( options: Readonly<{ maxEntries?: number; maxCanonicalBytes?: number; tokenFactory?: () => string; }> = {}, ): RuntimeIdentityRegistry { const maxEntries = options.maxEntries ?? 4_096; const maxCanonicalBytes = options.maxCanonicalBytes ?? 4 * 1024 * 1024; const tokenFactory = options.tokenFactory ?? (() => { if ( typeof crypto === "undefined" || typeof crypto.randomUUID !== "function" ) { throw new TypeError("Secure runtime identity generation is unavailable."); } return crypto.randomUUID(); }); const byCanonical = new Map(); const byToken = new Map(); let totalCanonicalBytes = 0; let sequence = 0; let closed = false; function evictAvailable(requiredBytes: number): void { const candidates = [...byCanonical.values()] .filter((row) => row.refCount === 0) .sort((left, right) => left.touched - right.touched); for (const row of candidates) { if ( byCanonical.size < maxEntries && totalCanonicalBytes + requiredBytes <= maxCanonicalBytes ) { return; } byCanonical.delete(row.canonical); byToken.delete(row.token); totalCanonicalBytes -= row.canonicalBytes; } } return Object.freeze({ intern(value): RuntimeIdentityBinding { if (closed) throw new TypeError("Runtime identity registry is closed."); const canonical = JSON.stringify(canonicalize(value)); const canonicalBytes = new TextEncoder().encode(canonical).byteLength; let row = byCanonical.get(canonical); if (!row) { evictAvailable(canonicalBytes); if ( byCanonical.size >= maxEntries || totalCanonicalBytes + canonicalBytes > maxCanonicalBytes ) { throw new TypeError("Runtime identity capacity exceeded."); } let token = ""; for (let attempt = 0; attempt < 8; attempt += 1) { const candidate = tokenFactory(); if ( /^[A-Za-z0-9._:-]{16,128}$/.test(candidate) && !byToken.has(candidate) ) { token = candidate; break; } } if (!token) { throw new TypeError("Runtime identity token collision."); } row = { canonical, canonicalBytes, token, refCount: 0, touched: sequence++, }; byCanonical.set(canonical, row); byToken.set(token, row); totalCanonicalBytes += canonicalBytes; } row.touched = sequence++; let leaseCount = 0; return Object.freeze({ token: row.token, acquire() { if (closed) return; leaseCount += 1; row.refCount += 1; row.touched = sequence++; }, release() { if (leaseCount === 0) return; leaseCount -= 1; row.refCount = Math.max(0, row.refCount - 1); row.touched = sequence++; }, }); }, close() { closed = true; byCanonical.clear(); byToken.clear(); totalCanonicalBytes = 0; }, inspect() { return Object.freeze({ entries: byCanonical.size, canonicalBytes: totalCanonicalBytes, activeLeases: [...byCanonical.values()].reduce( (total, row) => total + row.refCount, 0, ), closed, }); }, }); } const defaultIdentityRegistry = createRuntimeIdentityRegistry(); export function runtimeIdentityToken(value: unknown): string { return defaultIdentityRegistry.intern(value).token; }