@pol-studios/powersync 1.0.4 → 1.0.7

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 (115) hide show
  1. package/dist/CacheSettingsManager-1exbOC6S.d.ts +261 -0
  2. package/dist/attachments/index.d.ts +65 -355
  3. package/dist/attachments/index.js +24 -6
  4. package/dist/{types-Cd7RhNqf.d.ts → background-sync-ChCXW-EV.d.ts} +53 -2
  5. package/dist/chunk-4C3RY5SU.js +204 -0
  6. package/dist/chunk-4C3RY5SU.js.map +1 -0
  7. package/dist/{chunk-3AYXHQ4W.js → chunk-53WH2JJV.js} +111 -47
  8. package/dist/chunk-53WH2JJV.js.map +1 -0
  9. package/dist/chunk-A4IBBWGO.js +377 -0
  10. package/dist/chunk-A4IBBWGO.js.map +1 -0
  11. package/dist/chunk-BREGB4WL.js +1768 -0
  12. package/dist/chunk-BREGB4WL.js.map +1 -0
  13. package/dist/{chunk-EJ23MXPQ.js → chunk-CGL33PL4.js} +3 -1
  14. package/dist/chunk-CGL33PL4.js.map +1 -0
  15. package/dist/chunk-DGUM43GV.js +11 -0
  16. package/dist/chunk-DHYUBVP7.js +131 -0
  17. package/dist/chunk-DHYUBVP7.js.map +1 -0
  18. package/dist/chunk-FV2HXEIY.js +124 -0
  19. package/dist/chunk-FV2HXEIY.js.map +1 -0
  20. package/dist/chunk-GKF7TOMT.js +1 -0
  21. package/dist/{chunk-OTJXIRWX.js → chunk-H772V6XQ.js} +304 -51
  22. package/dist/chunk-H772V6XQ.js.map +1 -0
  23. package/dist/{chunk-C2RSTGDC.js → chunk-HFOFLW5F.js} +525 -87
  24. package/dist/chunk-HFOFLW5F.js.map +1 -0
  25. package/dist/chunk-KGSFAE5B.js +1 -0
  26. package/dist/chunk-LNL64IJZ.js +1 -0
  27. package/dist/chunk-MKD2VCX3.js +32 -0
  28. package/dist/chunk-MKD2VCX3.js.map +1 -0
  29. package/dist/{chunk-7EMDVIZX.js → chunk-N75DEF5J.js} +19 -1
  30. package/dist/chunk-N75DEF5J.js.map +1 -0
  31. package/dist/chunk-P6WOZO7H.js +49 -0
  32. package/dist/chunk-P6WOZO7H.js.map +1 -0
  33. package/dist/chunk-TGBT5XBE.js +1 -0
  34. package/dist/chunk-TGBT5XBE.js.map +1 -0
  35. package/dist/chunk-UEYRTLKE.js +72 -0
  36. package/dist/chunk-UEYRTLKE.js.map +1 -0
  37. package/dist/chunk-WGHNIAF7.js +329 -0
  38. package/dist/chunk-WGHNIAF7.js.map +1 -0
  39. package/dist/chunk-WQ5MPAVC.js +449 -0
  40. package/dist/chunk-WQ5MPAVC.js.map +1 -0
  41. package/dist/{chunk-FPTDATY5.js → chunk-XQAJM2MW.js} +22 -11
  42. package/dist/chunk-XQAJM2MW.js.map +1 -0
  43. package/dist/chunk-YSTEESEG.js +676 -0
  44. package/dist/chunk-YSTEESEG.js.map +1 -0
  45. package/dist/chunk-ZEOKPWUC.js +1165 -0
  46. package/dist/chunk-ZEOKPWUC.js.map +1 -0
  47. package/dist/connector/index.d.ts +182 -2
  48. package/dist/connector/index.js +14 -3
  49. package/dist/core/index.d.ts +5 -3
  50. package/dist/core/index.js +5 -2
  51. package/dist/error/index.d.ts +54 -0
  52. package/dist/error/index.js +8 -0
  53. package/dist/error/index.js.map +1 -0
  54. package/dist/index.d.ts +237 -11
  55. package/dist/index.js +183 -27
  56. package/dist/index.native.d.ts +20 -9
  57. package/dist/index.native.js +183 -28
  58. package/dist/index.web.d.ts +20 -9
  59. package/dist/index.web.js +184 -28
  60. package/dist/maintenance/index.d.ts +118 -0
  61. package/dist/maintenance/index.js +17 -0
  62. package/dist/maintenance/index.js.map +1 -0
  63. package/dist/platform/index.d.ts +16 -1
  64. package/dist/platform/index.js +2 -0
  65. package/dist/platform/index.js.map +1 -1
  66. package/dist/platform/index.native.d.ts +2 -2
  67. package/dist/platform/index.native.js +2 -1
  68. package/dist/platform/index.web.d.ts +1 -1
  69. package/dist/platform/index.web.js +2 -1
  70. package/dist/pol-attachment-queue-C7YNXXhK.d.ts +676 -0
  71. package/dist/provider/index.d.ts +693 -12
  72. package/dist/provider/index.js +57 -12
  73. package/dist/storage/index.d.ts +6 -0
  74. package/dist/storage/index.js +28 -0
  75. package/dist/storage/index.js.map +1 -0
  76. package/dist/storage/index.native.d.ts +6 -0
  77. package/dist/storage/index.native.js +26 -0
  78. package/dist/storage/index.native.js.map +1 -0
  79. package/dist/storage/index.web.d.ts +6 -0
  80. package/dist/storage/index.web.js +26 -0
  81. package/dist/storage/index.web.js.map +1 -0
  82. package/dist/storage/upload/index.d.ts +55 -0
  83. package/dist/storage/upload/index.js +15 -0
  84. package/dist/storage/upload/index.js.map +1 -0
  85. package/dist/storage/upload/index.native.d.ts +57 -0
  86. package/dist/storage/upload/index.native.js +14 -0
  87. package/dist/storage/upload/index.native.js.map +1 -0
  88. package/dist/storage/upload/index.web.d.ts +5 -0
  89. package/dist/storage/upload/index.web.js +14 -0
  90. package/dist/storage/upload/index.web.js.map +1 -0
  91. package/dist/{index-Cb-NI0Ct.d.ts → supabase-connector-qLm-WHkM.d.ts} +146 -10
  92. package/dist/sync/index.d.ts +288 -22
  93. package/dist/sync/index.js +23 -5
  94. package/dist/types-BVacP54t.d.ts +52 -0
  95. package/dist/types-Bgvx7-E8.d.ts +187 -0
  96. package/dist/{types-afHtE1U_.d.ts → types-CDqWh56B.d.ts} +2 -0
  97. package/package.json +72 -2
  98. package/dist/chunk-32OLICZO.js +0 -1
  99. package/dist/chunk-3AYXHQ4W.js.map +0 -1
  100. package/dist/chunk-7EMDVIZX.js.map +0 -1
  101. package/dist/chunk-7JQZBZ5N.js +0 -1
  102. package/dist/chunk-C2RSTGDC.js.map +0 -1
  103. package/dist/chunk-EJ23MXPQ.js.map +0 -1
  104. package/dist/chunk-FPTDATY5.js.map +0 -1
  105. package/dist/chunk-GMFDCVMZ.js +0 -1285
  106. package/dist/chunk-GMFDCVMZ.js.map +0 -1
  107. package/dist/chunk-OLHGI472.js +0 -1
  108. package/dist/chunk-OTJXIRWX.js.map +0 -1
  109. package/dist/chunk-V6LJ6MR2.js +0 -740
  110. package/dist/chunk-V6LJ6MR2.js.map +0 -1
  111. package/dist/chunk-VJCL2SWD.js +0 -1
  112. /package/dist/{chunk-32OLICZO.js.map → chunk-DGUM43GV.js.map} +0 -0
  113. /package/dist/{chunk-7JQZBZ5N.js.map → chunk-GKF7TOMT.js.map} +0 -0
  114. /package/dist/{chunk-OLHGI472.js.map → chunk-KGSFAE5B.js.map} +0 -0
  115. /package/dist/{chunk-VJCL2SWD.js.map → chunk-LNL64IJZ.js.map} +0 -0
@@ -0,0 +1,449 @@
1
+ import {
2
+ resolveBucketFromConfig
3
+ } from "./chunk-MKD2VCX3.js";
4
+
5
+ // src/utils/mimeTypes.ts
6
+ var MIME_TYPES = {
7
+ // Images
8
+ jpg: "image/jpeg",
9
+ jpeg: "image/jpeg",
10
+ png: "image/png",
11
+ gif: "image/gif",
12
+ webp: "image/webp",
13
+ heic: "image/heic",
14
+ heif: "image/heic",
15
+ svg: "image/svg+xml",
16
+ bmp: "image/bmp",
17
+ tiff: "image/tiff",
18
+ tif: "image/tiff",
19
+ ico: "image/x-icon",
20
+ avif: "image/avif",
21
+ // Videos
22
+ mp4: "video/mp4",
23
+ mov: "video/quicktime",
24
+ avi: "video/x-msvideo",
25
+ webm: "video/webm",
26
+ mkv: "video/x-matroska",
27
+ m4v: "video/x-m4v",
28
+ "3gp": "video/3gpp",
29
+ flv: "video/x-flv",
30
+ // Audio
31
+ mp3: "audio/mpeg",
32
+ wav: "audio/wav",
33
+ ogg: "audio/ogg",
34
+ m4a: "audio/mp4",
35
+ aac: "audio/aac",
36
+ flac: "audio/flac",
37
+ wma: "audio/x-ms-wma",
38
+ // Documents
39
+ pdf: "application/pdf",
40
+ doc: "application/msword",
41
+ docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
42
+ xls: "application/vnd.ms-excel",
43
+ xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
44
+ ppt: "application/vnd.ms-powerpoint",
45
+ pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
46
+ txt: "text/plain",
47
+ csv: "text/csv",
48
+ rtf: "application/rtf",
49
+ odt: "application/vnd.oasis.opendocument.text",
50
+ ods: "application/vnd.oasis.opendocument.spreadsheet",
51
+ odp: "application/vnd.oasis.opendocument.presentation",
52
+ // Data formats
53
+ json: "application/json",
54
+ xml: "application/xml",
55
+ yaml: "application/x-yaml",
56
+ yml: "application/x-yaml",
57
+ // Archives
58
+ zip: "application/zip",
59
+ rar: "application/vnd.rar",
60
+ "7z": "application/x-7z-compressed",
61
+ tar: "application/x-tar",
62
+ gz: "application/gzip",
63
+ // Code
64
+ js: "text/javascript",
65
+ ts: "text/typescript",
66
+ jsx: "text/jsx",
67
+ tsx: "text/tsx",
68
+ css: "text/css",
69
+ html: "text/html",
70
+ htm: "text/html",
71
+ md: "text/markdown",
72
+ // Other
73
+ woff: "font/woff",
74
+ woff2: "font/woff2",
75
+ ttf: "font/ttf",
76
+ otf: "font/otf",
77
+ eot: "application/vnd.ms-fontobject"
78
+ };
79
+ var DEFAULT_MIME_TYPE = "application/octet-stream";
80
+ function getMimeType(extension) {
81
+ if (!extension) {
82
+ return DEFAULT_MIME_TYPE;
83
+ }
84
+ const ext = extension.replace(/^\./, "").toLowerCase();
85
+ return MIME_TYPES[ext] ?? DEFAULT_MIME_TYPE;
86
+ }
87
+ function getMimeTypeFromPath(filePath) {
88
+ if (!filePath) {
89
+ return DEFAULT_MIME_TYPE;
90
+ }
91
+ const ext = filePath.split(".").pop();
92
+ return getMimeType(ext);
93
+ }
94
+ function isImageMimeType(mimeType) {
95
+ return mimeType.startsWith("image/");
96
+ }
97
+ function isVideoMimeType(mimeType) {
98
+ return mimeType.startsWith("video/");
99
+ }
100
+ function isAudioMimeType(mimeType) {
101
+ return mimeType.startsWith("audio/");
102
+ }
103
+ function isDocumentMimeType(mimeType) {
104
+ return mimeType === "application/pdf" || mimeType.includes("wordprocessingml") || mimeType.includes("spreadsheetml") || mimeType.includes("presentationml") || mimeType.includes("msword") || mimeType.includes("ms-excel") || mimeType.includes("ms-powerpoint") || mimeType.includes("opendocument");
105
+ }
106
+ function getExtensionFromMimeType(mimeType) {
107
+ for (const [ext, mime] of Object.entries(MIME_TYPES)) {
108
+ if (mime === mimeType) {
109
+ return ext;
110
+ }
111
+ }
112
+ return void 0;
113
+ }
114
+
115
+ // src/storage/SupabaseStorageAdapter.ts
116
+ var SupabaseStorageAdapter = class {
117
+ client;
118
+ bucketConfig;
119
+ signedUrlExpiry;
120
+ fileSystem;
121
+ logger;
122
+ constructor(options, fileSystem) {
123
+ this.client = options.client;
124
+ this.bucketConfig = options.bucketConfig;
125
+ this.signedUrlExpiry = options.signedUrlExpiry ?? 60;
126
+ this.fileSystem = fileSystem;
127
+ this.logger = options.logger;
128
+ }
129
+ /**
130
+ * Set the file system adapter (can be set after construction).
131
+ */
132
+ setFileSystem(fileSystem) {
133
+ this.fileSystem = fileSystem;
134
+ }
135
+ /**
136
+ * Resolve the storage bucket for a given file path.
137
+ */
138
+ resolveBucket(filePath) {
139
+ return resolveBucketFromConfig(this.bucketConfig, filePath);
140
+ }
141
+ // ─── RemoteStorageAdapter Interface ─────────────────────────────────────────
142
+ /**
143
+ * Download a file from Supabase Storage to a local path.
144
+ *
145
+ * Uses the platform's streaming downloadFile method to avoid loading
146
+ * the entire file into memory (prevents OOM on large files).
147
+ */
148
+ async download(remotePath, localPath) {
149
+ if (!this.fileSystem) {
150
+ throw new Error("FileSystem adapter not configured");
151
+ }
152
+ const signedUrl = await this.getDownloadUrl(remotePath);
153
+ await this.fileSystem.downloadFile(signedUrl, localPath);
154
+ }
155
+ /**
156
+ * Get a signed download URL for a remote file.
157
+ */
158
+ async getDownloadUrl(remotePath) {
159
+ const bucket = this.resolveBucket(remotePath);
160
+ const {
161
+ data,
162
+ error
163
+ } = await this.client.storage.from(bucket).createSignedUrl(remotePath, this.signedUrlExpiry);
164
+ if (error) {
165
+ throw new Error(`Failed to create signed URL: ${error.message}`);
166
+ }
167
+ if (!data?.signedUrl) {
168
+ throw new Error("Failed to create signed URL: No URL returned");
169
+ }
170
+ return data.signedUrl;
171
+ }
172
+ /**
173
+ * Check if a file exists in remote storage.
174
+ */
175
+ async exists(remotePath) {
176
+ const bucket = this.resolveBucket(remotePath);
177
+ try {
178
+ const pathParts = remotePath.split("/");
179
+ const fileName = pathParts.pop();
180
+ const directory = pathParts.join("/");
181
+ const {
182
+ data,
183
+ error
184
+ } = await this.client.storage.from(bucket).list(directory, {
185
+ search: fileName,
186
+ limit: 1
187
+ });
188
+ if (error) {
189
+ return false;
190
+ }
191
+ return data?.some((file) => file.name === fileName) ?? false;
192
+ } catch {
193
+ return false;
194
+ }
195
+ }
196
+ // ─── PowerSyncStorageAdapter Interface ──────────────────────────────────────
197
+ /**
198
+ * No-op for uploads. Use SupabaseUploadHandler for upload operations.
199
+ *
200
+ * Uploads are handled separately by the upload manager pipeline to support
201
+ * background uploads and proper queue management.
202
+ */
203
+ async uploadFile(filename, _data, _options) {
204
+ const message = "[SupabaseStorageAdapter] uploadFile called but uploads should be handled by SupabaseUploadHandler. File:";
205
+ if (this.logger) {
206
+ this.logger.warn(message, filename);
207
+ } else {
208
+ console.warn(message, filename);
209
+ }
210
+ }
211
+ /**
212
+ * Download a file from Supabase Storage and return as a Blob.
213
+ *
214
+ * Uses signed URL + fetch to download the file efficiently.
215
+ * This method is required by the PowerSync attachments interface.
216
+ *
217
+ * Note: This loads the file into memory as a Blob. For very large files,
218
+ * consider using download() to save directly to disk instead.
219
+ */
220
+ async downloadFile(filePath) {
221
+ const signedUrl = await this.getDownloadUrl(filePath);
222
+ const response = await fetch(signedUrl);
223
+ if (!response.ok) {
224
+ throw new Error(`Download failed with status ${response.status}: ${filePath}`);
225
+ }
226
+ const blob = await response.blob();
227
+ if (!blob.type || blob.type === "application/octet-stream") {
228
+ const mimeType = getMimeTypeFromPath(filePath);
229
+ return new Blob([blob], {
230
+ type: mimeType
231
+ });
232
+ }
233
+ return blob;
234
+ }
235
+ /**
236
+ * Write data to a local file.
237
+ */
238
+ async writeFile(fileURI, data, options) {
239
+ if (!this.fileSystem) {
240
+ throw new Error("FileSystem adapter not configured");
241
+ }
242
+ const encoding = options?.encoding ?? "utf8";
243
+ const parentDir = fileURI.substring(0, fileURI.lastIndexOf("/"));
244
+ if (parentDir) {
245
+ await this.fileSystem.makeDirectory(parentDir, {
246
+ intermediates: true
247
+ });
248
+ }
249
+ await this.fileSystem.writeFile(fileURI, data, encoding);
250
+ }
251
+ /**
252
+ * Read data from a local file.
253
+ */
254
+ async readFile(fileURI, options) {
255
+ if (!this.fileSystem) {
256
+ throw new Error("FileSystem adapter not configured");
257
+ }
258
+ const encoding = options?.encoding ?? "utf8";
259
+ const content = await this.fileSystem.readFile(fileURI, encoding);
260
+ if (encoding === "base64") {
261
+ const binaryString = atob(content);
262
+ const bytes = new Uint8Array(binaryString.length);
263
+ for (let i = 0; i < binaryString.length; i++) {
264
+ bytes[i] = binaryString.charCodeAt(i);
265
+ }
266
+ return bytes.buffer;
267
+ }
268
+ const encoder = new TextEncoder();
269
+ return encoder.encode(content).buffer;
270
+ }
271
+ /**
272
+ * Delete a local file.
273
+ */
274
+ async deleteFile(uri, _options) {
275
+ if (!this.fileSystem) {
276
+ throw new Error("FileSystem adapter not configured");
277
+ }
278
+ await this.fileSystem.deleteFile(uri);
279
+ }
280
+ /**
281
+ * Check if a local file exists.
282
+ */
283
+ async fileExists(fileURI) {
284
+ if (!this.fileSystem) {
285
+ throw new Error("FileSystem adapter not configured");
286
+ }
287
+ const info = await this.fileSystem.getFileInfo(fileURI);
288
+ return info?.exists ?? false;
289
+ }
290
+ /**
291
+ * Create a directory.
292
+ */
293
+ async makeDir(uri) {
294
+ if (!this.fileSystem) {
295
+ throw new Error("FileSystem adapter not configured");
296
+ }
297
+ await this.fileSystem.makeDirectory(uri, {
298
+ intermediates: true
299
+ });
300
+ }
301
+ /**
302
+ * Copy a file.
303
+ */
304
+ async copyFile(sourceUri, targetUri) {
305
+ if (!this.fileSystem) {
306
+ throw new Error("FileSystem adapter not configured");
307
+ }
308
+ await this.fileSystem.copyFile(sourceUri, targetUri);
309
+ }
310
+ /**
311
+ * Get the user storage directory.
312
+ */
313
+ getUserStorageDirectory() {
314
+ if (!this.fileSystem) {
315
+ throw new Error("FileSystem adapter not configured");
316
+ }
317
+ return this.fileSystem.getDocumentsDirectory();
318
+ }
319
+ };
320
+ function createSupabaseStorageAdapter(client, defaultBucket, fileSystem, options) {
321
+ return new SupabaseStorageAdapter({
322
+ client,
323
+ bucketConfig: {
324
+ defaultBucket,
325
+ bucketMap: options?.bucketMap
326
+ },
327
+ signedUrlExpiry: options?.signedUrlExpiry,
328
+ logger: options?.logger
329
+ }, fileSystem);
330
+ }
331
+
332
+ // src/storage/cache/types.ts
333
+ var DEFAULT_CACHE_SETTINGS = {
334
+ maxCacheSizeMb: 5120,
335
+ // 5 GB
336
+ compressionQuality: 0.7
337
+ // 70% quality
338
+ };
339
+
340
+ // src/storage/cache/CacheSettingsManager.ts
341
+ var STORAGE_KEYS = {
342
+ MAX_CACHE_SIZE_MB: "max-cache-size-mb",
343
+ COMPRESSION_QUALITY: "compression-quality"
344
+ };
345
+ var CacheSettingsManager = class {
346
+ storage;
347
+ keyPrefix;
348
+ defaults;
349
+ constructor(storage, options) {
350
+ this.storage = storage;
351
+ this.keyPrefix = options?.storageKeyPrefix ?? "@pol-studios/cache";
352
+ this.defaults = {
353
+ ...DEFAULT_CACHE_SETTINGS,
354
+ ...options?.defaults
355
+ };
356
+ }
357
+ /**
358
+ * Get the full storage key for a setting.
359
+ */
360
+ getKey(setting) {
361
+ return `${this.keyPrefix}/${STORAGE_KEYS[setting]}`;
362
+ }
363
+ /**
364
+ * Get all cache settings.
365
+ */
366
+ async getSettings() {
367
+ const keys = [this.getKey("MAX_CACHE_SIZE_MB"), this.getKey("COMPRESSION_QUALITY")];
368
+ const results = await this.storage.multiGet(keys);
369
+ const sizeValue = results.find(([k]) => k === keys[0])?.[1];
370
+ const qualityValue = results.find(([k]) => k === keys[1])?.[1];
371
+ return {
372
+ maxCacheSizeMb: sizeValue ? Number(sizeValue) : this.defaults.maxCacheSizeMb,
373
+ compressionQuality: qualityValue ? Number(qualityValue) : this.defaults.compressionQuality
374
+ };
375
+ }
376
+ /**
377
+ * Get the maximum cache size in megabytes.
378
+ * Returns 0 for unlimited.
379
+ */
380
+ async getMaxCacheSizeMb() {
381
+ const value = await this.storage.getItem(this.getKey("MAX_CACHE_SIZE_MB"));
382
+ return value ? Number(value) : this.defaults.maxCacheSizeMb;
383
+ }
384
+ /**
385
+ * Set the maximum cache size in megabytes.
386
+ * Use 0 for unlimited.
387
+ *
388
+ * @param mb - Maximum cache size in megabytes
389
+ */
390
+ async setMaxCacheSizeMb(mb) {
391
+ if (mb < 0) {
392
+ throw new Error("Cache size must be non-negative");
393
+ }
394
+ await this.storage.setItem(this.getKey("MAX_CACHE_SIZE_MB"), String(mb));
395
+ }
396
+ /**
397
+ * Get the maximum cache size in bytes.
398
+ * Returns Number.MAX_SAFE_INTEGER for unlimited.
399
+ */
400
+ async getMaxCacheSizeBytes() {
401
+ const mb = await this.getMaxCacheSizeMb();
402
+ return mb === 0 ? Number.MAX_SAFE_INTEGER : mb * 1024 * 1024;
403
+ }
404
+ /**
405
+ * Get the compression quality (0.0 to 1.0).
406
+ */
407
+ async getCompressionQuality() {
408
+ const value = await this.storage.getItem(this.getKey("COMPRESSION_QUALITY"));
409
+ return value ? Number(value) : this.defaults.compressionQuality;
410
+ }
411
+ /**
412
+ * Set the compression quality.
413
+ *
414
+ * @param quality - Compression quality (0.0 to 1.0)
415
+ */
416
+ async setCompressionQuality(quality) {
417
+ if (quality < 0 || quality > 1) {
418
+ throw new Error("Compression quality must be between 0 and 1");
419
+ }
420
+ await this.storage.setItem(this.getKey("COMPRESSION_QUALITY"), String(quality));
421
+ }
422
+ /**
423
+ * Reset all settings to defaults.
424
+ */
425
+ async resetToDefaults() {
426
+ await this.storage.multiSet([[this.getKey("MAX_CACHE_SIZE_MB"), String(this.defaults.maxCacheSizeMb)], [this.getKey("COMPRESSION_QUALITY"), String(this.defaults.compressionQuality)]]);
427
+ }
428
+ /**
429
+ * Clear all stored settings.
430
+ */
431
+ async clear() {
432
+ await Promise.all([this.storage.removeItem(this.getKey("MAX_CACHE_SIZE_MB")), this.storage.removeItem(this.getKey("COMPRESSION_QUALITY"))]);
433
+ }
434
+ };
435
+
436
+ export {
437
+ getMimeType,
438
+ getMimeTypeFromPath,
439
+ isImageMimeType,
440
+ isVideoMimeType,
441
+ isAudioMimeType,
442
+ isDocumentMimeType,
443
+ getExtensionFromMimeType,
444
+ SupabaseStorageAdapter,
445
+ createSupabaseStorageAdapter,
446
+ DEFAULT_CACHE_SETTINGS,
447
+ CacheSettingsManager
448
+ };
449
+ //# sourceMappingURL=chunk-WQ5MPAVC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/mimeTypes.ts","../src/storage/SupabaseStorageAdapter.ts","../src/storage/cache/types.ts","../src/storage/cache/CacheSettingsManager.ts"],"sourcesContent":["/**\n * MIME Type Utilities for @pol-studios/powersync\n *\n * Provides file extension to MIME type mapping for storage operations.\n */\n\n/**\n * MIME type mappings by file extension\n */\nconst MIME_TYPES: Record<string, string> = {\n // Images\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n png: 'image/png',\n gif: 'image/gif',\n webp: 'image/webp',\n heic: 'image/heic',\n heif: 'image/heic',\n svg: 'image/svg+xml',\n bmp: 'image/bmp',\n tiff: 'image/tiff',\n tif: 'image/tiff',\n ico: 'image/x-icon',\n avif: 'image/avif',\n // Videos\n mp4: 'video/mp4',\n mov: 'video/quicktime',\n avi: 'video/x-msvideo',\n webm: 'video/webm',\n mkv: 'video/x-matroska',\n m4v: 'video/x-m4v',\n '3gp': 'video/3gpp',\n flv: 'video/x-flv',\n // Audio\n mp3: 'audio/mpeg',\n wav: 'audio/wav',\n ogg: 'audio/ogg',\n m4a: 'audio/mp4',\n aac: 'audio/aac',\n flac: 'audio/flac',\n wma: 'audio/x-ms-wma',\n // Documents\n pdf: 'application/pdf',\n doc: 'application/msword',\n docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n xls: 'application/vnd.ms-excel',\n xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n ppt: 'application/vnd.ms-powerpoint',\n pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n txt: 'text/plain',\n csv: 'text/csv',\n rtf: 'application/rtf',\n odt: 'application/vnd.oasis.opendocument.text',\n ods: 'application/vnd.oasis.opendocument.spreadsheet',\n odp: 'application/vnd.oasis.opendocument.presentation',\n // Data formats\n json: 'application/json',\n xml: 'application/xml',\n yaml: 'application/x-yaml',\n yml: 'application/x-yaml',\n // Archives\n zip: 'application/zip',\n rar: 'application/vnd.rar',\n '7z': 'application/x-7z-compressed',\n tar: 'application/x-tar',\n gz: 'application/gzip',\n // Code\n js: 'text/javascript',\n ts: 'text/typescript',\n jsx: 'text/jsx',\n tsx: 'text/tsx',\n css: 'text/css',\n html: 'text/html',\n htm: 'text/html',\n md: 'text/markdown',\n // Other\n woff: 'font/woff',\n woff2: 'font/woff2',\n ttf: 'font/ttf',\n otf: 'font/otf',\n eot: 'application/vnd.ms-fontobject'\n};\n\n/**\n * Default MIME type for unknown file extensions\n */\nconst DEFAULT_MIME_TYPE = 'application/octet-stream';\n\n/**\n * Get MIME type from file extension.\n *\n * @param extension - File extension (with or without leading dot)\n * @returns MIME type string\n *\n * @example\n * ```typescript\n * getMimeType('jpg'); // 'image/jpeg'\n * getMimeType('.png'); // 'image/png'\n * getMimeType('unknown'); // 'application/octet-stream'\n * getMimeType(undefined); // 'application/octet-stream'\n * ```\n */\nexport function getMimeType(extension: string | undefined | null): string {\n if (!extension) {\n return DEFAULT_MIME_TYPE;\n }\n\n // Remove leading dot if present and convert to lowercase\n const ext = extension.replace(/^\\./, '').toLowerCase();\n return MIME_TYPES[ext] ?? DEFAULT_MIME_TYPE;\n}\n\n/**\n * Get MIME type from a file path or filename.\n *\n * @param filePath - Full file path or filename\n * @returns MIME type string\n *\n * @example\n * ```typescript\n * getMimeTypeFromPath('/path/to/image.jpg'); // 'image/jpeg'\n * getMimeTypeFromPath('document.pdf'); // 'application/pdf'\n * getMimeTypeFromPath('file-without-extension'); // 'application/octet-stream'\n * ```\n */\nexport function getMimeTypeFromPath(filePath: string | undefined | null): string {\n if (!filePath) {\n return DEFAULT_MIME_TYPE;\n }\n const ext = filePath.split('.').pop();\n return getMimeType(ext);\n}\n\n/**\n * Check if a MIME type represents an image.\n */\nexport function isImageMimeType(mimeType: string): boolean {\n return mimeType.startsWith('image/');\n}\n\n/**\n * Check if a MIME type represents a video.\n */\nexport function isVideoMimeType(mimeType: string): boolean {\n return mimeType.startsWith('video/');\n}\n\n/**\n * Check if a MIME type represents audio.\n */\nexport function isAudioMimeType(mimeType: string): boolean {\n return mimeType.startsWith('audio/');\n}\n\n/**\n * Check if a MIME type represents a document (PDF, Office, etc.).\n */\nexport function isDocumentMimeType(mimeType: string): boolean {\n return mimeType === 'application/pdf' || mimeType.includes('wordprocessingml') || mimeType.includes('spreadsheetml') || mimeType.includes('presentationml') || mimeType.includes('msword') || mimeType.includes('ms-excel') || mimeType.includes('ms-powerpoint') || mimeType.includes('opendocument');\n}\n\n/**\n * Get file extension from MIME type (reverse lookup).\n * Returns the most common extension for the given MIME type.\n *\n * @param mimeType - MIME type string\n * @returns File extension without leading dot, or undefined if unknown\n */\nexport function getExtensionFromMimeType(mimeType: string): string | undefined {\n // Find the first matching extension\n for (const [ext, mime] of Object.entries(MIME_TYPES)) {\n if (mime === mimeType) {\n return ext;\n }\n }\n return undefined;\n}","/**\n * Supabase Storage Adapter for @pol-studios/powersync\n *\n * Provides attachment storage operations using Supabase Storage with\n * platform-agnostic file system operations via PlatformAdapter.\n *\n * Key features:\n * - Memory-efficient downloads using signed URLs + native file system\n * - Multi-bucket support via BucketConfig/BucketResolver\n * - Platform-agnostic via FileSystemAdapter interface\n * - Compatible with PowerSync attachments interface\n */\n\nimport type { FileSystemAdapter, LoggerAdapter } from '../platform/types';\nimport type { RemoteStorageAdapter, SupabaseStorageAdapterOptions, BucketConfig, PowerSyncStorageAdapter } from './types';\nimport { resolveBucketFromConfig } from './types';\nimport { getMimeTypeFromPath } from '../utils/mimeTypes';\n\n/**\n * Supabase Storage adapter for attachment downloads and local file operations.\n *\n * Uses PlatformAdapter's fileSystem for I/O operations to remain platform-agnostic.\n *\n * IMPORTANT: This adapter downloads files using signed URLs + platform file system\n * operations to avoid loading entire files into memory. This prevents OOM crashes\n * on large files that occurred with the previous blob-based approach.\n *\n * @example\n * ```typescript\n * const adapter = new SupabaseStorageAdapter(\n * {\n * client: supabaseClient,\n * bucketConfig: {\n * defaultBucket: 'attachments',\n * bucketMap: new Map([['avatars/', 'user-avatars']]),\n * },\n * },\n * platform.fileSystem\n * );\n *\n * // Download to local path\n * await adapter.download('photos/image.jpg', '/local/path/image.jpg');\n *\n * // Get signed URL for direct access\n * const url = await adapter.getDownloadUrl('photos/image.jpg');\n * ```\n */\nexport class SupabaseStorageAdapter implements RemoteStorageAdapter, PowerSyncStorageAdapter {\n private client: any;\n private bucketConfig: BucketConfig;\n private signedUrlExpiry: number;\n private fileSystem?: FileSystemAdapter;\n private logger?: LoggerAdapter;\n constructor(options: SupabaseStorageAdapterOptions, fileSystem?: FileSystemAdapter) {\n this.client = options.client;\n this.bucketConfig = options.bucketConfig;\n this.signedUrlExpiry = options.signedUrlExpiry ?? 60;\n this.fileSystem = fileSystem;\n this.logger = options.logger;\n }\n\n /**\n * Set the file system adapter (can be set after construction).\n */\n setFileSystem(fileSystem: FileSystemAdapter): void {\n this.fileSystem = fileSystem;\n }\n\n /**\n * Resolve the storage bucket for a given file path.\n */\n resolveBucket(filePath: string): string {\n return resolveBucketFromConfig(this.bucketConfig, filePath);\n }\n\n // ─── RemoteStorageAdapter Interface ─────────────────────────────────────────\n\n /**\n * Download a file from Supabase Storage to a local path.\n *\n * Uses the platform's streaming downloadFile method to avoid loading\n * the entire file into memory (prevents OOM on large files).\n */\n async download(remotePath: string, localPath: string): Promise<void> {\n if (!this.fileSystem) {\n throw new Error('FileSystem adapter not configured');\n }\n const signedUrl = await this.getDownloadUrl(remotePath);\n\n // Use the platform's streaming download method\n // This writes directly to disk without loading the entire file into memory\n await this.fileSystem.downloadFile(signedUrl, localPath);\n }\n\n /**\n * Get a signed download URL for a remote file.\n */\n async getDownloadUrl(remotePath: string): Promise<string> {\n const bucket = this.resolveBucket(remotePath);\n const {\n data,\n error\n } = await this.client.storage.from(bucket).createSignedUrl(remotePath, this.signedUrlExpiry);\n if (error) {\n throw new Error(`Failed to create signed URL: ${error.message}`);\n }\n if (!data?.signedUrl) {\n throw new Error('Failed to create signed URL: No URL returned');\n }\n return data.signedUrl;\n }\n\n /**\n * Check if a file exists in remote storage.\n */\n async exists(remotePath: string): Promise<boolean> {\n const bucket = this.resolveBucket(remotePath);\n try {\n // Use list with a specific path prefix to check existence\n const pathParts = remotePath.split('/');\n const fileName = pathParts.pop();\n const directory = pathParts.join('/');\n const {\n data,\n error\n } = await this.client.storage.from(bucket).list(directory, {\n search: fileName,\n limit: 1\n });\n if (error) {\n return false;\n }\n return data?.some((file: {\n name: string;\n }) => file.name === fileName) ?? false;\n } catch {\n return false;\n }\n }\n\n // ─── PowerSyncStorageAdapter Interface ──────────────────────────────────────\n\n /**\n * No-op for uploads. Use SupabaseUploadHandler for upload operations.\n *\n * Uploads are handled separately by the upload manager pipeline to support\n * background uploads and proper queue management.\n */\n async uploadFile(filename: string, _data: ArrayBuffer, _options?: {\n mediaType?: string;\n }): Promise<void> {\n const message = '[SupabaseStorageAdapter] uploadFile called but uploads should be handled by SupabaseUploadHandler. File:';\n if (this.logger) {\n this.logger.warn(message, filename);\n } else {\n console.warn(message, filename);\n }\n }\n\n /**\n * Download a file from Supabase Storage and return as a Blob.\n *\n * Uses signed URL + fetch to download the file efficiently.\n * This method is required by the PowerSync attachments interface.\n *\n * Note: This loads the file into memory as a Blob. For very large files,\n * consider using download() to save directly to disk instead.\n */\n async downloadFile(filePath: string): Promise<Blob> {\n const signedUrl = await this.getDownloadUrl(filePath);\n const response = await fetch(signedUrl);\n if (!response.ok) {\n throw new Error(`Download failed with status ${response.status}: ${filePath}`);\n }\n const blob = await response.blob();\n\n // If the blob doesn't have a type, set it based on file extension\n if (!blob.type || blob.type === 'application/octet-stream') {\n const mimeType = getMimeTypeFromPath(filePath);\n return new Blob([blob], {\n type: mimeType\n });\n }\n return blob;\n }\n\n /**\n * Write data to a local file.\n */\n async writeFile(fileURI: string, data: string, options?: {\n encoding?: 'utf8' | 'base64';\n }): Promise<void> {\n if (!this.fileSystem) {\n throw new Error('FileSystem adapter not configured');\n }\n const encoding = options?.encoding ?? 'utf8';\n\n // Ensure parent directory exists\n const parentDir = fileURI.substring(0, fileURI.lastIndexOf('/'));\n if (parentDir) {\n await this.fileSystem.makeDirectory(parentDir, {\n intermediates: true\n });\n }\n await this.fileSystem.writeFile(fileURI, data, encoding);\n }\n\n /**\n * Read data from a local file.\n */\n async readFile(fileURI: string, options?: {\n encoding?: 'utf8' | 'base64';\n mediaType?: string;\n }): Promise<ArrayBuffer> {\n if (!this.fileSystem) {\n throw new Error('FileSystem adapter not configured');\n }\n const encoding = options?.encoding ?? 'utf8';\n const content = await this.fileSystem.readFile(fileURI, encoding);\n if (encoding === 'base64') {\n // Decode base64 to ArrayBuffer\n const binaryString = atob(content);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n return bytes.buffer;\n }\n\n // For utf8, encode to ArrayBuffer\n const encoder = new TextEncoder();\n return encoder.encode(content).buffer;\n }\n\n /**\n * Delete a local file.\n */\n async deleteFile(uri: string, _options?: {\n filename?: string;\n }): Promise<void> {\n if (!this.fileSystem) {\n throw new Error('FileSystem adapter not configured');\n }\n await this.fileSystem.deleteFile(uri);\n }\n\n /**\n * Check if a local file exists.\n */\n async fileExists(fileURI: string): Promise<boolean> {\n if (!this.fileSystem) {\n throw new Error('FileSystem adapter not configured');\n }\n const info = await this.fileSystem.getFileInfo(fileURI);\n return info?.exists ?? false;\n }\n\n /**\n * Create a directory.\n */\n async makeDir(uri: string): Promise<void> {\n if (!this.fileSystem) {\n throw new Error('FileSystem adapter not configured');\n }\n await this.fileSystem.makeDirectory(uri, {\n intermediates: true\n });\n }\n\n /**\n * Copy a file.\n */\n async copyFile(sourceUri: string, targetUri: string): Promise<void> {\n if (!this.fileSystem) {\n throw new Error('FileSystem adapter not configured');\n }\n await this.fileSystem.copyFile(sourceUri, targetUri);\n }\n\n /**\n * Get the user storage directory.\n */\n getUserStorageDirectory(): string {\n if (!this.fileSystem) {\n throw new Error('FileSystem adapter not configured');\n }\n return this.fileSystem.getDocumentsDirectory();\n }\n}\n\n/**\n * Create a SupabaseStorageAdapter with simplified configuration.\n *\n * @example\n * ```typescript\n * const adapter = createSupabaseStorageAdapter(\n * supabaseClient,\n * 'attachments',\n * platform.fileSystem\n * );\n * ```\n */\nexport function createSupabaseStorageAdapter(client: any, defaultBucket: string, fileSystem?: FileSystemAdapter, options?: {\n bucketMap?: Map<string, string>;\n signedUrlExpiry?: number;\n logger?: LoggerAdapter;\n}): SupabaseStorageAdapter {\n return new SupabaseStorageAdapter({\n client,\n bucketConfig: {\n defaultBucket,\n bucketMap: options?.bucketMap\n },\n signedUrlExpiry: options?.signedUrlExpiry,\n logger: options?.logger\n }, fileSystem);\n}","/**\n * Cache Settings Types for @pol-studios/powersync\n *\n * Defines types for cache configuration storage.\n * Note: UI-specific options (labels, descriptions) should be defined in the app.\n */\n\n/**\n * Cache settings stored via AsyncStorageAdapter.\n */\nexport interface CacheSettings {\n /**\n * Maximum cache size in megabytes.\n * A value of 0 indicates unlimited cache size.\n */\n maxCacheSizeMb: number;\n\n /**\n * Compression quality for cached images (0.0 to 1.0).\n * Higher values mean better quality but larger file sizes.\n */\n compressionQuality: number;\n}\n\n/**\n * Options for creating a CacheSettingsManager.\n */\nexport interface CacheSettingsManagerOptions {\n /**\n * Prefix for storage keys.\n * Useful for namespacing when multiple apps share storage.\n * @default '@pol-studios/cache'\n */\n storageKeyPrefix?: string;\n\n /**\n * Default values for cache settings.\n */\n defaults?: Partial<CacheSettings>;\n}\n\n/**\n * Default cache settings values.\n */\nexport const DEFAULT_CACHE_SETTINGS: CacheSettings = {\n maxCacheSizeMb: 5120,\n // 5 GB\n compressionQuality: 0.7 // 70% quality\n};","/**\n * Cache Settings Manager for @pol-studios/powersync\n *\n * Manages persistence of cache settings via AsyncStorageAdapter.\n * Uses platform-agnostic storage interface for cross-platform support.\n */\n\nimport type { AsyncStorageAdapter } from '../../platform/types';\nimport type { CacheSettings, CacheSettingsManagerOptions } from './types';\nimport { DEFAULT_CACHE_SETTINGS } from './types';\n\n/**\n * Storage keys used by the cache settings manager.\n */\nconst STORAGE_KEYS = {\n MAX_CACHE_SIZE_MB: 'max-cache-size-mb',\n COMPRESSION_QUALITY: 'compression-quality'\n} as const;\n\n/**\n * Manages cache settings persistence using AsyncStorageAdapter.\n *\n * @example\n * ```typescript\n * const manager = new CacheSettingsManager(platform.storage, {\n * storageKeyPrefix: '@myapp/cache',\n * defaults: { maxCacheSizeMb: 2048 },\n * });\n *\n * const settings = await manager.getSettings();\n * await manager.setMaxCacheSizeMb(1024);\n * ```\n */\nexport class CacheSettingsManager {\n private storage: AsyncStorageAdapter;\n private keyPrefix: string;\n private defaults: CacheSettings;\n constructor(storage: AsyncStorageAdapter, options?: CacheSettingsManagerOptions) {\n this.storage = storage;\n this.keyPrefix = options?.storageKeyPrefix ?? '@pol-studios/cache';\n this.defaults = {\n ...DEFAULT_CACHE_SETTINGS,\n ...options?.defaults\n };\n }\n\n /**\n * Get the full storage key for a setting.\n */\n private getKey(setting: keyof typeof STORAGE_KEYS): string {\n return `${this.keyPrefix}/${STORAGE_KEYS[setting]}`;\n }\n\n /**\n * Get all cache settings.\n */\n async getSettings(): Promise<CacheSettings> {\n const keys = [this.getKey('MAX_CACHE_SIZE_MB'), this.getKey('COMPRESSION_QUALITY')];\n const results = await this.storage.multiGet(keys);\n\n // Build settings object from stored values or defaults\n const sizeValue = results.find(([k]) => k === keys[0])?.[1];\n const qualityValue = results.find(([k]) => k === keys[1])?.[1];\n return {\n maxCacheSizeMb: sizeValue ? Number(sizeValue) : this.defaults.maxCacheSizeMb,\n compressionQuality: qualityValue ? Number(qualityValue) : this.defaults.compressionQuality\n };\n }\n\n /**\n * Get the maximum cache size in megabytes.\n * Returns 0 for unlimited.\n */\n async getMaxCacheSizeMb(): Promise<number> {\n const value = await this.storage.getItem(this.getKey('MAX_CACHE_SIZE_MB'));\n return value ? Number(value) : this.defaults.maxCacheSizeMb;\n }\n\n /**\n * Set the maximum cache size in megabytes.\n * Use 0 for unlimited.\n *\n * @param mb - Maximum cache size in megabytes\n */\n async setMaxCacheSizeMb(mb: number): Promise<void> {\n if (mb < 0) {\n throw new Error('Cache size must be non-negative');\n }\n await this.storage.setItem(this.getKey('MAX_CACHE_SIZE_MB'), String(mb));\n }\n\n /**\n * Get the maximum cache size in bytes.\n * Returns Number.MAX_SAFE_INTEGER for unlimited.\n */\n async getMaxCacheSizeBytes(): Promise<number> {\n const mb = await this.getMaxCacheSizeMb();\n return mb === 0 ? Number.MAX_SAFE_INTEGER : mb * 1024 * 1024;\n }\n\n /**\n * Get the compression quality (0.0 to 1.0).\n */\n async getCompressionQuality(): Promise<number> {\n const value = await this.storage.getItem(this.getKey('COMPRESSION_QUALITY'));\n return value ? Number(value) : this.defaults.compressionQuality;\n }\n\n /**\n * Set the compression quality.\n *\n * @param quality - Compression quality (0.0 to 1.0)\n */\n async setCompressionQuality(quality: number): Promise<void> {\n if (quality < 0 || quality > 1) {\n throw new Error('Compression quality must be between 0 and 1');\n }\n await this.storage.setItem(this.getKey('COMPRESSION_QUALITY'), String(quality));\n }\n\n /**\n * Reset all settings to defaults.\n */\n async resetToDefaults(): Promise<void> {\n await this.storage.multiSet([[this.getKey('MAX_CACHE_SIZE_MB'), String(this.defaults.maxCacheSizeMb)], [this.getKey('COMPRESSION_QUALITY'), String(this.defaults.compressionQuality)]]);\n }\n\n /**\n * Clear all stored settings.\n */\n async clear(): Promise<void> {\n await Promise.all([this.storage.removeItem(this.getKey('MAX_CACHE_SIZE_MB')), this.storage.removeItem(this.getKey('COMPRESSION_QUALITY'))]);\n }\n}"],"mappings":"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","names":[]}
@@ -80,12 +80,18 @@ var ConfigurationError = class extends PowerSyncError {
80
80
  }
81
81
  };
82
82
  var ERROR_PATTERNS = {
83
- network: /network|fetch|econnrefused|etimedout|offline/i,
84
- auth: /401|403|auth|token|unauthorized|forbidden/i,
85
- server: /500|502|503|504|internal server/i,
86
- conflict: /conflict|concurrent|version/i,
87
- validation: /validation|constraint|invalid|required/i,
88
- quota: /quota|storage|enospc|disk/i,
83
+ // Network errors - specific patterns to avoid false positives
84
+ network: /\bnetwork\s+(error|failed|failure)\b|\bfetch\s+failed\b|\bfailed\s+to\s+fetch\b|\beconnrefused\b|\betimedout\b|\boffline\b|\bconnection\s+(refused|reset|closed)\b/i,
85
+ // Auth errors - specific patterns for authentication/authorization failures
86
+ auth: /\b401\b|\b403\b|http\s*40[13]\b|\bunauthorized\s+(access|request|error)?\b|\baccess\s+(denied|forbidden)\b|\bnot\s+authorized\b|\bjwt\s+(expired|invalid)\b|\btoken\s+(expired|invalid)\b|\bsession\s+expired\b/i,
87
+ // Server errors - specific HTTP 5xx codes and server-specific messages
88
+ server: /\b50[0-4]\b|http\s*5\d{2}\b|\binternal\s+server\s+error\b|\bservice\s+unavailable\b|\bbad\s+gateway\b|\bgateway\s+timeout\b/i,
89
+ // Conflict errors - data concurrency issues
90
+ conflict: /\bconflict\b|\bconcurrent\s+(update|modification)\b|\bversion\s+mismatch\b|\boptimistic\s+lock\b/i,
91
+ // Validation errors - data validation failures
92
+ validation: /\bvalidation\s+(error|failed)\b|\bconstraint\s+violation\b|\binvalid\s+(data|input|value)\b|\brequired\s+field\b|\bschema\s+error\b/i,
93
+ // Quota errors - storage/resource limit issues
94
+ quota: /\bquota\s+(exceeded|limit)\b|\bstorage\s+(full|limit)\b|\benospc\b|\bdisk\s+(full|space)\b|\bout\s+of\s+(memory|space)\b/i,
89
95
  unknown: /.*/
90
96
  };
91
97
  function classifyError(error) {
@@ -241,15 +247,19 @@ function classifySupabaseError(error) {
241
247
  }
242
248
  }
243
249
  const lowerMessage = errorMessage.toLowerCase();
244
- if (/network|fetch|econnrefused|etimedout|offline|dns|socket/.test(lowerMessage)) {
250
+ const isNetworkError = /\bnetwork\s+(error|request|failed|failure|unavailable)\b/.test(lowerMessage) || /\bfetch\s+(failed|error)\b/.test(lowerMessage) || /\bfailed\s+to\s+fetch\b/.test(lowerMessage) || /\beconnrefused\b/.test(lowerMessage) || /\betimedout\b/.test(lowerMessage) || /\bconnection\s+(timed?\s*out|refused|reset|closed)\b/.test(lowerMessage) || /\boffline\b/.test(lowerMessage) || /\bdns\s+(error|failed|lookup)\b/.test(lowerMessage) || /\bsocket\s+(error|closed|hang\s*up)\b/.test(lowerMessage) || /\bno\s+internet\b/.test(lowerMessage) || /\brequest\s+timeout\b/.test(lowerMessage);
251
+ if (isNetworkError) {
245
252
  result.type = "network";
246
253
  result.isPermanent = false;
247
254
  result.userMessage = "Network error. Will retry when connected.";
248
255
  return result;
249
256
  }
250
- if (/401|403|auth|token|unauthorized|forbidden|jwt|expired/.test(lowerMessage)) {
257
+ const isAuthError = /\b401\b/.test(lowerMessage) || /\b403\b/.test(lowerMessage) || /http 401|http 403/.test(lowerMessage) || /\bauth(entication|orization)?\s+(error|failed|required)\b/.test(lowerMessage) || /\bunauthorized\s+(access|request|error)?\b/.test(lowerMessage) || /\baccess\s+(denied|forbidden)\b/.test(lowerMessage) || /\bnot\s+authorized\b/.test(lowerMessage) || /\bjwt\b/.test(lowerMessage) || /\bbearer\s+token\b/.test(lowerMessage) || /\baccess\s+token\b/.test(lowerMessage);
258
+ if (isAuthError) {
251
259
  result.type = "auth";
252
- result.isPermanent = lowerMessage.includes("expired") || lowerMessage.includes("invalid");
260
+ const isTokenExpired = lowerMessage.includes("jwt expired") || lowerMessage.includes("token expired") || lowerMessage.includes("session expired") || lowerMessage.includes("jwt has expired") || lowerMessage.includes("refresh token expired") || lowerMessage.includes("access token expired") || lowerMessage.includes("token is expired") || lowerMessage.includes("token has expired");
261
+ const isInvalidToken = lowerMessage.includes("invalid token") || lowerMessage.includes("invalid jwt") || lowerMessage.includes("malformed token") || lowerMessage.includes("token invalid") || lowerMessage.includes("jwt invalid") || lowerMessage.includes("invalid signature");
262
+ result.isPermanent = isTokenExpired || isInvalidToken;
253
263
  result.userMessage = "Authentication error. Please sign in again.";
254
264
  return result;
255
265
  }
@@ -259,7 +269,8 @@ function classifySupabaseError(error) {
259
269
  result.userMessage = "The request was rejected. Please check your data.";
260
270
  return result;
261
271
  }
262
- if (/500|502|503|504|internal server|service unavailable/.test(lowerMessage)) {
272
+ const isServerError = /\b500\b/.test(lowerMessage) || /\b502\b/.test(lowerMessage) || /\b503\b/.test(lowerMessage) || /\b504\b/.test(lowerMessage) || /http\s*5\d{2}\b/.test(lowerMessage) || /\binternal\s+server\s+error\b/.test(lowerMessage) || /\bservice\s+unavailable\b/.test(lowerMessage) || /\bserver\s+(error|unavailable|down|overloaded)\b/.test(lowerMessage) || /\bbad\s+gateway\b/.test(lowerMessage) || /\bgateway\s+timeout\b/.test(lowerMessage);
273
+ if (isServerError) {
263
274
  result.type = "server";
264
275
  result.isPermanent = false;
265
276
  result.userMessage = "Server temporarily unavailable. Will retry.";
@@ -319,4 +330,4 @@ export {
319
330
  extractEntityIds,
320
331
  extractTableNames
321
332
  };
322
- //# sourceMappingURL=chunk-FPTDATY5.js.map
333
+ //# sourceMappingURL=chunk-XQAJM2MW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/errors.ts"],"sourcesContent":["/**\n * Custom Error Classes for @pol-studios/powersync\n *\n * This module provides specialized error classes for different failure scenarios.\n */\n\nimport type { SyncErrorType, ClassifiedError, SyncError, CrudEntry } from './types';\n\n/**\n * Base error class for PowerSync-related errors\n */\nexport class PowerSyncError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'PowerSyncError';\n // Maintains proper stack trace for where our error was thrown (only in V8)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, PowerSyncError);\n }\n }\n}\n\n/**\n * Error thrown when PowerSync initialization fails\n */\nexport class InitializationError extends PowerSyncError {\n constructor(message: string, public readonly cause?: Error) {\n super(message);\n this.name = 'InitializationError';\n }\n}\n\n/**\n * Error thrown when a sync operation fails\n */\nexport class SyncOperationError extends PowerSyncError {\n constructor(message: string, public readonly errorType: SyncErrorType, public readonly cause?: Error) {\n super(message);\n this.name = 'SyncOperationError';\n }\n\n /**\n * Whether this error can be automatically retried\n */\n get isRetryable(): boolean {\n return this.errorType === 'network' || this.errorType === 'server';\n }\n\n /**\n * Get a user-friendly error message\n */\n get userFriendlyMessage(): string {\n switch (this.errorType) {\n case 'network':\n return 'Unable to connect. Check your internet connection.';\n case 'auth':\n return 'Session expired. Please sign in again.';\n case 'server':\n return 'Server is temporarily unavailable. Try again later.';\n case 'conflict':\n return 'Your changes conflict with recent updates.';\n case 'quota':\n return 'Device storage is full. Free up space to continue.';\n default:\n return 'An unexpected error occurred. Please try again.';\n }\n }\n}\n\n/**\n * Error thrown when a connector operation fails\n */\nexport class ConnectorError extends PowerSyncError {\n constructor(message: string, public readonly operation: 'fetchCredentials' | 'uploadData', public readonly cause?: Error) {\n super(message);\n this.name = 'ConnectorError';\n }\n}\n\n/**\n * Error thrown when an attachment operation fails\n */\nexport class AttachmentError extends PowerSyncError {\n constructor(message: string, public readonly attachmentId: string, public readonly operation: 'download' | 'compress' | 'delete' | 'evict', public readonly cause?: Error) {\n super(message);\n this.name = 'AttachmentError';\n }\n}\n\n/**\n * Error thrown when the platform adapter is missing required functionality\n */\nexport class PlatformAdapterError extends PowerSyncError {\n constructor(message: string, public readonly missingFeature: string) {\n super(message);\n this.name = 'PlatformAdapterError';\n }\n}\n\n/**\n * Error thrown when configuration is invalid\n */\nexport class ConfigurationError extends PowerSyncError {\n constructor(message: string, public readonly configKey?: string) {\n super(message);\n this.name = 'ConfigurationError';\n }\n}\n\n// ─── Error Classification Utilities ──────────────────────────────────────────\n\n/** Pattern definitions for error classification */\nconst ERROR_PATTERNS: Record<SyncErrorType, RegExp> = {\n // Network errors - specific patterns to avoid false positives\n network: /\\bnetwork\\s+(error|failed|failure)\\b|\\bfetch\\s+failed\\b|\\bfailed\\s+to\\s+fetch\\b|\\beconnrefused\\b|\\betimedout\\b|\\boffline\\b|\\bconnection\\s+(refused|reset|closed)\\b/i,\n // Auth errors - specific patterns for authentication/authorization failures\n auth: /\\b401\\b|\\b403\\b|http\\s*40[13]\\b|\\bunauthorized\\s+(access|request|error)?\\b|\\baccess\\s+(denied|forbidden)\\b|\\bnot\\s+authorized\\b|\\bjwt\\s+(expired|invalid)\\b|\\btoken\\s+(expired|invalid)\\b|\\bsession\\s+expired\\b/i,\n // Server errors - specific HTTP 5xx codes and server-specific messages\n server: /\\b50[0-4]\\b|http\\s*5\\d{2}\\b|\\binternal\\s+server\\s+error\\b|\\bservice\\s+unavailable\\b|\\bbad\\s+gateway\\b|\\bgateway\\s+timeout\\b/i,\n // Conflict errors - data concurrency issues\n conflict: /\\bconflict\\b|\\bconcurrent\\s+(update|modification)\\b|\\bversion\\s+mismatch\\b|\\boptimistic\\s+lock\\b/i,\n // Validation errors - data validation failures\n validation: /\\bvalidation\\s+(error|failed)\\b|\\bconstraint\\s+violation\\b|\\binvalid\\s+(data|input|value)\\b|\\brequired\\s+field\\b|\\bschema\\s+error\\b/i,\n // Quota errors - storage/resource limit issues\n quota: /\\bquota\\s+(exceeded|limit)\\b|\\bstorage\\s+(full|limit)\\b|\\benospc\\b|\\bdisk\\s+(full|space)\\b|\\bout\\s+of\\s+(memory|space)\\b/i,\n unknown: /.*/\n};\n\n/**\n * Classify an error into a SyncErrorType based on its message\n *\n * @param error - The error to classify\n * @returns The classified error type\n */\nexport function classifyError(error: Error): SyncErrorType {\n const message = error.message || '';\n\n // Check patterns in priority order (more specific first)\n if (ERROR_PATTERNS.auth.test(message)) return 'auth';\n if (ERROR_PATTERNS.server.test(message)) return 'server';\n if (ERROR_PATTERNS.network.test(message)) return 'network';\n if (ERROR_PATTERNS.conflict.test(message)) return 'conflict';\n if (ERROR_PATTERNS.validation.test(message)) return 'validation';\n if (ERROR_PATTERNS.quota.test(message)) return 'quota';\n return 'unknown';\n}\n\n/**\n * Create a SyncOperationError from a regular Error\n *\n * @param error - The original error\n * @param message - Optional custom message\n * @returns A classified SyncOperationError\n */\nexport function toSyncOperationError(error: Error, message?: string): SyncOperationError {\n const errorType = classifyError(error);\n return new SyncOperationError(message || error.message, errorType, error);\n}\n\n// ─── Supabase/PostgreSQL Error Classification ────────────────────────────────\n\n/**\n * PostgreSQL error code ranges and their meanings.\n * See: https://www.postgresql.org/docs/current/errcodes-appendix.html\n */\nconst PG_ERROR_CODES = {\n // Class 23 - Integrity Constraint Violation (permanent - data issue)\n UNIQUE_VIOLATION: '23505',\n FOREIGN_KEY_VIOLATION: '23503',\n NOT_NULL_VIOLATION: '23502',\n CHECK_VIOLATION: '23514',\n // Class 42 - Syntax Error or Access Rule Violation (permanent - schema issue)\n UNDEFINED_TABLE: '42P01',\n UNDEFINED_COLUMN: '42703',\n INSUFFICIENT_PRIVILEGE: '42501',\n // Class 08 - Connection Exception (transient)\n CONNECTION_FAILURE: '08006',\n CONNECTION_DOES_NOT_EXIST: '08003',\n // Class 53 - Insufficient Resources (transient)\n OUT_OF_MEMORY: '53200',\n DISK_FULL: '53100',\n // Class 40 - Transaction Rollback (transient)\n SERIALIZATION_FAILURE: '40001',\n DEADLOCK_DETECTED: '40P01'\n} as const;\n\n/**\n * User-friendly messages for PostgreSQL error codes\n */\nconst PG_ERROR_MESSAGES: Record<string, string> = {\n [PG_ERROR_CODES.UNIQUE_VIOLATION]: 'This record already exists or conflicts with existing data.',\n [PG_ERROR_CODES.FOREIGN_KEY_VIOLATION]: 'This record references data that no longer exists.',\n [PG_ERROR_CODES.NOT_NULL_VIOLATION]: 'A required field is missing.',\n [PG_ERROR_CODES.CHECK_VIOLATION]: 'The data does not meet validation requirements.',\n [PG_ERROR_CODES.UNDEFINED_TABLE]: 'The database table does not exist.',\n [PG_ERROR_CODES.UNDEFINED_COLUMN]: 'A database column does not exist.',\n [PG_ERROR_CODES.INSUFFICIENT_PRIVILEGE]: 'You do not have permission to perform this action.'\n};\n\n/**\n * Extract HTTP status code from an error object.\n *\n * Checks for common status code properties and falls back to pattern matching\n * in the error message for 4xx/5xx codes.\n */\nfunction extractHttpStatusCode(error: unknown): number | undefined {\n if (!error || typeof error !== 'object') return undefined;\n const err = error as Record<string, unknown>;\n\n // Direct properties\n if (typeof err.status === 'number') return err.status;\n if (typeof err.statusCode === 'number') return err.statusCode;\n\n // Check nested error object (Supabase format)\n if (err.error && typeof err.error === 'object') {\n const nested = err.error as Record<string, unknown>;\n if (typeof nested.status === 'number') return nested.status;\n if (typeof nested.statusCode === 'number') return nested.statusCode;\n }\n\n // Pattern match in message\n const message = String(err.message || '');\n const match = message.match(/\\b(4\\d{2}|5\\d{2})\\b/);\n if (match) return parseInt(match[1], 10);\n return undefined;\n}\n\n/**\n * Extract PostgreSQL error code from a Supabase error.\n *\n * Supabase errors from PostgREST typically include the PostgreSQL error code\n * in the error object or message.\n */\nfunction extractPgCode(error: unknown): string | undefined {\n if (!error || typeof error !== 'object') return undefined;\n const err = error as Record<string, unknown>;\n\n // Supabase error format: { code: \"PGRST...\", details: \"...\", hint: \"...\", message: \"...\" }\n // PostgreSQL error format: { code: \"23505\", ... }\n if (typeof err.code === 'string') {\n // Check if it's a direct PostgreSQL code (5 chars, starts with digit)\n if (/^\\d{5}$/.test(err.code)) {\n return err.code;\n }\n // Extract from PGRST format or message\n const match = err.code.match(/\\d{5}/) || String(err.message || '').match(/\\d{5}/);\n if (match) return match[0];\n }\n\n // Check in details or hint\n if (typeof err.details === 'string') {\n const match = err.details.match(/\\b(\\d{5})\\b/);\n if (match) return match[1];\n }\n return undefined;\n}\n\n/**\n * User-friendly messages for PostgREST error codes (PGRST*).\n * See: https://postgrest.org/en/stable/references/errors.html\n */\nfunction getPostgRESTMessage(code: string, fallback: string): string {\n const messages: Record<string, string> = {\n 'PGRST116': 'Record not found or query returned no results.',\n 'PGRST204': 'Column not found in the database.',\n 'PGRST301': 'Row-level security prevented this operation.',\n 'PGRST302': 'The requested operation is not allowed.'\n };\n return messages[code] || `Database error: ${fallback}`;\n}\n\n/**\n * Classify a Supabase/PostgreSQL error into a structured result.\n *\n * This function analyzes errors from Supabase operations and determines:\n * - The error type category\n * - Whether the error is permanent (won't be fixed by retry)\n * - Whether it's a conflict with existing data\n * - A user-friendly message\n *\n * @param error - The error from a Supabase operation\n * @returns Classified error information\n *\n * @example\n * ```typescript\n * try {\n * await supabase.from('users').insert({ email: 'duplicate@test.com' });\n * } catch (error) {\n * const classified = classifySupabaseError(error);\n * if (classified.isPermanent) {\n * // Show error to user - retry won't help\n * }\n * }\n * ```\n */\nexport function classifySupabaseError(error: unknown): ClassifiedError {\n const pgCode = extractPgCode(error);\n const httpStatusCode = extractHttpStatusCode(error);\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n // Default result\n let result: ClassifiedError = {\n type: 'unknown',\n isPermanent: false,\n isConflict: false,\n pgCode,\n userMessage: 'An unexpected error occurred. Please try again.'\n };\n\n // Check for PostgREST error codes (PGRST*)\n if (error && typeof error === 'object') {\n const err = error as Record<string, unknown>;\n const code = String(err.code || '');\n if (code.startsWith('PGRST')) {\n result.type = 'validation';\n result.isPermanent = true;\n result.userMessage = getPostgRESTMessage(code, errorMessage);\n return result;\n }\n }\n\n // First, check HTTP status code for quick classification\n if (httpStatusCode) {\n // 4xx client errors (except 401/403 which are auth errors handled separately)\n if (httpStatusCode >= 400 && httpStatusCode < 500 && httpStatusCode !== 401 && httpStatusCode !== 403) {\n result.type = 'validation';\n result.isPermanent = true;\n result.userMessage = 'The request was rejected. Please check your data.';\n return result;\n }\n\n // 5xx server errors (transient)\n if (httpStatusCode >= 500) {\n result.type = 'server';\n result.isPermanent = false;\n result.userMessage = 'Server temporarily unavailable. Will retry.';\n return result;\n }\n }\n\n // Second, check PostgreSQL error code (most reliable)\n if (pgCode) {\n // Class 23 - Integrity Constraint Violations (permanent)\n if (pgCode.startsWith('23')) {\n result.type = pgCode === PG_ERROR_CODES.UNIQUE_VIOLATION ? 'conflict' : 'validation';\n result.isPermanent = true;\n result.isConflict = pgCode === PG_ERROR_CODES.UNIQUE_VIOLATION;\n result.userMessage = PG_ERROR_MESSAGES[pgCode] || 'Data validation failed.';\n return result;\n }\n\n // Class 42 - Syntax/Access Errors (permanent - schema issue)\n if (pgCode.startsWith('42')) {\n result.type = pgCode === PG_ERROR_CODES.INSUFFICIENT_PRIVILEGE ? 'auth' : 'validation';\n result.isPermanent = true;\n result.userMessage = PG_ERROR_MESSAGES[pgCode] || 'Database schema error.';\n return result;\n }\n\n // Class 08 - Connection Exceptions (transient)\n if (pgCode.startsWith('08')) {\n result.type = 'network';\n result.isPermanent = false;\n result.userMessage = 'Connection lost. Will retry automatically.';\n return result;\n }\n\n // Class 53 - Insufficient Resources (transient, but may need action)\n if (pgCode.startsWith('53')) {\n result.type = 'quota';\n result.isPermanent = pgCode === PG_ERROR_CODES.DISK_FULL;\n result.userMessage = 'Server resources exhausted. Please try again later.';\n return result;\n }\n\n // Class 40 - Transaction Rollback (transient)\n if (pgCode.startsWith('40')) {\n result.type = 'conflict';\n result.isPermanent = false;\n result.isConflict = true;\n result.userMessage = 'Concurrent update detected. Retrying...';\n return result;\n }\n }\n\n // Fall back to pattern matching on error message\n const lowerMessage = errorMessage.toLowerCase();\n\n // Network errors (transient)\n // Use specific patterns to avoid false positives\n const isNetworkError = /\\bnetwork\\s+(error|request|failed|failure|unavailable)\\b/.test(lowerMessage) || /\\bfetch\\s+(failed|error)\\b/.test(lowerMessage) || /\\bfailed\\s+to\\s+fetch\\b/.test(lowerMessage) || /\\beconnrefused\\b/.test(lowerMessage) || /\\betimedout\\b/.test(lowerMessage) || /\\bconnection\\s+(timed?\\s*out|refused|reset|closed)\\b/.test(lowerMessage) || /\\boffline\\b/.test(lowerMessage) || /\\bdns\\s+(error|failed|lookup)\\b/.test(lowerMessage) || /\\bsocket\\s+(error|closed|hang\\s*up)\\b/.test(lowerMessage) || /\\bno\\s+internet\\b/.test(lowerMessage) || /\\brequest\\s+timeout\\b/.test(lowerMessage);\n if (isNetworkError) {\n result.type = 'network';\n result.isPermanent = false;\n result.userMessage = 'Network error. Will retry when connected.';\n return result;\n }\n\n // Auth errors (may be permanent if token is invalid)\n // Use specific patterns to avoid false positives (e.g., 'cache expired' matching 'expired')\n const isAuthError = /\\b401\\b/.test(lowerMessage) || /\\b403\\b/.test(lowerMessage) || /http 401|http 403/.test(lowerMessage) || /\\bauth(entication|orization)?\\s+(error|failed|required)\\b/.test(lowerMessage) || /\\bunauthorized\\s+(access|request|error)?\\b/.test(lowerMessage) || /\\baccess\\s+(denied|forbidden)\\b/.test(lowerMessage) || /\\bnot\\s+authorized\\b/.test(lowerMessage) || /\\bjwt\\b/.test(lowerMessage) || /\\bbearer\\s+token\\b/.test(lowerMessage) || /\\baccess\\s+token\\b/.test(lowerMessage);\n if (isAuthError) {\n result.type = 'auth';\n // Check for specific token expiration patterns, avoiding false positives\n const isTokenExpired = lowerMessage.includes('jwt expired') || lowerMessage.includes('token expired') || lowerMessage.includes('session expired') || lowerMessage.includes('jwt has expired') || lowerMessage.includes('refresh token expired') || lowerMessage.includes('access token expired') || lowerMessage.includes('token is expired') || lowerMessage.includes('token has expired');\n const isInvalidToken = lowerMessage.includes('invalid token') || lowerMessage.includes('invalid jwt') || lowerMessage.includes('malformed token') || lowerMessage.includes('token invalid') || lowerMessage.includes('jwt invalid') || lowerMessage.includes('invalid signature');\n result.isPermanent = isTokenExpired || isInvalidToken;\n result.userMessage = 'Authentication error. Please sign in again.';\n return result;\n }\n\n // Client errors (permanent - request is malformed or rejected)\n if (/400|406|bad request|not acceptable|422|unprocessable/i.test(lowerMessage)) {\n result.type = 'validation';\n result.isPermanent = true;\n result.userMessage = 'The request was rejected. Please check your data.';\n return result;\n }\n\n // Server errors (transient)\n // Use specific patterns with word boundaries to avoid false positives\n const isServerError = /\\b500\\b/.test(lowerMessage) || /\\b502\\b/.test(lowerMessage) || /\\b503\\b/.test(lowerMessage) || /\\b504\\b/.test(lowerMessage) || /http\\s*5\\d{2}\\b/.test(lowerMessage) || /\\binternal\\s+server\\s+error\\b/.test(lowerMessage) || /\\bservice\\s+unavailable\\b/.test(lowerMessage) || /\\bserver\\s+(error|unavailable|down|overloaded)\\b/.test(lowerMessage) || /\\bbad\\s+gateway\\b/.test(lowerMessage) || /\\bgateway\\s+timeout\\b/.test(lowerMessage);\n if (isServerError) {\n result.type = 'server';\n result.isPermanent = false;\n result.userMessage = 'Server temporarily unavailable. Will retry.';\n return result;\n }\n\n // Constraint/validation errors in message (permanent)\n if (/duplicate|unique|constraint|violates|invalid|required/.test(lowerMessage)) {\n result.type = 'validation';\n result.isPermanent = true;\n result.isConflict = lowerMessage.includes('duplicate') || lowerMessage.includes('unique');\n result.userMessage = 'Data validation failed. Please check your input.';\n return result;\n }\n return result;\n}\n\n/**\n * Create a SyncError from a classified error result.\n */\nexport function createSyncError(classified: ClassifiedError, originalMessage: string): SyncError {\n return {\n type: classified.type,\n message: originalMessage,\n userMessage: classified.userMessage,\n timestamp: new Date(),\n pgCode: classified.pgCode,\n isPermanent: classified.isPermanent\n };\n}\n\n/**\n * Generate a unique ID for a failed transaction.\n * Uses a combination of timestamp and entry IDs to ensure uniqueness.\n */\nexport function generateFailureId(entries: CrudEntry[]): string {\n const timestamp = Date.now();\n const entryIds = entries.map(e => e.id).join('-');\n return `failure-${timestamp}-${entryIds.substring(0, 32)}`;\n}\n\n/**\n * Extract entity IDs from CRUD entries.\n * Includes both the PowerSync entry ID and the record's 'id' from opData if different.\n * This ensures we can match failures to entities regardless of which ID format is used.\n */\nexport function extractEntityIds(entries: CrudEntry[]): string[] {\n const ids: string[] = [];\n for (const entry of entries) {\n // Always include the PowerSync entry ID\n ids.push(entry.id);\n // Also include the record's 'id' field from opData if it exists and is different\n if (entry.opData?.id !== undefined && String(entry.opData.id) !== entry.id) {\n ids.push(String(entry.opData.id));\n }\n }\n return [...new Set(ids)];\n}\n\n/**\n * Extract unique table names from CRUD entries.\n */\nexport function extractTableNames(entries: CrudEntry[]): string[] {\n return [...new Set(entries.map(entry => entry.table))];\n}"],"mappings":"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","names":[]}