@pol-studios/powersync 1.0.30 → 1.0.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{CacheSettingsManager-uz-kbnRH.d.ts → CacheSettingsManager-0H_7thHW.d.ts} +21 -3
- package/dist/attachments/index.d.ts +30 -30
- package/dist/attachments/index.js +13 -4
- package/dist/{background-sync-CVR3PkFi.d.ts → background-sync-BujnI3IR.d.ts} +1 -1
- package/dist/{chunk-RE5HWLCB.js → chunk-2RDWLXJW.js} +322 -103
- package/dist/chunk-2RDWLXJW.js.map +1 -0
- package/dist/{chunk-P4HZA6ZT.js → chunk-4665ZSE5.js} +2 -2
- package/dist/chunk-4665ZSE5.js.map +1 -0
- package/dist/{chunk-XOY2CJ67.js → chunk-4F5B5CZ7.js} +3 -3
- package/dist/chunk-5WRI5ZAA.js +31 -0
- package/dist/{chunk-BC2SRII2.js → chunk-65A3SYJZ.js} +14 -1
- package/dist/chunk-65A3SYJZ.js.map +1 -0
- package/dist/chunk-6SZ64KCZ.js +755 -0
- package/dist/chunk-6SZ64KCZ.js.map +1 -0
- package/dist/{chunk-C2ACBYBZ.js → chunk-74TBHWJ4.js} +10 -96
- package/dist/{chunk-C2ACBYBZ.js.map → chunk-74TBHWJ4.js.map} +1 -1
- package/dist/chunk-ANXWYQEJ.js +1 -0
- package/dist/chunk-ANXWYQEJ.js.map +1 -0
- package/dist/{chunk-CAB26E6F.js → chunk-C4J4MLER.js} +29 -24
- package/dist/chunk-C4J4MLER.js.map +1 -0
- package/dist/{chunk-C5ODS3XH.js → chunk-EOW7JK7Q.js} +9 -16
- package/dist/chunk-EOW7JK7Q.js.map +1 -0
- package/dist/chunk-HRAVPIAZ.js +220 -0
- package/dist/chunk-HRAVPIAZ.js.map +1 -0
- package/dist/{chunk-XAEII4ZX.js → chunk-NUGQOTEM.js} +32 -4
- package/dist/chunk-NUGQOTEM.js.map +1 -0
- package/dist/chunk-OGUFUZSY.js +5415 -0
- package/dist/chunk-OGUFUZSY.js.map +1 -0
- package/dist/{chunk-JCGOZVWL.js → chunk-P4D6BQ4X.js} +115 -576
- package/dist/chunk-P4D6BQ4X.js.map +1 -0
- package/dist/{chunk-CACKC6XG.js → chunk-PGEDE6IM.js} +136 -89
- package/dist/chunk-PGEDE6IM.js.map +1 -0
- package/dist/{chunk-A4IBBWGO.js → chunk-RALHHPTU.js} +1 -1
- package/dist/chunk-RIDSPLE5.js +42 -0
- package/dist/chunk-RIDSPLE5.js.map +1 -0
- package/dist/{chunk-Z6VOBGTU.js → chunk-UOMHWUHV.js} +2 -12
- package/dist/chunk-UOMHWUHV.js.map +1 -0
- package/dist/{chunk-QREWE3NR.js → chunk-YONQYTVH.js} +2 -2
- package/dist/chunk-ZAN22NGL.js +13 -0
- package/dist/chunk-ZAN22NGL.js.map +1 -0
- package/dist/config/index.d.ts +200 -0
- package/dist/config/index.js +23 -0
- package/dist/config/index.js.map +1 -0
- package/dist/connector/index.d.ts +23 -5
- package/dist/connector/index.js +4 -1
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js +1 -0
- package/dist/error/index.js +1 -0
- package/dist/generator/index.js +2 -0
- package/dist/generator/index.js.map +1 -1
- package/dist/index.d.ts +19 -16
- package/dist/index.js +68 -36
- package/dist/index.native.d.ts +18 -14
- package/dist/index.native.js +73 -34
- package/dist/index.web.d.ts +17 -14
- package/dist/index.web.js +68 -36
- package/dist/maintenance/index.d.ts +2 -2
- package/dist/maintenance/index.js +3 -2
- package/dist/platform/index.d.ts +1 -1
- package/dist/platform/index.js +2 -0
- package/dist/platform/index.js.map +1 -1
- package/dist/platform/index.native.d.ts +1 -1
- package/dist/platform/index.native.js +1 -0
- package/dist/platform/index.web.d.ts +1 -1
- package/dist/platform/index.web.js +1 -0
- package/dist/pol-attachment-queue-DqBvLAEY.d.ts +255 -0
- package/dist/provider/index.d.ts +149 -114
- package/dist/provider/index.js +9 -14
- package/dist/provider/index.native.d.ts +108 -0
- package/dist/provider/index.native.js +121 -0
- package/dist/provider/index.native.js.map +1 -0
- package/dist/provider/index.web.d.ts +16 -0
- package/dist/provider/index.web.js +112 -0
- package/dist/provider/index.web.js.map +1 -0
- package/dist/react/index.d.ts +16 -65
- package/dist/react/index.js +2 -9
- package/dist/storage/index.d.ts +5 -4
- package/dist/storage/index.js +12 -9
- package/dist/storage/index.native.d.ts +5 -4
- package/dist/storage/index.native.js +8 -5
- package/dist/storage/index.web.d.ts +5 -4
- package/dist/storage/index.web.js +11 -8
- package/dist/storage/upload/index.d.ts +4 -3
- package/dist/storage/upload/index.js +4 -2
- package/dist/storage/upload/index.native.d.ts +4 -3
- package/dist/storage/upload/index.native.js +4 -2
- package/dist/storage/upload/index.web.d.ts +2 -1
- package/dist/storage/upload/index.web.js +4 -2
- package/dist/{supabase-connector-C4YpH_l3.d.ts → supabase-connector-HMxBA9Kg.d.ts} +2 -2
- package/dist/sync/index.d.ts +155 -20
- package/dist/sync/index.js +13 -3
- package/dist/{types-CyvBaAl8.d.ts → types-6QHGELuY.d.ts} +4 -1
- package/dist/{types-Dv1uf0LZ.d.ts → types-B9MptP7E.d.ts} +7 -10
- package/dist/types-BhAEsJj-.d.ts +330 -0
- package/dist/{types-D0WcHrq6.d.ts → types-CGMibJKD.d.ts} +8 -0
- package/dist/{types-CpM2_LhU.d.ts → types-DqJnP50o.d.ts} +6 -1
- package/dist/{pol-attachment-queue-BE2HU3Us.d.ts → types-JCEhw2Lf.d.ts} +139 -346
- package/package.json +18 -4
- package/dist/chunk-654ERHA7.js +0 -1
- package/dist/chunk-BC2SRII2.js.map +0 -1
- package/dist/chunk-C5ODS3XH.js.map +0 -1
- package/dist/chunk-CAB26E6F.js.map +0 -1
- package/dist/chunk-CACKC6XG.js.map +0 -1
- package/dist/chunk-FNYQFILT.js +0 -44
- package/dist/chunk-FNYQFILT.js.map +0 -1
- package/dist/chunk-JCGOZVWL.js.map +0 -1
- package/dist/chunk-P4HZA6ZT.js.map +0 -1
- package/dist/chunk-RBPWEOIV.js +0 -358
- package/dist/chunk-RBPWEOIV.js.map +0 -1
- package/dist/chunk-RE5HWLCB.js.map +0 -1
- package/dist/chunk-XAEII4ZX.js.map +0 -1
- package/dist/chunk-Z6VOBGTU.js.map +0 -1
- /package/dist/{chunk-XOY2CJ67.js.map → chunk-4F5B5CZ7.js.map} +0 -0
- /package/dist/{chunk-654ERHA7.js.map → chunk-5WRI5ZAA.js.map} +0 -0
- /package/dist/{chunk-A4IBBWGO.js.map → chunk-RALHHPTU.js.map} +0 -0
- /package/dist/{chunk-QREWE3NR.js.map → chunk-YONQYTVH.js.map} +0 -0
|
@@ -17,8 +17,8 @@ var PolStorageAdapter = class {
|
|
|
17
17
|
this.remoteStorage = options.remoteStorage;
|
|
18
18
|
this.attachmentDirectoryName = options.attachmentDirectoryName ?? "attachments";
|
|
19
19
|
this.logger = options.logger;
|
|
20
|
-
const
|
|
21
|
-
this.userStorageDirectory =
|
|
20
|
+
const documentsDir = this.platform.fileSystem.getDocumentsDirectory();
|
|
21
|
+
this.userStorageDirectory = documentsDir.endsWith("/") ? `${documentsDir}${this.attachmentDirectoryName}/` : `${documentsDir}/${this.attachmentDirectoryName}/`;
|
|
22
22
|
}
|
|
23
23
|
// ─── Remote Operations ──────────────────────────────────────────────────────
|
|
24
24
|
/**
|
|
@@ -31,6 +31,23 @@ var PolStorageAdapter = class {
|
|
|
31
31
|
const base64 = this._arrayBufferToBase64(data);
|
|
32
32
|
await this.remoteStorage.uploadFile(filePath, base64);
|
|
33
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Convert base64 string to Blob with error handling.
|
|
36
|
+
* Throws a descriptive error if the base64 data is malformed.
|
|
37
|
+
*/
|
|
38
|
+
_base64ToBlob(base64String, filePath) {
|
|
39
|
+
try {
|
|
40
|
+
const binaryString = atob(base64String);
|
|
41
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
42
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
43
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
44
|
+
}
|
|
45
|
+
return new Blob([bytes]);
|
|
46
|
+
} catch (error) {
|
|
47
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
48
|
+
throw new Error(`[PolStorageAdapter] Failed to decode base64 for file "${filePath}": ${message}. The file data may be corrupted or incorrectly encoded.`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
34
51
|
/**
|
|
35
52
|
* Download a file from remote storage.
|
|
36
53
|
*
|
|
@@ -47,19 +64,9 @@ var PolStorageAdapter = class {
|
|
|
47
64
|
if (result.startsWith("file://")) {
|
|
48
65
|
this.logger?.warn(`[PolStorageAdapter] PERFORMANCE WARNING: file:// path hit in downloadFile() - reading entire file into memory. This should be avoided; use direct file copy instead. File: ${filePath}`);
|
|
49
66
|
const base64Content = await this.platform.fileSystem.readFile(result, "base64");
|
|
50
|
-
|
|
51
|
-
const bytes2 = new Uint8Array(binaryString2.length);
|
|
52
|
-
for (let i = 0; i < binaryString2.length; i++) {
|
|
53
|
-
bytes2[i] = binaryString2.charCodeAt(i);
|
|
54
|
-
}
|
|
55
|
-
return new Blob([bytes2]);
|
|
67
|
+
return this._base64ToBlob(base64Content, filePath);
|
|
56
68
|
}
|
|
57
|
-
|
|
58
|
-
const bytes = new Uint8Array(binaryString.length);
|
|
59
|
-
for (let i = 0; i < binaryString.length; i++) {
|
|
60
|
-
bytes[i] = binaryString.charCodeAt(i);
|
|
61
|
-
}
|
|
62
|
-
return new Blob([bytes]);
|
|
69
|
+
return this._base64ToBlob(result, filePath);
|
|
63
70
|
}
|
|
64
71
|
return result;
|
|
65
72
|
}
|
|
@@ -120,7 +127,7 @@ var PolStorageAdapter = class {
|
|
|
120
127
|
}
|
|
121
128
|
/**
|
|
122
129
|
* Get the user's storage directory for attachments.
|
|
123
|
-
* Returns the
|
|
130
|
+
* Returns the documents directory path ending with '/'.
|
|
124
131
|
*/
|
|
125
132
|
getUserStorageDirectory() {
|
|
126
133
|
return this.userStorageDirectory;
|
|
@@ -141,12 +148,17 @@ var PolStorageAdapter = class {
|
|
|
141
148
|
return btoa(chunks.join(""));
|
|
142
149
|
}
|
|
143
150
|
_base64ToArrayBuffer(base64) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
151
|
+
try {
|
|
152
|
+
const binaryString = atob(base64);
|
|
153
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
154
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
155
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
156
|
+
}
|
|
157
|
+
return bytes.buffer;
|
|
158
|
+
} catch (error) {
|
|
159
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
160
|
+
throw new Error(`[PolStorageAdapter] Failed to decode base64 data: ${message}. The data may be corrupted or incorrectly encoded.`);
|
|
148
161
|
}
|
|
149
|
-
return bytes.buffer;
|
|
150
162
|
}
|
|
151
163
|
};
|
|
152
164
|
|
|
@@ -161,7 +173,6 @@ var PolAttachmentState = /* @__PURE__ */ ((PolAttachmentState2) => {
|
|
|
161
173
|
PolAttachmentState2[PolAttachmentState2["SYNCED"] = 3] = "SYNCED";
|
|
162
174
|
PolAttachmentState2[PolAttachmentState2["ARCHIVED"] = 4] = "ARCHIVED";
|
|
163
175
|
PolAttachmentState2[PolAttachmentState2["FAILED_PERMANENT"] = 5] = "FAILED_PERMANENT";
|
|
164
|
-
PolAttachmentState2[PolAttachmentState2["DOWNLOAD_SKIPPED"] = 6] = "DOWNLOAD_SKIPPED";
|
|
165
176
|
return PolAttachmentState2;
|
|
166
177
|
})(PolAttachmentState || {});
|
|
167
178
|
var DEFAULT_COMPRESSION_CONFIG = {
|
|
@@ -221,6 +232,27 @@ function formatCacheSize(bytes) {
|
|
|
221
232
|
}
|
|
222
233
|
return `${bytes} bytes`;
|
|
223
234
|
}
|
|
235
|
+
function resolveBucketFromConfig(config) {
|
|
236
|
+
if (config.source && config.source.type === "supabase-bucket") {
|
|
237
|
+
return config.source.bucket;
|
|
238
|
+
}
|
|
239
|
+
return void 0;
|
|
240
|
+
}
|
|
241
|
+
function isSignedUrlSource(config) {
|
|
242
|
+
if (config.source && config.source.type === "supabase-bucket") {
|
|
243
|
+
return config.source.signed !== false;
|
|
244
|
+
}
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
247
|
+
function isCustomSource(config) {
|
|
248
|
+
return config.source?.type === "custom";
|
|
249
|
+
}
|
|
250
|
+
function getCustomUrlResolver(config) {
|
|
251
|
+
if (config.source?.type === "custom") {
|
|
252
|
+
return config.source.getUrl;
|
|
253
|
+
}
|
|
254
|
+
return void 0;
|
|
255
|
+
}
|
|
224
256
|
|
|
225
257
|
// src/attachments/state-machine.ts
|
|
226
258
|
import { AttachmentState as AttachmentState2 } from "@powersync/attachments";
|
|
@@ -482,17 +514,21 @@ async function downloadRecord(deps, record) {
|
|
|
482
514
|
deps.notify(true);
|
|
483
515
|
return true;
|
|
484
516
|
} catch (e) {
|
|
517
|
+
const errorMessage = e instanceof Error ? e.message : String(e);
|
|
518
|
+
logger.warn(`[DownloadManager] Download failed for "${record.id}": ${errorMessage}`);
|
|
485
519
|
if (deps.onDownloadError) {
|
|
486
520
|
const {
|
|
487
521
|
retry
|
|
488
522
|
} = await deps.onDownloadError(record, e);
|
|
489
523
|
if (!retry) {
|
|
524
|
+
logger.info(`[DownloadManager] Archiving "${record.id}" after download error (retry=false)`);
|
|
490
525
|
await deps.update({
|
|
491
526
|
...record,
|
|
492
527
|
state: AttachmentState3.ARCHIVED
|
|
493
528
|
});
|
|
494
529
|
return true;
|
|
495
530
|
}
|
|
531
|
+
logger.debug(`[DownloadManager] Will retry "${record.id}" on next cycle (retry=true)`);
|
|
496
532
|
}
|
|
497
533
|
}
|
|
498
534
|
return false;
|
|
@@ -514,6 +550,9 @@ function isPermanentError(error) {
|
|
|
514
550
|
}
|
|
515
551
|
return false;
|
|
516
552
|
}
|
|
553
|
+
function hasStatusCode(e) {
|
|
554
|
+
return e instanceof Error && ("status" in e || "statusCode" in e);
|
|
555
|
+
}
|
|
517
556
|
function extractErrorCode(error) {
|
|
518
557
|
const message = error.message;
|
|
519
558
|
const patterns = [
|
|
@@ -532,8 +571,13 @@ function extractErrorCode(error) {
|
|
|
532
571
|
return match[1];
|
|
533
572
|
}
|
|
534
573
|
}
|
|
535
|
-
if (
|
|
536
|
-
|
|
574
|
+
if (hasStatusCode(error)) {
|
|
575
|
+
if (typeof error.status === "number") {
|
|
576
|
+
return String(error.status);
|
|
577
|
+
}
|
|
578
|
+
if (typeof error.statusCode === "string") {
|
|
579
|
+
return error.statusCode;
|
|
580
|
+
}
|
|
537
581
|
}
|
|
538
582
|
return void 0;
|
|
539
583
|
}
|
|
@@ -1028,20 +1072,22 @@ async function getLocalUriForStoragePath(deps, storagePath, storage) {
|
|
|
1028
1072
|
return null;
|
|
1029
1073
|
}
|
|
1030
1074
|
} catch (e) {
|
|
1031
|
-
logger.warn(`[CacheManager] Failed to verify file exists: ${storagePath}`, e);
|
|
1075
|
+
logger.warn(`[CacheManager] Failed to verify file exists, returning null: ${storagePath}`, e);
|
|
1076
|
+
return null;
|
|
1032
1077
|
}
|
|
1033
1078
|
return uri;
|
|
1034
1079
|
}
|
|
1035
1080
|
async function copyToManagedCache(platform, logger, sourceUri, storagePath) {
|
|
1036
1081
|
const localPath = storagePath.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
1037
|
-
const
|
|
1038
|
-
const
|
|
1082
|
+
const docsDir = platform.fileSystem.getDocumentsDirectory();
|
|
1083
|
+
const basePath = docsDir.endsWith("/") ? docsDir : `${docsDir}/`;
|
|
1084
|
+
const targetUri = `${basePath}upload_queue/${localPath}`;
|
|
1039
1085
|
const dir = targetUri.substring(0, targetUri.lastIndexOf("/"));
|
|
1040
1086
|
await platform.fileSystem.makeDirectory(dir, {
|
|
1041
1087
|
intermediates: true
|
|
1042
1088
|
});
|
|
1043
1089
|
await platform.fileSystem.copyFile(sourceUri, targetUri);
|
|
1044
|
-
logger.info(`[CacheManager] Copied to
|
|
1090
|
+
logger.info(`[CacheManager] Copied to documents for upload: ${targetUri}`);
|
|
1045
1091
|
return targetUri;
|
|
1046
1092
|
}
|
|
1047
1093
|
function createCacheManagerDeps(partial) {
|
|
@@ -1064,6 +1110,7 @@ var PolAttachmentQueue = class extends AbstractAttachmentQueue2 {
|
|
|
1064
1110
|
polLogger;
|
|
1065
1111
|
source;
|
|
1066
1112
|
remoteStorage;
|
|
1113
|
+
supabaseClient;
|
|
1067
1114
|
uploadHandler;
|
|
1068
1115
|
uploadConfig;
|
|
1069
1116
|
downloadConfig;
|
|
@@ -1075,10 +1122,12 @@ var PolAttachmentQueue = class extends AbstractAttachmentQueue2 {
|
|
|
1075
1122
|
_disposed = false;
|
|
1076
1123
|
_initialized = false;
|
|
1077
1124
|
_watchGeneration = 0;
|
|
1078
|
-
|
|
1125
|
+
_watchCleanup = void 0;
|
|
1079
1126
|
_watchMutex = Promise.resolve();
|
|
1080
1127
|
_networkListenerCleanup = void 0;
|
|
1081
1128
|
_wasConnected = null;
|
|
1129
|
+
_cacheCapacityRetries = 0;
|
|
1130
|
+
// Track cache capacity retries to prevent infinite loops
|
|
1082
1131
|
// Notification state
|
|
1083
1132
|
_progressCallbacks = /* @__PURE__ */ new Set();
|
|
1084
1133
|
_lastNotifyTime = 0;
|
|
@@ -1103,6 +1152,7 @@ var PolAttachmentQueue = class extends AbstractAttachmentQueue2 {
|
|
|
1103
1152
|
this.polLogger = options.platform.logger;
|
|
1104
1153
|
this.source = options.source;
|
|
1105
1154
|
this.remoteStorage = options.remoteStorage;
|
|
1155
|
+
this.supabaseClient = options.supabaseClient;
|
|
1106
1156
|
this.uploadHandler = options.uploadHandler;
|
|
1107
1157
|
this.uploadConfig = {
|
|
1108
1158
|
...DEFAULT_UPLOAD_CONFIG,
|
|
@@ -1132,7 +1182,7 @@ var PolAttachmentQueue = class extends AbstractAttachmentQueue2 {
|
|
|
1132
1182
|
* The parent implementation deletes SYNCED/ARCHIVED records beyond cacheLimit,
|
|
1133
1183
|
* which caused a bug where downloads would reset because:
|
|
1134
1184
|
* 1. expireCache deleted records beyond cacheLimit (default 100)
|
|
1135
|
-
* 2.
|
|
1185
|
+
* 2. watchPaths still emitted those IDs
|
|
1136
1186
|
* 3. They got re-created as QUEUED_DOWNLOAD
|
|
1137
1187
|
* 4. Downloads restarted in an infinite loop
|
|
1138
1188
|
*
|
|
@@ -1172,7 +1222,20 @@ var PolAttachmentQueue = class extends AbstractAttachmentQueue2 {
|
|
|
1172
1222
|
if (hasMaxSize) {
|
|
1173
1223
|
const nearCapacity = await isCacheNearCapacity(this._getCacheManagerDeps());
|
|
1174
1224
|
if (nearCapacity) {
|
|
1175
|
-
this.
|
|
1225
|
+
this._cacheCapacityRetries++;
|
|
1226
|
+
const maxRetries = 3;
|
|
1227
|
+
if (this._cacheCapacityRetries >= maxRetries) {
|
|
1228
|
+
this.polLogger?.warn?.(`[PolAttachmentQueue] Cache at capacity, max retries (${maxRetries}) reached. ${this.downloadQueue.size} items pending, waiting for next watchPaths emission.`);
|
|
1229
|
+
this._cacheCapacityRetries = 0;
|
|
1230
|
+
} else {
|
|
1231
|
+
const delay = 5e3 * this._cacheCapacityRetries;
|
|
1232
|
+
this.polLogger?.warn?.(`[PolAttachmentQueue] Cache at ${Math.round(this.cacheConfig.downloadStopThreshold * 100)}% capacity. ${this.downloadQueue.size} items pending, retry ${this._cacheCapacityRetries}/${maxRetries} in ${delay / 1e3}s.`);
|
|
1233
|
+
setTimeout(() => {
|
|
1234
|
+
if (!this._disposed && this.downloadQueue.size > 0) {
|
|
1235
|
+
this._downloadRecordsConcurrent();
|
|
1236
|
+
}
|
|
1237
|
+
}, delay);
|
|
1238
|
+
}
|
|
1176
1239
|
break;
|
|
1177
1240
|
}
|
|
1178
1241
|
}
|
|
@@ -1191,6 +1254,13 @@ var PolAttachmentQueue = class extends AbstractAttachmentQueue2 {
|
|
|
1191
1254
|
}
|
|
1192
1255
|
} catch (err) {
|
|
1193
1256
|
this.polLogger?.warn?.(`[PolAttachmentQueue] Download failed for ${id}:`, err);
|
|
1257
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
1258
|
+
if (isPermanentError(error)) {
|
|
1259
|
+
this.polLogger?.info?.(`[PolAttachmentQueue] Not retrying ${id} (permanent error)`);
|
|
1260
|
+
} else {
|
|
1261
|
+
this.polLogger?.debug?.(`[PolAttachmentQueue] Re-queuing ${id} for retry (transient error)`);
|
|
1262
|
+
this.downloadQueue.add(id);
|
|
1263
|
+
}
|
|
1194
1264
|
}
|
|
1195
1265
|
});
|
|
1196
1266
|
await Promise.all(downloadPromises);
|
|
@@ -1207,45 +1277,23 @@ var PolAttachmentQueue = class extends AbstractAttachmentQueue2 {
|
|
|
1207
1277
|
}
|
|
1208
1278
|
async watchAttachmentIds() {
|
|
1209
1279
|
this.onAttachmentIdsChange(async (ids) => {
|
|
1210
|
-
|
|
1211
|
-
this.polLogger?.debug?.(`[PolAttachmentQueue]
|
|
1212
|
-
|
|
1213
|
-
let skippedIds = [];
|
|
1214
|
-
if (this.source.skipDownload && ids.length > 0) {
|
|
1215
|
-
try {
|
|
1216
|
-
const context = {
|
|
1217
|
-
ids,
|
|
1218
|
-
db: this.powersync
|
|
1219
|
-
};
|
|
1220
|
-
skippedIds = await this.source.skipDownload(context);
|
|
1221
|
-
if (generation !== this._watchGeneration) {
|
|
1222
|
-
this.polLogger?.debug?.("[PolAttachmentQueue] Stale watch callback, ignoring");
|
|
1223
|
-
return;
|
|
1224
|
-
}
|
|
1225
|
-
const skipSet = new Set(skippedIds);
|
|
1226
|
-
filteredIds = ids.filter((id) => !skipSet.has(id));
|
|
1227
|
-
this.polLogger?.info?.(`[PolAttachmentQueue] Pre-filtered: ${ids.length} total, ${skippedIds.length} skipped, ${filteredIds.length} to sync`);
|
|
1228
|
-
} catch (error) {
|
|
1229
|
-
this.polLogger?.warn?.("[PolAttachmentQueue] skipDownload filter failed, using all IDs:", error);
|
|
1230
|
-
filteredIds = ids;
|
|
1231
|
-
skippedIds = [];
|
|
1232
|
-
}
|
|
1233
|
-
}
|
|
1234
|
-
this.polLogger?.debug?.(`[PolAttachmentQueue] Syncing attachment IDs: [${filteredIds.length} items]`);
|
|
1280
|
+
this.polLogger?.debug?.(`[PolAttachmentQueue] Received ${ids.length} attachment paths from watch`);
|
|
1281
|
+
this.polLogger?.debug?.(`[PolAttachmentQueue] Syncing attachment paths: [${ids.length} items]`);
|
|
1282
|
+
this._cacheCapacityRetries = 0;
|
|
1235
1283
|
if (this.initialSync) {
|
|
1236
1284
|
this.initialSync = false;
|
|
1237
|
-
if (
|
|
1238
|
-
const placeholders =
|
|
1285
|
+
if (ids.length > 0) {
|
|
1286
|
+
const placeholders = ids.map(() => "?").join(",");
|
|
1239
1287
|
await this.powersync.execute(`UPDATE ${this.table}
|
|
1240
1288
|
SET state = ${AttachmentState6.QUEUED_SYNC}
|
|
1241
1289
|
WHERE state < ${AttachmentState6.SYNCED}
|
|
1242
|
-
AND state NOT IN (${AttachmentState6.QUEUED_UPLOAD}, ${5 /* FAILED_PERMANENT */}
|
|
1243
|
-
AND id IN (${placeholders})`,
|
|
1290
|
+
AND state NOT IN (${AttachmentState6.QUEUED_UPLOAD}, ${5 /* FAILED_PERMANENT */})
|
|
1291
|
+
AND id IN (${placeholders})`, ids);
|
|
1244
1292
|
}
|
|
1245
1293
|
}
|
|
1246
1294
|
const attachmentsInDatabase = await this.powersync.getAll(`SELECT * FROM ${this.table} WHERE state < ${AttachmentState6.ARCHIVED}`);
|
|
1247
1295
|
const attachmentsMap = new Map(attachmentsInDatabase.map((r) => [r.id, r]));
|
|
1248
|
-
for (const id of
|
|
1296
|
+
for (const id of ids) {
|
|
1249
1297
|
const record = attachmentsMap.get(id);
|
|
1250
1298
|
if (!record) {
|
|
1251
1299
|
const newRecord = await this.newAttachmentRecord({
|
|
@@ -1257,7 +1305,6 @@ var PolAttachmentQueue = class extends AbstractAttachmentQueue2 {
|
|
|
1257
1305
|
}
|
|
1258
1306
|
if (PROTECTED_UPLOAD_STATES.has(record.state)) continue;
|
|
1259
1307
|
if (record.upload_source_uri) continue;
|
|
1260
|
-
if (record.state === 6 /* DOWNLOAD_SKIPPED */) continue;
|
|
1261
1308
|
if (record.local_uri == null || !await this.storage.fileExists(this.getLocalUri(record.local_uri))) {
|
|
1262
1309
|
await this.update({
|
|
1263
1310
|
...record,
|
|
@@ -1265,22 +1312,14 @@ var PolAttachmentQueue = class extends AbstractAttachmentQueue2 {
|
|
|
1265
1312
|
});
|
|
1266
1313
|
}
|
|
1267
1314
|
}
|
|
1268
|
-
if (
|
|
1269
|
-
const placeholders =
|
|
1270
|
-
await this.powersync.execute(`UPDATE ${this.table}
|
|
1271
|
-
SET state = ${6 /* DOWNLOAD_SKIPPED */}
|
|
1272
|
-
WHERE id IN (${placeholders})
|
|
1273
|
-
AND state NOT IN (${AttachmentState6.QUEUED_UPLOAD}, ${5 /* FAILED_PERMANENT */}, ${AttachmentState6.SYNCED})`, skippedIds);
|
|
1274
|
-
}
|
|
1275
|
-
const allValidIds = [.../* @__PURE__ */ new Set([...filteredIds, ...skippedIds])];
|
|
1276
|
-
if (allValidIds.length > 0) {
|
|
1277
|
-
const placeholders = allValidIds.map(() => "?").join(",");
|
|
1315
|
+
if (ids.length > 0) {
|
|
1316
|
+
const placeholders = ids.map(() => "?").join(",");
|
|
1278
1317
|
await this.powersync.execute(`UPDATE ${this.table}
|
|
1279
1318
|
SET state = ${AttachmentState6.ARCHIVED}
|
|
1280
1319
|
WHERE state < ${AttachmentState6.ARCHIVED}
|
|
1281
1320
|
AND state NOT IN (${AttachmentState6.QUEUED_UPLOAD}, ${5 /* FAILED_PERMANENT */})
|
|
1282
1321
|
AND upload_source_uri IS NULL
|
|
1283
|
-
AND id NOT IN (${placeholders})`,
|
|
1322
|
+
AND id NOT IN (${placeholders})`, ids);
|
|
1284
1323
|
}
|
|
1285
1324
|
this._invalidateStatsCache();
|
|
1286
1325
|
this._notify(true);
|
|
@@ -1314,21 +1353,25 @@ var PolAttachmentQueue = class extends AbstractAttachmentQueue2 {
|
|
|
1314
1353
|
onAttachmentIdsChange(onUpdate) {
|
|
1315
1354
|
this._watchMutex = this._watchMutex.then(async () => {
|
|
1316
1355
|
if (this._disposed) return;
|
|
1317
|
-
if (this.
|
|
1356
|
+
if (this._watchCleanup) {
|
|
1318
1357
|
try {
|
|
1319
|
-
this.
|
|
1358
|
+
this._watchCleanup();
|
|
1320
1359
|
} catch (error) {
|
|
1321
1360
|
this.polLogger?.warn?.("[PolAttachmentQueue] Watch cleanup failed:", error);
|
|
1322
1361
|
}
|
|
1323
|
-
this.
|
|
1362
|
+
this._watchCleanup = void 0;
|
|
1324
1363
|
}
|
|
1325
1364
|
try {
|
|
1326
|
-
|
|
1365
|
+
if (!this.source.watchPaths) {
|
|
1366
|
+
this.polLogger?.warn?.("[PolAttachmentQueue] No watchPaths callback provided");
|
|
1367
|
+
return;
|
|
1368
|
+
}
|
|
1369
|
+
const cleanup = this.source.watchPaths(this.powersync, this.supabaseClient, onUpdate);
|
|
1327
1370
|
if (typeof cleanup === "function") {
|
|
1328
|
-
this.
|
|
1371
|
+
this._watchCleanup = cleanup;
|
|
1329
1372
|
}
|
|
1330
1373
|
} catch (error) {
|
|
1331
|
-
this.polLogger?.warn?.("[PolAttachmentQueue]
|
|
1374
|
+
this.polLogger?.warn?.("[PolAttachmentQueue] watchPaths callback failed:", error);
|
|
1332
1375
|
}
|
|
1333
1376
|
}).catch((err) => {
|
|
1334
1377
|
this.polLogger?.warn?.("[PolAttachmentQueue] Watch mutex error:", err);
|
|
@@ -1413,13 +1456,13 @@ var PolAttachmentQueue = class extends AbstractAttachmentQueue2 {
|
|
|
1413
1456
|
dispose() {
|
|
1414
1457
|
this._disposed = true;
|
|
1415
1458
|
this._uploadState.abortController.abort();
|
|
1416
|
-
if (this.
|
|
1459
|
+
if (this._watchCleanup) {
|
|
1417
1460
|
try {
|
|
1418
|
-
this.
|
|
1461
|
+
this._watchCleanup();
|
|
1419
1462
|
} catch (error) {
|
|
1420
|
-
this.polLogger?.warn?.("[PolAttachmentQueue]
|
|
1463
|
+
this.polLogger?.warn?.("[PolAttachmentQueue] watchPaths cleanup failed:", error);
|
|
1421
1464
|
}
|
|
1422
|
-
this.
|
|
1465
|
+
this._watchCleanup = void 0;
|
|
1423
1466
|
}
|
|
1424
1467
|
if (this._networkListenerCleanup) {
|
|
1425
1468
|
try {
|
|
@@ -1756,7 +1799,7 @@ var PolAttachmentQueue = class extends AbstractAttachmentQueue2 {
|
|
|
1756
1799
|
}
|
|
1757
1800
|
const rows = await this.powersync.getAll(`SELECT state, COUNT(*) as cnt, COALESCE(SUM(size), 0) as sz
|
|
1758
1801
|
FROM ${this.table} GROUP BY state`);
|
|
1759
|
-
let synced = 0, syncedSize = 0, pending = 0, pendingUpload = 0, failedPermanent = 0
|
|
1802
|
+
let synced = 0, syncedSize = 0, pending = 0, pendingUpload = 0, failedPermanent = 0;
|
|
1760
1803
|
for (const r of rows) {
|
|
1761
1804
|
if (r.state === AttachmentState6.SYNCED) {
|
|
1762
1805
|
synced = r.cnt;
|
|
@@ -1765,7 +1808,6 @@ var PolAttachmentQueue = class extends AbstractAttachmentQueue2 {
|
|
|
1765
1808
|
if (r.state === AttachmentState6.QUEUED_DOWNLOAD || r.state === AttachmentState6.QUEUED_SYNC) pending += r.cnt;
|
|
1766
1809
|
if (r.state === AttachmentState6.QUEUED_UPLOAD) pendingUpload = r.cnt;
|
|
1767
1810
|
if (r.state === 5 /* FAILED_PERMANENT */) failedPermanent = r.cnt;
|
|
1768
|
-
if (r.state === 6 /* DOWNLOAD_SKIPPED */) skippedDownloadCount = r.cnt;
|
|
1769
1811
|
}
|
|
1770
1812
|
const staleUploads = await this.getStaleUploads();
|
|
1771
1813
|
const stats = {
|
|
@@ -1786,7 +1828,8 @@ var PolAttachmentQueue = class extends AbstractAttachmentQueue2 {
|
|
|
1786
1828
|
failedPermanentCount: failedPermanent,
|
|
1787
1829
|
staleUploadCount: staleUploads.length,
|
|
1788
1830
|
activeUploads: this.activeUploads,
|
|
1789
|
-
skippedDownloadCount
|
|
1831
|
+
skippedDownloadCount: 0
|
|
1832
|
+
// No longer tracked - filtering should happen in watchPaths
|
|
1790
1833
|
};
|
|
1791
1834
|
this._cachedStats = stats;
|
|
1792
1835
|
this._cachedStatsTimestamp = now;
|
|
@@ -1970,10 +2013,10 @@ function createPolAttachmentQueue(powersync, platform, config) {
|
|
|
1970
2013
|
storage: void 0,
|
|
1971
2014
|
platform,
|
|
1972
2015
|
remoteStorage: config.remoteStorage,
|
|
2016
|
+
supabaseClient: config.supabaseClient,
|
|
1973
2017
|
source: {
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
skipDownload: config.skipDownload
|
|
2018
|
+
source: config.source,
|
|
2019
|
+
watchPaths: config.watchPaths
|
|
1977
2020
|
},
|
|
1978
2021
|
attachmentDirectoryName: "attachments",
|
|
1979
2022
|
attachmentTableName: "attachments",
|
|
@@ -2003,6 +2046,10 @@ export {
|
|
|
2003
2046
|
DEFAULT_CACHE_CONFIG,
|
|
2004
2047
|
CACHE_SIZE_PRESETS,
|
|
2005
2048
|
formatCacheSize,
|
|
2049
|
+
resolveBucketFromConfig,
|
|
2050
|
+
isSignedUrlSource,
|
|
2051
|
+
isCustomSource,
|
|
2052
|
+
getCustomUrlResolver,
|
|
2006
2053
|
ATTACHMENT_TABLE,
|
|
2007
2054
|
AttachmentState,
|
|
2008
2055
|
AttachmentTable,
|
|
@@ -2058,4 +2105,4 @@ export {
|
|
|
2058
2105
|
PolAttachmentQueue,
|
|
2059
2106
|
createPolAttachmentQueue
|
|
2060
2107
|
};
|
|
2061
|
-
//# sourceMappingURL=chunk-
|
|
2108
|
+
//# sourceMappingURL=chunk-PGEDE6IM.js.map
|