@rebasepro/client 0.24.0 → 0.24.1-canary.gcb918fc
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -10
- package/dist/admin-contract.types.d.ts +21 -0
- package/dist/admin.d.ts +4 -0
- package/dist/auth.d.ts +26 -4
- package/dist/backups.d.ts +13 -2
- package/dist/collection.d.ts +37 -16
- package/dist/cron.d.ts +12 -5
- package/dist/exports-contract.types.d.ts +39 -0
- package/dist/functions.d.ts +2 -12
- package/dist/index.d.ts +36 -10
- package/dist/index.es.js +1033 -4301
- package/dist/index.es.js.map +1 -1
- package/dist/offline-QNQgsPOq.js +3307 -0
- package/dist/offline-QNQgsPOq.js.map +1 -0
- package/dist/offline-codec.d.ts +12 -0
- package/dist/offline-errors.d.ts +9 -0
- package/dist/offline-lazy.d.ts +58 -0
- package/dist/offline-store-Cm5sAX81.js +1837 -0
- package/dist/offline-store-Cm5sAX81.js.map +1 -0
- package/dist/offline-store.d.ts +37 -0
- package/dist/offline.d.ts +228 -16
- package/dist/query-contract.types.d.ts +53 -1
- package/dist/realtime-channel.d.ts +25 -0
- package/dist/reviver.d.ts +18 -0
- package/dist/storage-resumable-VO-cMpse.js +2 -0
- package/dist/storage-resumable.d.ts +1 -0
- package/dist/transport.d.ts +85 -5
- package/dist/websocket.d.ts +94 -11
- package/package.json +4 -4
- package/dist/query_builder.d.ts +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"offline-QNQgsPOq.js","names":[],"sources":["../src/offline-codec.ts","../src/offline-connectivity.ts","../src/offline-query.ts","../src/offline.ts"],"sourcesContent":["import { EntityReference, EntityRelation, GeoPoint, Vector } from \"@rebasepro/types\";\nimport { rebaseReviver } from \"./reviver\";\nimport type { PendingMutation } from \"./offline-store\";\n\n/**\n * Lossless round-tripping of rows through the offline store.\n *\n * Both persistence backends move values by structured clone, which keeps\n * `Date` but flattens every class instance to a plain object. For\n * `EntityReference`/`EntityRelation` that is harmless — they carry their own\n * `__type` discriminator, so the JSON reviver can rebuild them — but\n * `GeoPoint` and `Vector` do not, and would come back out of the cache as\n * anonymous `{ latitude, longitude }` / `{ value }` bags. A row read from the\n * cache must be indistinguishable from the same row read from the network, so\n * those two are tagged on the way in and revived on the way out.\n *\n * Type tests here are structural rather than `instanceof`, because a structured\n * clone can arrive from another realm — an iframe, a worker, or the polyfill\n * the tests run against — where the constructor identity differs but the value\n * is the real thing. Only *plain* objects are walked; anything else is passed\n * through whole, so a class instance is never quietly reduced to `{}`.\n */\n\nfunction isDate(value: unknown): value is Date {\n return Object.prototype.toString.call(value) === \"[object Date]\";\n}\n\n/** An object literal — not a Date, RegExp, Map, or any class instance. */\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) return false;\n const proto = Object.getPrototypeOf(value) as { constructor?: { name?: string } } | null;\n if (proto === null || proto === Object.prototype) return true;\n // A literal cloned out of another realm has a different `Object.prototype`\n // but is still, in every way that matters here, a plain object.\n return proto.constructor?.name === \"Object\";\n}\n\n/**\n * `out[key] = value`, as an own property whatever the key. Assigned, a key\n * read from stored data that is literally `__proto__` (which `JSON.parse`\n * creates as an own property) set the new object's prototype instead, and the\n * column was gone from the row.\n */\nexport function setOwn(out: Record<string, unknown>, key: string, value: unknown): void {\n Object.defineProperty(out, key, { value, enumerable: true, writable: true, configurable: true });\n}\n\nfunction dehydrateValue(value: unknown): unknown {\n if (value === null || value === undefined) return value;\n if (value instanceof GeoPoint) {\n return { __type: \"GeoPoint\", latitude: value.latitude, longitude: value.longitude };\n }\n if (value instanceof Vector) return { __type: \"Vector\", value: [...value.value] };\n // EntityReference/EntityRelation already serialize themselves via `__type`\n // own properties, so a structured clone is enough for the reviver below.\n if (value instanceof EntityReference || value instanceof EntityRelation) return value;\n if (Array.isArray(value)) return value.map(dehydrateValue);\n if (isPlainObject(value)) {\n const out: Record<string, unknown> = {};\n for (const [key, inner] of Object.entries(value)) setOwn(out, key, dehydrateValue(inner));\n return out;\n }\n return value;\n}\n\nfunction hydrateValue(value: unknown): unknown {\n if (value === null || value === undefined || isDate(value)) return value;\n if (Array.isArray(value)) return value.map(hydrateValue);\n if (typeof value === \"object\") {\n const revived = rebaseReviver(\"\", value);\n // The reviver recognised it — hand back the class instance untouched\n // rather than walking into its (now private) internals.\n if (revived !== value) return revived;\n if (!isPlainObject(value)) return value;\n const out: Record<string, unknown> = {};\n for (const [key, inner] of Object.entries(value)) setOwn(out, key, hydrateValue(inner));\n return out;\n }\n return value;\n}\n\n/** Prepare a row for the store. */\nexport function dehydrateRow<T extends Record<string, unknown>>(row: T): Record<string, unknown> {\n return dehydrateValue(row) as Record<string, unknown>;\n}\n\n/** Restore a row read back from the store. */\nexport function hydrateRow<T extends Record<string, unknown>>(row: Record<string, unknown>): T {\n return hydrateValue(row) as T;\n}\n\n/**\n * A queued write as the store keeps it, and back. Its payloads are rows, and\n * a row read back from the queue has to be the row that was queued: stored\n * raw, a pending `GeoPoint` came back after a reload as a bare\n * `{ latitude, longitude }`, was overlaid onto the server's rows, and was\n * written back to the cache that way.\n */\nfunction mapMutation(op: PendingMutation, map: (value: unknown) => unknown): PendingMutation {\n const rows = (value: PendingMutation[\"data\"]) => value === undefined ? value : map(value) as PendingMutation[\"data\"];\n return {\n ...op,\n ...(op.data !== undefined ? { data: rows(op.data) } : {}),\n ...(op.parts ? { parts: op.parts.map((part) => map(part) as Record<string, unknown>) } : {}),\n ...(op.updates ? { updates: op.updates.map((u) => ({ id: u.id, data: map(u.data) as Record<string, unknown> })) } : {}),\n ...(op.rollback\n ? {\n rollback: {\n rows: Object.fromEntries(Object.entries(op.rollback.rows).map(([id, row]) =>\n [id, row === null ? null : map(row) as Record<string, unknown>]))\n }\n }\n : {}),\n ...(op.sent?.data !== undefined ? { sent: { ...op.sent, data: rows(op.sent.data) } } : {})\n };\n}\n\n/** Prepare a queued write for the store. */\nexport function dehydrateMutation(op: PendingMutation): PendingMutation {\n return mapMutation(op, dehydrateValue);\n}\n\n/** Restore a queued write read back from the store. */\nexport function hydrateMutation(op: PendingMutation): PendingMutation {\n return mapMutation(op, hydrateValue);\n}\n","import { RebaseApiError } from \"./transport\";\nimport { unref } from \"@rebasepro/utils\";\n\n/**\n * Whether the network is worth trying, and when to try again after it wasn't.\n *\n * `navigator.onLine` is necessary but not sufficient: it reports the state of\n * the network interface, so it stays `true` behind a captive portal, on a\n * connection that resolves DNS but reaches nothing, and while the API itself\n * is down. This tracks what actually happened to requests as well, so the\n * first failure is the only one an app pays for — everything after it inside\n * the backoff window skips the doomed round trip and answers from the local\n * store immediately, which is the difference between an app that freezes when\n * the wifi drops and one that does not.\n */\n\n/**\n * The request never reached the server, so nothing was decided by it.\n *\n * One question, one answer: `status === 0` is how a transport spells \"there\n * was no response at all\", and the transport now wraps every `fetch` rejection\n * into a `RebaseApiError` carrying it. This used to also sniff for the shapes\n * a raw `fetch` rejects with — a `TypeError` in a browser, an `AbortError`, a\n * `TimeoutError` — which is a list that has to be kept in step with three\n * runtimes and was wrong in both directions: it missed anything they add, and\n * it claimed a `TypeError` thrown by application code inside a callback was a\n * network failure, which quietly served a cached answer in its place.\n */\nexport function isNetworkError(error: unknown): boolean {\n return error instanceof RebaseApiError && error.status === 0;\n}\n\n/**\n * Statuses that mean \"not now\" rather than \"not ever\": a queued write that\n * gets one of these is worth replaying, while a 400 or a 403 never will be.\n * 500 is deliberately absent — an unhandled server error is far more often a\n * bug the same payload will hit again than a blip, and retrying it forever\n * jams every write behind it.\n */\nconst RETRYABLE_STATUSES = new Set([408, 425, 429, 502, 503, 504]);\n\n/**\n * The server holds this key for a request it has not answered yet.\n *\n * It is a 409 like a duplicate row is a 409, and nothing but the code separates\n * them — one means \"your write is already there\", the other means \"your write\n * may not have happened at all, ask again\".\n */\nconst IDEMPOTENCY_IN_PROGRESS = \"IDEMPOTENCY_KEY_IN_PROGRESS\";\n\n/**\n * Is the server still answering an earlier attempt of this same write?\n *\n * The only correct response is to ask again — which is exactly what the\n * server's own message says, and exactly what this SDK used not to do.\n */\nexport function isIdempotencyInProgressError(error: unknown): boolean {\n return error instanceof RebaseApiError\n && error.status === 409\n && error.code === IDEMPOTENCY_IN_PROGRESS;\n}\n\n/**\n * Is this key held for a different request than the one just sent with it?\n *\n * For a create the queue already sent once, that is an answer rather than a\n * failure: the key is live only because the first attempt got through and\n * committed, and only its response went missing.\n */\nexport function isIdempotencyKeyReusedError(error: unknown): boolean {\n return error instanceof RebaseApiError\n && error.status === 422\n && error.code === \"IDEMPOTENCY_KEY_REUSED\";\n}\n\n/** Is this failure worth another attempt later? */\nexport function isRetryableError(error: unknown): boolean {\n if (isNetworkError(error)) return true;\n if (!(error instanceof RebaseApiError)) return false;\n // The one 409 that resolves on its own. A key whose claim outlived the\n // request that took it — the process was killed between the write and the\n // answer — is refused until the claim's lease expires, and giving up on it\n // means dropping a write that retrying would have completed.\n if (isIdempotencyInProgressError(error)) return true;\n return error.status !== undefined && RETRYABLE_STATUSES.has(error.status);\n}\n\n/**\n * Did this write fail because the row is already there?\n *\n * Matched on the SQLSTATE the server passes through (`23505`, unique_violation)\n * and on 409, never on the message — a duplicate-key message names the\n * constraint and the values, so it is neither stable nor safe to parse.\n *\n * The queue uses this to recognise its own earlier attempt. A create whose\n * response was lost is replayed, and for a row carrying an id the SDK generated\n * the server can only be rejecting it because the first attempt actually landed.\n *\n * Which is why the status alone cannot decide it: `IDEMPOTENCY_KEY_IN_PROGRESS`\n * is a 409 that means the opposite — the row may not exist at all. Read as a\n * duplicate, the queue looked for a row that was never written, found nothing,\n * concluded there was nothing left to do and deleted the write from the queue.\n */\nexport function isDuplicateKeyError(error: unknown): boolean {\n if (!(error instanceof RebaseApiError)) return false;\n if (error.code === \"23505\") return true;\n return error.status === 409 && !isIdempotencyInProgressError(error);\n}\n\n/**\n * The longest delay `setTimeout` holds. Past it the delay overflows a signed\n * 32-bit integer and the timer fires after 1 ms — so a `syncIntervalMs` of a\n * month retried continuously instead of almost never.\n */\nconst MAX_TIMER_DELAY_MS = 2_147_483_647;\n\nexport interface ConnectivityOptions {\n /** First retry delay after a failure. Defaults to 1 000 ms. */\n initialBackoffMs?: number;\n /** Ceiling for the doubling retry delay. Defaults to 60 000 ms. */\n maxBackoffMs?: number;\n /**\n * Let a known-failed connection suppress further attempts until the\n * backoff window opens. On by default — it is what makes a read or write\n * during an outage instant instead of a timeout. Turn it off when nothing\n * will ever wake the client up again (no retry timer, no `online` event),\n * where suppressing attempts would mean never recovering.\n */\n respectBackoff?: boolean;\n /** Injected for tests. */\n now?: () => number;\n /** Injected for tests; must return a handle `clearTimeout` accepts. */\n setTimer?: (fn: () => void, ms: number) => ReturnType<typeof setTimeout>;\n clearTimer?: (handle: ReturnType<typeof setTimeout>) => void;\n}\n\nexport class ConnectivityMonitor {\n private state: \"online\" | \"offline\" = \"online\";\n private backoffMs: number;\n private readonly initialBackoffMs: number;\n private readonly maxBackoffMs: number;\n private retryAt = 0;\n private timer?: ReturnType<typeof setTimeout>;\n private listeners = new Set<(online: boolean) => void>();\n private readonly respectBackoff: boolean;\n private readonly now: () => number;\n private readonly setTimer: (fn: () => void, ms: number) => ReturnType<typeof setTimeout>;\n private readonly clearTimer: (handle: ReturnType<typeof setTimeout>) => void;\n /** Called when the backoff window expires, to drive an automatic retry. */\n onRetryDue?: () => void;\n /**\n * Called when the browser says the connection is back. Its own hook rather\n * than {@link onRetryDue}: a client with automatic retries off sets no retry\n * callback, and the `online` event has to wake it all the same.\n */\n onOnline?: () => void;\n\n private readonly handleOnline = () => {\n // The OS says the interface is back. Trust it enough to try\n // immediately rather than sitting out the rest of the backoff — and to\n // say so, or a client with nothing queued would have no request whose\n // success could ever flip the badge back to \"online\".\n this.retryAt = 0;\n this.backoffMs = this.initialBackoffMs;\n this.clearPendingTimer();\n this.setState(\"online\");\n (this.onOnline ?? this.onRetryDue)?.();\n };\n private readonly handleOffline = () => {\n this.setState(\"offline\");\n };\n\n constructor(options: ConnectivityOptions = {}) {\n this.initialBackoffMs = options.initialBackoffMs ?? 1_000;\n this.maxBackoffMs = Math.max(this.initialBackoffMs, options.maxBackoffMs ?? 60_000);\n this.backoffMs = this.initialBackoffMs;\n this.respectBackoff = options.respectBackoff ?? true;\n this.now = options.now ?? (() => Date.now());\n this.setTimer = options.setTimer ?? ((fn, ms) => setTimeout(fn, ms));\n this.clearTimer = options.clearTimer ?? ((handle) => clearTimeout(handle));\n\n if (typeof window !== \"undefined\" && typeof window.addEventListener === \"function\") {\n window.addEventListener(\"online\", this.handleOnline);\n window.addEventListener(\"offline\", this.handleOffline);\n }\n if (typeof navigator !== \"undefined\" && navigator.onLine === false) {\n this.state = \"offline\";\n }\n }\n\n /** What the app should be told: are we connected? */\n isOnline(): boolean {\n if (typeof navigator !== \"undefined\" && navigator.onLine === false) return false;\n return this.state === \"online\";\n }\n\n /**\n * Should this request even be sent? False means \"answer from the local\n * store instead\" — the request would only burn a timeout to reach the same\n * conclusion the last one already did.\n */\n shouldAttempt(): boolean {\n if (typeof navigator !== \"undefined\" && navigator.onLine === false) return false;\n if (this.state === \"online\" || !this.respectBackoff) return true;\n // Exactly one request is let through when the window opens; it is the\n // probe whose outcome decides whether we are back.\n return this.now() >= this.retryAt;\n }\n\n /** A request reached the server. */\n markSuccess(): void {\n this.backoffMs = this.initialBackoffMs;\n this.retryAt = 0;\n this.clearPendingTimer();\n this.setState(\"online\");\n }\n\n /** A request did not reach the server: we are offline until proven otherwise. */\n markFailure(): void {\n this.deferRetry();\n this.setState(\"offline\");\n }\n\n /**\n * Back off and try again later without claiming the connection is gone.\n * This is what a 429 or a 503 deserves — the server answered, so the app\n * is demonstrably online; it just should not hammer.\n */\n deferRetry(): void {\n const jitter = 0.8 + Math.random() * 0.4;\n this.retryAt = this.now() + this.backoffMs * jitter;\n const delay = Math.max(0, this.retryAt - this.now());\n this.backoffMs = Math.min(this.maxBackoffMs, this.backoffMs * 2);\n this.scheduleRetry(delay);\n }\n\n /** Milliseconds until the next attempt is allowed; 0 when one is allowed now. */\n msUntilRetry(): number {\n if (this.state === \"online\") return 0;\n return Math.max(0, this.retryAt - this.now());\n }\n\n onChange(listener: (online: boolean) => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n dispose(): void {\n if (typeof window !== \"undefined\" && typeof window.removeEventListener === \"function\") {\n window.removeEventListener(\"online\", this.handleOnline);\n window.removeEventListener(\"offline\", this.handleOffline);\n }\n this.clearPendingTimer();\n this.listeners.clear();\n this.onRetryDue = undefined;\n this.onOnline = undefined;\n }\n\n private scheduleRetry(delay: number): void {\n this.clearPendingTimer();\n if (!this.onRetryDue) return;\n this.timer = this.setTimer(() => {\n this.timer = undefined;\n this.onRetryDue?.();\n }, Math.min(delay, MAX_TIMER_DELAY_MS));\n // A retry timer must never be the reason a Node script refuses to exit.\n unref(this.timer);\n }\n\n private clearPendingTimer(): void {\n if (this.timer !== undefined) {\n this.clearTimer(this.timer);\n this.timer = undefined;\n }\n }\n\n private setState(next: \"online\" | \"offline\"): void {\n if (this.state === next) return;\n this.state = next;\n const online = this.isOnline();\n for (const listener of this.listeners) listener(online);\n }\n}\n","import {\n EntityRelation,\n FilterValues,\n FindResult,\n LogicalCondition,\n FilterCondition,\n OrderBySpec,\n WhereFilterOp,\n toCanonicalOp,\n parseRelationAggregateSort\n} from \"@rebasepro/types\";\nimport { FindParams } from \"./transport\";\nimport { normalizeOrderBy, resolveFindWindow } from \"@rebasepro/common\";\nimport { splitSearchTerms } from \"@rebasepro/utils\";\n\n/**\n * A local evaluator for `FindParams`, so cached rows can answer a query the\n * client has never sent to the server — and so a row written offline shows up\n * in every filtered list it belongs to, not just in unfiltered ones.\n *\n * This mirrors the Postgres driver's semantics rather than JavaScript's:\n *\n * - Comparing against NULL is *unknown*, not false-or-true. `status != \"done\"`\n * excludes rows where `status` is null, exactly as SQL does — a JS `!==`\n * would have included them.\n * - `ORDER BY` puts nulls last ascending and first descending, which is the\n * Postgres default.\n * - A filter value may arrive as a string (off a URL, say), so a string is\n * compared numerically against a number and as an instant against a date.\n * `[\"==\", \"3\"]` matches the number `3`, as it does server-side. Two strings\n * compare as text: `\"01234\"` is not `\"1234\"`.\n *\n * Two things it deliberately approximates, both flagged by\n * {@link isExactlyEvaluable}: `searchString` becomes a case-insensitive\n * substring scan over the row's string fields (the server runs real full-text\n * search over the collection's configured columns), and `include` cannot be\n * evaluated at all, because the related rows live in collections this query\n * knows nothing about.\n */\n\nconst collator = typeof Intl !== \"undefined\" && typeof Intl.Collator === \"function\"\n ? new Intl.Collator(undefined, { numeric: false, sensitivity: \"variant\" })\n : undefined;\n\n/**\n * The server's page size when the caller does not ask for one.\n *\n * Re-exported rather than redeclared. This was its own `= 20` — a third\n * constant of this name in the workspace, next to `@rebasepro/common`'s 200 and\n * the 50 the REST layer actually applies — and a local copy of a number that\n * belongs to another process is a number that goes stale silently.\n */\nexport { DEFAULT_LIST_LIMIT as DEFAULT_PAGE_SIZE } from \"@rebasepro/types\";\n\nfunction isNullish(value: unknown): boolean {\n return value === null || value === undefined;\n}\n\n/**\n * Reduce a value to something comparable. Relations compare by the id they\n * point at — the column holds a foreign key, so that is what the server\n * compares too.\n */\nfunction toComparable(value: unknown): unknown {\n if (value instanceof Date) return value.getTime();\n if (value instanceof EntityRelation) return value.id;\n if (value && typeof value === \"object\") {\n const record = value as Record<string, unknown>;\n // A reference/relation that lost its prototype somewhere still\n // compares by id.\n if (typeof record.__type === \"string\" && \"id\" in record) return record.id;\n }\n return value;\n}\n\n/**\n * Three-way compare with SQL's type coercion but not its collation. Returns\n * `undefined` when the two values are not ordered relative to each other,\n * which is how NULL propagates through a comparison.\n */\nexport function compareValues(a: unknown, b: unknown): number | undefined {\n const left = toComparable(a);\n const right = toComparable(b);\n if (isNullish(left) || isNullish(right)) return undefined;\n\n if (typeof left === \"boolean\" || typeof right === \"boolean\") {\n const l = left === true || left === \"true\" || left === 1 ? 1 : 0;\n const r = right === true || right === \"true\" || right === 1 ? 1 : 0;\n return l - r;\n }\n\n // Numbers compare as numbers, and so does a numeric string against a\n // number: a filter value read off a URL is a string, and `[\"<\", \"10\"]`\n // against a number column must not order 10 before 9 as text. Two strings\n // stay text. Rows arrive typed — a declared number is served as a number —\n // so a string row value is a text column, where Postgres says\n // `'01234' <> '1234'` and orders \"10\" before \"9\".\n if (isNumeric(left) || isNumeric(right)) {\n const leftNum = numericOrNaN(left);\n const rightNum = numericOrNaN(right);\n if (!Number.isNaN(leftNum) && !Number.isNaN(rightNum)) {\n return leftNum < rightNum ? -1 : leftNum > rightNum ? 1 : 0;\n }\n }\n\n // One side is a date-shaped string and the other an instant.\n if (typeof left === \"number\" || typeof right === \"number\") {\n const leftTime = toTime(left);\n const rightTime = toTime(right);\n if (leftTime !== undefined && rightTime !== undefined) {\n return leftTime < rightTime ? -1 : leftTime > rightTime ? 1 : 0;\n }\n }\n\n const leftStr = String(left);\n const rightStr = String(right);\n if (collator) return collator.compare(leftStr, rightStr);\n return leftStr < rightStr ? -1 : leftStr > rightStr ? 1 : 0;\n}\n\nfunction isNumeric(value: unknown): value is number | bigint {\n return typeof value === \"number\" || typeof value === \"bigint\";\n}\n\nfunction numericOrNaN(value: unknown): number {\n if (typeof value === \"number\") return value;\n if (typeof value === \"string\" && value.trim() !== \"\") {\n const n = Number(value);\n return Number.isNaN(n) ? NaN : n;\n }\n if (typeof value === \"bigint\") return Number(value);\n return NaN;\n}\n\nfunction toTime(value: unknown): number | undefined {\n if (typeof value === \"number\") return value;\n if (typeof value === \"string\") {\n const t = Date.parse(value);\n return Number.isNaN(t) ? undefined : t;\n }\n return undefined;\n}\n\n/**\n * Equality with a string filter value allowed to name a number, a boolean or\n * an instant, but never across NULL. Two strings are equal only when they are\n * the same string, as text is in Postgres.\n */\nexport function looseEquals(a: unknown, b: unknown): boolean {\n const left = toComparable(a);\n const right = toComparable(b);\n if (isNullish(left) || isNullish(right)) return isNullish(left) && isNullish(right);\n if (left === right) return true;\n if (typeof left === \"string\" && typeof right === \"string\") return false;\n const cmp = compareValues(left, right);\n return cmp === 0;\n}\n\n/**\n * Translate a SQL `LIKE` pattern to an anchored regular expression.\n * `%` matches any run of characters, `_` exactly one, and a backslash escapes\n * either of them.\n */\nfunction likeToRegExp(pattern: string, caseInsensitive: boolean): RegExp {\n let source = \"^\";\n // Runs of `%` collapse to one. `%%%%X` means exactly what `%X` means, but\n // as a regular expression it is four adjacent unbounded quantifiers, and on\n // a subject that does not match the engine tries every way of splitting the\n // subject between them. Fourteen of them against a forty-eight character\n // value took eighty-seven seconds to answer `false`.\n //\n // The pattern is user input — `?title=like.%25%25%25…` over HTTP — so that\n // is a request that pins a CPU. Collapsing is semantics-preserving and\n // removes the ambiguity the backtracking feeds on.\n let lastWasWildcard = false;\n for (let i = 0; i < pattern.length; i++) {\n const char = pattern[i];\n if (char === \"\\\\\" && i + 1 < pattern.length) {\n source += pattern[i + 1].replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n i++;\n lastWasWildcard = false;\n } else if (char === \"%\") {\n if (!lastWasWildcard) source += \"[\\\\s\\\\S]*\";\n lastWasWildcard = true;\n } else if (char === \"_\") {\n source += \"[\\\\s\\\\S]\";\n lastWasWildcard = false;\n } else {\n source += char.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n lastWasWildcard = false;\n }\n }\n return new RegExp(source + \"$\", caseInsensitive ? \"i\" : \"\");\n}\n\nfunction asArray(value: unknown): unknown[] {\n if (Array.isArray(value)) return value;\n if (value === undefined) return [];\n return [value];\n}\n\n/** Evaluate one canonical operator against one row value. */\nexport function matchesOperator(rowValue: unknown, op: WhereFilterOp, filterValue: unknown): boolean {\n switch (op) {\n case \"is-null\":\n return isNullish(rowValue);\n case \"is-not-null\":\n return !isNullish(rowValue);\n case \"==\":\n return looseEquals(rowValue, filterValue);\n case \"!=\":\n // SQL: `x != v` is unknown when x is NULL, so the row drops out.\n if (isNullish(rowValue)) return false;\n return !looseEquals(rowValue, filterValue);\n case \"<\":\n case \"<=\":\n case \">\":\n case \">=\": {\n const cmp = compareValues(rowValue, filterValue);\n if (cmp === undefined) return false;\n if (op === \"<\") return cmp < 0;\n if (op === \"<=\") return cmp <= 0;\n if (op === \">\") return cmp > 0;\n return cmp >= 0;\n }\n case \"in\":\n if (isNullish(rowValue)) return false;\n return asArray(filterValue).some((v) => looseEquals(rowValue, v));\n case \"not-in\":\n if (isNullish(rowValue)) return false;\n return !asArray(filterValue).some((v) => looseEquals(rowValue, v));\n case \"array-contains\": {\n if (!Array.isArray(rowValue)) return false;\n return rowValue.some((v) => looseEquals(v, filterValue));\n }\n case \"array-contains-any\": {\n if (!Array.isArray(rowValue)) return false;\n const wanted = asArray(filterValue);\n return rowValue.some((v) => wanted.some((w) => looseEquals(v, w)));\n }\n case \"like\":\n case \"not-like\":\n case \"ilike\":\n case \"not-ilike\": {\n if (isNullish(rowValue)) return false;\n const insensitive = op === \"ilike\" || op === \"not-ilike\";\n const negated = op === \"not-like\" || op === \"not-ilike\";\n const matched = likeToRegExp(String(filterValue), insensitive).test(String(rowValue));\n return negated ? !matched : matched;\n }\n default:\n // An operator this build does not know must not silently drop rows.\n return true;\n }\n}\n\nfunction isTuple(value: unknown): value is [WhereFilterOp, unknown] {\n return Array.isArray(value) && value.length === 2 && typeof value[0] === \"string\"\n && toCanonicalOp(value[0]) !== undefined;\n}\n\n/**\n * One field's condition, as the tuples this evaluator can read.\n *\n * The single reading of a condition, for {@link matchesWhere} and\n * {@link isExactlyEvaluable} both. Each used to have its own, and only the\n * first was hardened: `{ status: undefined }` (a skipped filter) and the bare\n * wire string `\"eq.active\"` both reached `.filter` on a non-array in the\n * second and threw.\n *\n * `unreadable` is set when the condition is there but yields nothing this\n * build understands — a wire string, an operator from a newer server. Such a\n * condition filters nothing locally while the server does filter on it, so an\n * answer that ignored it would be wider than the server's.\n */\nfunction conditionTuples(condition: unknown): { tuples: [WhereFilterOp, unknown][]; unreadable: boolean } {\n if (condition === undefined) return { tuples: [], unreadable: false };\n if (isTuple(condition)) return { tuples: [condition], unreadable: false };\n if (!Array.isArray(condition)) return { tuples: [], unreadable: true };\n const tuples = condition.filter(isTuple);\n return { tuples, unreadable: tuples.length !== condition.length || tuples.length === 0 };\n}\n\n/** Evaluate a `where` clause: every field, and every tuple on a field, AND-ed. */\nexport function matchesWhere(row: Record<string, unknown>, where: FilterValues<string> | undefined): boolean {\n if (!where) return true;\n for (const [field, condition] of Object.entries(where)) {\n const { tuples } = conditionTuples(condition);\n for (const [rawOp, value] of tuples) {\n const op = toCanonicalOp(rawOp) ?? rawOp;\n if (!matchesOperator(row[field], op, value)) return false;\n }\n }\n return true;\n}\n\n/** Evaluate a nested and/or tree. */\nexport function matchesLogical(\n row: Record<string, unknown>,\n condition: LogicalCondition | FilterCondition | undefined\n): boolean {\n if (!condition) return true;\n if (\"type\" in condition) {\n const children = condition.conditions ?? [];\n if (children.length === 0) return true;\n return condition.type === \"or\"\n ? children.some((c) => matchesLogical(row, c))\n : children.every((c) => matchesLogical(row, c));\n }\n const op = toCanonicalOp(condition.operator) ?? condition.operator;\n return matchesOperator(row[condition.column], op as WhereFilterOp, condition.value);\n}\n\n/**\n * Approximate the server's full-text search with a case-insensitive substring\n * scan over the row's own string fields. Narrower than the real thing (no\n * stemming, no configured search columns), and it never matches a field the\n * cached row does not carry — a local list may therefore be missing rows the\n * server would have returned, which is why {@link isExactlyEvaluable} refuses\n * to call a search query exact.\n *\n * Every term has to match, but they may match different fields — the same rule\n * both drivers apply, and the one that finds `sebastian melendez` on a row that\n * keeps the two halves of a name in separate fields. Matching the typed string\n * as a whole found neither that row nor, because the space was part of the\n * needle, anything at all for `sebastian `.\n */\nexport function matchesSearch(row: Record<string, unknown>, searchString: string | undefined): boolean {\n if (!searchString) return true;\n const terms = splitSearchTerms(searchString).map(term => term.toLowerCase());\n if (terms.length === 0) return true;\n const values = Object.values(row);\n return terms.every(term => values.some(value => {\n if (typeof value === \"string\") return value.toLowerCase().includes(term);\n if (typeof value === \"number\") return String(value).includes(term);\n return false;\n }));\n}\n\n/** Does this row belong in the result set for `params`, ignoring pagination? */\nexport function matchesParams(row: Record<string, unknown>, params?: FindParams): boolean {\n if (!params) return true;\n return matchesWhere(row, params.where)\n && matchesLogical(row, params.logical)\n && matchesSearch(row, params.searchString);\n}\n\n/**\n * Sort in place, Postgres-style: nulls last ascending, first descending, with\n * the row id as a tiebreak so paging through an unsorted-but-equal run does\n * not shuffle rows between pages.\n *\n * The tiebreak runs *descending*, which is not a taste: every server-side sort\n * ends on `id DESC` — `FetchService.buildOrderExpressions` appends it to make\n * the ordering total, and the keyset cursor is built to match. This ran\n * ascending, so two rows sharing a sort value came back from the local overlay\n * in the opposite order to the server's, and {@link isLocallySortable} called\n * that page exactly reproducible while it was not.\n */\nexport function sortRows<M extends Record<string, unknown>>(rows: M[], orderBy?: OrderBySpec): M[] {\n const keys = normalizeOrderBy(orderBy);\n if (!keys) return rows;\n return rows.sort((a, b) => {\n for (const [field, direction = \"asc\"] of keys) {\n const cmp = compareOnKey(a, b, field, direction);\n // Equal on this key — and equal is not a decision, so the next key\n // gets to make one. Returning the tiebreak here instead is what a\n // single-key sort does at the end, and doing it per key would order\n // by the id the moment two rows shared a role.\n if (cmp !== 0) return cmp;\n }\n return tiebreak(a, b);\n });\n}\n\n/** One key's verdict: negative, positive, or 0 for \"these two are equal here\". */\nfunction compareOnKey(\n a: Record<string, unknown>,\n b: Record<string, unknown>,\n field: string,\n direction: \"asc\" | \"desc\"\n): number {\n const av = a[field];\n const bv = b[field];\n const aNull = isNullish(toComparable(av));\n const bNull = isNullish(toComparable(bv));\n if (aNull || bNull) {\n if (aNull && bNull) return 0;\n // NULLS LAST ascending, NULLS FIRST descending.\n return (aNull ? 1 : -1) * (direction === \"desc\" ? -1 : 1);\n }\n const cmp = compareValues(av, bv);\n if (cmp === undefined || cmp === 0) return 0;\n return cmp * (direction === \"desc\" ? -1 : 1);\n}\n\n/** The last word, and the server's: `id DESC`. */\nfunction tiebreak(a: Record<string, unknown>, b: Record<string, unknown>): number {\n const cmp = compareValues(a.id, b.id);\n return cmp === undefined ? 0 : -cmp;\n}\n\n/**\n * Resolve `page`/`offset`/`limit` the way the server does.\n *\n * It did not: this defaulted an absent limit to 20 while `/api/data` pages by\n * 50, so the same `observe()` answered with 20 rows from the local database and\n * 50 from the network — a list that changed length depending on which side\n * answered, with `page` striding differently on each. Delegated now, so the\n * sentence above is true by construction rather than by agreement.\n */\nexport function resolvePagination(params?: FindParams): { limit: number; offset: number } {\n const { limit, offset } = resolveFindWindow(params);\n return { limit, offset };\n}\n\n/** `<`, `<=`, `>`, `>=` — the operators whose answer depends on a collation. */\nconst ORDERING_OPS = new Set<WhereFilterOp>([\"<\", \"<=\", \">\", \">=\"]);\n\n/**\n * Does any condition in this `where` clause order its operands — or say\n * something this evaluator cannot read at all? Either way the local answer is\n * not the server's.\n */\nfunction whereNotExact(where: FilterValues<string> | undefined): boolean {\n if (!where) return false;\n for (const condition of Object.values(where)) {\n const { tuples, unreadable } = conditionTuples(condition);\n if (unreadable) return true;\n if (tuples.some(([op]) => ORDERING_OPS.has(toCanonicalOp(op) ?? op))) return true;\n }\n return false;\n}\n\n/** The same question, through an `and(...)`/`or(...)` tree. */\nfunction logicalOrders(condition: LogicalCondition | FilterCondition | undefined, depth = 0): boolean {\n if (!condition || depth > 32) return false;\n if (\"type\" in condition) {\n return (condition.conditions ?? []).some((c) => logicalOrders(c, depth + 1));\n }\n return ORDERING_OPS.has(condition.operator);\n}\n\n/**\n * Can a locally evaluated answer to `params` be trusted to match the server's,\n * assuming the cache holds every row of the collection?\n *\n * `include` pulls in rows from other collections that this evaluator never\n * sees, and `searchString` is only approximated — both make the local answer a\n * best effort rather than an equivalent one.\n *\n * **Ordering comparisons are refused, and that is the interesting one.**\n * `compareValues` falls back to an `Intl.Collator` for operands it cannot read\n * as numbers or instants. PostgreSQL orders text by the *database's* collation,\n * which is a property of the server this process has never been told: under the\n * C collation `'apple' < 'Banana'` is false, under `en_US.UTF-8` it is true,\n * and the collator says true. So `[\"<\", \"Banana\"]` selects a different set here\n * than it does there — silently, and in whichever direction the deployment\n * happens to have been created.\n *\n * The refusal covers *every* ordering comparison rather than only the ones with\n * a string operand, because the operand type does not settle it: a numeric\n * bound against a text column (`[\"<\", 10]` on a `varchar`) also reaches the\n * collator, and nothing in `params` says what the column holds. Conservative on\n * purpose — the cost is that a query combining an ordering filter with\n * *unsynced local writes* stops placing those writes optimistically, which is a\n * degraded answer rather than a wrong one. Claiming exactness we do not have is\n * the other way round.\n *\n * This says nothing about ordering *results*; that is a separate claim with a\n * separate answer, because a sort changes which rows come first and not which\n * rows match. See {@link isLocallySortable}.\n */\n/**\n * Whether an `include` asks for anything, in any of its spellings.\n *\n * `include` is a list of names, a list of dotted paths, or a tree — and only\n * the first two have a `length`. A `.length > 0` test read the tree form as\n * \"no relations\", which is the answer that makes the local cache claim it can\n * evaluate a relational query exactly.\n */\nfunction hasAnyInclude(include: FindParams[\"include\"]): boolean {\n if (!include) return false;\n if (Array.isArray(include)) return include.length > 0;\n return Object.keys(include).length > 0;\n}\n\nexport function isExactlyEvaluable(params?: FindParams): boolean {\n if (!params) return true;\n // Any include at all. Reading `.length` was only ever true of the flat\n // spelling; `include` is also a tree now, whose length is `undefined`, and\n // a tree read as \"no relations\" would have the cache answer a relational\n // query from rows that hold no relations.\n if (hasAnyInclude(params.include)) return false;\n if (params.searchString) return false;\n // Nearest-neighbour ordering is the server's to compute: the cache holds no\n // vectors, and even with them, answering from a subset would return the\n // nearest of what happens to be cached while looking like the nearest there\n // are — a wrong answer that is indistinguishable from a right one.\n if (params.vectorSearch) return false;\n if (whereNotExact(params.where)) return false;\n if (logicalOrders(params.logical)) return false;\n // A dotted key reaches through a relation — `applications.status` asks\n // about rows in another table. `matchesWhere` reads `row[field]` flat, so\n // the key resolves to `undefined` on every cached row and the condition\n // excludes all of them: a 200 with an empty list, indistinguishable from\n // \"nothing matched\". The cache holds one collection; it cannot answer a\n // question about a second, so it must not claim to.\n if (whereReachesThroughRelation(params.where)) return false;\n if (logicalReachesThroughRelation(params.logical)) return false;\n return true;\n}\n\n/** Does any filter key reach outside this row — `applications.status`? */\nfunction whereReachesThroughRelation(where: FilterValues<string> | undefined): boolean {\n return where ? Object.keys(where).some((field) => field.includes(\".\")) : false;\n}\n\n/** The same question, through an `and(...)`/`or(...)` tree. */\nfunction logicalReachesThroughRelation(\n condition: LogicalCondition | FilterCondition | undefined,\n depth = 0\n): boolean {\n if (!condition || depth > 32) return false;\n if (\"type\" in condition) {\n return (condition.conditions ?? []).some((c) => logicalReachesThroughRelation(c, depth + 1));\n }\n return typeof condition.column === \"string\" && condition.column.includes(\".\");\n}\n\n/**\n * Would sorting `rows` locally reproduce the order the server would have sent?\n *\n * Asked of the rows rather than of the query, because unlike a filter this one\n * *is* decidable from the data in hand: {@link compareValues} reaches the\n * collator only when neither operand is a number, and `toComparable` has\n * already turned dates and relations into numbers and ids by then. If every\n * value on the sort column normalises to a number, the collator is unreachable\n * and the local order is the server's order.\n *\n * A text column is therefore refused — see {@link isExactlyEvaluable} for why\n * the two cannot be made to agree — including one holding only digits, which\n * Postgres orders as text (\"10\", \"100\", \"9\").\n *\n * Nulls are fine either way: they are ordered by an explicit rule (last\n * ascending, first descending) that matches Postgres and never reaches the\n * comparator.\n */\nexport function isLocallySortable(\n rows: readonly Record<string, unknown>[],\n orderBy?: OrderBySpec\n): boolean {\n const keys = normalizeOrderBy(orderBy);\n if (!keys) return true;\n // An aggregate over a relation is computed by the database and is not a\n // field on the row, so every cached row reads `undefined` for it. That\n // looks exactly like a column of nulls to the loop below, which would call\n // the order reproducible and then hand back rows in id order — a queue\n // sorted by nothing at all, presented as the server's answer.\n if (keys.some(([field]) => parseRelationAggregateSort(field))) return false;\n // Every key has to be decidable, not just the first: a sort the local side\n // can only agree with down to its second column is one it disagrees with.\n return keys.every(([field]) => rows.every((row) => {\n const value = toComparable(row[field]);\n if (isNullish(value)) return true;\n if (typeof value === \"number\" || typeof value === \"boolean\") return true;\n if (typeof value === \"bigint\") return true;\n return false;\n }));\n}\n\n/** Run a full query — filter, sort, paginate — over a set of rows. */\nexport function runLocalQuery<M extends Record<string, unknown>>(\n rows: M[],\n params?: FindParams\n): FindResult<M> {\n const matched = rows.filter((row) => matchesParams(row, params));\n sortRows(matched, params?.orderBy);\n const { limit, offset } = resolvePagination(params);\n const page = matched.slice(offset, offset + limit);\n return {\n data: page,\n meta: {\n total: matched.length,\n limit,\n offset,\n hasMore: offset + page.length < matched.length\n }\n };\n}\n","import { buildQueryString, FindParams, RebaseApiError } from \"./transport\";\nimport { FindAllParams, FindResult, IterateParams, LogicalCondition, SDKCollectionClient, WhereFilterOp, WhereValueFor, WriteOptions, hasFieldOperation, isUnsupported, type ByIdReadOptions, type UpdateValues, type UpsertOptions } from \"@rebasepro/types\";\nimport { collectAllPages, normalizeOrderBy, paginateFind } from \"@rebasepro/common\";\nimport { CollectionClient, LiveResult, ObserveOptions, RowSnapshotMeta, byIdRead, etagOf, invalidBulkBody, type ObserveByIdOptions, type RestoreOptions, type TrashClient } from \"./collection\";\nimport { SDKQueryBuilder } from \"./sdk_query_builder\";\nimport { dehydrateMutation, dehydrateRow, hydrateMutation, hydrateRow, setOwn } from \"./offline-codec\";\nimport { RebaseClientError } from \"./errors\";\nimport {\n ConnectivityMonitor,\n isDuplicateKeyError,\n isIdempotencyInProgressError,\n isIdempotencyKeyReusedError,\n isNetworkError,\n isRetryableError\n} from \"./offline-connectivity\";\nimport {\n IndexedDBOfflineStore,\n MemoryOfflineStore,\n OfflineStore,\n PendingMutation,\n QUEUE_SCHEMA_VERSION,\n createMutationId\n} from \"./offline-store\";\nimport {\n isExactlyEvaluable,\n isLocallySortable,\n matchesParams,\n resolvePagination,\n runLocalQuery,\n sortRows\n} from \"./offline-query\";\nimport { unref } from \"@rebasepro/utils\";\n\n/**\n * The SDK's local-first sync engine.\n *\n * The design goal is that the network is never in the way of the interface.\n * That comes from three properties, and everything in this file exists to\n * serve one of them:\n *\n * 1. **A local database, not a response cache.** Rows are stored normalized,\n * by id, and queries are answered by evaluating them\n * ({@link ./offline-query}) against those rows. A row written offline\n * therefore appears in *every* list it belongs to, a row edited in one view\n * updates in all of them, and `findById` answers for a row only ever seen\n * inside a `find`. Server responses are merged into this database rather\n * than replacing it, and a row with unsynced local writes keeps them: the\n * user's own change never flickers away underneath them.\n *\n * 2. **Writes are decided locally.** A write made while offline is applied to\n * the local database and queued — with the state it replaced, so a server\n * rejection can be undone — and the call returns immediately. When\n * connectivity is known to be gone the request is not even attempted, so\n * an offline write costs nothing instead of a timeout.\n *\n * 3. **Reads are reactive.** {@link OfflineManager.observe} emits from the\n * local database synchronously-ish, revalidates in the background, and\n * re-emits whenever anything touches the rows it covers — a local write,\n * a replay landing, a rollback, a realtime event, or another browser tab.\n *\n * What it deliberately is not: a full replica. Only rows the app has actually\n * read or written are local, so a query the cache cannot fully answer is\n * flagged `partial` rather than silently reported as complete.\n */\n\nexport interface OfflineConfig {\n /**\n * Persistence backend. Defaults to IndexedDB in the browser and an\n * in-memory store elsewhere; pass a custom implementation (e.g. backed by\n * AsyncStorage in React Native) to persist in other environments.\n */\n store?: OfflineStore;\n /**\n * Cached query snapshots kept per collection; the least recently written\n * are evicted beyond this. Defaults to 50.\n */\n maxCachedQueriesPerCollection?: number;\n /**\n * Cached rows kept per collection. Rows with unsynced local writes are\n * never evicted. Defaults to 5 000.\n */\n maxCachedRowsPerCollection?: number;\n /**\n * Ceiling for the exponential retry backoff, in milliseconds. Replay\n * retries start at one second and double up to this. `0` disables\n * automatic retries entirely — `client.offline.sync()`, a sign-in, and the\n * browser's `online` event still trigger one. Defaults to 60 000.\n */\n syncIntervalMs?: number;\n /**\n * Keep several tabs of the same app in step over a `BroadcastChannel`: a\n * write in one appears in the others, and only one of them replays the\n * shared queue. Defaults to on for the IndexedDB store (a real shared\n * database) and off for the in-memory one, which no other tab can see.\n */\n crossTab?: boolean;\n /**\n * How many times a mutation rejected with a *retryable* status (429, 503,\n * …) is replayed before it is given up on and rolled back. Network\n * failures do not count against this: being offline is not an attempt.\n * Defaults to 5.\n */\n maxRetries?: number;\n /**\n * Called when the server *rejects* a queued mutation (a 4xx/5xx that will\n * not resolve on its own — validation, RLS, a since-deleted row). The\n * local rows it wrote are rolled back to the state they had before it, and\n * any later queued writes to the same rows are discarded with it — they\n * were built on a change that never happened. Each discarded mutation is\n * reported here.\n *\n * Network failures are not errors: those mutations stay queued.\n */\n onSyncError?: (error: Error, mutation: PendingMutation) => void;\n /**\n * Detect conflicts when a queued edit replays: an `update` made offline\n * is sent with `If-Match`, the version of the row it was made against,\n * and if someone changed the row on the server since, this decides what\n * happens to the edit:\n *\n * - `\"overwrite\"`: send it again without the precondition. Last writer\n * wins, as without this option.\n * - `\"discard\"`: drop it. The row goes back to what it was before the\n * edit, as for a rejection, but it is not reported to `onSyncError`\n * (writes queued on top of it are, as `DEPENDENCY_REJECTED`), and the\n * row is read again from the server.\n *\n * The edit's version is the one the row's last read reported: a\n * `findById`, a `listenById` frame, or the answer to an earlier `update`.\n * A row last seen in a `find()` or `listen()` list has no version, and an\n * edit made on top of another queued write to the same row has none\n * either; those replay without a precondition. A caller's own `ifMatch` is\n * kept on a queued edit too.\n *\n * The queue waits while this runs, so a prompt can ask the user. Without\n * it — the default — replay sends no precondition and the last writer\n * wins, per field.\n */\n onConflict?: (error: RebaseApiError, mutation: PendingMutation) => ConflictResolution | Promise<ConflictResolution>;\n /**\n * Remember, on this device, the last user who signed in, and open their\n * local database when a reload cannot reach the server to restore the\n * session. Off by default.\n *\n * This matters in cookie mode, where nothing about the session is stored\n * on the device: without it, an offline reload has no user, so it shows\n * the signed-out local database and queues the user's writes as the\n * signed-out user's. With it, the reload shows the last user's rows, and\n * writes made meanwhile go into their queue. That queue is not replayed\n * until the session is confirmed — by a refresh once the connection is\n * back, or a sign-in. If the server then refuses the session, or someone\n * else signs in, the device switches users and the queue waits, kept, for\n * its author.\n *\n * The trade-off is the reason it is opt-in: on a shared device, the\n * previous user's cached rows can be read offline without a session.\n * Turn it on for installs that belong to one person. The id is forgotten\n * at sign-out, and when the server refuses the session; it is never used\n * when the server answered that there is no session.\n *\n * {@link OfflineStatus.unverifiedUser} is `true` while the device shows a\n * user whose session it has not confirmed.\n */\n keepLastUser?: boolean;\n /**\n * How many queued creates replay as one request. Defaults to `1`: every\n * queued write is its own request, in order. Raise it (up to 1 000) and a\n * run of consecutive offline creates in one collection drains as one\n * `createMany` — 500 rows typed offline go back in a handful of requests\n * instead of 500 round trips.\n *\n * Only creates whose ids the SDK minted as strings are folded, and never\n * one that references another row of the same run: those are the writes a\n * lost answer cannot duplicate (the server refuses the id the second time,\n * and the create is recognised as its own) and whose values need nothing\n * from the server first. Anything else — and any run the server refuses or\n * defers for any reason but a lost connection — replays one write at a\n * time exactly as with the default, so each write still stands or falls\n * on its own.\n */\n replayBatchSize?: number;\n}\n\n/** What {@link OfflineConfig.onConflict} does with an edit the row has moved past. */\nexport type ConflictResolution = \"overwrite\" | \"discard\";\n\n/** A snapshot of the engine's state, for a status indicator. */\nexport interface OfflineStatus {\n /** False once a request has failed to reach the server, until one does. */\n online: boolean;\n /** True while the queue is being replayed. */\n syncing: boolean;\n /** Local writes not yet accepted by the server. */\n pending: number;\n /** When the queue was last fully drained. */\n lastSyncedAt?: number;\n /** The last replay rejection, if any. */\n lastError?: string;\n /**\n * Whether the browser agreed to keep the offline database through storage\n * pressure (`navigator.storage.persist()`), asked when the first write is\n * queued. `false` means it may be evicted — on Safari, after seven days\n * without a visit — and unsent writes with it; a UI can warn. Unset until\n * asked, and where there is nothing to ask.\n */\n persisted?: boolean;\n /**\n * `true` while the local data shown is the last signed-in user's, opened\n * without a confirmed session ({@link OfflineConfig.keepLastUser}): their\n * writes queue, and none replays until the session is confirmed. Unset\n * otherwise.\n */\n unverifiedUser?: boolean;\n}\n\nexport type { LiveResult, ObserveByIdOptions, ObserveOptions, RowSnapshotMeta } from \"./collection\";\n\n/** Which queue {@link OfflineApi.pending} and {@link OfflineApi.clear} act on. */\nexport interface OfflineQueueOptions {\n /**\n * The writes queued while nobody was signed in, instead of the current\n * user's.\n *\n * While someone is signed in these are held back: they were not made by\n * that user, so they are never replayed under their credentials, and never\n * moved into their queue. `pending({ orphaned: true })` lists them so the\n * app can decide — re-issue them as the signed-in user, or discard them\n * with `clear({ orphaned: true })`. Left alone, they replay the next time\n * nobody is signed in.\n *\n * With nobody signed in they are the current queue, and are not orphaned:\n * `pending({ orphaned: true })` lists nothing.\n */\n orphaned?: boolean;\n}\n\n/** What `client.offline` exposes to the app. */\nexport interface OfflineApi {\n /** Replay the queue now. Resolves with what was flushed and what remains. */\n sync(): Promise<{ flushed: number; remaining: number }>;\n /**\n * The queued mutations for the current user, oldest first — or, with\n * `{ orphaned: true }`, the ones queued while nobody was signed in (see\n * {@link OfflineQueueOptions.orphaned}).\n */\n pending(options?: OfflineQueueOptions): Promise<PendingMutation[]>;\n /** The current engine state — connectivity, queue depth, last sync. */\n status(): OfflineStatus;\n /** Subscribe to {@link OfflineStatus} changes (for a sync indicator). */\n onStatusChange(listener: (status: OfflineStatus) => void): () => void;\n /**\n * Drop the current user's queued mutations AND their local rows.\n * Destructive: queued writes are lost, not replayed. For \"discard my\n * offline changes\" flows, not for sign-out (scoping already isolates\n * users).\n *\n * With `{ orphaned: true }`, drop the writes queued while nobody was\n * signed in, and the local rows they were applied to, instead — the\n * current user's are left alone.\n */\n clear(options?: OfflineQueueOptions): Promise<void>;\n /** Subscribe to queue-size changes (for a \"pending changes\" badge). */\n onQueueChange(listener: (count: number) => void): () => void;\n}\n\n// In a module of its own so the client's barrel can export it without\n// bringing the engine along — see offline-lazy.ts.\nexport { isOfflineError } from \"./offline-errors\";\n\nfunction offlineError(message: string): RebaseApiError {\n return new RebaseApiError(message, { status: 0, code: \"OFFLINE\" });\n}\n\n/**\n * What a write discarded because an earlier write it depends on was refused is\n * reported with. It was never sent; the refusal that doomed it is its `cause`.\n */\nfunction dependencyRejected(refused: PendingMutation, error: Error): RebaseApiError {\n return new RebaseApiError(\n `Not sent: an earlier queued write to the same row was refused (${error.message}).`,\n {\n status: error instanceof RebaseApiError ? error.status : undefined,\n code: \"DEPENDENCY_REJECTED\",\n details: { rejectedMutationId: refused.mutationId },\n cause: error\n }\n );\n}\n\n/**\n * A refusal about what a write contains — a field the collection no longer\n * has, one the caller may not write, a value a constraint refuses — rather\n * than about the row or the caller as a whole.\n */\nfunction isFieldRefusal(error: unknown): boolean {\n if (!(error instanceof RebaseApiError)) return false;\n return error.status === 400 || error.status === 403 || error.status === 422;\n}\n\n/**\n * `value` with every occurrence of `from` replaced by `to`, walking plain\n * objects and arrays — and whether anything was replaced.\n *\n * Only ever called with an id the SDK minted for an offline create (a UUID, or\n * a negative number from the clock), which nothing but a reference to that row\n * can equal. That is what makes replacing by value sound without knowing which\n * columns are references.\n */\nfunction replaceMintedId(value: unknown, from: string | number, to: string | number): { value: unknown; changed: boolean } {\n if (value === from) return { value: to, changed: true };\n if (Array.isArray(value)) {\n let changed = false;\n const out = value.map((item) => {\n const replaced = replaceMintedId(item, from, to);\n changed ||= replaced.changed;\n return replaced.value;\n });\n return changed ? { value: out, changed } : { value, changed };\n }\n if (isPlainObject(value)) {\n let changed = false;\n const out: AnyRow = {};\n for (const [key, item] of Object.entries(value as AnyRow)) {\n const replaced = replaceMintedId(item, from, to);\n changed ||= replaced.changed;\n setOwn(out, key, replaced.value);\n }\n return changed ? { value: out, changed } : { value, changed };\n }\n return { value, changed: false };\n}\n\n/**\n * A plain object from any realm — a queued payload read back from the store is\n * a structured clone, whose `Object.prototype` need not be this one. A class\n * instance (a `GeoPoint`, a `Date`) is not walked.\n */\nfunction isPlainObject(value: unknown): value is AnyRow {\n if (value === null || typeof value !== \"object\") return false;\n const proto = Object.getPrototypeOf(value);\n return proto === null || Object.getPrototypeOf(proto) === null;\n}\n\n/** Whether a queued write's payload mentions `id` anywhere — see {@link replaceMintedId}. */\nfunction mentionsMintedId(op: PendingMutation, id: string | number): boolean {\n const payloads: unknown[] = [op.data, ...(op.updates ?? []).map((u) => u.data)];\n return payloads.some((payload) => replaceMintedId(payload, id, \"\").changed);\n}\n\n/**\n * A page that local rows were added to, cut back to the `limit` it was asked\n * with — as a refetch would return it.\n *\n * Sorted, the page is cut where the order puts it. Unsorted, the rows created\n * here (the last `added`) stand where they were placed, and the server's rows\n * make room from the end of the page.\n */\nfunction fitToLimit<R>(rows: R[], limit: number, added: number, sorted: boolean): R[] {\n if (!(limit > 0) || rows.length <= limit) return rows;\n if (sorted || added === 0) return rows.slice(0, limit);\n const local = rows.slice(rows.length - added);\n const server = rows.slice(0, rows.length - added);\n return [...server.slice(0, Math.max(0, limit - local.length)), ...local].slice(0, limit);\n}\n\n/**\n * Call the app back without letting it break the engine.\n *\n * A status badge that throws while rendering used to abort a replay half way\n * (and skip every listener registered after it); the replay's own failure\n * handling then had an error that was never about the replay. The app's error\n * is still reported, on the console, where an uncaught one would have gone.\n */\nfunction callSafely(callback: () => void): void {\n try {\n callback();\n } catch (error) {\n console.error(\"[rebase offline] A listener threw:\", error);\n }\n}\n\n/** The server has no such row — deleted by someone else, or never visible to this user. */\n/** A `412`: the row is no longer the version an `If-Match` named. */\nfunction isPreconditionFailed(error: unknown): error is RebaseApiError {\n return error instanceof RebaseApiError && error.status === 412;\n}\n\nfunction isNotFoundError(error: unknown): boolean {\n return error instanceof RebaseApiError && error.status === 404;\n}\n\nfunction generateOfflineStringId(): string {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n // Non-cryptographic fallback for exotic runtimes; collision odds are\n // irrelevant at offline-queue scale.\n return `off-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\n/**\n * The last temporary numeric id minted, so the next one is smaller.\n *\n * Module-scoped and strictly decreasing: two temporary ids in the same session\n * must not collide, and neither must one minted a millisecond after another.\n */\nlet lastOfflineNumericId = 0;\n\n/**\n * A temporary id for a collection whose ids are numbers.\n *\n * **Negative**, which is the convention every local-first engine settles on for\n * the same reason: a real key is a positive integer or an identity sequence, so\n * the sign alone says \"this one is not the server's yet\" — and it stays a\n * number, which is what matters. A UUID string was minted for every collection,\n * so a `create` while offline handed back `{ id: \"526e2faf-…\" }` on a row the\n * generated types declare `id: number`. Anything that put that in a URL, a\n * foreign key or an `id.toFixed()` was wrong or threw until the replay\n * reconciled it — and the SDK's own types said it could not happen.\n */\nfunction generateOfflineNumericId(): number {\n const candidate = -Date.now();\n lastOfflineNumericId = lastOfflineNumericId === 0\n ? candidate\n : Math.min(candidate, lastOfflineNumericId - 1);\n return lastOfflineNumericId;\n}\n\ntype AnyRow = Record<string, unknown>;\ntype InnerFactory = (slug: string) => SDKCollectionClient<AnyRow>;\n\n/**\n * The row an optimistic write puts in the cache before the server has seen it.\n *\n * It is NOT an `M`, and saying so is the point of collecting this in one place.\n * `M` is the row as the database has it — every server default, every generated\n * column, every `afterRead` transform. What an optimistic write has is the\n * fields the caller supplied (plus, on an update, whatever was already cached)\n * and an id, which may itself be a locally-minted placeholder.\n *\n * The two are reconciled when the queued write drains and the server's row\n * replaces this one. Until then the SDK hands the caller this, under `M`,\n * because that is what the offline API's return type promises — and there is\n * nothing in this file that can make that promise true.\n *\n * So: one deliberate assertion, named, rather than five spread across the\n * create / createMany / update / upsert paths, each free to assemble the fields\n * differently. Fixing it properly means the offline surface saying what it\n * actually returns, which is a change to its public types.\n */\nfunction optimisticRow<M>(fields: AnyRow, id: string | number): M {\n return { ...fields, id } as unknown as M;\n}\n\n/**\n * Whether a query answers with something narrower than whole rows: `fields`\n * returns only the columns it names (and the key), and `distinct` collapses\n * rows into their distinct projections. Either way what comes back is not a\n * row of the collection, and must not be stored as one.\n */\nfunction isProjection(params?: FindParams): boolean {\n return (params?.fields?.length ?? 0) > 0 || params?.distinct === true;\n}\n\n/** `row` narrowed to `keys`: a local row in the shape a projection has. */\nfunction pick(row: AnyRow, keys: readonly string[]): AnyRow {\n const out: AnyRow = {};\n for (const key of keys) if (Object.hasOwn(row, key)) setOwn(out, key, row[key]);\n return out;\n}\n\n/** A snapshot as read back from the store, its projected rows revived. */\nfunction readSnapshot(value: unknown): QuerySnapshot {\n const snapshot = value as QuerySnapshot;\n return snapshot.rows ? { ...snapshot, rows: snapshot.rows.map((row) => hydrateRow<AnyRow>(row)) } : snapshot;\n}\n\n/** What the server said about one query, as ids into the local row database. */\ninterface QuerySnapshot {\n ids: (string | number)[];\n total: number;\n limit: number;\n offset: number;\n hasMore: boolean;\n /**\n * For a projected query (`fields`, `distinct`): the rows the server\n * answered with, as it sent them. They carry only the columns asked for,\n * so they are kept with the answer rather than in the row store, where\n * they would replace the full rows every other query reads.\n */\n rows?: AnyRow[];\n}\n\n/**\n * Which user an operation runs for: the scope, and the epoch of that scope.\n *\n * Captured before an operation's first await and handed to every write it\n * makes to the local database or the queue — see `OfflineManager.scopeEpoch`.\n */\ninterface ScopeTicket {\n scope: string;\n epoch: number;\n}\n\n/** The queue's row ids for one collection — see `OfflineManager.pendingIndex`. */\ninterface PendingIds {\n /** Rows any queued write writes to. */\n writes: Set<string>;\n /** Rows a queued write creates. */\n creates: Set<string>;\n /** The first queued write to each row. */\n first: Map<string, PendingMutation>;\n}\n\ninterface RowEntry {\n row: AnyRow;\n cachedAt: number;\n /** Bumped on every local change, so observers can diff cheaply. */\n rev: number;\n}\n\ninterface CollectionState {\n rows: Map<string, RowEntry>;\n snapshots: Map<string, QuerySnapshot>;\n /**\n * Query keys whose snapshot came from a request that completed in this\n * session. Deliberately not persisted: a snapshot read back off disk is\n * exactly what \"from the cache\" means, however recent it looks.\n */\n fresh: Set<string>;\n /** The same, per row id, for `observeById`. */\n freshRows: Set<string>;\n /** Ids the server has confirmed do not exist — a negative cache. */\n absent: Set<string>;\n /**\n * Per row id, the version the server last reported for it — the\n * `If-Match` of an edit queued against it ({@link OfflineConfig.onConflict}).\n * In memory only: a version is a fact about a read, and a row read back off\n * disk has not been read from the server.\n */\n etags?: Map<string, string>;\n loaded?: Promise<void>;\n /**\n * True once the persisted rows are in memory. Observers must not emit\n * before this: an empty map during the load is not an empty collection,\n * and emitting it would flash an empty list over real data.\n */\n ready: boolean;\n}\n\ninterface Observer {\n slug: string;\n params?: FindParams;\n /** Set for observeById; then `params` is unused. */\n id?: string | number;\n emit: () => void;\n /** Re-run this observer's query against the server. */\n refresh: () => Promise<unknown>;\n signature?: string;\n error?: Error;\n settled: boolean;\n}\n\n// `\\u0000` as an escape, not a raw NUL byte in the source. The value is\n// identical — an id can never contain it, which is the point — but written raw it\n// made this whole file test as binary, so every `grep` over the repo skipped\n// all 1,700 lines of it in silence.\nconst MISSING = \"\\u0000missing\";\n\n/**\n * Replays to spend on a mutation whose idempotency key the server is still\n * holding, when the app has not asked for more.\n *\n * Retries double from a second and cap at the sync interval, so the default\n * budget of five covers about half a minute — less than the lease a server\n * gives a claim nobody came back for. This many outlast it with room for a slow\n * batch, and the count is what stops a server that never releases the key from\n * blocking the queue behind it indefinitely.\n */\nconst IN_PROGRESS_MIN_RETRIES = 12;\n\n/** The scope of whatever is cached and queued while nobody is signed in. */\nconst SIGNED_OUT_SCOPE = \"anon\";\n\n/** The most rows one folded replay sends: the server's default bulk limit. */\nconst MAX_REPLAY_BATCH = 1_000;\n\n/**\n * Where {@link OfflineConfig.keepLastUser} keeps the last signed-in user's id.\n * In the cache area but under no user's scope, so clearing one user's data\n * leaves it alone.\n */\nconst LAST_USER_KEY = \"rebase-offline:last-user\";\n\nexport class OfflineManager {\n private readonly store: OfflineStore;\n private readonly maxCachedQueries: number;\n private readonly maxCachedRows: number;\n private readonly maxRetries: number;\n private readonly onSyncError?: OfflineConfig[\"onSyncError\"];\n private readonly onConflict?: OfflineConfig[\"onConflict\"];\n private readonly createInner: InnerFactory;\n private readonly inners = new Map<string, SDKCollectionClient<AnyRow>>();\n private readonly connectivity: ConnectivityMonitor;\n private readonly keepLastUser: boolean;\n private readonly replayBatchSize: number;\n\n private scope = SIGNED_OUT_SCOPE;\n /**\n * The scope is the last signed-in user's, taken without a confirmed\n * session ({@link resumeLastUser}). Nothing replays while it is set: the\n * queue is sent under the credentials of whoever is signed in, and nobody\n * is yet.\n */\n private unverified = false;\n /**\n * Set while the manager does not know whose data it holds: from\n * {@link holdScope} until the next {@link setScope}. `scope` is not\n * consulted meanwhile — no operation gets a {@link ScopeTicket}, and\n * nothing reads or writes the store.\n */\n private scopeHold?: { known: Promise<void>; release: () => void };\n /**\n * Bumped by every change of user, and by `clear()`.\n *\n * The load paths always re-checked the scope after their awaits; the write\n * paths did not. A `find` sent for user A that answered after B had signed\n * in wrote A's RLS-filtered rows into B's local database, under B's keys,\n * and showed them to B's observers; a replay acknowledged after the switch\n * dequeued a key under B's scope that did not exist, so A's write stayed\n * queued and was sent again when A came back. Every write now carries the\n * {@link ScopeTicket} its operation started under, and one that is stale\n * touches nothing that belongs to the new user.\n */\n private scopeEpoch = 0;\n /** The local database: normalized rows and query snapshots per collection. */\n private collections = new Map<string, CollectionState>();\n /** In-memory mirror of the current scope's queue, in replay order. */\n private queueEntries: PendingMutation[] = [];\n private get queue(): PendingMutation[] {\n return this.queueEntries;\n }\n private set queue(next: PendingMutation[]) {\n this.queueEntries = next;\n this.pendingIndex = undefined;\n }\n /**\n * Per collection, the row ids the queue writes to and the ones it creates\n * — {@link hasPending} and {@link isLocallyCreated}, which answering a\n * page asks once or twice per row. Each used to scan the whole queue: a\n * 500-row page against 200 queued writes read 80,000 queue entries, on\n * every emit. Built on first use after the queue changes; whatever changes\n * it in place calls {@link queueChangedInPlace}.\n */\n private pendingIndex?: Map<string, PendingIds>;\n /**\n * The mutations currently on the wire: one, or the members of a folded\n * run (`replayBatchSize`).\n *\n * `flush` awaits `replay(op)` with `op` still at the head of `queue`, so for\n * the whole duration of that request the in-flight op is also the queue's\n * *tail* whenever it is the only entry. Both shortcuts in `enqueue` reach\n * for the tail, and neither may touch an op the server is already reading:\n *\n * - Coalescing an update into it mutates a payload that has already been\n * serialized and sent, and `drop` then removes the whole entry on ACK —\n * so the second edit is neither sent nor kept. A silently lost write.\n * - Cancelling it out against a delete assumes the server never saw the\n * create. It is seeing it right now, so the row would be created and the\n * delete never queued — an orphan row nothing will ever remove.\n *\n * Guarding on ids rather than on a boolean is what keeps this correct\n * when a folded run sends several at once, its last member the tail.\n */\n private readonly inFlight = new Set<string>();\n private queueLoad?: Promise<void>;\n /** Serializes enqueues so concurrent writes keep the order the app made them. */\n private enqueueChain: Promise<unknown> = Promise.resolve();\n private flushPromise?: Promise<{ flushed: number; remaining: number }>;\n private queueListeners = new Set<(count: number) => void>();\n private statusListeners = new Set<(status: OfflineStatus) => void>();\n private observers = new Map<string, Set<Observer>>();\n private refreshPending = new Set<string>();\n private revCounter = 0;\n private disposed = false;\n /** Whether {@link requestPersistence} has asked. */\n private persistenceRequested = false;\n private currentStatus: OfflineStatus = { online: true, syncing: false, pending: 0 };\n private readonly channel?: BroadcastChannel;\n private readonly tabId = createMutationId();\n\n readonly api: OfflineApi;\n\n constructor(config: OfflineConfig, createInner: InnerFactory) {\n this.store = config.store\n ?? (typeof indexedDB !== \"undefined\" ? new IndexedDBOfflineStore() : new MemoryOfflineStore());\n this.maxCachedQueries = config.maxCachedQueriesPerCollection ?? 50;\n this.maxCachedRows = config.maxCachedRowsPerCollection ?? 5_000;\n this.maxRetries = config.maxRetries ?? 5;\n this.onSyncError = config.onSyncError;\n this.onConflict = config.onConflict;\n this.keepLastUser = config.keepLastUser === true;\n const batch = Math.floor(config.replayBatchSize ?? 1);\n this.replayBatchSize = Number.isFinite(batch) ? Math.min(Math.max(batch, 1), MAX_REPLAY_BATCH) : 1;\n this.createInner = createInner;\n\n const maxBackoffMs = config.syncIntervalMs ?? 60_000;\n this.connectivity = new ConnectivityMonitor({\n maxBackoffMs: Math.max(1_000, maxBackoffMs),\n // With no retry timer nothing would ever reopen the window, so a\n // single failure would strand the client offline forever.\n respectBackoff: maxBackoffMs > 0\n });\n if (maxBackoffMs > 0) {\n this.connectivity.onRetryDue = () => { void this.sync().catch(() => undefined); };\n }\n // Whatever the retry policy: `0` turns off the timer, not the\n // browser's word that the connection is back (see `syncIntervalMs`).\n this.connectivity.onOnline = () => { void this.sync().catch(() => undefined); };\n this.connectivity.onChange((online) => {\n this.patchStatus({ online });\n if (online) this.revalidateAll();\n });\n this.currentStatus.online = this.connectivity.isOnline();\n\n // Other tabs share the same IndexedDB. Without this they would each\n // hold a stale copy of the row database and quietly diverge — one tab\n // showing an edit the other never learns about. A memory store is not\n // shared with anyone, so there is nothing to reconcile and the channel\n // would only relay writes between unrelated clients.\n const crossTab = config.crossTab ?? this.store instanceof IndexedDBOfflineStore;\n if (crossTab && typeof BroadcastChannel !== \"undefined\") {\n try {\n this.channel = new BroadcastChannel(\"rebase-offline\");\n this.channel.onmessage = (event: MessageEvent) => this.onBroadcast(event.data);\n // Node's BroadcastChannel is ref'd, and a script that opened a\n // client should still be able to exit.\n unref(this.channel);\n } catch {\n // Not fatal: a browser that refuses the channel just loses\n // cross-tab propagation.\n }\n }\n\n this.api = {\n sync: () => this.sync(),\n pending: async (options) => {\n if (options?.orphaned) {\n await this.scopeKnown();\n if (this.scope === SIGNED_OUT_SCOPE) return [];\n // Read off the store, never loaded into `queue`: nothing\n // here may replay under the signed-in user's credentials.\n return await this.readQueue(`${SIGNED_OUT_SCOPE}|`);\n }\n await this.ensureQueueLoaded();\n // Deep-copied: these are live queue entries (tail coalescing\n // mutates them in place), and a caller must not be able to\n // edit what will be replayed. Through the codec, which a bare\n // structured clone would flatten every class instance past.\n return this.queue.map((m) => hydrateMutation(structuredClone(dehydrateMutation(m))));\n },\n status: () => ({ ...this.currentStatus }),\n onStatusChange: (listener) => {\n this.statusListeners.add(listener);\n return () => this.statusListeners.delete(listener);\n },\n clear: async (options) => {\n await this.scopeKnown();\n if (options?.orphaned) {\n if (this.scope === SIGNED_OUT_SCOPE) return;\n await this.store.clear(`${SIGNED_OUT_SCOPE}|`);\n // A tab still signed out holds that queue in memory.\n this.broadcast({ type: \"queue\" }, SIGNED_OUT_SCOPE);\n return;\n }\n // Anything in flight was read for the rows being thrown away.\n this.scopeEpoch++;\n await this.store.clear(`${this.scope}|`);\n this.queue = [];\n this.resetCollections();\n this.patchStatus({ pending: 0, lastError: undefined });\n this.notifyQueue();\n for (const slug of this.observers.keys()) this.notifyCollection(slug, false);\n },\n onQueueChange: (listener) => {\n this.queueListeners.add(listener);\n return () => this.queueListeners.delete(listener);\n }\n };\n }\n\n /**\n * Cache and queue are partitioned per signed-in user: cached rows are\n * RLS-filtered for the user who fetched them, and queued writes must\n * replay under the credentials that made them — so neither may ever leak\n * across a sign-out/sign-in on a shared browser.\n */\n setScope(uid: string | undefined, options?: { unverified?: boolean }): void {\n const next = uid || SIGNED_OUT_SCOPE;\n const unverified = next !== SIGNED_OUT_SCOPE && options?.unverified === true;\n if (!unverified) this.rememberUser(uid);\n const hold = this.scopeHold;\n if (!hold && next === this.scope) {\n if (this.unverified && !unverified) {\n // The user this device was showing is the one signed in: their\n // rows stay where they are, and their queue can go now.\n this.unverified = false;\n this.patchStatus({ unverifiedUser: undefined });\n void this.sync().catch(() => undefined);\n }\n return;\n }\n this.scope = next;\n this.unverified = unverified;\n this.scopeHold = undefined;\n this.leaveScope();\n this.patchStatus({ unverifiedUser: unverified || undefined });\n // What was waiting for a user runs for this one.\n hold?.release();\n this.revalidateAll();\n // The returning user's queue may hold writes from a previous session.\n void this.sync().catch(() => undefined);\n }\n\n /** Whether the manager was created with {@link OfflineConfig.keepLastUser}. */\n get keepsLastUser(): boolean {\n return this.keepLastUser;\n }\n\n /**\n * Take the scope of the last user who signed in on this device, without a\n * session — for a load whose session restore could not reach the server.\n * See {@link OfflineConfig.keepLastUser}. With no user remembered (or the\n * option off) this is the signed-out scope, as it would have been anyway.\n *\n * Only while the scope is still held: an auth event that settled it while\n * the id was being read is newer news.\n */\n async resumeLastUser(): Promise<void> {\n let uid: string | undefined;\n if (this.keepLastUser) {\n try {\n const entry = await this.store.getCache(LAST_USER_KEY);\n if (typeof entry?.value === \"string\" && entry.value) uid = entry.value;\n } catch {\n // A store that cannot be read has no user to offer.\n }\n }\n if (!this.scopeHold) return;\n this.setScope(uid, { unverified: uid !== undefined });\n }\n\n /**\n * Keep the signed-in user's id for {@link resumeLastUser}, or forget it at\n * sign-out. Forgetting does not depend on the option, so turning it off\n * does not leave the last id behind for good.\n */\n private rememberUser(uid: string | undefined): void {\n const write = uid\n ? (this.keepLastUser ? this.store.setCache(LAST_USER_KEY, { value: uid, cachedAt: Date.now() }) : undefined)\n : this.store.deleteCache([LAST_USER_KEY]);\n void write?.catch(() => undefined);\n }\n\n /**\n * Forget whose data this is until the next {@link setScope}.\n *\n * For the time before the client knows who is signed in — a session being\n * restored on load. Taking that time for \"signed out\" would put the user's\n * own writes in the signed-out queue, which no sign-in replays, and show\n * them the signed-out local database instead of theirs.\n *\n * Meanwhile the manager has no scope at all. Every operation — a read, a\n * write, a replay, `pending()`, `clear()` — waits for one and then runs\n * for whoever it turns out to be, and nothing reads or writes the store.\n * A realtime frame arriving in between is handed on as the server sent it\n * and kept nowhere.\n */\n holdScope(): void {\n if (this.scopeHold) return;\n let release!: () => void;\n const known = new Promise<void>((resolve) => { release = resolve; });\n this.scopeHold = { known, release };\n this.leaveScope();\n }\n\n /** Let go of the current user's rows and queue: in memory, and on screen. */\n private leaveScope(): void {\n this.scopeEpoch++;\n this.queueLoad = undefined;\n this.queue = [];\n this.resetCollections();\n this.patchStatus({ pending: 0, lastError: undefined });\n this.notifyQueue();\n // Everything on screen belongs to the previous user.\n for (const slug of this.observers.keys()) this.notifyCollection(slug, false);\n }\n\n /** Settles once the manager knows whose data it holds — see {@link holdScope}. */\n private async scopeKnown(): Promise<void> {\n while (this.scopeHold) await this.scopeHold.known;\n }\n\n /**\n * The user an operation is running for — see {@link scopeEpoch} — or\n * nothing while that is not known ({@link holdScope}). An operation takes\n * it as `this.ticket() ?? await this.nextTicket()`, before its first await.\n */\n private ticket(): ScopeTicket | undefined {\n if (this.scopeHold) return undefined;\n return { scope: this.scope, epoch: this.scopeEpoch };\n }\n\n /** The ticket of whoever the held scope turns out to be. */\n private async nextTicket(): Promise<ScopeTicket> {\n await this.scopeKnown();\n return { scope: this.scope, epoch: this.scopeEpoch };\n }\n\n /** Whether an operation's user is still the signed-in one. */\n private isCurrent(ticket: ScopeTicket): boolean {\n return ticket.epoch === this.scopeEpoch;\n }\n\n /**\n * Throw away every local row, for a scope change or an explicit clear.\n *\n * The state objects are replaced rather than emptied, so a load still in\n * flight for the previous user fails its identity check and discards what\n * it read instead of grafting it onto the new one. The replacements are\n * marked ready: nothing needs loading until something asks, and observers\n * have to be told *now* that the rows they are showing are gone.\n */\n private resetCollections(): void {\n const slugs = [...this.collections.keys()];\n this.collections = new Map();\n for (const slug of slugs) {\n this.collections.set(slug, {\n rows: new Map(),\n snapshots: new Map(),\n fresh: new Set(),\n freshRows: new Set(),\n absent: new Set(),\n ready: true\n });\n }\n }\n\n /** Release listeners, timers and the cross-tab channel (client.close()). */\n dispose(): void {\n this.disposed = true;\n this.connectivity.dispose();\n try {\n this.channel?.close();\n } catch {\n // A channel that is already closed is not a problem.\n }\n this.observers.clear();\n this.queueListeners.clear();\n this.statusListeners.clear();\n }\n\n // ─── Collection wrapping ─────────────────────────────────────────────────\n\n wrap<M extends AnyRow>(slug: string, inner: CollectionClient<M>): CollectionClient<M> {\n this.inners.set(slug, inner as SDKCollectionClient<AnyRow>);\n\n /**\n * `find`, and the page reader of `iterate()` / `findAll()` when `walk`\n * is set.\n *\n * A walk reads `meta.hasMore` as the server's word on whether to go\n * on. A page the server never answered here is evaluated over whatever\n * rows happen to be cached, and its `hasMore` is about those rows — so\n * offline, `findAll()` stopped at the first such page and returned a\n * fraction of the collection as the whole of it, with nothing to tell\n * the two apart. A walk refuses that page instead.\n */\n const findPage = async (params: FindParams<M> | undefined, walk: boolean): Promise<FindResult<M>> => {\n const ticket = this.ticket() ?? await this.nextTicket();\n const state = await this.ensureCollection(slug);\n if (this.connectivity.shouldAttempt()) {\n try {\n const res = await inner.find(params);\n this.connectivity.markSuccess();\n // Answered for a user who has since signed out: theirs\n // to read, not the next user's to keep.\n if (!this.isCurrent(ticket)) return res;\n await this.ingest(slug, res.data ?? [], ticket, isProjection(params));\n if (!this.isCurrent(ticket)) return res;\n const snapshot = this.recordSnapshot(slug, params, res, ticket);\n const answer = this.answer<M>(slug, params, snapshot);\n this.notifyCollection(slug, false);\n return { data: answer.data, meta: answer.meta };\n } catch (error) {\n if (!isNetworkError(error)) {\n // A 5xx or a rate limit still deserves the cached\n // answer rather than an exception the app has to\n // special-case, but only when we have one.\n if (isRetryableError(error) && this.hasLocalAnswer(state, slug, params)\n && !(walk && !this.snapshotFor(slug, params))) {\n const answer = this.answer<M>(slug, params, this.snapshotFor(slug, params));\n return { data: answer.data, meta: answer.meta };\n }\n throw error;\n }\n this.connectivity.markFailure();\n }\n }\n if (walk && !this.snapshotFor(slug, params)) throw unwalkable();\n const answer = this.localFind<M>(slug, params);\n // Falling back is a state change even when the rows are the\n // same — it is how a \"showing cached data\" badge lights up.\n this.notifyCollection(slug, false);\n return { data: answer.data, meta: answer.meta };\n };\n const unwalkable = () => offlineError(\n `Offline: a page of \"${slug}\" the server has not answered on this device is needed to ` +\n \"read the collection to the end, and the local database cannot say what is on it.\"\n );\n\n const wrapped: CollectionClient<M> = {\n find: (params?: FindParams<M>) => findPage(params, false),\n\n // Paginates through the local database page by page as the server\n // answered those pages here, and rejoins the network mid-walk if\n // it returns. A page it never answered fails the walk — see\n // `findPage`.\n iterate: (params?: IterateParams<M>) => paginateFind<M>((p) => findPage(p, true), params, slug),\n\n findAll: (params?: FindAllParams<M>) => collectAllPages<M>((p) => findPage(p, true), params, slug),\n\n findById: async (id: string | number, options?: ByIdReadOptions) => {\n const ticket = this.ticket() ?? await this.nextTicket();\n await this.ensureCollection(slug);\n if (this.connectivity.shouldAttempt()) {\n try {\n const row = await inner.findById(id, options);\n this.connectivity.markSuccess();\n if (!this.isCurrent(ticket)) return row;\n if (row !== undefined) {\n await this.ingest(slug, [row], ticket);\n } else if (!this.hasPending(slug, id)) {\n // The server is authoritative that it is gone, and\n // nothing local is waiting to recreate it.\n this.removeLocalRow(slug, id, ticket, true);\n }\n this.notifyCollection(slug, false);\n return this.localRow<M>(slug, id);\n } catch (error) {\n if (!isNetworkError(error)) throw error;\n this.connectivity.markFailure();\n }\n }\n const local = this.localRow<M>(slug, id);\n if (local !== undefined || this.hasPending(slug, id)) return local;\n // \"Not there\" is an answer, and one we may already have.\n if (this.collections.get(slug)?.absent.has(String(id))) return undefined;\n throw offlineError(\n `Offline: \"${slug}\" row ${String(id)} is not in the local database.`\n );\n },\n\n get: async (id: string | number) => {\n // Defined in terms of the wrapper's own `findById`, so the whole\n // offline path — local row, pending write, the \"not in the local\n // database\" error — applies unchanged, and only the absent case\n // differs.\n const row = await wrapped.findById(id);\n if (row === undefined) {\n throw new RebaseApiError(\n `No record with id ${JSON.stringify(String(id))} in \"${slug}\".`,\n { status: 404, code: \"NOT_FOUND\" }\n );\n }\n return row;\n },\n\n create: async (data: Partial<M>, id?: string | number, options?: WriteOptions) => {\n const ticket = this.ticket() ?? await this.nextTicket();\n await this.ensureCollection(slug);\n // Named before it is sent: if the answer is lost, the queued\n // replay presents the same key on the same request, and the\n // server can tell it from a second create.\n const idempotencyKey = options?.idempotencyKey ?? createMutationId();\n let sent = false;\n if (this.connectivity.shouldAttempt()) {\n try {\n const row = await inner.create(data, id, { ...options, idempotencyKey });\n this.connectivity.markSuccess();\n await this.ingest(slug, [row], ticket);\n this.notifyCollection(slug);\n this.scheduleRefresh(slug);\n return row;\n } catch (error) {\n if (!isNetworkError(error)) throw error;\n this.connectivity.markFailure();\n sent = true;\n }\n }\n const providedId = id ?? (data as AnyRow).id as string | number | undefined;\n const rowId = providedId ?? this.mintOfflineId(slug);\n const row = optimisticRow<M>(data as AnyRow, rowId);\n await this.enqueue({\n collection: slug,\n type: \"create\",\n id: rowId,\n data: row,\n generatedId: providedId === undefined,\n ...(sent ? { sent: { idempotencyKey, data: { ...(data as AnyRow) }, id } } : {}),\n rollback: { rows: { [String(rowId)]: this.rawLocalRow(slug, rowId) ?? null } }\n }, ticket);\n this.setLocalRow(slug, rowId, row, ticket);\n this.notifyCollection(slug);\n return row;\n },\n\n createMany: async (\n data: Partial<M>[],\n options?: { upsert?: boolean; onConflict?: readonly string[] } & WriteOptions\n ) => {\n const ticket = this.ticket() ?? await this.nextTicket();\n await this.ensureCollection(slug);\n if (!Array.isArray(data)) {\n throw invalidBulkBody(\"createMany expects an array of records.\");\n }\n if (data.length === 0) return [];\n // As in `create`: the key the batch is sent under is the key\n // its replay is sent under.\n const idempotencyKey = options?.idempotencyKey ?? createMutationId();\n let sent = false;\n if (this.connectivity.shouldAttempt()) {\n try {\n const rows = await inner.createMany(data, { ...options, idempotencyKey });\n this.connectivity.markSuccess();\n await this.ingest(slug, rows, ticket);\n this.notifyCollection(slug);\n this.scheduleRefresh(slug);\n return rows;\n } catch (error) {\n if (!isNetworkError(error)) throw error;\n this.connectivity.markFailure();\n sent = true;\n }\n }\n // Refused for the reason `upsert` refuses it: which row a\n // natural key names is the server's to find, and the rows below\n // are about to be given ids that name none of them. A batch\n // already sent is different — its replay is that same request.\n if (!sent && options?.onConflict?.length) {\n throw new RebaseClientError(\n `Cannot upsert into \"${slug}\" while offline: the rows it would replace can only be ` +\n \"found by the server. Upserting on the primary key, with the key in each row, is \" +\n \"queued; upserting on a natural key is not.\",\n { code: \"OFFLINE_UPSERT_UNSUPPORTED\" }\n );\n }\n const rows = data.map((r) =>\n optimisticRow<M>(r as AnyRow, ((r as AnyRow).id as string | number) ?? this.mintOfflineId(slug)));\n const rollback: Record<string, AnyRow | null> = {};\n for (const row of rows) {\n const key = String(row.id);\n rollback[key] = this.rawLocalRow(slug, row.id as string | number) ?? null;\n }\n await this.enqueue({\n collection: slug,\n type: \"createMany\",\n data: rows,\n upsert: options?.upsert,\n ...(sent\n ? {\n sent: {\n idempotencyKey,\n data: data.map((r) => ({ ...(r as AnyRow) })),\n ...(options?.onConflict?.length ? { onConflict: [...options.onConflict] } : {})\n }\n }\n : {}),\n rollback: { rows: rollback }\n }, ticket);\n for (const row of rows) this.setLocalRow(slug, row.id as string | number, row, ticket);\n this.notifyCollection(slug);\n return rows;\n },\n\n /**\n * Upsert, with the one case that cannot be resolved without the\n * server refused rather than guessed.\n *\n * On the primary key an upsert is create-or-replace, which the\n * local store can do and the queue already carries (`createMany`\n * with `upsert`). On a natural key it is not: deciding whether a\n * row with that email exists means an index this store does not\n * keep, and inventing an id would insert a duplicate the moment the\n * queue drains — the exact outcome upsert exists to prevent.\n */\n upsert: async (data: Partial<M>, options?: UpsertOptions) => {\n const ticket = this.ticket() ?? await this.nextTicket();\n await this.ensureCollection(slug);\n if (this.connectivity.shouldAttempt()) {\n try {\n const row = await inner.upsert(data, options);\n this.connectivity.markSuccess();\n await this.ingest(slug, [row], ticket);\n this.notifyCollection(slug);\n this.scheduleRefresh(slug);\n return row;\n } catch (error) {\n if (!isNetworkError(error)) throw error;\n this.connectivity.markFailure();\n }\n }\n const rowId = (data as AnyRow).id as string | number | undefined;\n if (options?.onConflict?.length || rowId === undefined) {\n throw new RebaseClientError(\n `Cannot upsert into \"${slug}\" while offline: the row it would replace can only be ` +\n \"found by the server. Upserting on the primary key, with the key in the row, is \" +\n \"queued; upserting on a natural key is not.\",\n { code: \"OFFLINE_UPSERT_UNSUPPORTED\" }\n );\n }\n const row = optimisticRow<M>(data as AnyRow, rowId);\n await this.enqueue({\n collection: slug,\n type: \"createMany\",\n data: [row],\n upsert: true,\n rollback: { rows: { [String(rowId)]: this.rawLocalRow(slug, rowId) ?? null } }\n }, ticket);\n this.setLocalRow(slug, rowId, row, ticket);\n this.notifyCollection(slug);\n return row;\n },\n\n updateMany: async (\n updates: { id: string | number; data: Partial<M> | UpdateValues<Partial<M>> }[],\n options?: WriteOptions\n ) => {\n const ticket = this.ticket() ?? await this.nextTicket();\n await this.ensureCollection(slug);\n if (!Array.isArray(updates)) {\n throw invalidBulkBody(\"updateMany expects an array of { id, data } entries.\");\n }\n if (updates.length === 0) return [];\n // Any row in the batch with a write already queued sends the\n // whole batch to the queue. Splitting it — some rows now, some\n // later — would break the one guarantee a batch makes, that its\n // rows land together, and would reorder writes against a row\n // whose own create has not landed yet.\n const anyPending = updates.some((u) => this.hasPending(slug, u.id));\n if (this.connectivity.shouldAttempt() && !anyPending) {\n try {\n const rows = await inner.updateMany(updates, options);\n this.connectivity.markSuccess();\n await this.ingest(slug, rows, ticket);\n this.notifyCollection(slug);\n return rows;\n } catch (error) {\n if (!isNetworkError(error)) throw error;\n this.connectivity.markFailure();\n }\n }\n const rollback: Record<string, AnyRow | null> = {};\n const optimistic: M[] = [];\n for (const { id, data } of updates) {\n const base = this.rawLocalRow(slug, id);\n rollback[String(id)] = base ?? null;\n optimistic.push(optimisticRow<M>({ ...(base ?? {}), ...(data as AnyRow) }, id));\n }\n await this.enqueue({\n collection: slug,\n type: \"updateMany\",\n updates: updates.map((u) => ({ id: u.id,\ndata: u.data as AnyRow })),\n rollback: { rows: rollback }\n }, ticket);\n for (const row of optimistic) this.setLocalRow(slug, row.id as string | number, row, ticket);\n this.notifyCollection(slug);\n return optimistic;\n },\n\n deleteMany: async (ids: (string | number)[], options?: WriteOptions) => {\n const ticket = this.ticket() ?? await this.nextTicket();\n await this.ensureCollection(slug);\n if (!Array.isArray(ids)) {\n throw invalidBulkBody(\"deleteMany expects an array of ids.\");\n }\n if (ids.length === 0) return;\n const anyPending = ids.some((id) => this.hasPending(slug, id));\n if (this.connectivity.shouldAttempt() && !anyPending) {\n try {\n await inner.deleteMany(ids, options);\n this.connectivity.markSuccess();\n for (const id of ids) this.removeLocalRow(slug, id, ticket, true);\n this.notifyCollection(slug);\n this.scheduleRefresh(slug);\n return;\n } catch (error) {\n if (!isNetworkError(error)) throw error;\n this.connectivity.markFailure();\n }\n }\n const rollback: Record<string, AnyRow | null> = {};\n for (const id of ids) {\n rollback[String(id)] = this.rawLocalRow(slug, id) ?? null;\n }\n await this.enqueue({\n collection: slug,\n type: \"deleteMany\",\n ids,\n rollback: { rows: rollback }\n }, ticket);\n for (const id of ids) this.removeLocalRow(slug, id, ticket, false);\n this.notifyCollection(slug);\n },\n\n update: async (\n id: string | number,\n data: Partial<M> | UpdateValues<Partial<M>>,\n options?: WriteOptions\n ) => {\n const ticket = this.ticket() ?? await this.nextTicket();\n await this.ensureCollection(slug);\n // As in `create`: the key the edit is sent under is the key\n // its replay is sent under, so a replay of an edit that already\n // committed is answered from the server's record of it rather\n // than applied again over whatever was written since.\n const idempotencyKey = options?.idempotencyKey ?? createMutationId();\n let sent = false;\n let sendFailure: unknown;\n // Never overtake a write already queued for this row. The\n // reads already respect the queue; the writes did not, so an\n // edit made while the row's own create was still pending went\n // straight to a server that had never heard of the row and came\n // back 404 — the caller's edit failing on a row they could see.\n // Queuing keeps the order the app issued the writes in.\n if (this.connectivity.shouldAttempt() && !this.hasPending(slug, id)) {\n try {\n const row = await inner.update(id, data, { ...options, idempotencyKey });\n this.connectivity.markSuccess();\n await this.ingest(slug, [row], ticket);\n this.notifyCollection(slug);\n return row;\n } catch (error) {\n if (!isNetworkError(error)) throw error;\n this.connectivity.markFailure();\n sent = true;\n sendFailure = error;\n }\n }\n // A field operation is an expression over the *stored* value,\n // and the point of it is that the server evaluates it under the\n // row lock. Queuing it would be correct on arrival and wrong on\n // screen in the meantime: the optimistic row below can only\n // spread the marker object into the column, so a UI showing\n // `views` would render `{ $inc: 1 }` until the queue drained.\n if (hasFieldOperation(data as Record<string, unknown>)) {\n // Sent, and no answer: it may well have been applied. \"It\n // cannot be applied, retry\" would apply it twice — so the\n // caller hears that the outcome is unknown, and gets the key\n // under which a retry is applied at most once.\n if (sent) {\n throw new RebaseApiError(\n `The connection failed after a field operation on \"${slug}\" was sent, so it may ` +\n \"or may not have been applied. Retry it with the idempotencyKey in `details` \" +\n \"to apply it at most once.\",\n { status: 0, code: \"NETWORK_ERROR\", details: { idempotencyKey }, cause: sendFailure }\n );\n }\n throw new RebaseClientError(\n `Cannot apply a field operation to \"${slug}\" while offline: it is evaluated ` +\n \"against the stored value, which this device does not have a current copy of. \" +\n \"Send the value itself, or retry when the connection is back.\",\n { code: \"OFFLINE_FIELD_OP_UNSUPPORTED\" }\n );\n }\n const base = this.rawLocalRow(slug, id);\n // The version this edit was made against. On top of another\n // queued write it is that write's row, which has no version\n // until it replays — so none.\n const ifMatch = this.onConflict\n ? options?.ifMatch ?? (this.hasPending(slug, id) ? undefined : this.etagFor(slug, id))\n : undefined;\n await this.enqueue({\n collection: slug,\n type: \"update\",\n id,\n data: data as AnyRow,\n ...(sent ? { sent: { idempotencyKey } } : {}),\n ...(ifMatch ? { ifMatch } : {}),\n rollback: { rows: { [String(id)]: base ?? null } }\n }, ticket);\n const optimistic = optimisticRow<M>({ ...(base ?? {}), ...(data as AnyRow) }, id);\n this.setLocalRow(slug, id, optimistic, ticket);\n this.notifyCollection(slug);\n return optimistic;\n },\n\n delete: async (id: string | number, options?: WriteOptions) => {\n const ticket = this.ticket() ?? await this.nextTicket();\n await this.ensureCollection(slug);\n // Keyed from the first attempt, because a delete is the write\n // a lost answer hurts most: its replay finds the row gone and\n // answers 404, which the queue takes for a refusal — rolling\n // back, and reporting as failed, a delete that succeeded.\n const idempotencyKey = options?.idempotencyKey ?? createMutationId();\n let sent = false;\n // As in `update`: a delete must not overtake this row's own\n // queued create, or it 404s and the create then lands behind\n // it, leaving the row the caller just deleted.\n if (this.connectivity.shouldAttempt() && !this.hasPending(slug, id)) {\n try {\n await inner.delete(id, { ...options, idempotencyKey });\n this.connectivity.markSuccess();\n this.removeLocalRow(slug, id, ticket, true);\n this.notifyCollection(slug);\n this.scheduleRefresh(slug);\n return;\n } catch (error) {\n if (!isNetworkError(error)) throw error;\n this.connectivity.markFailure();\n sent = true;\n }\n }\n await this.enqueue({\n collection: slug,\n type: \"delete\",\n id,\n ...(sent ? { sent: { idempotencyKey } } : {}),\n rollback: { rows: { [String(id)]: this.rawLocalRow(slug, id) ?? null } }\n }, ticket);\n this.removeLocalRow(slug, id, ticket);\n this.notifyCollection(slug);\n },\n\n count: async (params?: FindParams<M>): Promise<number> => {\n const ticket = this.ticket() ?? await this.nextTicket();\n await this.ensureCollection(slug);\n if (this.connectivity.shouldAttempt()) {\n try {\n const n = await inner.count(params);\n this.connectivity.markSuccess();\n if (!this.isCurrent(ticket)) return n;\n void this.writeCache(this.countKey(slug, params), n);\n return Math.max(0, n + this.pendingDelta(slug, params));\n } catch (error) {\n if (!isNetworkError(error)) throw error;\n this.connectivity.markFailure();\n }\n }\n const cached = await this.readCache<number>(this.countKey(slug, params));\n if (cached !== undefined) return Math.max(0, cached + this.pendingDelta(slug, params));\n // Counting the cached rows would answer \"how many rows does\n // this device hold\" under the name of \"how many rows are\n // there\": 20 of 214 after a cold start, said with confidence.\n throw offlineError(`Offline: no cached count for \"${slug}\".`);\n },\n\n observe: (\n params: FindParams<M> | undefined,\n onResult: (result: LiveResult<M>) => void,\n onError?: (error: Error) => void,\n options?: ObserveOptions\n ) => this.observe<M>(slug, wrapped, inner, params, onResult, onError, options),\n\n observeById: (\n id: string | number,\n onResult: (row: M | undefined, meta: RowSnapshotMeta) => void,\n onError?: (error: Error) => void,\n options?: ObserveByIdOptions\n ) => this.observeById<M>(slug, wrapped, inner, id, onResult, onError, options),\n\n // The builder calls back into `wrapped.find(...)`, so fluent\n // queries go through the local database like direct calls.\n where(columnOrCondition: string | LogicalCondition, operator?: WhereFilterOp, value?: unknown) {\n const builder = new SDKQueryBuilder<M>(wrapped);\n if (typeof columnOrCondition === \"object\") return builder.where(columnOrCondition);\n return builder.where(\n columnOrCondition as keyof M & string,\n operator!,\n value as WhereValueFor<WhereFilterOp, M[keyof M & string]>\n );\n },\n orderBy: (column, direction, nulls) => new SDKQueryBuilder<M>(wrapped).orderBy(column, direction, nulls),\n limit: (count) => new SDKQueryBuilder<M>(wrapped).limit(count),\n offset: (count) => new SDKQueryBuilder<M>(wrapped).offset(count),\n search: (searchString, options) => new SDKQueryBuilder<M>(wrapped).search(searchString, options),\n vectorSearch: (property, vector, options) => new SDKQueryBuilder<M>(wrapped).vectorSearch(property, vector, options),\n include: (...relations) => new SDKQueryBuilder<M>(wrapped).include(...relations),\n fields: (...columns) => new SDKQueryBuilder<M>(wrapped).fields(...columns),\n distinct: (enabled) => new SDKQueryBuilder<M>(wrapped).distinct(enabled),\n after: (cursor) => new SDKQueryBuilder<M>(wrapped).after(cursor),\n\n trash: this.wrapTrash<M>(slug, inner),\n\n // Straight through to the server. An aggregate is a reduction over\n // rows the cache does not necessarily hold, and answering one from\n // a subset is a number that looks exactly like the right number —\n // the same reason a vector search is not answered locally.\n aggregate: inner.aggregate,\n\n // Carried over as-is when the inner client cannot listen, so the\n // wrapper does not turn \"realtime is off on this client\" into\n // \"this method does not exist\" — the two used to be the same thing.\n listen: inner.listen,\n listenById: inner.listenById,\n // The server's count, live. Not offline-aware: it is a number the\n // server keeps, and the queue's writes are not in it until they replay.\n listenCount: inner.listenCount\n };\n\n // Realtime stays a live server stream — everything it delivers feeds\n // the local database on its way past — but what the app is handed is\n // the local database's answer, as `observe` hands it. The raw frame\n // knows nothing of the queue: a frame landing before an offline edit\n // replayed showed the server's value over the user's own edit, while\n // `findById` beside it still returned the edit.\n //\n // The socket re-authenticates as whoever is signed in, so a frame is\n // the current user's — once it is known who that is. Before then a\n // frame is handed on as the server sent it, and kept nowhere.\n if (!isUnsupported(inner.listen)) {\n wrapped.listen = (params, onUpdate, onError) => inner.listen(\n params,\n (response) => {\n const ticket = this.ticket();\n if (!ticket) {\n onUpdate(response);\n return;\n }\n void this.ingest(slug, response.data ?? [], ticket, isProjection(params)).then(() => {\n if (!this.isCurrent(ticket)) return;\n const snapshot = this.recordSnapshot(slug, params, response, ticket);\n const answer = this.answer<M>(slug, params, snapshot);\n this.notifyCollection(slug, false);\n onUpdate({ ...response, data: answer.data, meta: answer.meta });\n });\n },\n onError\n );\n }\n if (!isUnsupported(inner.listenById)) {\n wrapped.listenById = (id, onUpdate, onError, options) => inner.listenById(\n id,\n (row) => {\n const ticket = this.ticket();\n if (!ticket) {\n onUpdate(row);\n return;\n }\n if (!row) {\n // Deleted elsewhere. `observeById` always handled this;\n // here the row stayed in the local database and was\n // served offline. One with a queued write is kept: the\n // write decides, when it replays.\n if (!this.hasPending(slug, id)) this.removeLocalRow(slug, id, ticket, true);\n this.notifyCollection(slug, false);\n onUpdate(row);\n return;\n }\n void this.ingest(slug, [row], ticket).then(() => {\n if (!this.isCurrent(ticket)) return;\n this.notifyCollection(slug, false);\n onUpdate(this.localRow<M>(slug, id) ?? row);\n });\n },\n onError,\n options\n );\n }\n\n return wrapped;\n }\n\n /**\n * `client.data.<slug>.trash` on an offline client: every call goes to the\n * server, and none is cached or queued.\n *\n * The local database holds live rows only — a trashed row read into it\n * would show up in every live query that matches it — so it cannot answer\n * a trash read, and a restore or a purge queued offline would act on a row\n * this device has never seen. Each of them rejects with `OFFLINE` instead.\n *\n * What the server answers does reach the local database: a restored row\n * is live again and joins it, and a purged row leaves it. A row with a\n * write still queued is synced first, so a purge never overtakes the\n * queued delete it follows; if the queue cannot drain, the call is refused.\n */\n private wrapTrash<M extends AnyRow>(slug: string, inner: CollectionClient<M>): TrashClient<M> {\n const online = async <T>(what: string, call: () => Promise<T>): Promise<T> => {\n const message = `Offline: ${what} on the trash of \"${slug}\" needs the server; the trash is never cached on this device.`;\n if (!this.connectivity.shouldAttempt()) throw offlineError(message);\n try {\n const result = await call();\n this.connectivity.markSuccess();\n return result;\n } catch (error) {\n if (!isNetworkError(error)) throw error;\n this.connectivity.markFailure();\n throw new RebaseApiError(message, { status: 0, code: \"OFFLINE\", cause: error });\n }\n };\n const settleQueued = async (what: string, ids: readonly (string | number)[]): Promise<void> => {\n if (!ids.some((id) => this.hasPending(slug, id))) return;\n await this.sync().catch(() => undefined);\n const stuck = ids.find((id) => this.hasPending(slug, id));\n if (stuck === undefined) return;\n throw new RebaseClientError(\n `Cannot ${what} \"${slug}\" row ${String(stuck)} yet: a write to it is still queued, and the ` +\n \"trash acts on the server's copy. Retry once `client.offline.sync()` has sent it.\",\n { code: \"TRASH_PENDING_WRITE\", details: { id: stuck } }\n );\n };\n const restored = async (rows: M[], ticket: ScopeTicket): Promise<void> => {\n await this.ingest(slug, rows.filter((row) => row && typeof row === \"object\"), ticket);\n this.notifyCollection(slug);\n this.scheduleRefresh(slug);\n };\n const purged = (ids: readonly (string | number)[], ticket: ScopeTicket): void => {\n for (const id of ids) this.removeLocalRow(slug, id, ticket, true);\n this.notifyCollection(slug);\n this.scheduleRefresh(slug);\n };\n return {\n find: (params?: FindParams<M>) => online(\"find()\", () => inner.trash.find(params)),\n count: (params?: FindParams<M>) => online(\"count()\", () => inner.trash.count(params)),\n restore: async (id: string | number, options?: RestoreOptions<M>) => {\n const ticket = this.ticket() ?? await this.nextTicket();\n await this.ensureCollection(slug);\n await settleQueued(\"restore\", [id]);\n const row = await online(\"restore()\", () => inner.trash.restore(id, options));\n await restored(row ? [row] : [], ticket);\n return row;\n },\n restoreMany: async (ids: (string | number)[], options?: RestoreOptions<M>) => {\n const ticket = this.ticket() ?? await this.nextTicket();\n await this.ensureCollection(slug);\n if (!Array.isArray(ids)) throw invalidBulkBody(\"trash.restoreMany expects an array of ids.\");\n await settleQueued(\"restore\", ids);\n const rows = await online(\"restoreMany()\", () => inner.trash.restoreMany(ids, options));\n await restored(rows, ticket);\n return rows;\n },\n purge: async (id: string | number, options?: WriteOptions) => {\n const ticket = this.ticket() ?? await this.nextTicket();\n await this.ensureCollection(slug);\n await settleQueued(\"purge\", [id]);\n await online(\"purge()\", () => inner.trash.purge(id, options));\n purged([id], ticket);\n },\n purgeMany: async (ids: (string | number)[], options?: WriteOptions) => {\n const ticket = this.ticket() ?? await this.nextTicket();\n await this.ensureCollection(slug);\n if (!Array.isArray(ids)) throw invalidBulkBody(\"trash.purgeMany expects an array of ids.\");\n if (ids.length === 0) return;\n await settleQueued(\"purge\", ids);\n await online(\"purgeMany()\", () => inner.trash.purgeMany(ids, options));\n purged(ids, ticket);\n }\n };\n }\n\n // ─── Live queries ────────────────────────────────────────────────────────\n\n private observe<M extends AnyRow>(\n slug: string,\n wrapped: CollectionClient<M>,\n inner: CollectionClient<M>,\n params: FindParams<M> | undefined,\n onResult: (result: LiveResult<M>) => void,\n onError?: (error: Error) => void,\n options?: ObserveOptions\n ): () => void {\n let closed = false;\n let unlisten: (() => void) | undefined;\n\n const observer: Observer = {\n slug,\n params,\n settled: false,\n refresh: () => wrapped.find(params).catch(() => undefined),\n emit: () => {\n if (closed || !this.collections.get(slug)?.ready) return;\n const result = this.answer<M>(slug, params, this.snapshotFor(slug, params));\n // Every field the callback receives has to be in the\n // signature, or a change to one of them is deduplicated away —\n // a row settling from \"saving\" to saved is exactly that.\n const signature = `${result.fromCache ? \"c\" : \"s\"}${result.hasPendingWrites ? \"p\" : \"-\"}`\n + this.signature(slug, result.data, result.meta.total);\n if (observer.settled && signature === observer.signature) return;\n observer.signature = signature;\n observer.settled = true;\n onResult(observer.error ? { ...result, error: observer.error } : result);\n }\n };\n this.observersFor(slug).add(observer);\n\n void (async () => {\n await this.ensureCollection(slug);\n if (closed) return;\n // Emit whatever is already local before touching the network. An\n // app that has run this query before renders instantly.\n if (this.hasLocalAnswer(this.collections.get(slug), slug, params)) observer.emit();\n try {\n await wrapped.find(params);\n observer.error = undefined;\n } catch (error) {\n observer.error = error as Error;\n if (closed) return;\n // A read that found nothing locally has nothing to emit, so the\n // failure is all the app gets.\n if (!observer.settled) {\n onError?.(error as Error);\n return;\n }\n }\n if (!closed) observer.emit();\n })();\n\n if (options?.realtime !== false && !isUnsupported(inner.listen)) {\n unlisten = inner.listen(params, (response) => {\n // Whose rows these are is not known yet. The observer reads\n // the query itself once it is.\n const ticket = this.ticket();\n if (!ticket) return;\n void this.ingest(slug, response.data ?? [], ticket, isProjection(params)).then(() => {\n this.recordSnapshot(slug, params, response, ticket);\n this.notifyCollection(slug, false);\n });\n }, onError);\n }\n\n return () => {\n closed = true;\n this.observersFor(slug).delete(observer);\n unlisten?.();\n };\n }\n\n private observeById<M extends AnyRow>(\n slug: string,\n wrapped: CollectionClient<M>,\n inner: CollectionClient<M>,\n id: string | number,\n onResult: (row: M | undefined, meta: RowSnapshotMeta) => void,\n onError?: (error: Error) => void,\n options?: ObserveByIdOptions\n ): () => void {\n // Both reads load the same relations, so every emission carries them.\n const read = byIdRead(options);\n let closed = false;\n let unlisten: (() => void) | undefined;\n const observer: Observer = {\n slug,\n id,\n settled: false,\n refresh: () => wrapped.findById(id, read).catch(() => undefined),\n emit: () => {\n if (closed || !this.collections.get(slug)?.ready) return;\n const row = this.localRow<M>(slug, id);\n const entry = this.collections.get(slug)?.rows.get(String(id));\n const fromCache = !this.collections.get(slug)?.freshRows.has(String(id));\n const hasPendingWrites = this.hasPending(slug, id);\n const signature = `${fromCache ? \"c\" : \"s\"}${hasPendingWrites ? \"p\" : \"-\"}|`\n + (row === undefined ? MISSING : `${String(id)}:${entry?.rev ?? 0}`);\n if (observer.settled && signature === observer.signature) return;\n observer.signature = signature;\n observer.settled = true;\n onResult(row, { fromCache, hasPendingWrites });\n }\n };\n this.observersFor(slug).add(observer);\n\n void (async () => {\n await this.ensureCollection(slug);\n if (closed) return;\n if (this.localRow<M>(slug, id) !== undefined) observer.emit();\n try {\n await wrapped.findById(id, read);\n } catch (error) {\n if (closed) return;\n if (!observer.settled) {\n onError?.(error as Error);\n return;\n }\n }\n if (!closed) observer.emit();\n })();\n\n if (options?.realtime !== false && !isUnsupported(inner.listenById)) {\n unlisten = inner.listenById(id, (row) => {\n // As in `observe`: before the scope is known, the observer's\n // own read is what fills it in.\n const ticket = this.ticket();\n if (!ticket) return;\n if (!row) {\n if (!this.hasPending(slug, id)) this.removeLocalRow(slug, id, ticket, true);\n this.notifyCollection(slug, false);\n return;\n }\n void this.ingest(slug, [row], ticket).then(() => this.notifyCollection(slug, false));\n }, onError, read);\n }\n\n return () => {\n closed = true;\n this.observersFor(slug).delete(observer);\n unlisten?.();\n };\n }\n\n private observersFor(slug: string): Set<Observer> {\n let set = this.observers.get(slug);\n if (!set) {\n set = new Set();\n this.observers.set(slug, set);\n }\n return set;\n }\n\n /** Cheap change detection: which rows, in what order, at which revision. */\n private signature(slug: string, rows: AnyRow[], total: number): string {\n const state = this.collections.get(slug);\n const parts = rows.map((row) => {\n const key = String(row.id);\n const entry = state?.rows.get(key);\n // A stored row is told apart by its revision; anything else — a\n // projection, as served or narrowed from a local row — by what it\n // holds, since nothing revises it.\n return entry?.row === row ? `${key}:${entry.rev}` : `${key}=${JSON.stringify(row)}`;\n });\n return `${total}|${parts.join(\",\")}`;\n }\n\n private notifyCollection(slug: string, broadcast = true): void {\n const set = this.observers.get(slug);\n if (set) for (const observer of [...set]) callSafely(() => observer.emit());\n if (broadcast) this.broadcast({ type: \"rows\", slugs: [slug] });\n }\n\n /** Connectivity came back (or the user changed): re-read everything live. */\n private revalidateAll(): void {\n for (const slug of this.observers.keys()) {\n this.notifyCollection(slug, false);\n this.scheduleRefresh(slug);\n }\n }\n\n // ─── Reading the local database ──────────────────────────────────────────\n\n private collectionState(slug: string): CollectionState {\n let state = this.collections.get(slug);\n if (!state) {\n state = {\n rows: new Map(),\n snapshots: new Map(),\n fresh: new Set(),\n freshRows: new Set(),\n absent: new Set(),\n ready: false\n };\n this.collections.set(slug, state);\n }\n return state;\n }\n\n private ensureCollection(slug: string): Promise<CollectionState> {\n // Whose rows to load is not known yet.\n if (this.scopeHold) return this.scopeKnown().then(() => this.ensureCollection(slug));\n const state = this.collectionState(slug);\n if (!state.loaded) {\n const scope = this.scope;\n state.loaded = (async () => {\n await this.ensureQueueLoaded();\n const [rows, snapshots, absent] = await Promise.all([\n this.store.listCacheEntries(`${scope}|row|${slug}|`).catch(() => []),\n this.store.listCacheEntries(`${scope}|q|${slug}|`).catch(() => []),\n this.store.listCache(`${scope}|abs|${slug}|`).catch(() => [])\n ]);\n // A scope switch mid-load must not graft the previous user's\n // rows onto the new one.\n if (this.scope !== scope || this.collections.get(slug) !== state) return;\n for (const entry of rows) {\n const row = entry.value as AnyRow | undefined;\n if (!row || row.id === undefined || row.id === null) continue;\n state.rows.set(String(row.id), {\n row: hydrateRow(row),\n cachedAt: entry.cachedAt,\n rev: ++this.revCounter\n });\n }\n for (const entry of snapshots) {\n const key = entry.key.slice(`${scope}|q|${slug}|`.length);\n if (entry.value) state.snapshots.set(key, readSnapshot(entry.value));\n }\n for (const entry of absent) {\n state.absent.add(entry.key.slice(`${scope}|abs|${slug}|`.length));\n }\n })().catch(() => undefined).finally(() => { state.ready = true; });\n }\n return state.loaded.then(() => state);\n }\n\n private snapshotFor(slug: string, params?: FindParams): QuerySnapshot | undefined {\n return this.collections.get(slug)?.snapshots.get(buildQueryString(params));\n }\n\n private hasLocalAnswer(state: CollectionState | undefined, slug: string, params?: FindParams): boolean {\n if (!state) return false;\n return state.snapshots.has(buildQueryString(params)) || state.rows.size > 0;\n }\n\n /**\n * Answer a query from the local database.\n *\n * With a snapshot, the server's own page — its ids, order and total — is\n * the skeleton, and the local rows fill it in: rows deleted locally drop\n * out, rows edited locally show the edit, and rows *created* locally join\n * the first page if they match. Without one, the query is evaluated\n * outright over every cached row, which is the best that can be done for a\n * query the server has never answered here.\n */\n private answer<M extends AnyRow>(\n slug: string,\n params: FindParams | undefined,\n snapshot: QuerySnapshot | undefined\n ): LiveResult<M> {\n const state = this.collections.get(slug);\n const exact = isExactlyEvaluable(params);\n const fromCache = !state?.fresh.has(buildQueryString(params));\n if (!state) {\n return {\n data: [],\n meta: { ...resolvePagination(params), total: 0, hasMore: false },\n fromCache: true,\n hasPendingWrites: false,\n partial: true\n };\n }\n\n if (!snapshot) {\n const local = runLocalQuery<M>([...state.rows.values()].map((e) => e.row) as M[], params);\n return {\n ...local,\n fromCache,\n hasPendingWrites: local.data.some((row) => this.hasPending(slug, row.id as string | number)),\n partial: true\n };\n }\n if (snapshot.rows) return this.projectedAnswer<M>(slug, params, snapshot, snapshot.rows, fromCache);\n\n const rows: M[] = [];\n const seen = new Set<string>();\n /** Rows the server counted that we know are no longer in the result. */\n let removed = 0;\n for (const id of snapshot.ids) {\n const key = String(id);\n const entry = state.rows.get(key);\n if (!entry) {\n // Gone for a reason (deleted here, or confirmed gone by the\n // server) versus merely evicted to stay under the cache cap:\n // only the former should move the total the server gave us.\n if (state.absent.has(key) || this.hasPending(slug, key)) removed++;\n continue;\n }\n // A local edit that moves a row out of its own filter should take\n // it off the list, exactly as a refetch would.\n if (exact && this.hasPending(slug, key) && !matchesParams(entry.row, params)) {\n removed++;\n continue;\n }\n rows.push(entry.row as M);\n seen.add(key);\n }\n\n // Rows the server has never seen belong on the first page of a\n // matching query. Injecting them into *every* page would show the same\n // new row once per page.\n let added = 0;\n const offset = snapshot.offset ?? 0;\n if (exact && offset === 0) {\n for (const [key, entry] of state.rows) {\n if (seen.has(key) || !this.hasPending(slug, key)) continue;\n if (!this.isLocallyCreated(slug, key) && !this.movedIntoFilter(slug, key, params)) continue;\n if (!matchesParams(entry.row, params)) continue;\n rows.push(entry.row as M);\n added++;\n }\n }\n\n // Order is part of the query, not a detail of how the rows were\n // obtained. This used to sort only when a locally-created row had been\n // injected — every other read handed back cache order, which is\n // insertion order, and a caller that asked for `orderBy` got whatever\n // the store happened to hold. In the admin that is the collection's\n // `sort` being silently ignored on every list backed by this overlay:\n // the query carries it, the server honours it, and the answer served\n // from here did not.\n //\n // …but only when the local sort would land where the server's did.\n // `snapshot.ids` already arrived in the server's order, so re-sorting a\n // text column with `Intl.Collator` *replaces* a correct order with a\n // possibly different one — under the C collation Postgres puts\n // `Banana` before `apple` and the collator does not. When the column\n // cannot be ordered locally the snapshot's order is the better answer,\n // and the result says so rather than presenting it as the sorted page\n // that was asked for.\n const orderIsLocal = isLocallySortable(rows, params?.orderBy);\n const sorted = Boolean(params?.orderBy && orderIsLocal);\n if (sorted) sortRows(rows, params!.orderBy!);\n\n const total = Math.max(rows.length, snapshot.total - removed + added);\n const page = fitToLimit(rows, snapshot.limit, added, sorted);\n return {\n data: page,\n meta: {\n total,\n limit: snapshot.limit,\n offset,\n hasMore: snapshot.hasMore || page.length < rows.length\n },\n fromCache,\n hasPendingWrites: rows.some((row) => this.hasPending(slug, row.id as string | number)),\n // Not the page that was asked for if either the membership\n // decision or the order could not be reproduced here.\n partial: !exact || !orderIsLocal\n };\n }\n\n /**\n * Answer a projected query (`fields`, `distinct`) from the server's own\n * answer to it.\n *\n * The server's rows are the answer. The local database contributes only\n * what it knows better: a row with unsynced writes shows them, narrowed to\n * the columns the server sent, or drops out if it was deleted here or\n * edited out of a filter this side can evaluate; and rows created here\n * join the first page when there is somewhere to put them. A distinct\n * query, or an order on a column the projection does not carry, leaves\n * them out, and the result says it is partial.\n */\n private projectedAnswer<M extends AnyRow>(\n slug: string,\n params: FindParams | undefined,\n snapshot: QuerySnapshot,\n served: AnyRow[],\n fromCache: boolean\n ): LiveResult<M> {\n const state = this.collectionState(slug);\n const exact = isExactlyEvaluable(params);\n const rows: AnyRow[] = [];\n const seen = new Set<string>();\n let removed = 0;\n for (const row of served) {\n const key = row.id === undefined || row.id === null ? undefined : String(row.id);\n if (key !== undefined) seen.add(key);\n if (key === undefined || !this.hasPending(slug, key)) {\n rows.push(row);\n continue;\n }\n const local = state.rows.get(key)?.row;\n if (!local || (exact && !matchesParams(local, params))) {\n removed++;\n continue;\n }\n rows.push(pick(local, Object.keys(row)));\n }\n\n let added = 0;\n let unplaced = false;\n const offset = snapshot.offset ?? 0;\n if (exact && offset === 0) {\n const shape = served.length > 0 ? Object.keys(served[0]) : [\"id\", ...(params?.fields ?? [])];\n const placeable = !params?.distinct\n && (normalizeOrderBy(params?.orderBy) ?? []).every(([field]) => shape.includes(field));\n for (const [key, entry] of state.rows) {\n if (seen.has(key) || !this.hasPending(slug, key)) continue;\n if (!this.isLocallyCreated(slug, key) && !this.movedIntoFilter(slug, key, params)) continue;\n if (!matchesParams(entry.row, params)) continue;\n if (!placeable) {\n unplaced = true;\n continue;\n }\n rows.push(pick(entry.row, shape));\n added++;\n }\n }\n const orderIsLocal = added === 0 || isLocallySortable(rows, params?.orderBy);\n const sorted = Boolean(added > 0 && params?.orderBy && orderIsLocal);\n if (sorted) sortRows(rows, params!.orderBy!);\n const page = fitToLimit(rows, snapshot.limit, added, sorted);\n\n return {\n data: page as M[],\n meta: {\n total: Math.max(rows.length, snapshot.total - removed + added),\n limit: snapshot.limit,\n offset,\n hasMore: snapshot.hasMore || page.length < rows.length\n },\n fromCache,\n hasPendingWrites: rows.some((row) => row.id !== undefined && row.id !== null\n && this.hasPending(slug, row.id as string | number)),\n partial: !exact || !orderIsLocal || unplaced\n };\n }\n\n private localFind<M extends AnyRow>(slug: string, params?: FindParams): LiveResult<M> {\n const state = this.collections.get(slug);\n const snapshot = this.snapshotFor(slug, params);\n // However recent it looks, this answer did not come from the server.\n state?.fresh.delete(buildQueryString(params));\n if (!snapshot && (!state || state.rows.size === 0)) {\n throw offlineError(`Offline: no cached data for \"${slug}\".`);\n }\n const answer = this.answer<M>(slug, params, snapshot);\n return snapshot ? answer : { ...answer, partial: true };\n }\n\n /**\n * A temporary id of the type this collection's ids actually have.\n *\n * There is no schema here to read it off — the generated `Database` types\n * are erased at compile time, and the whole point of this path is that the\n * server is unreachable. So it is read off the rows the local database\n * already holds: a collection whose cached ids are numbers gets a negative\n * number, and everything else gets a UUID.\n *\n * A collection with nothing cached falls back to a UUID, which is the same\n * guess as before — but that is a first write on a device that has never\n * read the collection, which is also the case where nothing local can tell\n * the difference. Reading one row first is enough to fix it.\n */\n private mintOfflineId(slug: string): string | number {\n for (const entry of this.collections.get(slug)?.rows.values() ?? []) {\n const id = (entry.row as AnyRow).id;\n if (typeof id === \"number\") return generateOfflineNumericId();\n if (typeof id === \"string\") break;\n }\n return generateOfflineStringId();\n }\n\n /**\n * Keep the version a server row came with, or forget the one held when it\n * came with none: a row from a list carries no version, and may be newer\n * than the one held. Only with `onConflict`, the one reader of it.\n */\n private noteETag(state: CollectionState, key: string, row: AnyRow): void {\n if (!this.onConflict) return;\n const etag = etagOf(row);\n if (etag) (state.etags ??= new Map()).set(key, etag);\n else state.etags?.delete(key);\n }\n\n private etagFor(slug: string, id: string | number): string | undefined {\n return this.collections.get(slug)?.etags?.get(String(id));\n }\n\n private rawLocalRow(slug: string, id: string | number): AnyRow | undefined {\n const entry = this.collections.get(slug)?.rows.get(String(id));\n return entry ? { ...entry.row } : undefined;\n }\n\n private localRow<M extends AnyRow>(slug: string, id: string | number): M | undefined {\n return this.collections.get(slug)?.rows.get(String(id))?.row as M | undefined;\n }\n\n // ─── Writing the local database ──────────────────────────────────────────\n\n private setLocalRow(slug: string, id: string | number, row: AnyRow, ticket: ScopeTicket): void {\n if (!this.isCurrent(ticket)) return;\n const state = this.collectionState(slug);\n const key = String(id);\n const cachedAt = Date.now();\n state.rows.set(key, { row: { ...row }, cachedAt, rev: ++this.revCounter });\n state.freshRows.delete(key);\n this.forgetTombstone(slug, key);\n void this.writeCache(this.rowKey(slug, key), dehydrateRow(row), cachedAt);\n this.evictRows(slug);\n }\n\n /**\n * Drop a row and, when the server is the one saying it is gone, remember\n * that. \"I looked it up and it does not exist\" is real knowledge: without\n * it, opening a deleted row while offline would report a missing local\n * database instead of a missing row.\n */\n private removeLocalRow(slug: string, id: string | number, ticket: ScopeTicket, known = false): void {\n if (!this.isCurrent(ticket)) return;\n const state = this.collectionState(slug);\n const key = String(id);\n const existed = state.rows.delete(key);\n state.etags?.delete(key);\n if (known) {\n state.absent.add(key);\n state.freshRows.add(key);\n void this.writeCache(this.absentKey(slug, key), true);\n this.capTombstones(slug);\n } else {\n state.freshRows.delete(key);\n }\n if (existed) void this.deleteCache([this.rowKey(slug, key)]);\n }\n\n private forgetTombstone(slug: string, key: string): void {\n const state = this.collectionState(slug);\n if (!state.absent.delete(key)) return;\n void this.deleteCache([this.absentKey(slug, key)]);\n }\n\n /**\n * Merge server rows into the local database. A row with unsynced local\n * writes keeps them: the server's copy is the base the queued mutations\n * are re-applied to, not a replacement for what the user did.\n *\n * Rows that came back unchanged keep their identity and revision, so a\n * refetch that changed nothing does not re-render every live query that\n * touches them — or rewrite them all to disk.\n *\n * A `projection` (see {@link isProjection}) only refreshes the columns it\n * carries on rows already held, and never creates one. It is not a row:\n * stored as one, it replaced the full row every other query reads and\n * wrote the narrowed copy to disk, so a list lost its columns because a\n * dropdown elsewhere asked for titles.\n */\n private async ingest(slug: string, rows: AnyRow[], ticket: ScopeTicket, projection = false): Promise<void> {\n if (rows.length === 0 || !this.isCurrent(ticket)) return;\n const state = await this.ensureCollection(slug);\n if (!this.isCurrent(ticket)) return;\n const cachedAt = Date.now();\n const writes: { key: string; entry: { value: unknown; cachedAt: number } }[] = [];\n const deletes: string[] = [];\n for (const raw of rows) {\n if (!raw || raw.id === undefined || raw.id === null) continue;\n const key = String(raw.id);\n this.noteETag(state, key, raw);\n const existing = state.rows.get(key);\n if (projection && !existing) continue;\n const base = projection && existing ? { ...existing.row, ...raw } : { ...raw };\n const merged = this.hasPending(slug, key)\n ? this.applyPendingToRow(slug, key, base)\n : base;\n if (merged === undefined) {\n // A queued delete says this row is gone; do not resurrect it.\n state.rows.delete(key);\n deletes.push(this.rowKey(slug, key));\n continue;\n }\n this.forgetTombstone(slug, key);\n // Only a whole row is the server's word on the row.\n if (!projection) state.freshRows.add(key);\n if (existing && JSON.stringify(existing.row) === JSON.stringify(merged)) {\n existing.cachedAt = cachedAt;\n continue;\n }\n state.rows.set(key, { row: merged, cachedAt, rev: ++this.revCounter });\n writes.push({ key: this.rowKey(slug, key), entry: { value: dehydrateRow(merged), cachedAt } });\n }\n if (writes.length > 0) void this.store.setCacheMany(writes).catch(() => undefined);\n if (deletes.length > 0) void this.deleteCache(deletes);\n this.evictRows(slug);\n }\n\n /**\n * Fold the queued mutations for one row over a base, newest last.\n * `afterMutationId` skips everything up to and including that mutation,\n * which is how a just-replayed write avoids being applied on top of the\n * server's response to it.\n */\n private applyPendingToRow(\n slug: string,\n idKey: string,\n base: AnyRow | undefined,\n afterMutationId?: string\n ): AnyRow | undefined {\n let row = base;\n let skipping = afterMutationId !== undefined;\n for (const op of this.queue) {\n if (skipping) {\n if (op.mutationId === afterMutationId) skipping = false;\n continue;\n }\n if (op.collection !== slug) continue;\n if (op.type === \"createMany\") {\n const match = (op.data as AnyRow[] | undefined)?.find((r) => String(r.id) === idKey);\n if (match) row = { ...match };\n continue;\n }\n // The bulk verbs name their rows in a list rather than in `id`,\n // and were skipped here — so a server row arriving before the\n // replay (a realtime frame, a refetch) put back what an offline\n // bulk edit had changed, and a row deleted in bulk.\n if (op.type === \"updateMany\") {\n const update = op.updates?.find((u) => String(u.id) === idKey);\n if (update) row = { ...(row ?? {}), ...update.data, id: update.id };\n continue;\n }\n if (op.type === \"deleteMany\") {\n if (op.ids?.some((id) => String(id) === idKey)) row = undefined;\n continue;\n }\n if (op.id === undefined || String(op.id) !== idKey) continue;\n if (op.type === \"create\") row = { ...(op.data as AnyRow) };\n else if (op.type === \"update\") row = { ...(row ?? {}), ...(op.data as AnyRow), id: op.id };\n else if (op.type === \"delete\") row = undefined;\n }\n return row;\n }\n\n private recordSnapshot(\n slug: string,\n params: FindParams | undefined,\n result: FindResult<AnyRow>,\n ticket: ScopeTicket\n ): QuerySnapshot {\n const window = resolvePagination(params);\n const meta = result.meta ?? { total: result.data?.length ?? 0, ...window, hasMore: false };\n const snapshot: QuerySnapshot = {\n ids: (result.data ?? []).map((row) => row.id as string | number).filter((id) => id !== undefined),\n total: meta.total ?? result.data?.length ?? 0,\n limit: meta.limit ?? window.limit,\n offset: meta.offset ?? window.offset,\n hasMore: meta.hasMore ?? false,\n ...(isProjection(params) ? { rows: (result.data ?? []).map((row) => ({ ...row })) } : {})\n };\n if (!this.isCurrent(ticket)) return snapshot;\n const state = this.collectionState(slug);\n const key = buildQueryString(params);\n state.snapshots.set(key, snapshot);\n state.fresh.add(key);\n void this.writeCache(\n `${this.scope}|q|${slug}|${key}`,\n snapshot.rows ? { ...snapshot, rows: snapshot.rows.map((row) => dehydrateRow(row)) } : snapshot\n );\n this.evictSnapshots(slug);\n return snapshot;\n }\n\n /**\n * A write changed which rows belong in a list, and only the server can say\n * how — a row it generated is in no cached page, and the totals moved.\n * Re-run every live query on the collection; queries nobody is watching\n * are corrected by their next `find`.\n *\n * Coalesced per microtask so a burst of writes costs one round trip, and\n * skipped entirely while offline, where the local database is already the\n * best answer available.\n */\n private scheduleRefresh(slug: string): void {\n if (this.refreshPending.has(slug)) return;\n const observers = this.observers.get(slug);\n if (!observers || observers.size === 0) return;\n this.refreshPending.add(slug);\n void Promise.resolve().then(() => {\n this.refreshPending.delete(slug);\n if (this.disposed || !this.connectivity.shouldAttempt()) return;\n for (const observer of [...(this.observers.get(slug) ?? [])]) void observer.refresh();\n });\n }\n\n private evictRows(slug: string): void {\n const state = this.collections.get(slug);\n if (!state || state.rows.size <= this.maxCachedRows) return;\n const evictable = [...state.rows.entries()]\n .filter(([key]) => !this.hasPending(slug, key))\n .sort((a, b) => a[1].cachedAt - b[1].cachedAt);\n const excess = state.rows.size - this.maxCachedRows;\n const doomed = evictable.slice(0, excess);\n for (const [key] of doomed) {\n state.rows.delete(key);\n state.etags?.delete(key);\n }\n if (doomed.length > 0) void this.deleteCache(doomed.map(([key]) => this.rowKey(slug, key)));\n }\n\n /**\n * Tombstones are tiny but unbounded — every row the app ever asked for and\n * did not find leaves one. Capped against the row budget, oldest first,\n * whenever one is added: the cap used to sit behind the row cache's own\n * early return, so it only applied once the rows were over theirs, and\n * looking up missing ids grew the set without limit.\n */\n private capTombstones(slug: string): void {\n const state = this.collections.get(slug);\n if (!state || state.absent.size <= this.maxCachedRows) return;\n const stale = [...state.absent].slice(0, state.absent.size - this.maxCachedRows);\n for (const key of stale) state.absent.delete(key);\n void this.deleteCache(stale.map((key) => this.absentKey(slug, key)));\n }\n\n private evictSnapshots(slug: string): void {\n const state = this.collections.get(slug);\n if (!state || state.snapshots.size <= this.maxCachedQueries) return;\n // Insertion order is recency order for a Map that re-sets on write.\n const excess = state.snapshots.size - this.maxCachedQueries;\n const doomed = [...state.snapshots.keys()].slice(0, excess);\n for (const key of doomed) {\n state.snapshots.delete(key);\n state.fresh.delete(key);\n }\n void this.deleteCache(doomed.map((key) => `${this.scope}|q|${slug}|${key}`));\n }\n\n // ─── Queue ───────────────────────────────────────────────────────────────\n\n private ensureQueueLoaded(): Promise<void> {\n if (this.scopeHold) return this.scopeKnown().then(() => this.ensureQueueLoaded());\n if (!this.queueLoad) {\n const scope = this.scope;\n this.queueLoad = this.readQueue(`${scope}|`).then((queue) => {\n // A scope switch during the load must not graft the old\n // user's queue onto the new one.\n if (this.scope !== scope) return;\n this.queue = queue;\n this.patchStatus({ pending: queue.length });\n this.notifyQueue();\n }).catch(() => undefined);\n }\n return this.queueLoad;\n }\n\n private enqueue(mutation: Omit<PendingMutation, \"mutationId\" | \"queuedAt\">, ticket: ScopeTicket): Promise<void> {\n const result = this.enqueueChain.then(async () => {\n await this.ensureQueueLoaded();\n\n // Made by a user who has since signed out. It is still their\n // write, so it is kept under their scope — it replays when they\n // are back — but it must not join the queue that now replays\n // under someone else's credentials.\n if (!this.isCurrent(ticket)) {\n const orphan: PendingMutation = {\n ...mutation,\n mutationId: createMutationId(),\n queuedAt: Date.now(),\n schemaVersion: QUEUE_SCHEMA_VERSION\n };\n await this.persistMutation(`${ticket.scope}|${orphan.mutationId}`, orphan);\n return;\n }\n\n // Tail coalescing: repeated edits to the most recently written row\n // (typing in a form) collapse into the queued op instead of\n // growing the queue. Only the queue *tail* may absorb an update —\n // merging into an earlier op would move this write across ops\n // queued after it, silently reordering what the app did.\n if (mutation.type === \"update\") {\n const tail = this.queue[this.queue.length - 1];\n if (tail\n && !this.inFlight.has(tail.mutationId)\n // Not into a create already sent: if that one committed,\n // its replay is answered from the server's record of the\n // first request, which an edit merged in here predates —\n // so the edit stays a write of its own.\n && tail.sent === undefined\n // Nor into an entry a newer version wrote: this one cannot\n // vouch for what it would be merging into.\n && (tail.schemaVersion ?? 1) <= QUEUE_SCHEMA_VERSION\n && tail.collection === mutation.collection\n && (tail.type === \"create\" || tail.type === \"update\")\n && tail.id === mutation.id) {\n // The id must survive the merge: a queued create carries\n // the client-generated id inside its data. The rollback\n // stays the tail's — the state before the *first* of the\n // merged writes, which is what undoing them all restores.\n //\n // An update also remembers the edits it is made of, so a\n // refusal of one of them is not a refusal of all (see\n // `splitCoalesced`).\n if (tail.type === \"update\") {\n tail.parts = [...(tail.parts ?? [{ ...(tail.data as AnyRow) }]), { ...(mutation.data as AnyRow) }];\n }\n tail.data = { ...(tail.data as AnyRow), ...(mutation.data as AnyRow), id: tail.id };\n await this.persistMutation(this.queueKey(tail), tail);\n return;\n }\n }\n\n // Cancel-out: deleting a row whose create is still queued — and\n // whose id the SDK generated, so the server cannot already have a\n // row under it — means the server never saw the row. Remove every\n // queued op for it and queue nothing. Creates with caller-supplied\n // ids do NOT cancel (the id may name an existing server row, which\n // the delete must still remove), and neither do rows queued inside\n // a createMany (the bulk op replays first, then the delete).\n if (mutation.type === \"delete\") {\n // An in-flight create disqualifies the shortcut entirely: the\n // server is being told about the row as we speak, so \"it never\n // saw it\" is false and the delete has to replay after it.\n // A create already sent once disqualifies it the same way: it\n // may have reached the server before the connection failed.\n const hasPendingCreate = this.queue.some((m) =>\n m.collection === mutation.collection && m.type === \"create\"\n && m.id === mutation.id && m.generatedId === true\n && m.sent === undefined\n && !this.inFlight.has(m.mutationId));\n if (hasPendingCreate) {\n const doomed = this.queue.filter((m) =>\n m.collection === mutation.collection\n && m.id === mutation.id\n && (m.type === \"create\" || m.type === \"update\")\n && !this.inFlight.has(m.mutationId));\n for (const op of doomed) await this.store.dequeue(this.queueKey(op));\n this.queue = this.queue.filter((m) => !doomed.includes(m));\n this.afterQueueChange();\n return;\n }\n }\n\n const full: PendingMutation = {\n ...mutation,\n mutationId: createMutationId(),\n queuedAt: Date.now(),\n schemaVersion: QUEUE_SCHEMA_VERSION\n };\n await this.persistMutation(this.queueKey(full), full);\n this.queue.push(full);\n this.queueChangedInPlace();\n this.afterQueueChange();\n this.requestPersistence();\n });\n // The chain must survive a failed enqueue, or every later write dies\n // on the same stale rejection.\n this.enqueueChain = result.catch(() => undefined);\n return result;\n }\n\n /**\n * Ask the browser to keep the offline database, once, when there is first\n * something in it worth keeping. Without it IndexedDB is best-effort\n * storage, evicted under pressure (and by Safari after seven days without\n * a visit) with the unsent writes in it.\n */\n private requestPersistence(): void {\n if (this.persistenceRequested || !(this.store instanceof IndexedDBOfflineStore)) return;\n this.persistenceRequested = true;\n const storage = (globalThis as { navigator?: { storage?: { persist?: () => Promise<boolean> } } }).navigator?.storage;\n if (typeof storage?.persist !== \"function\") return;\n storage.persist().then((persisted) => this.patchStatus({ persisted }), () => undefined);\n }\n\n /** The queue's row ids for one collection — see {@link pendingIndex}. */\n private pendingIds(slug: string): PendingIds | undefined {\n if (!this.pendingIndex) {\n const index = new Map<string, PendingIds>();\n const note = (entry: PendingIds, key: string, op: PendingMutation) => {\n entry.writes.add(key);\n if (!entry.first.has(key)) entry.first.set(key, op);\n };\n for (const op of this.queue) {\n let entry = index.get(op.collection);\n if (!entry) index.set(op.collection, entry = { writes: new Set(), creates: new Set(), first: new Map() });\n if (op.type === \"createMany\") {\n for (const row of (op.data as AnyRow[] | undefined) ?? []) {\n note(entry, String(row.id), op);\n entry.creates.add(String(row.id));\n }\n } else if (op.type === \"updateMany\") {\n for (const update of op.updates ?? []) note(entry, String(update.id), op);\n } else if (op.type === \"deleteMany\") {\n for (const id of op.ids ?? []) note(entry, String(id), op);\n } else if (op.id !== undefined) {\n note(entry, String(op.id), op);\n if (op.type === \"create\") entry.creates.add(String(op.id));\n }\n }\n this.pendingIndex = index;\n }\n return this.pendingIndex.get(slug);\n }\n\n /**\n * Did the queued writes to this row bring it into the query's filter? The\n * row as it was before the first of them is that write's rollback; one\n * that did not match then is in no server page of the query, so only\n * this side can put it on screen.\n */\n private movedIntoFilter(slug: string, idKey: string, params: FindParams | undefined): boolean {\n const before = this.pendingIds(slug)?.first.get(idKey)?.rollback?.rows?.[idKey];\n return before !== undefined && before !== null && !matchesParams(before, params);\n }\n\n /** The queue's entries were changed without replacing the array. */\n private queueChangedInPlace(): void {\n this.pendingIndex = undefined;\n }\n\n private hasPending(slug: string, id: string | number): boolean {\n return this.pendingIds(slug)?.writes.has(String(id)) ?? false;\n }\n\n /** Is this row one the server has never been told about? */\n private isLocallyCreated(slug: string, idKey: string): boolean {\n return this.pendingIds(slug)?.creates.has(idKey) ?? false;\n }\n\n /** How many rows the queue adds to (or removes from) a server-side count. */\n private pendingDelta(slug: string, params?: FindParams): number {\n if (!isExactlyEvaluable(params)) return 0;\n // Each write moves the count by whether its row matched before it\n // and after it. \"Before\" is the row the write's rollback keeps; a row\n // that was not cached when it was written is unknown, and moves\n // nothing rather than a guess.\n const counts = (row: AnyRow | null | undefined) => (row && matchesParams(row, params) ? 1 : 0);\n const before = (op: PendingMutation, id: string | number | undefined) =>\n id === undefined ? undefined : op.rollback?.rows?.[String(id)];\n let delta = 0;\n for (const op of this.queue) {\n if (op.collection !== slug) continue;\n if (op.type === \"create\" || op.type === \"createMany\") {\n const rows = op.type === \"create\" ? [op.data as AnyRow] : (op.data as AnyRow[] | undefined) ?? [];\n // A create over a row this device already held (a\n // caller-supplied id) replaces it rather than adding one.\n for (const row of rows) delta += counts(row) - counts(before(op, row?.id as string | number | undefined));\n } else if (op.type === \"update\") {\n const was = before(op, op.id);\n if (was) delta += counts({ ...was, ...(op.data as AnyRow) }) - counts(was);\n } else if (op.type === \"updateMany\") {\n for (const update of op.updates ?? []) {\n const was = before(op, update.id);\n if (was) delta += counts({ ...was, ...update.data }) - counts(was);\n }\n } else if (op.type === \"delete\") {\n delta -= counts(before(op, op.id));\n } else if (op.type === \"deleteMany\") {\n for (const id of op.ids ?? []) delta -= counts(before(op, id));\n }\n }\n return delta;\n }\n\n // ─── Replay ──────────────────────────────────────────────────────────────\n\n sync(): Promise<{ flushed: number; remaining: number }> {\n if (this.flushPromise) return this.flushPromise;\n // The lock is per user, so it is taken once the user is known.\n const run = () => this.withLock(() => this.flush());\n this.flushPromise = (this.scopeHold ? this.scopeKnown().then(run) : run())\n .finally(() => { this.flushPromise = undefined; });\n return this.flushPromise;\n }\n\n private async flush(): Promise<{ flushed: number; remaining: number }> {\n const ticket = this.ticket() ?? await this.nextTicket();\n await this.ensureQueueLoaded();\n // Another tab may have queued or drained work since we last looked.\n await this.reloadQueue();\n if (this.queue.length === 0) return { flushed: 0, remaining: 0 };\n // A user taken without a session: nobody's credentials are theirs to\n // replay under yet. See `keepLastUser`.\n if (this.unverified) return { flushed: 0, remaining: this.queue.length };\n // No `shouldAttempt` guard: every caller of `sync` — the app, the\n // retry timer, an `online` event, a sign-in — is asking for a real\n // attempt, and its outcome is what reopens the connection.\n\n this.patchStatus({ syncing: true });\n const touched = new Set<string>();\n const queuedAtStart = this.queue.length;\n let flushed = 0;\n // Creates a folded replay was refused or deferred for: from then on,\n // in this drain, they go one at a time — see `replayBatchSize`.\n const unbatched = new Set<string>();\n try {\n // Stops at a change of user: the queue in memory is theirs now.\n while (this.queue.length > 0 && !this.disposed && this.isCurrent(ticket)) {\n const op = this.queue[0];\n // Written by a newer version of the SDK, in a layout this one\n // may misread. It waits — with everything behind it, which may\n // depend on it — for a client that can replay it.\n if ((op.schemaVersion ?? 1) > QUEUE_SCHEMA_VERSION) {\n this.patchStatus({\n lastError: `A queued write was saved by a newer version of the SDK (layout ${String(op.schemaVersion)}); ` +\n \"it is kept, and replays once this page runs that version.\"\n });\n break;\n }\n touched.add(op.collection);\n const run = this.foldableRun(unbatched);\n if (run.length > 1) {\n const outcome = await this.replayRun(run, ticket);\n if (outcome === \"offline\") break;\n if (outcome === \"unbatch\") {\n for (const member of run) unbatched.add(member.mutationId);\n continue;\n }\n flushed += run.length;\n continue;\n }\n // Held across `drop` as well as `replay`: between the ACK and\n // the dequeue the op is still in `queue`, still the tail, and\n // still about to be removed — coalescing into it there loses\n // the write exactly as coalescing during the request does.\n this.inFlight.add(op.mutationId);\n try {\n try {\n await this.replay(op, ticket);\n } catch (error) {\n if (isNetworkError(error)) {\n // Still offline — keep the op and everything behind it.\n this.connectivity.markFailure();\n break;\n }\n // The row moved on since the edit was made. Not a\n // failure of the write: the app decides.\n if (op.type === \"update\" && op.ifMatch && isPreconditionFailed(error)) {\n this.connectivity.markSuccess();\n await this.resolveConflict(op, error, ticket);\n continue;\n }\n op.attempts = (op.attempts ?? 0) + 1;\n op.lastError = (error as Error)?.message ?? String(error);\n // A key the server is still holding gets a longer\n // budget than a busy server does. The claim outlives\n // the request that took it — the process was killed\n // between the write and its answer — so it is refused\n // until the claim's lease runs out, which is longer\n // than the default five retries reach. Giving up on\n // that schedule rolls back precisely the write the key\n // exists to save.\n const limit = isIdempotencyInProgressError(error)\n ? Math.max(this.maxRetries, IN_PROGRESS_MIN_RETRIES)\n : this.maxRetries;\n if (isRetryableError(error) && op.attempts < limit) {\n // The server is busy, not unhappy. Keep the op — and\n // its place in line, since later writes may depend on\n // it — and come back after a backoff.\n await this.persistMutation(`${ticket.scope}|${op.mutationId}`, op).catch(() => undefined);\n this.connectivity.deferRetry();\n this.patchStatus({ lastError: op.lastError });\n break;\n }\n // A delete of a row that is already gone did what it\n // was for. Rolling it back put a row the server no\n // longer has back on screen, and reported the opposite\n // of what happened.\n if (op.type === \"delete\" && isNotFoundError(error)) {\n this.connectivity.markSuccess();\n this.removeLocalRow(op.collection, op.id!, ticket, true);\n await this.drop(op, ticket);\n flushed++;\n continue;\n }\n // Several edits merged into one request, refused as a\n // whole: maybe over just one of them. Split it back,\n // and let each edit stand or fall on its own.\n if (isFieldRefusal(error) && (op.parts?.length ?? 0) > 1) {\n await this.splitCoalesced(op, ticket);\n continue;\n }\n await this.rejectMutation(op, error as Error, ticket);\n continue;\n }\n this.connectivity.markSuccess();\n // Acknowledged, so it leaves the queue of the user who\n // made it — even if that is no longer the signed-in one.\n await this.drop(op, ticket);\n flushed++;\n } finally {\n this.inFlight.delete(op.mutationId);\n }\n }\n } finally {\n this.patchStatus({ syncing: false });\n }\n\n // The user changed mid-drain. What there was to clean up for theirs\n // is done; nothing on screen is theirs any more.\n if (!this.isCurrent(ticket)) return { flushed, remaining: this.queue.length };\n\n if (this.queue.length !== queuedAtStart) {\n for (const slug of touched) {\n this.notifyCollection(slug);\n // The server has now seen these writes, and its page\n // composition and totals moved with them.\n this.scheduleRefresh(slug);\n }\n // One message for the whole drain — including a drain that only\n // rolled writes back, which other tabs need to hear about just as\n // much as one that succeeded.\n this.broadcast({ type: \"queue\" });\n }\n if (this.queue.length === 0) this.patchStatus({ lastSyncedAt: Date.now() });\n return { flushed, remaining: this.queue.length };\n }\n\n /**\n * The creates at the head of the queue that may replay as one request —\n * see {@link OfflineConfig.replayBatchSize}. Fewer than two means the head\n * replays on its own.\n *\n * Consecutive, so the queue's order holds; one collection, since a bulk\n * write is one collection's. Each is a create never sent (so its request\n * is still its own to choose) with an id the SDK minted as a string — a\n * lost answer then cannot duplicate it, because the server refuses that\n * id the second time and the single replay recognises the row as its\n * own. A create whose values name another member's minted id waits: the\n * server may give that row a different id, which only a replay one at a\n * time can carry over.\n */\n private foldableRun(unbatched: ReadonlySet<string>): PendingMutation[] {\n if (this.replayBatchSize < 2) return [];\n const foldable = (op: PendingMutation | undefined, collection?: string): op is PendingMutation =>\n op !== undefined\n && op.type === \"create\"\n && op.generatedId === true\n && typeof op.id === \"string\"\n && op.sent === undefined\n && !op.upsert\n && (op.schemaVersion ?? 1) <= QUEUE_SCHEMA_VERSION\n && !unbatched.has(op.mutationId)\n && (collection === undefined || op.collection === collection);\n const head = this.queue[0];\n if (!foldable(head)) return [];\n const run = [head];\n for (let i = 1; i < this.queue.length && run.length < this.replayBatchSize; i++) {\n const next = this.queue[i];\n if (!foldable(next, head.collection)) break;\n if (run.some((member) => mentionsMintedId(next, member.id!))) break;\n run.push(next);\n }\n return run;\n }\n\n /**\n * Replay a {@link foldableRun} as one `createMany`.\n *\n * - `\"done\"`: every member is acknowledged, adopted and dropped.\n * - `\"offline\"`: the connection failed; the members stay queued, as one\n * write would.\n * - `\"unbatch\"`: anything else — a refusal, a busy server. Nothing was\n * written (a bulk write is one transaction), and the caller replays the\n * members one at a time, where each refusal, retry budget and recovery\n * applies to its own write.\n *\n * The key names the run by its first and last member and its length,\n * which fixes its composition: a run re-sent after a lost answer is the\n * same request under the same key, and is answered from the server's\n * record of it.\n */\n private async replayRun(run: PendingMutation[], ticket: ScopeTicket): Promise<\"done\" | \"offline\" | \"unbatch\"> {\n const inner = this.innerFor(run[0].collection);\n const idempotencyKey = `${run[0].mutationId}..${run[run.length - 1].mutationId}:${run.length}`;\n for (const member of run) this.inFlight.add(member.mutationId);\n try {\n let rows: AnyRow[];\n try {\n rows = await inner.createMany(run.map((member) => member.data as AnyRow), { idempotencyKey });\n } catch (error) {\n if (!isNetworkError(error)) return \"unbatch\";\n this.connectivity.markFailure();\n return \"offline\";\n }\n this.connectivity.markSuccess();\n for (let i = 0; i < run.length; i++) {\n await this.adoptServerRow(run[i], run[i].id, rows[i], ticket);\n await this.drop(run[i], ticket);\n }\n return \"done\";\n } finally {\n for (const member of run) this.inFlight.delete(member.mutationId);\n }\n }\n\n private async replay(op: PendingMutation, ticket: ScopeTicket): Promise<void> {\n const inner = this.innerFor(op.collection);\n if (op.type === \"create\") {\n // The queued row already carries its (client-generated) id.\n let row: AnyRow | undefined;\n try {\n // The mutation id names this write, so a server that stores keys\n // recognises a replay instead of inserting a second row. This is\n // the only defence for a table with a server-assigned id: the id\n // the client chose was never used, so a duplicate is invisible\n // from here. Ignored by servers that do not support it.\n row = await this.sendQueuedWrite(\n op,\n (idempotencyKey) => inner.create(op.data as AnyRow, undefined, { idempotencyKey }),\n (sent) => inner.create(sent.data as AnyRow, sent.id, { idempotencyKey: sent.idempotencyKey })\n );\n } catch (error) {\n // A lost response, not a rejection. The request reached the\n // server and committed; only the ACK went missing, so the\n // replay finds the row already there.\n //\n // Restricted to ids the SDK minted: a fresh uuid cannot name a\n // row anyone else created, so a duplicate under it is\n // necessarily this mutation's own first attempt. A\n // caller-supplied id carries no such guarantee — it may well\n // collide with a row that was already there, which is a real\n // conflict the caller has to hear about.\n //\n // Without this, `rejectMutation` rolled the write back and\n // DELETED the local row — the one case where the row does exist\n // on the server. The user watched their own saved record vanish.\n if (!(op.generatedId === true && isDuplicateKeyError(error))) throw error;\n // Only a row that reads back under our id proves the 409 was\n // our own first attempt. A 409 says nothing more than \"a\n // unique constraint refused this\": another row holding the\n // same email answers exactly the same way. The read used to\n // be trusted when it failed too (`.catch(() => undefined)` and\n // return) — so a refused create was dropped from the queue as\n // synced, `onSyncError` never fired, and the record the user\n // saw saved existed nowhere.\n //\n // A read that fails is thrown on: a network error keeps the\n // write queued, anything else is judged like any other\n // failure. A read that finds nothing means the conflict was\n // with some other row, and the original refusal is the answer.\n row = await inner.findById(op.id!) as AnyRow | undefined;\n if (!row) throw error;\n }\n await this.adoptServerRow(op, op.id, row, ticket);\n } else if (op.type === \"createMany\") {\n const queued = (op.data as AnyRow[]) ?? [];\n // The mutation id names this batch, exactly as it names a single\n // `create` above — and it matters more here. Without it, a batch\n // whose ACK went missing replays as a second genuine import and\n // duplicates every row it holds, not one. `upsert` masked that for\n // the callers who set it; nothing covered the ones who did not.\n const asSent = (sent: NonNullable<PendingMutation[\"sent\"]>) => inner.createMany(sent.data as AnyRow[], {\n ...(op.upsert ? { upsert: true } : {}),\n ...(sent.onConflict?.length ? { onConflict: sent.onConflict } : {}),\n idempotencyKey: sent.idempotencyKey\n });\n // A natural-key upsert is only ever the request already sent: the\n // ids minted here must not reach a statement that decides for\n // itself which row each one lands on.\n const rows = op.sent?.onConflict?.length\n ? await asSent(op.sent)\n : await this.sendQueuedWrite(\n op,\n (idempotencyKey) => inner.createMany(queued, {\n ...(op.upsert ? { upsert: true } : {}),\n idempotencyKey\n }),\n asSent\n );\n for (let i = 0; i < rows.length; i++) {\n await this.adoptServerRow(op, queued[i]?.id as string | number | undefined, rows[i], ticket);\n }\n } else if (op.type === \"updateMany\") {\n const queued = op.updates ?? [];\n // Keyed like every other replay: an update re-applied in full is\n // naturally idempotent, but one interleaved with another writer's is\n // not, and a lost ACK would otherwise re-apply a stale batch over\n // newer data.\n const rows = await inner.updateMany(\n queued.map(u => ({ id: u.id,\ndata: u.data as AnyRow })),\n { idempotencyKey: op.mutationId }\n );\n for (let i = 0; i < rows.length; i++) {\n await this.ingestReplaced(op, queued[i].id, rows[i], ticket);\n }\n } else if (op.type === \"update\") {\n // Always keyed. An edit only ever queued is given its key here, on\n // its first send, and recorded as sent before the request goes\n // out: from then on its body is frozen (tail coalescing skips an\n // op with `sent`, so a later edit queues as a write of its own),\n // and a replay is the same request under the same key. Sent bare,\n // a replay whose first attempt committed and lost its answer wrote\n // the queued values again — over whatever a colleague had written\n // since.\n if (!op.sent) {\n op.sent = { idempotencyKey: op.mutationId };\n await this.persistMutation(`${ticket.scope}|${op.mutationId}`, op).catch(() => undefined);\n }\n const row = await inner.update(op.id!, op.data as AnyRow, {\n idempotencyKey: op.sent.idempotencyKey,\n ...(op.ifMatch ? { ifMatch: op.ifMatch } : {})\n });\n await this.ingestReplaced(op, op.id!, row, ticket);\n } else if (op.type === \"deleteMany\") {\n const ids = op.ids ?? [];\n try {\n await inner.deleteMany(ids, { idempotencyKey: op.mutationId });\n } catch (error) {\n // The batch is refused whole when one of its rows is already\n // gone — deleted by someone else while this one was queued.\n // That row is as gone as the user wanted it; the rest are\n // deleted one at a time, each under a key of its own, and a\n // row that is gone by then counts as deleted too. Treated as a\n // refusal, every row of the batch was put back.\n if (!isNotFoundError(error)) throw error;\n for (const id of ids) {\n try {\n await inner.delete(id, { idempotencyKey: `${op.mutationId}:${String(id)}` });\n } catch (rowError) {\n if (!isNotFoundError(rowError)) throw rowError;\n }\n }\n }\n for (const id of ids) this.removeLocalRow(op.collection, id, ticket, true);\n } else if (op.type === \"delete\") {\n // A delete's request is its id, which nothing rewrites once it has\n // been sent, so it is always keyed: a replay of one that committed\n // is answered from the key instead of a 404 for the missing row.\n await inner.delete(op.id!, { idempotencyKey: op.sent?.idempotencyKey ?? op.mutationId });\n this.removeLocalRow(op.collection, op.id!, ticket, true);\n }\n }\n\n /**\n * Send a queued write under its key.\n *\n * A write the queue sent once already, before it was queued, carries that\n * attempt's key and is sent under it again, as queued. If the server holds\n * the key for a different request, the difference is the ids minted here\n * — so the first attempt committed and only its answer was lost, and\n * sending that request again returns the stored answer instead of a\n * second copy of the rows.\n */\n private async sendQueuedWrite<T>(\n op: PendingMutation,\n asQueued: (idempotencyKey: string) => Promise<T>,\n asSent: (sent: NonNullable<PendingMutation[\"sent\"]>) => Promise<T>\n ): Promise<T> {\n try {\n return await asQueued(op.sent?.idempotencyKey ?? op.mutationId);\n } catch (error) {\n if (!op.sent || !isIdempotencyKeyReusedError(error)) throw error;\n return asSent(op.sent);\n }\n }\n\n /**\n * Take the server's version of a row the client created offline.\n *\n * The server may have assigned a different id — a serial column ignores\n * the id we invented — in which case every local trace of the temporary id\n * has to move with it, including queued writes that were made against it\n * before it was ever sent.\n */\n private async adoptServerRow(\n op: PendingMutation,\n localId: string | number | undefined,\n row: AnyRow | undefined,\n ticket: ScopeTicket\n ): Promise<void> {\n if (!row) return;\n const slug = op.collection;\n const serverId = row.id as string | number | undefined;\n if (localId !== undefined && serverId !== undefined && String(serverId) !== String(localId)) {\n const oldKey = String(localId);\n this.removeLocalRow(slug, localId, ticket);\n // The writes queued against the temporary id are the queue of the\n // user who made them, which is only the one in memory while they\n // are still signed in.\n const queue = this.isCurrent(ticket)\n ? this.queue\n : await this.readQueue(`${ticket.scope}|`).catch(() => []);\n // A minted id names nothing but this row, so wherever another\n // queued write carries it — a post's `author_id`, in any\n // collection — it is a reference to this row, and has to follow it.\n // The queue is ordered across collections for exactly this case;\n // the id used to be moved only in the row's own collection, so the\n // post replayed pointing at an author that never existed.\n const minted = op.type === \"create\" && op.generatedId === true;\n for (const queued of queue) {\n let dirty = false;\n if (minted && queued !== op) {\n const data = replaceMintedId(queued.data, localId, serverId);\n if (data.changed) {\n queued.data = data.value as PendingMutation[\"data\"];\n dirty = true;\n }\n if (queued.updates) {\n const updates = replaceMintedId(queued.updates.map((u) => u.data), localId, serverId);\n if (updates.changed) {\n const values = updates.value as AnyRow[];\n queued.updates = queued.updates.map((u, i) => ({ id: u.id, data: values[i] }));\n dirty = true;\n }\n }\n }\n if (queued.collection !== slug) {\n if (dirty) await this.persistMutation(`${ticket.scope}|${queued.mutationId}`, queued).catch(() => undefined);\n continue;\n }\n if (queued.id !== undefined && String(queued.id) === oldKey) {\n queued.id = serverId;\n this.queueChangedInPlace();\n if (queued.data && !Array.isArray(queued.data)) {\n (queued.data as AnyRow).id = serverId;\n }\n dirty = true;\n }\n // The rollback map is keyed by row id too, and restoring it\n // under a name the server never had would resurrect a ghost.\n const rollbackRows = queued.rollback?.rows;\n if (rollbackRows && oldKey in rollbackRows) {\n rollbackRows[String(serverId)] = rollbackRows[oldKey];\n delete rollbackRows[oldKey];\n dirty = true;\n }\n if (dirty) await this.persistMutation(`${ticket.scope}|${queued.mutationId}`, queued).catch(() => undefined);\n }\n }\n await this.ingestReplaced(op, serverId ?? localId!, row, ticket);\n }\n\n /**\n * Write a server row over the local one, ignoring the mutation that just\n * produced it — re-applying that would put the pre-server values back on\n * top of the server's answer — but keeping every write queued *after* it.\n * Those are still unsent, and dropping them here would make the row snap\n * back to the server's version in front of the user, only to change again\n * when they replay a moment later.\n */\n private async ingestReplaced(op: PendingMutation, id: string | number, row: AnyRow, ticket: ScopeTicket): Promise<void> {\n if (!this.isCurrent(ticket)) return;\n const slug = op.collection;\n const state = await this.ensureCollection(slug);\n if (!this.isCurrent(ticket)) return;\n const key = String(id);\n this.noteETag(state, key, row);\n const merged = this.applyPendingToRow(slug, key, { ...row }, op.mutationId);\n if (merged === undefined) {\n // A queued delete is still waiting behind this write.\n this.removeLocalRow(slug, key, ticket);\n return;\n }\n const cachedAt = Date.now();\n state.rows.set(key, { row: merged, cachedAt, rev: ++this.revCounter });\n if (this.applyPendingToRow(slug, key, undefined, op.mutationId) === undefined) {\n // Nothing local is left on top of it, so this *is* the server's row.\n state.freshRows.add(key);\n }\n void this.writeCache(this.rowKey(slug, key), dehydrateRow(merged), cachedAt);\n }\n\n /**\n * The server refused a mutation. Put back what it changed, and discard the\n * queued writes that were built on top of it: an edit to a row whose\n * creation was rejected can only fail the same way, and applying it would\n * leave the local database claiming a row the server does not have.\n *\n * The cascade stops the moment a later write stops *depending* on the\n * rejected one. An `update` reads the row it edits, so it is doomed with\n * it; a `create` overwrites the row outright and a `delete` needs nothing\n * of it, so both stand on their own and are kept — dropping them would\n * silently lose writes the server would have accepted.\n */\n private async rejectMutation(op: PendingMutation, error: Error, ticket: ScopeTicket, report = true): Promise<void> {\n // Refused after its user signed out. Rolling back and reporting it\n // would put their write, and its error, in front of whoever is signed\n // in now; it stays in their queue and is refused again, to them, when\n // they are back.\n if (!this.isCurrent(ticket)) return;\n const ids = new Set(Object.keys(op.rollback?.rows ?? {}));\n if (op.id !== undefined) ids.add(String(op.id));\n\n const doomed: PendingMutation[] = [op];\n const orphaned = new Set(ids);\n // Rows created offline that the server will now never have. A write\n // anywhere in the queue that references one — a post whose author's\n // create was refused — can only fail on the reference, or worse, be\n // written pointing at nothing. See `replaceMintedId` for why matching\n // by value is sound for a minted id.\n const neverCreated: (string | number)[] = op.type === \"create\" && op.generatedId === true && op.id !== undefined\n ? [op.id]\n : [];\n const position = this.queue.indexOf(op);\n for (const later of this.queue.slice(position + 1)) {\n if (neverCreated.some((id) => mentionsMintedId(later, id))) {\n doomed.push(later);\n if (later.type === \"create\" && later.generatedId === true && later.id !== undefined) neverCreated.push(later.id);\n continue;\n }\n if (later.collection !== op.collection) continue;\n const hit = this.idsOf(later).filter((id) => orphaned.has(id));\n if (hit.length === 0) continue;\n if (later.type === \"update\") doomed.push(later);\n else for (const id of hit) orphaned.delete(id);\n }\n\n for (const dropped of doomed) await this.drop(dropped, ticket);\n if (!this.isCurrent(ticket)) return;\n\n // A write discarded for its reference was applied to rows of its own,\n // possibly in another collection; put those back as well.\n const touched = new Set([op.collection]);\n for (const dropped of doomed) {\n if (dropped === op || !neverCreated.length || dropped.collection === op.collection && dropped.type === \"update\") continue;\n touched.add(dropped.collection);\n for (const [idKey, previous] of Object.entries(dropped.rollback?.rows ?? {})) {\n const restored = this.applyPendingToRow(dropped.collection, idKey, previous ?? undefined);\n if (restored === undefined) this.removeLocalRow(dropped.collection, idKey, ticket);\n else this.setLocalRow(dropped.collection, idKey, restored, ticket);\n }\n }\n\n // An edit refused because its row is gone on the server: the row the\n // edit started from is not there to restore. Putting it back showed a\n // row nobody has, and served it offline until something refetched.\n const goneKey = op.type === \"update\" && isNotFoundError(error) ? String(op.id) : undefined;\n for (const [idKey, previous] of Object.entries(op.rollback?.rows ?? {})) {\n const gone = idKey === goneKey;\n // With the doomed writes gone, whatever survives in the queue is\n // what the row should still look like on top of the restored base.\n const restored = this.applyPendingToRow(op.collection, idKey, gone ? undefined : previous ?? undefined);\n if (restored === undefined) this.removeLocalRow(op.collection, idKey, ticket, gone);\n else this.setLocalRow(op.collection, idKey, restored, ticket);\n }\n\n this.patchStatus({ lastError: error.message });\n for (const slug of touched) {\n this.notifyCollection(slug);\n this.scheduleRefresh(slug);\n }\n // The refused write is reported with the server's answer; the ones\n // discarded along with it were never sent, and say so — with that\n // answer as their cause, so \"why\" is one property away.\n for (const dropped of doomed) {\n // A write the app chose to discard is not news to it.\n if (dropped === op && !report) continue;\n callSafely(() => this.onSyncError?.(dropped === op ? error : dependencyRejected(op, error), dropped));\n }\n }\n\n /**\n * An edit replayed with `If-Match` and refused with a 412: ask\n * {@link OfflineConfig.onConflict}, and do what it says. A callback that\n * throws, or none, is \"overwrite\" — what replay did before it knew of\n * conflicts.\n */\n private async resolveConflict(op: PendingMutation, error: RebaseApiError, ticket: ScopeTicket): Promise<ConflictResolution> {\n let resolution: ConflictResolution = \"overwrite\";\n if (this.onConflict) {\n try {\n resolution = await this.onConflict(error, op) === \"discard\" ? \"discard\" : \"overwrite\";\n } catch (callbackError) {\n console.error(\"Error in offline onConflict:\", callbackError);\n }\n }\n if (resolution === \"overwrite\") {\n // Sent again under the same key: a refused precondition hands the\n // key back, and the body is the same.\n delete op.ifMatch;\n await this.persistMutation(`${ticket.scope}|${op.mutationId}`, op).catch(() => undefined);\n return resolution;\n }\n await this.rejectMutation(op, error, ticket, false);\n // The row as the server has it now, which is what the user is left\n // looking at once their edit is gone.\n const slug = op.collection;\n const id = op.id!;\n try {\n const row = await this.innerFor(slug).findById(id);\n if (this.isCurrent(ticket)) {\n if (row) await this.ingest(slug, [row], ticket);\n else if (!this.hasPending(slug, id)) this.removeLocalRow(slug, id, ticket, true);\n this.notifyCollection(slug);\n }\n } catch {\n // The next read or realtime frame brings it.\n }\n return resolution;\n }\n\n /**\n * Put the separate edits a coalesced `update` was made of back in the\n * queue, in its place and in their order, each with the row as it stood\n * before it as its rollback — so a refusal undoes that edit alone.\n *\n * Their ids extend the merged op's, which sorts them after it and before\n * whatever was queued next, so the queue's order survives a reload.\n */\n private async splitCoalesced(op: PendingMutation, ticket: ScopeTicket): Promise<void> {\n const parts = op.parts ?? [];\n const idKey = String(op.id);\n let before: AnyRow | null = op.rollback?.rows?.[idKey] ?? null;\n const pieces: PendingMutation[] = parts.map((part, index) => {\n const piece: PendingMutation = {\n mutationId: `${op.mutationId}:${index}`,\n collection: op.collection,\n type: \"update\",\n id: op.id,\n data: { ...part },\n queuedAt: op.queuedAt,\n // The version the first edit was made against; the rest were\n // made on top of it.\n ...(index === 0 && op.ifMatch ? { ifMatch: op.ifMatch } : {}),\n rollback: { rows: { [idKey]: before === null ? null : { ...before } } }\n };\n if (before !== null) before = { ...before, ...part };\n return piece;\n });\n for (const piece of pieces) {\n await this.persistMutation(`${ticket.scope}|${piece.mutationId}`, piece).catch(() => undefined);\n }\n await this.store.dequeue(`${ticket.scope}|${op.mutationId}`).catch(() => undefined);\n if (!this.isCurrent(ticket)) return;\n const position = this.queue.indexOf(op);\n this.queue.splice(position < 0 ? 0 : position, position < 0 ? 0 : 1, ...pieces);\n this.queueChangedInPlace();\n this.afterQueueChange(false);\n }\n\n /** Every row id a mutation writes to. */\n private idsOf(op: PendingMutation): string[] {\n if (op.type === \"createMany\") {\n return ((op.data as AnyRow[] | undefined) ?? []).map((r) => String(r.id));\n }\n if (op.type === \"updateMany\") return (op.updates ?? []).map((u) => String(u.id));\n if (op.type === \"deleteMany\") return (op.ids ?? []).map((id) => String(id));\n return op.id === undefined ? [] : [String(op.id)];\n }\n\n private async drop(op: PendingMutation, ticket: ScopeTicket): Promise<void> {\n // Under the scope it was queued in: computed from the current one, a\n // replay acknowledged after a change of user dequeued a key that did\n // not exist, and the write was sent again when its user came back.\n await this.store.dequeue(`${ticket.scope}|${op.mutationId}`).catch(() => undefined);\n if (!this.isCurrent(ticket)) return;\n this.queue = this.queue.filter((m) => m.mutationId !== op.mutationId);\n // No broadcast per item: draining a queue of fifty would be fifty\n // messages to every other tab. The flush announces itself once, at the end.\n this.afterQueueChange(false);\n }\n\n /** Replay uses unwrapped clients: a failure must never re-enqueue itself. */\n private innerFor(slug: string): SDKCollectionClient<AnyRow> {\n let inner = this.inners.get(slug);\n if (!inner) {\n inner = this.createInner(slug);\n this.inners.set(slug, inner);\n }\n return inner;\n }\n\n private async withLock<T>(fn: () => Promise<T>): Promise<T> {\n const locks = (globalThis as { navigator?: { locks?: LockManager } }).navigator?.locks;\n // Two tabs replaying the same queue would each send every mutation.\n if (!locks?.request) return fn();\n // The request settles with the callback's own outcome, so a failure\n // of the work and a refusal of the lock look the same from here. Only\n // the refusal may fall back: a replay that had started and thrown was\n // run a second time with no lock held, alongside whichever tab was\n // waiting for it.\n let started = false;\n try {\n return await locks.request(`rebase-offline-sync:${this.scope}`, () => {\n started = true;\n return fn();\n }) as T;\n } catch (error) {\n if (started) throw error;\n // A browser that denies the lock (or a policy that blocks it) must\n // not stop the queue from draining at all.\n return fn();\n }\n }\n\n // ─── Cross-tab ───────────────────────────────────────────────────────────\n\n private broadcast(message: { type: \"rows\"; slugs: string[] } | { type: \"queue\" }, scope = this.scope): void {\n if (!this.channel) return;\n try {\n this.channel.postMessage({ ...message, scope, sender: this.tabId });\n } catch {\n // Structured-clone failures here would only cost cross-tab freshness.\n }\n }\n\n private onBroadcast(message: unknown): void {\n if (this.disposed || !message || typeof message !== \"object\") return;\n const msg = message as { type?: string; scope?: string; sender?: string; slugs?: string[] };\n // Held, this tab is nobody's yet: there is nothing in memory to keep fresh.\n if (this.scopeHold || msg.sender === this.tabId || msg.scope !== this.scope) return;\n if (msg.type === \"rows\") {\n for (const slug of msg.slugs ?? []) void this.reloadCollection(slug);\n } else if (msg.type === \"queue\") {\n void this.reloadQueue();\n }\n }\n\n /** Re-read one collection from the store, replacing what is in memory. */\n private async reloadCollection(slug: string): Promise<void> {\n const state = this.collections.get(slug);\n if (!state?.loaded || this.scopeHold) return; // never loaded here — nothing to keep fresh\n await this.reloadQueue();\n const scope = this.scope;\n const [rows, snapshots, absent] = await Promise.all([\n this.store.listCacheEntries(`${scope}|row|${slug}|`).catch(() => []),\n this.store.listCacheEntries(`${scope}|q|${slug}|`).catch(() => []),\n this.store.listCache(`${scope}|abs|${slug}|`).catch(() => [])\n ]);\n if (this.scope !== scope || this.collections.get(slug) !== state) return;\n const next = new Map<string, RowEntry>();\n for (const entry of rows) {\n const row = entry.value as AnyRow | undefined;\n if (!row || row.id === undefined || row.id === null) continue;\n const key = String(row.id);\n const existing = state.rows.get(key);\n const hydrated = hydrateRow(row);\n // Keep the previous revision when nothing actually changed, so a\n // cross-tab ping does not re-render every observer.\n const unchanged = existing && JSON.stringify(existing.row) === JSON.stringify(hydrated);\n next.set(key, {\n row: hydrated,\n cachedAt: entry.cachedAt,\n rev: unchanged ? existing!.rev : ++this.revCounter\n });\n }\n state.rows = next;\n state.snapshots = new Map();\n for (const entry of snapshots) {\n const key = entry.key.slice(`${scope}|q|${slug}|`.length);\n if (entry.value) state.snapshots.set(key, readSnapshot(entry.value));\n }\n state.absent = new Set(absent.map((entry) => entry.key.slice(`${scope}|abs|${slug}|`.length)));\n this.notifyCollection(slug, false);\n }\n\n private async reloadQueue(): Promise<void> {\n if (this.scopeHold) return;\n const scope = this.scope;\n const queue = await this.readQueue(`${scope}|`).catch(() => undefined);\n if (!queue || this.scope !== scope) return;\n this.queue = queue;\n this.afterQueueChange(false);\n }\n\n // ─── Notifications ───────────────────────────────────────────────────────\n\n private afterQueueChange(broadcast = true): void {\n this.patchStatus({ pending: this.queue.length });\n this.notifyQueue();\n if (broadcast) this.broadcast({ type: \"queue\" });\n }\n\n private notifyQueue(): void {\n for (const listener of this.queueListeners) callSafely(() => listener(this.queue.length));\n }\n\n private patchStatus(patch: Partial<OfflineStatus>): void {\n let changed = false;\n for (const [key, value] of Object.entries(patch) as [keyof OfflineStatus, never][]) {\n if (this.currentStatus[key] !== value) {\n this.currentStatus[key] = value;\n changed = true;\n }\n }\n if (!changed) return;\n const snapshot = { ...this.currentStatus };\n for (const listener of this.statusListeners) callSafely(() => listener(snapshot));\n }\n\n // ─── Store keys and access ───────────────────────────────────────────────\n\n private countKey(slug: string, params?: FindParams): string {\n return `${this.scope}|count|${slug}|${buildQueryString(params)}`;\n }\n\n private rowKey(slug: string, id: string | number): string {\n return `${this.scope}|row|${slug}|${String(id)}`;\n }\n\n private absentKey(slug: string, id: string | number): string {\n return `${this.scope}|abs|${slug}|${String(id)}`;\n }\n\n private queueKey(mutation: PendingMutation): string {\n return `${this.scope}|${mutation.mutationId}`;\n }\n\n /** Queue a write in the store, its rows encoded as the cache's are. */\n private persistMutation(key: string, op: PendingMutation): Promise<void> {\n return this.store.enqueue(key, dehydrateMutation(op));\n }\n\n /** The store's queue under `prefix`, its rows revived. */\n private async readQueue(prefix: string): Promise<PendingMutation[]> {\n return (await this.store.listQueue(prefix)).map(hydrateMutation);\n }\n\n private async readCache<T>(key: string): Promise<T | undefined> {\n try {\n const entry = await this.store.getCache(key);\n return entry?.value as T | undefined;\n } catch {\n // A broken cache read must degrade to \"no cache\", never break the app.\n return undefined;\n }\n }\n\n private async writeCache(key: string, value: unknown, cachedAt = Date.now()): Promise<void> {\n try {\n await this.store.setCache(key, { value, cachedAt });\n } catch {\n // Quota errors and private-browsing restrictions must not fail the\n // read or write that got us here.\n }\n }\n\n private async deleteCache(keys: string[]): Promise<void> {\n try {\n await this.store.deleteCache(keys);\n } catch {\n // Same rationale as writeCache.\n }\n }\n}\n"],"mappings":"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"}
|