@pol-studios/powersync 1.0.22 → 1.0.25

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 (39) hide show
  1. package/dist/attachments/index.d.ts +51 -17
  2. package/dist/attachments/index.js +6 -2
  3. package/dist/{chunk-PG2NPQG3.js → chunk-55DKCJV4.js} +25 -5
  4. package/dist/chunk-55DKCJV4.js.map +1 -0
  5. package/dist/{chunk-IMRSLJRV.js → chunk-BGBQYQV3.js} +129 -38
  6. package/dist/chunk-BGBQYQV3.js.map +1 -0
  7. package/dist/{chunk-ZM4ENYMF.js → chunk-C5ODS3XH.js} +51 -8
  8. package/dist/chunk-C5ODS3XH.js.map +1 -0
  9. package/dist/{chunk-4TXTAEF2.js → chunk-CACKC6XG.js} +3 -2
  10. package/dist/chunk-CACKC6XG.js.map +1 -0
  11. package/dist/{chunk-XOCIONAA.js → chunk-TIFL2KWE.js} +3 -3
  12. package/dist/{chunk-N4K7E53V.js → chunk-VB737IVN.js} +33 -41
  13. package/dist/{chunk-N4K7E53V.js.map → chunk-VB737IVN.js.map} +1 -1
  14. package/dist/connector/index.d.ts +1 -1
  15. package/dist/connector/index.js +1 -1
  16. package/dist/generator/cli.js +6 -1
  17. package/dist/generator/index.d.ts +1 -0
  18. package/dist/generator/index.js +9 -1
  19. package/dist/generator/index.js.map +1 -1
  20. package/dist/index.d.ts +3 -3
  21. package/dist/index.js +10 -6
  22. package/dist/index.native.d.ts +3 -3
  23. package/dist/index.native.js +10 -6
  24. package/dist/index.web.d.ts +3 -3
  25. package/dist/index.web.js +10 -6
  26. package/dist/{pol-attachment-queue-BVAIueoP.d.ts → pol-attachment-queue-BE2HU3Us.d.ts} +71 -7
  27. package/dist/provider/index.d.ts +2 -2
  28. package/dist/provider/index.js +4 -4
  29. package/dist/react/index.d.ts +1 -1
  30. package/dist/react/index.js +3 -3
  31. package/dist/{supabase-connector-WuiFiBnV.d.ts → supabase-connector-D2oIl2t8.d.ts} +13 -2
  32. package/dist/sync/index.d.ts +3 -0
  33. package/dist/sync/index.js +1 -1
  34. package/package.json +14 -4
  35. package/dist/chunk-4TXTAEF2.js.map +0 -1
  36. package/dist/chunk-IMRSLJRV.js.map +0 -1
  37. package/dist/chunk-PG2NPQG3.js.map +0 -1
  38. package/dist/chunk-ZM4ENYMF.js.map +0 -1
  39. /package/dist/{chunk-XOCIONAA.js.map → chunk-TIFL2KWE.js.map} +0 -0
package/dist/index.web.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  useAttachmentQueueContext,
5
5
  usePowerSyncContext,
6
6
  useSyncStatusContext
7
- } from "./chunk-XOCIONAA.js";
7
+ } from "./chunk-TIFL2KWE.js";
8
8
  import {
9
9
  DOWNLOAD_WORKFLOW_STATES,
10
10
  STATE_MAPPING,
@@ -16,6 +16,8 @@ import {
16
16
  buildRecordFetchQuery,
17
17
  buildWatchQuery,
18
18
  createMigrationStats,
19
+ createWatchIds,
20
+ extractIdsFromRows,
19
21
  formatMigrationStats,
20
22
  getStateName,
21
23
  isDownloadWorkflowState,
@@ -28,13 +30,13 @@ import {
28
30
  validateSqlIdentifier as validateSqlIdentifier2,
29
31
  validateWhereClause,
30
32
  watchConfigToSourceConfig
31
- } from "./chunk-ZM4ENYMF.js";
33
+ } from "./chunk-C5ODS3XH.js";
32
34
  import {
33
35
  ConflictBus,
34
36
  OfflineDataProvider,
35
37
  PowerSyncProvider,
36
38
  ProviderBridge
37
- } from "./chunk-N4K7E53V.js";
39
+ } from "./chunk-VB737IVN.js";
38
40
  import "./chunk-YHTZ7VMV.js";
39
41
  import {
40
42
  PowerSyncErrorBoundary
@@ -102,7 +104,7 @@ import {
102
104
  stripFileUri,
103
105
  uploadOne,
104
106
  validateSqlIdentifier
105
- } from "./chunk-4TXTAEF2.js";
107
+ } from "./chunk-CACKC6XG.js";
106
108
  import {
107
109
  DeadLetterQueue,
108
110
  createDeadLetterEntry,
@@ -117,7 +119,7 @@ import {
117
119
  HealthMonitor,
118
120
  MetricsCollector,
119
121
  SyncStatusTracker
120
- } from "./chunk-PG2NPQG3.js";
122
+ } from "./chunk-55DKCJV4.js";
121
123
  import {
122
124
  DEFAULT_CONNECTION_HEALTH,
123
125
  DEFAULT_SYNC_CONFIG,
@@ -260,7 +262,7 @@ import {
260
262
  runUploadErrorMiddlewareSync,
261
263
  successOnPgCodes,
262
264
  tableHandlers
263
- } from "./chunk-IMRSLJRV.js";
265
+ } from "./chunk-BGBQYQV3.js";
264
266
  import {
265
267
  AbortError,
266
268
  DEFAULT_BACKOFF_CONFIG,
@@ -418,6 +420,7 @@ export {
418
420
  createSyncError,
419
421
  createUploadManagerDeps,
420
422
  createUploadManagerState,
423
+ createWatchIds,
421
424
  createWebPlatformAdapter,
422
425
  defaultSchemaRouter,
423
426
  defineBackgroundSyncTask,
@@ -432,6 +435,7 @@ export {
432
435
  extractEntityIds,
433
436
  extractErrorCode,
434
437
  extractHttpStatusCode,
438
+ extractIdsFromRows,
435
439
  extractTableNames,
436
440
  fetchServerVersion,
437
441
  formatBytes,
@@ -92,15 +92,25 @@ interface PolAttachmentRecord {
92
92
  upload_bucket_id?: string | null;
93
93
  }
94
94
  /**
95
- * Legacy configuration for watching a source table.
96
- * @deprecated Use AttachmentSourceConfig with watchIds callback instead.
97
- * This interface is kept for backward compatibility with query-builder utilities.
95
+ * Configuration for watching a source table.
96
+ * 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.
98
100
  */
99
101
  interface WatchConfig {
100
102
  /** Source table name */
101
103
  table: string;
102
- /** Column containing attachment ID/path */
103
- idColumn: 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;
104
114
  /** Additional columns to include in context */
105
115
  selectColumns?: string[];
106
116
  /** Optional WHERE clause fragment (e.g., "storagePath IS NOT NULL") */
@@ -111,6 +121,28 @@ interface WatchConfig {
111
121
  direction: "ASC" | "DESC";
112
122
  };
113
123
  }
124
+ /**
125
+ * Simplified attachment configuration for single-table use cases.
126
+ * Use this when you have a single table with attachment paths and don't need
127
+ * complex JOIN queries or custom watch logic.
128
+ *
129
+ * @example
130
+ * ```typescript
131
+ * const config: SimpleAttachmentConfig = {
132
+ * bucket: 'photos',
133
+ * table: 'EquipmentUnitMediaContent',
134
+ * pathColumn: 'storagePath',
135
+ * };
136
+ * ```
137
+ */
138
+ interface SimpleAttachmentConfig {
139
+ /** Storage bucket name for this attachment source */
140
+ bucket: string;
141
+ /** Source table name */
142
+ table: string;
143
+ /** Column containing the attachment path/ID */
144
+ pathColumn: string;
145
+ }
114
146
  /**
115
147
  * Legacy context for batch filtering of attachments.
116
148
  * @deprecated Use SkipDownloadContext with skipDownload callback instead.
@@ -173,6 +205,9 @@ interface AttachmentSourceConfig {
173
205
  * - Queue downloads for IDs that appear in subsequent emissions
174
206
  * - Auto-archive attachments whose IDs disappear from emissions
175
207
  *
208
+ * For simple single-table cases, you can use `table` and `pathColumn` instead
209
+ * of providing a custom `watchIds` callback.
210
+ *
176
211
  * @param db - PowerSync database instance for querying
177
212
  * @param onUpdate - Callback to emit current set of attachment IDs
178
213
  * @returns Optional cleanup function to dispose of the watch subscription
@@ -191,7 +226,36 @@ interface AttachmentSourceConfig {
191
226
  * }
192
227
  * ```
193
228
  */
194
- watchIds: (db: AbstractPowerSyncDatabase, onUpdate: (ids: string[]) => void) => (() => void) | void;
229
+ watchIds?: (db: AbstractPowerSyncDatabase, onUpdate: (ids: string[]) => void) => (() => void) | void;
230
+ /**
231
+ * Source table name for simplified configuration.
232
+ * Use with `pathColumn` as an alternative to providing a custom `watchIds` callback.
233
+ * Only for simple single-table cases without JOINs.
234
+ *
235
+ * @example
236
+ * ```typescript
237
+ * const config: AttachmentSourceConfig = {
238
+ * bucket: 'photos',
239
+ * table: 'EquipmentUnitMediaContent',
240
+ * pathColumn: 'storagePath',
241
+ * };
242
+ * ```
243
+ */
244
+ table?: string;
245
+ /**
246
+ * Column containing the attachment path/ID for simplified configuration.
247
+ * Use with `table` as an alternative to providing a custom `watchIds` callback.
248
+ *
249
+ * @example
250
+ * ```typescript
251
+ * const config: AttachmentSourceConfig = {
252
+ * bucket: 'photos',
253
+ * table: 'EquipmentUnitMediaContent',
254
+ * pathColumn: 'storagePath',
255
+ * };
256
+ * ```
257
+ */
258
+ pathColumn?: string;
195
259
  /**
196
260
  * Optional batch filter to skip downloading certain attachments.
197
261
  *
@@ -814,4 +878,4 @@ interface CreateAttachmentQueueOptions extends AttachmentConfig {
814
878
  }
815
879
  declare function createPolAttachmentQueue(powersync: AbstractPowerSyncDatabase, platform: PlatformAdapter, config: CreateAttachmentQueueOptions): PolAttachmentQueue;
816
880
 
817
- export { type AttachmentSourceConfig as A, type BatchFilterContext as B, type CompressionConfig as C, DEFAULT_COMPRESSION_CONFIG as D, type EvictRow as E, type IdRow as I, PolAttachmentQueue as P, type SkipDownloadContext 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 AttachmentConfig as e, type AttachmentStorageAdapter 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 };
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 };
@@ -3,8 +3,8 @@ import { QueryClient } from '@tanstack/react-query';
3
3
  import { A as AbstractPowerSyncDatabase, a as SyncStatus, C as CrudEntry, S as SyncMode, F as FailedTransaction, h as CompletedTransaction, b as ConnectionHealth, e as SyncMetrics, D as DownloadProgress, E as EntitySyncState, f as SyncError } from '../types-CDqWh56B.js';
4
4
  import { PlatformAdapter } from '../platform/index.js';
5
5
  import { a as ConnectorConfig, i as ConflictBus } from '../types-DiBvmGEi.js';
6
- import { e as AttachmentConfig, P as PolAttachmentQueue, A as AttachmentSourceConfig, z as AttachmentRecord, C as CompressionConfig, i as DownloadConfig } from '../pol-attachment-queue-BVAIueoP.js';
7
- import { S as SupabaseConnector } from '../supabase-connector-WuiFiBnV.js';
6
+ import { f as AttachmentConfig, P as PolAttachmentQueue, A as AttachmentSourceConfig, F as AttachmentRecord, C as CompressionConfig, j as DownloadConfig } from '../pol-attachment-queue-BE2HU3Us.js';
7
+ import { S as SupabaseConnector } from '../supabase-connector-D2oIl2t8.js';
8
8
  import * as react from 'react';
9
9
  import react__default, { ReactNode } from 'react';
10
10
  import { Schema } from '@powersync/react-native';
@@ -2,11 +2,11 @@ import {
2
2
  OfflineDataProvider,
3
3
  PowerSyncProvider,
4
4
  ProviderBridge
5
- } from "../chunk-N4K7E53V.js";
5
+ } from "../chunk-VB737IVN.js";
6
6
  import "../chunk-YHTZ7VMV.js";
7
7
  import "../chunk-P6WOZO7H.js";
8
- import "../chunk-4TXTAEF2.js";
9
- import "../chunk-PG2NPQG3.js";
8
+ import "../chunk-CACKC6XG.js";
9
+ import "../chunk-55DKCJV4.js";
10
10
  import {
11
11
  DEFAULT_CONNECTION_HEALTH,
12
12
  DEFAULT_SYNC_CONFIG,
@@ -56,7 +56,7 @@ import "../chunk-XAEII4ZX.js";
56
56
  import "../chunk-Z6VOBGTU.js";
57
57
  import "../chunk-CGL33PL4.js";
58
58
  import "../chunk-WN5ZJ3E2.js";
59
- import "../chunk-IMRSLJRV.js";
59
+ import "../chunk-BGBQYQV3.js";
60
60
  import "../chunk-FV2HXEIY.js";
61
61
  import "../chunk-I2AYMY5O.js";
62
62
  export {
@@ -3,7 +3,7 @@ import react__default, { ReactNode } from 'react';
3
3
  import { Schema } from '@powersync/react-native';
4
4
  import { A as AuthProvider } from '../types-DiBvmGEi.js';
5
5
  import { a as StorageBackend } from '../types-D0WcHrq6.js';
6
- import { e as AttachmentConfig, P as PolAttachmentQueue } from '../pol-attachment-queue-BVAIueoP.js';
6
+ import { f as AttachmentConfig, P as PolAttachmentQueue } from '../pol-attachment-queue-BE2HU3Us.js';
7
7
  import { PlatformAdapter } from '../platform/index.js';
8
8
  import { f as SyncError, a as SyncStatus, A as AbstractPowerSyncDatabase } from '../types-CDqWh56B.js';
9
9
  import '@supabase/supabase-js';
@@ -6,10 +6,10 @@ import {
6
6
  useAttachmentQueueContext,
7
7
  usePowerSyncContext,
8
8
  useSyncStatusContext
9
- } from "../chunk-XOCIONAA.js";
10
- import "../chunk-4TXTAEF2.js";
9
+ } from "../chunk-TIFL2KWE.js";
10
+ import "../chunk-CACKC6XG.js";
11
11
  import "../chunk-24RDMMCL.js";
12
- import "../chunk-IMRSLJRV.js";
12
+ import "../chunk-BGBQYQV3.js";
13
13
  import "../chunk-FV2HXEIY.js";
14
14
  import "../chunk-I2AYMY5O.js";
15
15
  export {
@@ -82,9 +82,11 @@ declare class SupabaseConnector implements PowerSyncBackendConnector {
82
82
  private completionFailures;
83
83
  private static readonly COMPLETION_MAX_FAILURES;
84
84
  private static readonly COMPLETION_EXTENDED_TIMEOUT_MS;
85
+ private static readonly MAX_STORED_RESOLUTIONS;
85
86
  private autoRetryPaused;
86
87
  private entryCooldowns;
87
88
  private static readonly COOLDOWN_DURATION_MS;
89
+ private static readonly MAX_ENTRY_COOLDOWNS;
88
90
  private readonly uploadErrorMiddleware;
89
91
  constructor(options: SupabaseConnectorOptions);
90
92
  /**
@@ -170,7 +172,7 @@ declare class SupabaseConnector implements PowerSyncBackendConnector {
170
172
  * Process batched PUT (upsert) operations for a single table.
171
173
  * Falls back to individual processing if batch fails.
172
174
  * CRITICAL: Throws on first failure to maintain transaction atomicity.
173
- * @returns Array of successfully processed entries
175
+ * @returns Object containing successful and discarded entries
174
176
  * @throws Error on first failure - keeps entire transaction in ps_crud
175
177
  */
176
178
  private processBatchedPuts;
@@ -178,10 +180,19 @@ declare class SupabaseConnector implements PowerSyncBackendConnector {
178
180
  * Process batched DELETE operations for a single table.
179
181
  * Falls back to individual processing if batch fails.
180
182
  * CRITICAL: Throws on first failure to maintain transaction atomicity.
181
- * @returns Array of successfully processed entries
183
+ * @returns Object containing successful and discarded entries
182
184
  * @throws Error on first failure - keeps entire transaction in ps_crud
183
185
  */
184
186
  private processBatchedDeletes;
187
+ /**
188
+ * Process batched PATCH (update) operations for a single table.
189
+ * Uses parallel processing with configurable concurrency since each PATCH may have different fields.
190
+ * CRITICAL: Throws on first non-DiscardEntryError failure to maintain transaction atomicity.
191
+ * @param batchSize Number of concurrent PATCH operations (default: 5)
192
+ * @returns Object containing successful and discarded entries
193
+ * @throws Error on first non-DiscardEntryError failure - keeps entire transaction in ps_crud
194
+ */
195
+ private processBatchedPatches;
185
196
  /**
186
197
  * Check if a table has a _version column (cached).
187
198
  * P4.1: Uses Promise-based locking to prevent duplicate concurrent queries.
@@ -333,6 +333,8 @@ declare class MetricsCollector {
333
333
  private _initialized;
334
334
  private _syncStartTime;
335
335
  private _wasSyncing;
336
+ private _persistTimeout;
337
+ private readonly PERSIST_DEBOUNCE_MS;
336
338
  constructor(storage: AsyncStorageAdapter, logger: LoggerAdapter, options?: MetricsCollectorOptions);
337
339
  /**
338
340
  * Initialize the collector by loading persisted metrics.
@@ -380,6 +382,7 @@ declare class MetricsCollector {
380
382
  * @returns Unsubscribe function
381
383
  */
382
384
  onMetricsUpdate(listener: (metrics: SyncMetrics) => void): Unsubscribe;
385
+ private _schedulePersist;
383
386
  private _persist;
384
387
  private _notifyListeners;
385
388
  }
@@ -12,7 +12,7 @@ import {
12
12
  HealthMonitor,
13
13
  MetricsCollector,
14
14
  SyncStatusTracker
15
- } from "../chunk-PG2NPQG3.js";
15
+ } from "../chunk-55DKCJV4.js";
16
16
  import "../chunk-24RDMMCL.js";
17
17
  import "../chunk-CGL33PL4.js";
18
18
  import "../chunk-I2AYMY5O.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pol-studios/powersync",
3
- "version": "1.0.22",
3
+ "version": "1.0.25",
4
4
  "description": "Enterprise PowerSync integration for offline-first applications",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -141,7 +141,7 @@
141
141
  "commander": "^12.0.0",
142
142
  "jiti": "^2.4.0",
143
143
  "picocolors": "^1.0.0",
144
- "@pol-studios/db": "1.0.54"
144
+ "@pol-studios/db": "1.0.59"
145
145
  },
146
146
  "peerDependencies": {
147
147
  "@powersync/react-native": ">=1.0.8",
@@ -202,12 +202,18 @@
202
202
  "@babel/core": "^7.28.0",
203
203
  "@powersync/common": "^1.49.0",
204
204
  "@powersync/op-sqlite": "^0.8.0",
205
+ "@testing-library/react": "^16.0.0",
206
+ "@testing-library/react-hooks": "^8.0.1",
205
207
  "@types/react": "^18.0.0",
208
+ "@vitest/coverage-v8": "^3.0.0",
209
+ "@vitest/ui": "^3.0.0",
206
210
  "babel-plugin-react-compiler": "^1.0.0",
207
211
  "expo-background-task": "^0.0.1",
208
212
  "expo-task-manager": "^12.0.0",
213
+ "jsdom": "^26.0.0",
209
214
  "tsup": "^8.0.0",
210
- "typescript": "^5.0.0"
215
+ "typescript": "^5.0.0",
216
+ "vitest": "^3.0.0"
211
217
  },
212
218
  "publishConfig": {
213
219
  "access": "public"
@@ -215,6 +221,10 @@
215
221
  "scripts": {
216
222
  "build": "NODE_OPTIONS='--max-old-space-size=8192' tsup",
217
223
  "dev": "tsup --watch",
218
- "typecheck": "tsc --noEmit"
224
+ "typecheck": "tsc --noEmit",
225
+ "test": "vitest run",
226
+ "test:watch": "vitest",
227
+ "test:coverage": "vitest run --coverage",
228
+ "test:ui": "vitest --ui"
219
229
  }
220
230
  }