@pol-studios/powersync 1.0.30 → 1.0.32

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 (116) hide show
  1. package/dist/{CacheSettingsManager-uz-kbnRH.d.ts → CacheSettingsManager-0H_7thHW.d.ts} +21 -3
  2. package/dist/attachments/index.d.ts +30 -30
  3. package/dist/attachments/index.js +13 -4
  4. package/dist/{background-sync-CVR3PkFi.d.ts → background-sync-BujnI3IR.d.ts} +1 -1
  5. package/dist/{chunk-RE5HWLCB.js → chunk-2RDWLXJW.js} +322 -103
  6. package/dist/chunk-2RDWLXJW.js.map +1 -0
  7. package/dist/{chunk-P4HZA6ZT.js → chunk-4665ZSE5.js} +2 -2
  8. package/dist/chunk-4665ZSE5.js.map +1 -0
  9. package/dist/{chunk-XOY2CJ67.js → chunk-4F5B5CZ7.js} +3 -3
  10. package/dist/chunk-5WRI5ZAA.js +31 -0
  11. package/dist/{chunk-BC2SRII2.js → chunk-65A3SYJZ.js} +14 -1
  12. package/dist/chunk-65A3SYJZ.js.map +1 -0
  13. package/dist/chunk-6SZ64KCZ.js +755 -0
  14. package/dist/chunk-6SZ64KCZ.js.map +1 -0
  15. package/dist/{chunk-C2ACBYBZ.js → chunk-74TBHWJ4.js} +10 -96
  16. package/dist/{chunk-C2ACBYBZ.js.map → chunk-74TBHWJ4.js.map} +1 -1
  17. package/dist/chunk-ANXWYQEJ.js +1 -0
  18. package/dist/chunk-ANXWYQEJ.js.map +1 -0
  19. package/dist/{chunk-CAB26E6F.js → chunk-C4J4MLER.js} +29 -24
  20. package/dist/chunk-C4J4MLER.js.map +1 -0
  21. package/dist/{chunk-C5ODS3XH.js → chunk-EOW7JK7Q.js} +9 -16
  22. package/dist/chunk-EOW7JK7Q.js.map +1 -0
  23. package/dist/chunk-HRAVPIAZ.js +220 -0
  24. package/dist/chunk-HRAVPIAZ.js.map +1 -0
  25. package/dist/{chunk-XAEII4ZX.js → chunk-NUGQOTEM.js} +32 -4
  26. package/dist/chunk-NUGQOTEM.js.map +1 -0
  27. package/dist/chunk-OGUFUZSY.js +5415 -0
  28. package/dist/chunk-OGUFUZSY.js.map +1 -0
  29. package/dist/{chunk-JCGOZVWL.js → chunk-P4D6BQ4X.js} +115 -576
  30. package/dist/chunk-P4D6BQ4X.js.map +1 -0
  31. package/dist/{chunk-CACKC6XG.js → chunk-PGEDE6IM.js} +136 -89
  32. package/dist/chunk-PGEDE6IM.js.map +1 -0
  33. package/dist/{chunk-A4IBBWGO.js → chunk-RALHHPTU.js} +1 -1
  34. package/dist/chunk-RIDSPLE5.js +42 -0
  35. package/dist/chunk-RIDSPLE5.js.map +1 -0
  36. package/dist/{chunk-Z6VOBGTU.js → chunk-UOMHWUHV.js} +2 -12
  37. package/dist/chunk-UOMHWUHV.js.map +1 -0
  38. package/dist/{chunk-QREWE3NR.js → chunk-YONQYTVH.js} +2 -2
  39. package/dist/chunk-ZAN22NGL.js +13 -0
  40. package/dist/chunk-ZAN22NGL.js.map +1 -0
  41. package/dist/config/index.d.ts +200 -0
  42. package/dist/config/index.js +23 -0
  43. package/dist/config/index.js.map +1 -0
  44. package/dist/connector/index.d.ts +23 -5
  45. package/dist/connector/index.js +4 -1
  46. package/dist/core/index.d.ts +2 -2
  47. package/dist/core/index.js +1 -0
  48. package/dist/error/index.js +1 -0
  49. package/dist/generator/index.js +2 -0
  50. package/dist/generator/index.js.map +1 -1
  51. package/dist/index.d.ts +19 -16
  52. package/dist/index.js +68 -36
  53. package/dist/index.native.d.ts +18 -14
  54. package/dist/index.native.js +73 -34
  55. package/dist/index.web.d.ts +17 -14
  56. package/dist/index.web.js +68 -36
  57. package/dist/maintenance/index.d.ts +2 -2
  58. package/dist/maintenance/index.js +3 -2
  59. package/dist/platform/index.d.ts +1 -1
  60. package/dist/platform/index.js +2 -0
  61. package/dist/platform/index.js.map +1 -1
  62. package/dist/platform/index.native.d.ts +1 -1
  63. package/dist/platform/index.native.js +1 -0
  64. package/dist/platform/index.web.d.ts +1 -1
  65. package/dist/platform/index.web.js +1 -0
  66. package/dist/pol-attachment-queue-DqBvLAEY.d.ts +255 -0
  67. package/dist/provider/index.d.ts +149 -114
  68. package/dist/provider/index.js +9 -14
  69. package/dist/provider/index.native.d.ts +108 -0
  70. package/dist/provider/index.native.js +121 -0
  71. package/dist/provider/index.native.js.map +1 -0
  72. package/dist/provider/index.web.d.ts +16 -0
  73. package/dist/provider/index.web.js +112 -0
  74. package/dist/provider/index.web.js.map +1 -0
  75. package/dist/react/index.d.ts +16 -65
  76. package/dist/react/index.js +2 -9
  77. package/dist/storage/index.d.ts +5 -4
  78. package/dist/storage/index.js +12 -9
  79. package/dist/storage/index.native.d.ts +5 -4
  80. package/dist/storage/index.native.js +8 -5
  81. package/dist/storage/index.web.d.ts +5 -4
  82. package/dist/storage/index.web.js +11 -8
  83. package/dist/storage/upload/index.d.ts +4 -3
  84. package/dist/storage/upload/index.js +4 -2
  85. package/dist/storage/upload/index.native.d.ts +4 -3
  86. package/dist/storage/upload/index.native.js +4 -2
  87. package/dist/storage/upload/index.web.d.ts +2 -1
  88. package/dist/storage/upload/index.web.js +4 -2
  89. package/dist/{supabase-connector-C4YpH_l3.d.ts → supabase-connector-HMxBA9Kg.d.ts} +2 -2
  90. package/dist/sync/index.d.ts +155 -20
  91. package/dist/sync/index.js +13 -3
  92. package/dist/{types-CyvBaAl8.d.ts → types-6QHGELuY.d.ts} +4 -1
  93. package/dist/{types-Dv1uf0LZ.d.ts → types-B9MptP7E.d.ts} +7 -10
  94. package/dist/types-BhAEsJj-.d.ts +330 -0
  95. package/dist/{types-D0WcHrq6.d.ts → types-CGMibJKD.d.ts} +8 -0
  96. package/dist/{types-CpM2_LhU.d.ts → types-DqJnP50o.d.ts} +6 -1
  97. package/dist/{pol-attachment-queue-BE2HU3Us.d.ts → types-JCEhw2Lf.d.ts} +139 -346
  98. package/package.json +18 -4
  99. package/dist/chunk-654ERHA7.js +0 -1
  100. package/dist/chunk-BC2SRII2.js.map +0 -1
  101. package/dist/chunk-C5ODS3XH.js.map +0 -1
  102. package/dist/chunk-CAB26E6F.js.map +0 -1
  103. package/dist/chunk-CACKC6XG.js.map +0 -1
  104. package/dist/chunk-FNYQFILT.js +0 -44
  105. package/dist/chunk-FNYQFILT.js.map +0 -1
  106. package/dist/chunk-JCGOZVWL.js.map +0 -1
  107. package/dist/chunk-P4HZA6ZT.js.map +0 -1
  108. package/dist/chunk-RBPWEOIV.js +0 -358
  109. package/dist/chunk-RBPWEOIV.js.map +0 -1
  110. package/dist/chunk-RE5HWLCB.js.map +0 -1
  111. package/dist/chunk-XAEII4ZX.js.map +0 -1
  112. package/dist/chunk-Z6VOBGTU.js.map +0 -1
  113. /package/dist/{chunk-XOY2CJ67.js.map → chunk-4F5B5CZ7.js.map} +0 -0
  114. /package/dist/{chunk-654ERHA7.js.map → chunk-5WRI5ZAA.js.map} +0 -0
  115. /package/dist/{chunk-A4IBBWGO.js.map → chunk-RALHHPTU.js.map} +0 -0
  116. /package/dist/{chunk-QREWE3NR.js.map → chunk-YONQYTVH.js.map} +0 -0
@@ -1,6 +1,4 @@
1
- import { AbstractAttachmentQueue, AttachmentQueueOptions, AttachmentRecord as AttachmentRecord$1 } from '@powersync/attachments';
2
1
  import { AbstractPowerSyncDatabase } from '@powersync/common';
3
- import { PlatformAdapter } from './platform/index.js';
4
2
 
5
3
  /**
6
4
  * Attachment Queue Types for @pol-studios/powersync
@@ -49,9 +47,7 @@ declare enum PolAttachmentState {
49
47
  /** Attachment has been orphaned, i.e. the associated record has been deleted */
50
48
  ARCHIVED = 4,
51
49
  /** Permanently failed (exhausted retries or unrecoverable error) - POL extension */
52
- FAILED_PERMANENT = 5,
53
- /** Download was skipped due to downloadFilter returning false - POL extension */
54
- DOWNLOAD_SKIPPED = 6
50
+ FAILED_PERMANENT = 5
55
51
  }
56
52
  /**
57
53
  * Extended attachment record with POL-specific upload tracking fields.
@@ -94,23 +90,12 @@ interface PolAttachmentRecord {
94
90
  /**
95
91
  * Configuration for watching a source table.
96
92
  * Used by query-builder utilities to generate SQL queries.
97
- *
98
- * Note: Either `pathColumn` or `idColumn` must be provided.
99
- * `pathColumn` is the preferred option; `idColumn` is deprecated but still supported.
100
93
  */
101
94
  interface WatchConfig {
102
95
  /** Source table name */
103
96
  table: string;
104
- /**
105
- * Column containing attachment path/ID.
106
- * Preferred over `idColumn`.
107
- */
108
- pathColumn?: string;
109
- /**
110
- * Column containing attachment ID/path.
111
- * @deprecated Use `pathColumn` instead. Will be removed in a future version.
112
- */
113
- idColumn?: string;
97
+ /** Column containing attachment path */
98
+ pathColumn: string;
114
99
  /** Additional columns to include in context */
115
100
  selectColumns?: string[];
116
101
  /** Optional WHERE clause fragment (e.g., "storagePath IS NOT NULL") */
@@ -144,20 +129,54 @@ interface SimpleAttachmentConfig {
144
129
  pathColumn: string;
145
130
  }
146
131
  /**
147
- * Legacy context for batch filtering of attachments.
148
- * @deprecated Use SkipDownloadContext with skipDownload callback instead.
149
- */
150
- interface BatchFilterContext {
151
- /** All pending attachment IDs */
152
- ids: string[];
153
- /** Source records from watch config (ID → record) */
154
- records: Map<string, Record<string, unknown>>;
155
- /** Database access for batch queries */
156
- db: {
157
- getAll<T>(sql: string, params?: unknown[]): Promise<T[]>;
158
- getOptional<T>(sql: string, params?: unknown[]): Promise<T | null>;
159
- };
132
+ * Supabase bucket source configuration.
133
+ * Uses Supabase Storage as the attachment backend.
134
+ */
135
+ interface SupabaseBucketSource {
136
+ type: 'supabase-bucket';
137
+ /** Supabase Storage bucket name */
138
+ bucket: string;
139
+ /**
140
+ * Whether to use signed URLs (default: true).
141
+ * Set to false for public buckets to use getPublicUrl instead of createSignedUrl.
142
+ */
143
+ signed?: boolean;
144
+ /**
145
+ * Optional: image compression settings for downloads.
146
+ * Uses Supabase's transform feature to resize/compress images on download.
147
+ * Only applies to supported image formats (jpg, png, webp, avif, gif, heic).
148
+ * Note: Compression is only available for supabase-bucket sources, not custom sources.
149
+ */
150
+ compression?: Partial<CompressionConfig>;
160
151
  }
152
+ /**
153
+ * Custom source configuration for non-Supabase backends.
154
+ * Provide a getUrl function to resolve download URLs for attachment paths.
155
+ */
156
+ interface CustomAttachmentSource {
157
+ type: 'custom';
158
+ /**
159
+ * Resolve a download URL for a given attachment path.
160
+ * Called during download to get the URL to fetch the file from.
161
+ *
162
+ * @param path - The attachment storage path
163
+ * @returns The URL to download the file from (can be async)
164
+ *
165
+ * @example
166
+ * ```typescript
167
+ * source: {
168
+ * type: 'custom',
169
+ * getUrl: (path) => `https://cdn.example.com/attachments/${path}`,
170
+ * }
171
+ * ```
172
+ */
173
+ getUrl: (path: string) => Promise<string> | string;
174
+ }
175
+ /**
176
+ * Discriminated union for attachment source configuration.
177
+ * Supports both Supabase Storage and custom backends.
178
+ */
179
+ type AttachmentSource = SupabaseBucketSource | CustomAttachmentSource;
161
180
  /**
162
181
  * Configuration for an attachment source.
163
182
  *
@@ -167,57 +186,72 @@ interface BatchFilterContext {
167
186
  * @example
168
187
  * ```typescript
169
188
  * const config: AttachmentSourceConfig = {
170
- * bucket: 'project-assets',
189
+ * source: {
190
+ * type: 'supabase-bucket',
191
+ * bucket: 'project-assets',
192
+ * },
171
193
  *
172
- * // Reactive source of attachment IDs
173
- * watchIds: (db, onUpdate) => {
174
- * // Using PowerSync's watch API
194
+ * // Reactive source of attachment paths
195
+ * watchPaths: (db, supabase, onUpdate) => {
196
+ * const controller = new AbortController();
175
197
  * db.watch('SELECT storagePath FROM photos WHERE storagePath IS NOT NULL', [], {
176
198
  * onResult: (results) => {
177
199
  * onUpdate(results.rows._array.map(r => r.storagePath));
178
200
  * }
179
- * });
201
+ * }, { signal: controller.signal });
202
+ * return () => controller.abort();
180
203
  * },
181
- *
182
- * // Optional: skip downloading videos
183
- * skipDownload: async ({ ids, db }) => {
184
- * const videos = await db.getAll<{ path: string }>(
185
- * `SELECT storagePath as path FROM photos WHERE storagePath IN (${ids.map(() => '?').join(',')}) AND mediaType LIKE 'video/%'`,
186
- * ids
187
- * );
188
- * return videos.map(v => v.path);
189
- * }
190
204
  * };
191
205
  * ```
192
206
  */
193
207
  interface AttachmentSourceConfig {
194
208
  /**
195
- * Storage bucket name for this attachment source.
196
- * Maps to the Supabase Storage bucket (or equivalent in other backends).
209
+ * Attachment storage source configuration.
210
+ * Supports Supabase Storage buckets or custom backends.
211
+ *
212
+ * For Supabase Storage:
213
+ * ```typescript
214
+ * source: {
215
+ * type: 'supabase-bucket',
216
+ * bucket: 'my-bucket',
217
+ * signed: true, // default, uses createSignedUrl
218
+ * }
219
+ * ```
220
+ *
221
+ * For custom backends:
222
+ * ```typescript
223
+ * source: {
224
+ * type: 'custom',
225
+ * getUrl: (path) => `https://cdn.example.com/${path}`,
226
+ * }
227
+ * ```
197
228
  */
198
- bucket: string;
229
+ source?: AttachmentSource;
199
230
  /**
200
- * Reactive source of attachment IDs. Called once during initialization.
231
+ * Reactive source of attachment paths. Called once during initialization.
201
232
  *
202
233
  * This callback should set up a reactive subscription that calls `onUpdate`
203
- * whenever the set of attachment IDs changes. The queue will:
204
- * - Queue downloads for new IDs on first emission
205
- * - Queue downloads for IDs that appear in subsequent emissions
206
- * - Auto-archive attachments whose IDs disappear from emissions
234
+ * whenever the set of attachment paths changes. The queue will:
235
+ * - Queue downloads for new paths on first emission
236
+ * - Queue downloads for paths that appear in subsequent emissions
237
+ * - Auto-archive attachments whose paths disappear from emissions
207
238
  *
208
- * For simple single-table cases, you can use `table` and `pathColumn` instead
209
- * of providing a custom `watchIds` callback.
239
+ * Filtering should happen in this callback - only emit paths you want to download.
210
240
  *
211
241
  * @param db - PowerSync database instance for querying
212
- * @param onUpdate - Callback to emit current set of attachment IDs
242
+ * @param supabase - Supabase client for additional queries if needed
243
+ * @param onUpdate - Callback to emit current set of attachment paths
213
244
  * @returns Optional cleanup function to dispose of the watch subscription
214
245
  *
215
246
  * @example
216
247
  * ```typescript
217
- * watchIds: (db, onUpdate) => {
248
+ * watchPaths: (db, supabase, onUpdate) => {
218
249
  * const abort = new AbortController();
219
250
  * db.watch(
220
- * 'SELECT storagePath FROM photos WHERE storagePath IS NOT NULL',
251
+ * // Only emit non-video paths (filtering happens here)
252
+ * `SELECT storagePath FROM photos
253
+ * WHERE storagePath IS NOT NULL
254
+ * AND mediaType NOT LIKE 'video/%'`,
221
255
  * [],
222
256
  * { onResult: (r) => onUpdate(r.rows._array.map(row => row.storagePath)) },
223
257
  * { signal: abort.signal }
@@ -226,16 +260,17 @@ interface AttachmentSourceConfig {
226
260
  * }
227
261
  * ```
228
262
  */
229
- watchIds?: (db: AbstractPowerSyncDatabase, onUpdate: (ids: string[]) => void) => (() => void) | void;
263
+ watchPaths?: (db: AbstractPowerSyncDatabase, supabase: unknown, // SupabaseClient - using unknown to avoid import
264
+ onUpdate: (paths: string[]) => void) => (() => void) | void;
230
265
  /**
231
266
  * Source table name for simplified configuration.
232
- * Use with `pathColumn` as an alternative to providing a custom `watchIds` callback.
267
+ * Use with `pathColumn` as an alternative to providing a custom `watchPaths` callback.
233
268
  * Only for simple single-table cases without JOINs.
234
269
  *
235
270
  * @example
236
271
  * ```typescript
237
272
  * const config: AttachmentSourceConfig = {
238
- * bucket: 'photos',
273
+ * source: { type: 'supabase-bucket', bucket: 'photos' },
239
274
  * table: 'EquipmentUnitMediaContent',
240
275
  * pathColumn: 'storagePath',
241
276
  * };
@@ -243,74 +278,45 @@ interface AttachmentSourceConfig {
243
278
  */
244
279
  table?: string;
245
280
  /**
246
- * Column containing the attachment path/ID for simplified configuration.
247
- * Use with `table` as an alternative to providing a custom `watchIds` callback.
281
+ * Column containing the attachment path for simplified configuration.
282
+ * Use with `table` as an alternative to providing a custom `watchPaths` callback.
248
283
  *
249
284
  * @example
250
285
  * ```typescript
251
286
  * const config: AttachmentSourceConfig = {
252
- * bucket: 'photos',
287
+ * source: { type: 'supabase-bucket', bucket: 'photos' },
253
288
  * table: 'EquipmentUnitMediaContent',
254
289
  * pathColumn: 'storagePath',
255
290
  * };
256
291
  * ```
257
292
  */
258
293
  pathColumn?: string;
259
- /**
260
- * Optional batch filter to skip downloading certain attachments.
261
- *
262
- * Called with all pending attachment IDs. Return the IDs that should
263
- * be SKIPPED (not downloaded). Useful for:
264
- * - Filtering out video files on mobile
265
- * - Skipping large files
266
- * - Conditional download based on user preferences
267
- *
268
- * @param context - Contains pending IDs and database access
269
- * @returns Promise resolving to array of IDs to skip
270
- *
271
- * @example
272
- * ```typescript
273
- * skipDownload: async ({ ids, db }) => {
274
- * // Skip video files
275
- * const videos = await db.getAll<{ id: string }>(
276
- * `SELECT storagePath as id FROM photos
277
- * WHERE storagePath IN (${ids.map(() => '?').join(',')})
278
- * AND mediaType LIKE 'video/%'`,
279
- * ids
280
- * );
281
- * return videos.map(v => v.id);
282
- * }
283
- * ```
284
- */
285
- skipDownload?: (context: SkipDownloadContext) => Promise<string[]>;
286
- }
287
- /**
288
- * Context passed to the skipDownload callback.
289
- */
290
- interface SkipDownloadContext {
291
- /** All pending attachment IDs to evaluate */
292
- ids: string[];
293
- /** PowerSync database instance for queries */
294
- db: AbstractPowerSyncDatabase;
295
294
  }
296
295
  /**
297
296
  * Full attachment configuration including source configs and handlers.
298
297
  * This extends the source config with upload/download handlers and callbacks.
299
298
  */
300
299
  interface AttachmentConfig {
301
- /** Bucket name in Supabase storage */
302
- bucket: string;
303
300
  /**
304
- * Reactive source of attachment IDs. Called once during initialization.
305
- * May return an optional cleanup function to dispose of the watch subscription.
306
- * @see AttachmentSourceConfig.watchIds
301
+ * Attachment storage source configuration.
302
+ * Supports Supabase Storage buckets or custom backends.
303
+ *
304
+ * @example
305
+ * ```typescript
306
+ * source: {
307
+ * type: 'supabase-bucket',
308
+ * bucket: 'my-bucket',
309
+ * signed: true, // default
310
+ * }
311
+ * ```
307
312
  */
308
- watchIds: AttachmentSourceConfig["watchIds"];
313
+ source?: AttachmentSource;
309
314
  /**
310
- * Optional batch filter to skip downloading certain attachments.
311
- * @see AttachmentSourceConfig.skipDownload
315
+ * Reactive source of attachment paths. Called once during initialization.
316
+ * May return an optional cleanup function to dispose of the watch subscription.
317
+ * @see AttachmentSourceConfig.watchPaths
312
318
  */
313
- skipDownload?: AttachmentSourceConfig["skipDownload"];
319
+ watchPaths?: AttachmentSourceConfig["watchPaths"];
314
320
  /** Optional: callback when upload completes */
315
321
  onUploadComplete?: (attachment: AttachmentRecord) => void;
316
322
  /** Optional: callback when upload fails */
@@ -321,12 +327,6 @@ interface AttachmentConfig {
321
327
  remoteStorage?: AttachmentStorageAdapter;
322
328
  /** Optional: upload handler for uploads */
323
329
  uploadHandler?: UploadHandler;
324
- /**
325
- * Optional: image compression settings for downloads.
326
- * Uses Supabase's transform feature to resize/compress images on download.
327
- * Only applies to supported image formats (jpg, png, webp, avif, gif, heic).
328
- */
329
- compression?: Partial<CompressionConfig>;
330
330
  /**
331
331
  * Optional: download configuration for performance tuning.
332
332
  * Adjusts concurrency and timeout for downloads.
@@ -639,243 +639,36 @@ interface IdRow {
639
639
  * AttachmentRecord is exported as OfficialAttachmentRecord.
640
640
  */
641
641
  type AttachmentRecord = PolAttachmentRecord;
642
-
643
642
  /**
644
- * POL Attachment Queue
645
- *
646
- * Extends the official @powersync/attachments AbstractAttachmentQueue with
647
- * POL-specific features:
648
- * - Reactive watchIds callback for attachment ID sources
649
- * - Optional skipDownload callback for filtering downloads
650
- * - Durable upload queue with exponential backoff retry
651
- * - FAILED_PERMANENT state for unrecoverable upload errors
652
- * - Image compression integration
653
- * - Upload callbacks (onUploadComplete, onUploadFailed)
643
+ * Resolve the bucket name from an AttachmentConfig or AttachmentSourceConfig.
654
644
  *
655
- * @example
656
- * ```typescript
657
- * const queue = new PolAttachmentQueue({
658
- * powersync: db,
659
- * storage: storageAdapter,
660
- * source: {
661
- * bucket: 'project-assets',
662
- * watchIds: (db, onUpdate) => {
663
- * db.watch('SELECT storagePath FROM photos WHERE storagePath IS NOT NULL', [], {
664
- * onResult: (r) => onUpdate(r.rows._array.map(row => row.storagePath))
665
- * });
666
- * },
667
- * skipDownload: async ({ ids, db }) => {
668
- * // Return IDs to skip downloading
669
- * const videos = await db.getAll('SELECT storagePath FROM photos WHERE mediaType LIKE "video/%"');
670
- * return videos.map(v => v.storagePath);
671
- * }
672
- * },
673
- * });
674
- *
675
- * await queue.init();
676
- * ```
645
+ * @param config - The attachment configuration
646
+ * @returns The bucket name, or undefined if not configured
677
647
  */
678
-
648
+ declare function resolveBucketFromConfig(config: AttachmentConfig | AttachmentSourceConfig): string | undefined;
679
649
  /**
680
- * Options for PolAttachmentQueue that extend the official AttachmentQueueOptions.
650
+ * Check if the attachment source uses signed URLs.
651
+ * Defaults to true for Supabase buckets, not applicable for custom sources.
652
+ *
653
+ * @param config - The attachment configuration
654
+ * @returns true if signed URLs should be used
681
655
  */
682
- interface PolAttachmentQueueOptions extends AttachmentQueueOptions {
683
- platform: PlatformAdapter;
684
- remoteStorage: AttachmentStorageAdapter;
685
- /** Attachment source configuration with reactive watchIds callback */
686
- source: AttachmentSourceConfig;
687
- uploadHandler?: UploadHandler;
688
- uploadConfig?: Partial<UploadConfig>;
689
- /** Download configuration for concurrency tuning */
690
- downloadConfig?: Partial<DownloadConfig>;
691
- onUploadComplete?: (record: PolAttachmentRecord) => Promise<void>;
692
- onUploadFailed?: (record: PolAttachmentRecord, error: Error) => void;
693
- compression?: Partial<CompressionConfig>;
694
- cache?: Partial<CacheConfig>;
695
- }
656
+ declare function isSignedUrlSource(config: AttachmentConfig | AttachmentSourceConfig): boolean;
696
657
  /**
697
- * POL Attachment Queue that extends the official AbstractAttachmentQueue.
698
- */
699
- declare class PolAttachmentQueue extends AbstractAttachmentQueue<PolAttachmentQueueOptions> {
700
- private readonly platform;
701
- private readonly polLogger;
702
- private readonly source;
703
- private readonly remoteStorage;
704
- private readonly uploadHandler?;
705
- private readonly uploadConfig;
706
- private readonly downloadConfig;
707
- private readonly compressionConfig;
708
- private readonly cacheConfig;
709
- private _uploadState;
710
- private _disposed;
711
- private _initialized;
712
- private _watchGeneration;
713
- private _watchIdsCleanup;
714
- private _watchMutex;
715
- private _networkListenerCleanup;
716
- private _wasConnected;
717
- private _progressCallbacks;
718
- private _lastNotifyTime;
719
- private _notifyTimer;
720
- private _cachedStats;
721
- private _cachedStatsTimestamp;
722
- constructor(options: PolAttachmentQueueOptions);
723
- watchUploads(): void;
724
- /**
725
- * Override parent's expireCache to disable count-based cache eviction.
726
- *
727
- * The parent implementation deletes SYNCED/ARCHIVED records beyond cacheLimit,
728
- * which caused a bug where downloads would reset because:
729
- * 1. expireCache deleted records beyond cacheLimit (default 100)
730
- * 2. watchIds still emitted those IDs
731
- * 3. They got re-created as QUEUED_DOWNLOAD
732
- * 4. Downloads restarted in an infinite loop
733
- *
734
- * Our implementation uses size-based cache limits only (via clearCache/cacheConfig.maxSize).
735
- */
736
- expireCache(): Promise<void>;
737
- /**
738
- * Override parent's watchDownloads to use concurrent downloads.
739
- *
740
- * The parent implementation downloads one file at a time.
741
- * This override processes downloads in parallel batches for faster sync.
742
- */
743
- watchDownloads(): void;
744
- /**
745
- * Process pending downloads with concurrency control.
746
- * Downloads multiple files in parallel based on downloadConfig.concurrency.
747
- * Enforces cache size limits after each batch completes.
748
- */
749
- private _downloadRecordsConcurrent;
750
- uploadAttachment(record: {
751
- id: string;
752
- }): Promise<boolean>;
753
- watchAttachmentIds(): Promise<void>;
754
- saveToQueue(record: Omit<AttachmentRecord$1, 'timestamp'>): Promise<AttachmentRecord$1>;
755
- onAttachmentIdsChange(onUpdate: (ids: string[]) => void): void;
756
- downloadRecord(record: AttachmentRecord$1): Promise<boolean>;
757
- newAttachmentRecord(record?: Partial<AttachmentRecord$1>): Promise<AttachmentRecord$1>;
758
- init(): Promise<void>;
759
- /**
760
- * Dispose the attachment queue and clean up resources.
761
- * This method is synchronous to ensure callers don't need to await it,
762
- * but it fires off async cleanup in the background for graceful shutdown.
763
- */
764
- dispose(): void;
765
- /**
766
- * Async cleanup that runs in the background after dispose().
767
- * Waits for active upload promises to settle gracefully.
768
- */
769
- private _asyncCleanup;
770
- queueUpload(options: {
771
- storagePath: string;
772
- sourceUri: string;
773
- filename: string;
774
- mediaType: string;
775
- bucketId?: string;
776
- metadata?: Record<string, unknown>;
777
- }): Promise<void>;
778
- getPendingUploads(): Promise<PolAttachmentRecord[]>;
779
- getSoonestRetryTime(): Promise<number | null>;
780
- getFailedPermanentUploads(): Promise<PolAttachmentRecord[]>;
781
- getStaleUploads(): Promise<PolAttachmentRecord[]>;
782
- getSyncedUploadsWithPendingCallback(): Promise<PolAttachmentRecord[]>;
783
- clearUploadCallback(id: string): Promise<void>;
784
- retryUpload(id: string): Promise<void>;
785
- /**
786
- * Reset all uploads in QUEUED_UPLOAD state so they retry immediately.
787
- * This clears retry counts and errors, allowing uploads to be retried fresh.
788
- *
789
- * @returns The number of uploads that were reset
790
- */
791
- resetUploadRetries(): Promise<number>;
792
- /**
793
- * Trigger immediate retry of uploads WITHOUT resetting their retry count.
794
- * This preserves backoff state for truly failing uploads while allowing
795
- * uploads that were waiting for network to retry immediately.
796
- *
797
- * Only affects uploads that:
798
- * - Are past their retry time (upload_next_retry_at <= now), OR
799
- * - Have no retry time set (upload_next_retry_at IS NULL)
800
- *
801
- * @returns The number of uploads that will be retried
802
- */
803
- retryUploads(): Promise<number>;
804
- deleteUpload(id: string): Promise<void>;
805
- /**
806
- * Re-queue an upload for an orphaned attachment.
807
- * Use this when a database record exists with a storagePath but the file was never uploaded.
808
- *
809
- * This handles the case where:
810
- * - User took a photo and the database record was created with a storagePath
811
- * - The attachment queue record was created but disappeared before upload completed
812
- * - The photo shows locally but was never uploaded to storage
813
- *
814
- * @param options.storagePath - The storage path (e.g., "projectId/fileId.jpg")
815
- * @param options.localFileUri - URI to the local file to upload
816
- * @param options.mediaType - MIME type of the file
817
- * @param options.bucketId - Optional bucket ID for multi-bucket setups
818
- * @returns true if upload was queued, false if already exists in valid state
819
- */
820
- requeueOrphanedUpload(options: {
821
- storagePath: string;
822
- localFileUri: string;
823
- mediaType: string;
824
- bucketId?: string;
825
- }): Promise<boolean>;
826
- getRecord(id: string): Promise<PolAttachmentRecord | null>;
827
- getFailedUploads(): Promise<PolAttachmentRecord[]>;
828
- retryFailedUpload(id: string): Promise<void>;
829
- deleteFailedUpload(id: string): Promise<void>;
830
- get activeUploads(): UploadStatus[];
831
- pauseUploads(): void;
832
- resumeUploads(): void;
833
- clearCache(): Promise<void>;
834
- cacheLocalFile(storagePath: string, sourceUri: string): Promise<void>;
835
- getLocalUriForStoragePath(storagePath: string): Promise<string | null>;
836
- /**
837
- * Purge attachments by their IDs.
838
- * Archives and deletes local files for the specified attachment IDs.
839
- * Useful for edge cases where external code needs to force-remove attachments.
840
- *
841
- * @param ids - Array of attachment IDs to purge
842
- */
843
- purgeAttachments(ids: string[]): Promise<void>;
844
- onProgress(callback: (stats: AttachmentSyncStats) => void): () => void;
845
- getStats(): Promise<AttachmentSyncStats>;
846
- /**
847
- * Repair attachment sizes for synced records that have size=0.
848
- * This backfills sizes from the actual file system for existing downloads.
849
- * @returns Number of records repaired
850
- */
851
- repairAttachmentSizes(): Promise<number>;
852
- private _getDownloadManagerDeps;
853
- private _getUploadManagerDeps;
854
- private _getCacheManagerDeps;
855
- private _startUploadProcessing;
856
- private _createTableIfNotExists;
857
- private _migrateUploadColumns;
858
- private _invalidateStatsCache;
859
- private _getStatus;
860
- private _notify;
861
- }
658
+ * Check if the attachment source is a custom (non-Supabase) source.
659
+ *
660
+ * @param config - The attachment configuration
661
+ * @returns true if this is a custom source
662
+ */
663
+ declare function isCustomSource(config: AttachmentConfig | AttachmentSourceConfig): config is AttachmentConfig & {
664
+ source: CustomAttachmentSource;
665
+ };
862
666
  /**
863
- * Factory function options that combine AttachmentConfig with required runtime dependencies.
667
+ * Get the URL resolver function for a custom source.
668
+ *
669
+ * @param config - The attachment configuration
670
+ * @returns The getUrl function, or undefined if not a custom source
864
671
  */
865
- interface CreateAttachmentQueueOptions extends AttachmentConfig {
866
- /** Remote storage adapter for downloading/uploading files */
867
- remoteStorage: AttachmentStorageAdapter;
868
- /** Upload handler for processing uploads */
869
- uploadHandler?: UploadHandler;
870
- /** Upload configuration */
871
- uploadConfig?: Partial<UploadConfig>;
872
- /** Download configuration (concurrency, timeout) */
873
- downloadConfig?: Partial<DownloadConfig>;
874
- /** Compression configuration */
875
- compression?: Partial<CompressionConfig>;
876
- /** Cache configuration */
877
- cache?: Partial<CacheConfig>;
878
- }
879
- declare function createPolAttachmentQueue(powersync: AbstractPowerSyncDatabase, platform: PlatformAdapter, config: CreateAttachmentQueueOptions): PolAttachmentQueue;
672
+ declare function getCustomUrlResolver(config: AttachmentConfig | AttachmentSourceConfig): ((path: string) => Promise<string> | string) | undefined;
880
673
 
881
- export { type AttachmentSourceConfig as A, type BatchFilterContext as B, type CompressionConfig as C, DEFAULT_COMPRESSION_CONFIG as D, type EvictRow as E, type AttachmentRecord as F, type IdRow as I, PolAttachmentQueue as P, type SimpleAttachmentConfig as S, type UploadConfig as U, type WatchConfig as W, type PolAttachmentQueueOptions as a, PolAttachmentState as b, createPolAttachmentQueue as c, type PolAttachmentRecord as d, type SkipDownloadContext as e, type AttachmentConfig as f, type AttachmentStorageAdapter as g, DEFAULT_UPLOAD_CONFIG as h, type UploadHandler as i, type DownloadConfig as j, DEFAULT_DOWNLOAD_CONFIG as k, type CacheConfig as l, DEFAULT_CACHE_CONFIG as m, CACHE_SIZE_PRESETS as n, type CacheSizePreset as o, type CacheSizeValue as p, formatCacheSize as q, type DownloadPhase as r, type DownloadStatus as s, type UploadPhase as t, type UploadStatus as u, type AttachmentSyncStatus as v, type AttachmentSyncStats as w, type AttachmentStatsRow as x, type CacheFileRow as y, type CachedSizeRow as z };
674
+ export { type AttachmentSource as A, resolveBucketFromConfig as B, type CustomAttachmentSource as C, DEFAULT_COMPRESSION_CONFIG as D, type EvictRow as E, isSignedUrlSource as F, isCustomSource as G, getCustomUrlResolver as H, type IdRow as I, PolAttachmentState as P, type SimpleAttachmentConfig as S, type UploadConfig as U, type WatchConfig as W, type PolAttachmentRecord as a, type SupabaseBucketSource as b, type AttachmentSourceConfig as c, type AttachmentConfig as d, type AttachmentStorageAdapter as e, type CompressionConfig as f, DEFAULT_UPLOAD_CONFIG as g, type UploadHandler as h, type DownloadConfig as i, DEFAULT_DOWNLOAD_CONFIG as j, type CacheConfig as k, DEFAULT_CACHE_CONFIG as l, CACHE_SIZE_PRESETS as m, type CacheSizePreset as n, type CacheSizeValue as o, formatCacheSize as p, type DownloadPhase as q, type DownloadStatus as r, type UploadPhase as s, type UploadStatus as t, type AttachmentSyncStatus as u, type AttachmentSyncStats as v, type AttachmentStatsRow as w, type CacheFileRow as x, type CachedSizeRow as y, type AttachmentRecord as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pol-studios/powersync",
3
- "version": "1.0.30",
3
+ "version": "1.0.32",
4
4
  "description": "Enterprise PowerSync integration for offline-first applications",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -52,8 +52,18 @@
52
52
  "types": "./dist/attachments/index.d.ts"
53
53
  },
54
54
  "./provider": {
55
- "import": "./dist/provider/index.js",
56
- "types": "./dist/provider/index.d.ts"
55
+ "react-native": {
56
+ "import": "./dist/provider/index.native.js",
57
+ "types": "./dist/provider/index.native.d.ts"
58
+ },
59
+ "browser": {
60
+ "import": "./dist/provider/index.web.js",
61
+ "types": "./dist/provider/index.web.d.ts"
62
+ },
63
+ "default": {
64
+ "import": "./dist/provider/index.js",
65
+ "types": "./dist/provider/index.d.ts"
66
+ }
57
67
  },
58
68
  "./sync": {
59
69
  "import": "./dist/sync/index.js",
@@ -132,6 +142,10 @@
132
142
  "./generator": {
133
143
  "import": "./dist/generator/index.js",
134
144
  "types": "./dist/generator/index.d.ts"
145
+ },
146
+ "./config": {
147
+ "import": "./dist/config/index.js",
148
+ "types": "./dist/config/index.d.ts"
135
149
  }
136
150
  },
137
151
  "files": [
@@ -141,7 +155,7 @@
141
155
  "commander": "^12.0.0",
142
156
  "jiti": "^2.4.0",
143
157
  "picocolors": "^1.0.0",
144
- "@pol-studios/db": "1.0.59"
158
+ "@pol-studios/db": "1.0.61"
145
159
  },
146
160
  "peerDependencies": {
147
161
  "@powersync/react-native": ">=1.0.8",
@@ -1 +0,0 @@
1
- //# sourceMappingURL=chunk-654ERHA7.js.map