pbtsdb 0.8.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/react.tsx"],"names":[],"mappings":";;;;AA4HO,SAAS,oBACZ,WAAA,EACmC;AACnC,EAAA,MAAM,OAAA,GAAU,cAAqC,IAAI,CAAA;AAEzD,EAAA,MAAM,QAAA,GAA8C,CAAC,EAAE,QAAA,EAAS,qBAC5D,GAAA,CAAC,OAAA,CAAQ,QAAA,EAAR,EAAiB,KAAA,EAAO,WAAA,EAAc,QAAA,EAAS,CAAA;AAGpD,EAAA,SAAS,YACF,IAAA,EACiF;AACpF,IAAA,MAAM,OAAA,GAAU,WAAW,OAAO,CAAA;AAElC,IAAA,IAAI,CAAC,OAAA,EAAS;AACV,MAAA,MAAM,IAAI,KAAA;AAAA,QACN;AAAA,OACJ;AAAA,IACJ;AAEA,IAAA,OAAO,IAAA,CAAK,IAAI,CAAA,GAAA,KAAO;AACnB,MAAA,IAAI,EAAE,OAAO,OAAA,CAAA,EAAU;AACnB,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,YAAA,EAAe,MAAA,CAAO,GAAG,CAAC,CAAA,0BAAA,CAA4B,CAAA;AAAA,MAC1E;AACA,MAAA,OAAO,QAAQ,GAAG,CAAA;AAAA,IACtB,CAAC,CAAA;AAAA,EACL;AAEA,EAAA,OAAO;AAAA,IACH,QAAA;AAAA,IACA;AAAA,GACJ;AACJ","file":"index.js","sourcesContent":["import React, { createContext, type ReactNode, useContext } from 'react'\n\n/**\n * UseStore hook type for variadic collection access.\n * @internal\n */\ntype UseStoreFn<CollectionsMap> = <K extends (keyof CollectionsMap)[]>(\n ...keys: K\n) => { [I in keyof K]: K[I] extends keyof CollectionsMap ? CollectionsMap[K[I]] : never }\n\n/**\n * Return type for createReactProvider function.\n */\nexport interface ReactProviderResult<CollectionsMap> {\n /**\n * React Context Provider component.\n * Wrap your app with this provider to make collections available to useStore.\n */\n Provider: React.FC<{ children: ReactNode }>\n\n /**\n * Hook to access collections from the provider.\n * Uses variadic arguments for clean syntax with automatic type inference.\n *\n * @example\n * ```tsx\n * // Single collection\n * const [books] = useStore('books');\n *\n * // Multiple collections (no 'as const' needed!)\n * const [books, authors] = useStore('books', 'authors');\n * ```\n */\n useStore: UseStoreFn<CollectionsMap>\n}\n\n/**\n * Creates a React Provider and useStore hook from a collections map.\n *\n * @param collections - Map of collection keys to Collection instances\n * @returns Object containing Provider component and useStore hook\n *\n * @example\n * Basic usage:\n * ```tsx\n * import { createCollection, createReactProvider } from 'pbtsdb';\n * import { useLiveQuery } from '@tanstack/react-db';\n *\n * // Step 1: Create collections\n * const c = createCollection<Schema>(pb, queryClient);\n * const collections = {\n * books: c('books', {}),\n * authors: c('authors', {}),\n * };\n *\n * // Step 2: Wrap for React\n * const { Provider, useStore } = createReactProvider(collections);\n *\n * // Step 3: Wrap your app\n * function App() {\n * return (\n * <QueryClientProvider client={queryClient}>\n * <Provider>\n * <BooksList />\n * </Provider>\n * </QueryClientProvider>\n * );\n * }\n *\n * // Step 4: Use in components\n * function BooksList() {\n * const [books] = useStore('books');\n * const { data } = useLiveQuery((q) => q.from({ books }));\n * return <div>{data?.map(book => <p key={book.id}>{book.title}</p>)}</div>;\n * }\n * ```\n *\n * @example\n * Variadic useStore pattern:\n * ```tsx\n * function BooksWithAuthors() {\n * const [books, authors] = useStore('books', 'authors');\n *\n * const { data } = useLiveQuery((q) =>\n * q.from({ book: books })\n * .join(\n * { author: authors },\n * ({ book, author }) => eq(book.author, author.id),\n * 'left'\n * )\n * );\n *\n * return <div>...</div>;\n * }\n * ```\n *\n * @example\n * With auto-expand collections:\n * ```tsx\n * const c = createCollection<Schema>(pb, queryClient);\n * const authors = c('authors', {});\n * const books = c('books', {\n * relations: { author: authors },\n * alwaysExpand: ['author'],\n * });\n *\n * const { Provider, useStore } = createReactProvider({ authors, books });\n *\n * function BooksWithExpandedAuthors() {\n * const [books] = useStore('books');\n * const { data } = useLiveQuery((q) => q.from({ books }));\n *\n * return (\n * <ul>\n * {data?.map(book => (\n * <li key={book.id}>\n * {book.title} by {book.expand?.author?.name}\n * </li>\n * ))}\n * </ul>\n * );\n * }\n * ```\n */\nexport function createReactProvider<CollectionsMap extends Record<string, unknown>>(\n collections: CollectionsMap\n): ReactProviderResult<CollectionsMap> {\n const Context = createContext<CollectionsMap | null>(null)\n\n const Provider: React.FC<{ children: ReactNode }> = ({ children }) => (\n <Context.Provider value={collections}>{children}</Context.Provider>\n )\n\n function useStore<K extends (keyof CollectionsMap)[]>(\n ...keys: K\n ): { [I in keyof K]: K[I] extends keyof CollectionsMap ? CollectionsMap[K[I]] : never } {\n const context = useContext(Context)\n\n if (!context) {\n throw new Error(\n 'useStore must be used within the Provider returned by createReactProvider'\n )\n }\n\n return keys.map(key => {\n if (!(key in context)) {\n throw new Error(`Collection \"${String(key)}\" not found in collections`)\n }\n return context[key]\n }) as { [I in keyof K]: K[I] extends keyof CollectionsMap ? CollectionsMap[K[I]] : never }\n }\n\n return {\n Provider,\n useStore: useStore as UseStoreFn<CollectionsMap>,\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/react.tsx"],"names":[],"mappings":";;;;AAmIO,SAAS,oBACZ,WAAA,EACmC;AACnC,EAAA,MAAM,OAAA,GAAU,cAAqC,IAAI,CAAA;AAEzD,EAAA,MAAM,QAAA,GAA8C,CAAC,EAAE,QAAA,EAAS,qBAC5D,GAAA,CAAC,OAAA,CAAQ,QAAA,EAAR,EAAiB,KAAA,EAAO,WAAA,EAAc,QAAA,EAAS,CAAA;AAGpD,EAAA,SAAS,YACF,IAAA,EACiF;AACpF,IAAA,MAAM,OAAA,GAAU,WAAW,OAAO,CAAA;AAElC,IAAA,IAAI,CAAC,OAAA,EAAS;AACV,MAAA,MAAM,IAAI,KAAA;AAAA,QACN;AAAA,OACJ;AAAA,IACJ;AAEA,IAAA,OAAO,IAAA,CAAK,IAAI,CAAA,GAAA,KAAO;AACnB,MAAA,IAAI,EAAE,OAAO,OAAA,CAAA,EAAU;AACnB,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,YAAA,EAAe,MAAA,CAAO,GAAG,CAAC,CAAA,0BAAA,CAA4B,CAAA;AAAA,MAC1E;AACA,MAAA,OAAO,QAAQ,GAAG,CAAA;AAAA,IACtB,CAAC,CAAA;AAAA,EACL;AAEA,EAAA,OAAO;AAAA,IACH,QAAA;AAAA,IACA;AAAA,GACJ;AACJ","file":"index.js","sourcesContent":["import React, { createContext, type ReactNode, useContext } from 'react'\n\n/**\n * UseStore hook type for variadic collection access.\n * @internal\n */\ntype UseStoreFn<CollectionsMap> = <K extends (keyof CollectionsMap)[]>(\n ...keys: K\n) => { [I in keyof K]: K[I] extends keyof CollectionsMap ? CollectionsMap[K[I]] : never }\n\n/**\n * Return type for createReactProvider function.\n */\nexport interface ReactProviderResult<CollectionsMap> {\n /**\n * React Context Provider component.\n * Wrap your app with this provider to make collections available to useStore.\n */\n Provider: React.FC<{ children: ReactNode }>\n\n /**\n * Hook to access collections from the provider.\n * Uses variadic arguments for clean syntax with automatic type inference.\n *\n * @example\n * ```tsx\n * // Single collection\n * const [books] = useStore('books');\n *\n * // Multiple collections (no 'as const' needed!)\n * const [books, authors] = useStore('books', 'authors');\n * ```\n */\n useStore: UseStoreFn<CollectionsMap>\n}\n\n/**\n * Creates a React Provider and useStore hook from a collections map.\n *\n * @param collections - Map of collection keys to Collection instances\n * @returns Object containing Provider component and useStore hook\n *\n * @example\n * Basic usage:\n * ```tsx\n * import { createCollection, createReactProvider } from 'pbtsdb';\n * import { useLiveQuery } from '@tanstack/react-db';\n *\n * // Step 1: Create collections\n * const c = createCollection<Schema>(pb, queryClient);\n * const collections = {\n * books: c('books', {}),\n * authors: c('authors', {}),\n * };\n *\n * // Step 2: Wrap for React\n * const { Provider, useStore } = createReactProvider(collections);\n *\n * // Step 3: Wrap your app\n * function App() {\n * return (\n * <QueryClientProvider client={queryClient}>\n * <Provider>\n * <BooksList />\n * </Provider>\n * </QueryClientProvider>\n * );\n * }\n *\n * // Step 4: Use in components\n * function BooksList() {\n * const [books] = useStore('books');\n * const { data } = useLiveQuery((q) => q.from({ books }));\n * return <div>{data?.map(book => <p key={book.id}>{book.title}</p>)}</div>;\n * }\n * ```\n *\n * @example\n * Variadic useStore pattern:\n * ```tsx\n * function BooksWithAuthors() {\n * const [books, authors] = useStore('books', 'authors');\n *\n * const { data } = useLiveQuery((q) =>\n * q.from({ book: books })\n * .join(\n * { author: authors },\n * ({ book, author }) => eq(book.author, author.id),\n * 'left'\n * )\n * );\n *\n * return <div>...</div>;\n * }\n * ```\n *\n * @example\n * With relations filed via alwaysFetchRelations:\n * ```tsx\n * const c = createCollection<Schema>(pb, queryClient);\n * const authors = c('authors', { syncMode: 'on-demand' });\n * const books = c('books', {\n * relations: { author: authors },\n * alwaysFetchRelations: ['author'],\n * });\n *\n * const { Provider, useStore } = createReactProvider({ authors, books });\n *\n * function BooksWithAuthors() {\n * const [books, authors] = useStore('books', 'authors');\n * const { data } = useLiveQuery((q) =>\n * q.from({ b: books }).select(({ b }) => ({\n * ...b,\n * author: materialize(\n * q.from({ a: authors }).where(({ a }) => eq(a.id, b.author)).findOne()\n * ),\n * }))\n * );\n *\n * return (\n * <ul>\n * {data?.map(row => (\n * <li key={row.id}>\n * {row.title} by {row.author?.name}\n * </li>\n * ))}\n * </ul>\n * );\n * }\n * ```\n */\nexport function createReactProvider<CollectionsMap extends Record<string, unknown>>(\n collections: CollectionsMap\n): ReactProviderResult<CollectionsMap> {\n const Context = createContext<CollectionsMap | null>(null)\n\n const Provider: React.FC<{ children: ReactNode }> = ({ children }) => (\n <Context.Provider value={collections}>{children}</Context.Provider>\n )\n\n function useStore<K extends (keyof CollectionsMap)[]>(\n ...keys: K\n ): { [I in keyof K]: K[I] extends keyof CollectionsMap ? CollectionsMap[K[I]] : never } {\n const context = useContext(Context)\n\n if (!context) {\n throw new Error(\n 'useStore must be used within the Provider returned by createReactProvider'\n )\n }\n\n return keys.map(key => {\n if (!(key in context)) {\n throw new Error(`Collection \"${String(key)}\" not found in collections`)\n }\n return context[key]\n }) as { [I in keyof K]: K[I] extends keyof CollectionsMap ? CollectionsMap[K[I]] : never }\n }\n\n return {\n Provider,\n useStore: useStore as UseStoreFn<CollectionsMap>,\n }\n}\n"]}
package/llms.txt CHANGED
@@ -197,30 +197,50 @@ function BooksList() {
197
197
 
198
198
  ## Common Patterns
199
199
 
200
- **Approach 1: Auto-Expand (Recommended)**
200
+ **Approach 1: Related data (Recommended)**
201
+
202
+ PocketBase `expand` only files related records into their own collections;
203
+ rows never carry `expand`. Read related records from the target collection.
204
+
201
205
  ```typescript
206
+ import { eq } from '@tanstack/db';
207
+ import { materialize } from 'pbtsdb';
208
+
202
209
  const c = createCollection<Schema>(pb, queryClient);
203
- const authors = c('authors', {});
210
+ const authors = c('authors', { syncMode: 'on-demand' });
204
211
  const books = c('books', {
205
- relations: { author: authors }, // where expanded authors are upserted
206
- alwaysExpand: ['author'], // expanded on every fetch
212
+ relations: { author: authors }, // where expanded records are filed
213
+ alwaysFetchRelations: ['author'], // fetched with every books request
207
214
  });
208
215
 
209
- const { data } = useLiveQuery((q) => q.from({ books }));
210
- // data[0].expand?.author is typed and populated
216
+ const { data } = useLiveQuery((q) =>
217
+ q.from({ b: books }).select(({ b }) => ({
218
+ ...b,
219
+ author: materialize(
220
+ q.from({ a: authors }).where(({ a }) => eq(a.id, b.author)).findOne()
221
+ ),
222
+ }))
223
+ );
224
+ // data[0].author?.name is Authors | undefined and updates when the author changes
211
225
  ```
212
226
 
213
- **When to use Auto-Expand:**
214
- - You want expanded records to populate their own collections automatically
215
- - Performance: Single server query with server-side expand
227
+ An id-only load (`eq(id, x)`, `inArray(id, [...])`, or an `or` of those) is
228
+ served from the synced store when every id is present, except through a
229
+ `fetchRelations()` view, whose fetch always goes to PocketBase; anything else
230
+ is fetched in one batched request.
231
+
232
+ **When to use alwaysFetchRelations:**
233
+ - The parent is the only path by which those rows enter an on-demand collection
234
+ - Performance: single server request per fetch of the parent
216
235
  - Related data always available when fetching parent records
217
236
 
218
- **Per-query expand**
237
+ **Per-query fetchRelations**
219
238
  ```typescript
220
239
  const books = c('books', { relations: { author: authors, tags } });
221
- const { data } = useLiveQuery((q) => q.from({ books: books.expand('tags') }));
222
- // data[0].expand?.tags typed; nested paths like 'book.author' resolve through
223
- // the target collection's own relations. Views share the base store.
240
+ const { data } = useLiveQuery((q) => q.from({ books: books.fetchRelations('tags') }));
241
+ // tags referenced by these books are filed into the tags collection; nested
242
+ // paths like 'book.author' resolve through the target's own relations.
243
+ // Views share the base store, subscription, and mutations.
224
244
  ```
225
245
 
226
246
  **Approach 2: TanStack Joins**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pbtsdb",
3
- "version": "0.8.0",
3
+ "version": "0.9.1",
4
4
  "description": "Type-safe PocketBase integration with TanStack Query and TanStack DB",
5
5
  "keywords": [
6
6
  "pocketbase",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/expand-merge.ts","../src/logger.ts","../src/expand-patch.ts","../src/expand-paths.ts","../src/pocketbase-query-converter.ts","../src/build-collection.ts","../src/collection.ts","../src/util.ts"],"names":["patched","expand","createTanStackCollection"],"mappings":"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","file":"chunk-KMR6I4ZC.js","sourcesContent":["type Expandable = { expand?: Record<string, unknown> } & Record<string, unknown>\n\ntype Entry = { id?: unknown; updated?: unknown }\n\nfunction sameRelationValue(a: unknown, b: unknown): boolean {\n if (Array.isArray(a) && Array.isArray(b)) {\n return a.length === b.length && a.every((value, index) => value === b[index])\n }\n return a === b\n}\n\n// True when `stored` describes the same record as `incoming` but carries a\n// strictly newer `updated`. An in-flight parent fetch that resolves after a\n// relation-target echo otherwise reverts the patch with its older copy.\nfunction storedIsNewer(incoming: unknown, stored: unknown): boolean {\n const a = incoming as Entry | null | undefined\n const b = stored as Entry | null | undefined\n if (!a || !b || a.id !== b.id) return false\n if (typeof a.updated !== 'string' || typeof b.updated !== 'string') return false\n return b.updated > a.updated\n}\n\nfunction newerEntry(incoming: unknown, stored: unknown): unknown {\n if (Array.isArray(incoming) && Array.isArray(stored)) {\n let changed = false\n const merged = incoming.map(entry => {\n const match = stored.find(\n candidate => (candidate as Entry | null)?.id === (entry as Entry | null)?.id\n )\n if (!storedIsNewer(entry, match)) return entry\n changed = true\n return match\n })\n return changed ? merged : incoming\n }\n return storedIsNewer(incoming, stored) ? stored : incoming\n}\n\n/**\n * Carry `expand` entries from the stored row onto an incoming row that lacks them,\n * as long as the relation field itself did not change, and keep a stored entry\n * that is newer than the incoming one for the same record. Never mutates `incoming`.\n */\nexport function mergeExpand<T extends object>(incoming: T, existing: T | undefined): T {\n const stored = (existing as Expandable | undefined)?.expand\n if (!stored) return incoming\n const row = incoming as Expandable\n const merged: Record<string, unknown> = { ...(row.expand ?? {}) }\n let carried = false\n for (const [relation, value] of Object.entries(stored)) {\n if (relation in merged) {\n const kept = newerEntry(merged[relation], value)\n if (kept === merged[relation]) continue\n merged[relation] = kept\n carried = true\n continue\n }\n if (!sameRelationValue(row[relation], (existing as Expandable)[relation])) continue\n merged[relation] = value\n carried = true\n }\n return carried ? ({ ...row, expand: merged } as T) : incoming\n}\n","/**\n * Logger interface for subscription events and internal operations.\n * Users can provide their own implementation to integrate with external logging services.\n */\nexport interface Logger {\n /**\n * Log debug-level messages (typically only shown in development).\n * @param msg - The message to log\n * @param context - Optional context object with additional information\n */\n debug: (msg: string, context?: object) => void\n\n /**\n * Log info-level messages.\n * @param msg - The message to log\n * @param context - Optional context object with additional information\n */\n info: (msg: string, context?: object) => void\n\n /**\n * Log warning-level messages.\n * @param msg - The message to log\n * @param context - Optional context object with additional information\n */\n warn: (msg: string, context?: object) => void\n\n /**\n * Log error-level messages.\n * @param msg - The message to log\n * @param context - Optional context object with additional information\n */\n error: (msg: string, context?: object) => void\n}\n\n/**\n * Default console-based logger implementation.\n * Only logs debug messages in development mode.\n */\nconst defaultLogger: Logger = {\n debug: (msg: string, context?: object) => {\n if (process.env.NODE_ENV === 'development') {\n console.debug(`[pbtsdb] ${msg}`, context || '')\n }\n },\n info: (msg: string, context?: object) => {\n console.info(`[pbtsdb] ${msg}`, context || '')\n },\n warn: (msg: string, context?: object) => {\n console.warn(`[pbtsdb] ${msg}`, context || '')\n },\n error: (msg: string, context?: object) => {\n console.error(`[pbtsdb] ${msg}`, context || '')\n },\n}\n\n/**\n * Current logger instance (can be replaced by users).\n */\nlet currentLogger: Logger = defaultLogger\n\n/**\n * Internal logger instance used by the library.\n */\nexport const logger: Logger = {\n debug: (msg: string, context?: object) => currentLogger.debug(msg, context),\n info: (msg: string, context?: object) => currentLogger.info(msg, context),\n warn: (msg: string, context?: object) => currentLogger.warn(msg, context),\n error: (msg: string, context?: object) => currentLogger.error(msg, context),\n}\n\n/**\n * Set a custom logger implementation.\n * This allows users to integrate with their own logging services (e.g., Sentry, LogRocket, etc.).\n *\n * @param customLogger - The custom logger implementation\n *\n * @example\n * ```ts\n * import { setLogger } from 'pbtsdb';\n *\n * // Integration with a custom logging service\n * setLogger({\n * debug: (msg, context) => myLogger.debug(msg, context),\n * warn: (msg, context) => myLogger.warn(msg, context),\n * error: (msg, context) => {\n * myLogger.error(msg, context);\n * Sentry.captureMessage(msg, { level: 'error', extra: context });\n * },\n * });\n * ```\n *\n * @example\n * ```ts\n * // Disable all logging\n * setLogger({\n * debug: () => {},\n * warn: () => {},\n * error: () => {},\n * });\n * ```\n */\nexport function setLogger(customLogger: Logger): void {\n currentLogger = customLogger\n}\n\n/**\n * Reset the logger to the default implementation.\n */\nexport function resetLogger(): void {\n currentLogger = defaultLogger\n}\n","import { deepEquals } from '@tanstack/db'\nimport { mergeExpand } from './expand-merge'\nimport { logger } from './logger'\nimport type { ExpandTargetCollection, RelationDependent } from './types'\n\nexport type RelatedAction = 'create' | 'update' | 'delete'\n\ntype Row = Record<string, unknown> & { expand?: Record<string, unknown> }\n\nfunction embeddedId(value: unknown): string | undefined {\n return (value as { id: string } | null | undefined)?.id\n}\n\nfunction patchUpdate(\n row: Row,\n field: string,\n record: Record<string, unknown> & { id: string }\n): Row | undefined {\n const embedded = row.expand?.[field]\n if (embedded === undefined) return undefined\n let next: unknown\n if (Array.isArray(embedded)) {\n const index = embedded.findIndex(entry => embeddedId(entry) === record.id)\n if (index === -1) return undefined\n const replaced = mergeExpand(record, embedded[index] as { id: string })\n next = embedded.map((entry, i) => (i === index ? replaced : entry))\n } else {\n if (embeddedId(embedded) !== record.id) return undefined\n next = mergeExpand(record, embedded as { id: string })\n }\n if (deepEquals(next, embedded)) return undefined\n return { ...row, expand: { ...row.expand, [field]: next } }\n}\n\nfunction patchDelete(row: Row, field: string, id: string): Row | undefined {\n const value = row[field]\n const embedded = row.expand?.[field]\n if (Array.isArray(value)) {\n if (!value.includes(id)) return undefined\n const patched: Row = { ...row, [field]: value.filter(item => item !== id) }\n if (Array.isArray(embedded)) {\n patched.expand = {\n ...row.expand,\n [field]: embedded.filter(entry => embeddedId(entry) !== id),\n }\n }\n return patched\n }\n if (value !== id) return undefined\n const patched: Row = { ...row, [field]: '' }\n if (embedded !== undefined) {\n const expand = { ...row.expand }\n delete expand[field]\n patched.expand = expand\n }\n return patched\n}\n\n/**\n * Apply a relation target's realtime change to one parent row. Returns a new\n * row, or `undefined` when the row is unaffected or the result would be\n * identical, so callers can skip the write.\n */\nexport function patchEmbedded<T extends object>(\n row: T,\n field: string,\n action: RelatedAction,\n record: Record<string, unknown> & { id: string }\n): T | undefined {\n const current = row as Row\n const patched =\n action === 'delete'\n ? patchDelete(current, field, record.id)\n : patchUpdate(current, field, record)\n return patched as T | undefined\n}\n\n// Dependents grouped by parent, registration order preserved both for the\n// parents and for each parent's fields. One parent may declare several\n// relations onto the same target; all of its fields must reach it in a single\n// call, because `visited` is keyed per row and the first call marks the row.\nfunction fieldsByParent(\n dependents: readonly RelationDependent[]\n): Map<ExpandTargetCollection, string[]> {\n const grouped = new Map<ExpandTargetCollection, string[]>()\n for (const { field, parent } of dependents) {\n const fields = grouped.get(parent)\n if (fields) fields.push(field)\n else grouped.set(parent, [field])\n }\n return grouped\n}\n\n/**\n * Fan a relation target's change out to every collection that embeds it.\n * Each dependent patches its own rows and recurses with the same `visited`\n * set, so a cyclic relation graph terminates and a row is patched at most\n * once per originating echo.\n */\nexport function propagateRelatedChange(\n source: ExpandTargetCollection,\n action: RelatedAction,\n record: Record<string, unknown> & { id: string },\n visited: Set<string>\n): void {\n for (const [parent, fields] of fieldsByParent(source.relationDependents ?? [])) {\n try {\n parent.applyRelatedChange?.(fields, action, record, visited)\n } catch (error) {\n logger.error('Failed to patch a relation dependent', {\n collectionName: source.collectionName,\n dependent: parent.collectionName,\n fields,\n error,\n })\n }\n }\n}\n","import type { ExpandTargetCollection } from './types'\n\nexport type RelationTargets = Record<string, ExpandTargetCollection>\n\nexport function normalizePaths(paths: Iterable<string>): string[] {\n const set = new Set<string>()\n for (const path of paths) {\n const trimmed = path.trim()\n if (trimmed) set.add(trimmed)\n }\n return [...set].sort()\n}\n\nexport function splitPaths(csv: string | undefined): string[] {\n return csv ? normalizePaths(csv.split(',')) : []\n}\n\nexport function joinPaths(paths: Iterable<string>): string | undefined {\n const normalized = normalizePaths(paths)\n return normalized.length > 0 ? normalized.join(',') : undefined\n}\n\nexport function validateExpandPath(\n collectionName: string,\n targets: RelationTargets | undefined,\n path: string\n): void {\n if (!targets) {\n throw new Error(\n `Cannot expand \"${path}\" on collection \"${collectionName}\": no relations declared`\n )\n }\n let current: RelationTargets | undefined = targets\n for (const segment of path.split('.')) {\n const next: ExpandTargetCollection | undefined = current?.[segment]\n if (!next) {\n throw new Error(\n `Cannot expand \"${path}\" on collection \"${collectionName}\": segment \"${segment}\" is not a declared relation`\n )\n }\n current = next.relationTargets\n }\n}\n","import type { IR } from '@tanstack/db'\nimport {\n type FieldPath,\n type ParsedOrderBy,\n parseOrderByExpression,\n parseWhereExpression,\n} from '@tanstack/db'\n\ntype BasicExpression<T = unknown> = IR.BasicExpression<T>\n\nfunction escapeValue(value: unknown): string {\n if (value === null) {\n return 'null'\n }\n if (typeof value === 'boolean') {\n return value ? 'true' : 'false'\n }\n if (typeof value === 'number') {\n return value.toString()\n }\n if (typeof value === 'string') {\n return `\"${value.replace(/\"/g, '\\\\\"')}\"`\n }\n if (value instanceof Date) {\n return `\"${value.toISOString()}\"`\n }\n if (Array.isArray(value)) {\n return `[${value.map(escapeValue).join(',')}]`\n }\n return `\"${String(value)}\"`\n}\n\nfunction fieldPathToString(path: FieldPath): string {\n return path.join('.')\n}\n\nexport function convertToPocketBaseFilter(\n where: BasicExpression<boolean> | undefined | null\n): string | undefined {\n if (!where) {\n return undefined\n }\n\n const result = parseWhereExpression(where, {\n handlers: {\n eq: (field: FieldPath, value: unknown) => {\n return `${fieldPathToString(field)} = ${escapeValue(value)}`\n },\n gt: (field: FieldPath, value: unknown) => {\n return `${fieldPathToString(field)} > ${escapeValue(value)}`\n },\n gte: (field: FieldPath, value: unknown) => {\n return `${fieldPathToString(field)} >= ${escapeValue(value)}`\n },\n lt: (field: FieldPath, value: unknown) => {\n return `${fieldPathToString(field)} < ${escapeValue(value)}`\n },\n lte: (field: FieldPath, value: unknown) => {\n return `${fieldPathToString(field)} <= ${escapeValue(value)}`\n },\n and: (...conditions: string[]) => {\n if (conditions.length === 0) return ''\n if (conditions.length === 1) return conditions[0]\n return `(${conditions.join(' && ')})`\n },\n or: (...conditions: string[]) => {\n if (conditions.length === 0) return ''\n if (conditions.length === 1) return conditions[0]\n return `(${conditions.join(' || ')})`\n },\n not: (condition: string) => {\n return `!(${condition})`\n },\n in: (field: FieldPath, values: unknown) => {\n const valueArray = Array.isArray(values) ? values : [values]\n const uniqueValues = [...new Set(valueArray)]\n const fieldStr = fieldPathToString(field)\n const conditions = uniqueValues.map(v => `${fieldStr} = ${escapeValue(v)}`)\n return conditions.length > 1 ? `(${conditions.join(' || ')})` : conditions[0]\n },\n like: (field: FieldPath, value: unknown) => {\n return `${fieldPathToString(field)} ~ ${escapeValue(value)}`\n },\n isNull: (field: FieldPath) => {\n return `${fieldPathToString(field)} = null`\n },\n isUndefined: (field: FieldPath) => {\n return `${fieldPathToString(field)} = null`\n },\n },\n onUnknownOperator: (operator: string, _args: unknown[]) => {\n throw new Error(\n `Unsupported operator '${operator}' for PocketBase filter conversion. ` +\n `Supported operators: eq, gt, gte, lt, lte, in, like, and, or, not, isNull, isUndefined`\n )\n },\n })\n\n return result || undefined\n}\n\nexport function convertToPocketBaseSort(\n orderBy: IR.OrderBy | undefined | null\n): string | undefined {\n if (!orderBy) {\n return undefined\n }\n\n const sorts = parseOrderByExpression(orderBy)\n\n if (sorts.length === 0) {\n return undefined\n }\n\n return sorts\n .map((sort: ParsedOrderBy) => {\n const field = fieldPathToString(sort.field)\n return sort.direction === 'desc' ? `-${field}` : field\n })\n .join(',')\n}\n","import {\n BTreeIndex,\n type Collection,\n createCollection as createTanStackCollection,\n type LoadSubsetOptions,\n} from '@tanstack/db'\nimport {\n DeleteOperationItemNotFoundError,\n type QueryCollectionUtils,\n queryCollectionOptions,\n} from '@tanstack/query-db-collection'\nimport type { QueryClient } from '@tanstack/react-query'\nimport type PocketBase from 'pocketbase'\nimport type { RecordSubscribeOptions, RecordSubscription } from 'pocketbase'\nimport { mergeExpand } from './expand-merge'\nimport { patchEmbedded, propagateRelatedChange, type RelatedAction } from './expand-patch'\nimport type { RelationTargets } from './expand-paths'\nimport { joinPaths, normalizePaths, splitPaths, validateExpandPath } from './expand-paths'\nimport { logger } from './logger'\nimport { convertToPocketBaseFilter, convertToPocketBaseSort } from './pocketbase-query-converter'\nimport type {\n CreateCollectionOptions,\n ExpandTargetCollection,\n ExtractRecordType,\n RelationDependent,\n SchemaDeclaration,\n} from './types'\n\n// Subscriptions created through a view, mapped to the view's expand paths. Keyed\n// by the subscription object TanStack hands back to loadSubset/unloadSubset.\nconst viewPaths = new WeakMap<object, string[]>()\n\n/**\n * Options applied to every collection built by a {@link createCollection} factory.\n */\nexport interface CreateCollectionFactoryOptions {\n /**\n * Extra options passed to every real-time subscription this factory creates,\n * such as `headers`, `filter`, `expand` or `fields`.\n *\n * Invoked at subscribe time rather than read once, because a subscription is\n * re-established on reconnect and whenever the subscriber count rises from\n * zero — a value captured at build time would go stale exactly then.\n *\n * Returning `undefined` subscribes with no extra options.\n */\n subscribeOptions?: () => RecordSubscribeOptions | undefined\n}\n\n/**\n * Subscription helpers added to collection instances.\n * @internal\n */\nexport interface CollectionSubscriptionHelpers {\n /** The PocketBase collection name */\n collectionName: string\n /** Wait for subscription to be established (useful in tests) */\n waitForSubscription: (timeout?: number) => Promise<void>\n /** Check if collection has an active subscription */\n isSubscribed: () => boolean\n /** Relation targets declared through `relations` */\n relationTargets: RelationTargets | undefined\n /** Number of relation targets currently held live */\n heldRelationTargetCount: () => number\n /** Collections that declared this one in their `relations` */\n relationDependents: RelationDependent[]\n /** Patch this collection's rows for a change in a relation target */\n applyRelatedChange: (\n fields: readonly string[],\n action: RelatedAction,\n record: Record<string, unknown> & { id: string },\n visited: Set<string>\n ) => void\n}\n\n/**\n * Runtime shape of a built collection, before the public factory narrows it.\n * @internal\n */\nexport type BuiltCollection<T extends object> = Collection<\n T,\n string | number,\n QueryCollectionUtils<T, string | number, T>,\n never,\n T\n> &\n CollectionSubscriptionHelpers\n\n/** @internal */\nexport interface BuildCollectionInput<\n Schema extends SchemaDeclaration,\n C extends keyof Schema & string,\n> {\n pb: PocketBase\n queryClient: QueryClient\n factoryOptions: CreateCollectionFactoryOptions | undefined\n collectionName: C\n options: CreateCollectionOptions<Schema, C> | undefined\n}\n\n/** @internal */\nexport function buildCollection<Schema extends SchemaDeclaration, C extends keyof Schema & string>(\n input: BuildCollectionInput<Schema, C>\n): BuiltCollection<ExtractRecordType<Schema, C>> {\n const { pb, queryClient, factoryOptions, collectionName, options } = input\n type RecordType = ExtractRecordType<Schema, C>\n\n const relationTargets = options?.relations as RelationTargets | undefined\n const alwaysExpand = normalizePaths(options?.alwaysExpand ?? [])\n for (const path of alwaysExpand) validateExpandPath(collectionName, relationTargets, path)\n const syncMode = options?.syncMode ?? 'eager'\n\n // Paths requested by views that have subscribed at least once. Eager fetches\n // read it because they cannot receive per-subset options; the realtime\n // subscription reads it so echoes carry every relation in use.\n const requestedExpand = new Set<string>()\n\n type LoadOptions = LoadSubsetOptions & { expand?: readonly string[] }\n type PbRequest = { filter?: string; sort?: string; limit?: number; expand?: string }\n\n function toRequest(opts: LoadSubsetOptions | undefined): PbRequest {\n const request: PbRequest = {}\n const filter = convertToPocketBaseFilter(opts?.where)\n const sort = convertToPocketBaseSort(opts?.orderBy)\n const expand = joinPaths((opts as LoadOptions | undefined)?.expand ?? [])\n if (filter) request.filter = filter\n if (sort) request.sort = sort\n if (opts?.limit) request.limit = opts.limit\n if (expand) request.expand = expand\n return request\n }\n\n function queryKeyFor(opts?: LoadSubsetOptions): [C] | [C, PbRequest] {\n const request = toRequest(opts)\n return Object.keys(request).length === 0 ? [collectionName] : [collectionName, request]\n }\n\n function activeExpand(request: PbRequest): string | undefined {\n return joinPaths([\n ...alwaysExpand,\n ...splitPaths(request.expand),\n ...(syncMode === 'eager' ? requestedExpand : []),\n ])\n }\n\n const ignoreAutoCancellation = options?.ignoreAutoCancellation ?? true\n const refetchOnMutation = options?.refetchOnMutation ?? false\n\n function eagerSyncInFlight(target: ExpandTargetCollection): boolean {\n return (\n target.status !== undefined &&\n target.status !== 'idle' &&\n target.status !== 'cleaned-up'\n )\n }\n\n async function upsertInto(\n key: string,\n target: ExpandTargetCollection,\n values: object[]\n ): Promise<void> {\n if (!target.utils) return\n if (!target.isReady()) {\n if (target.config?.syncMode === 'on-demand') {\n await target._sync.startSync()\n } else if (target.preload && eagerSyncInFlight(target)) {\n // An eager target whose full load is already running (a held\n // subscription started it) becomes ready shortly; wait rather\n // than drop the records or race the load.\n await target.preload()\n } else {\n logger.warn(\n `not syncing ${key} on ${collectionName} because store is not yet ready`\n )\n return\n }\n }\n target.utils.writeUpsert(values)\n }\n\n async function upsertExpandedField(\n key: string,\n value: object | object[],\n targets: RelationTargets\n ): Promise<void> {\n const target = targets[key]\n if (!target) {\n logger.debug('No relation target for expanded field', { collectionName, key })\n return\n }\n const values = Array.isArray(value) ? value : [value]\n await upsertInto(key, target, values)\n await upsertExpanded(values, target.relationTargets)\n }\n\n async function upsertExpanded(\n records: object[],\n targets: RelationTargets | undefined\n ): Promise<void> {\n if (!targets) return\n for (const record of records) {\n const expandData = (record as { expand?: Record<string, object | object[]> }).expand\n if (!expandData) continue\n for (const [key, value] of Object.entries(expandData)) {\n await upsertExpandedField(key, value, targets)\n }\n }\n }\n\n async function fetchItems(request: PbRequest): Promise<RecordType[]> {\n const { filter, sort, limit } = request\n const expand = activeExpand(request)\n\n if (limit) {\n // Use getList when limit is specified to avoid fetching all records\n const result = await pb.collection(collectionName).getList(1, limit, {\n filter,\n sort,\n skipTotal: true, // Optimize by skipping total count\n expand,\n })\n return result.items as unknown as RecordType[]\n }\n // Use getFullList to fetch all records with automatic pagination\n return (await pb.collection(collectionName).getFullList({\n filter,\n sort,\n expand,\n })) as unknown as RecordType[]\n }\n\n // Each in-flight fetch registers a set here before its request goes out;\n // authoritative local writes (mutation write-backs and realtime echoes)\n // add the confirmed record ids to every registered set. An id added\n // after a fetch was issued is newer than that fetch's view of the\n // server, so the result cannot speak to the id's absence. The merge\n // deliberately ignores the fetch's filter: the manual-write cache push\n // grants every active query ownership of every synced row, so even a\n // row outside this subset's filter must be shielded from its reconcile.\n //\n // Why this exists: @tanstack/query-db-collection's applySuccessfulResult\n // reconcile-DELETES every row a query owns that its result omits, and the\n // synced-write guard below deliberately exempts deletes. A subset read\n // issued before a row existed can therefore resolve late and delete the\n // just-confirmed row (rows a query owns include rows pushed into its\n // cache by the manual-write path that runs on every write-back). The fix\n // is applied to the RESULT rather than the delete: fetchRecords merges\n // such rows back in, which both prevents the delete and keeps the row\n // owned by the query — a dropped delete alone would still strip\n // ownership and leave the row to a later GC pass.\n const inFlightConfirmedIds = new Set<Set<string>>()\n\n function markConfirmedPresent(records: RecordType[]): void {\n if (inFlightConfirmedIds.size === 0) return\n for (const record of records) {\n const id = (record as { id?: unknown } | null | undefined)?.id\n if (typeof id !== 'string') continue\n for (const confirmed of inFlightConfirmedIds) confirmed.add(id)\n }\n }\n\n function withRowsConfirmedMidFlight(\n items: RecordType[],\n confirmedMidFlight: Set<string>\n ): RecordType[] {\n if (confirmedMidFlight.size === 0) return items\n const resultIds = new Set(\n items.map(item => (item as { id?: unknown } | null | undefined)?.id)\n )\n // Ids absent from the synced store (deleted mid-flight, or never\n // landed) have nothing to protect and drop out of the merge.\n const mergedIds = [...confirmedMidFlight].filter(\n id => !resultIds.has(id) && collection._state.syncedData.has(id)\n )\n if (mergedIds.length === 0) return items\n logger.debug('Merging rows confirmed while fetch was in flight', {\n collectionName,\n ids: mergedIds,\n })\n return [\n ...items,\n ...mergedIds.map(id => collection._state.syncedData.get(id) as RecordType),\n ]\n }\n\n async function fetchRecords(\n request: PbRequest,\n queryKey: readonly unknown[]\n ): Promise<RecordType[]> {\n const confirmedMidFlight = new Set<string>()\n inFlightConfirmedIds.add(confirmedMidFlight)\n try {\n let items: RecordType[]\n try {\n items = await fetchItems(request)\n } catch (error) {\n if (\n ignoreAutoCancellation &&\n error instanceof Error &&\n error.message.includes('autocancelled')\n ) {\n // PocketBase auto-cancelled this in-flight read because a newer\n // request superseded it. Resolve to THIS subset's own cached rows\n // (keyed by the full query key) so the reconcile is a no-op for the\n // subset. The base key ([collectionName]) holds the full-collection\n // snapshot — returning that here would let applySuccessfulResult\n // reconcile foreign rows into a filtered subset (re-introducing rows\n // the subset's filter excludes). Re-throwing instead would error the\n // subset and empty/retry it.\n return withRowsConfirmedMidFlight(\n queryClient.getQueryData<RecordType[]>(queryKey) ?? [],\n confirmedMidFlight\n )\n }\n throw error\n }\n\n await upsertExpanded(items, relationTargets)\n if (request.expand) writeExpandedRows(items)\n\n return withRowsConfirmedMidFlight(items, confirmedMidFlight)\n } finally {\n inFlightConfirmedIds.delete(confirmedMidFlight)\n }\n }\n\n // query-db-collection only calls its synced `write` for a row a query newly\n // \"owns\" in the synced store — a query whose result includes a row another\n // query already put there is treated as a no-op, even though this fetch may\n // be the only one carrying `expand` data for that row (e.g. a base and a view\n // of the same collection joined in one live query). Write such rows directly\n // so the view's `expand` field always reaches the shared store.\n function writeExpandedRows(items: RecordType[]): void {\n // On a collection's first fetch the store is empty, so\n // applySuccessfulResult inserts the rows itself; nothing to do here yet.\n if (!collection.utils || !collection.isReady()) return\n // Not writeOwn: writeOwn's optimistic-pending exemption is reserved for\n // writes already staleness-filtered upstream (writeBackAfterPersisted,\n // isStaleEcho). A view fetch is an unfiltered server read — exactly what\n // the optimistic-pending arm of shouldDropSyncedWrite must still catch,\n // since isStaleServerRecord alone compares against the synced store,\n // which a pending optimistic overlay does not update.\n collection.utils.writeUpsert(items)\n }\n\n // Every field this collection declares onto the changed target is patched in\n // one pass, so a collection with two relations to the same target (author and\n // editor both pointing at authors) updates both embedded copies per echo.\n function patchRowFields(\n row: RecordType,\n fields: readonly string[],\n action: RelatedAction,\n record: Record<string, unknown> & { id: string }\n ): RecordType | undefined {\n let current: RecordType | undefined\n for (const field of fields) {\n const next = patchEmbedded(current ?? row, field, action, record)\n if (next) current = next\n }\n return current\n }\n\n function patchedRows(\n fields: readonly string[],\n action: RelatedAction,\n record: Record<string, unknown> & { id: string },\n visited: Set<string>\n ): RecordType[] {\n const patched: RecordType[] = []\n for (const row of collection._state.syncedData.values()) {\n const id = (row as { id?: unknown }).id\n if (typeof id !== 'string') continue\n const key = `${collectionName}:${id}`\n if (visited.has(key)) continue\n const next = patchRowFields(row as RecordType, fields, action, record)\n if (!next) continue\n visited.add(key)\n patched.push(next)\n }\n return patched\n }\n\n // Patch this collection's rows for a change in a relation target. Runs\n // synchronously from the target's realtime handler; writes go through the\n // authoritative path because the rows are the current synced rows with only\n // `expand` (or, on delete, the reference) changed.\n function applyRelatedChange(\n fields: readonly string[],\n action: RelatedAction,\n record: Record<string, unknown> & { id: string },\n visited: Set<string>\n ): void {\n if (!collection.utils || !collection.isReady()) return\n const patched = patchedRows(fields, action, record, visited)\n if (patched.length === 0) return\n writeOwn(() => collection.utils.writeUpsert(patched))\n for (const row of patched) {\n propagateRelatedChange(\n collection as unknown as ExpandTargetCollection,\n 'update',\n row as { id: string },\n visited\n )\n }\n }\n\n // TanStack DB 0.6 turned auto-indexing off by default; without an index an\n // orderBy+limit query loads the whole subset instead of paging lazily and\n // warns on every compile. Restore the earlier default; callers can override\n // both settings through collectionOptions.\n const queryCollectionConfig = queryCollectionOptions({\n autoIndex: 'eager',\n defaultIndexType: BTreeIndex,\n ...options?.collectionOptions,\n queryClient,\n queryKey: queryKeyFor,\n syncMode,\n queryFn: async (ctx): Promise<RecordType[]> => {\n const request = (ctx.queryKey[1] as PbRequest | undefined) ?? {}\n return fetchRecords(request, ctx.queryKey)\n },\n getKey: (item: RecordType) => {\n const record = item as unknown as Record<string, unknown>\n if (!record || typeof record !== 'object' || !('id' in record)) {\n throw new Error(\n `Record in collection '${collectionName}' is missing required 'id' field. Received: ${JSON.stringify(item)}`\n )\n }\n return record.id as string\n },\n onInsert:\n options?.onInsert === false\n ? undefined\n : (options?.onInsert ??\n (async ({ transaction }) => {\n const created = await Promise.all(\n transaction.mutations.map(async mutation => {\n const {\n created: _created,\n updated: _updated,\n collectionId: _collectionId,\n collectionName: _collectionName,\n ...data\n } = mutation.modified as unknown as Record<string, unknown>\n return pb.collection(collectionName).create(data)\n })\n )\n writeBackAfterPersisted(transaction, created)\n return { refetch: refetchOnMutation }\n })),\n onUpdate:\n options?.onUpdate === false\n ? undefined\n : (options?.onUpdate ??\n (async ({ transaction }) => {\n const updated = await Promise.all(\n transaction.mutations.map(async mutation => {\n const recordWithId = mutation.original as { id: string }\n return pb\n .collection(collectionName)\n .update(recordWithId.id, mutation.changes)\n })\n )\n writeBackAfterPersisted(transaction, updated)\n return { refetch: refetchOnMutation }\n })),\n onDelete:\n options?.onDelete === false\n ? undefined\n : (options?.onDelete ??\n (async ({ transaction }) => {\n await Promise.all(\n transaction.mutations.map(async mutation => {\n const recordWithId = mutation.original as { id: string }\n await pb.collection(collectionName).delete(recordWithId.id)\n })\n )\n return { refetch: refetchOnMutation }\n })),\n })\n\n // queryCollectionOptions consumes `gcTime` for the underlying react-query\n // observer and never forwards it to the collection options it returns, so\n // the DB collection's own lifecycle GC (what controls when an idle\n // collection reaches 'cleaned-up') would silently fall back to its\n // 5-minute default. Re-apply it explicitly so a caller-supplied value\n // reaches both layers.\n const collectionOptions =\n options?.collectionOptions?.gcTime === undefined\n ? queryCollectionConfig\n : { ...queryCollectionConfig, gcTime: options.collectionOptions.gcTime }\n\n // Write the server's copy of a mutation's rows back AFTER the transaction\n // has persisted — never from inside its handler.\n //\n // TanStack DB keeps a completed transaction's optimistic draft visible\n // until a synced write for the key arrives, so a record the server\n // fills in (a number, a timestamp) reaches the screen only through that\n // later synced write. A write-back issued from inside the handler lands\n // while the transaction is still `persisting`; TanStack applies it,\n // then on completion re-adds the draft as a \"confirmed but unsynced\"\n // overlay and waits for a synced write that already happened. If the\n // realtime echo has ALSO already been consumed (it arrives before the\n // create resolves under load, and an echo carrying the same `updated`\n // as the write-back is dropped as stale), nothing ever clears the\n // overlay: the row shows the draft — minus every server-assigned field\n // — until a reload. Deferring the write-back to after persistence makes\n // it the synced write TanStack is waiting for.\n //\n // `markConfirmedPresent` still runs immediately: the in-flight fetch\n // bookkeeping needs to know the rows are confirmed the moment the\n // server said so, not a tick later.\n //\n // The deferred write itself: a no-op until the collection is ready\n // (writing into the synced store before sync has initialized throws,\n // and with no live query there is nothing to keep in sync — the next\n // query fetches the already-persisted state; the transaction can\n // outlive the last subscriber), and it drops any row the store already\n // supersedes — a realtime echo may have landed a newer copy while the\n // transaction was settling, and writing the response over it would\n // revert the row.\n function writeBackAfterPersisted(\n transaction: { isPersisted: { promise: Promise<unknown> } },\n records: RecordType[]\n ): void {\n markConfirmedPresent(records)\n void transaction.isPersisted.promise.then(\n () => {\n if (!collection.utils || !collection.isReady()) return\n const fresh = records.filter(record => !isStaleServerRecord(record))\n if (fresh.length === 0) return\n writeOwn(() => collection.utils.writeUpsert(fresh))\n },\n // A rejected transaction rolled its draft back; there is\n // nothing to write and nothing to report here.\n () => undefined\n )\n }\n\n // Set while pbtsdb performs its own authoritative writes (mutation-response\n // write-backs and realtime echoes) through collection.utils.*. Those writes\n // share the same sync `write` primitive as the query-result reconcile path\n // (see the sync.sync wrapper below), so the guard uses this flag to tell them\n // apart: pbtsdb's own writes are exempt from the optimistic-pending arm of the\n // guard (the mutation-response write-back intentionally lands the confirmed\n // value while that very mutation's optimistic overlay is still in flight).\n let applyingOwnWrite = false\n function writeOwn(fn: () => void): void {\n applyingOwnWrite = true\n try {\n fn()\n } finally {\n applyingOwnWrite = false\n }\n }\n\n // The record id a synced insert/update targets, or null when the op is a delete\n // (terminal — never guarded) or carries no usable key.\n function syncedWriteKey(op: { type: string; value?: unknown; key?: unknown }): string | null {\n if (op.type !== 'insert' && op.type !== 'update') return null\n if (typeof op.key === 'string') return op.key\n const id = (op.value as { id?: unknown } | undefined)?.id\n return typeof id === 'string' ? id : null\n }\n\n // Guard the synced write path that pbtsdb does not otherwise control:\n // @tanstack/query-db-collection's applySuccessfulResult reconciles every query\n // result into the synced store via this same `write`, with no recency or\n // optimistic check. Under on-demand contention a single-row/subset read can\n // resolve with a pre-mutation row and land here after the row already moved on,\n // reverting it. We drop such a synced insert/update when either it targets a key\n // with a pending optimistic mutation (see the arm below) or it is strictly older\n // than the synced row (an out-of-order read). pbtsdb's own writes\n // (applyingOwnWrite) skip the optimistic arm; they are staleness-filtered\n // upstream by writeBackAfterPersisted/isStaleEcho.\n function shouldDropSyncedWrite(op: { type: string; value?: unknown; key?: unknown }): boolean {\n const key = syncedWriteKey(op)\n if (key === null) return false\n // Optimistic arm: only guard a key already present in the synced store. A\n // write to a key the synced store doesn't yet hold is populating it (e.g. the\n // initial fetch landing a row the user just optimistically inserted) and must\n // pass — dropping it would leave the row absent once the overlay clears. A\n // write to a key already synced, while an optimistic mutation is pending, is a\n // racing read that would revert the in-flight value, so drop it.\n if (\n !applyingOwnWrite &&\n hasPendingOptimisticMutation(key) &&\n collection._state.syncedData.has(key)\n ) {\n logger.debug('Dropping synced write for optimistically-pending row', {\n collectionName,\n id: key,\n })\n return true\n }\n if (isStaleServerRecord(op.value)) {\n logger.debug('Dropping stale synced write', { collectionName, id: key })\n return true\n }\n return false\n }\n\n // A view's subscription is tagged in viewPaths (see createView below); this\n // adds the view's expand paths to load options for a tagged subscription so\n // loadSubset/unloadSubset fetch (and later untrack) with the right `expand`.\n // A subscription's initial snapshot loads synchronously inside\n // collection.subscribeChanges, before that call returns the subscription\n // object a view tags in viewPaths — so that first loadSubset cannot yet be\n // looked up by identity. While a view's subscribeChanges call is on the\n // stack, its paths are used for load options with no tagged subscription;\n // every later call (untracked demand growth, unloadSubset) is tagged by then.\n let subscribingViewPaths: string[] | undefined\n\n function withViewExpand(opts: LoadSubsetOptions): LoadOptions {\n const paths =\n (opts.subscription && viewPaths.get(opts.subscription)) ?? subscribingViewPaths\n return paths ? { ...opts, expand: paths } : opts\n }\n\n // Merge a synced insert/update's value with any `expand` already stored for its\n // key, so a later write that omits `expand` (e.g. a plain fetch of the same row)\n // does not wipe an entry another query's view put there. Called only for an\n // insert/update carrying an object value; returns the value unchanged (by\n // identity) when there is nothing to carry.\n function mergedWriteValue(op: { type: string; value?: unknown; key?: unknown }): RecordType {\n const key = syncedWriteKey(op)\n const existing =\n key === null\n ? undefined\n : (collection._state.syncedData.get(key) as RecordType | undefined)\n return mergeExpand(op.value as RecordType, existing)\n }\n\n // Wrap the sync factory so every synced `write` flows through the guard above,\n // and every loadSubset/unloadSubset call is tagged with a view's expand paths.\n // @tanstack/db invokes sync.sync with the write primitives; we hand back the\n // same params with a filtered `write`. begin/commit/markReady/etc. pass through.\n const innerSync = collectionOptions.sync.sync\n collectionOptions.sync = {\n ...collectionOptions.sync,\n sync: (params: Parameters<typeof innerSync>[0]) => {\n const guardedWrite: typeof params.write = message => {\n const op = message as { type: string; value?: unknown; key?: unknown }\n if (shouldDropSyncedWrite(op)) return\n if (\n (op.type === 'insert' || op.type === 'update') &&\n op.value &&\n typeof op.value === 'object'\n ) {\n const merged = mergedWriteValue(op)\n if (merged !== op.value) return params.write({ ...message, value: merged })\n }\n return params.write(message)\n }\n const res = innerSync({ ...params, write: guardedWrite })\n if (!res || typeof res === 'function') return res\n const { loadSubset, unloadSubset } = res\n return {\n ...res,\n loadSubset: loadSubset\n ? (opts: LoadSubsetOptions) => loadSubset(withViewExpand(opts))\n : undefined,\n unloadSubset: unloadSubset\n ? (opts: LoadSubsetOptions) => unloadSubset(withViewExpand(opts))\n : undefined,\n }\n },\n }\n\n const collection = createTanStackCollection(collectionOptions)\n\n const relationDependents: RelationDependent[] = []\n for (const [field, target] of Object.entries(relationTargets ?? {})) {\n target.relationDependents ??= []\n target.relationDependents.push({\n field,\n parent: collection as unknown as ExpandTargetCollection,\n })\n }\n\n const views = new Map<string, object>()\n\n function createView(paths: string[]): object {\n const view = Object.create(collection)\n Object.defineProperties(view, {\n id: { value: `${collectionName}?expand=${paths.join(',')}` },\n subscribeChanges: {\n value: (...args: Parameters<typeof collection.subscribeChanges>) => {\n noteViewSubscribed(paths)\n subscribingViewPaths = paths\n try {\n const subscription = collection.subscribeChanges(...args)\n viewPaths.set(subscription, paths)\n return subscription\n } finally {\n subscribingViewPaths = undefined\n }\n },\n },\n expand: {\n value: () => {\n throw new Error(`A view of \"${collectionName}\" cannot be expanded further`)\n },\n },\n })\n return view\n }\n\n function expand(...paths: string[]): object {\n for (const path of paths) validateExpandPath(collectionName, relationTargets, path)\n const all = normalizePaths([...alwaysExpand, ...paths])\n if (all.every(path => alwaysExpand.includes(path))) return collection\n const key = all.join(',')\n let view = views.get(key)\n if (!view) {\n view = createView(all)\n views.set(key, view)\n }\n return view\n }\n\n // True when the key has an in-flight (not yet settled) optimistic mutation.\n // While pending, the optimistic overlay — not syncedData — is the visible value,\n // so any synced write would only take effect once the overlay collapses, and an\n // older/racing read landing here is exactly what reverts a just-applied move.\n function hasPendingOptimisticMutation(key: string): boolean {\n const state = collection._state as unknown as {\n optimisticUpserts: { has: (k: string) => boolean }\n optimisticDeletes: { has: (k: string) => boolean }\n }\n return state.optimisticUpserts.has(key) || state.optimisticDeletes.has(key)\n }\n\n // Read the PocketBase `updated` autodate from a record, if present.\n // Collections without an `updated` field opt out of staleness checks.\n function recordUpdatedAt(record: unknown): string | undefined {\n const updated = (record as { updated?: unknown } | null | undefined)?.updated\n return typeof updated === 'string' && updated !== '' ? updated : undefined\n }\n\n // A server record is stale relative to the synced store when an entry for\n // the same key already holds a newer `updated` timestamp. PocketBase can\n // redeliver or reorder realtime echoes (and a slow mutation response can\n // resolve after a newer echo), so applying an older write would revert the\n // row. ISO 8601 timestamps sort lexicographically, so string comparison is\n // chronological. When either side lacks a comparable timestamp we cannot\n // tell, so we treat the write as fresh and let it through.\n //\n // Strictly older, never equal. PocketBase stamps `updated` to the\n // millisecond and bumps it on every write, so an equal timestamp is the\n // same version of the row: re-landing it changes nothing, and it is what\n // lets a confirmed value clear a lingering optimistic overlay. (An earlier\n // `<=` variant on the query-result path guarded against a read carrying\n // old content under a new timestamp, which a real server cannot produce;\n // the revert it chased was the write-back racing its own transaction,\n // fixed in writeBackAfterPersisted.)\n function isStaleServerRecord(record: unknown): boolean {\n const id = (record as { id?: unknown } | null | undefined)?.id\n if (typeof id !== 'string') return false\n const incoming = recordUpdatedAt(record)\n if (!incoming) return false\n const current = recordUpdatedAt(\n collection._state.syncedData.get(id) as RecordType | undefined\n )\n if (current === undefined) return false\n return incoming < current\n }\n\n // Decide whether a realtime echo should be dropped as stale. Under realtime\n // contention PocketBase can redeliver or reorder events, so an echo carrying\n // a pre-mutation value can arrive after the row already moved on (e.g. the\n // local mutation that just wrote the fresh value back). Applying a\n // strictly-older create/update echo would revert the row, so it is ignored.\n // Deletes are terminal and not timestamp-guarded.\n function isStaleEcho(event: RecordSubscription<RecordType>): boolean {\n if (event.action !== 'create' && event.action !== 'update') return false\n if (!isStaleServerRecord(event.record)) return false\n logger.debug('Ignoring stale realtime echo', {\n collectionName,\n id: (event.record as { id?: string } | undefined)?.id,\n })\n return true\n }\n\n // Real-time subscription state\n let unsubscribeFn: (() => Promise<void>) | null = null\n let isSubscribed = false\n let subscriptionPromise: Promise<void> | null = null\n let subscriptionResolve: (() => void) | null = null\n // The `expand` string sent with the currently live subscription, so a\n // caller that widened requestedExpand mid-flight can tell whether the\n // subscription that just landed already covers it.\n let subscribedExpand: string | undefined\n\n // All start/stop/restart work is serialized onto this promise tail so\n // overlapping callers (two views created back-to-back, a reconnect\n // racing a widened expand) never run startSubscription/stopSubscription\n // concurrently — the tail is what lets a later caller's restart observe\n // the outcome of an earlier caller's in-flight start. Errors are caught\n // and logged so a failed step never poisons the tail for later work.\n let subscriptionWork: Promise<void> = Promise.resolve()\n function enqueueSubscriptionWork(fn: () => Promise<void>): Promise<void> {\n const run = subscriptionWork.then(fn, fn).catch(error => {\n logger.error('Subscription work failed', { collectionName, error })\n })\n subscriptionWork = run\n return run\n }\n\n // Handle real-time events from PocketBase.\n //\n // The write primitives differ in how they treat a key that is absent from\n // the *synced* store (collection._state.syncedData, which is what they\n // validate against — not the optimistic view exposed by collection.has()):\n // - writeInsert / writeUpsert: idempotent, never throw on an absent key.\n // - writeDelete: throws DeleteOperationItemNotFoundError on an absent key.\n // So only the delete branch can throw, and we make it idempotent below.\n // Runs BEFORE the stale-echo filter: even a stale create/update echo\n // proves the server holds the row. Delete echoes need no marking — the\n // merge checks the synced store, which the delete's writeDelete empties.\n function markEchoPresence(event: RecordSubscription<RecordType>): void {\n if (event.action !== 'delete') markConfirmedPresent([event.record])\n }\n\n const handleRealtimeEvent = (event: RecordSubscription<RecordType>) => {\n if (!collection.utils) return\n markEchoPresence(event)\n if (isStaleEcho(event)) return\n\n try {\n writeOwn(() =>\n collection.utils.writeBatch(() => {\n switch (event.action) {\n case 'create':\n collection.utils.writeInsert(event.record)\n break\n case 'update':\n collection.utils.writeUpsert(event.record)\n break\n case 'delete':\n if (event.record && 'id' in event.record) {\n // Throws DeleteOperationItemNotFoundError if the key\n // is no longer in the synced store (see catch below).\n collection.utils.writeDelete((event.record as { id: string }).id)\n }\n break\n }\n })\n )\n } catch (error) {\n // How a delete echo throws: writeDelete fails when its key is already\n // gone from the synced store. That happens when something removed it\n // before the echo arrived:\n // 1. on-demand sync — each useLiveQuery refetches with a server\n // filter, and query-db-collection prunes rows no longer owned by\n // any active query out of the synced store. If that prune (or a\n // concurrent query's reconcile) runs before this client's own\n // delete echo lands, the key is already gone -> throw. This is\n // the on-demand-only race; eager collections have no such second\n // writer to the synced store, so they cannot hit it.\n // 2. a re-delivered SSE delete (e.g. after a reconnect) for a key\n // that was already deleted -> throw on the second echo.\n // In both cases the record is already in its intended end state\n // (gone), so the echo is a no-op and the error is safe to ignore.\n // Anything that is NOT a missing-key delete is a real error: rethrow.\n if (error instanceof DeleteOperationItemNotFoundError) {\n logger.debug('Ignoring delete echo for already-removed record', {\n collectionName,\n id: (event.record as { id?: string } | undefined)?.id,\n })\n } else {\n throw error\n }\n }\n\n if (event.action !== 'delete') {\n upsertExpanded([event.record], relationTargets).catch(error =>\n logger.error('Failed to upsert expanded records from realtime echo', {\n collectionName,\n error,\n })\n )\n }\n\n propagateRelatedChange(\n collection as unknown as ExpandTargetCollection,\n event.action as RelatedAction,\n event.record as { id: string },\n new Set()\n )\n }\n\n // The union of expand paths the next (re)subscribe should carry:\n // alwaysExpand plus every path a view has requested. Pure and\n // side-effect-free (unlike realtimeSubscribeOptions below), so it is\n // safe to call more than once per subscribe attempt to detect drift.\n function pendingSubscribeExpand(): string | undefined {\n return joinPaths([...alwaysExpand, ...requestedExpand])\n }\n\n // Collections along every active expand path. Held live (below) so their\n // realtime echoes reach this collection's embedded copies.\n function activeExpandTargets(): Set<ExpandTargetCollection> {\n const targets = new Set<ExpandTargetCollection>()\n for (const path of splitPaths(pendingSubscribeExpand())) {\n let current: RelationTargets | undefined = relationTargets\n for (const segment of path.split('.')) {\n const target: ExpandTargetCollection | undefined = current?.[segment]\n if (!target) break\n targets.add(target)\n current = target.relationTargets\n }\n }\n return targets\n }\n\n // The only place held target subscriptions are added or removed, so the\n // map always mirrors the last desired set exactly.\n const heldTargetSubscriptions = new Map<ExpandTargetCollection, { unsubscribe: () => void }>()\n\n function releaseHeldTarget(target: ExpandTargetCollection): void {\n const held = heldTargetSubscriptions.get(target)\n if (!held) return\n heldTargetSubscriptions.delete(target)\n try {\n held.unsubscribe()\n } catch (error) {\n logger.error('Failed to release relation target subscription', {\n collectionName,\n error,\n })\n }\n }\n\n function holdTarget(target: ExpandTargetCollection): void {\n if (heldTargetSubscriptions.has(target) || !target.subscribeChanges) return\n try {\n const held = target.subscribeChanges(() => {}, { includeInitialState: false })\n heldTargetSubscriptions.set(target, held)\n } catch (error) {\n logger.error('Failed to hold relation target subscription', { collectionName, error })\n }\n }\n\n function syncHeldSubscriptions(desired: Set<ExpandTargetCollection>): void {\n for (const target of [...heldTargetSubscriptions.keys()]) {\n if (!desired.has(target)) releaseHeldTarget(target)\n }\n for (const target of desired) holdTarget(target)\n }\n\n // Options for the next (re)subscribe: the expand union above, merged\n // with whatever the factory's own subscribeOptions() supplies rather\n // than overridden by it. Calls the factory callback, so it is invoked\n // exactly once per subscribe attempt (never re-derived afterward).\n function realtimeSubscribeOptions(): RecordSubscribeOptions | undefined {\n const base = factoryOptions?.subscribeOptions?.()\n const expand = joinPaths([\n ...splitPaths(pendingSubscribeExpand()),\n ...splitPaths(base?.expand),\n ])\n return expand ? { ...base, expand } : base\n }\n\n // Start PocketBase real-time subscription. Only ever run through\n // enqueueSubscriptionWork so it never overlaps a stop/restart.\n const doStartSubscription = async () => {\n if (isSubscribed) return\n\n // Create promise before starting so waiters can await it\n if (!subscriptionPromise) {\n subscriptionPromise = new Promise<void>(resolve => {\n subscriptionResolve = resolve\n })\n }\n\n const pendingExpand = pendingSubscribeExpand()\n try {\n unsubscribeFn = await pb\n .collection(collectionName)\n .subscribe('*', handleRealtimeEvent, realtimeSubscribeOptions())\n isSubscribed = true\n subscribedExpand = pendingExpand\n syncHeldSubscriptions(activeExpandTargets())\n logger.debug('Subscription started', { collectionName })\n // Resolve the promise to notify waiters\n if (subscriptionResolve) {\n subscriptionResolve()\n }\n } catch (error) {\n logger.error('Failed to start subscription', { collectionName, error })\n }\n\n // requestedExpand can grow while the subscribe() call above was in\n // flight (a view mounted mid-round-trip sees no live subscription\n // yet, and would otherwise never schedule a restart). Comparing\n // against the pure expand union (not realtimeSubscribeOptions,\n // which would re-invoke the factory's own subscribeOptions()\n // callback) lets this check run after every start with no\n // observable side effect.\n if (pendingSubscribeExpand() !== subscribedExpand) {\n enqueueSubscriptionWork(doRestartSubscription).catch(() => {})\n }\n }\n\n // Stop PocketBase real-time subscription. Only ever run through\n // enqueueSubscriptionWork so it never overlaps a start/restart.\n const doStopSubscription = async (releaseTargets = true) => {\n // Before the guard below: a restart whose subscribe() threw leaves\n // isSubscribed false with targets still held, and this real stop is\n // the only remaining chance to release them.\n if (releaseTargets) syncHeldSubscriptions(new Set())\n if (!isSubscribed || !unsubscribeFn) return\n\n try {\n await unsubscribeFn()\n logger.debug('Subscription stopped', { collectionName })\n } catch (error) {\n logger.debug('Unsubscribe failed (expected if connection closed)', {\n collectionName,\n error,\n })\n } finally {\n // Unconditional: a throwing unsubscribe must not leave the state\n // machine believing it is still subscribed after targets were\n // released, or the next start would return early and never re-hold.\n unsubscribeFn = null\n isSubscribed = false\n subscribedExpand = undefined\n subscriptionPromise = null\n subscriptionResolve = null\n }\n }\n\n // Restart the live subscription, e.g. after the requested expand union\n // grows. A no-op when there is no live subscription to restart — the\n // next first-subscriber start already picks up the current union.\n const doRestartSubscription = async () => {\n if (!isSubscribed) return\n await doStopSubscription(false)\n await doStartSubscription()\n }\n\n const startSubscription = () => enqueueSubscriptionWork(doStartSubscription)\n const stopSubscription = () => enqueueSubscriptionWork(() => doStopSubscription())\n const restartSubscription = () => enqueueSubscriptionWork(doRestartSubscription)\n\n // Record which expand paths a view has subscribed with at least once.\n // Eager collections cannot request per-subset options, so a wider union\n // needs a refetch to pick up the new expand; a live realtime subscription\n // needs restarting so its own expand union grows too.\n function noteViewSubscribed(paths: string[]): void {\n let grew = false\n for (const path of paths) {\n if (requestedExpand.has(path)) continue\n requestedExpand.add(path)\n grew = true\n }\n if (!grew) return\n if (\n syncMode === 'eager' &&\n collection.status !== 'idle' &&\n collection.status !== 'cleaned-up'\n ) {\n void collection.utils.refetch().catch(error =>\n logger.error('Failed to refetch after widening expand', {\n collectionName,\n error,\n })\n )\n }\n // Enqueued unconditionally (not gated on isSubscribed): the tail\n // guarantees this runs after any in-flight start/stop, and\n // doRestartSubscription itself no-ops when nothing is live.\n restartSubscription().catch(error =>\n logger.error('Failed to restart subscription with wider expand', {\n collectionName,\n error,\n })\n )\n }\n\n // Wait for subscription to be established (for testing)\n const waitForSubscription = async (timeout = 5000): Promise<void> => {\n if (isSubscribed) return\n\n if (!subscriptionPromise) {\n // No subscription in progress, wait for one to start\n await new Promise<void>(resolve => {\n const checkInterval = setInterval(() => {\n if (subscriptionPromise) {\n clearInterval(checkInterval)\n resolve()\n }\n }, 10)\n setTimeout(() => {\n clearInterval(checkInterval)\n resolve()\n }, timeout)\n })\n }\n\n if (subscriptionPromise) {\n await Promise.race([\n subscriptionPromise,\n new Promise<void>((_, reject) =>\n setTimeout(() => reject(new Error('Subscription timeout')), timeout)\n ),\n ])\n }\n }\n\n // Manage subscription based on collection subscriber count\n collection.on(\n 'subscribers:change',\n (event: { subscriberCount: number; previousSubscriberCount: number }) => {\n const newCount = event.subscriberCount\n const previousCount = event.previousSubscriberCount\n\n if (newCount > 0 && previousCount === 0) {\n // First subscriber - start real-time subscription\n startSubscription().catch(() => {})\n } else if (newCount === 0 && previousCount > 0) {\n // Last subscriber removed - stop real-time subscription\n stopSubscription().catch(() => {})\n }\n }\n )\n\n // Add collectionName and subscription helpers\n Object.assign(collection, {\n collectionName,\n relationTargets,\n waitForSubscription,\n isSubscribed: () => isSubscribed,\n heldRelationTargetCount: () => heldTargetSubscriptions.size,\n expand,\n relationDependents,\n applyRelatedChange,\n })\n\n return collection as unknown as BuiltCollection<RecordType>\n}\n","import type { Collection } from '@tanstack/db'\nimport type { QueryCollectionUtils } from '@tanstack/query-db-collection'\nimport type { QueryClient } from '@tanstack/react-query'\nimport type PocketBase from 'pocketbase'\nimport { buildCollection, type CreateCollectionFactoryOptions } from './build-collection'\nimport type {\n AlwaysExpandOf,\n CreateCollectionOptions,\n ExpandPath,\n InsertInputOf,\n PbMeta,\n RelationsOf,\n SchemaDeclaration,\n WithExpandPaths,\n} from './types'\n\nexport type { CreateCollectionFactoryOptions } from './build-collection'\nexport type { BaseRecord, CreateCollectionOptions, SchemaDeclaration } from './types'\n\n/**\n * A pbtsdb collection or view: a TanStack DB collection whose rows carry the\n * expand paths in `Paths`, plus pbtsdb's subscription helpers.\n */\nexport type PbView<\n Schema extends SchemaDeclaration,\n C extends keyof Schema & string,\n Opts,\n Paths extends string,\n> = Collection<\n WithExpandPaths<Schema, C, RelationsOf<Opts>, Paths>,\n string | number,\n QueryCollectionUtils<\n WithExpandPaths<Schema, C, RelationsOf<Opts>, Paths>,\n string | number,\n WithExpandPaths<Schema, C, RelationsOf<Opts>, Paths>\n >,\n never,\n InsertInputOf<Schema, C, Opts>\n> & {\n /** The PocketBase collection name */\n readonly collectionName: C\n /** Wait for the real-time subscription to be established (useful in tests) */\n waitForSubscription: (timeout?: number) => Promise<void>\n /** Whether the collection has an active real-time subscription */\n isSubscribed: () => boolean\n /** @internal relation targets declared through `relations` */\n readonly relationTargets: Record<string, unknown> | undefined\n /** @internal number of relation targets currently held live */\n readonly heldRelationTargetCount: () => number\n /** @internal collections that declared this one in their `relations` */\n readonly relationDependents: readonly { field: string; parent: unknown }[]\n /** @internal patch rows for a relation target change; used by the target's realtime handler */\n readonly applyRelatedChange: (\n fields: readonly string[],\n action: 'create' | 'update' | 'delete',\n record: { id: string },\n visited: Set<string>\n ) => void\n /** @internal phantom; never present at runtime */\n readonly __pbtsdb: PbMeta<Schema, C, RelationsOf<Opts>>\n}\n\n/**\n * The collection returned by {@link createCollection}: a {@link PbView} over the\n * `alwaysExpand` paths, plus `expand()` for per-query views.\n */\nexport type PbCollection<\n Schema extends SchemaDeclaration,\n C extends keyof Schema & string,\n Opts,\n> = PbView<Schema, C, Opts, AlwaysExpandOf<Opts>> & {\n /**\n * A view of this collection whose queries also expand `paths`. Views share\n * this collection's store, realtime subscription, and mutations; only the\n * fetch differs. Paths must resolve through `relations`.\n *\n * @example\n * ```ts\n * const { data } = useLiveQuery(q => q.from({ books: books.expand('author') }))\n * data[0].expand?.author?.name\n * ```\n */\n expand<const P extends readonly ExpandPath<RelationsOf<Opts>>[]>(\n ...paths: P\n ): PbView<Schema, C, Opts, AlwaysExpandOf<Opts> | P[number]>\n}\n\ntype AlwaysExpandCheck<Opts> = {\n alwaysExpand?: readonly ExpandPath<RelationsOf<Opts>>[]\n}\n\n/**\n * Creates a type-safe TanStack DB collection backed by PocketBase.\n * Use this when you need fine-grained control or need to create collections with dependencies.\n *\n * @param pb - PocketBase client instance\n * @param queryClient - TanStack Query client\n * @returns A curried function that takes collection name and options\n *\n * @example\n * Basic usage:\n * ```ts\n * const booksCollection = createCollection<Schema>(pb, queryClient)('books', {});\n *\n * // Use directly\n * const books = await booksCollection.getFullList();\n * ```\n *\n * @example\n * With relations expanded on every fetch:\n * ```ts\n * const authorsCollection = createCollection<Schema>(pb, queryClient)('authors', {});\n * const booksCollection = createCollection<Schema>(pb, queryClient)('books', {\n * relations: { author: authorsCollection },\n * alwaysExpand: ['author'],\n * });\n *\n * const { data } = useLiveQuery((q) => q.from({ books: booksCollection }));\n * // data[0].expand?.author is typed and populated\n * ```\n *\n * @example\n * With a per-query expand view:\n * ```ts\n * const booksCollection = createCollection<Schema>(pb, queryClient)('books', {\n * relations: { author: authorsCollection },\n * });\n *\n * const { data } = useLiveQuery((q) => q.from({ books: booksCollection.expand('author') }));\n * // data[0].expand?.author is typed and populated for this query only\n * ```\n */\nexport function createCollection<Schema extends SchemaDeclaration>(\n pb: PocketBase,\n queryClient: QueryClient,\n factoryOptions?: CreateCollectionFactoryOptions\n) {\n return <C extends keyof Schema & string, const Opts extends CreateCollectionOptions<Schema, C>>(\n collectionName: C,\n options?: Opts & AlwaysExpandCheck<Opts>\n ): PbCollection<Schema, C, Opts> => {\n return buildCollection<Schema, C>({\n pb,\n queryClient,\n factoryOptions,\n collectionName,\n options,\n }) as unknown as PbCollection<Schema, C, Opts>\n }\n}\n","/**\n * Generates a new PocketBase-compatible record ID.\n * Returns a 15-character alphanumeric string (lowercase letters and numbers).\n *\n * PocketBase uses 15-character IDs for records, formatted as lowercase alphanumeric.\n *\n * @returns A 15-character alphanumeric string suitable for use as a PocketBase record ID\n *\n * @example\n * ```ts\n * const id = newRecordId(); // \"a1b2c3d4e5f6g7h\"\n * ```\n */\nexport function newRecordId(): string {\n const chars = 'abcdefghijklmnopqrstuvwxyz0123456789'\n let result = ''\n for (let i = 0; i < 15; i++) {\n result += chars.charAt(Math.floor(Math.random() * chars.length))\n }\n return result\n}\n"]}