@pol-studios/db 1.0.31 → 1.0.34

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.
Files changed (107) hide show
  1. package/dist/{DataLayerContext-Dc7nF2IG.d.ts → DataLayerContext-BwMk4VpG.d.ts} +92 -8
  2. package/dist/UserMetadataContext-QLIv-mfF.d.ts +171 -0
  3. package/dist/{UserMetadataContext-B8gVWGMl.d.ts → UserMetadataContext-pQb3A8_Q.d.ts} +1 -1
  4. package/dist/auth/context.d.ts +53 -5
  5. package/dist/auth/context.js +30 -8
  6. package/dist/auth/guards.d.ts +9 -9
  7. package/dist/auth/guards.js +2 -3
  8. package/dist/auth/hooks.d.ts +108 -4
  9. package/dist/auth/hooks.js +13 -9
  10. package/dist/auth/index.d.ts +6 -6
  11. package/dist/auth/index.js +45 -17
  12. package/dist/chunk-5HJLTYRA.js +355 -0
  13. package/dist/chunk-5HJLTYRA.js.map +1 -0
  14. package/dist/{chunk-WX4ABYIF.js → chunk-67HMVGV7.js} +292 -94
  15. package/dist/chunk-67HMVGV7.js.map +1 -0
  16. package/dist/chunk-6KN7KLEG.js +1 -0
  17. package/dist/{chunk-FZF26ZRB.js → chunk-7BGDQT5X.js} +29 -16
  18. package/dist/{chunk-FZF26ZRB.js.map → chunk-7BGDQT5X.js.map} +1 -1
  19. package/dist/{chunk-P4UZ7IXC.js → chunk-7D4SUZUM.js} +1 -5
  20. package/dist/{chunk-3PJTNH2L.js → chunk-AKIRHA4Q.js} +2 -2
  21. package/dist/{chunk-OQ7U6EQ3.js → chunk-AML2TLXJ.js} +3801 -3424
  22. package/dist/chunk-AML2TLXJ.js.map +1 -0
  23. package/dist/{chunk-5EFDS7SR.js → chunk-DMVUEJG2.js} +7 -2
  24. package/dist/chunk-DMVUEJG2.js.map +1 -0
  25. package/dist/{chunk-ADD5MIMK.js → chunk-FESQS4S5.js} +15 -15
  26. package/dist/{chunk-ADD5MIMK.js.map → chunk-FESQS4S5.js.map} +1 -1
  27. package/dist/{chunk-U5UNPBKB.js → chunk-FI6JAD5G.js} +3 -3
  28. package/dist/{chunk-TKWR5AAY.js → chunk-JOULSXOI.js} +2 -2
  29. package/dist/{chunk-HTJ2FQW5.js → chunk-LF3V3ERS.js} +13 -15
  30. package/dist/{chunk-HTJ2FQW5.js.map → chunk-LF3V3ERS.js.map} +1 -1
  31. package/dist/{chunk-5BLKZUKM.js → chunk-MREERKQU.js} +45 -14
  32. package/dist/chunk-MREERKQU.js.map +1 -0
  33. package/dist/{chunk-VGEMLNNM.js → chunk-NP34C3O3.js} +306 -704
  34. package/dist/chunk-NP34C3O3.js.map +1 -0
  35. package/dist/{chunk-CNIGRBRE.js → chunk-QJZUIAHA.js} +43 -19
  36. package/dist/{chunk-CNIGRBRE.js.map → chunk-QJZUIAHA.js.map} +1 -1
  37. package/dist/{chunk-HAWJTZCK.js → chunk-RT4O5H2E.js} +5 -7
  38. package/dist/chunk-RT4O5H2E.js.map +1 -0
  39. package/dist/{chunk-2NVSXZKQ.js → chunk-TN7QINPK.js} +74 -309
  40. package/dist/chunk-TN7QINPK.js.map +1 -0
  41. package/dist/chunk-UBHORKBS.js +215 -0
  42. package/dist/chunk-UBHORKBS.js.map +1 -0
  43. package/dist/{chunk-WVF7RUW5.js → chunk-WM25QE7E.js} +3 -3
  44. package/dist/{chunk-H6365JPC.js → chunk-YUX6RGLZ.js} +3 -3
  45. package/dist/{chunk-H6365JPC.js.map → chunk-YUX6RGLZ.js.map} +1 -1
  46. package/dist/{chunk-H3LNH2NT.js → chunk-Z456IHCB.js} +5 -9
  47. package/dist/{chunk-H3LNH2NT.js.map → chunk-Z456IHCB.js.map} +1 -1
  48. package/dist/{chunk-JAATANS3.js → chunk-ZCOFRJQD.js} +3 -3
  49. package/dist/{chunk-JAATANS3.js.map → chunk-ZCOFRJQD.js.map} +1 -1
  50. package/dist/client/index.d.ts +1 -1
  51. package/dist/client/index.js +2 -2
  52. package/dist/core/index.d.ts +54 -31
  53. package/dist/{executor-Br27YZvl.d.ts → executor-YJw4m7Q7.d.ts} +9 -1
  54. package/dist/gen/index.js +1 -1
  55. package/dist/hooks/index.d.ts +3 -22
  56. package/dist/hooks/index.js +12 -9
  57. package/dist/{index-CYFdO0iB.d.ts → index-lveh8qb0.d.ts} +1 -1
  58. package/dist/index.d.ts +38 -10
  59. package/dist/index.js +57 -36
  60. package/dist/index.native.d.ts +19 -13
  61. package/dist/index.native.js +64 -35
  62. package/dist/index.web.d.ts +18 -45
  63. package/dist/index.web.js +58 -49
  64. package/dist/index.web.js.map +1 -1
  65. package/dist/mutation/index.d.ts +2 -2
  66. package/dist/mutation/index.js +5 -5
  67. package/dist/parser/index.js +4 -4
  68. package/dist/powersync-bridge/index.d.ts +18 -3
  69. package/dist/powersync-bridge/index.js +2 -2
  70. package/dist/query/index.d.ts +1 -1
  71. package/dist/query/index.js +7 -8
  72. package/dist/realtime/index.js +7 -9
  73. package/dist/realtime/index.js.map +1 -1
  74. package/dist/types/index.d.ts +3 -3
  75. package/dist/types/index.js +6 -7
  76. package/dist/{useBatchUpsert-9OYjibLh.d.ts → useBatchUpsert-DAkiCNo3.d.ts} +1 -1
  77. package/dist/{useDbCount-Dk0yCKlT.d.ts → useDbCount-DWfYB2iu.d.ts} +16 -2
  78. package/dist/{useResolveFeedback-C1KucfdQ.d.ts → useResolveFeedback-CxLccZKK.d.ts} +197 -93
  79. package/dist/{useSupabase-DvWVuHHE.d.ts → useSupabase-DSZNeXnF.d.ts} +1 -1
  80. package/dist/with-auth/index.d.ts +2 -2
  81. package/dist/with-auth/index.js +46 -33
  82. package/dist/with-auth/index.js.map +1 -1
  83. package/package.json +18 -8
  84. package/dist/UserMetadataContext-DntmpK41.d.ts +0 -33
  85. package/dist/canvas-C4TBBDUL.node +0 -0
  86. package/dist/canvas-ZQNCL7JL.js +0 -1541
  87. package/dist/canvas-ZQNCL7JL.js.map +0 -1
  88. package/dist/chunk-2NVSXZKQ.js.map +0 -1
  89. package/dist/chunk-5BLKZUKM.js.map +0 -1
  90. package/dist/chunk-5EFDS7SR.js.map +0 -1
  91. package/dist/chunk-HAWJTZCK.js.map +0 -1
  92. package/dist/chunk-NSIAAYW3.js +0 -1
  93. package/dist/chunk-O7SETNGD.js +0 -3391
  94. package/dist/chunk-O7SETNGD.js.map +0 -1
  95. package/dist/chunk-OQ7U6EQ3.js.map +0 -1
  96. package/dist/chunk-VGEMLNNM.js.map +0 -1
  97. package/dist/chunk-WX4ABYIF.js.map +0 -1
  98. package/dist/dist-NDNRSNOG.js +0 -521
  99. package/dist/dist-NDNRSNOG.js.map +0 -1
  100. package/dist/pdf-PHXP7RHD.js +0 -20336
  101. package/dist/pdf-PHXP7RHD.js.map +0 -1
  102. /package/dist/{chunk-NSIAAYW3.js.map → chunk-6KN7KLEG.js.map} +0 -0
  103. /package/dist/{chunk-P4UZ7IXC.js.map → chunk-7D4SUZUM.js.map} +0 -0
  104. /package/dist/{chunk-3PJTNH2L.js.map → chunk-AKIRHA4Q.js.map} +0 -0
  105. /package/dist/{chunk-U5UNPBKB.js.map → chunk-FI6JAD5G.js.map} +0 -0
  106. /package/dist/{chunk-TKWR5AAY.js.map → chunk-JOULSXOI.js.map} +0 -0
  107. /package/dist/{chunk-WVF7RUW5.js.map → chunk-WM25QE7E.js.map} +0 -0
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  generateUUID,
6
6
  useSupabase
7
- } from "./chunk-5EFDS7SR.js";
7
+ } from "./chunk-DMVUEJG2.js";
8
8
 
9
9
  // src/useSupabaseFunction.ts
10
10
  import { c as _c } from "react/compiler-runtime";
@@ -87,7 +87,7 @@ import { useState, useCallback } from "react";
87
87
  var pdfjsLib = null;
88
88
  async function getPdfJs() {
89
89
  if (!pdfjsLib) {
90
- pdfjsLib = await import("./pdf-PHXP7RHD.js");
90
+ pdfjsLib = await import("pdfjs-dist");
91
91
  pdfjsLib.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjsLib.version}/build/pdf.worker.min.mjs`;
92
92
  }
93
93
  return pdfjsLib;
@@ -426,4 +426,4 @@ export {
426
426
  useSupabaseFunction,
427
427
  useReceiptAI_default
428
428
  };
429
- //# sourceMappingURL=chunk-JAATANS3.js.map
429
+ //# sourceMappingURL=chunk-ZCOFRJQD.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/useSupabaseFunction.ts","../src/useReceiptAI.ts"],"sourcesContent":["import { c as _c } from \"react/compiler-runtime\";\nimport { getSupabaseUrl } from \"./config\";\nimport useSupabase, { typedSupabase } from \"./useSupabase\";\nexport default function useSupabaseFunction() {\n const $ = _c(2);\n const supabase = useSupabase();\n let t0;\n if ($[0] !== supabase) {\n const downloadFunctionResponse = async function downloadFunctionResponse(functionName, body, name) {\n const {\n data,\n error\n } = await supabase.auth.getSession();\n if (error || !data.session) {\n console.error(\"Error retrieving session:\", error);\n return;\n }\n const accessToken = data.session.access_token;\n const response = await fetch(`${getSupabaseUrl()}/functions/v1/${functionName}`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": body && \"application/json\",\n Authorization: `Bearer ${accessToken}`\n },\n body: body && JSON.stringify(body)\n });\n if (!response.ok) {\n console.error(\"Error downloading invoice:\", response.statusText);\n return;\n }\n const contentDisposition = response.headers.get(\"Content-Disposition\");\n const mimeType = response.headers.get(\"Content-Type\") || \"application/octet-stream\";\n const filename = name ? name : (contentDisposition && contentDisposition.split(\"filename=\")[1]) ?? \"Unknown\";\n await downloadFile(response.body as any, filename, mimeType);\n };\n t0 = {\n downloadFunctionResponse\n };\n $[0] = supabase;\n $[1] = t0;\n } else {\n t0 = $[1];\n }\n return t0;\n}\nasync function downloadFile(stream: ReadableStream<Uint8Array> | null, filename: string, mimeType: string) {\n if (!stream) return;\n const reader = stream.getReader();\n const a = document.createElement(\"a\");\n a.style.display = \"none\";\n document.body.appendChild(a);\n try {\n const chunks = [];\n while (true) {\n const {\n done,\n value\n } = await reader.read();\n if (done) break;\n chunks.push(value);\n }\n const blob = new Blob(chunks, {\n type: mimeType\n });\n const url = window.URL.createObjectURL(blob);\n a.href = url;\n a.download = filename;\n a.click();\n window.URL.revokeObjectURL(url);\n } catch (error) {\n console.error(\"Error downloading file:\", error);\n } finally {\n document.body.removeChild(a);\n reader.releaseLock();\n }\n}\n\n// Invoke Supabase Edge Function with response streaming","import { useState, useCallback } from \"react\";\nimport useSupabase from \"./useSupabase\";\nimport { generateUUID } from \"./utils/uuid\";\nimport { Tables } from \"./database.types\";\n\n// Lazy-load PDF.js to avoid top-level side effects that break React Native\nlet pdfjsLib: typeof import(\"pdfjs-dist\") | null = null;\nasync function getPdfJs() {\n if (!pdfjsLib) {\n pdfjsLib = await import(\"pdfjs-dist\");\n pdfjsLib.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjsLib.version}/build/pdf.worker.min.mjs`;\n }\n return pdfjsLib;\n}\n\n// Schema for receipt extraction\nconst receiptSchema = {\n type: \"object\",\n properties: {\n merchantName: {\n type: \"string\",\n description: \"The merchant or vendor name from the receipt\"\n },\n transactionDate: {\n type: [\"string\", \"null\"],\n description: \"Transaction date in YYYY-MM-DD format, or null if not found\"\n },\n currency: {\n type: \"string\",\n description: \"Currency code (USD, EUR, GBP, CAD, etc.) or symbol ($, €, £)\"\n },\n subtotal: {\n type: [\"number\", \"null\"],\n description: \"Subtotal before tax, or null if not found\"\n },\n tax: {\n type: [\"number\", \"null\"],\n description: \"Tax amount, or null if not found\"\n },\n total: {\n type: \"number\",\n description: \"Total amount including tax\"\n },\n lineItems: {\n type: \"array\",\n description: \"Individual items on the receipt\",\n items: {\n type: \"object\",\n properties: {\n description: {\n type: \"string\",\n description: \"Item description\"\n },\n amount: {\n type: \"number\",\n description: \"Item amount/price\"\n },\n quantity: {\n type: [\"number\", \"null\"],\n description: \"Quantity if shown\"\n },\n suggestedCategory: {\n type: [\"string\", \"null\"],\n description: \"Suggested expense category (e.g., 'Meals', 'Transportation', 'Supplies', 'Equipment', 'Lodging', 'Utilities', 'Entertainment', 'Office Supplies')\"\n }\n },\n required: [\"description\", \"amount\", \"quantity\", \"suggestedCategory\"],\n additionalProperties: false\n }\n },\n confidence: {\n type: \"number\",\n description: \"Confidence score from 0 to 1 for the extraction quality\"\n },\n notes: {\n type: [\"string\", \"null\"],\n description: \"Any additional notes or context extracted from the receipt\"\n }\n },\n required: [\"merchantName\", \"transactionDate\", \"currency\", \"subtotal\", \"tax\", \"total\", \"lineItems\", \"confidence\", \"notes\"],\n additionalProperties: false\n};\nexport interface ExtractedReceipt {\n merchantName: string;\n transactionDate: string | null;\n currency: string;\n subtotal: number | null;\n tax: number | null;\n total: number;\n lineItems: Array<{\n description: string;\n amount: number;\n quantity: number | null;\n suggestedCategory: string | null;\n }>;\n confidence: number;\n notes: string | null;\n}\n\n// Types for batch processing\nexport interface PendingExpense {\n id: string; // temporary UUID for tracking\n file: File;\n status: \"processing\" | \"ready\" | \"error\" | \"confirming\";\n extractedData: ExtractedReceipt | null;\n error: string | null;\n duplicateWarning?: {\n existingExpenseId: number;\n reason: string;\n };\n}\nexport interface BatchAnalysisProgress {\n total: number;\n completed: number;\n processing: string[]; // file names currently processing\n}\ninterface AIResponse<T> {\n success: boolean;\n data?: T;\n model?: string;\n usage?: {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n };\n error?: string;\n errorCode?: string;\n}\ninterface RecentExpenseContext {\n merchantName: string;\n category: string | null;\n amount: number;\n}\ninterface UseReceiptAIOptions {\n recentExpenses?: RecentExpenseContext[];\n taxCategories?: Tables<\"TaxCategory\">[];\n}\n\n// Helper to generate UUID for pending expenses\nfunction generateId(): string {\n return generateUUID();\n}\nexport function useReceiptAI(options: UseReceiptAIOptions = {}) {\n const supabase = useSupabase();\n const [isAnalyzing, setIsAnalyzing] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [extractedData, setExtractedData] = useState<ExtractedReceipt | null>(null);\n // Batch processing state\n const [batchProgress, setBatchProgress] = useState<BatchAnalysisProgress | null>(null);\n const analyzeReceipt = useCallback(async (file: File): Promise<ExtractedReceipt | null> => {\n setIsAnalyzing(true);\n setError(null);\n try {\n // Convert file to base64\n const base64 = await fileToBase64(file);\n\n // Build context from recent expenses\n const context: Record<string, unknown> = {};\n if (options.recentExpenses && options.recentExpenses.length > 0) {\n context.recentExpensePatterns = options.recentExpenses.slice(0, 10);\n context.hint = \"Use recent expense patterns to help match merchant names and suggest categories based on user's history\";\n }\n if (options.taxCategories && options.taxCategories.length > 0) {\n context.availableCategories = options.taxCategories.map(c => c.title);\n context.categoryHint = \"When suggesting categories for line items, try to match one of the available categories\";\n }\n\n // Call the AI function\n const response = await supabase.functions.invoke<AIResponse<ExtractedReceipt>>(\"ai\", {\n body: {\n prompt: `Extract receipt data. Use official merchant names for known chains. Match categories from availableCategories when possible.`,\n context,\n files: [{\n source: \"base64\",\n data: base64,\n // PDFs and images are all converted to JPEG\n mimeType: file.type === \"application/pdf\" || file.type.startsWith(\"image/\") ? \"image/jpeg\" : file.type,\n fileName: file.name\n }],\n outputSchema: {\n name: \"receipt_extraction\",\n description: \"Structured data extracted from a receipt image or document\",\n schema: receiptSchema\n },\n options: {\n maxTokens: 5000\n }\n }\n });\n if (response.error) {\n throw new Error(`AI function error: ${response.error.message}`);\n }\n if (!response.data?.success) {\n throw new Error(response.data?.error || \"Failed to analyze receipt\");\n }\n const extracted = response.data.data!;\n setExtractedData(extracted);\n return extracted;\n } catch (err) {\n const message = err instanceof Error ? err.message : \"Unknown error\";\n setError(message);\n console.error(\"Receipt analysis error:\", err);\n return null;\n } finally {\n setIsAnalyzing(false);\n }\n }, [supabase, options.recentExpenses, options.taxCategories]);\n const reset = useCallback(() => {\n setExtractedData(null);\n setError(null);\n setBatchProgress(null);\n }, []);\n\n // Analyze a single file without updating shared state (for batch processing)\n const analyzeReceiptInternal = useCallback(async (file_0: File): Promise<ExtractedReceipt | null> => {\n try {\n const base64_0 = await fileToBase64(file_0);\n const context_0: Record<string, unknown> = {};\n if (options.recentExpenses && options.recentExpenses.length > 0) {\n context_0.recentExpensePatterns = options.recentExpenses.slice(0, 10);\n context_0.hint = \"Use recent expense patterns to help match merchant names and suggest categories based on user's history\";\n }\n if (options.taxCategories && options.taxCategories.length > 0) {\n context_0.availableCategories = options.taxCategories.map(c_0 => c_0.title);\n context_0.categoryHint = \"When suggesting categories for line items, try to match one of the available categories\";\n }\n const response_0 = await supabase.functions.invoke<AIResponse<ExtractedReceipt>>(\"ai\", {\n body: {\n prompt: `Extract receipt data. Use official merchant names for known chains. Match categories from availableCategories when possible.`,\n context: context_0,\n files: [{\n source: \"base64\",\n data: base64_0,\n // PDFs and images are all converted to JPEG\n mimeType: file_0.type === \"application/pdf\" || file_0.type.startsWith(\"image/\") ? \"image/jpeg\" : file_0.type,\n fileName: file_0.name\n }],\n outputSchema: {\n name: \"receipt_extraction\",\n description: \"Structured data extracted from a receipt image or document\",\n schema: receiptSchema\n },\n options: {\n maxTokens: 5000\n }\n }\n });\n if (response_0.error) {\n throw new Error(`AI function error: ${response_0.error.message}`);\n }\n if (!response_0.data?.success) {\n throw new Error(response_0.data?.error || \"Failed to analyze receipt\");\n }\n return response_0.data.data!;\n } catch (err_0) {\n console.error(\"Receipt analysis error:\", err_0);\n throw err_0;\n }\n }, [supabase, options.recentExpenses, options.taxCategories]);\n\n // Batch analyze multiple receipts with concurrency control\n const analyzeMultipleReceipts = useCallback(async (files: File[], onProgress?: (progress: BatchAnalysisProgress) => void, onItemComplete?: (item: PendingExpense) => void): Promise<PendingExpense[]> => {\n const CONCURRENCY_LIMIT = 3;\n const results: PendingExpense[] = [];\n const progress: BatchAnalysisProgress = {\n total: files.length,\n completed: 0,\n processing: []\n };\n setBatchProgress(progress);\n onProgress?.(progress);\n\n // Initialize all pending expenses\n const pendingItems: PendingExpense[] = files.map(file_1 => ({\n id: generateId(),\n file: file_1,\n status: \"processing\" as const,\n extractedData: null,\n error: null\n }));\n\n // Process files with concurrency limit\n const queue = [...pendingItems];\n const inProgress: Promise<void>[] = [];\n const processNext = async (): Promise<void> => {\n if (queue.length === 0) return;\n const pending = queue.shift()!;\n progress.processing.push(pending.file.name);\n setBatchProgress({\n ...progress\n });\n onProgress?.({\n ...progress\n });\n try {\n const extracted_0 = await analyzeReceiptInternal(pending.file);\n pending.extractedData = extracted_0;\n pending.status = \"ready\";\n } catch (err_1) {\n pending.error = err_1 instanceof Error ? err_1.message : \"Unknown error\";\n pending.status = \"error\";\n }\n\n // Update progress\n progress.completed++;\n progress.processing = progress.processing.filter(name => name !== pending.file.name);\n setBatchProgress({\n ...progress\n });\n onProgress?.({\n ...progress\n });\n\n // Notify caller immediately when this item completes\n onItemComplete?.(pending);\n results.push(pending);\n\n // Process next in queue\n if (queue.length > 0) {\n await processNext();\n }\n };\n\n // Start initial batch of concurrent processes\n for (let i = 0; i < Math.min(CONCURRENCY_LIMIT, files.length); i++) {\n inProgress.push(processNext());\n }\n\n // Wait for all to complete\n await Promise.all(inProgress);\n setBatchProgress(null);\n return pendingItems;\n }, [analyzeReceiptInternal]);\n return {\n analyzeReceipt,\n analyzeMultipleReceipts,\n isAnalyzing,\n batchProgress,\n error,\n extractedData,\n reset\n };\n}\n\n// Helper to render PDF to image\nasync function pdfToImage(file: File, maxDimension = 1200): Promise<string> {\n const pdfjs = await getPdfJs();\n const arrayBuffer = await file.arrayBuffer();\n const pdf = await pdfjs.getDocument({\n data: arrayBuffer\n }).promise;\n\n // Get first page (receipts are typically single page)\n const page = await pdf.getPage(1);\n\n // Calculate scale to fit within maxDimension while maintaining aspect ratio\n const viewport = page.getViewport({\n scale: 1\n });\n const scale = Math.min(maxDimension / viewport.width, maxDimension / viewport.height, 1.5);\n const scaledViewport = page.getViewport({\n scale\n });\n\n // Create canvas and render\n const canvas = document.createElement(\"canvas\");\n canvas.width = scaledViewport.width;\n canvas.height = scaledViewport.height;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n throw new Error(\"Could not get canvas context\");\n }\n\n // White background for PDFs\n ctx.fillStyle = \"#ffffff\";\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n await page.render({\n canvasContext: ctx,\n viewport: scaledViewport\n }).promise;\n\n // Convert to base64 JPEG (smaller file size than PNG)\n const dataUrl = canvas.toDataURL(\"image/jpeg\", 0.9);\n const base64 = dataUrl.split(\",\")[1];\n console.log(`📄 PDF rendered: ${Math.round(scaledViewport.width)}x${Math.round(scaledViewport.height)} (scale: ${scale.toFixed(2)}, ~${Math.round(base64.length / 1024)}KB)`);\n return base64;\n}\n\n// Helper to resize image and convert to base64\nasync function fileToBase64(file: File, maxDimension = 1024): Promise<string> {\n // For PDFs, render to image first\n if (file.type === \"application/pdf\") {\n return pdfToImage(file, 1200);\n }\n\n // For non-image files (other than PDF), just convert directly\n if (!file.type.startsWith(\"image/\")) {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => {\n const result = reader.result as string;\n const base64 = result.split(\",\")[1];\n resolve(base64);\n };\n reader.onerror = reject;\n reader.readAsDataURL(file);\n });\n }\n\n // For images, resize first\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => {\n // Calculate new dimensions\n let {\n width,\n height\n } = img;\n if (width > maxDimension || height > maxDimension) {\n if (width > height) {\n height = Math.round(height * maxDimension / width);\n width = maxDimension;\n } else {\n width = Math.round(width * maxDimension / height);\n height = maxDimension;\n }\n }\n\n // Draw to canvas\n const canvas = document.createElement(\"canvas\");\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n reject(new Error(\"Could not get canvas context\"));\n return;\n }\n ctx.drawImage(img, 0, 0, width, height);\n\n // Convert to base64 (JPEG at 85% quality for smaller size)\n const dataUrl = canvas.toDataURL(\"image/jpeg\", 0.85);\n const base64 = dataUrl.split(\",\")[1];\n console.log(`📷 Image resized: ${img.width}x${img.height} → ${width}x${height}`);\n resolve(base64);\n };\n img.onerror = reject;\n img.src = URL.createObjectURL(file);\n });\n}\nexport default useReceiptAI;"],"mappings":"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","names":["downloadFunctionResponse"]}
1
+ {"version":3,"sources":["../src/useSupabaseFunction.ts","../src/useReceiptAI.ts"],"sourcesContent":["import { c as _c } from \"react/compiler-runtime\";\nimport { getSupabaseUrl } from \"./config\";\nimport useSupabase, { typedSupabase } from \"./useSupabase\";\nexport default function useSupabaseFunction() {\n const $ = _c(2);\n const supabase = useSupabase();\n let t0;\n if ($[0] !== supabase) {\n const downloadFunctionResponse = async function downloadFunctionResponse(functionName, body, name) {\n const {\n data,\n error\n } = await supabase.auth.getSession();\n if (error || !data.session) {\n console.error(\"Error retrieving session:\", error);\n return;\n }\n const accessToken = data.session.access_token;\n const response = await fetch(`${getSupabaseUrl()}/functions/v1/${functionName}`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": body && \"application/json\",\n Authorization: `Bearer ${accessToken}`\n },\n body: body && JSON.stringify(body)\n });\n if (!response.ok) {\n console.error(\"Error downloading invoice:\", response.statusText);\n return;\n }\n const contentDisposition = response.headers.get(\"Content-Disposition\");\n const mimeType = response.headers.get(\"Content-Type\") || \"application/octet-stream\";\n const filename = name ? name : (contentDisposition && contentDisposition.split(\"filename=\")[1]) ?? \"Unknown\";\n await downloadFile(response.body as any, filename, mimeType);\n };\n t0 = {\n downloadFunctionResponse\n };\n $[0] = supabase;\n $[1] = t0;\n } else {\n t0 = $[1];\n }\n return t0;\n}\nasync function downloadFile(stream: ReadableStream<Uint8Array> | null, filename: string, mimeType: string) {\n if (!stream) return;\n const reader = stream.getReader();\n const a = document.createElement(\"a\");\n a.style.display = \"none\";\n document.body.appendChild(a);\n try {\n const chunks = [];\n while (true) {\n const {\n done,\n value\n } = await reader.read();\n if (done) break;\n chunks.push(value);\n }\n const blob = new Blob(chunks, {\n type: mimeType\n });\n const url = window.URL.createObjectURL(blob);\n a.href = url;\n a.download = filename;\n a.click();\n window.URL.revokeObjectURL(url);\n } catch (error) {\n console.error(\"Error downloading file:\", error);\n } finally {\n document.body.removeChild(a);\n reader.releaseLock();\n }\n}\n\n// Invoke Supabase Edge Function with response streaming","import { useState, useCallback } from \"react\";\nimport useSupabase from \"./useSupabase\";\nimport { generateUUID } from \"./utils/uuid\";\nimport { Tables } from \"./database.types\";\n\n// Lazy-load PDF.js to avoid top-level side effects that break React Native\nlet pdfjsLib: typeof import(\"pdfjs-dist\") | null = null;\nasync function getPdfJs() {\n if (!pdfjsLib) {\n pdfjsLib = await import(\"pdfjs-dist\");\n pdfjsLib.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjsLib.version}/build/pdf.worker.min.mjs`;\n }\n return pdfjsLib;\n}\n\n// Schema for receipt extraction\nconst receiptSchema = {\n type: \"object\",\n properties: {\n merchantName: {\n type: \"string\",\n description: \"The merchant or vendor name from the receipt\"\n },\n transactionDate: {\n type: [\"string\", \"null\"],\n description: \"Transaction date in YYYY-MM-DD format, or null if not found\"\n },\n currency: {\n type: \"string\",\n description: \"Currency code (USD, EUR, GBP, CAD, etc.) or symbol ($, €, £)\"\n },\n subtotal: {\n type: [\"number\", \"null\"],\n description: \"Subtotal before tax, or null if not found\"\n },\n tax: {\n type: [\"number\", \"null\"],\n description: \"Tax amount, or null if not found\"\n },\n total: {\n type: \"number\",\n description: \"Total amount including tax\"\n },\n lineItems: {\n type: \"array\",\n description: \"Individual items on the receipt\",\n items: {\n type: \"object\",\n properties: {\n description: {\n type: \"string\",\n description: \"Item description\"\n },\n amount: {\n type: \"number\",\n description: \"Item amount/price\"\n },\n quantity: {\n type: [\"number\", \"null\"],\n description: \"Quantity if shown\"\n },\n suggestedCategory: {\n type: [\"string\", \"null\"],\n description: \"Suggested expense category (e.g., 'Meals', 'Transportation', 'Supplies', 'Equipment', 'Lodging', 'Utilities', 'Entertainment', 'Office Supplies')\"\n }\n },\n required: [\"description\", \"amount\", \"quantity\", \"suggestedCategory\"],\n additionalProperties: false\n }\n },\n confidence: {\n type: \"number\",\n description: \"Confidence score from 0 to 1 for the extraction quality\"\n },\n notes: {\n type: [\"string\", \"null\"],\n description: \"Any additional notes or context extracted from the receipt\"\n }\n },\n required: [\"merchantName\", \"transactionDate\", \"currency\", \"subtotal\", \"tax\", \"total\", \"lineItems\", \"confidence\", \"notes\"],\n additionalProperties: false\n};\nexport interface ExtractedReceipt {\n merchantName: string;\n transactionDate: string | null;\n currency: string;\n subtotal: number | null;\n tax: number | null;\n total: number;\n lineItems: Array<{\n description: string;\n amount: number;\n quantity: number | null;\n suggestedCategory: string | null;\n }>;\n confidence: number;\n notes: string | null;\n}\n\n// Types for batch processing\nexport interface PendingExpense {\n id: string; // temporary UUID for tracking\n file: File;\n status: \"processing\" | \"ready\" | \"error\" | \"confirming\";\n extractedData: ExtractedReceipt | null;\n error: string | null;\n duplicateWarning?: {\n existingExpenseId: number;\n reason: string;\n };\n}\nexport interface BatchAnalysisProgress {\n total: number;\n completed: number;\n processing: string[]; // file names currently processing\n}\ninterface AIResponse<T> {\n success: boolean;\n data?: T;\n model?: string;\n usage?: {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n };\n error?: string;\n errorCode?: string;\n}\ninterface RecentExpenseContext {\n merchantName: string;\n category: string | null;\n amount: number;\n}\ninterface UseReceiptAIOptions {\n recentExpenses?: RecentExpenseContext[];\n taxCategories?: Tables<\"TaxCategory\">[];\n}\n\n// Helper to generate UUID for pending expenses\nfunction generateId(): string {\n return generateUUID();\n}\nexport function useReceiptAI(options: UseReceiptAIOptions = {}) {\n const supabase = useSupabase();\n const [isAnalyzing, setIsAnalyzing] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [extractedData, setExtractedData] = useState<ExtractedReceipt | null>(null);\n // Batch processing state\n const [batchProgress, setBatchProgress] = useState<BatchAnalysisProgress | null>(null);\n const analyzeReceipt = useCallback(async (file: File): Promise<ExtractedReceipt | null> => {\n setIsAnalyzing(true);\n setError(null);\n try {\n // Convert file to base64\n const base64 = await fileToBase64(file);\n\n // Build context from recent expenses\n const context: Record<string, unknown> = {};\n if (options.recentExpenses && options.recentExpenses.length > 0) {\n context.recentExpensePatterns = options.recentExpenses.slice(0, 10);\n context.hint = \"Use recent expense patterns to help match merchant names and suggest categories based on user's history\";\n }\n if (options.taxCategories && options.taxCategories.length > 0) {\n context.availableCategories = options.taxCategories.map(c => c.title);\n context.categoryHint = \"When suggesting categories for line items, try to match one of the available categories\";\n }\n\n // Call the AI function\n const response = await supabase.functions.invoke<AIResponse<ExtractedReceipt>>(\"ai\", {\n body: {\n prompt: `Extract receipt data. Use official merchant names for known chains. Match categories from availableCategories when possible.`,\n context,\n files: [{\n source: \"base64\",\n data: base64,\n // PDFs and images are all converted to JPEG\n mimeType: file.type === \"application/pdf\" || file.type.startsWith(\"image/\") ? \"image/jpeg\" : file.type,\n fileName: file.name\n }],\n outputSchema: {\n name: \"receipt_extraction\",\n description: \"Structured data extracted from a receipt image or document\",\n schema: receiptSchema\n },\n options: {\n maxTokens: 5000\n }\n }\n });\n if (response.error) {\n throw new Error(`AI function error: ${response.error.message}`);\n }\n if (!response.data?.success) {\n throw new Error(response.data?.error || \"Failed to analyze receipt\");\n }\n const extracted = response.data.data!;\n setExtractedData(extracted);\n return extracted;\n } catch (err) {\n const message = err instanceof Error ? err.message : \"Unknown error\";\n setError(message);\n console.error(\"Receipt analysis error:\", err);\n return null;\n } finally {\n setIsAnalyzing(false);\n }\n }, [supabase, options.recentExpenses, options.taxCategories]);\n const reset = useCallback(() => {\n setExtractedData(null);\n setError(null);\n setBatchProgress(null);\n }, []);\n\n // Analyze a single file without updating shared state (for batch processing)\n const analyzeReceiptInternal = useCallback(async (file_0: File): Promise<ExtractedReceipt | null> => {\n try {\n const base64_0 = await fileToBase64(file_0);\n const context_0: Record<string, unknown> = {};\n if (options.recentExpenses && options.recentExpenses.length > 0) {\n context_0.recentExpensePatterns = options.recentExpenses.slice(0, 10);\n context_0.hint = \"Use recent expense patterns to help match merchant names and suggest categories based on user's history\";\n }\n if (options.taxCategories && options.taxCategories.length > 0) {\n context_0.availableCategories = options.taxCategories.map(c_0 => c_0.title);\n context_0.categoryHint = \"When suggesting categories for line items, try to match one of the available categories\";\n }\n const response_0 = await supabase.functions.invoke<AIResponse<ExtractedReceipt>>(\"ai\", {\n body: {\n prompt: `Extract receipt data. Use official merchant names for known chains. Match categories from availableCategories when possible.`,\n context: context_0,\n files: [{\n source: \"base64\",\n data: base64_0,\n // PDFs and images are all converted to JPEG\n mimeType: file_0.type === \"application/pdf\" || file_0.type.startsWith(\"image/\") ? \"image/jpeg\" : file_0.type,\n fileName: file_0.name\n }],\n outputSchema: {\n name: \"receipt_extraction\",\n description: \"Structured data extracted from a receipt image or document\",\n schema: receiptSchema\n },\n options: {\n maxTokens: 5000\n }\n }\n });\n if (response_0.error) {\n throw new Error(`AI function error: ${response_0.error.message}`);\n }\n if (!response_0.data?.success) {\n throw new Error(response_0.data?.error || \"Failed to analyze receipt\");\n }\n return response_0.data.data!;\n } catch (err_0) {\n console.error(\"Receipt analysis error:\", err_0);\n throw err_0;\n }\n }, [supabase, options.recentExpenses, options.taxCategories]);\n\n // Batch analyze multiple receipts with concurrency control\n const analyzeMultipleReceipts = useCallback(async (files: File[], onProgress?: (progress: BatchAnalysisProgress) => void, onItemComplete?: (item: PendingExpense) => void): Promise<PendingExpense[]> => {\n const CONCURRENCY_LIMIT = 3;\n const results: PendingExpense[] = [];\n const progress: BatchAnalysisProgress = {\n total: files.length,\n completed: 0,\n processing: []\n };\n setBatchProgress(progress);\n onProgress?.(progress);\n\n // Initialize all pending expenses\n const pendingItems: PendingExpense[] = files.map(file_1 => ({\n id: generateId(),\n file: file_1,\n status: \"processing\" as const,\n extractedData: null,\n error: null\n }));\n\n // Process files with concurrency limit\n const queue = [...pendingItems];\n const inProgress: Promise<void>[] = [];\n const processNext = async (): Promise<void> => {\n if (queue.length === 0) return;\n const pending = queue.shift()!;\n progress.processing.push(pending.file.name);\n setBatchProgress({\n ...progress\n });\n onProgress?.({\n ...progress\n });\n try {\n const extracted_0 = await analyzeReceiptInternal(pending.file);\n pending.extractedData = extracted_0;\n pending.status = \"ready\";\n } catch (err_1) {\n pending.error = err_1 instanceof Error ? err_1.message : \"Unknown error\";\n pending.status = \"error\";\n }\n\n // Update progress\n progress.completed++;\n progress.processing = progress.processing.filter(name => name !== pending.file.name);\n setBatchProgress({\n ...progress\n });\n onProgress?.({\n ...progress\n });\n\n // Notify caller immediately when this item completes\n onItemComplete?.(pending);\n results.push(pending);\n\n // Process next in queue\n if (queue.length > 0) {\n await processNext();\n }\n };\n\n // Start initial batch of concurrent processes\n for (let i = 0; i < Math.min(CONCURRENCY_LIMIT, files.length); i++) {\n inProgress.push(processNext());\n }\n\n // Wait for all to complete\n await Promise.all(inProgress);\n setBatchProgress(null);\n return pendingItems;\n }, [analyzeReceiptInternal]);\n return {\n analyzeReceipt,\n analyzeMultipleReceipts,\n isAnalyzing,\n batchProgress,\n error,\n extractedData,\n reset\n };\n}\n\n// Helper to render PDF to image\nasync function pdfToImage(file: File, maxDimension = 1200): Promise<string> {\n const pdfjs = await getPdfJs();\n const arrayBuffer = await file.arrayBuffer();\n const pdf = await pdfjs.getDocument({\n data: arrayBuffer\n }).promise;\n\n // Get first page (receipts are typically single page)\n const page = await pdf.getPage(1);\n\n // Calculate scale to fit within maxDimension while maintaining aspect ratio\n const viewport = page.getViewport({\n scale: 1\n });\n const scale = Math.min(maxDimension / viewport.width, maxDimension / viewport.height, 1.5);\n const scaledViewport = page.getViewport({\n scale\n });\n\n // Create canvas and render\n const canvas = document.createElement(\"canvas\");\n canvas.width = scaledViewport.width;\n canvas.height = scaledViewport.height;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n throw new Error(\"Could not get canvas context\");\n }\n\n // White background for PDFs\n ctx.fillStyle = \"#ffffff\";\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n await page.render({\n canvasContext: ctx,\n viewport: scaledViewport\n }).promise;\n\n // Convert to base64 JPEG (smaller file size than PNG)\n const dataUrl = canvas.toDataURL(\"image/jpeg\", 0.9);\n const base64 = dataUrl.split(\",\")[1];\n console.log(`📄 PDF rendered: ${Math.round(scaledViewport.width)}x${Math.round(scaledViewport.height)} (scale: ${scale.toFixed(2)}, ~${Math.round(base64.length / 1024)}KB)`);\n return base64;\n}\n\n// Helper to resize image and convert to base64\nasync function fileToBase64(file: File, maxDimension = 1024): Promise<string> {\n // For PDFs, render to image first\n if (file.type === \"application/pdf\") {\n return pdfToImage(file, 1200);\n }\n\n // For non-image files (other than PDF), just convert directly\n if (!file.type.startsWith(\"image/\")) {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => {\n const result = reader.result as string;\n const base64 = result.split(\",\")[1];\n resolve(base64);\n };\n reader.onerror = reject;\n reader.readAsDataURL(file);\n });\n }\n\n // For images, resize first\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => {\n // Calculate new dimensions\n let {\n width,\n height\n } = img;\n if (width > maxDimension || height > maxDimension) {\n if (width > height) {\n height = Math.round(height * maxDimension / width);\n width = maxDimension;\n } else {\n width = Math.round(width * maxDimension / height);\n height = maxDimension;\n }\n }\n\n // Draw to canvas\n const canvas = document.createElement(\"canvas\");\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n reject(new Error(\"Could not get canvas context\"));\n return;\n }\n ctx.drawImage(img, 0, 0, width, height);\n\n // Convert to base64 (JPEG at 85% quality for smaller size)\n const dataUrl = canvas.toDataURL(\"image/jpeg\", 0.85);\n const base64 = dataUrl.split(\",\")[1];\n console.log(`📷 Image resized: ${img.width}x${img.height} → ${width}x${height}`);\n resolve(base64);\n };\n img.onerror = reject;\n img.src = URL.createObjectURL(file);\n });\n}\nexport default useReceiptAI;"],"mappings":"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","names":["downloadFunctionResponse"]}
@@ -1,4 +1,4 @@
1
- export { C as ClientInstanceId, D as Database, S as SupabaseDatabaseTypes, a as SupabaseProvider, T as TypedSupabaseClient, U as UserSessionId, c as createNewSupabaseClient, o as onSupabaseInitialized, s as setDefaultOptions, t as typedSupabase, u as useSupabase } from '../useSupabase-DvWVuHHE.js';
1
+ export { C as ClientInstanceId, D as Database, S as SupabaseDatabaseTypes, a as SupabaseProvider, T as TypedSupabaseClient, U as UserSessionId, c as createNewSupabaseClient, o as onSupabaseInitialized, s as setDefaultOptions, t as typedSupabase, u as useSupabase } from '../useSupabase-DSZNeXnF.js';
2
2
  import 'react/jsx-runtime';
3
3
  import '@supabase/supabase-js/dist/module/lib/types.js';
4
4
  import 'react';
@@ -11,8 +11,8 @@ import {
11
11
  setSupabaseUrl,
12
12
  typedSupabase,
13
13
  useSupabase
14
- } from "../chunk-5EFDS7SR.js";
15
- import "../chunk-P4UZ7IXC.js";
14
+ } from "../chunk-DMVUEJG2.js";
15
+ import "../chunk-7D4SUZUM.js";
16
16
 
17
17
  // src/client/useFunction.ts
18
18
  import { c as _c } from "react/compiler-runtime";
@@ -132,7 +132,7 @@ interface ConnectionConfig {
132
132
  /** Supabase anonymous key */
133
133
  anonKey: string;
134
134
  };
135
- powerSync: {
135
+ powerSync?: {
136
136
  /** PowerSync service URL */
137
137
  url: string;
138
138
  };
@@ -148,9 +148,19 @@ interface ScopeDefinition {
148
148
  parameterKey?: string;
149
149
  }
150
150
  /**
151
- * Sync mode determines when and how syncing occurs
151
+ * Sync schedule determines when syncing occurs.
152
+ *
153
+ * NOTE: This type was renamed from SyncMode to SyncSchedule to avoid
154
+ * collision with @pol-studios/powersync's SyncMode type which controls
155
+ * HOW data flows (push-pull vs pull-only vs offline).
156
+ *
157
+ * This type controls WHEN syncing happens:
158
+ * - "manual" - only sync when explicitly requested
159
+ * - "onForeground" - sync when app comes to foreground
160
+ * - "periodic" - sync at regular intervals
161
+ * - "live" - maintain continuous sync connection
152
162
  */
153
- type SyncMode =
163
+ type SyncSchedule =
154
164
  /** Manual - only sync when explicitly requested */
155
165
  "manual"
156
166
  /** On foreground - sync when app comes to foreground */
@@ -178,8 +188,12 @@ interface DataLayerConfig<DB = unknown> {
178
188
  };
179
189
  /** Default settings */
180
190
  defaults: {
181
- /** Default sync mode */
182
- syncMode: SyncMode;
191
+ /**
192
+ * Default sync schedule - controls WHEN syncing occurs.
193
+ * Use SyncSchedule type for new code.
194
+ * @see SyncSchedule
195
+ */
196
+ syncMode: SyncSchedule;
183
197
  /** Interval for periodic sync in milliseconds (default: 300000 = 5 min) */
184
198
  periodicIntervalMs?: number;
185
199
  };
@@ -358,23 +372,6 @@ interface SyncStatus {
358
372
  /** Any sync error */
359
373
  error: Error | null;
360
374
  }
361
- /**
362
- * Failed upload entry - represents a change that failed to sync
363
- */
364
- interface FailedUpload {
365
- id: string;
366
- table: string;
367
- operation: 'PUT' | 'PATCH' | 'DELETE';
368
- data: Record<string, unknown>;
369
- error: {
370
- message: string;
371
- code?: string;
372
- category: 'transient' | 'permanent' | 'unknown';
373
- };
374
- retryCount: number;
375
- lastAttempt: number;
376
- nextRetryAt: number;
377
- }
378
375
  /**
379
376
  * Controls for managing sync behavior
380
377
  */
@@ -391,18 +388,44 @@ interface SyncControl {
391
388
  * @param values - Array of values (e.g., project IDs)
392
389
  */
393
390
  setScope: (scopeName: string, values: string[]) => Promise<void>;
394
- /** Manually retry all failed uploads */
395
- retryFailedUploads: () => Promise<void>;
396
- /** Clear/discard all failed uploads without retrying */
397
- clearFailedUploads: () => void;
398
- /** Reactive list of failed uploads */
399
- failedUploads: FailedUpload[];
400
- /** Pause automatic retries of failed uploads */
391
+ /**
392
+ * Pause automatic retries of failed uploads.
393
+ *
394
+ * When wired to PowerSyncProvider, this calls connector.pauseAutoRetry()
395
+ * which prevents the connector from retrying failed transactions during
396
+ * the next uploadData() call.
397
+ *
398
+ * Use this when:
399
+ * - User is actively resolving conflicts
400
+ * - User wants to go offline intentionally
401
+ * - Manual control over sync timing is needed
402
+ */
401
403
  pauseAutoRetry: () => void;
402
- /** Resume automatic retries of failed uploads */
404
+ /**
405
+ * Resume automatic retries of failed uploads.
406
+ *
407
+ * When wired to PowerSyncProvider, this calls connector.resumeAutoRetry()
408
+ * which allows the connector to resume retrying failed transactions.
409
+ */
403
410
  resumeAutoRetry: () => void;
404
411
  /** Whether automatic retries are currently paused */
405
412
  isAutoRetryPaused: boolean;
413
+ /**
414
+ * Add a pending mutation to the list.
415
+ * Called by mutation hooks BEFORE the write operation for optimistic updates.
416
+ */
417
+ addPendingMutation: (entry: {
418
+ id: string;
419
+ table: string;
420
+ op: string;
421
+ opData?: unknown;
422
+ createdAt?: Date;
423
+ }) => void;
424
+ /**
425
+ * Remove a pending mutation from the list.
426
+ * Called by mutation hooks when a write fails, or by sync when transaction completes.
427
+ */
428
+ removePendingMutation: (id: string) => void;
406
429
  }
407
430
  /**
408
431
  * Interface that all data adapters must implement
@@ -565,4 +588,4 @@ interface BuiltQuery {
565
588
  params: (string | number | boolean | null)[];
566
589
  }
567
590
 
568
- export type { AdapterRegistry, AutoStrategy, BuiltQuery, CachedStrategy, ColumnInfo, ColumnType, ConnectionConfig, DataAdapter, DataLayerConfig, DataLayerHooks, DatabaseSchema, DeleteMutationResult, ExtractInsert, ExtractRow, ExtractUpdate, FailedUpload, HybridStrategy, MutationHookResult, MutationResult, OrderBy, ParsedSelect, PowerSyncStrategy, QueryOptions, QueryResult, QuerySingleResult, RelationshipInfo, RelationshipType, ResolvedRelationship, ScopeDefinition, SelectColumn, SelectRelation, SupabaseStrategy, SyncControl, SyncMode, SyncScope, SyncStatus, TableNames, TableSchema, TableStrategy, UseDbMutationHook, UseDbQueryByIdHook, UseDbQueryHook, WhereClause, WhereOperators };
591
+ export type { AdapterRegistry, AutoStrategy, BuiltQuery, CachedStrategy, ColumnInfo, ColumnType, ConnectionConfig, DataAdapter, DataLayerConfig, DataLayerHooks, DatabaseSchema, DeleteMutationResult, ExtractInsert, ExtractRow, ExtractUpdate, HybridStrategy, MutationHookResult, MutationResult, OrderBy, ParsedSelect, PowerSyncStrategy, QueryOptions, QueryResult, QuerySingleResult, RelationshipInfo, RelationshipType, ResolvedRelationship, ScopeDefinition, SelectColumn, SelectRelation, SupabaseStrategy, SyncControl, SyncSchedule, SyncScope, SyncStatus, TableNames, TableSchema, TableStrategy, UseDbMutationHook, UseDbQueryByIdHook, UseDbQueryHook, WhereClause, WhereOperators };
@@ -466,8 +466,16 @@ declare class QueryExecutor {
466
466
  /**
467
467
  * Upsert a record (insert or update).
468
468
  *
469
+ * PowerSync tables are SQLite VIEWs with INSTEAD OF INSERT triggers.
470
+ * Using INSERT OR REPLACE causes the native extension to bypass provided UUIDs
471
+ * and generate timestamp-based IDs (e.g., "1772167324515-7xufitksy").
472
+ *
473
+ * Logic:
474
+ * - No ID provided → generate UUID → INSERT directly
475
+ * - ID provided → try UPDATE first, if 0 rows affected → INSERT
476
+ *
469
477
  * @param table - The table to upsert into
470
- * @param data - The record data (must include ID for update)
478
+ * @param data - The record data (ID optional for new records)
471
479
  * @returns The upserted record
472
480
  */
473
481
  upsert<T>(table: string, data: Record<string, unknown>): Promise<T>;
package/dist/gen/index.js CHANGED
@@ -185,7 +185,7 @@ import {
185
185
  import {
186
186
  UserMetadata
187
187
  } from "../chunk-SM73S2DY.js";
188
- import "../chunk-P4UZ7IXC.js";
188
+ import "../chunk-7D4SUZUM.js";
189
189
  export {
190
190
  Accessory,
191
191
  Address,
@@ -1,10 +1,10 @@
1
- export { C as ClarificationQuestion, D as DatabaseTypes, F as Filter, x as FilterGroup, y as FilterOperator, z as Pagination, P as PublicTableNames, Q as QueryState, R as ResolveRowType, S as SchemaNames, l as SchemaTableNames, A as Sort, T as TableIdentifier, U as UseAdvanceQueryOptions, m as UseAdvanceQueryResult, n as UseDbCountOptions, o as UseDbCountResult, K as UseDbDeleteOptions, L as UseDbDeleteResult, p as UseDbInfiniteQueryOptions, q as UseDbInfiniteQueryResult, B as UseDbInsertOptions, E as UseDbInsertResult, v as UseDbQueryByIdOptions, w as UseDbQueryByIdResult, r as UseDbQueryOptions, s as UseDbQueryResult, G as UseDbUpdateOptions, H as UseDbUpdateResult, I as UseDbUpsertOptions, J as UseDbUpsertResult, u as useAdvanceQuery, a as useDataLayer, b as useDataLayerCore, t as useDataLayerOptional, c as useDataLayerStatus, d as useDbCount, e as useDbDelete, f as useDbInfiniteQuery, g as useDbInsert, h as useDbQuery, i as useDbQueryById, j as useDbUpdate, k as useDbUpsert } from '../useDbCount-Dk0yCKlT.js';
1
+ export { C as ClarificationQuestion, D as DatabaseTypes, F as Filter, x as FilterGroup, y as FilterOperator, z as Pagination, P as PublicTableNames, Q as QueryState, R as ResolveRowType, S as SchemaNames, m as SchemaTableNames, A as Sort, T as TableIdentifier, U as UseAdvanceQueryOptions, n as UseAdvanceQueryResult, o as UseDbCountOptions, p as UseDbCountResult, K as UseDbDeleteOptions, L as UseDbDeleteResult, q as UseDbInfiniteQueryOptions, r as UseDbInfiniteQueryResult, B as UseDbInsertOptions, E as UseDbInsertResult, v as UseDbQueryByIdOptions, w as UseDbQueryByIdResult, s as UseDbQueryOptions, t as UseDbQueryResult, G as UseDbUpdateOptions, H as UseDbUpdateResult, I as UseDbUpsertOptions, J as UseDbUpsertResult, u as useAdvanceQuery, a as useDataLayer, b as useDataLayerCore, M as useDataLayerCoreOptional, c as useDataLayerOptional, d as useDataLayerStatus, e as useDbCount, f as useDbDelete, g as useDbInfiniteQuery, h as useDbInsert, i as useDbQuery, j as useDbQueryById, k as useDbUpdate, l as useDbUpsert } from '../useDbCount-DWfYB2iu.js';
2
2
  import { SyncStatus, SyncControl } from '../core/index.js';
3
- import '../DataLayerContext-Dc7nF2IG.js';
3
+ import '../DataLayerContext-BwMk4VpG.js';
4
4
  import 'react';
5
5
  import '@supabase/supabase-js';
6
6
  import '@tanstack/react-query';
7
- import '../executor-Br27YZvl.js';
7
+ import '../executor-YJw4m7Q7.js';
8
8
 
9
9
  /**
10
10
  * V3 useSyncStatus Hook
@@ -59,25 +59,6 @@ declare function useSyncStatus(): SyncStatus;
59
59
  * // Start/stop live sync
60
60
  * await startLiveSync();
61
61
  * stopLiveSync();
62
- *
63
- * @example Failed upload controls
64
- * const {
65
- * failedUploads,
66
- * retryFailedUploads,
67
- * clearFailedUploads,
68
- * pauseAutoRetry,
69
- * resumeAutoRetry,
70
- * isAutoRetryPaused
71
- * } = useSyncControl();
72
- *
73
- * // Show failed uploads count
74
- * console.log(`${failedUploads.length} uploads failed`);
75
- *
76
- * // Manually retry all failed uploads
77
- * await retryFailedUploads();
78
- *
79
- * // Discard all failed uploads
80
- * clearFailedUploads();
81
62
  */
82
63
  declare function useSyncControl(): SyncControl;
83
64
 
@@ -1,30 +1,33 @@
1
1
  import {
2
2
  useAdvanceQuery,
3
- useDataLayer,
4
- useDataLayerCore,
5
- useDataLayerOptional,
6
- useDataLayerStatus,
7
3
  useDbCount,
8
4
  useDbDelete,
9
5
  useDbInfiniteQuery,
10
6
  useDbInsert,
11
- useDbQuery,
12
7
  useDbQueryById,
13
8
  useDbUpdate,
14
9
  useDbUpsert,
15
10
  useOnlineStatus,
16
11
  useSyncControl,
17
12
  useSyncStatus
18
- } from "../chunk-VGEMLNNM.js";
13
+ } from "../chunk-NP34C3O3.js";
14
+ import {
15
+ useDataLayer,
16
+ useDataLayerCore,
17
+ useDataLayerCoreOptional,
18
+ useDataLayerOptional,
19
+ useDataLayerStatus,
20
+ useDbQuery
21
+ } from "../chunk-UBHORKBS.js";
19
22
  import "../chunk-GC3TBUWE.js";
20
23
  import "../chunk-J4ZVCXZ4.js";
21
- import "../chunk-OQ7U6EQ3.js";
22
- import "../chunk-5EFDS7SR.js";
23
- import "../chunk-P4UZ7IXC.js";
24
+ import "../chunk-DMVUEJG2.js";
25
+ import "../chunk-7D4SUZUM.js";
24
26
  export {
25
27
  useAdvanceQuery,
26
28
  useDataLayer,
27
29
  useDataLayerCore,
30
+ useDataLayerCoreOptional,
28
31
  useDataLayerOptional,
29
32
  useDataLayerStatus,
30
33
  useDbCount,
@@ -5,7 +5,7 @@ import { PostgrestSingleResponse, SupabaseClient } from '@supabase/supabase-js';
5
5
  import { Dispatch, SetStateAction } from 'react';
6
6
  import { UseQueryOptions, DefinedUseQueryResult, QueryClient } from '@tanstack/react-query';
7
7
  import { SyncControl, SyncStatus, DataLayerConfig } from './core/index.js';
8
- import { s as DataLayerStatus, p as DataLayerContextValue } from './DataLayerContext-Dc7nF2IG.js';
8
+ import { u as DataLayerStatus, r as DataLayerContextValue } from './DataLayerContext-BwMk4VpG.js';
9
9
 
10
10
  /**
11
11
  * Represents a change log entry for database records.
package/dist/index.d.ts CHANGED
@@ -1,16 +1,16 @@
1
1
  export { C as CompositeTypes, c as Constants, D as Database, E as Enums, J as Json, T as Tables, a as TablesInsert, b as TablesUpdate } from './database.types-ChFCG-4M.js';
2
2
  export { a as FilterConfig, F as FilterConfigOption, G as Group, P as PropertyType, S as SortConfig, T as TableInfo, V as ValueForPropertyType, W as WhereFilter } from './FilterConfig-Bt2Ek74z.js';
3
- export { r as BackendSelectionResult, B as BooleanOperator, l as ClarificationQuestion, k as ClarificationSuggestion, C as CombinedProviderStatus, j as ComputedSortConfig, n as DataLayerWithPowerSyncProps, D as DbChangeLog, E as EnhancedSyncControl, a as EnhancedSyncStatus, e as Filter, d as FilterConditionType, m as FilterContextType, f as FilterGroup, g as FilterInput, F as FilterOperator, h as FilterState, H as HasPowerSyncConfig, O as OrderColumn, i as Pagination, P as PowerSyncEnabledConfig, b as PowerSyncEnabledContextValue, q as PowerSyncTables, Q as QueryState, S as Sort, U as UseDataLayerWithPowerSync, p as UseSyncControlWithPowerSync, o as UseSyncStatusWithPowerSync, V as ValueOrArrayForPropertyType, c as createCombinedStatus } from './index-CYFdO0iB.js';
4
- export { A as AIOptions, k as AIResponse, y as AlertProps, B as BUCKETS, v as BucketName, C as CustomPageQueryResult, D as DEFAULT_QUERY_TIMEOUT, Y as FeedbackListItem, Z as FeedbackListParams, L as LiveChangeContext, z as LiveChangeContextProvider, m as ServerAvailabilityState, t as StorageObjectMetadata, $ as SubmitFeedbackParams, S as SupabaseAdapter, T as TIMEOUT_ERROR_MESSAGE, q as UpdateOptions, U as UseMutationSuccessOptions, w as createInCondition, i as createSupabaseAdapter, r as executeAdvanceQuery, j as getErrorBody, g as getSupabaseUrl, x as isTimeoutError, n as newTimeActivity, s as setSupabaseUrl, l as useAI, a0 as useApplyFeedback, b as useAutosaveState, Q as useChangelogById, R as useChangelogBySlug, V as useChangelogEntries, W as useChangelogMedia, O as useChangelogs, F as useDeleteChangelog, I as useDeleteChangelogEntry, M as useDeleteChangelogMedia, X as useFeedbackList, a as useLatestOperationLog, u as useLiveChangeTracking, J as useMultiDeleteChangelogEntries, H as useMultiUpsertChangelogEntries, f as useMutationSuccess, h as useMutationSuccessRN, P as usePublishedChangelogs, a1 as useResolveFeedback, p as useSearchQuery, o as useServerAvailability, e as useStoragePath, d as useStorageUrl, _ as useSubmitFeedback, c as useToastError, N as useUploadChangelogMedia, E as useUpsertChangelog, G as useUpsertChangelogEntry, K as useUpsertChangelogMedia } from './useResolveFeedback-C1KucfdQ.js';
5
- export { u as useBatchDelete, a as useBatchUpsert } from './useBatchUpsert-9OYjibLh.js';
6
- export { AdapterRegistry as AdapterRegistryInterface, AutoStrategy, BuiltQuery, CachedStrategy, ColumnInfo, ColumnType, ConnectionConfig, DataAdapter, DataLayerConfig, DataLayerHooks, DatabaseSchema, DeleteMutationResult, ExtractInsert, ExtractRow, ExtractUpdate, FailedUpload, HybridStrategy, MutationHookResult, MutationResult, OrderBy, ParsedSelect, PowerSyncStrategy, QueryOptions, QueryResult, QuerySingleResult, RelationshipInfo, RelationshipType, ResolvedRelationship, ScopeDefinition, SelectColumn, SelectRelation, SupabaseStrategy, SyncControl, SyncMode, SyncScope, SyncStatus, TableNames, TableSchema, TableStrategy, UseDbMutationHook, UseDbQueryByIdHook, UseDbQueryHook, WhereClause, WhereOperators } from './core/index.js';
7
- export { f as ADAPTER_STRATEGIES, i as AdapterAutoDetector, c as AdapterCapabilities, a as AdapterConfig, d as AdapterDependencies, b as AdapterFactory, A as AdapterQueryResult, g as AdapterRegistry, e as AdapterStrategyType, k as AutoDetectionResult, l as AutoDetectorOptions, m as BackendChangeListener, B as BackendStatus, C as CapableDataAdapter, D as DataLayerContext, p as DataLayerContextValue, n as DataLayerCoreContext, q as DataLayerCoreContextValue, s as DataLayerStatus, o as DataLayerStatusContext, r as DataLayerStatusContextValue, S as SyncStatusInfo, T as TableDataAdapter, j as createAdapterAutoDetector, h as createAdapterRegistry } from './DataLayerContext-Dc7nF2IG.js';
3
+ export { r as BackendSelectionResult, B as BooleanOperator, l as ClarificationQuestion, k as ClarificationSuggestion, C as CombinedProviderStatus, j as ComputedSortConfig, n as DataLayerWithPowerSyncProps, D as DbChangeLog, E as EnhancedSyncControl, a as EnhancedSyncStatus, e as Filter, d as FilterConditionType, m as FilterContextType, f as FilterGroup, g as FilterInput, F as FilterOperator, h as FilterState, H as HasPowerSyncConfig, O as OrderColumn, i as Pagination, P as PowerSyncEnabledConfig, b as PowerSyncEnabledContextValue, q as PowerSyncTables, Q as QueryState, S as Sort, U as UseDataLayerWithPowerSync, p as UseSyncControlWithPowerSync, o as UseSyncStatusWithPowerSync, V as ValueOrArrayForPropertyType, c as createCombinedStatus } from './index-lveh8qb0.js';
4
+ export { y as AIOptions, z as AIResponse, P as AlertProps, A as AttachmentQueueProvider, I as BUCKETS, J as BucketName, H as CustomPageQueryResult, L as DEFAULT_QUERY_TIMEOUT, a9 as FeedbackListItem, aa as FeedbackListParams, Q as LiveChangeContext, R as LiveChangeContextProvider, C as ServerAvailabilityState, k as StorageQueueContext, m as StorageQueueContextValue, S as StorageQueueProvider, j as StorageQueueProviderProps, ac as SubmitFeedbackParams, v as SupabaseAdapter, T as TIMEOUT_ERROR_MESSAGE, F as UpdateOptions, U as UseAutosaveOptions, d as UseAutosaveResult, N as UseDbRealtimeQueryResult, q as UseMutationSuccessOptions, h as UseStorageSourceOptions, i as UseStorageSourceResult, O as convertFilterToRealtimeQuery, K as createInCondition, w as createSupabaseAdapter, G as executeAdvanceQuery, x as getErrorBody, g as getStorageUrl, p as getSupabaseUrl, M as isTimeoutError, n as newTimeActivity, s as setSupabaseUrl, B as useAI, ad as useApplyFeedback, c as useAutosave, b as useAutosaveState, a4 as useChangelogById, a5 as useChangelogBySlug, a6 as useChangelogEntries, a7 as useChangelogMedia, a2 as useChangelogs, o as useDbRealtimeQuery, W as useDeleteChangelog, Z as useDeleteChangelogEntry, a0 as useDeleteChangelogMedia, a8 as useFeedbackList, a as useLatestOperationLog, u as useLiveChangeTracking, _ as useMultiDeleteChangelogEntries, Y as useMultiUpsertChangelogEntries, r as useMutationSuccess, t as useMutationSuccessRN, a3 as usePublishedChangelogs, o as useRealtimeQuery, ae as useResolveFeedback, E as useSearchQuery, D as useServerAvailability, l as useStorageQueueContext, f as useStorageSource, ab as useSubmitFeedback, e as useToastError, a1 as useUploadChangelogMedia, V as useUpsertChangelog, X as useUpsertChangelogEntry, $ as useUpsertChangelogMedia } from './useResolveFeedback-CxLccZKK.js';
5
+ export { u as useBatchDelete, a as useBatchUpsert } from './useBatchUpsert-DAkiCNo3.js';
6
+ export { AdapterRegistry as AdapterRegistryInterface, AutoStrategy, BuiltQuery, CachedStrategy, ColumnInfo, ColumnType, ConnectionConfig, DataAdapter, DataLayerConfig, DataLayerHooks, DatabaseSchema, DeleteMutationResult, ExtractInsert, ExtractRow, ExtractUpdate, HybridStrategy, MutationHookResult, MutationResult, OrderBy, ParsedSelect, PowerSyncStrategy, QueryOptions, QueryResult, QuerySingleResult, RelationshipInfo, RelationshipType, ResolvedRelationship, ScopeDefinition, SelectColumn, SelectRelation, SupabaseStrategy, SyncControl, SyncSchedule, SyncScope, SyncStatus, TableNames, TableSchema, TableStrategy, UseDbMutationHook, UseDbQueryByIdHook, UseDbQueryHook, WhereClause, WhereOperators } from './core/index.js';
7
+ export { f as ADAPTER_STRATEGIES, i as AdapterAutoDetector, c as AdapterCapabilities, a as AdapterConfig, d as AdapterDependencies, b as AdapterFactory, A as AdapterQueryResult, g as AdapterRegistry, e as AdapterStrategyType, k as AutoDetectionResult, l as AutoDetectorOptions, m as BackendChangeListener, B as BackendStatus, C as CapableDataAdapter, D as DataLayerContext, r as DataLayerContextValue, p as DataLayerCoreContext, s as DataLayerCoreContextValue, u as DataLayerStatus, q as DataLayerStatusContext, t as DataLayerStatusContextValue, S as SyncStatusInfo, o as SyncTracker, n as SyncTrackingAdapter, T as TableDataAdapter, j as createAdapterAutoDetector, h as createAdapterRegistry } from './DataLayerContext-BwMk4VpG.js';
8
8
  export { ConflictCheckResult, ConflictContext, ConflictContextValue, ConflictProvider, ConflictProviderProps, ConflictResolution, DataLayerProvider, DataLayerProviderProps, FieldConflict, PowerSyncAdapter, UseConflictResolutionReturn, UseSupabaseUploadOptions, UseSupabaseUploadReturn, createPowerSyncAdapter, useBulkConflictResolution, useConflictCountByTable, useConflictForRecord, useConflictResolution, useConflictState, useConflictsForTable, useHasConflicts, usePendingConflicts, useSupabaseUpload } from './index.native.js';
9
- export { D as DatabaseTypes, P as PublicTableNames, R as ResolveRowType, S as SchemaNames, l as SchemaTableNames, T as TableIdentifier, U as UseAdvanceQueryOptions, m as UseAdvanceQueryResult, n as UseDbCountOptions, o as UseDbCountResult, p as UseDbInfiniteQueryOptions, q as UseDbInfiniteQueryResult, r as UseDbQueryOptions, s as UseDbQueryResult, u as useAdvanceQuery, a as useDataLayer, b as useDataLayerCore, c as useDataLayerStatus, d as useDbCount, d as useDbCountV3, e as useDbDelete, f as useDbInfiniteQuery, f as useDbInfiniteQueryV3, g as useDbInsert, h as useDbQuery, i as useDbQueryById, j as useDbUpdate, k as useDbUpsert } from './useDbCount-Dk0yCKlT.js';
9
+ export { D as DatabaseTypes, P as PublicTableNames, R as ResolveRowType, S as SchemaNames, m as SchemaTableNames, T as TableIdentifier, U as UseAdvanceQueryOptions, n as UseAdvanceQueryResult, o as UseDbCountOptions, p as UseDbCountResult, q as UseDbInfiniteQueryOptions, r as UseDbInfiniteQueryResult, s as UseDbQueryOptions, t as UseDbQueryResult, u as useAdvanceQuery, a as useDataLayer, b as useDataLayerCore, c as useDataLayerOptional, d as useDataLayerStatus, e as useDbCount, e as useDbCountV3, f as useDbDelete, g as useDbInfiniteQuery, g as useDbInfiniteQueryV3, h as useDbInsert, i as useDbQuery, j as useDbQueryById, k as useDbUpdate, l as useDbUpsert } from './useDbCount-DWfYB2iu.js';
10
10
  export { useOnlineStatus, useSyncControl, useSyncStatus } from './hooks/index.js';
11
- export { C as ClientInstanceId, S as SupabaseDatabaseTypes, a as SupabaseProvider, T as TypedSupabaseClient, U as UserSessionId, c as createNewSupabaseClient, u as default, o as onSupabaseInitialized, s as setDefaultOptions, t as typedSupabase, u as useSupabase } from './useSupabase-DvWVuHHE.js';
11
+ export { C as ClientInstanceId, S as SupabaseDatabaseTypes, a as SupabaseProvider, T as TypedSupabaseClient, U as UserSessionId, c as createNewSupabaseClient, u as default, o as onSupabaseInitialized, s as setDefaultOptions, t as typedSupabase, u as useSupabase } from './useSupabase-DSZNeXnF.js';
12
12
  export { B as BatchAnalysisProgress, E as ExtractedReceipt, P as PendingExpense, a as useReceiptAI, u as useSupabaseFunction } from './useReceiptAI-6HkRpRml.js';
13
- export { e as UserMetadataContextProvider, c as UserMetadataContextType, a as UserMetadataInsert, U as UserMetadataRow, b as UserMetadataUpdate, u as useLiveChangesIndicator, h as useSetUserMetadata, f as useUserMetadata, i as useUserMetadataState, g as useUserMetadataValue, d as userMetadataContext } from './UserMetadataContext-B8gVWGMl.js';
13
+ export { e as UserMetadataContextProvider, c as UserMetadataContextType, a as UserMetadataInsert, U as UserMetadataRow, b as UserMetadataUpdate, u as useLiveChangesIndicator, h as useSetUserMetadata, f as useUserMetadata, i as useUserMetadataState, g as useUserMetadataValue, d as userMetadataContext } from './UserMetadataContext-pQb3A8_Q.js';
14
14
  export { AnyPostgrestResponse, FilterDefinition, FilterDefinitions, FilterFn, NestedPath, OPERATOR_MAP, OperatorFn, OrderDefinition, Path, PostgrestFilter, PostgrestFilterOperator, PostgrestHasMorePaginationCacheData, PostgrestHasMorePaginationResponse, PostgrestPaginationCacheData, PostgrestPaginationResponse, PostgrestParser, PostgrestQueryParser, PostgrestQueryParserOptions, SUPPORTED_OPERATORS, ValueType, binarySearch, buildSortedComparator, denormalize, encodeObject, extractPathsFromFilters, filterFilterDefinitionsByPaths, findFilters, findIndexOrdered, findLastIndex, get, getTable, groupPathsRecursive, ifDateGetTime, isAndFilter, isAnyPostgrestResponse, isFilterDefinition, isISODateString, isNestedPath, isNotNull, isObject, isOrFilter, isPostgrestBuilder, isPostgrestHasMorePaginationCacheData, isPostgrestHasMorePaginationResponse, isPostgrestPaginationCacheData, isPostgrestPaginationResponse, parseOrderByKey, parseSelectParam, parseValue, removeAliasFromDeclaration, removeFirstPathElement, setFilterValue, sortSearchParams } from './parser/index.js';
15
15
  export { G as GetResult, S as SelectQueryError } from './select-query-parser-BwyHum1L.js';
16
16
  export { F as Fetch, i as GenericFunction, g as GenericNonUpdatableView, j as GenericSchema, G as GenericTable, f as GenericUpdatableView, h as GenericView, P as PostgrestError, d as PostgrestMaybeSingleResponse, e as PostgrestResponse, b as PostgrestResponseFailure, a as PostgrestResponseSuccess, c as PostgrestSingleResponse, k as Prettify } from './types-CYr9JiUE.js';
@@ -25,8 +25,36 @@ import '@supabase/postgrest-js';
25
25
  import './useDbQuery-C-TL8jY1.js';
26
26
  import '@pol-studios/utils';
27
27
  import '@supabase-cache-helpers/postgrest-react-query';
28
- import '@supabase/storage-js';
29
28
  import 'react/jsx-runtime';
30
- import './executor-Br27YZvl.js';
29
+ import '@supabase/storage-js';
30
+ import './executor-YJw4m7Q7.js';
31
31
  import 'react-dropzone';
32
32
  import '@supabase/supabase-js/dist/module/lib/types.js';
33
+
34
+ /**
35
+ * Utilities for detecting storage authentication errors.
36
+ *
37
+ * These utilities help identify when a storage operation failed due to
38
+ * authentication issues (expired tokens, invalid sessions, etc.) that
39
+ * can often be resolved by refreshing the user's session.
40
+ */
41
+ /**
42
+ * Check if a storage error is an authentication error.
43
+ *
44
+ * These errors can often be fixed by refreshing the session.
45
+ *
46
+ * @param error - The error to check (typically from Supabase Storage operations)
47
+ * @returns true if the error appears to be authentication-related
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * const { data, error } = await storage.createSignedUrl(path, 3600);
52
+ * if (error && isStorageAuthError(error)) {
53
+ * await supabase.auth.refreshSession();
54
+ * // Retry the request...
55
+ * }
56
+ * ```
57
+ */
58
+ declare function isStorageAuthError(error: unknown): boolean;
59
+
60
+ export { isStorageAuthError };