@haverstack/record-adapter-sqlite 0.34.0 → 0.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +13 -7
- package/dist/index.js +543 -427
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/node-sqlite.ts","../../sqlite-shared/src/schema.ts","../../sqlite-shared/src/fts5.ts","../../sqlite-shared/src/executor.ts","../../sqlite-shared/src/config.ts","../../sqlite-shared/src/cursor.ts","../../sqlite-shared/src/query.ts","../../sqlite-shared/src/indexes.ts","../../sqlite-shared/src/mappers.ts","../../sqlite-shared/src/record-logic.ts","../../sqlite-shared/src/record-adapter.ts","../../sqlite-shared/src/lock.ts","../../sqlite-shared/src/token-logic.ts","../src/executor.ts","../src/token-store.ts","../src/index.ts"],"names":["kind","entry","StackBadRequestError","cursor","constantSortEntry","contentSortEntry","page","statement","existsSync"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Loads node:sqlite via process.getBuiltinModule() rather than a static\n * `import ... from 'node:sqlite'`. node:sqlite is new enough that some\n * bundler/test-runner toolchains (Vite/Vitest as of this writing —\n * https://github.com/vitest-dev/vitest/issues/7177) mis-resolve it,\n * stripping the \"node:\" prefix and trying to load a package literally\n * named \"sqlite\". process.getBuiltinModule() is the Node-sanctioned way\n * to reach a builtin module without going through import resolution at\n * all, so it's immune to that class of bug — useful here since a\n * consuming app's own toolchain could hit the same issue, not just ours.\n */\nexport const { DatabaseSync } = process.getBuiltinModule(\n 'node:sqlite',\n) as typeof import('node:sqlite');\n\nexport type DatabaseSync = InstanceType<typeof DatabaseSync>;\n","import type { SqlExecutor } from './executor.js';\n\n/**\n * Schema DDL shared by SQLite-backed record adapters. TOKENS_SCHEMA_SQL\n * is split out from RECORD_SCHEMA_SQL because token storage lives in its\n * own file, never bundled with records — see NativeTokenStore in\n * record-adapter-sqlite and the StackTokenStore portability rationale\n * (docs/spec/wire-format.md § Authentication).\n */\n\nexport const RECORD_SCHEMA_SQL = `\n CREATE TABLE IF NOT EXISTS records (\n id TEXT PRIMARY KEY,\n type_id TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n content TEXT NOT NULL CHECK (json_valid(content)),\n version INTEGER NOT NULL DEFAULT 1,\n parent_id TEXT,\n entity_id TEXT,\n app_id TEXT,\n principal_id TEXT,\n updated_by TEXT,\n updated_via TEXT,\n deleted_at INTEGER,\n unlisted_at INTEGER\n ) STRICT;\n\n -- Every edge a record carries, authority and data alike: a permission\n -- has element identity and a delta shaped like a tag's, so it earns the\n -- same table. The permissions and associations fields are projections\n -- over it, partitioned by kind.\n -- See docs/spec/access-control.md § Record-level permissions.\n CREATE TABLE IF NOT EXISTS associations (\n record_id TEXT NOT NULL REFERENCES records(id),\n kind TEXT NOT NULL CHECK (kind IN ('tag', 'attachment', 'relationship', 'permission', 'anyone')),\n label TEXT NOT NULL,\n file_id TEXT NOT NULL DEFAULT '',\n -- A relationship target is (related_scope, related_id) qualified by\n -- related_ns (a foreign namespace) or related_stack (another stack); a\n -- permission's grantee reuses scope and id. All are in the key, so\n -- targets differing only by a qualifier are distinct associations.\n related_scope TEXT NOT NULL DEFAULT '' CHECK (related_scope IN ('', 'record', 'entity', 'external', 'group')),\n related_id TEXT NOT NULL DEFAULT '',\n related_ns TEXT NOT NULL DEFAULT '',\n related_stack TEXT NOT NULL DEFAULT '',\n -- Set only by a group grantee; in the key because member and admin name\n -- two different sets of people.\n related_role TEXT NOT NULL DEFAULT '' CHECK (related_role IN ('', 'member', 'admin')),\n -- Out of the key: it annotates a reference rather than naming one, so\n -- re-pointing it updates the existing row. See docs/spec/attachments.md\n -- § Naming the upload a reference came from.\n attachment_record_id TEXT NOT NULL DEFAULT '',\n -- Leads with record_id, so its implicit index serves every by-record\n -- read and delete; the indexes below cover only the filter directions.\n PRIMARY KEY (record_id, kind, label, file_id, related_scope, related_id, related_ns, related_stack, related_role)\n ) STRICT;\n\n -- Content and the type it is read under. No parent_id, unlisted_at or\n -- associations column: none of those aspects bumps version, so no\n -- version ever snapshots one. See\n -- docs/spec/versioning.md § Version history.\n CREATE TABLE IF NOT EXISTS versions (\n record_id TEXT NOT NULL REFERENCES records(id),\n version INTEGER NOT NULL,\n type_id TEXT NOT NULL,\n content TEXT NOT NULL CHECK (json_valid(content)),\n updated_at INTEGER NOT NULL,\n entity_id TEXT,\n principal_id TEXT,\n updated_by TEXT,\n updated_via TEXT,\n PRIMARY KEY (record_id, version)\n ) STRICT;\n\n -- The durable half of a change event: which aspects moved, who moved\n -- them, and the association deltas nothing else retains. Envelope-level\n -- by design — content lives on a versions row, and copying it here\n -- would make the journal the larger of the two stores.\n -- See docs/spec/journal.md.\n CREATE TABLE IF NOT EXISTS journal (\n record_id TEXT NOT NULL REFERENCES records(id),\n seq INTEGER NOT NULL,\n at INTEGER NOT NULL,\n -- No 'purged': a purge destroys the log rather than appending to it,\n -- so the constraint names exactly the kinds an entry can carry.\n -- See docs/spec/journal.md § A purge destroys the journal.\n kind TEXT NOT NULL CHECK (kind IN ('created', 'changed', 'removed')),\n ops TEXT NOT NULL CHECK (json_valid(ops)),\n version INTEGER NOT NULL,\n type_id TEXT NOT NULL,\n parent_id TEXT,\n -- NULL means the entry names no origin (the record did not move);\n -- '' means it moved off the root. parent_id above needs no such\n -- spelling: it is state, where this is a key that may be absent --\n -- the same input/state split parentId follows everywhere.\n previous_parent_id TEXT,\n actor TEXT CHECK (actor IS NULL OR json_valid(actor)),\n -- One tagged edit per association the write moved, each carrying the\n -- state it displaced. See docs/spec/journal.md § The entry.\n associations TEXT CHECK (associations IS NULL OR json_valid(associations)),\n PRIMARY KEY (record_id, seq)\n ) STRICT;\n\n CREATE TABLE IF NOT EXISTS types (\n id TEXT PRIMARY KEY,\n base_id TEXT NOT NULL,\n version INTEGER NOT NULL,\n name TEXT NOT NULL,\n schema TEXT NOT NULL CHECK (json_valid(schema)),\n schema_hash TEXT NOT NULL,\n migrates_from TEXT,\n created_at INTEGER NOT NULL\n ) STRICT;\n\n -- One row per top-level scalar content field a record holds a value at:\n -- what it orders as, and the file it references. See\n -- docs/spec/data-model.md § Sorting by a content field.\n --\n -- value_rank is 0 for a numeric value and 1 for a text one — the same\n -- split as \"num_value IS NULL\", but non-null, so one index can carry\n -- the whole ordering. file_id is set only for a 'file-ref' field.\n CREATE TABLE IF NOT EXISTS content_index (\n record_id TEXT NOT NULL REFERENCES records(id),\n field TEXT NOT NULL,\n value_rank INTEGER NOT NULL CHECK (value_rank IN (0, 1)),\n num_value REAL,\n text_key TEXT,\n text_value TEXT,\n file_id TEXT,\n PRIMARY KEY (record_id, field)\n ) STRICT;\n\n -- Each filter column continues into (created_at, id), the default order\n -- and its tiebreak: these columns are low-cardinality, and a narrow index\n -- leaves the planner sorting every match before it can honor LIMIT.\n -- deleted_at and unlisted_at get none: an index on a column every query\n -- tests IS NULL only lures the planner off the one answering ORDER BY.\n CREATE INDEX IF NOT EXISTS idx_records_type_id ON records(type_id, created_at, id);\n CREATE INDEX IF NOT EXISTS idx_records_parent_id ON records(parent_id, created_at, id);\n CREATE INDEX IF NOT EXISTS idx_records_entity_id ON records(entity_id, created_at, id);\n CREATE INDEX IF NOT EXISTS idx_records_app_id ON records(app_id, created_at, id);\n CREATE INDEX IF NOT EXISTS idx_records_principal_id ON records(principal_id, created_at, id);\n CREATE INDEX IF NOT EXISTS idx_records_created_at ON records(created_at, id);\n CREATE INDEX IF NOT EXISTS idx_records_updated_at ON records(updated_at, id);\n CREATE INDEX IF NOT EXISTS idx_records_version ON records(version, id);\n\n -- Each association index ends with record_id so the semi-joins in\n -- query.ts read the matching record ids out of the index alone.\n -- idx_assoc_related carries related_ns ahead of related_id because a\n -- record- or entity-scoped target always stores '' there, which\n -- buildQueryPlan states explicitly to keep the prefix contiguous.\n CREATE INDEX IF NOT EXISTS idx_assoc_kind_label ON associations(kind, label, record_id);\n CREATE INDEX IF NOT EXISTS idx_assoc_kind_file_id ON associations(kind, file_id, record_id);\n CREATE INDEX IF NOT EXISTS idx_assoc_related ON associations(kind, related_scope, related_ns, related_id, record_id);\n CREATE INDEX IF NOT EXISTS idx_types_base_id ON types(base_id, version);\n\n -- The whole content ordering, in index order, for one field at a time:\n -- a content-sorted page is an ordered walk of a slice of this index.\n CREATE INDEX IF NOT EXISTS idx_content_index_sort\n ON content_index(field, value_rank, num_value, text_key, text_value, record_id);\n CREATE INDEX IF NOT EXISTS idx_content_index_file\n ON content_index(file_id, record_id) WHERE file_id IS NOT NULL;\n`;\n\n/**\n * Bearer-token storage backing StackTokenStore. Kept separate from\n * RECORD_SCHEMA_SQL so an adapter can put it in its own file — the\n * portable stack file shouldn't also carry a server's auth material.\n */\nexport const TOKENS_SCHEMA_SQL = `\n CREATE TABLE IF NOT EXISTS tokens (\n id TEXT PRIMARY KEY,\n token_hash TEXT NOT NULL UNIQUE,\n principal_id TEXT NOT NULL,\n subject_id TEXT NOT NULL,\n label TEXT,\n created_at INTEGER NOT NULL,\n expires_at INTEGER\n ) STRICT;\n`;\n\n/**\n * The full-text index behind `StackQuery.filter.search` (see indexes.ts).\n * What `columnsize=0` costs a reader is in docs/spec/adapters.md\n * § SQLite-backed adapters. `detail` stays at its default: sanitizeFts5Query\n * passes phrase queries through, and a phrase needs the token positions\n * only that setting records.\n */\nexport const FTS5_SCHEMA_SQL = `\n CREATE VIRTUAL TABLE IF NOT EXISTS records_fts USING fts5(\n content,\n content='records',\n content_rowid='rowid',\n columnsize=0\n );\n`;\n\n/**\n * Enforces the REFERENCES constraints declared above (off by default per\n * SQLite connection), so touching a nonexistent record fails loudly\n * instead of creating an orphan row. Adapters map the constraint\n * violation to StackNotFoundError at the call sites that can trigger it.\n */\nexport const PRAGMA_FOREIGN_KEYS_ON = `PRAGMA foreign_keys = ON;`;\n\n/**\n * WAL journaling: page-level writes, crash-safe without our own\n * temp-file-and-rename dance, and real SQLite file locking. Only\n * meaningful for a real file (a :memory: database silently ignores it).\n */\nexport const PRAGMA_JOURNAL_MODE_WAL = `PRAGMA journal_mode = WAL;`;\n\nexport type RecordSchemaOptions = {\n /**\n * Whether to put the connection in WAL mode. False for an engine that\n * owns its own durability and rejects the pragma outright, as Durable\n * Object storage does.\n */\n wal: boolean;\n};\n\n/**\n * Brings a records database up to the schema every SQLite record adapter\n * expects: foreign keys on, then the tables and the FTS5 index. Every\n * statement is idempotent, so an engine that cannot tell\n * whether a store exists can run this on each attach.\n */\nexport const applyRecordSchema = (exec: SqlExecutor, opts: RecordSchemaOptions): void => {\n exec.exec(PRAGMA_FOREIGN_KEYS_ON);\n if (opts.wal) exec.exec(PRAGMA_JOURNAL_MODE_WAL);\n exec.exec(RECORD_SCHEMA_SQL);\n exec.exec(FTS5_SCHEMA_SQL);\n};\n","/**\n * FTS5 query sanitization: turning what a person typed into a search box\n * into a query FTS5 will parse. Indexing lives in indexes.ts.\n *\n * FTS5's query language supports operators (AND/OR/NOT, phrases, NEAR,\n * wildcards) that can be expensive or cause parse errors with untrusted\n * input, so a search string is rewritten before it reaches the engine:\n *\n * kept: AND/OR/NOT (with a left operand), phrase queries (\"…\"), implicit AND\n * removed: wildcards (*), NEAR(...) (terms kept, wrapper dropped), every\n * character outside the allow-list, bare NOT (no left operand),\n * operators with no right operand\n * capped: parenthesis nesting depth (default: 2)\n * closed: an odd trailing quote\n *\n * Two FTS5 grammar details drive the less obvious rules:\n *\n * - FTS5's NEAR is a function-call form — `NEAR(a b, 10)`. Deleting the\n * whole span would also delete the terms inside it, which can leave a\n * dangling operator when NEAR(...) sits next to AND/OR (e.g. \"x AND\n * NEAR(a b, 5)\" -> \"x AND\" — a syntax error). So this keeps the terms\n * and drops only the NEAR(...) wrapper and distance.\n * - FTS5 has real column-filter syntax and errors hard on any name but\n * the table's actual columns. It is wider than `colname:term`: `-name`\n * and `{a b}` filter columns with no colon at all, so an ordinary\n * hyphenated word is read as one. Since records_fts has exactly one\n * column and callers have no business targeting columns explicitly,\n * everything outside a phrase is reduced to an allow-list rather than\n * validated — see OUTSIDE_PHRASE_DISALLOWED.\n *\n * The rewrite is best-effort and makes no completeness claim against\n * FTS5's grammar — which is why the caller wraps execution as well, so a\n * case this misses surfaces as a StackBadRequestError rather than a raw engine\n * error. Search text is what a person typed into a box: an unbalanced\n * quote or a trailing \"AND\" is ordinary input, not a malformed request.\n *\n * What this bounds is the grammar, not the cost: a syntactically modest\n * search over a large index can still be expensive, and node:sqlite blocks\n * the calling thread, so there is no timeout to set from inside the call.\n * Bounding execution time belongs to whoever drives the engine under load\n * — see docs/spec/wire-format.md § Bounding query cost for the server-side\n * expectation and the `timeout` wire error that goes with it.\n *\n * Backtracking. The input is untrusted text, so every regex here is\n * written not to backtrack quadratically on it:\n *\n * - Whitespace runs are collapsed before any rule that spells \"beside an\n * operator or paren\" as `\\s*`; a `\\s*` facing a long run re-tries the\n * whole run per starting position. The rewrite is still a little\n * worse than linear overall, so bounding a search's length belongs to\n * whoever accepts it.\n * - The NEAR rule has no `\\s*` after its paren (its `[^,()]*` already\n * takes a space, and two quantifiers matching the same character give\n * the engine an ambiguous split), and neither of its runs crosses a\n * `(`, so an unclosed `NEAR(NEAR(NEAR(` doesn't re-scan to the end once\n * per occurrence.\n * - The no-right-operand rule has no leading `\\s*`, for the same reason\n * as the collapse.\n * - The operand-before-paren rule's lookbehind pins each match to the\n * start of a word; without it every position inside a long word is a\n * start, each re-scanning the rest of it.\n * - Empty phrases and empty paren pairs are removed by one rule, so a run\n * of them becomes one space rather than one per construct.\n */\n\n/**\n * Outside a phrase, everything but a letter, digit, mark, underscore,\n * whitespace, paren or quote becomes a separator. An allow-list because\n * FTS5's column-filter syntax is wider than any list of metacharacters.\n * See docs/spec/data-model.md § Capability-gated filters.\n */\nconst OUTSIDE_PHRASE_DISALLOWED = /[^\\p{L}\\p{N}\\p{M}_\\s()\"]/gu;\n\n/**\n * Bounds what any `\\s*` can backtrack over (see Backtracking above). Safe\n * inside a phrase too: FTS5 matches a phrase as a sequence of tokens, not\n * the spacing between them.\n */\nconst collapseWhitespace = (query: string): string => query.replace(/\\s+/g, ' ');\n\nexport const sanitizeFts5Query = (query: string, maxDepth = 2): string => {\n if (!query) return '';\n\n // Drop control characters, inside a phrase as well as outside. A NUL in\n // particular ends the string early for SQLite's C API, so the engine sees\n // an opening quote whose closing one is past the truncation and reports an\n // unterminated string; none of them can match an indexed token anyway.\n let clean = query.replace(/[\\p{Cc}\\p{Cf}]/gu, ' ');\n\n clean = clean.replace(/\\*/g, '');\n\n // NEAR(terms, distance) keeps its terms — see the note above. The\n // pattern's shape is about backtracking (see Backtracking); excluding `(`\n // costs nothing, since a NEAR's terms and distance never hold one.\n clean = clean.replace(/\\bNEAR\\s*\\(([^,()]*)(?:,[^()]*)?\\)/gi, '$1');\n\n // A NEAR( with no closing paren isn't the function-call form the rule\n // above rewrites, and the paren auto-close below would hand FTS5 a NEAR\n // call it never meant to write. Keep the grouping, drop the keyword.\n clean = clean.replace(/\\bNEAR\\s*\\(/gi, '(');\n\n // See OUTSIDE_PHRASE_DISALLOWED.\n clean = clean.replace(/\"[^\"]*\"|[^\"]+/g, (span) =>\n span.startsWith('\"') ? span : span.replace(OUTSIDE_PHRASE_DISALLOWED, ' '),\n );\n\n // The reduction above is where long whitespace runs come from.\n clean = collapseWhitespace(clean);\n\n // Strip bare NOT with no left operand — FTS5 requires \"term NOT term\", not\n // \"NOT term\". A phrase is matched first and kept whole, so a NOT inside one\n // stays the word it is; the closing quote is optional because an odd one\n // is only closed further down.\n clean = clean.replace(/\"[^\"]*\"?|(^|\\(\\s*)NOT\\s+/gi, (m, lead?: string) => lead ?? m);\n\n // Enforce max nesting depth; replace excess ( with a space and discard\n // unmatched ). Parens inside a phrase are literal text to FTS5, so the\n // depth count steps over quoted spans rather than reading them as syntax.\n let currentDepth = 0;\n let inPhrase = false;\n let result = '';\n for (const char of clean) {\n if (char === '\"') {\n inPhrase = !inPhrase;\n result += char;\n } else if (inPhrase) {\n result += char;\n } else if (char === '(') {\n if (currentDepth < maxDepth) {\n currentDepth++;\n result += char;\n } else result += ' ';\n } else if (char === ')') {\n if (currentDepth > 0) {\n currentDepth--;\n result += char;\n } else result += ' ';\n } else {\n result += char;\n }\n }\n\n // Close an odd trailing quote before the parens, so the added ) lands\n // outside the phrase rather than becoming a literal character in it.\n if (inPhrase) result += '\"';\n\n if (currentDepth > 0) result += ')'.repeat(currentDepth);\n\n // Looped to a fixpoint because each rule can create work for another:\n // dropping an operator can empty a pair (\"(a AND)\"), dropping a pair can\n // strand an operator (\"x AND ()\"), and an empty phrase's quotes can\n // re-pair once text is inserted beside it.\n let prev: string;\n do {\n prev = result;\n // Empty phrases and empty paren pairs match nothing. One rule for both\n // (see Backtracking).\n result = result.replace(/(?:\"\"|\\(\\s*\\))+/g, ' ');\n result = dropDanglingOperators(result);\n result = restoreImplicitAnd(result);\n } while (result !== prev);\n\n return collapseWhitespace(result).replace(/\\(\\s+/g, '(').replace(/\\s+\\)/g, ')').trim();\n};\n\n/** An operator FTS5 requires a term on both sides of. */\nconst OPERATOR = String.raw`(?:AND|OR|NOT)`;\n\n/**\n * Stands in for a phrase while operators are rewritten. A private-use\n * character is not a word character, so `\\b` still sees an operator beside\n * it, while the anchors see an operand. A literal U+E000 in the input is\n * one FTS5 tokenizes away regardless.\n */\nconst PHRASE_HOLE = '\\u{E000}';\n\n/**\n * Drop operators left without an operand — typed on the way to a longer\n * query (\"cats AND\"), or left behind once a rule above removed a term.\n * FTS5 rejects each outright. Phrases are masked: inside one, an operator\n * is a word the user searched for.\n */\nconst dropDanglingOperators = (query: string): string =>\n withPhrasesMasked(query, (masked) => {\n let out = masked;\n let prev: string;\n do {\n prev = out;\n // A run of operators keeps only the first — the rest have no left operand.\n out = out.replace(\n new RegExp(String.raw`\\b(${OPERATOR})\\b(?:\\s+\\b${OPERATOR}\\b)+`, 'gi'),\n '$1',\n );\n // No left operand: at the start of the query or straight after \"(\".\n out = out.replace(new RegExp(String.raw`(^|\\()\\s*\\b${OPERATOR}\\b\\s*`, 'gi'), '$1');\n // No right operand: at the end of the query or straight before \")\".\n // No leading `\\s*` (see Backtracking); the collapse on the way out\n // takes that whitespace.\n out = out.replace(new RegExp(String.raw`\\b${OPERATOR}\\b\\s*($|\\))`, 'gi'), '$1');\n } while (out !== prev);\n return out;\n });\n\n/**\n * Run `rewrite` over the query with each phrase swapped for PHRASE_HOLE,\n * then put the phrases back in order. Every rule that reasons about what\n * sits beside an operator or a paren needs this: inside a phrase the text\n * is literal, and from outside one the phrase is a single operand.\n */\nconst withPhrasesMasked = (query: string, rewrite: (masked: string) => string): string => {\n const phrases: string[] = [];\n const masked = query.replace(/\"[^\"]*\"/g, (phrase) => {\n phrases.push(phrase);\n return PHRASE_HOLE;\n });\n let i = 0;\n return rewrite(masked).replace(new RegExp(PHRASE_HOLE, 'g'), () => phrases[i++]);\n};\n\nconst OPERAND_CHAR = String.raw`[\\p{L}\\p{N}_${PHRASE_HOLE}]`;\n\n/** A whole word, never a prefix: the `D` of `AND` is not a term. */\nconst isOperator = (word: string): boolean => /^(?:AND|OR|NOT)$/i.test(word);\n\n/**\n * Put back the operator FTS5 requires beside a group: `cats dogs` is an\n * implicit AND, but `cats (dogs)` is a syntax error. A rewrite that strips\n * the operator beside a group keeps the grouping, so this writes back the\n * AND that was meant. A masked phrase is an operand like any other.\n */\nconst restoreImplicitAnd = (query: string): string =>\n withPhrasesMasked(query, (masked) =>\n masked\n // \")\" then an operand — \") cats\", \") (\", \") <phrase>\" — unless that\n // operand is an operator, which already joins the two sides.\n .replace(\n new RegExp(String.raw`\\)\\s*(?=${OPERAND_CHAR}|\\()`, 'gu'),\n (match, offset: number, whole: string) => {\n const next = /^\\s*([\\p{L}\\p{N}_]+)/u.exec(whole.slice(offset + match.length));\n return next && isOperator(next[1]) ? match : ') AND ';\n },\n )\n // An operand then \"(\", unless the operand is an operator. The\n // lookbehind is load-bearing (see Backtracking).\n .replace(\n new RegExp(String.raw`(?<!${OPERAND_CHAR})(${OPERAND_CHAR}+)\\s*(?=\\()`, 'gu'),\n (match, word: string) => (isOperator(word) ? match : `${word} AND `),\n ),\n );\n","/**\n * Normalizes a SQLite binding's call convention (array-bind-then-step,\n * spread-args run/get/all, cursor-returning exec) behind one interface,\n * so the actual CRUD/query/version/type/association/token logic can live\n * once in this package instead of being re-typed per engine. Each adapter\n * package provides a thin SqlExecutor implementation over its own\n * database handle.\n *\n * Deliberately synchronous: every binding this targets executes queries\n * in-process without yielding, and an async interface would force the\n * shared logic's transaction sequences to interleave.\n */\nexport interface SqlExecutor {\n /** Run DDL, pragmas, or any statement(s) with no bound params and no results needed. */\n exec(sql: string): void;\n /** Run a single parameterized statement. Returns the number of rows affected (INSERT/UPDATE/DELETE). */\n run(sql: string, params?: readonly unknown[]): number;\n /** Run a parameterized statement and return the first result row, or undefined. */\n get<T = Record<string, unknown>>(sql: string, params?: readonly unknown[]): T | undefined;\n /** Run a parameterized statement and return all result rows. */\n all<T = Record<string, unknown>>(sql: string, params?: readonly unknown[]): T[];\n /**\n * Run `fn` atomically: every statement it issues commits, or none do if it\n * throws. A callback rather than BEGIN/COMMIT text because some engines\n * only offer one (a Durable Object's storage.transactionSync); for the\n * same reason `fn` must be synchronous and use only this executor.\n */\n transaction<T>(fn: () => T): T;\n}\n\n/** SQLite reports FK violations with this exact message; verify it holds when adding an engine. */\nexport const isForeignKeyViolation = (err: unknown): boolean =>\n err instanceof Error && err.message.includes('FOREIGN KEY constraint failed');\n\n/** SQLite reports a PRIMARY KEY/UNIQUE collision with this exact message. */\nexport const isUniqueConstraintViolation = (err: unknown): boolean =>\n err instanceof Error && err.message.includes('UNIQUE constraint failed');\n","import type { SqlExecutor } from './executor.js';\n\n/** timezone is optional passthrough app metadata — no default. */\nexport type StackConfig = { entityId: string; timezone: string | undefined };\n\n/** The one place the singleton record's id is spelled. */\nconst CONFIG_ROW_SQL = `SELECT content FROM records WHERE id = '_config'`;\n\n/**\n * Inserts the singleton _config@1 record and returns what it wrote, so a\n * caller that has just created a database reaches the same StackConfig an\n * existing one yields without a read-back. Only valid on a freshly-created\n * database.\n */\nexport const insertConfigRecord = (\n exec: SqlExecutor,\n entityId: string,\n timezone: string | undefined,\n): StackConfig => {\n const now = Date.now();\n exec.run(\n `INSERT INTO records (id, type_id, created_at, updated_at, content, version)\n VALUES ('_config', '_config@1', ?, ?, ?, 1)`,\n [now, now, JSON.stringify({ entityId, timezone })],\n );\n return { entityId, timezone };\n};\n\n/**\n * Reads the singleton _config@1 record, or null if this database has none.\n * Null is the signal an engine that cannot tell from the outside whether a\n * store exists (a Durable Object) uses to decide between reattaching and creating.\n */\nexport const tryReadStackConfig = (exec: SqlExecutor): StackConfig | null => {\n const row = exec.get<{ content: string }>(CONFIG_ROW_SQL);\n if (!row) return null;\n const content = JSON.parse(row.content) as { entityId: string; timezone?: string };\n return { entityId: content.entityId, timezone: content.timezone };\n};\n\n/** Reads the singleton _config@1 record. Throws if the database is missing it. */\nexport const readStackConfig = (exec: SqlExecutor): StackConfig => {\n const config = tryReadStackConfig(exec);\n if (!config) throw new Error('Stack database is missing its config record.');\n return config;\n};\n","/**\n * Cursor encode/decode for keyset pagination. The payload is JSON in\n * base64 rather than delimited fields: a content sort carries the field's\n * stored text, and neither a field name nor a text value is constrained\n * to avoid whatever character a delimiter would claim. Uses btoa/atob\n * with an explicit UTF-8 step rather than Node's Buffer, so the codec\n * stays runtime-agnostic and a non-Latin-1 value survives the round trip.\n */\n\nimport { NATIVE_SORT_FIELDS, StackBadRequestError } from '@haverstack/core';\nimport { constantSortEntry, contentSortEntry } from '@haverstack/core/adapter';\nimport type { SortEntry } from '@haverstack/core/adapter';\nimport type {\n ContentSortKey,\n StackRecord,\n NativeSortField,\n QuerySort,\n ScalarFieldKind,\n} from '@haverstack/core';\n\n/**\n * Which partition of the ordering a cursor sits in: a native column or a\n * content field's number, text, or absent value. The three content cases\n * are the boundary keyset pagination has to hold — a page that ended on\n * the last numeric value resumes at the first text one, not back at the\n * top of either.\n */\nexport type CursorKind = 'native' | 'num' | 'text' | 'absent';\n\nexport type DecodedCursor =\n | { kind: 'native'; field: NativeSortField; value: number; id: string }\n | { kind: 'num'; field: string; value: number; id: string }\n | { kind: 'text'; field: string; value: string; id: string }\n | { kind: 'absent'; field: string; id: string };\n\nconst toBase64 = (text: string): string => {\n const bytes = new TextEncoder().encode(text);\n let binary = '';\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary);\n};\n\nconst fromBase64 = (cursor: string): string => {\n const binary = atob(cursor);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return new TextDecoder().decode(bytes);\n};\n\nexport const encodeCursor = (decoded: DecodedCursor): string =>\n toBase64(\n JSON.stringify(\n decoded.kind === 'absent'\n ? { k: decoded.kind, f: decoded.field, i: decoded.id }\n : { k: decoded.kind, f: decoded.field, i: decoded.id, v: decoded.value },\n ),\n );\n\n/** Throws StackBadRequestError for any malformed, corrupt, or unrecognized cursor. */\nexport const decodeCursor = (cursor: string): DecodedCursor => {\n const malformed = () => new StackBadRequestError(`Invalid cursor: malformed \"${cursor}\"`);\n let parsed: unknown;\n try {\n parsed = JSON.parse(fromBase64(cursor));\n } catch {\n throw malformed();\n }\n if (!parsed || typeof parsed !== 'object') throw malformed();\n const { k, f, i, v } = parsed as Record<string, unknown>;\n if (typeof f !== 'string' || !f || typeof i !== 'string') throw malformed();\n\n if (k === 'absent') return { kind: 'absent', field: f, id: i };\n if (k === 'text') {\n if (typeof v !== 'string') throw malformed();\n return { kind: 'text', field: f, value: v, id: i };\n }\n if (k === 'num' || k === 'native') {\n if (typeof v !== 'number' || !isFinite(v)) {\n throw new StackBadRequestError(`Invalid cursor: non-numeric sort value`);\n }\n if (k === 'native') {\n if (!NATIVE_SORT_FIELDS.includes(f as NativeSortField)) {\n throw new StackBadRequestError(`Invalid cursor: unknown sort field \"${f}\"`);\n }\n return { kind: 'native', field: f as NativeSortField, value: v, id: i };\n }\n return { kind: 'num', field: f, value: v, id: i };\n }\n throw malformed();\n};\n\n/**\n * The name a cursor carries for a `contentFieldByType` sort: the map\n * itself, keys in order, so a cursor resumes only the map it was minted\n * under.\n */\nexport const byTypeDescriptor = (byType: Record<string, ContentSortKey>): string =>\n JSON.stringify(Object.entries(byType).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)));\n\nexport const getSortField = (query: { sort?: QuerySort }): NativeSortField =>\n query.sort?.field ?? 'createdAt';\n\nexport const getSortColumn = (field: NativeSortField): string =>\n field === 'createdAt' ? 'created_at' : field === 'updatedAt' ? 'updated_at' : 'version';\n\n/**\n * The cursor naming the last record of a page: where the next page\n * resumes. A content sort re-derives the record's ordered value from its\n * stored content rather than reading it back out of the index, so the\n * cursor and the index can only ever disagree if the write path is\n * broken — in which case pagination is not the thing to paper over.\n */\nexport const makeCursor = (\n record: StackRecord,\n sort: QuerySort | undefined,\n kindOf?: (record: StackRecord, field: string) => ScalarFieldKind | undefined,\n): string => {\n const byType = sort?.contentFieldByType;\n if (byType) {\n const field = byTypeDescriptor(byType);\n const key = Object.hasOwn(byType, record.typeId) ? byType[record.typeId] : undefined;\n const kind = key?.field === undefined ? undefined : kindOf?.(record, key.field);\n const entry =\n key?.field !== undefined\n ? kind && contentSortEntry(kind, record.content[key.field])\n : key && constantSortEntry(key.value ?? null);\n return encodeEntry(field, entry || null, record.id);\n }\n const contentField = sort?.contentField;\n if (contentField === undefined) {\n const field = getSortField({ sort });\n const value =\n field === 'updatedAt'\n ? record.updatedAt.getTime()\n : field === 'version'\n ? record.version\n : record.createdAt.getTime();\n return encodeCursor({ kind: 'native', field, value, id: record.id });\n }\n\n const kind = kindOf?.(record, contentField);\n const entry = kind ? contentSortEntry(kind, record.content[contentField]) : null;\n return encodeEntry(contentField, entry, record.id);\n};\n\nconst encodeEntry = (field: string, entry: SortEntry | null, id: string): string => {\n if (!entry) return encodeCursor({ kind: 'absent', field, id });\n return entry.kind === 'num'\n ? encodeCursor({ kind: 'num', field, value: entry.num, id })\n : encodeCursor({ kind: 'text', field, value: entry.text, id });\n};\n","/**\n * StackQuery -> SQL. Engine-independent — shared verbatim between\n * SQLite-backed record adapters. The one caveat is full-text search:\n * `f.search` here assumes a `records_fts` virtual table with a MATCH-able\n * `content` column (see FTS5_SCHEMA_SQL in schema.ts).\n *\n * A query compiles to a plan rather than to a single statement, because a\n * content-field sort is two orderings end to end: the records that hold a\n * value at the field, ordered by it, then the records that hold none,\n * ordered by id. Reading them as two statements lets each one walk an\n * index in order and stop at the page boundary; the LEFT JOIN that would\n * express the same result in one statement can only be sorted after the\n * fact, which costs a full pass over the table for every page.\n */\n\nimport {\n StackBadRequestError,\n type ContentArm,\n type ContentSortKey,\n type NativeSortField,\n type StackQuery,\n} from '@haverstack/core';\nimport { constantSortEntry, contentSortKey, parseContentFilterKey } from '@haverstack/core/adapter';\nimport type { SortEntry } from '@haverstack/core/adapter';\nimport {\n byTypeDescriptor,\n decodeCursor,\n getSortColumn,\n getSortField,\n type DecodedCursor,\n} from './cursor.js';\nimport { sanitizeFts5Query } from './fts5.js';\n\n/** One statement plus the parameters it binds, in textual order. */\nexport type QueryStatement = { sql: string; params: unknown[] };\n\n/**\n * A page statement with the row budget its trailing `LIMIT ?` binds.\n * buildQueryPlan leaves that parameter off, so the budget is never one of\n * the parameters the query itself bound: the second partition of a\n * content sort asks for what the first left of the page rather than for a\n * page it then discards.\n */\nexport const atBudget = (page: QueryStatement, rows: number): QueryStatement => ({\n sql: page.sql,\n params: [...page.params, rows],\n});\n\n/**\n * Reduce `sort.direction` to a keyword safe to interpolate. Core's\n * assertValidSort() already checks it, but this is where it reaches SQL\n * text, so an unchecked value here would be an injection sink. Core\n * resolves the default direction before any adapter sees the query.\n */\nconst sqlDirection = (query: StackQuery): 'ASC' | 'DESC' => {\n // No sort at all is the unsorted default; a sort always carries its direction.\n const dir = query.sort ? query.sort.direction : 'desc';\n if (dir !== 'asc' && dir !== 'desc') {\n throw new StackBadRequestError(`Invalid sort direction \"${dir}\": expected \"asc\" or \"desc\".`);\n }\n return dir === 'asc' ? 'ASC' : 'DESC';\n};\n\n/**\n * Normalize a json_each row's value so one array element and one bare\n * value are walked by the same clause: an array stands for its elements,\n * anything else for itself. See docs/spec/data-model.md § Nested content\n * paths.\n */\nconst spread = (alias: string): string =>\n `CASE WHEN ${alias}.type = 'array' THEN ${alias}.value ` +\n `WHEN ${alias}.type = 'object' THEN json_array(json(${alias}.value)) ` +\n `ELSE json_array(${alias}.value) END`;\n\n/**\n * The members of a json_each row that is an object, and none for a row\n * that is not — a path descending through a scalar reaches no value rather\n * than reaching an error.\n */\nconst members = (alias: string): string =>\n `CASE WHEN ${alias}.type = 'object' THEN ${alias}.value ELSE '{}' END`;\n\n/**\n * True when some value reached by `segments` satisfies `leaf`, applied to\n * the alias holding that value. Each segment is a bound parameter matched\n * against json_each's `key`, never interpolated into a path expression, so\n * no key can be read as syntax. See docs/spec/data-model.md § Filter.\n */\nconst contentPathExists = (\n segments: string[],\n leaf: (alias: string) => string,\n params: unknown[],\n nextAlias: () => string,\n): string => {\n // The walk is a flat join list, not a subquery per segment: both SQLite\n // builds cap expression-tree depth far below the segment cap, and\n // nesting spends that budget while a join list spends the join budget\n // the cap is actually sized against.\n let key = nextAlias();\n let value = nextAlias();\n const from = [`json_each(r.content) AS ${key}`, `json_each(${spread(key)}) AS ${value}`];\n const where = [`${key}.key = ?`];\n params.push(segments[0]);\n\n for (const segment of segments.slice(1)) {\n key = nextAlias();\n from.push(`json_each(${members(value)}) AS ${key}`);\n value = nextAlias();\n from.push(`json_each(${spread(key)}) AS ${value}`);\n where.push(`${key}.key = ?`);\n params.push(segment);\n }\n\n where.push(leaf(value));\n return `EXISTS (SELECT 1 FROM ${from.join(', ')} WHERE ${where.join(' AND ')})`;\n};\n\n/**\n * A scalar filter value never matches an object or array stored at the\n * path: json_each exposes those as their JSON text, which would compare\n * equal to a string spelling the same document while every non-SQL adapter\n * compares the value itself.\n */\nconst equalsLeaf = (alias: string): string =>\n `${alias}.type NOT IN ('object', 'array') AND ${alias}.value = ?`;\n\n/** The join alias the content index is read through. */\nconst SORT_ALIAS = 'cs';\n\n/**\n * A cursor names a position in one ordering; carrying it into another\n * would silently resume somewhere arbitrary. The partition matters as\n * much as the field name — a cursor from a numeric page can't be read\n * against text values — so each ordering below accepts only the cursors\n * it can read, and rejecting the rest is what narrows the cursor to them.\n */\nconst cursorMismatch = (cursor: DecodedCursor, field: string): StackBadRequestError =>\n new StackBadRequestError(\n `Cursor sort field \"${cursor.field}\" does not match query sort field \"${field}\"`,\n );\n\nconst nativeCursor = (cursor: DecodedCursor, field: NativeSortField) => {\n if (cursor.kind !== 'native' || cursor.field !== field) throw cursorMismatch(cursor, field);\n return cursor;\n};\n\nconst contentCursor = (cursor: DecodedCursor, field: string) => {\n if (cursor.kind === 'native' || cursor.field !== field) throw cursorMismatch(cursor, field);\n return cursor;\n};\n\n/**\n * A `content` and `contentPresent` predicate as conditions on `r`, binding\n * in textual order. A dot-separated path is matched element-wise through\n * arrays, and a `null` value means \"no value at the path, or a value that\n * is null\" (docs/spec/data-model.md § Filter): the second arm below, \"some\n * value there is null\" OR \"nothing is there at all\".\n */\nconst contentConditions = (\n predicate: ContentArm,\n params: unknown[],\n nextAlias: () => string,\n): string[] => {\n const conditions: string[] = [];\n for (const [key, value] of Object.entries(predicate.content ?? {})) {\n const segments = parseContentFilterKey(key);\n // undefined is the same absence null names — JSON drops it on the\n // way over the wire, so treating it as a value would make an\n // in-process query and its wire equivalent disagree.\n if (value === null || value === undefined) {\n const isNull = contentPathExists(segments, (a) => `${a}.value IS NULL`, params, nextAlias);\n const anyValue = contentPathExists(\n segments,\n (a) => `${a}.value IS NOT NULL`,\n params,\n nextAlias,\n );\n conditions.push(`(${isNull} OR NOT ${anyValue})`);\n } else {\n const match = contentPathExists(segments, equalsLeaf, params, nextAlias);\n params.push(value);\n conditions.push(match);\n }\n }\n // Presence — the question an exact-match value cannot ask: a path holds\n // a value when at least one non-null value is reachable at it.\n for (const key of predicate.contentPresent ?? []) {\n conditions.push(\n contentPathExists(\n parseContentFilterKey(key),\n (a) => `${a}.value IS NOT NULL`,\n params,\n nextAlias,\n ),\n );\n }\n return conditions;\n};\n\n/**\n * Every condition on the records row itself — everything a query asks\n * except where in the ordering to resume, which is per-partition and gets\n * appended by the caller.\n */\nconst recordConditions = (query: StackQuery): { conditions: string[]; params: unknown[] } => {\n const conditions: string[] = [\"r.id != '_config'\"];\n const params: unknown[] = [];\n const f = query.filter ?? {};\n let aliasSeq = 0;\n const nextContentAlias = () => `cp${aliasSeq++}`;\n\n /**\n * A filter that accepts one value or a list of them, as the `IN` that\n * covers both. Written even for a single value rather than as `= ?`,\n * since SQLite plans a one-element IN identically and one form means one\n * place for the filter's placeholder count and its bindings to agree.\n */\n const inFilter = (column: string, value: string | readonly string[] | undefined): void => {\n if (value === undefined) return;\n const values = Array.isArray(value) ? value : [value as string];\n conditions.push(`r.${column} IN (${values.map(() => '?').join(',')})`);\n params.push(...values);\n };\n\n /** One side of a date range, as the open-ended comparison it is. */\n const rangeFilter = (\n column: string,\n range: { after?: Date; before?: Date } | undefined,\n ): void => {\n if (range?.after) {\n conditions.push(`r.${column} > ?`);\n params.push(range.after.getTime());\n }\n if (range?.before) {\n conditions.push(`r.${column} < ?`);\n params.push(range.before.getTime());\n }\n };\n\n if (!f.includeDeleted) {\n conditions.push('r.deleted_at IS NULL');\n }\n\n if (!f.includeUnlisted) {\n conditions.push('r.unlisted_at IS NULL');\n }\n\n inFilter('type_id', f.typeId);\n\n // Not an inFilter: parentId takes an explicit null for \"at the root\",\n // which is a different SQL predicate rather than a different value.\n if (f.parentId !== undefined) {\n if (f.parentId === null) {\n conditions.push('r.parent_id IS NULL');\n } else {\n conditions.push('r.parent_id = ?');\n params.push(f.parentId);\n }\n }\n\n inFilter('app_id', f.appId);\n inFilter('entity_id', f.createdBy?.subjectId);\n inFilter('principal_id', f.createdBy?.principalId);\n\n rangeFilter('created_at', f.createdAt);\n rangeFilter('updated_at', f.updatedAt);\n\n // Every association filter below is a semi-join rather than a correlated\n // EXISTS, so the planner reads matching record ids straight out of an\n // index ending in record_id instead of probing once per record: the work\n // scales with the matches, not the stack.\n\n /**\n * The semi-join itself. `kind` is one of this module's own literals, never\n * caller text, and each clause carries its own placeholder — so the only\n * thing interpolated here is SQL this file wrote.\n */\n const hasAssociation = (kind: 'tag' | 'attachment' | 'relationship', clauses: string[]): string =>\n `r.id IN (SELECT a.record_id FROM associations a WHERE a.kind = '${kind}'` +\n clauses.map((c) => ` AND ${c}`).join('') +\n `)`;\n\n // Conjunctive: a record must carry every tag named.\n if (f.tags?.length) {\n for (const tag of f.tags) {\n conditions.push(hasAssociation('tag', ['a.label = ?']));\n params.push(tag);\n }\n }\n\n // Both halves in one subquery, so they match the same association.\n if (f.attachment) {\n const clauses: string[] = [];\n if (f.attachment.label !== undefined) {\n clauses.push('a.label = ?');\n params.push(f.attachment.label);\n }\n if (f.attachment.fileId !== undefined) {\n clauses.push('a.file_id = ?');\n params.push(f.attachment.fileId);\n }\n conditions.push(hasAssociation('attachment', clauses));\n }\n\n // A reference is an attachment association or a top-level file-ref field.\n if (f.referencesFileId) {\n conditions.push(\n `(${hasAssociation('attachment', ['a.file_id = ?'])}\n OR r.id IN (SELECT ci.record_id FROM content_index ci WHERE ci.file_id = ?))`,\n );\n params.push(f.referencesFileId, f.referencesFileId);\n }\n\n // Each clause is an optional pattern (docs/spec/data-model.md § Filter).\n // A record or entity target always stores '' in related_ns; saying so\n // keeps idx_assoc_related's prefix a contiguous equality run.\n if (f.relatedTo) {\n const clauses: string[] = [];\n const target = f.relatedTo.target;\n if (f.relatedTo.label !== undefined) {\n clauses.push('a.label = ?');\n params.push(f.relatedTo.label);\n }\n if (target) {\n clauses.push('a.related_scope = ?');\n params.push(target.kind);\n if (target.kind === 'record') {\n clauses.push('a.related_ns = ?', 'a.related_id = ?', 'a.related_stack = ?');\n params.push('', target.recordId, target.stackUrl ?? '');\n } else if (target.kind === 'entity') {\n clauses.push('a.related_ns = ?', 'a.related_id = ?');\n params.push('', target.entityId);\n } else {\n clauses.push('a.related_ns = ?');\n params.push(target.ns);\n if (target.id !== undefined) {\n clauses.push('a.related_id = ?');\n params.push(target.id);\n }\n }\n }\n conditions.push(hasAssociation('relationship', clauses));\n }\n\n if (f.content || f.contentPresent?.length) {\n conditions.push(...contentConditions(f, params, nextContentAlias));\n }\n\n // One arm per Type, each pinned to its type_id; types partition records,\n // so no record meets two arms (docs/spec/data-model.md § Content by type).\n if (f.contentByType) {\n const arms = Object.entries(f.contentByType).map(([typeId, arm]) => {\n params.push(typeId);\n return ['r.type_id = ?', ...contentConditions(arm, params, nextContentAlias)].join(' AND ');\n });\n conditions.push(`(${arms.map((arm) => `(${arm})`).join(' OR ')})`);\n }\n\n if (f.search) {\n const sanitized = sanitizeFts5Query(f.search);\n if (sanitized) {\n conditions.push(`r.rowid IN (SELECT rowid FROM records_fts WHERE records_fts MATCH ?)`);\n params.push(sanitized);\n } else {\n // A search that sanitizes to nothing (e.g. \"*\", punctuation-only) is\n // an honest zero-match result, not \"no filter\" — omitting the clause\n // would silently return the full table as the \"search result\".\n conditions.push('0');\n }\n }\n\n return { conditions, params };\n};\n\n/**\n * Everything after the cursor's record within the partition that holds a\n * value. `op` compares the way the ORDER BY does, so one form covers both\n * directions; where the cursor's rank is the last one, the leading\n * disjunct is simply never true.\n */\nconst presentCursorCondition = (\n cursor: Extract<DecodedCursor, { kind: 'num' | 'text' }>,\n op: '>' | '<',\n params: unknown[],\n): string => {\n if (cursor.kind === 'num') {\n params.push(cursor.value, cursor.value, cursor.id);\n return (\n `(${SORT_ALIAS}.value_rank ${op} 0 OR (${SORT_ALIAS}.value_rank = 0 AND ` +\n `(${SORT_ALIAS}.num_value ${op} ? OR (${SORT_ALIAS}.num_value = ? AND ` +\n `${SORT_ALIAS}.record_id ${op} ?))))`\n );\n }\n const key = contentSortKey(cursor.value);\n params.push(key, key, cursor.value, cursor.value, cursor.id);\n return (\n `(${SORT_ALIAS}.value_rank ${op} 1 OR (${SORT_ALIAS}.value_rank = 1 AND ` +\n `(${SORT_ALIAS}.text_key ${op} ? OR (${SORT_ALIAS}.text_key = ? AND ` +\n `(${SORT_ALIAS}.text_value ${op} ? OR (${SORT_ALIAS}.text_value = ? AND ` +\n `${SORT_ALIAS}.record_id ${op} ?))))))`\n );\n};\n\nconst statement = (\n select: string,\n from: string,\n conditions: string[],\n params: unknown[],\n tail = '',\n): QueryStatement => ({\n sql: `SELECT ${select} FROM ${from} WHERE ${conditions.join(' AND ')}${tail}`,\n params,\n});\n\n/**\n * Compile a query into the statements that answer it, read in order and\n * their rows concatenated: the first that fills the page ends the read,\n * so the second is never run for a page that doesn't reach it. Each still\n * needs the row budget its `LIMIT ?` binds — see atBudget.\n */\nexport const buildQueryPlan = (query: StackQuery): QueryStatement[] => {\n const dir = sqlDirection(query);\n const op = dir === 'ASC' ? '>' : '<';\n const decoded = query.cursor ? decodeCursor(query.cursor) : null;\n if (query.sort?.contentFieldByType) {\n return byTypePlan(query, query.sort.contentFieldByType, dir, op, decoded);\n }\n const contentField = query.sort?.contentField;\n\n if (contentField === undefined) {\n const { conditions, params } = recordConditions(query);\n const field = getSortField(query);\n const col = getSortColumn(field);\n if (decoded) {\n const cursor = nativeCursor(decoded, field);\n conditions.push(`(r.${col} ${op} ? OR (r.${col} = ? AND r.id ${op} ?))`);\n params.push(cursor.value, cursor.value, cursor.id);\n }\n return [\n statement(\n 'r.*',\n 'records r',\n conditions,\n params,\n ` ORDER BY r.${col} ${dir}, r.id ${dir} LIMIT ?`,\n ),\n ];\n }\n\n const cursor = decoded ? contentCursor(decoded, contentField) : null;\n const pages: QueryStatement[] = [];\n\n // Records holding a value at the field, in that value's order. A cursor\n // sitting in the absent partition has already passed every one of them.\n if (cursor?.kind !== 'absent') {\n const { conditions, params } = recordConditions(query);\n const from = `content_index ${SORT_ALIAS} JOIN records r ON r.id = ${SORT_ALIAS}.record_id`;\n conditions.push(`${SORT_ALIAS}.field = ?`);\n params.push(contentField);\n if (cursor) conditions.push(presentCursorCondition(cursor, op, params));\n // Ordered exactly as idx_content_index_sort stores it, so the page is\n // an ordered walk of the index rather than a sort of the matches.\n const order =\n `${SORT_ALIAS}.value_rank ${dir}, ${SORT_ALIAS}.num_value ${dir}, ` +\n `${SORT_ALIAS}.text_key ${dir}, ${SORT_ALIAS}.text_value ${dir}, ` +\n `${SORT_ALIAS}.record_id ${dir}`;\n pages.push(statement('r.*', from, conditions, params, ` ORDER BY ${order} LIMIT ?`));\n }\n\n // Records holding nothing there, which trail the others whichever way\n // the sort runs (docs/spec/data-model.md § Sorting by a content field).\n {\n const { conditions, params } = recordConditions(query);\n conditions.push(\n `NOT EXISTS (SELECT 1 FROM content_index ${SORT_ALIAS} ` +\n `WHERE ${SORT_ALIAS}.record_id = r.id AND ${SORT_ALIAS}.field = ?)`,\n );\n params.push(contentField);\n if (cursor?.kind === 'absent') {\n conditions.push(`r.id ${op} ?`);\n params.push(cursor.id);\n }\n pages.push(statement('r.*', 'records r', conditions, params, ` ORDER BY r.id ${dir} LIMIT ?`));\n }\n\n return pages;\n};\n\n/**\n * A sort naming its value per Type, read through a derived table in place\n * of the index: each Type's own index rows, and its constant in the index's\n * columns, so one cursor condition and one ORDER BY serve both. See\n * docs/spec/data-model.md § Sorting by a content field.\n */\nconst byTypePlan = (\n query: StackQuery,\n byType: Record<string, ContentSortKey>,\n dir: 'ASC' | 'DESC',\n op: '>' | '<',\n decoded: DecodedCursor | null,\n): QueryStatement[] => {\n const cursor = decoded ? contentCursor(decoded, byTypeDescriptor(byType)) : null;\n const fields: [string, string][] = [];\n const constants: [string, SortEntry][] = [];\n for (const [typeId, key] of Object.entries(byType)) {\n if (key.field !== undefined) {\n fields.push([typeId, key.field]);\n continue;\n }\n const entry = constantSortEntry(key.value ?? null);\n if (entry) constants.push([typeId, entry]);\n }\n const pages: QueryStatement[] = [];\n const fieldOf = (alias: string, record: string) =>\n fields.map(() => `(${record}.type_id = ? AND ${alias}.field = ?)`).join(' OR ');\n\n if (cursor?.kind !== 'absent' && fields.length + constants.length > 0) {\n const sources: string[] = [];\n const sourceParams: unknown[] = [];\n if (fields.length > 0) {\n sources.push(\n 'SELECT c.record_id AS record_id, c.value_rank AS value_rank, c.num_value AS num_value, ' +\n 'c.text_key AS text_key, c.text_value AS text_value ' +\n `FROM content_index c JOIN records t ON t.id = c.record_id WHERE ${fieldOf('c', 't')}`,\n );\n for (const [typeId, field] of fields) sourceParams.push(typeId, field);\n }\n for (const [typeId, entry] of constants) {\n sources.push(\n 'SELECT t.id AS record_id, ? AS value_rank, ? AS num_value, ? AS text_key, ' +\n '? AS text_value FROM records t WHERE t.type_id = ?',\n );\n sourceParams.push(\n ...(entry.kind === 'num' ? [0, entry.num, null, null] : [1, null, entry.key, entry.text]),\n typeId,\n );\n }\n const { conditions, params } = recordConditions(query);\n if (cursor) conditions.push(presentCursorCondition(cursor, op, params));\n const from =\n `(${sources.join(' UNION ALL ')}) ${SORT_ALIAS} ` +\n `JOIN records r ON r.id = ${SORT_ALIAS}.record_id`;\n const order =\n `${SORT_ALIAS}.value_rank ${dir}, ${SORT_ALIAS}.num_value ${dir}, ` +\n `${SORT_ALIAS}.text_key ${dir}, ${SORT_ALIAS}.text_value ${dir}, ` +\n `${SORT_ALIAS}.record_id ${dir}`;\n pages.push(\n statement(\n 'r.*',\n from,\n conditions,\n [...sourceParams, ...params],\n ` ORDER BY ${order} LIMIT ?`,\n ),\n );\n }\n\n // Records holding nothing to order by: a Type's field with no value, a\n // `null` constant, or a Type the map does not name.\n {\n const { conditions, params } = recordConditions(query);\n if (fields.length > 0) {\n conditions.push(\n `NOT EXISTS (SELECT 1 FROM content_index ${SORT_ALIAS} ` +\n `WHERE ${SORT_ALIAS}.record_id = r.id AND (${fieldOf(SORT_ALIAS, 'r')}))`,\n );\n for (const [typeId, field] of fields) params.push(typeId, field);\n }\n if (constants.length > 0) {\n conditions.push(`r.type_id NOT IN (${constants.map(() => '?').join(',')})`);\n params.push(...constants.map(([typeId]) => typeId));\n }\n if (cursor?.kind === 'absent') {\n conditions.push(`r.id ${op} ?`);\n params.push(cursor.id);\n }\n pages.push(statement('r.*', 'records r', conditions, params, ` ORDER BY r.id ${dir} LIMIT ?`));\n }\n return pages;\n};\n","/**\n * The two derived indexes a records database keeps beside its rows: FTS5\n * for `filter.search`, and content_index for `sort.contentField` and the\n * file-reference filters. Both can be rebuilt from `records` alone, and\n * both must be rewritten in the same transaction as any write that changes\n * what they cover, or a query answers from a record that no longer exists.\n */\n\nimport type { StackType, ScalarFieldKind } from '@haverstack/core';\nimport { contentSortEntry } from '@haverstack/core/adapter';\nimport type { SqlExecutor } from './executor.js';\n\n/**\n * FTS5's external-content table needs its special `('delete', rowid,\n * content)` command — with the *old* content — to unindex a row; a plain\n * DELETE leaves stale, still-searchable entries. remove() therefore reads\n * the current rowid/content and must run before the caller's change.\n */\nexport class SearchIndex {\n constructor(private readonly exec: SqlExecutor) {}\n\n /** Index a record that has no FTS entry yet (used right after an INSERT). */\n insert(recordId: string, content: string): void {\n this.exec.run(\n `INSERT INTO records_fts(rowid, content) SELECT rowid, ? FROM records WHERE id = ?`,\n [content, recordId],\n );\n }\n\n /**\n * Remove a record's FTS entry. MUST be called before the records row's\n * content changes or the row is deleted — see the note above.\n */\n remove(recordId: string): void {\n const row = this.exec.get<{ rowid: number; content: string }>(\n 'SELECT rowid, content FROM records WHERE id = ?',\n [recordId],\n );\n if (!row) return;\n this.exec.run(`INSERT INTO records_fts(records_fts, rowid, content) VALUES('delete', ?, ?)`, [\n row.rowid,\n row.content,\n ]);\n }\n}\n\n/**\n * Top-level scalar fields, by name and declared kind — what content_index\n * covers. Arrays and objects are left out: a value inside one has no\n * single position to order its record by, and no file reference the\n * attachment filter can see.\n */\nconst indexedFieldKinds = (\n schema: Record<string, { kind?: string }>,\n): Map<string, ScalarFieldKind> => {\n const kinds = new Map<string, ScalarFieldKind>();\n for (const [field, def] of Object.entries(schema)) {\n if (!def.kind || def.kind === 'array' || def.kind === 'object') continue;\n kinds.set(field, def.kind as ScalarFieldKind);\n }\n return kinds;\n};\n\n/**\n * One row per top-level scalar field a record holds a value at. Caches each\n * type's indexed fields so a write doesn't re-read and re-parse the schema.\n */\nexport class ContentIndex {\n private readonly fieldsByType = new Map<string, Map<string, ScalarFieldKind>>();\n\n constructor(private readonly exec: SqlExecutor) {}\n\n /** Prime the cache from a type as it is saved. */\n rememberType(type: StackType): void {\n this.fieldsByType.set(\n type.id,\n indexedFieldKinds(type.schema as Record<string, { kind?: string }>),\n );\n }\n\n /**\n * Replace a record's rows with what its content currently holds, on every\n * write that can change content or typeId, so neither the ordering nor the\n * file-reference lookup can drift from the record. A field holding no\n * orderable value gets no row at all, which is what puts the record at the\n * end of a sort on that field.\n */\n sync(recordId: string, typeId: string, content: Record<string, unknown>): void {\n this.remove(recordId);\n\n for (const [field, kind] of this.fieldsOf(typeId)) {\n const entry = contentSortEntry(kind, content[field]);\n if (!entry) continue;\n const sql = `INSERT OR IGNORE INTO content_index\n (record_id, field, value_rank, num_value, text_key, text_value, file_id)\n VALUES (?, ?, ?, ?, ?, ?, ?)`;\n if (entry.kind === 'num') {\n this.exec.run(sql, [recordId, field, 0, entry.num, null, null, null]);\n } else {\n // A file-ref field's value is its file id, so the row it already\n // needs for ordering also answers the attachment filter — one\n // field is one row, whatever a query reads it for.\n const fileId = kind === 'file-ref' ? entry.text : null;\n this.exec.run(sql, [recordId, field, 1, null, entry.key, entry.text, fileId]);\n }\n }\n }\n\n remove(recordId: string): void {\n this.exec.run('DELETE FROM content_index WHERE record_id = ?', [recordId]);\n }\n\n /** The declared kind of a type's top-level `field`, if it has one. */\n kindOf(typeId: string, field: string): ScalarFieldKind | undefined {\n return this.fieldsOf(typeId).get(field);\n }\n\n /**\n * From the cache, falling back to a `types` lookup only for a typeId this\n * process hasn't seen via rememberType() yet, e.g. right after open().\n */\n private fieldsOf(typeId: string): Map<string, ScalarFieldKind> {\n const cached = this.fieldsByType.get(typeId);\n if (cached) return cached;\n\n const typeRow = this.exec.get<{ schema: string }>('SELECT schema FROM types WHERE id = ?', [\n typeId,\n ]);\n const fields = typeRow\n ? indexedFieldKinds(JSON.parse(typeRow.schema) as Record<string, { kind?: string }>)\n : new Map<string, ScalarFieldKind>();\n this.fieldsByType.set(typeId, fields);\n return fields;\n }\n}\n","/**\n * Row <-> domain object mappers shared by every SQLite-backed record\n * adapter. Column names and JSON-encoding choices are the storage\n * contract; keeping one copy means the adapters can't drift on them.\n */\n\nimport type {\n Actor,\n GroupRole,\n Grantee,\n RecordJournalEntry,\n StackRecord,\n StackType,\n RecordVersion,\n Association,\n RelationshipTarget,\n} from '@haverstack/core';\nimport { partitionAssociations } from '@haverstack/core/adapter';\n\nexport const toMs = (d: Date): number => d.getTime();\n\n/**\n * An Actor from its two columns. A principal with no subject beside it\n * names nobody to attribute to, so it reads as absent like the subject.\n */\nconst actorFromColumns = (subject: unknown, principal: unknown): Actor | undefined =>\n subject == null\n ? undefined\n : {\n subjectId: subject as string,\n ...(principal != null && { principalId: principal as string }),\n };\nexport const fromMs = (ms: number): Date => new Date(ms);\n\nexport const rowToRecord = (\n row: Record<string, unknown>,\n associations: Association[],\n): StackRecord => {\n const record: StackRecord = {\n id: row.id as string,\n typeId: row.type_id as string,\n createdAt: fromMs(row.created_at as number),\n updatedAt: fromMs(row.updated_at as number),\n content: JSON.parse(row.content as string),\n version: row.version as number,\n };\n // Presence, never truthiness: SQL NULL is the only spelling of an absent\n // field, so the empty string and the epoch are values like any other.\n // The query predicates beside this read `IS NULL`, and a mapper that\n // disagreed would let a record answer one way to get() and another to\n // the filter that should have found it.\n if (row.parent_id != null) record.parentId = row.parent_id as string;\n if (row.app_id != null) record.appId = row.app_id as string;\n const createdBy = actorFromColumns(row.entity_id, row.principal_id);\n if (createdBy) record.createdBy = createdBy;\n const updatedBy = actorFromColumns(row.updated_by, row.updated_via);\n if (updatedBy) record.updatedBy = updatedBy;\n if (row.deleted_at != null) record.deletedAt = fromMs(row.deleted_at as number);\n if (row.unlisted_at != null) record.unlistedAt = fromMs(row.unlisted_at as number);\n // One table, partitioned on read. See docs/spec/access-control.md\n // § Record-level permissions.\n const partitioned = partitionAssociations(associations);\n if (partitioned.associations.length) record.associations = partitioned.associations;\n if (partitioned.permissions.length) record.permissions = partitioned.permissions;\n return record;\n};\n\nexport const rowToAssociation = (row: Record<string, unknown>): Association => {\n if (row.kind === 'tag') {\n return { kind: 'tag', label: row.label as string };\n }\n if (row.kind === 'anyone') {\n return { kind: 'anyone', label: 'read' };\n }\n if (row.kind === 'permission') {\n return {\n kind: 'permission',\n label: row.label as 'read' | 'write',\n grantee: rowToGrantee(row),\n };\n }\n if (row.kind === 'attachment') {\n const attachmentRecordId = row.attachment_record_id as string;\n return {\n kind: 'attachment',\n label: row.label as string,\n fileId: row.file_id as string,\n // Stored as '' when absent, like every other optional column here —\n // the field is omitted rather than served empty, so a round trip\n // produces the association the caller wrote.\n ...(attachmentRecordId && { attachmentRecordId }),\n };\n }\n return {\n kind: 'relationship',\n label: row.label as string,\n target: rowToTarget(row),\n };\n};\n\n/**\n * The six columns that identify an association, in the order every\n * INSERT and DELETE below binds them. One helper because the two must\n * agree exactly — a dissociate that bound them differently would delete\n * nothing and report success.\n */\nexport const associationKeyColumns = (\n a: Association,\n): [string, string, string, string, string, string] => {\n if (a.kind === 'attachment') return [a.fileId, '', '', '', '', ''];\n if (a.kind === 'permission') {\n const g = a.grantee;\n return g.kind === 'entity'\n ? ['', 'entity', g.entityId, '', '', '']\n : ['', 'group', g.groupId, '', '', g.role];\n }\n if (a.kind !== 'relationship') return ['', '', '', '', '', ''];\n const t = a.target;\n if (t.kind === 'entity') return ['', 'entity', t.entityId, '', '', ''];\n if (t.kind === 'external') return ['', 'external', t.id, t.ns, '', ''];\n return ['', 'record', t.recordId, '', t.stackUrl ?? '', ''];\n};\n\n/**\n * A permission's grantee, read back off the columns a relationship target\n * otherwise uses. `related_role` is what tells the two group sets apart —\n * `member` is the wider one. See docs/spec/access-control.md\n * § Record-level permissions.\n */\nconst rowToGrantee = (row: Record<string, unknown>): Grantee =>\n row.related_scope === 'group'\n ? {\n kind: 'group',\n groupId: row.related_id as string,\n role: row.related_role as GroupRole,\n }\n : { kind: 'entity', entityId: row.related_id as string };\n\nconst rowToTarget = (row: Record<string, unknown>): RelationshipTarget => {\n const id = row.related_id as string;\n if (row.related_scope === 'entity') return { kind: 'entity', entityId: id };\n if (row.related_scope === 'external') {\n return { kind: 'external', ns: row.related_ns as string, id };\n }\n const stackUrl = row.related_stack as string;\n return { kind: 'record', recordId: id, ...(stackUrl && { stackUrl }) };\n};\n\nexport const rowToType = (row: Record<string, unknown>): StackType => {\n const t: StackType = {\n id: row.id as string,\n baseId: row.base_id as string,\n version: row.version as number,\n name: row.name as string,\n schema: JSON.parse(row.schema as string),\n schemaHash: row.schema_hash as string,\n createdAt: fromMs(row.created_at as number),\n };\n if (row.migrates_from) t.migratesFrom = row.migrates_from as string;\n return t;\n};\n\nexport const rowToVersion = (row: Record<string, unknown>): RecordVersion => {\n const v: RecordVersion = {\n version: row.version as number,\n typeId: row.type_id as string,\n content: JSON.parse(row.content as string),\n updatedAt: fromMs(row.updated_at as number),\n };\n const createdBy = actorFromColumns(row.entity_id, row.principal_id);\n if (createdBy) v.createdBy = createdBy;\n const updatedBy = actorFromColumns(row.updated_by, row.updated_via);\n if (updatedBy) v.updatedBy = updatedBy;\n return v;\n};\n\n/**\n * One journal row. `previous_parent_id` carries the three-way spelling the\n * column comment states: SQL NULL is an entry naming no origin, '' is the\n * root, anything else is a container id.\n */\nexport const rowToJournalEntry = (row: Record<string, unknown>): RecordJournalEntry => {\n const e: RecordJournalEntry = {\n seq: row.seq as number,\n at: fromMs(row.at as number),\n kind: row.kind as RecordJournalEntry['kind'],\n ops: JSON.parse(row.ops as string),\n version: row.version as number,\n typeId: row.type_id as string,\n };\n if (row.parent_id != null) e.parentId = row.parent_id as string;\n if (row.previous_parent_id != null) {\n e.previousParentId = row.previous_parent_id === '' ? null : (row.previous_parent_id as string);\n }\n if (row.actor != null) e.actor = JSON.parse(row.actor as string);\n if (row.associations != null) e.associations = JSON.parse(row.associations as string);\n return e;\n};\n","/**\n * The actual StackRecordAdapter logic (minus lifecycle: open/\n * close/flush stay per-engine, since schema setup, pragmas, locking, and\n * durability differ there). Every CRUD/query/version/type/association\n * operation lives here exactly once, parametrized over a SqlExecutor\n * (which normalizes each engine's call conventions). Concrete adapters\n * construct one of these and delegate their StackRecordAdapter methods\n * to it — see record-adapter-sqlite.\n */\n\nimport {\n StackConflictError,\n StackVersionConflictError,\n StackNotFoundError,\n StackBadRequestError,\n applyMergePatch,\n assertOneSurface,\n} from '@haverstack/core';\nimport type {\n RecordJournalEntry,\n JournalQuery,\n VersionsQuery,\n StackRecord,\n StackType,\n TypeId,\n FileId,\n RecordVersion,\n RecordChangeSet,\n StackQuery,\n QueryResult,\n Association,\n AssociationEdit,\n ActorOptions,\n IfVersionOptions,\n} from '@haverstack/core';\nimport type {\n BumpVersionOptions,\n JournalEntryInput,\n JournalOptions,\n MutateOptions,\n} from '@haverstack/core/adapter';\nimport { AUTHORITY_ASSOCIATION_KINDS } from '@haverstack/core/adapter';\nimport type { SqlExecutor } from './executor.js';\nimport { isForeignKeyViolation, isUniqueConstraintViolation } from './executor.js';\nimport { buildQueryPlan, atBudget } from './query.js';\nimport { ContentIndex, SearchIndex } from './indexes.js';\nimport {\n rowToRecord,\n rowToAssociation,\n rowToType,\n rowToVersion,\n rowToJournalEntry,\n toMs,\n associationKeyColumns,\n} from './mappers.js';\nimport { makeCursor } from './cursor.js';\n\n/**\n * Restate an engine parse error as `bad_request` when the query carries\n * search text, the one filter with a query language the sanitizer can't\n * fully repair. Any other clause is built from parameters, so a parse\n * error there is this module's bug and is rethrown untouched.\n */\nconst asStackBadRequestError = <T>(query: StackQuery, run: () => T): T => {\n try {\n return run();\n } catch (err) {\n if (!query.filter?.search) throw err;\n throw new StackBadRequestError(\n `Search text could not be parsed: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n};\n\n/**\n * One spelling of the optimistic-concurrency failure, so the message a\n * caller sees never depends on which check noticed it.\n */\nconst versionConflict = (id: string, expected: number, actual: number): StackVersionConflictError =>\n new StackVersionConflictError(\n `Record \"${id}\" is at version ${actual}, expected ${expected}`,\n id,\n expected,\n actual,\n );\n\nconst recordNotFound = (id: string): StackNotFoundError =>\n new StackNotFoundError(`Record not found: \"${id}\"`);\n\n/**\n * Every `versions` column beyond the (record_id, version) key, and the\n * values for them in the same order — one list, so the INSERT that writes a\n * snapshot and the UPDATE that replaces one can't drift apart on which\n * columns a snapshot is made of.\n */\nconst VERSION_COLUMNS = [\n 'type_id',\n 'content',\n 'updated_at',\n 'entity_id',\n 'principal_id',\n 'updated_by',\n 'updated_via',\n] as const;\n\nconst versionRowValues = (version: RecordVersion): unknown[] => [\n version.typeId,\n JSON.stringify(version.content),\n toMs(version.updatedAt),\n version.createdBy?.subjectId ?? null,\n version.createdBy?.principalId ?? null,\n version.updatedBy?.subjectId ?? null,\n version.updatedBy?.principalId ?? null,\n];\n\nexport type SharedSqlRecordLogicDeps = {\n exec: SqlExecutor;\n};\n\nexport class SharedSqlRecordLogic {\n private readonly exec: SqlExecutor;\n private readonly searchIndex: SearchIndex;\n private readonly contentIndex: ContentIndex;\n\n constructor({ exec }: SharedSqlRecordLogicDeps) {\n this.exec = exec;\n this.searchIndex = new SearchIndex(exec);\n this.contentIndex = new ContentIndex(exec);\n }\n\n /** Check `ifVersion` against a version read inside the caller's transaction. */\n private checkExpectedVersion(id: string, actual: number, expected: number | undefined): void {\n if (expected === undefined || actual === expected) return;\n throw versionConflict(id, expected, actual);\n }\n\n /**\n * Called after a version-gated statement affected zero rows.\n * Distinguishes \"record doesn't exist\" (StackNotFoundError) from \"it\n * exists but isn't at expectedVersion\" (StackVersionConflictError, with\n * the actual current version for the caller to act on).\n */\n private throwVersionConflict(id: string, expectedVersion: number | undefined): never {\n const version = this.currentVersion(id);\n if (version === undefined) throw recordNotFound(id);\n throw versionConflict(id, expectedVersion as number, version);\n }\n\n private currentVersion(id: string): number | undefined {\n return this.exec.get<{ version: number }>('SELECT version FROM records WHERE id = ?', [id])\n ?.version;\n }\n\n /**\n * What a mutation builds on, read inside its transaction so nothing can\n * land between the read and the write: a patch applied to an earlier read\n * would overwrite whatever changed since. Throws for a missing record or\n * a failed `ifVersion`.\n */\n private readForWrite(\n id: string,\n ifVersion: number | undefined,\n ): { typeId: TypeId; content: Record<string, unknown> } {\n const row = this.exec.get<{ version: number; type_id: string; content: string }>(\n 'SELECT version, type_id, content FROM records WHERE id = ?',\n [id],\n );\n if (!row) throw recordNotFound(id);\n this.checkExpectedVersion(id, row.version, ifVersion);\n return { typeId: row.type_id, content: JSON.parse(row.content) };\n }\n\n /**\n * Every version-bumping UPDATE. The `ifVersion` guard rides in the WHERE\n * clause, so a write that reads nothing first (a soft delete, an\n * undelete) enforces it with no separate read.\n */\n private versionedUpdate(\n id: string,\n sets: string[],\n values: unknown[],\n opts: IfVersionOptions & ActorOptions,\n now = toMs(new Date()),\n ): void {\n const guarded = opts.ifVersion !== undefined;\n const changed = this.exec.run(\n `UPDATE records SET ${[...sets, 'version = version + 1', 'updated_at = ?', 'updated_by = ?', 'updated_via = ?'].join(', ')}` +\n ` WHERE id = ?${guarded ? ' AND version = ?' : ''}`,\n [\n ...values,\n now,\n opts.actor?.subjectId ?? null,\n opts.actor?.principalId ?? null,\n id,\n ...(guarded ? [opts.ifVersion] : []),\n ],\n );\n if (changed === 0) this.throwVersionConflict(id, opts.ifVersion);\n }\n\n /**\n * Read a record back after its own mutation committed. Absence here is an\n * invariant breach, not a \"not found\". Synchronous, so nothing can run\n * between the commit and the read — see readRecord().\n */\n private reread(id: string, verb: string): StackRecord {\n const updated = this.readRecord(id);\n if (!updated) throw new Error(`Record not found after ${verb}: \"${id}\"`);\n return updated;\n }\n\n // -------------------------------------------------------\n // Records\n // -------------------------------------------------------\n\n /**\n * One transaction, because a record and the tables that describe it are\n * one fact: a half-applied create raises, so the caller believes nothing\n * landed, while the surviving row fails their retry on the PK and is\n * missing from both indexes. A duplicate id maps to StackConflictError.\n */\n async createRecord(record: StackRecord, opts: JournalOptions = {}): Promise<StackRecord> {\n this.exec.transaction(() => {\n try {\n this.exec.run(\n `INSERT INTO records\n (id, type_id, created_at, updated_at, content, version,\n parent_id, entity_id, app_id, principal_id, updated_by, updated_via,\n deleted_at, unlisted_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n [\n record.id,\n record.typeId,\n toMs(record.createdAt),\n toMs(record.updatedAt),\n JSON.stringify(record.content),\n record.version,\n record.parentId ?? null,\n record.createdBy?.subjectId ?? null,\n record.appId ?? null,\n record.createdBy?.principalId ?? null,\n record.updatedBy?.subjectId ?? null,\n record.updatedBy?.principalId ?? null,\n record.deletedAt ? toMs(record.deletedAt) : null,\n record.unlistedAt ? toMs(record.unlistedAt) : null,\n ],\n );\n } catch (err) {\n if (isUniqueConstraintViolation(err)) {\n throw new StackConflictError(`Record already exists: \"${record.id}\"`);\n }\n throw err;\n }\n\n const edges = [...(record.associations ?? []), ...(record.permissions ?? [])];\n if (edges.length) this.insertAssociations(record.id, edges);\n\n this.searchIndex.insert(record.id, JSON.stringify(record.content));\n this.contentIndex.sync(record.id, record.typeId, record.content);\n this.appendJournal(record.id, opts.journal);\n });\n\n return record;\n }\n\n async getRecord(id: string): Promise<StackRecord | null> {\n return this.readRecord(id);\n }\n\n /**\n * The synchronous read behind getRecord(), for use inside\n * exec.transaction(), whose callback can't await. reread() relies on the\n * same synchrony: nothing interleaves between a commit and its read, so a\n * concurrent mutation is never reported under this one's verb.\n */\n private readRecord(id: string): StackRecord | null {\n const row = this.exec.get<Record<string, unknown>>('SELECT * FROM records WHERE id = ?', [id]);\n return row ? this.hydrate(row) : null;\n }\n\n /** A records row with its association set attached. */\n private hydrate(row: Record<string, unknown>): StackRecord {\n return rowToRecord(row, this.getAssociationsForRecord(row.id as string));\n }\n\n /**\n * One transaction, so one call is one version whatever it moved, and the\n * patch applies to the content as it stands when the write lands.\n */\n async mutateRecord(\n id: string,\n changes: RecordChangeSet,\n opts: MutateOptions & BumpVersionOptions = {},\n ): Promise<StackRecord> {\n const now = toMs(new Date());\n\n // Assembled, since a fixed statement per combination of aspects would\n // be 2^4 of them. Shared by both paths; only `content` is the bumping\n // path's alone, since a patch always bumps.\n const sets: string[] = [];\n const values: unknown[] = [];\n if (changes.parentId !== undefined) {\n sets.push('parent_id = ?');\n values.push(changes.parentId);\n }\n if (changes.unlisted !== undefined) {\n sets.push('unlisted_at = ?');\n // Stamped fresh because this key is only ever present on a\n // transition — Stack narrows a change set to the aspects that\n // actually moved before it reaches an adapter.\n values.push(changes.unlisted ? now : null);\n }\n\n this.exec.transaction(() => {\n const current = this.readForWrite(id, opts.ifVersion);\n\n // No versioned UPDATE to carry `ifVersion`, so readForWrite() is the\n // only check. See docs/spec/versioning.md § Version history.\n if (opts.bumpsVersion === false) {\n if (sets.length > 0) {\n this.exec.run(`UPDATE records SET ${sets.join(', ')} WHERE id = ?`, [...values, id]);\n }\n this.replaceAssociationHalves(id, changes);\n this.appendJournal(id, opts.journal);\n return;\n }\n\n const merged = changes.contentPatch\n ? applyMergePatch(current.content, changes.contentPatch)\n : undefined;\n if (merged !== undefined) {\n sets.unshift('content = ?');\n values.unshift(JSON.stringify(merged));\n }\n\n if (opts.snapshot) this.snapshotBeforeMutation(id, opts.snapshot);\n if (merged !== undefined) this.searchIndex.remove(id);\n\n this.versionedUpdate(id, sets, values, opts, now);\n\n this.replaceAssociationHalves(id, changes);\n\n if (merged !== undefined) {\n this.searchIndex.insert(id, JSON.stringify(merged));\n this.contentIndex.sync(id, current.typeId, merged);\n }\n this.appendJournal(id, opts.journal);\n });\n\n return this.reread(id, 'mutateRecord');\n }\n\n async deleteRecord(\n id: string,\n opts: { purge?: boolean } & MutateOptions = {},\n ): Promise<StackRecord | null> {\n if (opts.purge) {\n return this.exec.transaction(() => this.purgeRecord(id, opts.ifVersion));\n }\n\n // One timestamp for both columns: a soft delete is a single event, and\n // two `new Date()` calls can straddle a millisecond boundary and leave\n // deleted_at and updated_at disagreeing about when it happened.\n const now = toMs(new Date());\n this.exec.transaction(() => {\n if (opts.snapshot) this.snapshotBeforeMutation(id, opts.snapshot);\n this.versionedUpdate(id, ['deleted_at = ?'], [now], opts, now);\n this.appendJournal(id, opts.journal);\n });\n\n return this.reread(id, 'deleteRecord');\n }\n\n /**\n * Delete a record and everything that refers to it, returning the record\n * as it stood (null if there was none). Read here, inside the caller's\n * transaction, so nothing can overtake the last copy that will ever exist.\n */\n private purgeRecord(id: string, ifVersion?: number): StackRecord | null {\n const purged = this.readRecord(id);\n if (!purged) {\n // A CAS against a record that isn't there is a failed precondition,\n // not the \"nothing to delete\" that an unconditional purge\n // reports by returning null.\n if (ifVersion !== undefined) throw recordNotFound(id);\n return null;\n }\n this.checkExpectedVersion(id, purged.version, ifVersion);\n this.searchIndex.remove(id);\n this.exec.run('DELETE FROM associations WHERE record_id = ?', [id]);\n this.exec.run('DELETE FROM versions WHERE record_id = ?', [id]);\n // A purge takes the journal with it, for the reason it takes the\n // version history: a log naming what a destroyed record once held is\n // exactly the residue this verb exists to leave nothing of.\n this.exec.run('DELETE FROM journal WHERE record_id = ?', [id]);\n this.contentIndex.remove(id);\n this.exec.run('DELETE FROM records WHERE id = ?', [id]);\n return purged;\n }\n\n async undeleteRecord(id: string, opts: MutateOptions = {}): Promise<StackRecord> {\n this.exec.transaction(() => {\n if (opts.snapshot) this.snapshotBeforeMutation(id, opts.snapshot);\n this.versionedUpdate(id, ['deleted_at = NULL'], [], opts);\n this.appendJournal(id, opts.journal);\n });\n\n return this.reread(id, 'undelete');\n }\n\n async restoreVersion(\n id: string,\n version: number,\n opts: MutateOptions = {},\n ): Promise<StackRecord> {\n // Only content and its type are restored — a snapshot carries nothing\n // else, so there is nothing here to roll containment, listing or the\n // associations table back to.\n this.exec.transaction(() => {\n this.readForWrite(id, opts.ifVersion);\n const target = this.readVersion(id, version);\n if (!target) throw new StackNotFoundError(`Version not found: \"${id}\"@${version}`);\n if (opts.snapshot) this.snapshotBeforeMutation(id, opts.snapshot);\n this.rewriteContent(id, target.typeId, target.content, opts);\n this.appendJournal(id, opts.journal);\n });\n\n return this.reread(id, 'restoreVersion');\n }\n\n async commitMigration(\n id: string,\n toTypeId: TypeId,\n content: Record<string, unknown>,\n opts: MutateOptions = {},\n ): Promise<StackRecord> {\n this.exec.transaction(() => {\n this.readForWrite(id, opts.ifVersion);\n if (opts.snapshot) this.snapshotBeforeMutation(id, opts.snapshot);\n this.rewriteContent(id, toTypeId, content, opts);\n this.appendJournal(id, opts.journal);\n });\n\n return this.reread(id, 'commitMigration');\n }\n\n /**\n * Replace a record's type and content wholesale. Unindex, write, re-index,\n * in that order (docs/spec/adapters.md § The search index is unindexed\n * before the row moves); callers must be inside exec.transaction().\n */\n private rewriteContent(\n id: string,\n typeId: TypeId,\n content: Record<string, unknown>,\n opts: IfVersionOptions & ActorOptions,\n ): void {\n const json = JSON.stringify(content);\n this.searchIndex.remove(id);\n this.versionedUpdate(id, ['type_id = ?', 'content = ?'], [typeId, json], opts);\n this.searchIndex.insert(id, json);\n this.contentIndex.sync(id, typeId, content);\n }\n\n async queryRecords(query: StackQuery): Promise<QueryResult> {\n const limit = query.limit ?? 50;\n // One extra row, to learn whether a further page follows.\n const fetch = limit + 1;\n\n // A content-field sort is two statements (see buildQueryPlan). Each asks\n // only for what the page still lacks, so the second usually never runs.\n const rows: Record<string, unknown>[] = [];\n for (const page of buildQueryPlan(query)) {\n const budget = fetch - rows.length;\n if (budget <= 0) break;\n const statement = atBudget(page, budget);\n rows.push(\n ...asStackBadRequestError(query, () =>\n this.exec.all<Record<string, unknown>>(statement.sql, statement.params),\n ),\n );\n }\n\n const hasMore = rows.length > limit;\n const page = hasMore ? rows.slice(0, limit) : rows;\n\n const records = page.map((row) => this.hydrate(row));\n\n const lastRecord = records[records.length - 1];\n const cursor =\n hasMore && lastRecord\n ? makeCursor(lastRecord, query.sort, (record, field) =>\n this.contentIndex.kindOf(record.typeId, field),\n )\n : null;\n\n return { records, cursor };\n }\n\n /**\n * The reference check and the purges share one synchronous transaction,\n * so nothing can add a reference between the two.\n */\n async deleteUnreferencedAttachmentRecords(\n fileId: FileId,\n metadataTypeIds: TypeId[],\n ): Promise<StackRecord[]> {\n return this.exec.transaction(() => {\n const referenced = this.exec.all<{ found: number }>(\n `SELECT 1 as found FROM associations WHERE kind = 'attachment' AND file_id = ?\n UNION ALL\n SELECT 1 FROM content_index WHERE file_id = ?\n LIMIT 1`,\n [fileId, fileId],\n );\n if (referenced.length) {\n throw new StackConflictError('Attachment is still referenced by one or more records');\n }\n\n // An empty family still owes the caller the reference check above —\n // the conflict is a fact about the file, not about which metadata\n // types happen to be defined.\n if (metadataTypeIds.length === 0) return [];\n\n const placeholders = metadataTypeIds.map(() => '?').join(', ');\n const metaRows = this.exec.all<{ id: string }>(\n `SELECT id FROM records\n WHERE type_id IN (${placeholders}) AND json_extract(content, '$.fileId') = ?`,\n [...metadataTypeIds, fileId],\n );\n const deleted: StackRecord[] = [];\n for (const row of metaRows) {\n const purged = this.purgeRecord(row.id);\n if (purged) deleted.push(purged);\n }\n\n return deleted;\n });\n }\n\n // -------------------------------------------------------\n // Versions\n // -------------------------------------------------------\n\n async getVersions(id: string, query: VersionsQuery = {}): Promise<RecordVersion[]> {\n const conditions = ['record_id = ?'];\n const values: unknown[] = [id];\n if (query.beforeVersion !== undefined) {\n conditions.push('version < ?');\n values.push(query.beforeVersion);\n }\n const rows = this.exec.all<Record<string, unknown>>(\n `SELECT * FROM versions WHERE ${conditions.join(' AND ')} ORDER BY version DESC${\n query.limit !== undefined ? ' LIMIT ?' : ''\n }`,\n query.limit !== undefined ? [...values, query.limit] : values,\n );\n return rows.map(rowToVersion);\n }\n\n async getVersion(id: string, version: number): Promise<RecordVersion | null> {\n return this.readVersion(id, version);\n }\n\n private readVersion(id: string, version: number): RecordVersion | null {\n const row = this.exec.get<Record<string, unknown>>(\n 'SELECT * FROM versions WHERE record_id = ? AND version = ?',\n [id, version],\n );\n return row ? rowToVersion(row) : null;\n }\n\n /**\n * A (record_id, version) collision is rejected loudly via the UNIQUE\n * constraint, mapped to StackConflictError — never a silently discarded\n * snapshot leaving a hole in rollback history. See\n * docs/spec/versioning.md § Optimistic concurrency (`ifVersion`).\n */\n private insertVersionRow(id: string, version: RecordVersion): void {\n try {\n this.exec.run(\n `INSERT INTO versions\n (record_id, version, ${VERSION_COLUMNS.join(', ')})\n VALUES (?, ?, ${VERSION_COLUMNS.map(() => '?').join(', ')})`,\n [id, version.version, ...versionRowValues(version)],\n );\n } catch (err) {\n if (isUniqueConstraintViolation(err)) {\n throw new StackConflictError(\n `Version ${version.version} already exists for record \"${id}\" — a concurrent ` +\n `writer raced past this version. Use ifVersion to detect this before it happens.`,\n );\n }\n throw err;\n }\n }\n\n /**\n * Replaces every column insertVersionRow writes — structurally, off the\n * same VERSION_COLUMNS list, because a column left out here would keep\n * the replaced row's value and surface later as a restore putting back\n * something the snapshot never said.\n */\n private overwriteVersionRow(id: string, version: RecordVersion): void {\n this.exec.run(\n `UPDATE versions\n SET ${VERSION_COLUMNS.map((c) => `${c} = ?`).join(', ')}\n WHERE record_id = ? AND version = ?`,\n [...versionRowValues(version), id, version.version],\n );\n }\n\n /**\n * Standalone snapshot write for tooling and tests — loud on any\n * collision, since nothing here is about to bump the version. Mutating\n * methods take a `snapshot` option instead; see snapshotBeforeMutation.\n */\n async saveVersion(id: string, version: RecordVersion): Promise<void> {\n this.insertVersionRow(id, version);\n }\n\n /**\n * The snapshot half of a mutating method's atomic snapshot-then-mutate\n * transaction. A collision is a racing-writer conflict, except an orphan\n * row at the record's *current* version — recognized by version number\n * alone, never content — which is overwritten so the interrupted write\n * can complete. See docs/spec/versioning.md § Snapshot atomicity.\n */\n private snapshotBeforeMutation(id: string, version: RecordVersion): void {\n try {\n this.insertVersionRow(id, version);\n } catch (err) {\n if (!(err instanceof StackConflictError)) throw err;\n\n if (this.currentVersion(id) !== version.version) throw err;\n\n this.overwriteVersionRow(id, version);\n }\n }\n\n // -------------------------------------------------------\n // Change journal\n // -------------------------------------------------------\n\n /**\n * Append one entry, stamped from the row as it now stands, so callers run\n * this inside their write's transaction, after the write. `seq` is\n * allocated in the INSERT itself, so no caller ever holds one it expects\n * to be free. See docs/spec/journal.md § Ordering.\n */\n private appendJournal(recordId: string, entry: JournalEntryInput | undefined): void {\n if (!entry) return;\n // Not readRecord(): this runs on every write and needs three columns,\n // not the row plus its associations. parent_id stays raw so its\n // NULL/''/id spelling reaches the journal unchanged.\n const row = this.exec.get<{\n version: number;\n type_id: string;\n parent_id: string | null;\n }>('SELECT version, type_id, parent_id FROM records WHERE id = ?', [recordId]);\n if (!row) throw recordNotFound(recordId);\n\n this.exec.run(\n `INSERT INTO journal\n (record_id, seq, at, kind, ops, version, type_id, parent_id,\n previous_parent_id, actor, associations)\n VALUES (\n ?,\n (SELECT COALESCE(MAX(seq), 0) + 1 FROM journal WHERE record_id = ?),\n ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n [\n recordId,\n recordId,\n toMs(new Date()),\n entry.kind,\n JSON.stringify(entry.ops),\n row.version,\n row.type_id,\n row.parent_id,\n // '' is the root; NULL is an entry that names no origin at all.\n entry.previousParentId === undefined ? null : (entry.previousParentId ?? ''),\n entry.actor ? JSON.stringify(entry.actor) : null,\n entry.associations?.length ? JSON.stringify(entry.associations) : null,\n ],\n );\n }\n\n async getJournal(id: string, query: JournalQuery = {}): Promise<RecordJournalEntry[]> {\n // An empty log means \"nothing changed\" unconditionally, so a record\n // that isn't there cannot be spelled that way. A purged record is gone,\n // and gets the same refusal. See docs/spec/journal.md § Reading it.\n if (!this.exec.get('SELECT 1 FROM records WHERE id = ?', [id])) {\n throw recordNotFound(id);\n }\n const conditions = ['record_id = ?'];\n const values: unknown[] = [id];\n if (query.afterSeq !== undefined) {\n conditions.push('seq > ?');\n values.push(query.afterSeq);\n }\n const rows = this.exec.all<Record<string, unknown>>(\n `SELECT * FROM journal WHERE ${conditions.join(' AND ')} ORDER BY seq ASC${\n query.limit !== undefined ? ' LIMIT ?' : ''\n }`,\n query.limit !== undefined ? [...values, query.limit] : values,\n );\n return rows.map(rowToJournalEntry);\n }\n\n // -------------------------------------------------------\n // Types\n // -------------------------------------------------------\n\n async saveType(type: StackType): Promise<void> {\n this.exec.run(\n `INSERT OR REPLACE INTO types\n (id, base_id, version, name, schema, schema_hash, migrates_from, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,\n [\n type.id,\n type.baseId,\n type.version,\n type.name,\n JSON.stringify(type.schema),\n type.schemaHash,\n type.migratesFrom ?? null,\n toMs(type.createdAt),\n ],\n );\n this.contentIndex.rememberType(type);\n }\n\n async getType(id: TypeId): Promise<StackType | null> {\n const row = this.exec.get<Record<string, unknown>>('SELECT * FROM types WHERE id = ?', [id]);\n return row ? rowToType(row) : null;\n }\n\n async listTypes(): Promise<StackType[]> {\n const rows = this.exec.all<Record<string, unknown>>(\n 'SELECT * FROM types ORDER BY base_id, version',\n );\n return rows.map(rowToType);\n }\n\n // -------------------------------------------------------\n // Associations\n // -------------------------------------------------------\n\n /**\n * Never bumps `version`/`updatedAt` and never snapshots — see\n * StackRecordAdapter.amendAssociations(). Removes apply before adds, so\n * removing and re-adding one identity in a call leaves it present.\n */\n async amendAssociations(\n recordId: string,\n changes: AssociationEdit[],\n opts: JournalOptions = {},\n ): Promise<StackRecord> {\n assertOneSurface(changes);\n this.exec.transaction(() => {\n if (this.currentVersion(recordId) === undefined) throw recordNotFound(recordId);\n for (const change of changes) {\n if (change.op !== 'remove') continue;\n const { association } = change;\n this.exec.run(\n `DELETE FROM associations\n WHERE record_id = ?\n AND kind = ?\n AND label = ?\n AND file_id = ?\n AND related_scope = ?\n AND related_id = ?\n AND related_ns = ?\n AND related_stack = ?\n AND related_role = ?`,\n [recordId, association.kind, association.label, ...associationKeyColumns(association)],\n );\n }\n const adds = changes.flatMap((c) => (c.op === 'add' ? [c.association] : []));\n if (adds.length) this.insertAssociations(recordId, adds);\n this.appendJournal(recordId, opts.journal);\n });\n\n return this.reread(recordId, 'amendAssociations');\n }\n\n /**\n * Each key replaces only within its own half of the partition, which is\n * why a tag write cannot drop an ACL. Caller-transactional.\n * See docs/spec/access-control.md § Record-level permissions.\n */\n private replaceAssociationHalves(recordId: string, changes: RecordChangeSet): void {\n if (changes.associations !== undefined) {\n this.replaceAssociations(recordId, changes.associations, 'data');\n }\n if (changes.permissions !== undefined) {\n this.replaceAssociations(recordId, changes.permissions, 'authority');\n }\n }\n\n /**\n * Swap one half of a record's association set wholesale — the \"replace,\n * don't merge\" semantics a change set's association list carries. The data\n * half is \"not an authority kind\", so core's list is the only one.\n */\n private replaceAssociations(\n recordId: string,\n associations: Association[],\n half: 'data' | 'authority',\n ): void {\n this.exec.run(\n `DELETE FROM associations WHERE record_id = ? AND kind ${half === 'data' ? 'NOT IN' : 'IN'} ` +\n `(${AUTHORITY_ASSOCIATION_KINDS.map(() => '?').join(', ')})`,\n [recordId, ...AUTHORITY_ASSOCIATION_KINDS],\n );\n if (associations.length) this.insertAssociations(recordId, associations);\n }\n\n /**\n * Upserts on association identity, so re-pointing `attachment_record_id`\n * (outside the key) costs no second row. A missing record trips the\n * foreign key, reported as StackNotFoundError rather than an orphan row.\n */\n private insertAssociations(recordId: string, associations: Association[]): void {\n for (const assoc of associations) {\n try {\n this.exec.run(\n `INSERT INTO associations\n (record_id, kind, label, file_id, related_scope, related_id, related_ns,\n related_stack, related_role, attachment_record_id)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT DO UPDATE SET attachment_record_id = excluded.attachment_record_id`,\n [\n recordId,\n assoc.kind,\n assoc.label,\n ...associationKeyColumns(assoc),\n assoc.kind === 'attachment' ? (assoc.attachmentRecordId ?? '') : '',\n ],\n );\n } catch (err) {\n if (isForeignKeyViolation(err)) {\n throw recordNotFound(recordId);\n }\n throw err;\n }\n }\n }\n\n private getAssociationsForRecord(recordId: string): Association[] {\n const rows = this.exec.all<Record<string, unknown>>(\n 'SELECT * FROM associations WHERE record_id = ?',\n [recordId],\n );\n return rows.map(rowToAssociation);\n }\n}\n","/**\n * The engine-independent half of a SQLite-backed StackRecordAdapter: the\n * capability declaration and the delegation of all seventeen\n * StackRecordAdapter methods onto SharedSqlRecordLogic. Every method here\n * is a forward with no engine-specific content, so an adapter that owns a\n * SqlExecutor already knows how to answer all of them.\n *\n * What a concrete adapter is left to supply is exactly what differs\n * between bindings: constructing the database handle, applying the\n * schema, and its own lifecycle (flush/close) — hence those two being the\n * only abstract members.\n *\n * Lives in record.js's barrel rather than index.js's, so an adapter that\n * imports it never pulls in token-logic.ts's `node:crypto` — see the note\n * at the top of record.ts.\n */\n\nimport type {\n JournalQuery,\n VersionsQuery,\n RecordJournalEntry,\n StackType,\n TypeId,\n FileId,\n RecordVersion,\n StackRecord,\n StackQuery,\n QueryResult,\n AssociationEdit,\n RecordChangeSet,\n StackCapabilities,\n} from '@haverstack/core';\nimport type {\n StackRecordAdapter,\n BumpVersionOptions,\n JournalOptions,\n MutateOptions,\n} from '@haverstack/core/adapter';\nimport type { SqlExecutor } from './executor.js';\nimport type { StackConfig } from './config.js';\nimport { SharedSqlRecordLogic } from './record-logic.js';\n\n/**\n * What every engine running SharedSqlRecordLogic's query builder supports.\n * It describes the shared SQL, not the binding, so it is the same for each\n * of them — an engine whose SQLite build lacked FTS5 would override\n * `filter.search` rather than restate the whole declaration.\n */\nexport const SQLITE_RECORD_CAPABILITIES: StackCapabilities = {\n filter: {\n content: 'path',\n contentPresent: true,\n // Inside SQLite's limits on expression depth and compound selects; see\n // docs/spec/adapters.md § Adapter capabilities.\n contentByType: 64,\n search: true,\n },\n sort: {\n fields: ['createdAt', 'updatedAt', 'version'],\n contentField: true,\n contentFieldByType: 64,\n },\n limits: {\n attachmentBytes: null,\n contentBytes: null,\n },\n};\n\nexport abstract class SharedSqlRecordAdapter implements StackRecordAdapter {\n readonly capabilities: StackCapabilities = SQLITE_RECORD_CAPABILITIES;\n\n readonly ownerEntityId: string;\n readonly timezone: string | undefined;\n\n private readonly record: SharedSqlRecordLogic;\n\n protected constructor(exec: SqlExecutor, config: StackConfig) {\n this.record = new SharedSqlRecordLogic({ exec });\n this.ownerEntityId = config.entityId;\n this.timezone = config.timezone;\n }\n\n // -------------------------------------------------------\n // Records\n // -------------------------------------------------------\n\n createRecord(record: StackRecord, opts?: JournalOptions): Promise<StackRecord> {\n return this.record.createRecord(record, opts);\n }\n\n getRecord(id: string): Promise<StackRecord | null> {\n return this.record.getRecord(id);\n }\n\n mutateRecord(\n id: string,\n changes: RecordChangeSet,\n opts?: MutateOptions & BumpVersionOptions,\n ): Promise<StackRecord> {\n return this.record.mutateRecord(id, changes, opts);\n }\n\n deleteRecord(\n id: string,\n opts?: { purge?: boolean } & MutateOptions,\n ): Promise<StackRecord | null> {\n return this.record.deleteRecord(id, opts);\n }\n\n undeleteRecord(id: string, opts?: MutateOptions): Promise<StackRecord> {\n return this.record.undeleteRecord(id, opts);\n }\n\n restoreVersion(id: string, version: number, opts?: MutateOptions): Promise<StackRecord> {\n return this.record.restoreVersion(id, version, opts);\n }\n\n commitMigration(\n id: string,\n toTypeId: TypeId,\n content: Record<string, unknown>,\n opts?: MutateOptions,\n ): Promise<StackRecord> {\n return this.record.commitMigration(id, toTypeId, content, opts);\n }\n\n queryRecords(query: StackQuery): Promise<QueryResult> {\n return this.record.queryRecords(query);\n }\n\n deleteUnreferencedAttachmentRecords(\n fileId: FileId,\n metadataTypeIds: TypeId[],\n ): Promise<StackRecord[]> {\n return this.record.deleteUnreferencedAttachmentRecords(fileId, metadataTypeIds);\n }\n\n // -------------------------------------------------------\n // Versions\n // -------------------------------------------------------\n\n getVersions(id: string, query?: VersionsQuery): Promise<RecordVersion[]> {\n return this.record.getVersions(id, query);\n }\n\n getVersion(id: string, version: number): Promise<RecordVersion | null> {\n return this.record.getVersion(id, version);\n }\n\n saveVersion(id: string, version: RecordVersion): Promise<void> {\n return this.record.saveVersion(id, version);\n }\n\n // -------------------------------------------------------\n // Change journal\n // -------------------------------------------------------\n\n getJournal(id: string, query?: JournalQuery): Promise<RecordJournalEntry[]> {\n return this.record.getJournal(id, query);\n }\n\n // -------------------------------------------------------\n // Types\n // -------------------------------------------------------\n\n saveType(type: StackType): Promise<void> {\n return this.record.saveType(type);\n }\n\n getType(id: TypeId): Promise<StackType | null> {\n return this.record.getType(id);\n }\n\n listTypes(): Promise<StackType[]> {\n return this.record.listTypes();\n }\n\n // -------------------------------------------------------\n // Associations\n // -------------------------------------------------------\n\n amendAssociations(\n recordId: string,\n changes: AssociationEdit[],\n opts?: JournalOptions,\n ): Promise<StackRecord> {\n return this.record.amendAssociations(recordId, changes, opts);\n }\n\n // -------------------------------------------------------\n // Lifecycle\n // -------------------------------------------------------\n\n abstract flush(): Promise<void>;\n abstract close(): Promise<void>;\n}\n","/**\n * Storage-ownership lock file. A stack file is owned by exactly one\n * process at a time (see docs/spec/adapters.md § Concurrency & storage ownership).\n * The lock file sits beside the database and records the PID of its\n * opener — pure Node fs/process logic, no SQLite engine involved, so\n * every Node-backed record adapter shares one implementation and one\n * error message.\n */\n\nimport { readFileSync, writeFileSync, existsSync, unlinkSync } from 'fs';\n\ntype LockInfo = { pid: number };\n\nconst lockPathFor = (dbPath: string): string => `${dbPath}.lock`;\n\nconst isProcessAlive = (pid: number): boolean => {\n try {\n process.kill(pid, 0);\n return true;\n } catch (err) {\n // ESRCH: no such process — safe to reclaim. Anything else (e.g. EPERM,\n // meaning the process exists but we can't signal it) — assume alive.\n return (err as NodeJS.ErrnoException).code !== 'ESRCH';\n }\n};\n\n/**\n * Acquire the lock, throwing a clear error if another live process\n * already holds it. Reclaims stale locks (owning process no longer\n * running) automatically. `force` bypasses the check entirely, for the\n * rare case of PID reuse across a reboot.\n */\nexport const acquireLock = (dbPath: string, force?: boolean): void => {\n const lockPath = lockPathFor(dbPath);\n const info = readLock(lockPath);\n if (info) {\n const ownedBySelf = info.pid === process.pid;\n if (!ownedBySelf && !force && isProcessAlive(info.pid)) {\n throw new Error(\n `Stack database at \"${dbPath}\" is in use by another process (pid ${info.pid}). ` +\n `Connect via its server instead, or pass { force: true } to override. ` +\n `If no such process is running, remove \"${lockPath}\".`,\n );\n }\n }\n writeFileSync(lockPath, JSON.stringify({ pid: process.pid } satisfies LockInfo));\n};\n\n/**\n * Read the lock, treating an unreadable one as absent. A crash mid-write\n * leaves a torn lock naming no live process, which is what acquireLock()\n * reclaims anyway; refusing it would lock the data out for good. The lock\n * exists to stop a second writer, not to outrank the data it guards.\n */\nconst readLock = (lockPath: string): LockInfo | null => {\n try {\n const info = JSON.parse(readFileSync(lockPath, 'utf-8')) as LockInfo;\n return typeof info?.pid === 'number' ? info : null;\n } catch {\n return null;\n }\n};\n\n/**\n * Release the lock, if it's still owned by this process. An unreadable lock\n * is removed rather than left behind: readLock() treats it as absent and\n * acquireLock() would reclaim it anyway, so leaving it would only make\n * storage look permanently locked to a reader that doesn't get that far.\n */\nexport const releaseLock = (dbPath: string): void => {\n const lockPath = lockPathFor(dbPath);\n if (!existsSync(lockPath)) return;\n const info = readLock(lockPath);\n if (!info || info.pid === process.pid) unlinkSync(lockPath);\n};\n","/**\n * The actual StackTokenStore logic (createToken/lookupToken/listTokens/\n * revokeToken), parametrized over a SqlExecutor. Consumed by\n * record-adapter-sqlite's NativeTokenStore, which points it at a file\n * separate from records — see TOKENS_SCHEMA_SQL in schema.ts.\n */\n\nimport { createHash, randomBytes } from 'node:crypto';\nimport type { Actor } from '@haverstack/core';\nimport type { TokenSession, TokenInfo } from '@haverstack/core/wire';\nimport type { SqlExecutor } from './executor.js';\nimport { toMs, fromMs } from './mappers.js';\n\n/**\n * How a bearer token is reduced to what the `tokens` table stores. One\n * function because createToken and lookupToken must agree exactly — a\n * divergence would silently make every issued token unlookupable.\n */\nconst hashToken = (token: string): string => createHash('sha256').update(token).digest('hex');\n\nexport type SharedTokenLogicDeps = {\n exec: SqlExecutor;\n};\n\nexport class SharedTokenLogic {\n private readonly exec: SqlExecutor;\n\n constructor({ exec }: SharedTokenLogicDeps) {\n this.exec = exec;\n }\n\n async createToken(\n actor: Actor,\n opts: { label?: string; expiresAt?: Date } = {},\n ): Promise<{ id: string; token: string }> {\n const id = randomBytes(8).toString('hex');\n const token = randomBytes(32).toString('hex');\n const tokenHash = hashToken(token);\n this.exec.run(\n 'INSERT INTO tokens (id, token_hash, principal_id, subject_id, label, created_at, expires_at) VALUES (?, ?, ?, ?, ?, ?, ?)',\n [\n id,\n tokenHash,\n // Stored rather than left null for an undelegated token, so a\n // reader never has to know which column stands in for the other.\n actor.principalId ?? actor.subjectId,\n actor.subjectId,\n opts.label ?? null,\n toMs(new Date()),\n opts.expiresAt ? toMs(opts.expiresAt) : null,\n ],\n );\n return { id, token };\n }\n\n async lookupToken(token: string): Promise<TokenSession | null> {\n const hash = hashToken(token);\n const row = this.exec.get<{\n principal_id: string;\n subject_id: string;\n expires_at: number | null;\n }>('SELECT principal_id, subject_id, expires_at FROM tokens WHERE token_hash = ?', [hash]);\n if (!row) return null;\n if (row.expires_at !== null && Date.now() > row.expires_at) return null;\n return { principalId: row.principal_id, subjectId: row.subject_id };\n }\n\n async listTokens(): Promise<TokenInfo[]> {\n const rows = this.exec.all<{\n id: string;\n principal_id: string;\n subject_id: string;\n label: string | null;\n created_at: number;\n expires_at: number | null;\n }>(\n 'SELECT id, principal_id, subject_id, label, created_at, expires_at FROM tokens ORDER BY created_at DESC',\n );\n return rows.map((row) => ({\n id: row.id,\n principalId: row.principal_id,\n subjectId: row.subject_id,\n ...(row.label && { label: row.label }),\n createdAt: fromMs(row.created_at),\n ...(row.expires_at !== null && { expiresAt: fromMs(row.expires_at) }),\n }));\n }\n\n async revokeToken(id: string): Promise<void> {\n this.exec.run('DELETE FROM tokens WHERE id = ?', [id]);\n }\n}\n","import type { SqlExecutor } from '@haverstack/sqlite-shared';\nimport { DatabaseSync } from './node-sqlite.js';\n\n/** Normalizes node:sqlite's spread-args run/get/all calls to SqlExecutor. */\nexport class NativeSqliteExecutor implements SqlExecutor {\n constructor(private readonly db: DatabaseSync) {}\n\n exec(sql: string): void {\n this.db.exec(sql);\n }\n\n run(sql: string, params: readonly unknown[] = []): number {\n const result = this.db.prepare(sql).run(...(params as (string | number | null)[]));\n return Number(result.changes);\n }\n\n get<T = Record<string, unknown>>(sql: string, params: readonly unknown[] = []): T | undefined {\n return this.db.prepare(sql).get(...(params as (string | number | null)[])) as T | undefined;\n }\n\n all<T = Record<string, unknown>>(sql: string, params: readonly unknown[] = []): T[] {\n return this.db.prepare(sql).all(...(params as (string | number | null)[])) as T[];\n }\n\n transaction<T>(fn: () => T): T {\n this.db.exec('BEGIN');\n try {\n const result = fn();\n this.db.exec('COMMIT');\n return result;\n } catch (err) {\n this.db.exec('ROLLBACK');\n throw err;\n }\n }\n}\n","/**\n * Bearer-token storage backing @haverstack/core's StackTokenStore,\n * implemented against its own file — deliberately separate from\n * NativeSQLiteRecordAdapter's records database. The portable stack file\n * is \"your data, take it with you\"; auth material shouldn't travel with\n * it, and restoring a backup shouldn't resurrect revoked tokens. Server\n * implementations wire these up as separate parts\n * (`{ adapter, tokens }`), the same philosophy as combineAdapters().\n *\n * The actual createToken/lookupToken/listTokens/revokeToken logic lives\n * in @haverstack/sqlite-shared's SharedTokenLogic, reached through the\n * SqlExecutor interface.\n */\n\nimport type { Actor } from '@haverstack/core';\nimport type { TokenSession, StackTokenStore, TokenInfo } from '@haverstack/core/wire';\nimport {\n TOKENS_SCHEMA_SQL,\n PRAGMA_JOURNAL_MODE_WAL,\n acquireLock,\n releaseLock,\n SharedTokenLogic,\n} from '@haverstack/sqlite-shared';\nimport { DatabaseSync } from './node-sqlite.js';\nimport { NativeSqliteExecutor } from './executor.js';\n\n/** Conventional sibling path for a token store beside a stack's main .db file. */\nexport const defaultTokenStorePath = (dbPath: string): string => `${dbPath}.tokens`;\n\nexport type NativeTokenStoreOpenOptions = {\n /** Absolute path to the token store file. Created if it doesn't exist. */\n path: string;\n /** Bypass the storage-ownership lock check. See docs/spec/adapters.md § Concurrency & storage ownership. */\n force?: boolean;\n};\n\nexport class NativeTokenStore implements StackTokenStore {\n private db!: DatabaseSync;\n private tokens!: SharedTokenLogic;\n\n private constructor(private readonly path: string) {}\n\n /** Opens the token store, creating the file and schema if needed. */\n static async open(opts: NativeTokenStoreOpenOptions): Promise<NativeTokenStore> {\n acquireLock(opts.path, opts.force);\n const store = new NativeTokenStore(opts.path);\n store.db = new DatabaseSync(opts.path);\n store.db.exec(PRAGMA_JOURNAL_MODE_WAL);\n store.db.exec(TOKENS_SCHEMA_SQL);\n store.tokens = new SharedTokenLogic({ exec: new NativeSqliteExecutor(store.db) });\n return store;\n }\n\n createToken(\n actor: Actor,\n opts?: { label?: string; expiresAt?: Date },\n ): Promise<{ id: string; token: string }> {\n return this.tokens.createToken(actor, opts);\n }\n\n lookupToken(token: string): Promise<TokenSession | null> {\n return this.tokens.lookupToken(token);\n }\n\n listTokens(): Promise<TokenInfo[]> {\n return this.tokens.listTokens();\n }\n\n revokeToken(id: string): Promise<void> {\n return this.tokens.revokeToken(id);\n }\n\n async close(): Promise<void> {\n this.db.close();\n releaseLock(this.path);\n }\n}\n","/**\n * Haverstack — Native SQLite Record Adapter\n * -------------------------------------------------------\n * Implements StackRecordAdapter using node:sqlite (Node's built-in\n * SQLite binding, Node >= 22.5). No native compilation, no node-gyp,\n * no prebuilt binaries, and writes go straight to the file via normal\n * SQLite journaling (WAL mode) — no whole-database rewrite per write,\n * no in-memory copy of the whole store, real OS-level file locking.\n * Full-text search uses FTS5.\n *\n * A stack file is owned by exactly one process at a time (see\n * docs/spec/adapters.md § Concurrency & storage ownership). open()\n * acquires a PID-stamped lock file beside the database and rejects if\n * another live process already holds it; close() releases it.\n *\n * Token storage is a separate concern — see NativeTokenStore in this\n * package, which implements @haverstack/core's StackTokenStore against\n * its own file rather than this adapter's records database.\n *\n * This class itself is a thin node:sqlite binding: opening the file, the\n * storage-ownership lock, and the WAL checkpoint are what's genuinely\n * engine-specific and live here. Everything above storage comes from\n * @haverstack/sqlite-shared's SharedSqlRecordAdapter, reached through the\n * SqlExecutor interface (NativeSqliteExecutor here normalizes node:sqlite's\n * spread-args run/get/all calls to it).\n */\n\nimport { DatabaseSync } from './node-sqlite.js';\nimport { existsSync } from 'fs';\nimport {\n applyRecordSchema,\n acquireLock,\n releaseLock,\n insertConfigRecord,\n readStackConfig,\n SharedSqlRecordAdapter,\n type StackConfig,\n} from '@haverstack/sqlite-shared';\nimport { OwnerMismatchError } from '@haverstack/core/adapter';\nimport { NativeSqliteExecutor } from './executor.js';\n\n// -------------------------------------------------------\n// Types\n// -------------------------------------------------------\n\n/** What open() does when the store is missing or present, like O_CREAT / O_EXCL. */\nexport type StoreCreateMode = 'never' | 'ifMissing' | 'exclusive';\n\n/** A plain DID, or a lazy provider called only when a store is actually created. */\nexport type OwnerEntityIdInput = string | (() => string | Promise<string>);\n\nexport type NativeSQLiteRecordAdapterOpenOptions = {\n /** Absolute path to the .db file. */\n path: string;\n /** IANA timezone string e.g. \"America/New_York\". Consulted only when a store is created. No default. */\n timezone?: string;\n /**\n * Open even if a lock file from another live process is present.\n * Only needed if that process is gone but its PID was reused by\n * something else (the automatic stale-lock check already reclaims\n * locks whose owning process is no longer running).\n */\n force?: boolean;\n} & (\n | {\n /** Open an existing store; fail if the file is missing. */\n create?: 'never';\n /** Checked against the existing store's owner; a mismatch throws OwnerMismatchError. */\n ownerEntityId?: string;\n }\n | {\n /** `'ifMissing'` opens the store if present and creates it if not; `'exclusive'` creates it and fails if present. */\n create: 'ifMissing' | 'exclusive';\n /**\n * Owner of a newly created store. A plain string is also checked against an\n * existing store's owner; a lazy provider is never called just to compare.\n */\n ownerEntityId: OwnerEntityIdInput;\n }\n);\n\n// -------------------------------------------------------\n// NativeSQLiteRecordAdapter\n// -------------------------------------------------------\n\nexport class NativeSQLiteRecordAdapter extends SharedSqlRecordAdapter {\n private constructor(\n private readonly path: string,\n private readonly db: DatabaseSync,\n exec: NativeSqliteExecutor,\n config: StackConfig,\n ) {\n super(exec, config);\n }\n\n /**\n * Opens or creates the stack database at `path` according to `create`.\n * Takes the storage-ownership lock first and releases it again if the\n * open fails, since the caller never receives an adapter to close.\n * See docs/spec/adapters.md § Construction.\n */\n static async open(\n opts: NativeSQLiteRecordAdapterOpenOptions,\n ): Promise<NativeSQLiteRecordAdapter> {\n const mode: StoreCreateMode = opts.create ?? 'never';\n const checkMode = (exists: boolean): void => {\n if (!exists && mode === 'never') {\n throw new Error(\n `Cannot open: no database found at \"${opts.path}\". ` +\n `Pass create: 'ifMissing' or 'exclusive' to create one.`,\n );\n }\n if (exists && mode === 'exclusive') {\n throw new Error(\n `Cannot create: database already exists at \"${opts.path}\". ` +\n `Pass create: 'never' or 'ifMissing' to open it.`,\n );\n }\n };\n const existedBeforeLock = existsSync(opts.path);\n checkMode(existedBeforeLock);\n\n // Resolved before the lock is taken so a failing provider leaves nothing held.\n let newOwner: string | undefined;\n if (!existedBeforeLock) {\n newOwner =\n typeof opts.ownerEntityId === 'function' ? await opts.ownerEntityId() : opts.ownerEntityId;\n if (!newOwner) {\n throw new Error(\n `Cannot create: no ownerEntityId given for the new database at \"${opts.path}\".`,\n );\n }\n }\n\n acquireLock(opts.path, opts.force);\n let db: DatabaseSync | undefined;\n try {\n // Re-checked under the lock: another process may have created the file meanwhile.\n const exists = existsSync(opts.path);\n checkMode(exists);\n db = new DatabaseSync(opts.path);\n const exec = new NativeSqliteExecutor(db);\n applyRecordSchema(exec, { wal: true });\n let config: StackConfig;\n if (exists) {\n config = readStackConfig(exec);\n if (typeof opts.ownerEntityId === 'string' && opts.ownerEntityId !== config.entityId) {\n throw new OwnerMismatchError(opts.ownerEntityId, config.entityId, `\"${opts.path}\"`);\n }\n } else {\n if (!newOwner) throw new Error(`Cannot create: \"${opts.path}\" vanished while opening.`);\n config = insertConfigRecord(exec, newOwner, opts.timezone);\n }\n return new NativeSQLiteRecordAdapter(opts.path, db, exec, config);\n } catch (err) {\n db?.close();\n releaseLock(opts.path);\n throw err;\n }\n }\n\n // -------------------------------------------------------\n // Lifecycle\n // -------------------------------------------------------\n\n /** Folds the WAL back into the main file — useful before copying/backing up the database. */\n async flush(): Promise<void> {\n this.db.exec('PRAGMA wal_checkpoint(TRUNCATE);');\n }\n\n async close(): Promise<void> {\n this.db.close();\n releaseLock(this.path);\n }\n}\n\nexport {\n NativeTokenStore,\n defaultTokenStorePath,\n type NativeTokenStoreOpenOptions,\n} from './token-store.js';\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/node-sqlite.ts","../../sqlite-shared/src/schema.ts","../../sqlite-shared/src/fts5.ts","../../sqlite-shared/src/executor.ts","../../sqlite-shared/src/config.ts","../../sqlite-shared/src/cursor.ts","../../sqlite-shared/src/mappers.ts","../../sqlite-shared/src/query.ts","../../sqlite-shared/src/indexes.ts","../../sqlite-shared/src/record-logic.ts","../../sqlite-shared/src/record-adapter.ts","../../sqlite-shared/src/lock.ts","../../sqlite-shared/src/token-logic.ts","../src/executor.ts","../src/token-store.ts","../src/index.ts"],"names":["kindOf","field","kind","entry","rows","StackBadRequestError","cursor","constantSortEntry","contentSortEntry","page","statement","existsSync"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Loads node:sqlite via process.getBuiltinModule() rather than a static\n * `import ... from 'node:sqlite'`. node:sqlite is new enough that some\n * bundler/test-runner toolchains (Vite/Vitest as of this writing —\n * https://github.com/vitest-dev/vitest/issues/7177) mis-resolve it,\n * stripping the \"node:\" prefix and trying to load a package literally\n * named \"sqlite\". process.getBuiltinModule() is the Node-sanctioned way\n * to reach a builtin module without going through import resolution at\n * all, so it's immune to that class of bug — useful here since a\n * consuming app's own toolchain could hit the same issue, not just ours.\n */\nexport const { DatabaseSync } = process.getBuiltinModule(\n 'node:sqlite',\n) as typeof import('node:sqlite');\n\nexport type DatabaseSync = InstanceType<typeof DatabaseSync>;\n","import type { SqlExecutor } from './executor.js';\n\n/**\n * Schema DDL shared by SQLite-backed record adapters. TOKENS_SCHEMA_SQL\n * is split out from RECORD_SCHEMA_SQL because token storage lives in its\n * own file, never bundled with records — see NativeTokenStore in\n * record-adapter-sqlite and the StackTokenStore portability rationale\n * (docs/spec/wire-format.md § Authentication).\n */\n\nexport const RECORD_SCHEMA_SQL = `\n CREATE TABLE IF NOT EXISTS records (\n id TEXT PRIMARY KEY,\n type_id TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n content TEXT NOT NULL CHECK (json_valid(content)),\n version INTEGER NOT NULL DEFAULT 1,\n parent_id TEXT,\n entity_id TEXT,\n app_id TEXT,\n principal_id TEXT,\n updated_by TEXT,\n updated_via TEXT,\n deleted_at INTEGER,\n unlisted_at INTEGER\n ) STRICT;\n\n -- A record's data associations: tags, attachments and relationships.\n -- Its permissions are in their own table below, so no predicate over this\n -- one can match a grantee as a relationship target.\n CREATE TABLE IF NOT EXISTS associations (\n record_id TEXT NOT NULL REFERENCES records(id),\n kind TEXT NOT NULL CHECK (kind IN ('tag', 'attachment', 'relationship')),\n label TEXT NOT NULL,\n file_id TEXT NOT NULL DEFAULT '',\n -- A relationship target is (related_scope, related_id) qualified by\n -- related_ns (a foreign namespace) or related_stack (another stack).\n -- All are in the key, so targets differing only by a qualifier are\n -- distinct associations.\n related_scope TEXT NOT NULL DEFAULT '' CHECK (related_scope IN ('', 'record', 'entity', 'external')),\n related_id TEXT NOT NULL DEFAULT '',\n related_ns TEXT NOT NULL DEFAULT '',\n related_stack TEXT NOT NULL DEFAULT '',\n -- Out of the key: it annotates a reference rather than naming one, so\n -- re-pointing it updates the existing row. See docs/spec/attachments.md\n -- § Naming the upload a reference came from.\n attachment_record_id TEXT NOT NULL DEFAULT '',\n -- Leads with record_id, so its implicit index serves every by-record\n -- read and delete; the indexes below cover only the filter directions.\n PRIMARY KEY (record_id, kind, label, file_id, related_scope, related_id, related_ns, related_stack)\n ) STRICT;\n\n -- Who reaches a record, one row per element. An 'anyone' row names no\n -- grantee; a group grantee's role is in the key, because member and\n -- admin name two different sets of people.\n -- See docs/spec/access-control.md § Record-level permissions.\n CREATE TABLE IF NOT EXISTS permissions (\n record_id TEXT NOT NULL REFERENCES records(id),\n kind TEXT NOT NULL CHECK (kind IN ('permission', 'anyone')),\n label TEXT NOT NULL CHECK (label IN ('read', 'write')),\n grantee_kind TEXT NOT NULL DEFAULT '' CHECK (grantee_kind IN ('', 'entity', 'group')),\n grantee_id TEXT NOT NULL DEFAULT '',\n role TEXT NOT NULL DEFAULT '' CHECK (role IN ('', 'member', 'admin')),\n PRIMARY KEY (record_id, kind, label, grantee_kind, grantee_id, role)\n ) STRICT;\n\n -- Content and the type it is read under. No parent_id, unlisted_at or\n -- associations column: none of those aspects bumps version, so no\n -- version ever snapshots one. See\n -- docs/spec/versioning.md § Version history.\n CREATE TABLE IF NOT EXISTS versions (\n record_id TEXT NOT NULL REFERENCES records(id),\n version INTEGER NOT NULL,\n type_id TEXT NOT NULL,\n content TEXT NOT NULL CHECK (json_valid(content)),\n updated_at INTEGER NOT NULL,\n entity_id TEXT,\n principal_id TEXT,\n updated_by TEXT,\n updated_via TEXT,\n PRIMARY KEY (record_id, version)\n ) STRICT;\n\n -- The durable half of a change event: which aspects moved, who moved\n -- them, and the association deltas nothing else retains. Envelope-level\n -- by design — content lives on a versions row, and copying it here\n -- would make the journal the larger of the two stores.\n -- See docs/spec/journal.md.\n CREATE TABLE IF NOT EXISTS journal (\n record_id TEXT NOT NULL REFERENCES records(id),\n seq INTEGER NOT NULL,\n at INTEGER NOT NULL,\n -- No 'purged': a purge destroys the log rather than appending to it,\n -- so the constraint names exactly the kinds an entry can carry.\n -- See docs/spec/journal.md § A purge destroys the journal.\n kind TEXT NOT NULL CHECK (kind IN ('created', 'changed', 'removed')),\n ops TEXT NOT NULL CHECK (json_valid(ops)),\n version INTEGER NOT NULL,\n type_id TEXT NOT NULL,\n parent_id TEXT,\n -- NULL means the entry names no origin (the record did not move);\n -- '' means it moved off the root. parent_id above needs no such\n -- spelling: it is state, where this is a key that may be absent --\n -- the same input/state split parentId follows everywhere.\n previous_parent_id TEXT,\n actor TEXT CHECK (actor IS NULL OR json_valid(actor)),\n -- One tagged edit per association the write moved, each carrying the\n -- state it displaced. See docs/spec/journal.md § The entry.\n associations TEXT CHECK (associations IS NULL OR json_valid(associations)),\n PRIMARY KEY (record_id, seq)\n ) STRICT;\n\n CREATE TABLE IF NOT EXISTS types (\n id TEXT PRIMARY KEY,\n base_id TEXT NOT NULL,\n version INTEGER NOT NULL,\n name TEXT NOT NULL,\n schema TEXT NOT NULL CHECK (json_valid(schema)),\n schema_hash TEXT NOT NULL,\n migrates_from TEXT,\n created_at INTEGER NOT NULL\n ) STRICT;\n\n -- One row per top-level scalar content field a record holds a value at:\n -- what it orders as, and the file it references. See\n -- docs/spec/data-model.md § Sorting by a content field.\n --\n -- value_rank is 0 for a numeric value and 1 for a text one — the same\n -- split as \"num_value IS NULL\", but non-null, so one index can carry\n -- the whole ordering. file_id is set only for a 'file-ref' field.\n CREATE TABLE IF NOT EXISTS content_index (\n record_id TEXT NOT NULL REFERENCES records(id),\n field TEXT NOT NULL,\n value_rank INTEGER NOT NULL CHECK (value_rank IN (0, 1)),\n num_value REAL,\n text_key TEXT,\n text_value TEXT,\n file_id TEXT,\n PRIMARY KEY (record_id, field)\n ) STRICT;\n\n -- Each filter column continues into (created_at, id), the default order\n -- and its tiebreak: these columns are low-cardinality, and a narrow index\n -- leaves the planner sorting every match before it can honor LIMIT.\n -- deleted_at and unlisted_at get none: an index on a column every query\n -- tests IS NULL only lures the planner off the one answering ORDER BY.\n CREATE INDEX IF NOT EXISTS idx_records_type_id ON records(type_id, created_at, id);\n CREATE INDEX IF NOT EXISTS idx_records_parent_id ON records(parent_id, created_at, id);\n CREATE INDEX IF NOT EXISTS idx_records_entity_id ON records(entity_id, created_at, id);\n CREATE INDEX IF NOT EXISTS idx_records_app_id ON records(app_id, created_at, id);\n CREATE INDEX IF NOT EXISTS idx_records_principal_id ON records(principal_id, created_at, id);\n CREATE INDEX IF NOT EXISTS idx_records_created_at ON records(created_at, id);\n CREATE INDEX IF NOT EXISTS idx_records_updated_at ON records(updated_at, id);\n CREATE INDEX IF NOT EXISTS idx_records_version ON records(version, id);\n\n -- Each association index ends with record_id so the semi-joins in\n -- query.ts read the matching record ids out of the index alone.\n -- idx_assoc_related carries related_ns ahead of related_id because a\n -- record- or entity-scoped target always stores '' there, which\n -- buildQueryPlan states explicitly to keep the prefix contiguous.\n CREATE INDEX IF NOT EXISTS idx_assoc_kind_label ON associations(kind, label, record_id);\n CREATE INDEX IF NOT EXISTS idx_assoc_kind_file_id ON associations(kind, file_id, record_id);\n CREATE INDEX IF NOT EXISTS idx_assoc_related ON associations(kind, related_scope, related_ns, related_id, record_id);\n CREATE INDEX IF NOT EXISTS idx_types_base_id ON types(base_id, version);\n\n -- The permissions key with record_id moved last, so a scoped query reads\n -- the records carrying an element straight out of the index.\n CREATE INDEX IF NOT EXISTS idx_permissions_element\n ON permissions(kind, label, grantee_kind, grantee_id, role, record_id);\n\n -- The whole content ordering, in index order, for one field at a time:\n -- a content-sorted page is an ordered walk of a slice of this index.\n CREATE INDEX IF NOT EXISTS idx_content_index_sort\n ON content_index(field, value_rank, num_value, text_key, text_value, record_id);\n CREATE INDEX IF NOT EXISTS idx_content_index_file\n ON content_index(file_id, record_id) WHERE file_id IS NOT NULL;\n`;\n\n/**\n * Bearer-token storage backing StackTokenStore. Kept separate from\n * RECORD_SCHEMA_SQL so an adapter can put it in its own file — the\n * portable stack file shouldn't also carry a server's auth material.\n */\nexport const TOKENS_SCHEMA_SQL = `\n CREATE TABLE IF NOT EXISTS tokens (\n id TEXT PRIMARY KEY,\n token_hash TEXT NOT NULL UNIQUE,\n principal_id TEXT NOT NULL,\n subject_id TEXT NOT NULL,\n label TEXT,\n created_at INTEGER NOT NULL,\n expires_at INTEGER\n ) STRICT;\n`;\n\n/**\n * The full-text index behind `StackQuery.filter.search` (see indexes.ts).\n * What `columnsize=0` costs a reader is in docs/spec/adapters.md\n * § SQLite-backed adapters. `detail` stays at its default: sanitizeFts5Query\n * passes phrase queries through, and a phrase needs the token positions\n * only that setting records.\n */\nexport const FTS5_SCHEMA_SQL = `\n CREATE VIRTUAL TABLE IF NOT EXISTS records_fts USING fts5(\n content,\n content='records',\n content_rowid='rowid',\n columnsize=0\n );\n`;\n\n/**\n * Enforces the REFERENCES constraints declared above (off by default per\n * SQLite connection), so touching a nonexistent record fails loudly\n * instead of creating an orphan row. Adapters map the constraint\n * violation to StackNotFoundError at the call sites that can trigger it.\n */\nexport const PRAGMA_FOREIGN_KEYS_ON = `PRAGMA foreign_keys = ON;`;\n\n/**\n * WAL journaling: page-level writes, crash-safe without our own\n * temp-file-and-rename dance, and real SQLite file locking. Only\n * meaningful for a real file (a :memory: database silently ignores it).\n */\nexport const PRAGMA_JOURNAL_MODE_WAL = `PRAGMA journal_mode = WAL;`;\n\nexport type RecordSchemaOptions = {\n /**\n * Whether to put the connection in WAL mode. False for an engine that\n * owns its own durability and rejects the pragma outright, as Durable\n * Object storage does.\n */\n wal: boolean;\n};\n\n/**\n * Brings a records database up to the schema every SQLite record adapter\n * expects: foreign keys on, then the tables and the FTS5 index. Every\n * statement is idempotent, so an engine that cannot tell\n * whether a store exists can run this on each attach.\n */\nexport const applyRecordSchema = (exec: SqlExecutor, opts: RecordSchemaOptions): void => {\n exec.exec(PRAGMA_FOREIGN_KEYS_ON);\n if (opts.wal) exec.exec(PRAGMA_JOURNAL_MODE_WAL);\n exec.exec(RECORD_SCHEMA_SQL);\n exec.exec(FTS5_SCHEMA_SQL);\n};\n","/**\n * FTS5 query sanitization: turning what a person typed into a search box\n * into a query FTS5 will parse. Indexing lives in indexes.ts.\n *\n * FTS5's query language supports operators (AND/OR/NOT, phrases, NEAR,\n * wildcards) that can be expensive or cause parse errors with untrusted\n * input, so a search string is rewritten before it reaches the engine:\n *\n * kept: AND/OR/NOT (with a left operand), phrase queries (\"…\"), implicit AND\n * removed: wildcards (*), NEAR(...) (terms kept, wrapper dropped), every\n * character outside the allow-list, bare NOT (no left operand),\n * operators with no right operand\n * capped: parenthesis nesting depth (default: 2)\n * closed: an odd trailing quote\n *\n * Two FTS5 grammar details drive the less obvious rules:\n *\n * - FTS5's NEAR is a function-call form — `NEAR(a b, 10)`. Deleting the\n * whole span would also delete the terms inside it, which can leave a\n * dangling operator when NEAR(...) sits next to AND/OR (e.g. \"x AND\n * NEAR(a b, 5)\" -> \"x AND\" — a syntax error). So this keeps the terms\n * and drops only the NEAR(...) wrapper and distance.\n * - FTS5 has real column-filter syntax and errors hard on any name but\n * the table's actual columns. It is wider than `colname:term`: `-name`\n * and `{a b}` filter columns with no colon at all, so an ordinary\n * hyphenated word is read as one. Since records_fts has exactly one\n * column and callers have no business targeting columns explicitly,\n * everything outside a phrase is reduced to an allow-list rather than\n * validated — see OUTSIDE_PHRASE_DISALLOWED.\n *\n * The rewrite is best-effort and makes no completeness claim against\n * FTS5's grammar — which is why the caller wraps execution as well, so a\n * case this misses surfaces as a StackBadRequestError rather than a raw engine\n * error. Search text is what a person typed into a box: an unbalanced\n * quote or a trailing \"AND\" is ordinary input, not a malformed request.\n *\n * What this bounds is the grammar, not the cost: a syntactically modest\n * search over a large index can still be expensive, and node:sqlite blocks\n * the calling thread, so there is no timeout to set from inside the call.\n * Bounding execution time belongs to whoever drives the engine under load\n * — see docs/spec/wire-format.md § Bounding query cost for the server-side\n * expectation and the `timeout` wire error that goes with it.\n *\n * Backtracking. The input is untrusted text, so every regex here is\n * written not to backtrack quadratically on it:\n *\n * - Whitespace runs are collapsed before any rule that spells \"beside an\n * operator or paren\" as `\\s*`; a `\\s*` facing a long run re-tries the\n * whole run per starting position. The rewrite is still a little\n * worse than linear overall, so bounding a search's length belongs to\n * whoever accepts it.\n * - The NEAR rule has no `\\s*` after its paren (its `[^,()]*` already\n * takes a space, and two quantifiers matching the same character give\n * the engine an ambiguous split), and neither of its runs crosses a\n * `(`, so an unclosed `NEAR(NEAR(NEAR(` doesn't re-scan to the end once\n * per occurrence.\n * - The no-right-operand rule has no leading `\\s*`, for the same reason\n * as the collapse.\n * - The operand-before-paren rule's lookbehind pins each match to the\n * start of a word; without it every position inside a long word is a\n * start, each re-scanning the rest of it.\n * - Empty phrases and empty paren pairs are removed by one rule, so a run\n * of them becomes one space rather than one per construct.\n */\n\n/**\n * Outside a phrase, everything but a letter, digit, mark, underscore,\n * whitespace, paren or quote becomes a separator. An allow-list because\n * FTS5's column-filter syntax is wider than any list of metacharacters.\n * See docs/spec/data-model.md § Capability-gated filters.\n */\nconst OUTSIDE_PHRASE_DISALLOWED = /[^\\p{L}\\p{N}\\p{M}_\\s()\"]/gu;\n\n/**\n * Bounds what any `\\s*` can backtrack over (see Backtracking above). Safe\n * inside a phrase too: FTS5 matches a phrase as a sequence of tokens, not\n * the spacing between them.\n */\nconst collapseWhitespace = (query: string): string => query.replace(/\\s+/g, ' ');\n\nexport const sanitizeFts5Query = (query: string, maxDepth = 2): string => {\n if (!query) return '';\n\n // Drop control characters, inside a phrase as well as outside. A NUL in\n // particular ends the string early for SQLite's C API, so the engine sees\n // an opening quote whose closing one is past the truncation and reports an\n // unterminated string; none of them can match an indexed token anyway.\n let clean = query.replace(/[\\p{Cc}\\p{Cf}]/gu, ' ');\n\n clean = clean.replace(/\\*/g, '');\n\n // NEAR(terms, distance) keeps its terms — see the note above. The\n // pattern's shape is about backtracking (see Backtracking); excluding `(`\n // costs nothing, since a NEAR's terms and distance never hold one.\n clean = clean.replace(/\\bNEAR\\s*\\(([^,()]*)(?:,[^()]*)?\\)/gi, '$1');\n\n // A NEAR( with no closing paren isn't the function-call form the rule\n // above rewrites, and the paren auto-close below would hand FTS5 a NEAR\n // call it never meant to write. Keep the grouping, drop the keyword.\n clean = clean.replace(/\\bNEAR\\s*\\(/gi, '(');\n\n // See OUTSIDE_PHRASE_DISALLOWED.\n clean = clean.replace(/\"[^\"]*\"|[^\"]+/g, (span) =>\n span.startsWith('\"') ? span : span.replace(OUTSIDE_PHRASE_DISALLOWED, ' '),\n );\n\n // The reduction above is where long whitespace runs come from.\n clean = collapseWhitespace(clean);\n\n // Strip bare NOT with no left operand — FTS5 requires \"term NOT term\", not\n // \"NOT term\". A phrase is matched first and kept whole, so a NOT inside one\n // stays the word it is; the closing quote is optional because an odd one\n // is only closed further down.\n clean = clean.replace(/\"[^\"]*\"?|(^|\\(\\s*)NOT\\s+/gi, (m, lead?: string) => lead ?? m);\n\n // Enforce max nesting depth; replace excess ( with a space and discard\n // unmatched ). Parens inside a phrase are literal text to FTS5, so the\n // depth count steps over quoted spans rather than reading them as syntax.\n let currentDepth = 0;\n let inPhrase = false;\n let result = '';\n for (const char of clean) {\n if (char === '\"') {\n inPhrase = !inPhrase;\n result += char;\n } else if (inPhrase) {\n result += char;\n } else if (char === '(') {\n if (currentDepth < maxDepth) {\n currentDepth++;\n result += char;\n } else result += ' ';\n } else if (char === ')') {\n if (currentDepth > 0) {\n currentDepth--;\n result += char;\n } else result += ' ';\n } else {\n result += char;\n }\n }\n\n // Close an odd trailing quote before the parens, so the added ) lands\n // outside the phrase rather than becoming a literal character in it.\n if (inPhrase) result += '\"';\n\n if (currentDepth > 0) result += ')'.repeat(currentDepth);\n\n // Looped to a fixpoint because each rule can create work for another:\n // dropping an operator can empty a pair (\"(a AND)\"), dropping a pair can\n // strand an operator (\"x AND ()\"), and an empty phrase's quotes can\n // re-pair once text is inserted beside it.\n let prev: string;\n do {\n prev = result;\n // Empty phrases and empty paren pairs match nothing. One rule for both\n // (see Backtracking).\n result = result.replace(/(?:\"\"|\\(\\s*\\))+/g, ' ');\n result = dropDanglingOperators(result);\n result = restoreImplicitAnd(result);\n } while (result !== prev);\n\n return collapseWhitespace(result).replace(/\\(\\s+/g, '(').replace(/\\s+\\)/g, ')').trim();\n};\n\n/** An operator FTS5 requires a term on both sides of. */\nconst OPERATOR = String.raw`(?:AND|OR|NOT)`;\n\n/**\n * Stands in for a phrase while operators are rewritten. A private-use\n * character is not a word character, so `\\b` still sees an operator beside\n * it, while the anchors see an operand. A literal U+E000 in the input is\n * one FTS5 tokenizes away regardless.\n */\nconst PHRASE_HOLE = '\\u{E000}';\n\n/**\n * Drop operators left without an operand — typed on the way to a longer\n * query (\"cats AND\"), or left behind once a rule above removed a term.\n * FTS5 rejects each outright. Phrases are masked: inside one, an operator\n * is a word the user searched for.\n */\nconst dropDanglingOperators = (query: string): string =>\n withPhrasesMasked(query, (masked) => {\n let out = masked;\n let prev: string;\n do {\n prev = out;\n // A run of operators keeps only the first — the rest have no left operand.\n out = out.replace(\n new RegExp(String.raw`\\b(${OPERATOR})\\b(?:\\s+\\b${OPERATOR}\\b)+`, 'gi'),\n '$1',\n );\n // No left operand: at the start of the query or straight after \"(\".\n out = out.replace(new RegExp(String.raw`(^|\\()\\s*\\b${OPERATOR}\\b\\s*`, 'gi'), '$1');\n // No right operand: at the end of the query or straight before \")\".\n // No leading `\\s*` (see Backtracking); the collapse on the way out\n // takes that whitespace.\n out = out.replace(new RegExp(String.raw`\\b${OPERATOR}\\b\\s*($|\\))`, 'gi'), '$1');\n } while (out !== prev);\n return out;\n });\n\n/**\n * Run `rewrite` over the query with each phrase swapped for PHRASE_HOLE,\n * then put the phrases back in order. Every rule that reasons about what\n * sits beside an operator or a paren needs this: inside a phrase the text\n * is literal, and from outside one the phrase is a single operand.\n */\nconst withPhrasesMasked = (query: string, rewrite: (masked: string) => string): string => {\n const phrases: string[] = [];\n const masked = query.replace(/\"[^\"]*\"/g, (phrase) => {\n phrases.push(phrase);\n return PHRASE_HOLE;\n });\n let i = 0;\n return rewrite(masked).replace(new RegExp(PHRASE_HOLE, 'g'), () => phrases[i++]);\n};\n\nconst OPERAND_CHAR = String.raw`[\\p{L}\\p{N}_${PHRASE_HOLE}]`;\n\n/** A whole word, never a prefix: the `D` of `AND` is not a term. */\nconst isOperator = (word: string): boolean => /^(?:AND|OR|NOT)$/i.test(word);\n\n/**\n * Put back the operator FTS5 requires beside a group: `cats dogs` is an\n * implicit AND, but `cats (dogs)` is a syntax error. A rewrite that strips\n * the operator beside a group keeps the grouping, so this writes back the\n * AND that was meant. A masked phrase is an operand like any other.\n */\nconst restoreImplicitAnd = (query: string): string =>\n withPhrasesMasked(query, (masked) =>\n masked\n // \")\" then an operand — \") cats\", \") (\", \") <phrase>\" — unless that\n // operand is an operator, which already joins the two sides.\n .replace(\n new RegExp(String.raw`\\)\\s*(?=${OPERAND_CHAR}|\\()`, 'gu'),\n (match, offset: number, whole: string) => {\n const next = /^\\s*([\\p{L}\\p{N}_]+)/u.exec(whole.slice(offset + match.length));\n return next && isOperator(next[1]) ? match : ') AND ';\n },\n )\n // An operand then \"(\", unless the operand is an operator. The\n // lookbehind is load-bearing (see Backtracking).\n .replace(\n new RegExp(String.raw`(?<!${OPERAND_CHAR})(${OPERAND_CHAR}+)\\s*(?=\\()`, 'gu'),\n (match, word: string) => (isOperator(word) ? match : `${word} AND `),\n ),\n );\n","/**\n * Normalizes a SQLite binding's call convention (array-bind-then-step,\n * spread-args run/get/all, cursor-returning exec) behind one interface,\n * so the actual CRUD/query/version/type/association/token logic can live\n * once in this package instead of being re-typed per engine. Each adapter\n * package provides a thin SqlExecutor implementation over its own\n * database handle.\n *\n * Deliberately synchronous: every binding this targets executes queries\n * in-process without yielding, and an async interface would force the\n * shared logic's transaction sequences to interleave.\n */\nexport interface SqlExecutor {\n /** Run DDL, pragmas, or any statement(s) with no bound params and no results needed. */\n exec(sql: string): void;\n /** Run a single parameterized statement. Returns the number of rows affected (INSERT/UPDATE/DELETE). */\n run(sql: string, params?: readonly unknown[]): number;\n /** Run a parameterized statement and return the first result row, or undefined. */\n get<T = Record<string, unknown>>(sql: string, params?: readonly unknown[]): T | undefined;\n /** Run a parameterized statement and return all result rows. */\n all<T = Record<string, unknown>>(sql: string, params?: readonly unknown[]): T[];\n /**\n * Run `fn` atomically: every statement it issues commits, or none do if it\n * throws. A callback rather than BEGIN/COMMIT text because some engines\n * only offer one (a Durable Object's storage.transactionSync); for the\n * same reason `fn` must be synchronous and use only this executor.\n */\n transaction<T>(fn: () => T): T;\n}\n\n/** SQLite reports FK violations with this exact message; verify it holds when adding an engine. */\nexport const isForeignKeyViolation = (err: unknown): boolean =>\n err instanceof Error && err.message.includes('FOREIGN KEY constraint failed');\n\n/** SQLite reports a PRIMARY KEY/UNIQUE collision with this exact message. */\nexport const isUniqueConstraintViolation = (err: unknown): boolean =>\n err instanceof Error && err.message.includes('UNIQUE constraint failed');\n","import type { SqlExecutor } from './executor.js';\n\n/** timezone is optional passthrough app metadata — no default. */\nexport type StackConfig = { entityId: string; timezone: string | undefined };\n\n/** The one place the singleton record's id is spelled. */\nconst CONFIG_ROW_SQL = `SELECT content FROM records WHERE id = '_config'`;\n\n/**\n * Inserts the singleton _config@1 record and returns what it wrote, so a\n * caller that has just created a database reaches the same StackConfig an\n * existing one yields without a read-back. Only valid on a freshly-created\n * database.\n */\nexport const insertConfigRecord = (\n exec: SqlExecutor,\n entityId: string,\n timezone: string | undefined,\n): StackConfig => {\n const now = Date.now();\n exec.run(\n `INSERT INTO records (id, type_id, created_at, updated_at, content, version)\n VALUES ('_config', '_config@1', ?, ?, ?, 1)`,\n [now, now, JSON.stringify({ entityId, timezone })],\n );\n return { entityId, timezone };\n};\n\n/**\n * Reads the singleton _config@1 record, or null if this database has none.\n * Null is the signal an engine that cannot tell from the outside whether a\n * store exists (a Durable Object) uses to decide between reattaching and creating.\n */\nexport const tryReadStackConfig = (exec: SqlExecutor): StackConfig | null => {\n const row = exec.get<{ content: string }>(CONFIG_ROW_SQL);\n if (!row) return null;\n const content = JSON.parse(row.content) as { entityId: string; timezone?: string };\n return { entityId: content.entityId, timezone: content.timezone };\n};\n\n/** Reads the singleton _config@1 record. Throws if the database is missing it. */\nexport const readStackConfig = (exec: SqlExecutor): StackConfig => {\n const config = tryReadStackConfig(exec);\n if (!config) throw new Error('Stack database is missing its config record.');\n return config;\n};\n","/**\n * Cursor encode/decode for keyset pagination. The payload is JSON in\n * base64 rather than delimited fields: a content sort carries the field's\n * stored text, and neither a field name nor a text value is constrained\n * to avoid whatever character a delimiter would claim. Uses btoa/atob\n * with an explicit UTF-8 step rather than Node's Buffer, so the codec\n * stays runtime-agnostic and a non-Latin-1 value survives the round trip.\n */\n\nimport { NATIVE_SORT_FIELDS, StackBadRequestError } from '@haverstack/core';\nimport { constantSortEntry, contentSortEntry } from '@haverstack/core/adapter';\nimport type { AdapterSort, SortEntry } from '@haverstack/core/adapter';\nimport type {\n ContentSortKey,\n StackRecord,\n NativeSortField,\n ScalarFieldKind,\n} from '@haverstack/core';\n\n/**\n * Which partition of the ordering a cursor sits in: a native column or a\n * content field's number, text, or absent value. The three content cases\n * are the boundary keyset pagination has to hold — a page that ended on\n * the last numeric value resumes at the first text one, not back at the\n * top of either.\n */\nexport type CursorKind = 'native' | 'num' | 'text' | 'absent';\n\nexport type DecodedCursor =\n | { kind: 'native'; field: NativeSortField; value: number; id: string }\n | { kind: 'num'; field: string; value: number; id: string }\n | { kind: 'text'; field: string; value: string; id: string }\n | { kind: 'absent'; field: string; id: string };\n\nconst toBase64 = (text: string): string => {\n const bytes = new TextEncoder().encode(text);\n let binary = '';\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary);\n};\n\nconst fromBase64 = (cursor: string): string => {\n const binary = atob(cursor);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return new TextDecoder().decode(bytes);\n};\n\nexport const encodeCursor = (decoded: DecodedCursor): string =>\n toBase64(\n JSON.stringify(\n decoded.kind === 'absent'\n ? { k: decoded.kind, f: decoded.field, i: decoded.id }\n : { k: decoded.kind, f: decoded.field, i: decoded.id, v: decoded.value },\n ),\n );\n\n/** Throws StackBadRequestError for any malformed, corrupt, or unrecognized cursor. */\nexport const decodeCursor = (cursor: string): DecodedCursor => {\n const malformed = () => new StackBadRequestError(`Invalid cursor: malformed \"${cursor}\"`);\n let parsed: unknown;\n try {\n parsed = JSON.parse(fromBase64(cursor));\n } catch {\n throw malformed();\n }\n if (!parsed || typeof parsed !== 'object') throw malformed();\n const { k, f, i, v } = parsed as Record<string, unknown>;\n if (typeof f !== 'string' || !f || typeof i !== 'string') throw malformed();\n\n if (k === 'absent') return { kind: 'absent', field: f, id: i };\n if (k === 'text') {\n if (typeof v !== 'string') throw malformed();\n return { kind: 'text', field: f, value: v, id: i };\n }\n if (k === 'num' || k === 'native') {\n if (typeof v !== 'number' || !isFinite(v)) {\n throw new StackBadRequestError(`Invalid cursor: non-numeric sort value`);\n }\n if (k === 'native') {\n if (!NATIVE_SORT_FIELDS.includes(f as NativeSortField)) {\n throw new StackBadRequestError(`Invalid cursor: unknown sort field \"${f}\"`);\n }\n return { kind: 'native', field: f as NativeSortField, value: v, id: i };\n }\n return { kind: 'num', field: f, value: v, id: i };\n }\n throw malformed();\n};\n\n/**\n * The name a cursor carries for a `contentFieldByType` sort: the map\n * itself, keys in order, so a cursor resumes only the map it was minted\n * under.\n */\nexport const byTypeDescriptor = (byType: Record<string, ContentSortKey>): string =>\n JSON.stringify(Object.entries(byType).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)));\n\nexport const getSortColumn = (field: NativeSortField): string =>\n field === 'createdAt' ? 'created_at' : field === 'updatedAt' ? 'updated_at' : 'version';\n\n/**\n * The cursor naming the last record of a page: where the next page\n * resumes. A content sort re-derives the record's ordered value from its\n * stored content rather than reading it back out of the index, so the\n * cursor and the index can only ever disagree if the write path is\n * broken — in which case pagination is not the thing to paper over.\n */\nexport const makeCursor = (\n record: StackRecord,\n sort: AdapterSort,\n kindOf?: (record: StackRecord, field: string) => ScalarFieldKind | undefined,\n): string => {\n const byType = sort.contentFieldByType;\n if (byType) {\n const field = byTypeDescriptor(byType);\n const key = Object.hasOwn(byType, record.typeId) ? byType[record.typeId] : undefined;\n const kind = key?.field === undefined ? undefined : kindOf?.(record, key.field);\n const entry =\n key?.field !== undefined\n ? kind && contentSortEntry(kind, record.content[key.field])\n : key && constantSortEntry(key.value ?? null);\n return encodeEntry(field, entry || null, record.id);\n }\n const { contentField, field } = sort;\n if (field !== undefined) {\n const value =\n field === 'updatedAt'\n ? record.updatedAt.getTime()\n : field === 'version'\n ? record.version\n : record.createdAt.getTime();\n return encodeCursor({ kind: 'native', field, value, id: record.id });\n }\n\n const kind = kindOf?.(record, contentField);\n const entry = kind ? contentSortEntry(kind, record.content[contentField]) : null;\n return encodeEntry(contentField, entry, record.id);\n};\n\nconst encodeEntry = (field: string, entry: SortEntry | null, id: string): string => {\n if (!entry) return encodeCursor({ kind: 'absent', field, id });\n return entry.kind === 'num'\n ? encodeCursor({ kind: 'num', field, value: entry.num, id })\n : encodeCursor({ kind: 'text', field, value: entry.text, id });\n};\n","/**\n * Row <-> domain object mappers shared by every SQLite-backed record\n * adapter. Column names and JSON-encoding choices are the storage\n * contract; keeping one copy means the adapters can't drift on them.\n */\n\nimport type {\n Actor,\n AuthorityAssociation,\n DataAssociation,\n GroupRole,\n RecordJournalEntry,\n StackRecord,\n StackType,\n RecordVersion,\n RelationshipTarget,\n} from '@haverstack/core';\n\nexport const toMs = (d: Date): number => d.getTime();\n\n/**\n * An Actor from its two columns. A principal with no subject beside it\n * names nobody to attribute to, so it reads as absent like the subject.\n */\nconst actorFromColumns = (subject: unknown, principal: unknown): Actor | undefined =>\n subject == null\n ? undefined\n : {\n subjectId: subject as string,\n ...(principal != null && { principalId: principal as string }),\n };\nexport const fromMs = (ms: number): Date => new Date(ms);\n\nexport const rowToRecord = (\n row: Record<string, unknown>,\n associations: DataAssociation[],\n permissions: AuthorityAssociation[],\n): StackRecord => {\n const record: StackRecord = {\n id: row.id as string,\n typeId: row.type_id as string,\n createdAt: fromMs(row.created_at as number),\n updatedAt: fromMs(row.updated_at as number),\n content: JSON.parse(row.content as string),\n version: row.version as number,\n };\n // Presence, never truthiness: SQL NULL is the only spelling of an absent\n // field, so the empty string and the epoch are values like any other.\n // The query predicates beside this read `IS NULL`, and a mapper that\n // disagreed would let a record answer one way to get() and another to\n // the filter that should have found it.\n if (row.parent_id != null) record.parentId = row.parent_id as string;\n if (row.app_id != null) record.appId = row.app_id as string;\n const createdBy = actorFromColumns(row.entity_id, row.principal_id);\n if (createdBy) record.createdBy = createdBy;\n const updatedBy = actorFromColumns(row.updated_by, row.updated_via);\n if (updatedBy) record.updatedBy = updatedBy;\n if (row.deleted_at != null) record.deletedAt = fromMs(row.deleted_at as number);\n if (row.unlisted_at != null) record.unlistedAt = fromMs(row.unlisted_at as number);\n if (associations.length) record.associations = associations;\n if (permissions.length) record.permissions = permissions;\n return record;\n};\n\nexport const rowToAssociation = (row: Record<string, unknown>): DataAssociation => {\n if (row.kind === 'tag') {\n return { kind: 'tag', label: row.label as string };\n }\n if (row.kind === 'attachment') {\n const attachmentRecordId = row.attachment_record_id as string;\n return {\n kind: 'attachment',\n label: row.label as string,\n fileId: row.file_id as string,\n // Stored as '' when absent, like every other optional column here —\n // the field is omitted rather than served empty, so a round trip\n // produces the association the caller wrote.\n ...(attachmentRecordId && { attachmentRecordId }),\n };\n }\n return {\n kind: 'relationship',\n label: row.label as string,\n target: rowToTarget(row),\n };\n};\n\n/**\n * The five columns that identify an association beyond its kind and\n * label, in the order every INSERT and DELETE below binds them. One helper\n * because the two must agree exactly — a remove that bound them\n * differently would delete nothing and report success.\n */\nexport const associationKeyColumns = (\n a: DataAssociation,\n): [string, string, string, string, string] => {\n if (a.kind === 'attachment') return [a.fileId, '', '', '', ''];\n if (a.kind !== 'relationship') return ['', '', '', '', ''];\n const t = a.target;\n if (t.kind === 'entity') return ['', 'entity', t.entityId, '', ''];\n if (t.kind === 'external') return ['', 'external', t.id, t.ns, ''];\n return ['', 'record', t.recordId, '', t.stackUrl ?? ''];\n};\n\n/**\n * The three columns that identify a permission element beyond its kind\n * and label — grantee kind, id and role, all '' for `anyone` — in the\n * order every INSERT and DELETE binds them.\n */\nexport const permissionKeyColumns = (p: AuthorityAssociation): [string, string, string] => {\n if (p.kind === 'anyone') return ['', '', ''];\n const g = p.grantee;\n return g.kind === 'entity' ? ['entity', g.entityId, ''] : ['group', g.groupId, g.role];\n};\n\nexport const rowToPermission = (row: Record<string, unknown>): AuthorityAssociation => {\n if (row.kind === 'anyone') return { kind: 'anyone', label: 'read' };\n const id = row.grantee_id as string;\n return {\n kind: 'permission',\n label: row.label as 'read' | 'write',\n grantee:\n row.grantee_kind === 'group'\n ? { kind: 'group', groupId: id, role: row.role as GroupRole }\n : { kind: 'entity', entityId: id },\n };\n};\n\nconst rowToTarget = (row: Record<string, unknown>): RelationshipTarget => {\n const id = row.related_id as string;\n if (row.related_scope === 'entity') return { kind: 'entity', entityId: id };\n if (row.related_scope === 'external') {\n return { kind: 'external', ns: row.related_ns as string, id };\n }\n const stackUrl = row.related_stack as string;\n return { kind: 'record', recordId: id, ...(stackUrl && { stackUrl }) };\n};\n\nexport const rowToType = (row: Record<string, unknown>): StackType => {\n const t: StackType = {\n id: row.id as string,\n baseId: row.base_id as string,\n version: row.version as number,\n name: row.name as string,\n schema: JSON.parse(row.schema as string),\n schemaHash: row.schema_hash as string,\n createdAt: fromMs(row.created_at as number),\n };\n if (row.migrates_from) t.migratesFrom = row.migrates_from as string;\n return t;\n};\n\nexport const rowToVersion = (row: Record<string, unknown>): RecordVersion => {\n const v: RecordVersion = {\n version: row.version as number,\n typeId: row.type_id as string,\n content: JSON.parse(row.content as string),\n updatedAt: fromMs(row.updated_at as number),\n };\n const createdBy = actorFromColumns(row.entity_id, row.principal_id);\n if (createdBy) v.createdBy = createdBy;\n const updatedBy = actorFromColumns(row.updated_by, row.updated_via);\n if (updatedBy) v.updatedBy = updatedBy;\n return v;\n};\n\n/**\n * One journal row. `previous_parent_id` carries the three-way spelling the\n * column comment states: SQL NULL is an entry naming no origin, '' is the\n * root, anything else is a container id.\n */\nexport const rowToJournalEntry = (row: Record<string, unknown>): RecordJournalEntry => {\n const e: RecordJournalEntry = {\n seq: row.seq as number,\n at: fromMs(row.at as number),\n kind: row.kind as RecordJournalEntry['kind'],\n ops: JSON.parse(row.ops as string),\n version: row.version as number,\n typeId: row.type_id as string,\n };\n if (row.parent_id != null) e.parentId = row.parent_id as string;\n if (row.previous_parent_id != null) {\n e.previousParentId = row.previous_parent_id === '' ? null : (row.previous_parent_id as string);\n }\n if (row.actor != null) e.actor = JSON.parse(row.actor as string);\n if (row.associations != null) e.associations = JSON.parse(row.associations as string);\n return e;\n};\n","/**\n * StackQuery -> SQL. Engine-independent — shared verbatim between\n * SQLite-backed record adapters. The one caveat is full-text search:\n * `f.search` here assumes a `records_fts` virtual table with a MATCH-able\n * `content` column (see FTS5_SCHEMA_SQL in schema.ts).\n *\n * A query compiles to a plan rather than to a single statement, because a\n * content-field sort is two orderings end to end: the records that hold a\n * value at the field, ordered by it, then the records that hold none,\n * ordered by id. Reading them as two statements lets each one walk an\n * index in order and stop at the page boundary; the LEFT JOIN that would\n * express the same result in one statement can only be sorted after the\n * fact, which costs a full pass over the table for every page.\n */\n\nimport {\n StackBadRequestError,\n type AuthorityAssociation,\n type ContentArm,\n type ContentSortKey,\n type NativeSortField,\n} from '@haverstack/core';\nimport { constantSortEntry, contentSortKey, parseContentFilterKey } from '@haverstack/core/adapter';\nimport type { AdapterQuery, Reach, SortEntry } from '@haverstack/core/adapter';\nimport { byTypeDescriptor, decodeCursor, getSortColumn, type DecodedCursor } from './cursor.js';\nimport { sanitizeFts5Query } from './fts5.js';\nimport { permissionKeyColumns } from './mappers.js';\n\n/** One statement plus the parameters it binds, in textual order. */\nexport type QueryStatement = { sql: string; params: unknown[] };\n\n/**\n * A page statement with the row budget its trailing `LIMIT ?` binds.\n * buildQueryPlan leaves that parameter off, so the budget is never one of\n * the parameters the query itself bound: the second partition of a\n * content sort asks for what the first left of the page rather than for a\n * page it then discards.\n */\nexport const atBudget = (page: QueryStatement, rows: number): QueryStatement => ({\n sql: page.sql,\n params: [...page.params, rows],\n});\n\n/**\n * The direction as SQL text. Mapped from a fixed pair rather than\n * interpolated, as getSortColumn() maps the field, so no value reaches\n * the statement but `ASC` or `DESC`.\n */\nconst sqlDirection = (query: AdapterQuery): 'ASC' | 'DESC' =>\n query.sort.direction === 'asc' ? 'ASC' : 'DESC';\n\n/**\n * Normalize a json_each row's value so one array element and one bare\n * value are walked by the same clause: an array stands for its elements,\n * anything else for itself. A boolean is rewrapped from its type, since\n * json_each's `value` reads it as 0 or 1. See docs/spec/data-model.md\n * § Nested content paths.\n */\nconst spread = (alias: string): string =>\n `CASE ${alias}.type WHEN 'array' THEN ${alias}.value ` +\n `WHEN 'object' THEN json_array(json(${alias}.value)) ` +\n `WHEN 'true' THEN '[true]' WHEN 'false' THEN '[false]' ` +\n `ELSE json_array(${alias}.value) END`;\n\n/**\n * The members of a walk row that is an object, and none for a row that is\n * not — a path descending through a scalar reaches no value rather than\n * reaching an error.\n */\nconst members = (alias: string): string =>\n `CASE WHEN ${alias}.t = 'object' THEN ${alias}.v ELSE '{}' END`;\n\n/**\n * One statement as it is built: its tables, then its conditions on `r` and\n * the parameters its text binds, in textual order. Every table's parameter\n * binds ahead of the text's, since the tables lead the statement.\n */\ntype Statement = {\n tables: string[];\n tableParams: unknown[];\n conditions: string[];\n params: unknown[];\n};\n\nconst emptyStatement = (): Statement => ({\n tables: [],\n tableParams: [],\n conditions: [\"r.id != '_config'\"],\n params: [],\n});\n\n/**\n * Tuples as a table of `s` with `columns`, named in tuple order: the one\n * shape a caller-sized part of a query takes. It binds as one JSON\n * parameter, so the statement never grows with it, and is materialized\n * once, so nothing that reads it per record re-parses the JSON. Returns the\n * table's name. See docs/spec/adapters.md § Statement size.\n */\nconst rows = (s: Statement, columns: readonly string[], tuples: unknown[][]): string => {\n const name = `t${s.tables.length}`;\n s.tables.push(`${name} AS MATERIALIZED ${rowsTable(columns)}`);\n s.tableParams.push(JSON.stringify(tuples));\n return name;\n};\n\n/** The table rows() binds, for a statement outside the query plan. */\nexport const rowsTable = (columns: readonly string[]): string => {\n const named = columns.map((column, i) => `json_extract(value, '$[${i}]') AS ${column}`);\n return `(SELECT ${named.join(', ')} FROM json_each(?))`;\n};\n\n/** The columns of a content condition; see contentRows(). */\nconst CONDITION_COLUMNS = ['scope', 'path', 'op', 'val', 'kind'];\n\n/**\n * A JSON value's type as json_each reports it, with integer and real as one\n * number: what an `equals` condition compares besides the value itself, as\n * `===` does. valueKind() reads a filter value the same way.\n */\nconst kindOf = (type: string): string =>\n `CASE ${type} WHEN 'integer' THEN 'number' WHEN 'real' THEN 'number' ELSE ${type} END`;\n\n/**\n * Whether condition row `c` holds for record row `r`: one walk of the path\n * as data, a segment matched against json_each's `key` per step, gathering\n * what each op asks of the values it reaches. See docs/spec/adapters.md\n * § Statement size and docs/spec/data-model.md § Filter.\n */\nconst holds = (c: string, r: string): string => {\n const depth = `json_array_length(${c}.path)`;\n return (\n `(WITH RECURSIVE w(d, v, t) AS (SELECT 0, ${r}.content, 'object' UNION ALL ` +\n `SELECT w.d + 1, e.value, e.type FROM w JOIN json_each(${members('w')}) m ` +\n `JOIN json_each(${spread('m')}) e ` +\n `WHERE w.d < ${depth} AND m.key = json_extract(${c}.path, '$[' || w.d || ']')) ` +\n `SELECT CASE ${c}.op ` +\n `WHEN 'equals' THEN IFNULL(MAX(${kindOf('w.t')} = ${c}.kind AND w.v = ${c}.val), 0) ` +\n \"WHEN 'present' THEN IFNULL(MAX(w.t != 'null'), 0) \" +\n \"WHEN 'isNull' THEN IFNULL(MAX(w.t = 'null'), 0) OR NOT IFNULL(MAX(w.t != 'null'), 0) \" +\n `END FROM w WHERE w.d = ${depth})`\n );\n};\n\n/** The join alias the content index is read through. */\nconst SORT_ALIAS = 'cs';\n\n/**\n * A cursor names a position in one ordering; carrying it into another\n * would silently resume somewhere arbitrary. The partition matters as\n * much as the field name — a cursor from a numeric page can't be read\n * against text values — so each ordering below accepts only the cursors\n * it can read, and rejecting the rest is what narrows the cursor to them.\n */\nconst cursorMismatch = (cursor: DecodedCursor, field: string): StackBadRequestError =>\n new StackBadRequestError(\n `Cursor sort field \"${cursor.field}\" does not match query sort field \"${field}\"`,\n );\n\nconst nativeCursor = (cursor: DecodedCursor, field: NativeSortField) => {\n if (cursor.kind !== 'native' || cursor.field !== field) throw cursorMismatch(cursor, field);\n return cursor;\n};\n\nconst contentCursor = (cursor: DecodedCursor, field: string) => {\n if (cursor.kind === 'native' || cursor.field !== field) throw cursorMismatch(cursor, field);\n return cursor;\n};\n\n/** A filter value's kindOf(), which it mirrors, or null for one nothing equals. */\nconst valueKind = (value: unknown): string | null => {\n if (typeof value === 'boolean') return `${value}`;\n if (typeof value === 'number') return 'number';\n return typeof value === 'string' ? 'text' : null;\n};\n\n/**\n * A `content` and `contentPresent` predicate as condition rows scoped to\n * `scope`: path segments, the op, and for `equals` the value and its\n * valueKind(). A `null` value means \"no value at the path, or a value that\n * is null\" (docs/spec/data-model.md § Filter).\n */\nconst contentRows = (scope: string | null, predicate: ContentArm): unknown[][] => {\n const row = (key: string, op: string, value: unknown = null) => {\n const path = parseContentFilterKey(key);\n return [scope, path, op, value, valueKind(value)];\n };\n return [\n ...Object.entries(predicate.content ?? {}).map(([key, value]) =>\n // undefined is the same absence null names — JSON drops it on the way\n // over the wire, so treating it as a value would make an in-process\n // query and its wire equivalent disagree.\n value === null || value === undefined ? row(key, 'isNull') : row(key, 'equals', value),\n ),\n ...(predicate.contentPresent ?? []).map((key) => row(key, 'present')),\n ];\n};\n\n/**\n * Values as the condition matching any of them: rows() of one column, or\n * one value bound as itself, so an index on the column still yields rows in\n * its order. An empty list matches nothing.\n */\nconst inList = (s: Statement, column: string, values: readonly string[]): string => {\n if (values.length === 1) {\n s.params.push(values[0]);\n return `${column} = ?`;\n }\n const table = rows(\n s,\n ['value'],\n values.map((value) => [value]),\n );\n return `${column} IN (SELECT value FROM ${table})`;\n};\n\n/** The bounds of one family's TypeIds; see inFamilies(). */\nconst familyRange = (baseId: string): [string, string] => [`${baseId}@`, `${baseId}A`];\n\n/** `column` inside the family bounds `lo` and `hi`; see inFamilies(). */\nconst withinFamily = (column: string, lo: string, hi: string): string =>\n `(${column} >= ${lo} AND ${column} < ${hi})`;\n\n/** One family as a condition on a TypeId `column`, for a statement of its own. */\nexport const inFamily = (column: string, baseId: string): QueryStatement => ({\n sql: withinFamily(column, '?', '?'),\n params: familyRange(baseId),\n});\n\n/**\n * Families as the condition matching a Record of `record` in any of them:\n * `F@…` is exactly the range from `F@` up to `FA`, since `A` follows `@`\n * in the binary collation, so it never matches a family that merely shares\n * a prefix, as `note` and `notes`. Each family is its own range search of\n * the type_id index, several joined through rows() of their bounds. An\n * empty list matches nothing. See docs/spec/data-model.md § Filter.\n */\nconst inFamilies = (s: Statement, record: string, baseIds: readonly string[]): string => {\n if (baseIds.length === 1) {\n const one = inFamily(`${record}.type_id`, baseIds[0]);\n s.params.push(...one.params);\n return one.sql;\n }\n const table = rows(s, ['lo', 'hi'], baseIds.map(familyRange));\n return (\n `${record}.id IN (SELECT fr.id FROM ${table} f ` +\n `JOIN records fr ON ${withinFamily('fr.type_id', 'f.lo', 'f.hi')})`\n );\n};\n\n/**\n * Whether the record carries every element of one of `sets`, matched on the\n * permissions table's key — the identity editAccess() removes by — through\n * idx_permissions_element. Each element is a row naming its set and that\n * set's size; an empty set matches nothing.\n */\nconst carriesPermissions = (s: Statement, sets: AuthorityAssociation[][]): string => {\n const elements = rows(\n s,\n ['set_index', 'set_size', 'kind', 'label', 'grantee_kind', 'grantee_id', 'role'],\n sets.flatMap((set, i) =>\n set.map((p) => [i, set.length, p.kind, p.label, ...permissionKeyColumns(p)]),\n ),\n );\n return (\n `r.id IN (SELECT p.record_id FROM ${elements} e JOIN permissions p ` +\n 'ON p.kind = e.kind AND p.label = e.label AND p.grantee_kind = e.grantee_kind ' +\n 'AND p.grantee_id = e.grantee_id AND p.role = e.role ' +\n 'GROUP BY p.record_id, e.set_index HAVING COUNT(*) = MAX(e.set_size))'\n );\n};\n\n/**\n * The reach as conditions on `r`: inside the fence, and inside `within` by\n * one of its arms. See docs/spec/access-control.md § Reach.\n */\nconst reachConditions = (s: Statement, reach: Reach): void => {\n if (reach.fence) s.conditions.push(inFamilies(s, 'r', reach.fence));\n const within = reach.within;\n if (within) {\n const arms = [inFamilies(s, 'r', within.baseIds)];\n if (within.authored) {\n s.params.push(within.authored.subjectId);\n arms.push(`(r.entity_id = ? AND ${inFamilies(s, 'r', within.authored.baseIds)})`);\n }\n arms.push(carriesPermissions(s, within.permissions));\n s.conditions.push(`(${arms.join(' OR ')})`);\n }\n};\n\n/**\n * Every condition on the records row itself — everything a query asks\n * except where in the ordering to resume, which is per-partition and gets\n * appended by the caller.\n */\nconst recordConditions = (query: AdapterQuery, reach: Reach | undefined): Statement => {\n const s = emptyStatement();\n const { conditions, params } = s;\n const f = query.filter ?? {};\n\n /**\n * A filter that accepts one value or a list of them, as the one `IN` that\n * covers both — see inList().\n */\n const inFilter = (column: string, value: string | readonly string[] | undefined): void => {\n if (value === undefined) return;\n conditions.push(inList(s, `r.${column}`, Array.isArray(value) ? value : [value as string]));\n };\n\n /** One side of a date range, as the open-ended comparison it is. */\n const rangeFilter = (\n column: string,\n range: { after?: Date; before?: Date } | undefined,\n ): void => {\n if (range?.after) {\n conditions.push(`r.${column} > ?`);\n params.push(range.after.getTime());\n }\n if (range?.before) {\n conditions.push(`r.${column} < ?`);\n params.push(range.before.getTime());\n }\n };\n\n if (!f.includeDeleted) {\n conditions.push('r.deleted_at IS NULL');\n }\n\n if (!f.includeUnlisted) {\n conditions.push('r.unlisted_at IS NULL');\n }\n\n if (reach) reachConditions(s, reach);\n\n inFilter('type_id', f.typeId);\n if (f.baseId !== undefined) {\n conditions.push(inFamilies(s, 'r', Array.isArray(f.baseId) ? f.baseId : [f.baseId]));\n }\n\n // Not an inFilter: parentId takes an explicit null for \"at the root\",\n // which is a different SQL predicate rather than a different value.\n if (f.parentId !== undefined) {\n if (f.parentId === null) {\n conditions.push('r.parent_id IS NULL');\n } else {\n conditions.push('r.parent_id = ?');\n params.push(f.parentId);\n }\n }\n\n inFilter('app_id', f.appId);\n inFilter('entity_id', f.createdBy?.subjectId);\n inFilter('principal_id', f.createdBy?.principalId);\n\n rangeFilter('created_at', f.createdAt);\n rangeFilter('updated_at', f.updatedAt);\n\n // Every association filter below is a semi-join rather than a correlated\n // EXISTS, so the planner reads matching record ids straight out of an\n // index ending in record_id instead of probing once per record: the work\n // scales with the matches, not the stack.\n\n /**\n * The semi-join itself. `kind` is one of this module's own literals, never\n * caller text, and each clause carries its own placeholder — so the only\n * thing interpolated here is SQL this file wrote.\n */\n const hasAssociation = (kind: 'tag' | 'attachment' | 'relationship', clauses: string[]): string =>\n `r.id IN (SELECT a.record_id FROM associations a WHERE a.kind = '${kind}'` +\n clauses.map((c) => ` AND ${c}`).join('') +\n `)`;\n\n // Conjunctive: a record must carry every tag named, so its matches are\n // counted against the distinct tags asked for, the list bound as one.\n if (f.tags?.length) {\n const tags = [...new Set(f.tags)];\n const label = inList(s, 'a.label', tags);\n conditions.push(\n `r.id IN (SELECT a.record_id FROM associations a WHERE a.kind = 'tag' AND ${label} ` +\n `GROUP BY a.record_id HAVING COUNT(DISTINCT a.label) = ?)`,\n );\n params.push(tags.length);\n }\n\n // Both halves in one subquery, so they match the same association.\n if (f.attachment) {\n const clauses: string[] = [];\n if (f.attachment.label !== undefined) {\n clauses.push('a.label = ?');\n params.push(f.attachment.label);\n }\n if (f.attachment.fileId !== undefined) {\n clauses.push('a.file_id = ?');\n params.push(f.attachment.fileId);\n }\n conditions.push(hasAssociation('attachment', clauses));\n }\n\n // A reference is an attachment association or a top-level file-ref field.\n if (f.referencesFileId) {\n conditions.push(\n `(${hasAssociation('attachment', ['a.file_id = ?'])}\n OR r.id IN (SELECT ci.record_id FROM content_index ci WHERE ci.file_id = ?))`,\n );\n params.push(f.referencesFileId, f.referencesFileId);\n }\n\n // Each clause is an optional pattern (docs/spec/data-model.md § Filter).\n // A record or entity target always stores '' in related_ns; saying so\n // keeps idx_assoc_related's prefix a contiguous equality run.\n if (f.relatedTo) {\n const clauses: string[] = [];\n const target = f.relatedTo.target;\n if (f.relatedTo.label !== undefined) {\n clauses.push('a.label = ?');\n params.push(f.relatedTo.label);\n }\n if (target) {\n clauses.push('a.related_scope = ?');\n params.push(target.kind);\n if (target.kind === 'record') {\n clauses.push('a.related_ns = ?', 'a.related_id = ?', 'a.related_stack = ?');\n params.push('', target.recordId, target.stackUrl ?? '');\n } else if (target.kind === 'entity') {\n clauses.push('a.related_ns = ?', 'a.related_id = ?');\n params.push('', target.entityId);\n } else {\n clauses.push('a.related_ns = ?');\n params.push(target.ns);\n if (target.id !== undefined) {\n clauses.push('a.related_id = ?');\n params.push(target.id);\n }\n }\n }\n conditions.push(hasAssociation('relationship', clauses));\n }\n\n // An arm is the content filter scoped to one Type; types partition\n // records, so a record meets at most the arm for its own type\n // (docs/spec/data-model.md § Content by type).\n const content = contentRows(null, f);\n if (f.contentByType) {\n const arms = Object.entries(f.contentByType);\n // The Types themselves bound the result too: an empty arm adds no\n // condition row, yet still admits only its own Type.\n const typeIds = arms.map(([typeId]) => typeId);\n conditions.push(inList(s, 'r.type_id', typeIds));\n for (const [typeId, arm] of arms) content.push(...contentRows(typeId, arm));\n }\n\n if (content.length > 0) {\n const table = rows(s, CONDITION_COLUMNS, content);\n conditions.push(\n `NOT EXISTS (SELECT 1 FROM ${table} c WHERE (c.scope IS NULL OR c.scope = r.type_id) ` +\n `AND NOT ${holds('c', 'r')})`,\n );\n }\n\n if (f.search) {\n const sanitized = sanitizeFts5Query(f.search);\n if (sanitized) {\n conditions.push(`r.rowid IN (SELECT rowid FROM records_fts WHERE records_fts MATCH ?)`);\n params.push(sanitized);\n } else {\n // A search that sanitizes to nothing (e.g. \"*\", punctuation-only) is\n // an honest zero-match result, not \"no filter\" — omitting the clause\n // would silently return the full table as the \"search result\".\n conditions.push('0');\n }\n }\n\n return s;\n};\n\n/**\n * Everything after the cursor's record within the partition that holds a\n * value. `op` compares the way the ORDER BY does, so one form covers both\n * directions; where the cursor's rank is the last one, the leading\n * disjunct is simply never true.\n */\nconst presentCursorCondition = (\n cursor: Extract<DecodedCursor, { kind: 'num' | 'text' }>,\n op: '>' | '<',\n params: unknown[],\n): string => {\n if (cursor.kind === 'num') {\n params.push(cursor.value, cursor.value, cursor.id);\n return (\n `(${SORT_ALIAS}.value_rank ${op} 0 OR (${SORT_ALIAS}.value_rank = 0 AND ` +\n `(${SORT_ALIAS}.num_value ${op} ? OR (${SORT_ALIAS}.num_value = ? AND ` +\n `${SORT_ALIAS}.record_id ${op} ?))))`\n );\n }\n const key = contentSortKey(cursor.value);\n params.push(key, key, cursor.value, cursor.value, cursor.id);\n return (\n `(${SORT_ALIAS}.value_rank ${op} 1 OR (${SORT_ALIAS}.value_rank = 1 AND ` +\n `(${SORT_ALIAS}.text_key ${op} ? OR (${SORT_ALIAS}.text_key = ? AND ` +\n `(${SORT_ALIAS}.text_value ${op} ? OR (${SORT_ALIAS}.text_value = ? AND ` +\n `${SORT_ALIAS}.record_id ${op} ?))))))`\n );\n};\n\n/** `s` as one statement reading `r` from `from`, its tables leading. */\nconst statement = (s: Statement, from: string, tail: string): QueryStatement => {\n const select = `SELECT r.* FROM ${from} WHERE ${s.conditions.join(' AND ')}${tail}`;\n const sql = s.tables.length === 0 ? select : `WITH ${s.tables.join(', ')} ${select}`;\n return { sql, params: [...s.tableParams, ...s.params] };\n};\n\n/**\n * Compile a query into the statements that answer it, read in order and\n * their rows concatenated: the first that fills the page ends the read,\n * so the second is never run for a page that doesn't reach it. Each still\n * needs the row budget its `LIMIT ?` binds — see atBudget.\n */\nexport const buildQueryPlan = (query: AdapterQuery, reach?: Reach): QueryStatement[] => {\n const dir = sqlDirection(query);\n const op = dir === 'ASC' ? '>' : '<';\n const decoded = query.cursor ? decodeCursor(query.cursor) : null;\n if (query.sort.contentFieldByType) {\n return byTypePlan(query, reach, query.sort.contentFieldByType, dir, op, decoded);\n }\n const { contentField, field } = query.sort;\n\n if (field !== undefined) {\n const where = recordConditions(query, reach);\n const col = getSortColumn(field);\n if (decoded) {\n const cursor = nativeCursor(decoded, field);\n where.conditions.push(`(r.${col} ${op} ? OR (r.${col} = ? AND r.id ${op} ?))`);\n where.params.push(cursor.value, cursor.value, cursor.id);\n }\n return [statement(where, 'records r', ` ORDER BY r.${col} ${dir}, r.id ${dir} LIMIT ?`)];\n }\n\n const cursor = decoded ? contentCursor(decoded, contentField) : null;\n const pages: QueryStatement[] = [];\n\n // Records holding a value at the field, in that value's order. A cursor\n // sitting in the absent partition has already passed every one of them.\n if (cursor?.kind !== 'absent') {\n const where = recordConditions(query, reach);\n const from = `content_index ${SORT_ALIAS} JOIN records r ON r.id = ${SORT_ALIAS}.record_id`;\n where.conditions.push(`${SORT_ALIAS}.field = ?`);\n where.params.push(contentField);\n if (cursor) where.conditions.push(presentCursorCondition(cursor, op, where.params));\n // Ordered exactly as idx_content_index_sort stores it, so the page is\n // an ordered walk of the index rather than a sort of the matches.\n const order =\n `${SORT_ALIAS}.value_rank ${dir}, ${SORT_ALIAS}.num_value ${dir}, ` +\n `${SORT_ALIAS}.text_key ${dir}, ${SORT_ALIAS}.text_value ${dir}, ` +\n `${SORT_ALIAS}.record_id ${dir}`;\n pages.push(statement(where, from, ` ORDER BY ${order} LIMIT ?`));\n }\n\n // Records holding nothing there, which trail the others whichever way\n // the sort runs (docs/spec/data-model.md § Sorting by a content field).\n {\n const where = recordConditions(query, reach);\n where.conditions.push(\n `NOT EXISTS (SELECT 1 FROM content_index ${SORT_ALIAS} ` +\n `WHERE ${SORT_ALIAS}.record_id = r.id AND ${SORT_ALIAS}.field = ?)`,\n );\n where.params.push(contentField);\n if (cursor?.kind === 'absent') {\n where.conditions.push(`r.id ${op} ?`);\n where.params.push(cursor.id);\n }\n pages.push(statement(where, 'records r', ` ORDER BY r.id ${dir} LIMIT ?`));\n }\n\n return pages;\n};\n\n/**\n * A sort naming its value per Type, read through a derived table in place\n * of the index: each Type's own index rows, and its constant in the index's\n * columns, so one cursor condition and one ORDER BY serve both. Fields and\n * constants are each rows(). See docs/spec/data-model.md § Sorting by a content field.\n */\nconst byTypePlan = (\n query: AdapterQuery,\n reach: Reach | undefined,\n byType: Record<string, ContentSortKey>,\n dir: 'ASC' | 'DESC',\n op: '>' | '<',\n decoded: DecodedCursor | null,\n): QueryStatement[] => {\n const cursor = decoded ? contentCursor(decoded, byTypeDescriptor(byType)) : null;\n const fields: [string, string][] = [];\n const constants: [string, SortEntry][] = [];\n for (const [typeId, key] of Object.entries(byType)) {\n if (key.field !== undefined) {\n fields.push([typeId, key.field]);\n continue;\n }\n const entry = constantSortEntry(key.value ?? null);\n if (entry) constants.push([typeId, entry]);\n }\n const pages: QueryStatement[] = [];\n\n if (cursor?.kind !== 'absent' && fields.length + constants.length > 0) {\n const where = recordConditions(query, reach);\n const sources: string[] = [];\n if (fields.length > 0) {\n const byField = rows(where, ['type_id', 'field'], fields);\n sources.push(\n 'SELECT ci.record_id AS record_id, ci.value_rank AS value_rank, ' +\n 'ci.num_value AS num_value, ci.text_key AS text_key, ci.text_value AS text_value ' +\n `FROM ${byField} f JOIN content_index ci ON ci.field = f.field ` +\n 'JOIN records t ON t.id = ci.record_id AND t.type_id = f.type_id',\n );\n }\n if (constants.length > 0) {\n const byConstant = rows(\n where,\n ['type_id', 'value_rank', 'num_value', 'text_key', 'text_value'],\n constants.map(([typeId, entry]) =>\n entry.kind === 'num'\n ? [typeId, 0, entry.num, null, null]\n : [typeId, 1, null, entry.key, entry.text],\n ),\n );\n sources.push(\n 'SELECT t.id AS record_id, k.value_rank AS value_rank, k.num_value AS num_value, ' +\n 'k.text_key AS text_key, k.text_value AS text_value ' +\n `FROM ${byConstant} k JOIN records t ON t.type_id = k.type_id`,\n );\n }\n if (cursor) where.conditions.push(presentCursorCondition(cursor, op, where.params));\n const from =\n `(${sources.join(' UNION ALL ')}) ${SORT_ALIAS} ` +\n `JOIN records r ON r.id = ${SORT_ALIAS}.record_id`;\n const order =\n `${SORT_ALIAS}.value_rank ${dir}, ${SORT_ALIAS}.num_value ${dir}, ` +\n `${SORT_ALIAS}.text_key ${dir}, ${SORT_ALIAS}.text_value ${dir}, ` +\n `${SORT_ALIAS}.record_id ${dir}`;\n pages.push(statement(where, from, ` ORDER BY ${order} LIMIT ?`));\n }\n\n // Records holding nothing to order by: a Type's field with no value, a\n // `null` constant, or a Type the map does not name.\n {\n const where = recordConditions(query, reach);\n if (fields.length > 0) {\n const byField = rows(where, ['type_id', 'field'], fields);\n where.conditions.push(\n `NOT EXISTS (SELECT 1 FROM ${byField} f JOIN content_index ${SORT_ALIAS} ` +\n `ON ${SORT_ALIAS}.record_id = r.id AND ${SORT_ALIAS}.field = f.field ` +\n 'WHERE f.type_id = r.type_id)',\n );\n }\n if (constants.length > 0) {\n const typeIds = constants.map(([typeId]) => typeId);\n where.conditions.push(`NOT (${inList(where, 'r.type_id', typeIds)})`);\n }\n if (cursor?.kind === 'absent') {\n where.conditions.push(`r.id ${op} ?`);\n where.params.push(cursor.id);\n }\n pages.push(statement(where, 'records r', ` ORDER BY r.id ${dir} LIMIT ?`));\n }\n return pages;\n};\n","/**\n * The two derived indexes a records database keeps beside its rows: FTS5\n * for `filter.search`, and content_index for `sort.contentField` and the\n * file-reference filters. Both can be rebuilt from `records` alone, and\n * both must be rewritten in the same transaction as any write that changes\n * what they cover, or a query answers from a record that no longer exists.\n */\n\nimport type { StackType, ScalarFieldKind } from '@haverstack/core';\nimport { contentSortEntry } from '@haverstack/core/adapter';\nimport type { SqlExecutor } from './executor.js';\n\n/**\n * FTS5's external-content table needs its special `('delete', rowid,\n * content)` command — with the *old* content — to unindex a row; a plain\n * DELETE leaves stale, still-searchable entries. remove() therefore reads\n * the current rowid/content and must run before the caller's change.\n */\nexport class SearchIndex {\n constructor(private readonly exec: SqlExecutor) {}\n\n /** Index a record that has no FTS entry yet (used right after an INSERT). */\n insert(recordId: string, content: string): void {\n this.exec.run(\n `INSERT INTO records_fts(rowid, content) SELECT rowid, ? FROM records WHERE id = ?`,\n [content, recordId],\n );\n }\n\n /**\n * Remove a record's FTS entry. MUST be called before the records row's\n * content changes or the row is deleted — see the note above.\n */\n remove(recordId: string): void {\n const row = this.exec.get<{ rowid: number; content: string }>(\n 'SELECT rowid, content FROM records WHERE id = ?',\n [recordId],\n );\n if (!row) return;\n this.exec.run(`INSERT INTO records_fts(records_fts, rowid, content) VALUES('delete', ?, ?)`, [\n row.rowid,\n row.content,\n ]);\n }\n}\n\n/**\n * Top-level scalar fields, by name and declared kind — what content_index\n * covers. Arrays and objects are left out: a value inside one has no\n * single position to order its record by, and no file reference the\n * attachment filter can see.\n */\nconst indexedFieldKinds = (\n schema: Record<string, { kind?: string }>,\n): Map<string, ScalarFieldKind> => {\n const kinds = new Map<string, ScalarFieldKind>();\n for (const [field, def] of Object.entries(schema)) {\n if (!def.kind || def.kind === 'array' || def.kind === 'object') continue;\n kinds.set(field, def.kind as ScalarFieldKind);\n }\n return kinds;\n};\n\n/**\n * One row per top-level scalar field a record holds a value at. Caches each\n * type's indexed fields so a write doesn't re-read and re-parse the schema.\n */\nexport class ContentIndex {\n private readonly fieldsByType = new Map<string, Map<string, ScalarFieldKind>>();\n\n constructor(private readonly exec: SqlExecutor) {}\n\n /** Prime the cache from a type as it is saved. */\n rememberType(type: StackType): void {\n this.fieldsByType.set(\n type.id,\n indexedFieldKinds(type.schema as Record<string, { kind?: string }>),\n );\n }\n\n /**\n * Replace a record's rows with what its content currently holds, on every\n * write that can change content or typeId, so neither the ordering nor the\n * file-reference lookup can drift from the record. A field holding no\n * orderable value gets no row at all, which is what puts the record at the\n * end of a sort on that field.\n */\n sync(recordId: string, typeId: string, content: Record<string, unknown>): void {\n this.remove(recordId);\n\n for (const [field, kind] of this.fieldsOf(typeId)) {\n const entry = contentSortEntry(kind, content[field]);\n if (!entry) continue;\n const sql = `INSERT OR IGNORE INTO content_index\n (record_id, field, value_rank, num_value, text_key, text_value, file_id)\n VALUES (?, ?, ?, ?, ?, ?, ?)`;\n if (entry.kind === 'num') {\n this.exec.run(sql, [recordId, field, 0, entry.num, null, null, null]);\n } else {\n // A file-ref field's value is its file id, so the row it already\n // needs for ordering also answers the attachment filter — one\n // field is one row, whatever a query reads it for.\n const fileId = kind === 'file-ref' ? entry.text : null;\n this.exec.run(sql, [recordId, field, 1, null, entry.key, entry.text, fileId]);\n }\n }\n }\n\n remove(recordId: string): void {\n this.exec.run('DELETE FROM content_index WHERE record_id = ?', [recordId]);\n }\n\n /** The declared kind of a type's top-level `field`, if it has one. */\n kindOf(typeId: string, field: string): ScalarFieldKind | undefined {\n return this.fieldsOf(typeId).get(field);\n }\n\n /**\n * From the cache, falling back to a `types` lookup only for a typeId this\n * process hasn't seen via rememberType() yet, e.g. right after open().\n */\n private fieldsOf(typeId: string): Map<string, ScalarFieldKind> {\n const cached = this.fieldsByType.get(typeId);\n if (cached) return cached;\n\n const typeRow = this.exec.get<{ schema: string }>('SELECT schema FROM types WHERE id = ?', [\n typeId,\n ]);\n const fields = typeRow\n ? indexedFieldKinds(JSON.parse(typeRow.schema) as Record<string, { kind?: string }>)\n : new Map<string, ScalarFieldKind>();\n this.fieldsByType.set(typeId, fields);\n return fields;\n }\n}\n","/**\n * The actual StackRecordAdapter logic (minus lifecycle: open/\n * close/flush stay per-engine, since schema setup, pragmas, locking, and\n * durability differ there). Every CRUD/query/version/type/association\n * operation lives here exactly once, parametrized over a SqlExecutor\n * (which normalizes each engine's call conventions). Concrete adapters\n * construct one of these and delegate their StackRecordAdapter methods\n * to it — see record-adapter-sqlite.\n */\n\nimport {\n StackConflictError,\n StackVersionConflictError,\n StackNotFoundError,\n StackBadRequestError,\n applyMergePatch,\n} from '@haverstack/core';\nimport type {\n RecordJournalEntry,\n JournalQuery,\n VersionsQuery,\n StackRecord,\n StackType,\n TypeId,\n BaseId,\n FileId,\n RecordVersion,\n QueryResult,\n Association,\n AssociationEdit,\n AuthorityAssociation,\n DataAssociation,\n ActorOptions,\n IfVersionOptions,\n} from '@haverstack/core';\nimport {\n ElementSetMovedError,\n sameAssociationSet,\n softDeletedRefusal,\n} from '@haverstack/core/adapter';\nimport type {\n AdapterQuery,\n AspectWriteOptions,\n ElementWriteOptions,\n JournalEntryInput,\n JournalOptions,\n MutateOptions,\n Reach,\n} from '@haverstack/core/adapter';\nimport type { SqlExecutor } from './executor.js';\nimport { isForeignKeyViolation, isUniqueConstraintViolation } from './executor.js';\nimport { buildQueryPlan, atBudget, inFamily, rowsTable } from './query.js';\nimport { ContentIndex, SearchIndex } from './indexes.js';\nimport {\n rowToRecord,\n rowToAssociation,\n rowToPermission,\n permissionKeyColumns,\n rowToType,\n rowToVersion,\n rowToJournalEntry,\n toMs,\n associationKeyColumns,\n} from './mappers.js';\nimport { makeCursor } from './cursor.js';\n\n/**\n * Restate an engine parse error as `bad_request` when the query carries\n * search text, the one filter with a query language the sanitizer can't\n * fully repair. Any other clause is built from parameters, so a parse\n * error there is this module's bug and is rethrown untouched.\n */\nconst asStackBadRequestError = <T>(query: AdapterQuery, run: () => T): T => {\n try {\n return run();\n } catch (err) {\n if (!query.filter?.search) throw err;\n throw new StackBadRequestError(\n `Search text could not be parsed: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n};\n\n/**\n * One spelling of the optimistic-concurrency failure, so the message a\n * caller sees never depends on which check noticed it.\n */\nconst versionConflict = (id: string, expected: number, actual: number): StackVersionConflictError =>\n new StackVersionConflictError(\n `Record \"${id}\" is at version ${actual}, expected ${expected}`,\n id,\n expected,\n actual,\n );\n\nconst recordNotFound = (id: string): StackNotFoundError =>\n new StackNotFoundError(`Record not found: \"${id}\"`);\n\n/**\n * Every `versions` column beyond the (record_id, version) key, and the\n * values for them in the same order — one list, so the INSERT that writes a\n * snapshot and the UPDATE that replaces one can't drift apart on which\n * columns a snapshot is made of.\n */\nconst VERSION_COLUMNS = [\n 'type_id',\n 'content',\n 'updated_at',\n 'entity_id',\n 'principal_id',\n 'updated_by',\n 'updated_via',\n] as const;\n\nconst versionRowValues = (version: RecordVersion): unknown[] => [\n version.typeId,\n JSON.stringify(version.content),\n toMs(version.updatedAt),\n version.createdBy?.subjectId ?? null,\n version.createdBy?.principalId ?? null,\n version.updatedBy?.subjectId ?? null,\n version.updatedBy?.principalId ?? null,\n];\n\nexport type SharedSqlRecordLogicDeps = {\n exec: SqlExecutor;\n};\n\nexport class SharedSqlRecordLogic {\n private readonly exec: SqlExecutor;\n private readonly searchIndex: SearchIndex;\n private readonly contentIndex: ContentIndex;\n\n constructor({ exec }: SharedSqlRecordLogicDeps) {\n this.exec = exec;\n this.searchIndex = new SearchIndex(exec);\n this.contentIndex = new ContentIndex(exec);\n }\n\n /** Check `ifVersion` against a version read inside the caller's transaction. */\n private checkExpectedVersion(id: string, actual: number, expected: number | undefined): void {\n if (expected === undefined || actual === expected) return;\n throw versionConflict(id, expected, actual);\n }\n\n /**\n * Called after a version-gated statement affected zero rows.\n * Distinguishes \"record doesn't exist\" (StackNotFoundError) from \"it\n * exists but isn't at expectedVersion\" (StackVersionConflictError, with\n * the actual current version for the caller to act on).\n */\n private throwVersionConflict(id: string, expectedVersion: number | undefined): never {\n const version = this.currentVersion(id);\n if (version === undefined) throw recordNotFound(id);\n throw versionConflict(id, expectedVersion as number, version);\n }\n\n /**\n * An aspect write's record, inside its transaction: missing is not found,\n * a tombstone is refused, and anything else answers its version.\n */\n private liveVersion(id: string): number {\n const row = this.exec.get<{ version: number; deleted_at: number | null }>(\n 'SELECT version, deleted_at FROM records WHERE id = ?',\n [id],\n );\n if (!row) throw recordNotFound(id);\n if (row.deleted_at !== null) throw softDeletedRefusal(id);\n return row.version;\n }\n\n private currentVersion(id: string): number | undefined {\n return this.exec.get<{ version: number }>('SELECT version FROM records WHERE id = ?', [id])\n ?.version;\n }\n\n /**\n * What a mutation builds on, read inside its transaction so nothing can\n * land between the read and the write: a patch applied to an earlier read\n * would overwrite whatever changed since. Throws for a missing record or\n * a failed `ifVersion`.\n */\n private readForWrite(\n id: string,\n ifVersion: number | undefined,\n ): { typeId: TypeId; content: Record<string, unknown> } {\n const row = this.exec.get<{ version: number; type_id: string; content: string }>(\n 'SELECT version, type_id, content FROM records WHERE id = ?',\n [id],\n );\n if (!row) throw recordNotFound(id);\n this.checkExpectedVersion(id, row.version, ifVersion);\n return { typeId: row.type_id, content: JSON.parse(row.content) };\n }\n\n /**\n * Every version-bumping UPDATE. The `ifVersion` guard rides in the WHERE\n * clause, so a write that reads nothing first (a soft delete, an\n * undelete) enforces it with no separate read.\n */\n private versionedUpdate(\n id: string,\n sets: string[],\n values: unknown[],\n opts: IfVersionOptions & ActorOptions,\n now = toMs(new Date()),\n ): void {\n const guarded = opts.ifVersion !== undefined;\n const changed = this.exec.run(\n `UPDATE records SET ${[...sets, 'version = version + 1', 'updated_at = ?', 'updated_by = ?', 'updated_via = ?'].join(', ')}` +\n ` WHERE id = ?${guarded ? ' AND version = ?' : ''}`,\n [\n ...values,\n now,\n opts.actor?.subjectId ?? null,\n opts.actor?.principalId ?? null,\n id,\n ...(guarded ? [opts.ifVersion] : []),\n ],\n );\n if (changed === 0) this.throwVersionConflict(id, opts.ifVersion);\n }\n\n /**\n * Read a record back after its own mutation committed. Absence here is an\n * invariant breach, not a \"not found\". Synchronous, so nothing can run\n * between the commit and the read — see readRecord().\n */\n private reread(id: string, verb: string): StackRecord {\n const updated = this.readRecord(id);\n if (!updated) throw new Error(`Record not found after ${verb}: \"${id}\"`);\n return updated;\n }\n\n // -------------------------------------------------------\n // Records\n // -------------------------------------------------------\n\n /**\n * One transaction, because a record and the tables that describe it are\n * one fact: a half-applied create raises, so the caller believes nothing\n * landed, while the surviving row fails their retry on the PK and is\n * missing from both indexes. A duplicate id maps to StackConflictError.\n */\n async createRecord(record: StackRecord, opts: JournalOptions = {}): Promise<StackRecord> {\n this.exec.transaction(() => {\n try {\n this.exec.run(\n `INSERT INTO records\n (id, type_id, created_at, updated_at, content, version,\n parent_id, entity_id, app_id, principal_id, updated_by, updated_via,\n deleted_at, unlisted_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n [\n record.id,\n record.typeId,\n toMs(record.createdAt),\n toMs(record.updatedAt),\n JSON.stringify(record.content),\n record.version,\n record.parentId ?? null,\n record.createdBy?.subjectId ?? null,\n record.appId ?? null,\n record.createdBy?.principalId ?? null,\n record.updatedBy?.subjectId ?? null,\n record.updatedBy?.principalId ?? null,\n record.deletedAt ? toMs(record.deletedAt) : null,\n record.unlistedAt ? toMs(record.unlistedAt) : null,\n ],\n );\n } catch (err) {\n if (isUniqueConstraintViolation(err)) {\n throw new StackConflictError(`Record already exists: \"${record.id}\"`);\n }\n throw err;\n }\n\n if (record.associations?.length) this.insertAssociations(record.id, record.associations);\n if (record.permissions?.length) this.insertPermissions(record.id, record.permissions);\n\n this.searchIndex.insert(record.id, JSON.stringify(record.content));\n this.contentIndex.sync(record.id, record.typeId, record.content);\n this.appendJournal(record.id, opts.journal);\n });\n\n return record;\n }\n\n async getRecord(id: string): Promise<StackRecord | null> {\n return this.readRecord(id);\n }\n\n /**\n * The synchronous read behind getRecord(), for use inside\n * exec.transaction(), whose callback can't await. reread() relies on the\n * same synchrony: nothing interleaves between a commit and its read, so a\n * concurrent mutation is never reported under this one's verb.\n */\n private readRecord(id: string): StackRecord | null {\n const row = this.exec.get<Record<string, unknown>>('SELECT * FROM records WHERE id = ?', [id]);\n return row ? this.hydrate([row])[0]! : null;\n }\n\n /**\n * Records rows with their associations and permissions attached: one\n * statement per element table for the whole list, so a page costs three\n * reads however many records it holds.\n */\n private hydrate(rows: Record<string, unknown>[]): StackRecord[] {\n const ids = rows.map((row) => row.id as string);\n const associations = this.elementsByRecord('associations', ids, rowToAssociation);\n const permissions = this.elementsByRecord('permissions', ids, rowToPermission);\n return rows.map((row) =>\n rowToRecord(\n row,\n associations.get(row.id as string) ?? [],\n permissions.get(row.id as string) ?? [],\n ),\n );\n }\n\n /**\n * The patch applies to the content as it stands when the write lands,\n * read inside the same transaction.\n */\n async patchContent(\n id: string,\n patch: Record<string, unknown | null>,\n opts: MutateOptions = {},\n ): Promise<StackRecord> {\n this.exec.transaction(() => {\n const current = this.readForWrite(id, opts.ifVersion);\n if (opts.snapshot) this.snapshotBeforeMutation(id, opts.snapshot);\n this.rewriteContent(id, current.typeId, applyMergePatch(current.content, patch), opts);\n this.appendJournal(id, opts.journal);\n });\n\n return this.reread(id, 'patchContent');\n }\n\n async setParent(\n id: string,\n parentId: string | null,\n opts: AspectWriteOptions = {},\n ): Promise<StackRecord> {\n return this.aspectUpdate(id, 'parent_id = ?', parentId, opts, 'setParent');\n }\n\n /** Stamped fresh: `Stack` hands this only a transition. */\n async setUnlisted(id: string, unlisted: boolean, opts: AspectWriteOptions = {}) {\n return this.aspectUpdate(\n id,\n 'unlisted_at = ?',\n unlisted ? toMs(new Date()) : null,\n opts,\n 'setUnlisted',\n );\n }\n\n /**\n * One records column that never bumps. The tombstone refusal and the\n * `ifVersion` guard ride in the WHERE clause, as on a versioned update.\n */\n private aspectUpdate(\n id: string,\n set: string,\n value: unknown,\n opts: AspectWriteOptions,\n verb: string,\n ): StackRecord {\n const guarded = opts.ifVersion !== undefined;\n this.exec.transaction(() => {\n const changed = this.exec.run(\n `UPDATE records SET ${set}\n WHERE id = ? AND deleted_at IS NULL${guarded ? ' AND version = ?' : ''}`,\n [value, id, ...(guarded ? [opts.ifVersion] : [])],\n );\n if (changed === 0) {\n throw versionConflict(id, opts.ifVersion as number, this.liveVersion(id));\n }\n this.appendJournal(id, opts.journal);\n });\n return this.reread(id, verb);\n }\n\n async deleteRecord(\n id: string,\n opts: { purge?: boolean } & MutateOptions = {},\n ): Promise<StackRecord | null> {\n if (opts.purge) {\n return this.exec.transaction(() => this.purgeRecord(id, opts.ifVersion));\n }\n\n // One timestamp for both columns: a soft delete is a single event, and\n // two `new Date()` calls can straddle a millisecond boundary and leave\n // deleted_at and updated_at disagreeing about when it happened.\n const now = toMs(new Date());\n this.exec.transaction(() => {\n if (opts.snapshot) this.snapshotBeforeMutation(id, opts.snapshot);\n this.versionedUpdate(id, ['deleted_at = ?'], [now], opts, now);\n this.appendJournal(id, opts.journal);\n });\n\n return this.reread(id, 'deleteRecord');\n }\n\n /**\n * Delete a record and everything that refers to it, returning the record\n * as it stood (null if there was none). Read here, inside the caller's\n * transaction, so nothing can overtake the last copy that will ever exist.\n */\n private purgeRecord(id: string, ifVersion?: number): StackRecord | null {\n const purged = this.readRecord(id);\n if (!purged) {\n // A CAS against a record that isn't there is a failed precondition,\n // not the \"nothing to delete\" that an unconditional purge\n // reports by returning null.\n if (ifVersion !== undefined) throw recordNotFound(id);\n return null;\n }\n this.checkExpectedVersion(id, purged.version, ifVersion);\n this.searchIndex.remove(id);\n this.exec.run('DELETE FROM associations WHERE record_id = ?', [id]);\n this.exec.run('DELETE FROM permissions WHERE record_id = ?', [id]);\n this.exec.run('DELETE FROM versions WHERE record_id = ?', [id]);\n // A purge takes the journal with it, for the reason it takes the\n // version history: a log naming what a destroyed record once held is\n // exactly the residue this verb exists to leave nothing of.\n this.exec.run('DELETE FROM journal WHERE record_id = ?', [id]);\n this.contentIndex.remove(id);\n this.exec.run('DELETE FROM records WHERE id = ?', [id]);\n return purged;\n }\n\n async undeleteRecord(id: string, opts: MutateOptions = {}): Promise<StackRecord> {\n this.exec.transaction(() => {\n if (opts.snapshot) this.snapshotBeforeMutation(id, opts.snapshot);\n this.versionedUpdate(id, ['deleted_at = NULL'], [], opts);\n this.appendJournal(id, opts.journal);\n });\n\n return this.reread(id, 'undelete');\n }\n\n async restoreVersion(\n id: string,\n version: number,\n opts: MutateOptions = {},\n ): Promise<StackRecord> {\n // Only content and its type are restored — a snapshot carries nothing\n // else, so there is nothing here to roll containment, listing or the\n // associations table back to.\n this.exec.transaction(() => {\n this.readForWrite(id, opts.ifVersion);\n const target = this.readVersion(id, version);\n if (!target) throw new StackNotFoundError(`Version not found: \"${id}\"@${version}`);\n if (opts.snapshot) this.snapshotBeforeMutation(id, opts.snapshot);\n this.rewriteContent(id, target.typeId, target.content, opts);\n this.appendJournal(id, opts.journal);\n });\n\n return this.reread(id, 'restoreVersion');\n }\n\n async commitMigration(\n id: string,\n toTypeId: TypeId,\n content: Record<string, unknown>,\n opts: MutateOptions = {},\n ): Promise<StackRecord> {\n this.exec.transaction(() => {\n this.readForWrite(id, opts.ifVersion);\n if (opts.snapshot) this.snapshotBeforeMutation(id, opts.snapshot);\n this.rewriteContent(id, toTypeId, content, opts);\n this.appendJournal(id, opts.journal);\n });\n\n return this.reread(id, 'commitMigration');\n }\n\n /**\n * Replace a record's type and content wholesale. Unindex, write, re-index,\n * in that order (docs/spec/adapters.md § The search index is unindexed\n * before the row moves); callers must be inside exec.transaction().\n */\n private rewriteContent(\n id: string,\n typeId: TypeId,\n content: Record<string, unknown>,\n opts: IfVersionOptions & ActorOptions,\n ): void {\n const json = JSON.stringify(content);\n this.searchIndex.remove(id);\n this.versionedUpdate(id, ['type_id = ?', 'content = ?'], [typeId, json], opts);\n this.searchIndex.insert(id, json);\n this.contentIndex.sync(id, typeId, content);\n }\n\n queryRecords(query: AdapterQuery): Promise<QueryResult> {\n return this.page(query);\n }\n\n queryReadable(query: AdapterQuery, reach: Reach): Promise<QueryResult> {\n return this.page(query, reach);\n }\n\n /** `reach`, when given, is one more condition of every statement in the plan. */\n private async page(query: AdapterQuery, reach?: Reach): Promise<QueryResult> {\n const { limit } = query;\n // One extra row, to learn whether a further page follows.\n const fetch = limit + 1;\n\n // A content-field sort is two statements (see buildQueryPlan). Each asks\n // only for what the page still lacks, so the second usually never runs.\n const rows: Record<string, unknown>[] = [];\n for (const page of buildQueryPlan(query, reach)) {\n const budget = fetch - rows.length;\n if (budget <= 0) break;\n const statement = atBudget(page, budget);\n rows.push(\n ...asStackBadRequestError(query, () =>\n this.exec.all<Record<string, unknown>>(statement.sql, statement.params),\n ),\n );\n }\n\n const hasMore = rows.length > limit;\n const page = hasMore ? rows.slice(0, limit) : rows;\n\n const records = this.hydrate(page);\n\n const lastRecord = records[records.length - 1];\n const cursor =\n hasMore && lastRecord\n ? makeCursor(lastRecord, query.sort, (record, field) =>\n this.contentIndex.kindOf(record.typeId, field),\n )\n : null;\n\n return { records, cursor };\n }\n\n /**\n * The reference check and the purges share one synchronous transaction,\n * so nothing can add a reference between the two.\n */\n async deleteUnreferencedAttachmentRecords(\n fileId: FileId,\n metadataBaseId: BaseId,\n ): Promise<StackRecord[]> {\n return this.exec.transaction(() => {\n const referenced = this.exec.all<{ found: number }>(\n `SELECT 1 as found FROM associations WHERE kind = 'attachment' AND file_id = ?\n UNION ALL\n SELECT 1 FROM content_index WHERE file_id = ?\n LIMIT 1`,\n [fileId, fileId],\n );\n if (referenced.length) {\n throw new StackConflictError('Attachment is still referenced by one or more records');\n }\n\n const family = inFamily('type_id', metadataBaseId);\n const metaRows = this.exec.all<{ id: string }>(\n `SELECT id FROM records\n WHERE ${family.sql} AND json_extract(content, '$.fileId') = ?`,\n [...family.params, fileId],\n );\n const deleted: StackRecord[] = [];\n for (const row of metaRows) {\n const purged = this.purgeRecord(row.id);\n if (purged) deleted.push(purged);\n }\n\n return deleted;\n });\n }\n\n // -------------------------------------------------------\n // Versions\n // -------------------------------------------------------\n\n async getVersions(id: string, query: VersionsQuery = {}): Promise<RecordVersion[]> {\n const conditions = ['record_id = ?'];\n const values: unknown[] = [id];\n if (query.beforeVersion !== undefined) {\n conditions.push('version < ?');\n values.push(query.beforeVersion);\n }\n const rows = this.exec.all<Record<string, unknown>>(\n `SELECT * FROM versions WHERE ${conditions.join(' AND ')} ORDER BY version DESC${\n query.limit !== undefined ? ' LIMIT ?' : ''\n }`,\n query.limit !== undefined ? [...values, query.limit] : values,\n );\n return rows.map(rowToVersion);\n }\n\n async getVersion(id: string, version: number): Promise<RecordVersion | null> {\n return this.readVersion(id, version);\n }\n\n private readVersion(id: string, version: number): RecordVersion | null {\n const row = this.exec.get<Record<string, unknown>>(\n 'SELECT * FROM versions WHERE record_id = ? AND version = ?',\n [id, version],\n );\n return row ? rowToVersion(row) : null;\n }\n\n /**\n * A (record_id, version) collision is rejected loudly via the UNIQUE\n * constraint, mapped to StackConflictError — never a silently discarded\n * snapshot leaving a hole in rollback history. See\n * docs/spec/versioning.md § Optimistic concurrency (`ifVersion`).\n */\n private insertVersionRow(id: string, version: RecordVersion): void {\n try {\n this.exec.run(\n `INSERT INTO versions\n (record_id, version, ${VERSION_COLUMNS.join(', ')})\n VALUES (?, ?, ${VERSION_COLUMNS.map(() => '?').join(', ')})`,\n [id, version.version, ...versionRowValues(version)],\n );\n } catch (err) {\n if (isUniqueConstraintViolation(err)) {\n throw new StackConflictError(\n `Version ${version.version} already exists for record \"${id}\" — a concurrent ` +\n `writer raced past this version. Use ifVersion to detect this before it happens.`,\n );\n }\n throw err;\n }\n }\n\n /**\n * Replaces every column insertVersionRow writes — structurally, off the\n * same VERSION_COLUMNS list, because a column left out here would keep\n * the replaced row's value and surface later as a restore putting back\n * something the snapshot never said.\n */\n private overwriteVersionRow(id: string, version: RecordVersion): void {\n this.exec.run(\n `UPDATE versions\n SET ${VERSION_COLUMNS.map((c) => `${c} = ?`).join(', ')}\n WHERE record_id = ? AND version = ?`,\n [...versionRowValues(version), id, version.version],\n );\n }\n\n /**\n * Standalone snapshot write for tooling and tests — loud on any\n * collision, since nothing here is about to bump the version. Mutating\n * methods take a `snapshot` option instead; see snapshotBeforeMutation.\n */\n async saveVersion(id: string, version: RecordVersion): Promise<void> {\n this.insertVersionRow(id, version);\n }\n\n /**\n * The snapshot half of a mutating method's atomic snapshot-then-mutate\n * transaction. A collision is a racing-writer conflict, except an orphan\n * row at the record's *current* version — recognized by version number\n * alone, never content — which is overwritten so the interrupted write\n * can complete. See docs/spec/versioning.md § Snapshot atomicity.\n */\n private snapshotBeforeMutation(id: string, version: RecordVersion): void {\n try {\n this.insertVersionRow(id, version);\n } catch (err) {\n if (!(err instanceof StackConflictError)) throw err;\n\n if (this.currentVersion(id) !== version.version) throw err;\n\n this.overwriteVersionRow(id, version);\n }\n }\n\n // -------------------------------------------------------\n // Change journal\n // -------------------------------------------------------\n\n /**\n * Append one entry, stamped from the row as it now stands, so callers run\n * this inside their write's transaction, after the write. `seq` is\n * allocated in the INSERT itself, so no caller ever holds one it expects\n * to be free. See docs/spec/journal.md § Ordering.\n */\n private appendJournal(recordId: string, entry: JournalEntryInput | undefined): void {\n if (!entry) return;\n // Not readRecord(): this runs on every write and needs three columns,\n // not the row plus its associations. parent_id stays raw so its\n // NULL/''/id spelling reaches the journal unchanged.\n const row = this.exec.get<{\n version: number;\n type_id: string;\n parent_id: string | null;\n }>('SELECT version, type_id, parent_id FROM records WHERE id = ?', [recordId]);\n if (!row) throw recordNotFound(recordId);\n\n this.exec.run(\n `INSERT INTO journal\n (record_id, seq, at, kind, ops, version, type_id, parent_id,\n previous_parent_id, actor, associations)\n VALUES (\n ?,\n (SELECT COALESCE(MAX(seq), 0) + 1 FROM journal WHERE record_id = ?),\n ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n [\n recordId,\n recordId,\n toMs(new Date()),\n entry.kind,\n JSON.stringify(entry.ops),\n row.version,\n row.type_id,\n row.parent_id,\n // '' is the root; NULL is an entry that names no origin at all.\n entry.previousParentId === undefined ? null : (entry.previousParentId ?? ''),\n entry.actor ? JSON.stringify(entry.actor) : null,\n entry.associations?.length ? JSON.stringify(entry.associations) : null,\n ],\n );\n }\n\n async getJournal(id: string, query: JournalQuery = {}): Promise<RecordJournalEntry[]> {\n // An empty log means \"nothing changed\" unconditionally, so a record\n // that isn't there cannot be spelled that way. A purged record is gone,\n // and gets the same refusal. See docs/spec/journal.md § Reading it.\n if (!this.exec.get('SELECT 1 FROM records WHERE id = ?', [id])) {\n throw recordNotFound(id);\n }\n const conditions = ['record_id = ?'];\n const values: unknown[] = [id];\n if (query.afterSeq !== undefined) {\n conditions.push('seq > ?');\n values.push(query.afterSeq);\n }\n const rows = this.exec.all<Record<string, unknown>>(\n `SELECT * FROM journal WHERE ${conditions.join(' AND ')} ORDER BY seq ASC${\n query.limit !== undefined ? ' LIMIT ?' : ''\n }`,\n query.limit !== undefined ? [...values, query.limit] : values,\n );\n return rows.map(rowToJournalEntry);\n }\n\n // -------------------------------------------------------\n // Types\n // -------------------------------------------------------\n\n async saveType(type: StackType): Promise<void> {\n this.exec.run(\n `INSERT OR REPLACE INTO types\n (id, base_id, version, name, schema, schema_hash, migrates_from, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,\n [\n type.id,\n type.baseId,\n type.version,\n type.name,\n JSON.stringify(type.schema),\n type.schemaHash,\n type.migratesFrom ?? null,\n toMs(type.createdAt),\n ],\n );\n this.contentIndex.rememberType(type);\n }\n\n async getType(id: TypeId): Promise<StackType | null> {\n const row = this.exec.get<Record<string, unknown>>('SELECT * FROM types WHERE id = ?', [id]);\n return row ? rowToType(row) : null;\n }\n\n async listTypes(): Promise<StackType[]> {\n const rows = this.exec.all<Record<string, unknown>>(\n 'SELECT * FROM types ORDER BY base_id, version',\n );\n return rows.map(rowToType);\n }\n\n // -------------------------------------------------------\n // Associations\n // -------------------------------------------------------\n\n /**\n * A write to one of a record's two element tables, inside a transaction\n * that first checks the record exists, is not soft-deleted, is at\n * `ifVersion`, and that the table holds `expectSet`. Never bumps and\n * never snapshots.\n */\n private elementWrite(\n id: string,\n table: 'associations' | 'permissions',\n opts: ElementWriteOptions<Association>,\n write: () => void,\n verb: string,\n ): StackRecord {\n this.exec.transaction(() => {\n this.checkExpectedVersion(id, this.liveVersion(id), opts.ifVersion);\n if (opts.expectSet) {\n const map = table === 'associations' ? rowToAssociation : rowToPermission;\n const stored = this.elementsByRecord<Association>(table, [id], map).get(id) ?? [];\n if (!sameAssociationSet(stored, opts.expectSet)) throw new ElementSetMovedError(id);\n }\n write();\n this.appendJournal(id, opts.journal);\n });\n return this.reread(id, verb);\n }\n\n async editAssociations(\n id: string,\n edits: AssociationEdit[],\n opts: ElementWriteOptions<DataAssociation> = {},\n ): Promise<StackRecord> {\n return this.elementWrite(\n id,\n 'associations',\n opts,\n () => {\n for (const edit of edits) {\n if (edit.op !== 'remove') continue;\n const association = edit.association as DataAssociation;\n this.exec.run(\n `DELETE FROM associations\n WHERE record_id = ? AND kind = ? AND label = ?\n AND file_id = ? AND related_scope = ? AND related_id = ?\n AND related_ns = ? AND related_stack = ?`,\n [id, association.kind, association.label, ...associationKeyColumns(association)],\n );\n }\n this.insertAssociations(id, addsOf(edits) as DataAssociation[]);\n },\n 'editAssociations',\n );\n }\n\n async setAssociations(\n id: string,\n associations: DataAssociation[],\n opts: ElementWriteOptions<DataAssociation> = {},\n ): Promise<StackRecord> {\n return this.elementWrite(\n id,\n 'associations',\n opts,\n () => {\n this.exec.run('DELETE FROM associations WHERE record_id = ?', [id]);\n this.insertAssociations(id, associations);\n },\n 'setAssociations',\n );\n }\n\n /** editAssociations() over the permissions table. */\n async editAccess(\n id: string,\n edits: AssociationEdit[],\n opts: ElementWriteOptions<AuthorityAssociation> = {},\n ): Promise<StackRecord> {\n return this.elementWrite(\n id,\n 'permissions',\n opts,\n () => {\n for (const edit of edits) {\n if (edit.op !== 'remove') continue;\n const permission = edit.association as AuthorityAssociation;\n this.exec.run(\n `DELETE FROM permissions\n WHERE record_id = ? AND kind = ? AND label = ?\n AND grantee_kind = ? AND grantee_id = ? AND role = ?`,\n [id, permission.kind, permission.label, ...permissionKeyColumns(permission)],\n );\n }\n this.insertPermissions(id, addsOf(edits) as AuthorityAssociation[]);\n },\n 'editAccess',\n );\n }\n\n async setAccess(\n id: string,\n permissions: AuthorityAssociation[],\n opts: ElementWriteOptions<AuthorityAssociation> = {},\n ): Promise<StackRecord> {\n return this.elementWrite(\n id,\n 'permissions',\n opts,\n () => {\n this.exec.run('DELETE FROM permissions WHERE record_id = ?', [id]);\n this.insertPermissions(id, permissions);\n },\n 'setAccess',\n );\n }\n\n /**\n * Upserts on association identity, so re-pointing `attachment_record_id`\n * (outside the key) costs no second row. A missing record trips the\n * foreign key, reported as StackNotFoundError rather than an orphan row.\n */\n private insertAssociations(recordId: string, associations: DataAssociation[]): void {\n for (const assoc of associations) {\n this.insertRow(recordId, () =>\n this.exec.run(\n `INSERT INTO associations\n (record_id, kind, label, file_id, related_scope, related_id, related_ns,\n related_stack, attachment_record_id)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT DO UPDATE SET attachment_record_id = excluded.attachment_record_id`,\n [\n recordId,\n assoc.kind,\n assoc.label,\n ...associationKeyColumns(assoc),\n assoc.kind === 'attachment' ? (assoc.attachmentRecordId ?? '') : '',\n ],\n ),\n );\n }\n }\n\n /** Every column is in the key, so a repeated element is the same row. */\n private insertPermissions(recordId: string, permissions: AuthorityAssociation[]): void {\n for (const p of permissions) {\n this.insertRow(recordId, () =>\n this.exec.run(\n `INSERT INTO permissions (record_id, kind, label, grantee_kind, grantee_id, role)\n VALUES (?, ?, ?, ?, ?, ?)\n ON CONFLICT DO NOTHING`,\n [recordId, p.kind, p.label, ...permissionKeyColumns(p)],\n ),\n );\n }\n }\n\n private insertRow(recordId: string, insert: () => void): void {\n try {\n insert();\n } catch (err) {\n if (isForeignKeyViolation(err)) throw recordNotFound(recordId);\n throw err;\n }\n }\n\n /**\n * One element table's rows for every record in `ids`, in primary-key\n * order — the order a single record's read has always had.\n */\n private elementsByRecord<T>(\n table: 'associations' | 'permissions',\n ids: readonly string[],\n map: (row: Record<string, unknown>) => T,\n ): Map<string, T[]> {\n const byRecord = new Map<string, T[]>();\n const rows = this.exec.all<Record<string, unknown>>(\n `WITH ids AS MATERIALIZED ${rowsTable(['id'])}\n SELECT * FROM ${table} WHERE record_id IN (SELECT id FROM ids)\n ORDER BY ${table === 'associations' ? ASSOCIATION_KEY : PERMISSION_KEY}`,\n [JSON.stringify(ids.map((id) => [id]))],\n );\n for (const row of rows) {\n const id = row.record_id as string;\n const list = byRecord.get(id);\n if (list) list.push(map(row));\n else byRecord.set(id, [map(row)]);\n }\n return byRecord;\n }\n}\n\n/** Each element table's primary key, so a batched read keeps one record's own order. */\nconst ASSOCIATION_KEY =\n 'record_id, kind, label, file_id, related_scope, related_id, related_ns, related_stack';\nconst PERMISSION_KEY = 'record_id, kind, label, grantee_kind, grantee_id, role';\n\nconst addsOf = (edits: readonly AssociationEdit[]) =>\n edits.flatMap((e) => (e.op === 'add' ? [e.association] : []));\n","/**\n * The engine-independent half of a SQLite-backed StackRecordAdapter: the\n * capability declaration and the delegation of all twenty-three\n * StackRecordAdapter methods onto SharedSqlRecordLogic. Every method here\n * is a forward with no engine-specific content, so an adapter that owns a\n * SqlExecutor already knows how to answer all of them.\n *\n * What a concrete adapter is left to supply is exactly what differs\n * between bindings: constructing the database handle, applying the\n * schema, and its own lifecycle (flush/close) — hence those two being the\n * only abstract members.\n *\n * Lives in record.js's barrel rather than index.js's, so an adapter that\n * imports it never pulls in token-logic.ts's `node:crypto` — see the note\n * at the top of record.ts.\n */\n\nimport type {\n JournalQuery,\n VersionsQuery,\n RecordJournalEntry,\n StackType,\n TypeId,\n BaseId,\n FileId,\n RecordVersion,\n StackRecord,\n QueryResult,\n AssociationEdit,\n AuthorityAssociation,\n DataAssociation,\n StackCapabilities,\n} from '@haverstack/core';\nimport type {\n AdapterQuery,\n StackRecordAdapter,\n AspectWriteOptions,\n ElementWriteOptions,\n JournalOptions,\n MutateOptions,\n Reach,\n} from '@haverstack/core/adapter';\nimport type { SqlExecutor } from './executor.js';\nimport type { StackConfig } from './config.js';\nimport { SharedSqlRecordLogic } from './record-logic.js';\n\n/**\n * What every engine running SharedSqlRecordLogic's query builder supports.\n * It describes the shared SQL, not the binding, so it is the same for each\n * of them — an engine whose SQLite build lacked FTS5 would override\n * `filter.search` rather than restate the whole declaration.\n */\nexport const SQLITE_RECORD_CAPABILITIES: StackCapabilities = {\n filter: {\n content: 'path',\n contentPresent: true,\n contentByType: true,\n search: true,\n },\n sort: {\n fields: ['createdAt', 'updatedAt', 'version'],\n contentField: true,\n contentFieldByType: true,\n },\n limits: {\n attachmentBytes: null,\n contentBytes: null,\n },\n};\n\nexport abstract class SharedSqlRecordAdapter implements StackRecordAdapter {\n readonly capabilities: StackCapabilities = SQLITE_RECORD_CAPABILITIES;\n\n readonly ownerEntityId: string;\n readonly timezone: string | undefined;\n\n private readonly record: SharedSqlRecordLogic;\n\n protected constructor(exec: SqlExecutor, config: StackConfig) {\n this.record = new SharedSqlRecordLogic({ exec });\n this.ownerEntityId = config.entityId;\n this.timezone = config.timezone;\n }\n\n // -------------------------------------------------------\n // Records\n // -------------------------------------------------------\n\n createRecord(record: StackRecord, opts?: JournalOptions): Promise<StackRecord> {\n return this.record.createRecord(record, opts);\n }\n\n getRecord(id: string): Promise<StackRecord | null> {\n return this.record.getRecord(id);\n }\n\n patchContent(\n id: string,\n patch: Record<string, unknown | null>,\n opts?: MutateOptions,\n ): Promise<StackRecord> {\n return this.record.patchContent(id, patch, opts);\n }\n\n setParent(id: string, parentId: string | null, opts?: AspectWriteOptions): Promise<StackRecord> {\n return this.record.setParent(id, parentId, opts);\n }\n\n setUnlisted(id: string, unlisted: boolean, opts?: AspectWriteOptions): Promise<StackRecord> {\n return this.record.setUnlisted(id, unlisted, opts);\n }\n\n deleteRecord(\n id: string,\n opts?: { purge?: boolean } & MutateOptions,\n ): Promise<StackRecord | null> {\n return this.record.deleteRecord(id, opts);\n }\n\n undeleteRecord(id: string, opts?: MutateOptions): Promise<StackRecord> {\n return this.record.undeleteRecord(id, opts);\n }\n\n restoreVersion(id: string, version: number, opts?: MutateOptions): Promise<StackRecord> {\n return this.record.restoreVersion(id, version, opts);\n }\n\n commitMigration(\n id: string,\n toTypeId: TypeId,\n content: Record<string, unknown>,\n opts?: MutateOptions,\n ): Promise<StackRecord> {\n return this.record.commitMigration(id, toTypeId, content, opts);\n }\n\n queryRecords(query: AdapterQuery): Promise<QueryResult> {\n return this.record.queryRecords(query);\n }\n\n queryReadable(query: AdapterQuery, reach: Reach): Promise<QueryResult> {\n return this.record.queryReadable(query, reach);\n }\n\n deleteUnreferencedAttachmentRecords(\n fileId: FileId,\n metadataBaseId: BaseId,\n ): Promise<StackRecord[]> {\n return this.record.deleteUnreferencedAttachmentRecords(fileId, metadataBaseId);\n }\n\n // -------------------------------------------------------\n // Versions\n // -------------------------------------------------------\n\n getVersions(id: string, query?: VersionsQuery): Promise<RecordVersion[]> {\n return this.record.getVersions(id, query);\n }\n\n getVersion(id: string, version: number): Promise<RecordVersion | null> {\n return this.record.getVersion(id, version);\n }\n\n saveVersion(id: string, version: RecordVersion): Promise<void> {\n return this.record.saveVersion(id, version);\n }\n\n // -------------------------------------------------------\n // Change journal\n // -------------------------------------------------------\n\n getJournal(id: string, query?: JournalQuery): Promise<RecordJournalEntry[]> {\n return this.record.getJournal(id, query);\n }\n\n // -------------------------------------------------------\n // Types\n // -------------------------------------------------------\n\n saveType(type: StackType): Promise<void> {\n return this.record.saveType(type);\n }\n\n getType(id: TypeId): Promise<StackType | null> {\n return this.record.getType(id);\n }\n\n listTypes(): Promise<StackType[]> {\n return this.record.listTypes();\n }\n\n // -------------------------------------------------------\n // Associations and permissions\n // -------------------------------------------------------\n\n editAssociations(\n id: string,\n edits: AssociationEdit[],\n opts?: ElementWriteOptions<DataAssociation>,\n ): Promise<StackRecord> {\n return this.record.editAssociations(id, edits, opts);\n }\n\n setAssociations(\n id: string,\n associations: DataAssociation[],\n opts?: ElementWriteOptions<DataAssociation>,\n ): Promise<StackRecord> {\n return this.record.setAssociations(id, associations, opts);\n }\n\n editAccess(\n id: string,\n edits: AssociationEdit[],\n opts?: ElementWriteOptions<AuthorityAssociation>,\n ): Promise<StackRecord> {\n return this.record.editAccess(id, edits, opts);\n }\n\n setAccess(\n id: string,\n permissions: AuthorityAssociation[],\n opts?: ElementWriteOptions<AuthorityAssociation>,\n ): Promise<StackRecord> {\n return this.record.setAccess(id, permissions, opts);\n }\n\n // -------------------------------------------------------\n // Lifecycle\n // -------------------------------------------------------\n\n abstract flush(): Promise<void>;\n abstract close(): Promise<void>;\n}\n","/**\n * Storage-ownership lock file. A stack file is owned by exactly one\n * process at a time (see docs/spec/adapters.md § Concurrency & storage ownership).\n * The lock file sits beside the database and records the PID of its\n * opener — pure Node fs/process logic, no SQLite engine involved, so\n * every Node-backed record adapter shares one implementation and one\n * error message.\n */\n\nimport { readFileSync, writeFileSync, existsSync, unlinkSync } from 'fs';\n\ntype LockInfo = { pid: number };\n\nconst lockPathFor = (dbPath: string): string => `${dbPath}.lock`;\n\nconst isProcessAlive = (pid: number): boolean => {\n try {\n process.kill(pid, 0);\n return true;\n } catch (err) {\n // ESRCH: no such process — safe to reclaim. Anything else (e.g. EPERM,\n // meaning the process exists but we can't signal it) — assume alive.\n return (err as NodeJS.ErrnoException).code !== 'ESRCH';\n }\n};\n\n/**\n * Acquire the lock, throwing a clear error if another live process\n * already holds it. Reclaims stale locks (owning process no longer\n * running) automatically. `force` bypasses the check entirely, for the\n * rare case of PID reuse across a reboot.\n */\nexport const acquireLock = (dbPath: string, force?: boolean): void => {\n const lockPath = lockPathFor(dbPath);\n const info = readLock(lockPath);\n if (info) {\n const ownedBySelf = info.pid === process.pid;\n if (!ownedBySelf && !force && isProcessAlive(info.pid)) {\n throw new Error(\n `Stack database at \"${dbPath}\" is in use by another process (pid ${info.pid}). ` +\n `Connect via its server instead, or pass { force: true } to override. ` +\n `If no such process is running, remove \"${lockPath}\".`,\n );\n }\n }\n writeFileSync(lockPath, JSON.stringify({ pid: process.pid } satisfies LockInfo));\n};\n\n/**\n * Read the lock, treating an unreadable one as absent. A crash mid-write\n * leaves a torn lock naming no live process, which is what acquireLock()\n * reclaims anyway; refusing it would lock the data out for good. The lock\n * exists to stop a second writer, not to outrank the data it guards.\n */\nconst readLock = (lockPath: string): LockInfo | null => {\n try {\n const info = JSON.parse(readFileSync(lockPath, 'utf-8')) as LockInfo;\n return typeof info?.pid === 'number' ? info : null;\n } catch {\n return null;\n }\n};\n\n/**\n * Release the lock, if it's still owned by this process. An unreadable lock\n * is removed rather than left behind: readLock() treats it as absent and\n * acquireLock() would reclaim it anyway, so leaving it would only make\n * storage look permanently locked to a reader that doesn't get that far.\n */\nexport const releaseLock = (dbPath: string): void => {\n const lockPath = lockPathFor(dbPath);\n if (!existsSync(lockPath)) return;\n const info = readLock(lockPath);\n if (!info || info.pid === process.pid) unlinkSync(lockPath);\n};\n","/**\n * The actual StackTokenStore logic (createToken/lookupToken/listTokens/\n * revokeToken), parametrized over a SqlExecutor. Consumed by\n * record-adapter-sqlite's NativeTokenStore, which points it at a file\n * separate from records — see TOKENS_SCHEMA_SQL in schema.ts.\n */\n\nimport { createHash, randomBytes } from 'node:crypto';\nimport type { Actor } from '@haverstack/core';\nimport type { TokenSession, TokenInfo } from '@haverstack/core/wire';\nimport type { SqlExecutor } from './executor.js';\nimport { toMs, fromMs } from './mappers.js';\n\n/**\n * How a bearer token is reduced to what the `tokens` table stores. One\n * function because createToken and lookupToken must agree exactly — a\n * divergence would silently make every issued token unlookupable.\n */\nconst hashToken = (token: string): string => createHash('sha256').update(token).digest('hex');\n\nexport type SharedTokenLogicDeps = {\n exec: SqlExecutor;\n};\n\nexport class SharedTokenLogic {\n private readonly exec: SqlExecutor;\n\n constructor({ exec }: SharedTokenLogicDeps) {\n this.exec = exec;\n }\n\n async createToken(\n actor: Actor,\n opts: { label?: string; expiresAt?: Date } = {},\n ): Promise<{ id: string; token: string }> {\n const id = randomBytes(8).toString('hex');\n const token = randomBytes(32).toString('hex');\n const tokenHash = hashToken(token);\n this.exec.run(\n 'INSERT INTO tokens (id, token_hash, principal_id, subject_id, label, created_at, expires_at) VALUES (?, ?, ?, ?, ?, ?, ?)',\n [\n id,\n tokenHash,\n // Stored rather than left null for an undelegated token, so a\n // reader never has to know which column stands in for the other.\n actor.principalId ?? actor.subjectId,\n actor.subjectId,\n opts.label ?? null,\n toMs(new Date()),\n opts.expiresAt ? toMs(opts.expiresAt) : null,\n ],\n );\n return { id, token };\n }\n\n async lookupToken(token: string): Promise<TokenSession | null> {\n const hash = hashToken(token);\n const row = this.exec.get<{\n principal_id: string;\n subject_id: string;\n expires_at: number | null;\n }>('SELECT principal_id, subject_id, expires_at FROM tokens WHERE token_hash = ?', [hash]);\n if (!row) return null;\n if (row.expires_at !== null && Date.now() > row.expires_at) return null;\n return { principalId: row.principal_id, subjectId: row.subject_id };\n }\n\n async listTokens(): Promise<TokenInfo[]> {\n const rows = this.exec.all<{\n id: string;\n principal_id: string;\n subject_id: string;\n label: string | null;\n created_at: number;\n expires_at: number | null;\n }>(\n 'SELECT id, principal_id, subject_id, label, created_at, expires_at FROM tokens ORDER BY created_at DESC',\n );\n return rows.map((row) => ({\n id: row.id,\n principalId: row.principal_id,\n subjectId: row.subject_id,\n ...(row.label && { label: row.label }),\n createdAt: fromMs(row.created_at),\n ...(row.expires_at !== null && { expiresAt: fromMs(row.expires_at) }),\n }));\n }\n\n async revokeToken(id: string): Promise<void> {\n this.exec.run('DELETE FROM tokens WHERE id = ?', [id]);\n }\n}\n","import type { SqlExecutor } from '@haverstack/sqlite-shared';\nimport { DatabaseSync } from './node-sqlite.js';\n\n/** Normalizes node:sqlite's spread-args run/get/all calls to SqlExecutor. */\nexport class NativeSqliteExecutor implements SqlExecutor {\n constructor(private readonly db: DatabaseSync) {}\n\n exec(sql: string): void {\n this.db.exec(sql);\n }\n\n run(sql: string, params: readonly unknown[] = []): number {\n const result = this.db.prepare(sql).run(...(params as (string | number | null)[]));\n return Number(result.changes);\n }\n\n get<T = Record<string, unknown>>(sql: string, params: readonly unknown[] = []): T | undefined {\n return this.db.prepare(sql).get(...(params as (string | number | null)[])) as T | undefined;\n }\n\n all<T = Record<string, unknown>>(sql: string, params: readonly unknown[] = []): T[] {\n return this.db.prepare(sql).all(...(params as (string | number | null)[])) as T[];\n }\n\n transaction<T>(fn: () => T): T {\n this.db.exec('BEGIN');\n try {\n const result = fn();\n this.db.exec('COMMIT');\n return result;\n } catch (err) {\n this.db.exec('ROLLBACK');\n throw err;\n }\n }\n}\n","/**\n * Bearer-token storage backing @haverstack/core's StackTokenStore,\n * implemented against its own file — deliberately separate from\n * NativeSQLiteRecordAdapter's records database. The portable stack file\n * is \"your data, take it with you\"; auth material shouldn't travel with\n * it, and restoring a backup shouldn't resurrect revoked tokens. Server\n * implementations wire these up as separate parts\n * (`{ adapter, tokens }`), the same philosophy as combineAdapters().\n *\n * The actual createToken/lookupToken/listTokens/revokeToken logic lives\n * in @haverstack/sqlite-shared's SharedTokenLogic, reached through the\n * SqlExecutor interface.\n */\n\nimport type { Actor } from '@haverstack/core';\nimport type { TokenSession, StackTokenStore, TokenInfo } from '@haverstack/core/wire';\nimport {\n TOKENS_SCHEMA_SQL,\n PRAGMA_JOURNAL_MODE_WAL,\n acquireLock,\n releaseLock,\n SharedTokenLogic,\n} from '@haverstack/sqlite-shared';\nimport { DatabaseSync } from './node-sqlite.js';\nimport { NativeSqliteExecutor } from './executor.js';\n\n/** Conventional sibling path for a token store beside a stack's main .db file. */\nexport const defaultTokenStorePath = (dbPath: string): string => `${dbPath}.tokens`;\n\nexport type NativeTokenStoreOpenOptions = {\n /** Absolute path to the token store file. Created if it doesn't exist. */\n path: string;\n /** Bypass the storage-ownership lock check. See docs/spec/adapters.md § Concurrency & storage ownership. */\n force?: boolean;\n};\n\nexport class NativeTokenStore implements StackTokenStore {\n private db!: DatabaseSync;\n private tokens!: SharedTokenLogic;\n\n private constructor(private readonly path: string) {}\n\n /** Opens the token store, creating the file and schema if needed. */\n static async open(opts: NativeTokenStoreOpenOptions): Promise<NativeTokenStore> {\n acquireLock(opts.path, opts.force);\n const store = new NativeTokenStore(opts.path);\n store.db = new DatabaseSync(opts.path);\n store.db.exec(PRAGMA_JOURNAL_MODE_WAL);\n store.db.exec(TOKENS_SCHEMA_SQL);\n store.tokens = new SharedTokenLogic({ exec: new NativeSqliteExecutor(store.db) });\n return store;\n }\n\n createToken(\n actor: Actor,\n opts?: { label?: string; expiresAt?: Date },\n ): Promise<{ id: string; token: string }> {\n return this.tokens.createToken(actor, opts);\n }\n\n lookupToken(token: string): Promise<TokenSession | null> {\n return this.tokens.lookupToken(token);\n }\n\n listTokens(): Promise<TokenInfo[]> {\n return this.tokens.listTokens();\n }\n\n revokeToken(id: string): Promise<void> {\n return this.tokens.revokeToken(id);\n }\n\n async close(): Promise<void> {\n this.db.close();\n releaseLock(this.path);\n }\n}\n","/**\n * Haverstack — Native SQLite Record Adapter\n * -------------------------------------------------------\n * Implements StackRecordAdapter using node:sqlite (Node's built-in\n * SQLite binding, Node >= 22.5). No native compilation, no node-gyp,\n * no prebuilt binaries, and writes go straight to the file via normal\n * SQLite journaling (WAL mode) — no whole-database rewrite per write,\n * no in-memory copy of the whole store, real OS-level file locking.\n * Full-text search uses FTS5.\n *\n * A stack file is owned by exactly one process at a time (see\n * docs/spec/adapters.md § Concurrency & storage ownership). open()\n * acquires a PID-stamped lock file beside the database and rejects if\n * another live process already holds it; close() releases it.\n *\n * Token storage is a separate concern — see NativeTokenStore in this\n * package, which implements @haverstack/core's StackTokenStore against\n * its own file rather than this adapter's records database.\n *\n * This class itself is a thin node:sqlite binding: opening the file, the\n * storage-ownership lock, and the WAL checkpoint are what's genuinely\n * engine-specific and live here. Everything above storage comes from\n * @haverstack/sqlite-shared's SharedSqlRecordAdapter, reached through the\n * SqlExecutor interface (NativeSqliteExecutor here normalizes node:sqlite's\n * spread-args run/get/all calls to it).\n */\n\nimport { DatabaseSync } from './node-sqlite.js';\nimport { existsSync } from 'fs';\nimport {\n applyRecordSchema,\n acquireLock,\n releaseLock,\n insertConfigRecord,\n readStackConfig,\n SharedSqlRecordAdapter,\n type StackConfig,\n} from '@haverstack/sqlite-shared';\nimport { OwnerMismatchError } from '@haverstack/core/adapter';\nimport { NativeSqliteExecutor } from './executor.js';\n\n// -------------------------------------------------------\n// Types\n// -------------------------------------------------------\n\n/** What open() does when the store is missing or present, like O_CREAT / O_EXCL. */\nexport type StoreCreateMode = 'never' | 'ifMissing' | 'exclusive';\n\n/** A plain DID, or a lazy provider called only when a store is actually created. */\nexport type OwnerEntityIdInput = string | (() => string | Promise<string>);\n\nexport type NativeSQLiteRecordAdapterOpenOptions = {\n /** Absolute path to the .db file. */\n path: string;\n /** IANA timezone string e.g. \"America/New_York\". Consulted only when a store is created. No default. */\n timezone?: string;\n /**\n * Open even if a lock file from another live process is present.\n * Only needed if that process is gone but its PID was reused by\n * something else (the automatic stale-lock check already reclaims\n * locks whose owning process is no longer running).\n */\n force?: boolean;\n} & (\n | {\n /** Open an existing store; fail if the file is missing. */\n create?: 'never';\n /** Checked against the existing store's owner; a mismatch throws OwnerMismatchError. */\n ownerEntityId?: string;\n }\n | {\n /** `'ifMissing'` opens the store if present and creates it if not; `'exclusive'` creates it and fails if present. */\n create: 'ifMissing' | 'exclusive';\n /**\n * Owner of a newly created store. A plain string is also checked against an\n * existing store's owner; a lazy provider is never called just to compare.\n */\n ownerEntityId: OwnerEntityIdInput;\n }\n);\n\n// -------------------------------------------------------\n// NativeSQLiteRecordAdapter\n// -------------------------------------------------------\n\nexport class NativeSQLiteRecordAdapter extends SharedSqlRecordAdapter {\n private constructor(\n private readonly path: string,\n private readonly db: DatabaseSync,\n exec: NativeSqliteExecutor,\n config: StackConfig,\n ) {\n super(exec, config);\n }\n\n /**\n * Opens or creates the stack database at `path` according to `create`.\n * Takes the storage-ownership lock first and releases it again if the\n * open fails, since the caller never receives an adapter to close.\n * See docs/spec/adapters.md § Construction.\n */\n static async open(\n opts: NativeSQLiteRecordAdapterOpenOptions,\n ): Promise<NativeSQLiteRecordAdapter> {\n const mode: StoreCreateMode = opts.create ?? 'never';\n const checkMode = (exists: boolean): void => {\n if (!exists && mode === 'never') {\n throw new Error(\n `Cannot open: no database found at \"${opts.path}\". ` +\n `Pass create: 'ifMissing' or 'exclusive' to create one.`,\n );\n }\n if (exists && mode === 'exclusive') {\n throw new Error(\n `Cannot create: database already exists at \"${opts.path}\". ` +\n `Pass create: 'never' or 'ifMissing' to open it.`,\n );\n }\n };\n const existedBeforeLock = existsSync(opts.path);\n checkMode(existedBeforeLock);\n\n // Resolved before the lock is taken so a failing provider leaves nothing held.\n let newOwner: string | undefined;\n if (!existedBeforeLock) {\n newOwner =\n typeof opts.ownerEntityId === 'function' ? await opts.ownerEntityId() : opts.ownerEntityId;\n if (!newOwner) {\n throw new Error(\n `Cannot create: no ownerEntityId given for the new database at \"${opts.path}\".`,\n );\n }\n }\n\n acquireLock(opts.path, opts.force);\n let db: DatabaseSync | undefined;\n try {\n // Re-checked under the lock: another process may have created the file meanwhile.\n const exists = existsSync(opts.path);\n checkMode(exists);\n db = new DatabaseSync(opts.path);\n const exec = new NativeSqliteExecutor(db);\n applyRecordSchema(exec, { wal: true });\n let config: StackConfig;\n if (exists) {\n config = readStackConfig(exec);\n if (typeof opts.ownerEntityId === 'string' && opts.ownerEntityId !== config.entityId) {\n throw new OwnerMismatchError(opts.ownerEntityId, config.entityId, `\"${opts.path}\"`);\n }\n } else {\n if (!newOwner) throw new Error(`Cannot create: \"${opts.path}\" vanished while opening.`);\n config = insertConfigRecord(exec, newOwner, opts.timezone);\n }\n return new NativeSQLiteRecordAdapter(opts.path, db, exec, config);\n } catch (err) {\n db?.close();\n releaseLock(opts.path);\n throw err;\n }\n }\n\n // -------------------------------------------------------\n // Lifecycle\n // -------------------------------------------------------\n\n /** Folds the WAL back into the main file — useful before copying/backing up the database. */\n async flush(): Promise<void> {\n this.db.exec('PRAGMA wal_checkpoint(TRUNCATE);');\n }\n\n async close(): Promise<void> {\n this.db.close();\n releaseLock(this.path);\n }\n}\n\nexport {\n NativeTokenStore,\n defaultTokenStorePath,\n type NativeTokenStoreOpenOptions,\n} from './token-store.js';\n"]}
|