pbtsdb 0.1.0 → 0.1.3

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 CHANGED
@@ -64,10 +64,10 @@ function convertToPocketBaseFilter(where) {
64
64
  return `!(${condition})`;
65
65
  },
66
66
  in: (field, values) => {
67
- if (!Array.isArray(values)) {
68
- values = [values];
69
- }
70
- const conditions = values.map((v) => `${fieldPathToString(field)} = ${escapeValue(v)}`);
67
+ const valueArray = Array.isArray(values) ? values : [values];
68
+ const uniqueValues = [...new Set(valueArray)];
69
+ const fieldStr = fieldPathToString(field);
70
+ const conditions = uniqueValues.map((v) => `${fieldStr} = ${escapeValue(v)}`);
71
71
  return conditions.length > 1 ? `(${conditions.join(" || ")})` : conditions[0];
72
72
  },
73
73
  like: (field, value) => {
@@ -143,15 +143,21 @@ function createCollection(pb, queryClient) {
143
143
  const sort = convertToPocketBaseSort(loadOptions?.orderBy);
144
144
  const limit = loadOptions?.limit;
145
145
  let items;
146
- if (!filter && !sort && !limit && !expandString) {
147
- items = await pb.collection(collectionName).getFullList();
148
- } else {
149
- const result = await pb.collection(collectionName).getList(1, limit || 500, {
146
+ if (limit) {
147
+ const result = await pb.collection(collectionName).getList(1, limit, {
150
148
  filter,
151
149
  sort,
150
+ skipTotal: true,
151
+ // Optimize by skipping total count
152
152
  expand: expandString
153
153
  });
154
154
  items = result.items;
155
+ } else {
156
+ items = await pb.collection(collectionName).getFullList({
157
+ filter,
158
+ sort,
159
+ expand: expandString
160
+ });
155
161
  }
156
162
  if (expandStores) {
157
163
  for (const record of items) {
@@ -227,7 +233,7 @@ function createCollection(pb, queryClient) {
227
233
  collection.utils.writeInsert(event.record);
228
234
  break;
229
235
  case "update":
230
- collection.utils.writeUpdate(event.record);
236
+ collection.utils.writeUpsert(event.record);
231
237
  break;
232
238
  case "delete":
233
239
  if (event.record && "id" in event.record) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/pocketbase-query-converter.ts","../src/logger.ts","../src/collection.ts","../src/react.tsx","../src/util.ts"],"names":["createTanStackCollection"],"mappings":"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","file":"index.js","sourcesContent":["import { parseWhereExpression, parseOrderByExpression, type FieldPath, type ParsedOrderBy } from '@tanstack/db';\nimport type { IR } from '@tanstack/db';\n\ntype BasicExpression<T = any> = IR.BasicExpression<T>;\n\nfunction escapeValue(value: any): 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: any) => {\n return `${fieldPathToString(field)} = ${escapeValue(value)}`;\n },\n gt: (field: FieldPath, value: any) => {\n return `${fieldPathToString(field)} > ${escapeValue(value)}`;\n },\n gte: (field: FieldPath, value: any) => {\n return `${fieldPathToString(field)} >= ${escapeValue(value)}`;\n },\n lt: (field: FieldPath, value: any) => {\n return `${fieldPathToString(field)} < ${escapeValue(value)}`;\n },\n lte: (field: FieldPath, value: any) => {\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: any[]) => {\n if (!Array.isArray(values)) {\n values = [values];\n }\n const conditions = values.map(v => `${fieldPathToString(field)} = ${escapeValue(v)}`);\n return conditions.length > 1 ? `(${conditions.join(' || ')})` : conditions[0];\n },\n like: (field: FieldPath, value: any) => {\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: any[]) => {\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","/**\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 // Only log debug in development\n if (process.env.NODE_ENV === 'development') {\n // biome-ignore lint/suspicious/noConsoleLog: Debug logging is acceptable in development\n console.log(`[pbtsdb] ${msg}`, context || '');\n }\n },\n info: (msg: string, context?: object) => {\n // biome-ignore lint/suspicious/noConsoleLog: Info logging is acceptable\n console.info(`[pbtsdb] ${msg}`, context || '');\n },\n warn: (msg: string, context?: object) => {\n // biome-ignore lint/suspicious/noConsoleLog: Warning logging is acceptable\n console.warn(`[pbtsdb] ${msg}`, context || '');\n },\n error: (msg: string, context?: object) => {\n // biome-ignore lint/suspicious/noConsoleLog: Error logging is acceptable\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 PocketBase from 'pocketbase';\nimport type { RecordSubscription } from 'pocketbase';\nimport { createCollection as createTanStackCollection, type Collection, type LoadSubsetOptions } from \"@tanstack/react-db\"\nimport { queryCollectionOptions, type QueryCollectionUtils } from \"@tanstack/query-db-collection\"\nimport { QueryClient } from '@tanstack/react-query'\nimport { convertToPocketBaseFilter, convertToPocketBaseSort } from './pocketbase-query-converter';\nimport type {\n SchemaDeclaration,\n CreateCollectionOptions,\n ExtractRecordType,\n ExpandTargetCollection,\n BaseRecord,\n} from './types';\nimport { logger } from './logger';\n\nexport type {\n SchemaDeclaration,\n CreateCollectionOptions,\n BaseRecord,\n} from './types';\n\n/**\n * Extended LoadSubsetOptions that includes PocketBase-specific expand parameter.\n * @internal\n */\ntype ExtendedLoadSubsetOptions = LoadSubsetOptions & {\n pbExpand?: string;\n};\n\n/**\n * Compute the record type with expand property when expand option is configured.\n * @internal\n */\ntype WithExpandFromConfig<\n Schema extends SchemaDeclaration,\n C extends keyof Schema,\n Opts\n> = Opts extends { expand: infer E }\n ? ExtractRecordType<Schema, C> & {\n expand?: {\n [K in keyof E]: K extends keyof import('./types').ExtractRelations<Schema, C>\n ? import('./types').ExtractRelations<Schema, C>[K] extends Array<infer U>\n ? U[]\n : import('./types').ExtractRelations<Schema, C>[K]\n : never;\n };\n }\n : ExtractRecordType<Schema, C>;\n\n/**\n * Subscription helpers added to collection instances.\n * @internal\n */\ninterface 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}\n\n/**\n * Inferred collection type from config options.\n * @internal\n */\ntype InferCollectionType<\n Schema extends SchemaDeclaration,\n C extends keyof Schema,\n Opts extends CreateCollectionOptions<Schema, C>\n> = Collection<\n WithExpandFromConfig<Schema, C, Opts>,\n string | number,\n // TUtils - QueryCollectionUtils from TanStack Query DB Collection\n QueryCollectionUtils<WithExpandFromConfig<Schema, C, Opts>, string | number, WithExpandFromConfig<Schema, C, Opts>>,\n // TSchema - we don't use StandardSchema validation\n never,\n Opts extends { omitOnInsert: infer O extends readonly import('./types').OmittableFields<ExtractRecordType<Schema, C>>[] }\n ? import('./types').ComputeInsertType<ExtractRecordType<Schema, C>, O>\n : ExtractRecordType<Schema, C>\n> & CollectionSubscriptionHelpers;\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 auto-expand relations:\n * ```ts\n * const authorsCollection = createCollection<Schema>(pb, queryClient)('authors', {});\n * const booksCollection = createCollection<Schema>(pb, queryClient)('books', {\n * expand: {\n * author: authorsCollection // Always expand, auto-upsert into authorsCollection\n * }\n * });\n *\n * // Expand is automatic - no .expand() call needed\n * const { data } = useLiveQuery((q) => q.from({ books: booksCollection }));\n * // data[0].expand.author is typed and populated\n * ```\n */\nexport function createCollection<Schema extends SchemaDeclaration>(\n pb: PocketBase,\n queryClient: QueryClient\n) {\n return <\n C extends keyof Schema & string,\n Opts extends CreateCollectionOptions<Schema, C> = CreateCollectionOptions<Schema, C>\n >(\n collectionName: C,\n options?: Opts\n ): InferCollectionType<Schema, C, Opts> => {\n type RecordType = ExtractRecordType<Schema, C>;\n const expandStores = options?.expand as Record<string, ExpandTargetCollection> | undefined;\n const expandString = expandStores ? Object.keys(expandStores).sort().join(',') : undefined;\n\n async function fetchRecords(loadOptions?: ExtendedLoadSubsetOptions): Promise<RecordType[]> {\n const filter = convertToPocketBaseFilter(loadOptions?.where);\n const sort = convertToPocketBaseSort(loadOptions?.orderBy);\n const limit = loadOptions?.limit;\n\n let items: RecordType[];\n if (!filter && !sort && !limit && !expandString) {\n items = await pb.collection(collectionName).getFullList() as unknown as RecordType[];\n } else {\n const result = await pb.collection(collectionName).getList(1, limit || 500, {\n filter,\n sort,\n expand: expandString,\n });\n items = result.items as unknown as RecordType[];\n }\n\n if (expandStores) {\n for (const record of items) {\n const expandData = (record as RecordType & { expand?: Record<string, object | object[]> }).expand;\n if (!expandData) continue;\n\n for (const [key, value] of Object.entries(expandData)) {\n const targetStore = expandStores[key];\n if (!targetStore.utils) continue;\n if (!targetStore.isReady()) {\n if (targetStore.config?.syncMode === 'on-demand') {\n await targetStore._sync.startSync();\n } else {\n logger.warn(`not syncing ${key} on ${collectionName} because store is not yet ready`)\n continue\n }\n }\n const values = Array.isArray(value) ? value : [value];\n targetStore.utils.writeUpsert(values);\n }\n }\n }\n\n return items;\n }\n\n const collectionOptions = queryCollectionOptions({\n queryClient,\n queryKey: [collectionName],\n syncMode: options?.syncMode ?? 'eager',\n queryFn: async (ctx): Promise<RecordType[]> => {\n return fetchRecords(ctx.meta?.loadSubsetOptions as ExtendedLoadSubsetOptions | undefined);\n },\n getKey: (item: RecordType) => {\n const record = item as any;\n if (!record || typeof record !== 'object' || !('id' in record)) {\n throw new Error(`Record in collection '${collectionName}' is missing required 'id' field. Received: ${JSON.stringify(item)}`);\n }\n return record.id;\n },\n onInsert: options?.onInsert === false ? undefined : options?.onInsert ?? (async ({ transaction }) => {\n await Promise.all(\n transaction.mutations.map(async (mutation) => {\n const { created, updated, collectionId, collectionName: _, ...data } = mutation.modified as unknown as Record<string, unknown>;\n await pb.collection(collectionName).create(data);\n })\n );\n }),\n onUpdate: options?.onUpdate === false ? undefined : options?.onUpdate ?? (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).update(recordWithId.id, mutation.changes);\n })\n );\n }),\n onDelete: options?.onDelete === false ? undefined : options?.onDelete ?? (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 })\n });\n\n const collection = createTanStackCollection(collectionOptions);\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\n // Handle real-time events from PocketBase\n const handleRealtimeEvent = (event: RecordSubscription<RecordType>) => {\n if (!collection.utils) return;\n\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.writeUpdate(event.record);\n break;\n case 'delete':\n if (event.record && 'id' in event.record) {\n collection.utils.writeDelete((event.record as { id: string }).id);\n }\n break;\n }\n });\n };\n\n // Start PocketBase real-time subscription\n const startSubscription = 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 try {\n unsubscribeFn = await pb.collection(collectionName).subscribe('*', handleRealtimeEvent);\n isSubscribed = true;\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\n // Stop PocketBase real-time subscription\n const stopSubscription = async () => {\n if (!isSubscribed || !unsubscribeFn) return;\n\n try {\n await unsubscribeFn();\n unsubscribeFn = null;\n isSubscribed = false;\n // Reset promise for next subscription cycle\n subscriptionPromise = null;\n subscriptionResolve = null;\n logger.debug('Subscription stopped', { collectionName });\n } catch (error) {\n logger.debug('Unsubscribe failed (expected if connection closed)', { collectionName, error });\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('subscribers:change', (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 // Add collectionName and subscription helpers\n Object.assign(collection, {\n collectionName,\n waitForSubscription,\n isSubscribed: () => isSubscribed,\n });\n\n return collection as any;\n };\n}\n\n","import React, { createContext, useContext, type ReactNode } 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 * expand: {\n * author: authors\n * }\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, any>>(\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('useStore must be used within the Provider returned by createReactProvider');\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","/**\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"]}
1
+ {"version":3,"sources":["../src/pocketbase-query-converter.ts","../src/logger.ts","../src/collection.ts","../src/react.tsx","../src/util.ts"],"names":["createTanStackCollection"],"mappings":"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","file":"index.js","sourcesContent":["import { parseWhereExpression, parseOrderByExpression, type FieldPath, type ParsedOrderBy } from '@tanstack/db';\nimport type { IR } 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","/**\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 // Only log debug in development\n if (process.env.NODE_ENV === 'development') {\n // biome-ignore lint/suspicious/noConsoleLog: Debug logging is acceptable in development\n console.log(`[pbtsdb] ${msg}`, context || '');\n }\n },\n info: (msg: string, context?: object) => {\n // biome-ignore lint/suspicious/noConsoleLog: Info logging is acceptable\n console.info(`[pbtsdb] ${msg}`, context || '');\n },\n warn: (msg: string, context?: object) => {\n // biome-ignore lint/suspicious/noConsoleLog: Warning logging is acceptable\n console.warn(`[pbtsdb] ${msg}`, context || '');\n },\n error: (msg: string, context?: object) => {\n // biome-ignore lint/suspicious/noConsoleLog: Error logging is acceptable\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 PocketBase from 'pocketbase';\nimport type { RecordSubscription } from 'pocketbase';\nimport { createCollection as createTanStackCollection, type Collection, type LoadSubsetOptions } from \"@tanstack/react-db\"\nimport { queryCollectionOptions, type QueryCollectionUtils } from \"@tanstack/query-db-collection\"\nimport { QueryClient } from '@tanstack/react-query'\nimport { convertToPocketBaseFilter, convertToPocketBaseSort } from './pocketbase-query-converter';\nimport type {\n SchemaDeclaration,\n CreateCollectionOptions,\n ExtractRecordType,\n ExpandTargetCollection,\n BaseRecord,\n} from './types';\nimport { logger } from './logger';\n\nexport type {\n SchemaDeclaration,\n CreateCollectionOptions,\n BaseRecord,\n} from './types';\n\n/**\n * Extended LoadSubsetOptions that includes PocketBase-specific expand parameter.\n * @internal\n */\ntype ExtendedLoadSubsetOptions = LoadSubsetOptions & {\n pbExpand?: string;\n};\n\n/**\n * Compute the record type with expand property when expand option is configured.\n * @internal\n */\ntype WithExpandFromConfig<\n Schema extends SchemaDeclaration,\n C extends keyof Schema,\n Opts\n> = Opts extends { expand: infer E }\n ? ExtractRecordType<Schema, C> & {\n expand?: {\n [K in keyof E]: K extends keyof import('./types').ExtractRelations<Schema, C>\n ? import('./types').ExtractRelations<Schema, C>[K] extends Array<infer U>\n ? U[]\n : import('./types').ExtractRelations<Schema, C>[K]\n : never;\n };\n }\n : ExtractRecordType<Schema, C>;\n\n/**\n * Subscription helpers added to collection instances.\n * @internal\n */\ninterface 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}\n\n/**\n * Inferred collection type from config options.\n * @internal\n */\ntype InferCollectionType<\n Schema extends SchemaDeclaration,\n C extends keyof Schema,\n Opts extends CreateCollectionOptions<Schema, C>\n> = Collection<\n WithExpandFromConfig<Schema, C, Opts>,\n string | number,\n // TUtils - QueryCollectionUtils from TanStack Query DB Collection\n QueryCollectionUtils<WithExpandFromConfig<Schema, C, Opts>, string | number, WithExpandFromConfig<Schema, C, Opts>>,\n // TSchema - we don't use StandardSchema validation\n never,\n Opts extends { omitOnInsert: infer O extends readonly import('./types').OmittableFields<ExtractRecordType<Schema, C>>[] }\n ? import('./types').ComputeInsertType<ExtractRecordType<Schema, C>, O>\n : ExtractRecordType<Schema, C>\n> & CollectionSubscriptionHelpers;\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 auto-expand relations:\n * ```ts\n * const authorsCollection = createCollection<Schema>(pb, queryClient)('authors', {});\n * const booksCollection = createCollection<Schema>(pb, queryClient)('books', {\n * expand: {\n * author: authorsCollection // Always expand, auto-upsert into authorsCollection\n * }\n * });\n *\n * // Expand is automatic - no .expand() call needed\n * const { data } = useLiveQuery((q) => q.from({ books: booksCollection }));\n * // data[0].expand.author is typed and populated\n * ```\n */\nexport function createCollection<Schema extends SchemaDeclaration>(\n pb: PocketBase,\n queryClient: QueryClient\n) {\n return <\n C extends keyof Schema & string,\n Opts extends CreateCollectionOptions<Schema, C> = CreateCollectionOptions<Schema, C>\n >(\n collectionName: C,\n options?: Opts\n ): InferCollectionType<Schema, C, Opts> => {\n type RecordType = ExtractRecordType<Schema, C>;\n const expandStores = options?.expand as Record<string, ExpandTargetCollection> | undefined;\n const expandString = expandStores ? Object.keys(expandStores).sort().join(',') : undefined;\n\n async function fetchRecords(loadOptions?: ExtendedLoadSubsetOptions): Promise<RecordType[]> {\n const filter = convertToPocketBaseFilter(loadOptions?.where);\n const sort = convertToPocketBaseSort(loadOptions?.orderBy);\n const limit = loadOptions?.limit;\n\n let items: RecordType[];\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: expandString,\n });\n items = result.items as unknown as RecordType[];\n } else {\n // Use getFullList to fetch all records with automatic pagination\n items = await pb.collection(collectionName).getFullList({\n filter,\n sort,\n expand: expandString,\n }) as unknown as RecordType[];\n }\n\n if (expandStores) {\n for (const record of items) {\n const expandData = (record as RecordType & { expand?: Record<string, object | object[]> }).expand;\n if (!expandData) continue;\n\n for (const [key, value] of Object.entries(expandData)) {\n const targetStore = expandStores[key];\n if (!targetStore.utils) continue;\n if (!targetStore.isReady()) {\n if (targetStore.config?.syncMode === 'on-demand') {\n await targetStore._sync.startSync();\n } else {\n logger.warn(`not syncing ${key} on ${collectionName} because store is not yet ready`)\n continue\n }\n }\n const values = Array.isArray(value) ? value : [value];\n targetStore.utils.writeUpsert(values);\n }\n }\n }\n\n return items;\n }\n\n const collectionOptions = queryCollectionOptions({\n queryClient,\n queryKey: [collectionName],\n syncMode: options?.syncMode ?? 'eager',\n queryFn: async (ctx): Promise<RecordType[]> => {\n return fetchRecords(ctx.meta?.loadSubsetOptions as ExtendedLoadSubsetOptions | undefined);\n },\n getKey: (item: RecordType) => {\n const record = item as any;\n if (!record || typeof record !== 'object' || !('id' in record)) {\n throw new Error(`Record in collection '${collectionName}' is missing required 'id' field. Received: ${JSON.stringify(item)}`);\n }\n return record.id;\n },\n onInsert: options?.onInsert === false ? undefined : options?.onInsert ?? (async ({ transaction }) => {\n await Promise.all(\n transaction.mutations.map(async (mutation) => {\n const { created, updated, collectionId, collectionName: _, ...data } = mutation.modified as unknown as Record<string, unknown>;\n await pb.collection(collectionName).create(data);\n })\n );\n }),\n onUpdate: options?.onUpdate === false ? undefined : options?.onUpdate ?? (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).update(recordWithId.id, mutation.changes);\n })\n );\n }),\n onDelete: options?.onDelete === false ? undefined : options?.onDelete ?? (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 })\n });\n\n const collection = createTanStackCollection(collectionOptions);\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\n // Handle real-time events from PocketBase\n const handleRealtimeEvent = (event: RecordSubscription<RecordType>) => {\n if (!collection.utils) return;\n\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 collection.utils.writeDelete((event.record as { id: string }).id);\n }\n break;\n }\n });\n };\n\n // Start PocketBase real-time subscription\n const startSubscription = 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 try {\n unsubscribeFn = await pb.collection(collectionName).subscribe('*', handleRealtimeEvent);\n isSubscribed = true;\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\n // Stop PocketBase real-time subscription\n const stopSubscription = async () => {\n if (!isSubscribed || !unsubscribeFn) return;\n\n try {\n await unsubscribeFn();\n unsubscribeFn = null;\n isSubscribed = false;\n // Reset promise for next subscription cycle\n subscriptionPromise = null;\n subscriptionResolve = null;\n logger.debug('Subscription stopped', { collectionName });\n } catch (error) {\n logger.debug('Unsubscribe failed (expected if connection closed)', { collectionName, error });\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('subscribers:change', (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 // Add collectionName and subscription helpers\n Object.assign(collection, {\n collectionName,\n waitForSubscription,\n isSubscribed: () => isSubscribed,\n });\n\n return collection as any;\n };\n}\n\n","import React, { createContext, useContext, type ReactNode } 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 * expand: {\n * author: authors\n * }\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, any>>(\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('useStore must be used within the Provider returned by createReactProvider');\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","/**\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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pbtsdb",
3
- "version": "0.1.0",
3
+ "version": "0.1.3",
4
4
  "description": "Type-safe PocketBase integration with TanStack Query and TanStack DB",
5
5
  "keywords": [
6
6
  "pocketbase",