@pol-studios/powersync 1.0.6 → 1.0.10

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 (128) hide show
  1. package/README.md +933 -0
  2. package/dist/CacheSettingsManager-uz-kbnRH.d.ts +461 -0
  3. package/dist/attachments/index.d.ts +745 -332
  4. package/dist/attachments/index.js +152 -6
  5. package/dist/{types-Cd7RhNqf.d.ts → background-sync-ChCXW-EV.d.ts} +53 -2
  6. package/dist/chunk-24RDMMCL.js +44 -0
  7. package/dist/chunk-24RDMMCL.js.map +1 -0
  8. package/dist/chunk-4TXTAEF2.js +2060 -0
  9. package/dist/chunk-4TXTAEF2.js.map +1 -0
  10. package/dist/chunk-63PXSPIN.js +358 -0
  11. package/dist/chunk-63PXSPIN.js.map +1 -0
  12. package/dist/chunk-654ERHA7.js +1 -0
  13. package/dist/chunk-A4IBBWGO.js +377 -0
  14. package/dist/chunk-A4IBBWGO.js.map +1 -0
  15. package/dist/chunk-BRXQNASY.js +1720 -0
  16. package/dist/chunk-BRXQNASY.js.map +1 -0
  17. package/dist/chunk-CAB26E6F.js +142 -0
  18. package/dist/chunk-CAB26E6F.js.map +1 -0
  19. package/dist/{chunk-EJ23MXPQ.js → chunk-CGL33PL4.js} +3 -1
  20. package/dist/chunk-CGL33PL4.js.map +1 -0
  21. package/dist/{chunk-R4YFWQ3Q.js → chunk-CUCAYK7Z.js} +309 -92
  22. package/dist/chunk-CUCAYK7Z.js.map +1 -0
  23. package/dist/chunk-FV2HXEIY.js +124 -0
  24. package/dist/chunk-FV2HXEIY.js.map +1 -0
  25. package/dist/chunk-HWSNV45P.js +279 -0
  26. package/dist/chunk-HWSNV45P.js.map +1 -0
  27. package/dist/{chunk-62J2DPKX.js → chunk-KN2IZERF.js} +530 -413
  28. package/dist/chunk-KN2IZERF.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-P4HZA6ZT.js +83 -0
  32. package/dist/chunk-P4HZA6ZT.js.map +1 -0
  33. package/dist/chunk-P6WOZO7H.js +49 -0
  34. package/dist/chunk-P6WOZO7H.js.map +1 -0
  35. package/dist/chunk-T4AO7JIG.js +1 -0
  36. package/dist/chunk-TGBT5XBE.js +1 -0
  37. package/dist/{chunk-FPTDATY5.js → chunk-VACPAAQZ.js} +54 -12
  38. package/dist/chunk-VACPAAQZ.js.map +1 -0
  39. package/dist/chunk-WGHNIAF7.js +329 -0
  40. package/dist/chunk-WGHNIAF7.js.map +1 -0
  41. package/dist/{chunk-3AYXHQ4W.js → chunk-WN5ZJ3E2.js} +108 -47
  42. package/dist/chunk-WN5ZJ3E2.js.map +1 -0
  43. package/dist/chunk-XAEII4ZX.js +456 -0
  44. package/dist/chunk-XAEII4ZX.js.map +1 -0
  45. package/dist/chunk-XOY2CJ67.js +289 -0
  46. package/dist/chunk-XOY2CJ67.js.map +1 -0
  47. package/dist/chunk-YHTZ7VMV.js +1 -0
  48. package/dist/chunk-YSTEESEG.js +676 -0
  49. package/dist/chunk-YSTEESEG.js.map +1 -0
  50. package/dist/chunk-Z6VOBGTU.js +32 -0
  51. package/dist/chunk-Z6VOBGTU.js.map +1 -0
  52. package/dist/chunk-ZM4ENYMF.js +230 -0
  53. package/dist/chunk-ZM4ENYMF.js.map +1 -0
  54. package/dist/connector/index.d.ts +236 -4
  55. package/dist/connector/index.js +15 -4
  56. package/dist/core/index.d.ts +16 -3
  57. package/dist/core/index.js +6 -2
  58. package/dist/error/index.d.ts +54 -0
  59. package/dist/error/index.js +7 -0
  60. package/dist/error/index.js.map +1 -0
  61. package/dist/index.d.ts +102 -12
  62. package/dist/index.js +309 -37
  63. package/dist/index.native.d.ts +22 -10
  64. package/dist/index.native.js +309 -38
  65. package/dist/index.web.d.ts +22 -10
  66. package/dist/index.web.js +310 -38
  67. package/dist/maintenance/index.d.ts +118 -0
  68. package/dist/maintenance/index.js +16 -0
  69. package/dist/maintenance/index.js.map +1 -0
  70. package/dist/platform/index.d.ts +16 -1
  71. package/dist/platform/index.js.map +1 -1
  72. package/dist/platform/index.native.d.ts +2 -2
  73. package/dist/platform/index.native.js +1 -1
  74. package/dist/platform/index.web.d.ts +1 -1
  75. package/dist/platform/index.web.js +1 -1
  76. package/dist/pol-attachment-queue-BVAIueoP.d.ts +817 -0
  77. package/dist/provider/index.d.ts +451 -21
  78. package/dist/provider/index.js +32 -13
  79. package/dist/react/index.d.ts +372 -0
  80. package/dist/react/index.js +25 -0
  81. package/dist/react/index.js.map +1 -0
  82. package/dist/storage/index.d.ts +6 -0
  83. package/dist/storage/index.js +42 -0
  84. package/dist/storage/index.js.map +1 -0
  85. package/dist/storage/index.native.d.ts +6 -0
  86. package/dist/storage/index.native.js +40 -0
  87. package/dist/storage/index.native.js.map +1 -0
  88. package/dist/storage/index.web.d.ts +6 -0
  89. package/dist/storage/index.web.js +40 -0
  90. package/dist/storage/index.web.js.map +1 -0
  91. package/dist/storage/upload/index.d.ts +54 -0
  92. package/dist/storage/upload/index.js +15 -0
  93. package/dist/storage/upload/index.js.map +1 -0
  94. package/dist/storage/upload/index.native.d.ts +56 -0
  95. package/dist/storage/upload/index.native.js +15 -0
  96. package/dist/storage/upload/index.native.js.map +1 -0
  97. package/dist/storage/upload/index.web.d.ts +2 -0
  98. package/dist/storage/upload/index.web.js +14 -0
  99. package/dist/storage/upload/index.web.js.map +1 -0
  100. package/dist/supabase-connector-T9vHq_3i.d.ts +202 -0
  101. package/dist/sync/index.d.ts +288 -23
  102. package/dist/sync/index.js +22 -10
  103. package/dist/{index-l3iL9Jte.d.ts → types-B212hgfA.d.ts} +101 -158
  104. package/dist/{types-afHtE1U_.d.ts → types-CDqWh56B.d.ts} +2 -0
  105. package/dist/types-CyvBaAl8.d.ts +60 -0
  106. package/dist/types-D0WcHrq6.d.ts +234 -0
  107. package/package.json +89 -5
  108. package/dist/chunk-32OLICZO.js +0 -1
  109. package/dist/chunk-3AYXHQ4W.js.map +0 -1
  110. package/dist/chunk-5FIMA26D.js +0 -1
  111. package/dist/chunk-62J2DPKX.js.map +0 -1
  112. package/dist/chunk-7EMDVIZX.js.map +0 -1
  113. package/dist/chunk-EJ23MXPQ.js.map +0 -1
  114. package/dist/chunk-FPTDATY5.js.map +0 -1
  115. package/dist/chunk-KCDG2MNP.js +0 -1431
  116. package/dist/chunk-KCDG2MNP.js.map +0 -1
  117. package/dist/chunk-OLHGI472.js +0 -1
  118. package/dist/chunk-PAFBKNL3.js +0 -99
  119. package/dist/chunk-PAFBKNL3.js.map +0 -1
  120. package/dist/chunk-R4YFWQ3Q.js.map +0 -1
  121. package/dist/chunk-V6LJ6MR2.js +0 -740
  122. package/dist/chunk-V6LJ6MR2.js.map +0 -1
  123. package/dist/chunk-VJCL2SWD.js +0 -1
  124. package/dist/failed-upload-store-C0cLxxPz.d.ts +0 -33
  125. /package/dist/{chunk-32OLICZO.js.map → chunk-654ERHA7.js.map} +0 -0
  126. /package/dist/{chunk-5FIMA26D.js.map → chunk-T4AO7JIG.js.map} +0 -0
  127. /package/dist/{chunk-OLHGI472.js.map → chunk-TGBT5XBE.js.map} +0 -0
  128. /package/dist/{chunk-VJCL2SWD.js.map → chunk-YHTZ7VMV.js.map} +0 -0
@@ -0,0 +1,289 @@
1
+ import {
2
+ getStorageErrorMessage,
3
+ isStorageAuthError,
4
+ normalizeStoragePath
5
+ } from "./chunk-XAEII4ZX.js";
6
+ import {
7
+ resolveBucket
8
+ } from "./chunk-Z6VOBGTU.js";
9
+
10
+ // src/storage/supabase.ts
11
+ function createSupabaseStorage(options) {
12
+ const {
13
+ client,
14
+ defaultBucket,
15
+ bucketMap,
16
+ bucketResolver,
17
+ signedUrlExpiry = 60,
18
+ fileSystem,
19
+ logger
20
+ } = options;
21
+ function getBucket(storagePath) {
22
+ return resolveBucket({
23
+ defaultBucket,
24
+ bucketMap,
25
+ bucketResolver
26
+ }, storagePath);
27
+ }
28
+ async function getSignedUrl(remotePath) {
29
+ const normalizedPath = normalizeStoragePath(remotePath);
30
+ const bucket = getBucket(normalizedPath);
31
+ logger?.debug?.(`[SupabaseStorage] Creating signed URL`, {
32
+ bucket,
33
+ path: normalizedPath,
34
+ originalPath: remotePath !== normalizedPath ? remotePath : void 0
35
+ });
36
+ const {
37
+ data,
38
+ error
39
+ } = await client.storage.from(bucket).createSignedUrl(normalizedPath, signedUrlExpiry);
40
+ if (error) {
41
+ const errorMessage = getStorageErrorMessage(error);
42
+ if (isStorageAuthError(error)) {
43
+ logger?.warn?.(`[SupabaseStorage] Auth error creating signed URL, refreshing session:`, {
44
+ path: normalizedPath,
45
+ bucket,
46
+ error: errorMessage
47
+ });
48
+ try {
49
+ await client.auth.refreshSession();
50
+ const {
51
+ data: retryData,
52
+ error: retryError
53
+ } = await client.storage.from(bucket).createSignedUrl(normalizedPath, signedUrlExpiry);
54
+ if (retryError) {
55
+ const retryErrorMessage = getStorageErrorMessage(retryError);
56
+ throw new Error(`Failed to create signed URL after session refresh: ${retryErrorMessage}`);
57
+ }
58
+ if (!retryData?.signedUrl) {
59
+ throw new Error("Failed to create signed URL after session refresh: No URL returned");
60
+ }
61
+ logger?.info?.(`[SupabaseStorage] Successfully created signed URL after session refresh`);
62
+ return retryData.signedUrl;
63
+ } catch (refreshError) {
64
+ throw new Error(`Failed to create signed URL: ${errorMessage} (session refresh also failed: ${refreshError instanceof Error ? refreshError.message : String(refreshError)})`);
65
+ }
66
+ }
67
+ throw new Error(`Failed to create signed URL for '${normalizedPath}' in bucket '${bucket}': ${errorMessage}`);
68
+ }
69
+ if (!data?.signedUrl) {
70
+ throw new Error(`Failed to create signed URL for '${normalizedPath}' in bucket '${bucket}': No URL returned`);
71
+ }
72
+ return data.signedUrl;
73
+ }
74
+ async function download(remotePath) {
75
+ const signedUrl = await getSignedUrl(remotePath);
76
+ if (fileSystem) {
77
+ const cacheDir = fileSystem.getCacheDirectory();
78
+ const tempFileName = `download_${Date.now()}_${Math.random().toString(36).slice(2)}`;
79
+ const tempPath = `${cacheDir}/${tempFileName}`;
80
+ try {
81
+ await fileSystem.downloadFile(signedUrl, tempPath);
82
+ return {
83
+ type: "file",
84
+ uri: tempPath
85
+ };
86
+ } catch (downloadError) {
87
+ try {
88
+ const info = await fileSystem.getFileInfo(tempPath);
89
+ if (info?.exists) {
90
+ await fileSystem.deleteFile(tempPath);
91
+ }
92
+ } catch {
93
+ }
94
+ throw downloadError;
95
+ }
96
+ }
97
+ const response = await fetch(signedUrl);
98
+ if (!response.ok) {
99
+ throw new Error(`Download failed with status ${response.status}: ${remotePath}`);
100
+ }
101
+ const blob = await response.blob();
102
+ return {
103
+ type: "blob",
104
+ data: blob
105
+ };
106
+ }
107
+ async function upload(remotePath, localUri, contentType, options2) {
108
+ const normalizedPath = normalizeStoragePath(remotePath);
109
+ const bucket = getBucket(normalizedPath);
110
+ const {
111
+ signal,
112
+ onProgress
113
+ } = options2 ?? {};
114
+ let fileData;
115
+ if (fileSystem && localUri.startsWith("file://")) {
116
+ const base64Content = await fileSystem.readFile(localUri, "base64");
117
+ const binaryString = atob(base64Content);
118
+ const bytes = new Uint8Array(binaryString.length);
119
+ for (let i = 0; i < binaryString.length; i++) {
120
+ bytes[i] = binaryString.charCodeAt(i);
121
+ }
122
+ fileData = new Blob([bytes], {
123
+ type: contentType
124
+ });
125
+ } else if (localUri.startsWith("blob:") || localUri.startsWith("http")) {
126
+ const response = await fetch(localUri);
127
+ fileData = await response.blob();
128
+ } else {
129
+ throw new Error(`Unsupported URI format: ${localUri}`);
130
+ }
131
+ if (signal?.aborted) {
132
+ throw new Error("Upload cancelled");
133
+ }
134
+ onProgress?.({
135
+ loaded: 0,
136
+ total: fileData.size
137
+ });
138
+ const {
139
+ error
140
+ } = await client.storage.from(bucket).upload(normalizedPath, fileData, {
141
+ contentType,
142
+ upsert: true
143
+ });
144
+ if (error) {
145
+ const errorMessage = getStorageErrorMessage(error);
146
+ throw new Error(`Upload failed for '${normalizedPath}' in bucket '${bucket}': ${errorMessage}`);
147
+ }
148
+ onProgress?.({
149
+ loaded: fileData.size,
150
+ total: fileData.size
151
+ });
152
+ }
153
+ async function deleteFile(remotePath) {
154
+ const normalizedPath = normalizeStoragePath(remotePath);
155
+ const bucket = getBucket(normalizedPath);
156
+ const {
157
+ error
158
+ } = await client.storage.from(bucket).remove([normalizedPath]);
159
+ if (error) {
160
+ const errorMessage = getStorageErrorMessage(error);
161
+ throw new Error(`Delete failed for '${normalizedPath}' in bucket '${bucket}': ${errorMessage}`);
162
+ }
163
+ }
164
+ return {
165
+ download,
166
+ upload,
167
+ delete: deleteFile,
168
+ resolveBucket: getBucket
169
+ };
170
+ }
171
+ function isFileResult(result) {
172
+ return result.type === "file";
173
+ }
174
+ function isBlobResult(result) {
175
+ return result.type === "blob";
176
+ }
177
+
178
+ // src/storage/cache/types.ts
179
+ var DEFAULT_CACHE_SETTINGS = {
180
+ maxCacheSizeMb: 5120,
181
+ // 5 GB
182
+ compressionQuality: 0.7
183
+ // 70% quality
184
+ };
185
+
186
+ // src/storage/cache/CacheSettingsManager.ts
187
+ var STORAGE_KEYS = {
188
+ MAX_CACHE_SIZE_MB: "max-cache-size-mb",
189
+ COMPRESSION_QUALITY: "compression-quality"
190
+ };
191
+ var CacheSettingsManager = class {
192
+ storage;
193
+ keyPrefix;
194
+ defaults;
195
+ constructor(storage, options) {
196
+ this.storage = storage;
197
+ this.keyPrefix = options?.storageKeyPrefix ?? "@pol-studios/cache";
198
+ this.defaults = {
199
+ ...DEFAULT_CACHE_SETTINGS,
200
+ ...options?.defaults
201
+ };
202
+ }
203
+ /**
204
+ * Get the full storage key for a setting.
205
+ */
206
+ getKey(setting) {
207
+ return `${this.keyPrefix}/${STORAGE_KEYS[setting]}`;
208
+ }
209
+ /**
210
+ * Get all cache settings.
211
+ */
212
+ async getSettings() {
213
+ const keys = [this.getKey("MAX_CACHE_SIZE_MB"), this.getKey("COMPRESSION_QUALITY")];
214
+ const results = await this.storage.multiGet(keys);
215
+ const sizeValue = results.find(([k]) => k === keys[0])?.[1];
216
+ const qualityValue = results.find(([k]) => k === keys[1])?.[1];
217
+ return {
218
+ maxCacheSizeMb: sizeValue ? Number(sizeValue) : this.defaults.maxCacheSizeMb,
219
+ compressionQuality: qualityValue ? Number(qualityValue) : this.defaults.compressionQuality
220
+ };
221
+ }
222
+ /**
223
+ * Get the maximum cache size in megabytes.
224
+ * Returns 0 for unlimited.
225
+ */
226
+ async getMaxCacheSizeMb() {
227
+ const value = await this.storage.getItem(this.getKey("MAX_CACHE_SIZE_MB"));
228
+ return value ? Number(value) : this.defaults.maxCacheSizeMb;
229
+ }
230
+ /**
231
+ * Set the maximum cache size in megabytes.
232
+ * Use 0 for unlimited.
233
+ *
234
+ * @param mb - Maximum cache size in megabytes
235
+ */
236
+ async setMaxCacheSizeMb(mb) {
237
+ if (mb < 0) {
238
+ throw new Error("Cache size must be non-negative");
239
+ }
240
+ await this.storage.setItem(this.getKey("MAX_CACHE_SIZE_MB"), String(mb));
241
+ }
242
+ /**
243
+ * Get the maximum cache size in bytes.
244
+ * Returns Number.MAX_SAFE_INTEGER for unlimited.
245
+ */
246
+ async getMaxCacheSizeBytes() {
247
+ const mb = await this.getMaxCacheSizeMb();
248
+ return mb === 0 ? Number.MAX_SAFE_INTEGER : mb * 1024 * 1024;
249
+ }
250
+ /**
251
+ * Get the compression quality (0.0 to 1.0).
252
+ */
253
+ async getCompressionQuality() {
254
+ const value = await this.storage.getItem(this.getKey("COMPRESSION_QUALITY"));
255
+ return value ? Number(value) : this.defaults.compressionQuality;
256
+ }
257
+ /**
258
+ * Set the compression quality.
259
+ *
260
+ * @param quality - Compression quality (0.0 to 1.0)
261
+ */
262
+ async setCompressionQuality(quality) {
263
+ if (quality < 0 || quality > 1) {
264
+ throw new Error("Compression quality must be between 0 and 1");
265
+ }
266
+ await this.storage.setItem(this.getKey("COMPRESSION_QUALITY"), String(quality));
267
+ }
268
+ /**
269
+ * Reset all settings to defaults.
270
+ */
271
+ async resetToDefaults() {
272
+ await this.storage.multiSet([[this.getKey("MAX_CACHE_SIZE_MB"), String(this.defaults.maxCacheSizeMb)], [this.getKey("COMPRESSION_QUALITY"), String(this.defaults.compressionQuality)]]);
273
+ }
274
+ /**
275
+ * Clear all stored settings.
276
+ */
277
+ async clear() {
278
+ await Promise.all([this.storage.removeItem(this.getKey("MAX_CACHE_SIZE_MB")), this.storage.removeItem(this.getKey("COMPRESSION_QUALITY"))]);
279
+ }
280
+ };
281
+
282
+ export {
283
+ createSupabaseStorage,
284
+ isFileResult,
285
+ isBlobResult,
286
+ DEFAULT_CACHE_SETTINGS,
287
+ CacheSettingsManager
288
+ };
289
+ //# sourceMappingURL=chunk-XOY2CJ67.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/storage/supabase.ts","../src/storage/cache/types.ts","../src/storage/cache/CacheSettingsManager.ts"],"sourcesContent":["/**\n * Supabase Storage Backend for @pol-studios/powersync\n *\n * Unified storage implementation using Supabase Storage.\n * Handles both web (Blob) and native (file URI) downloads.\n *\n * @example\n * ```typescript\n * import { createSupabaseStorage } from '@pol-studios/powersync/storage';\n *\n * const storage = createSupabaseStorage({\n * client: supabaseClient,\n * defaultBucket: 'attachments',\n * fileSystem: platform.fileSystem, // Required for native\n * });\n *\n * // Download\n * const result = await storage.download('photos/image.jpg');\n * if (result.type === 'file') {\n * // Native: zero-copy file path\n * console.log('Downloaded to:', result.uri);\n * } else {\n * // Web: Blob in memory\n * console.log('Downloaded blob:', result.data.size, 'bytes');\n * }\n *\n * // Upload with progress\n * await storage.upload('photos/new.jpg', 'file:///local/path.jpg', 'image/jpeg', {\n * onProgress: ({ loaded, total }) => {\n * console.log(`Progress: ${Math.round(loaded / total * 100)}%`);\n * },\n * });\n * ```\n */\n\nimport type { StorageBackend, DownloadResult, StorageUploadOptions, SupabaseStorageOptions, SupabaseClient } from './types';\nimport { resolveBucket } from './types';\nimport { isStorageAuthError, getStorageErrorMessage, normalizeStoragePath } from './auth-error-utils';\n\n/**\n * Create a Supabase storage backend.\n *\n * @param options - Configuration options\n * @returns StorageBackend implementation\n */\nexport function createSupabaseStorage(options: SupabaseStorageOptions): StorageBackend {\n const {\n client,\n defaultBucket,\n bucketMap,\n bucketResolver,\n signedUrlExpiry = 60,\n fileSystem,\n logger\n } = options;\n\n /**\n * Get the bucket for a storage path.\n */\n function getBucket(storagePath: string): string {\n return resolveBucket({\n defaultBucket,\n bucketMap,\n bucketResolver\n }, storagePath);\n }\n\n /**\n * Create a signed download URL with automatic session refresh on auth errors.\n */\n async function getSignedUrl(remotePath: string): Promise<string> {\n // Normalize the path to remove any leading slashes\n // Supabase Storage expects paths without leading slashes\n const normalizedPath = normalizeStoragePath(remotePath);\n const bucket = getBucket(normalizedPath);\n logger?.debug?.(`[SupabaseStorage] Creating signed URL`, {\n bucket,\n path: normalizedPath,\n originalPath: remotePath !== normalizedPath ? remotePath : undefined\n });\n\n // First attempt\n const {\n data,\n error\n } = await client.storage.from(bucket).createSignedUrl(normalizedPath, signedUrlExpiry);\n if (error) {\n const errorMessage = getStorageErrorMessage(error);\n\n // Check if this is an auth error that might be fixed by refreshing the session\n if (isStorageAuthError(error)) {\n logger?.warn?.(`[SupabaseStorage] Auth error creating signed URL, refreshing session:`, {\n path: normalizedPath,\n bucket,\n error: errorMessage\n });\n try {\n // Refresh the session\n await client.auth.refreshSession();\n\n // Retry the request\n const {\n data: retryData,\n error: retryError\n } = await client.storage.from(bucket).createSignedUrl(normalizedPath, signedUrlExpiry);\n if (retryError) {\n const retryErrorMessage = getStorageErrorMessage(retryError);\n throw new Error(`Failed to create signed URL after session refresh: ${retryErrorMessage}`);\n }\n if (!retryData?.signedUrl) {\n throw new Error('Failed to create signed URL after session refresh: No URL returned');\n }\n logger?.info?.(`[SupabaseStorage] Successfully created signed URL after session refresh`);\n return retryData.signedUrl;\n } catch (refreshError) {\n throw new Error(`Failed to create signed URL: ${errorMessage} (session refresh also failed: ${refreshError instanceof Error ? refreshError.message : String(refreshError)})`);\n }\n }\n\n // Non-auth error, throw with normalized error message\n throw new Error(`Failed to create signed URL for '${normalizedPath}' in bucket '${bucket}': ${errorMessage}`);\n }\n if (!data?.signedUrl) {\n throw new Error(`Failed to create signed URL for '${normalizedPath}' in bucket '${bucket}': No URL returned`);\n }\n return data.signedUrl;\n }\n\n /**\n * Download a file from remote storage.\n *\n * Returns a discriminated union:\n * - Native (with fileSystem): `{ type: 'file', uri: string }` - zero-copy file path\n * - Web (no fileSystem): `{ type: 'blob', data: Blob }` - blob in memory\n */\n async function download(remotePath: string): Promise<DownloadResult> {\n const signedUrl = await getSignedUrl(remotePath);\n\n // Native path: download directly to temp file\n if (fileSystem) {\n const cacheDir = fileSystem.getCacheDirectory();\n const tempFileName = `download_${Date.now()}_${Math.random().toString(36).slice(2)}`;\n const tempPath = `${cacheDir}/${tempFileName}`;\n try {\n await fileSystem.downloadFile(signedUrl, tempPath);\n return {\n type: 'file',\n uri: tempPath\n };\n } catch (downloadError) {\n // Clean up temp file on error\n try {\n const info = await fileSystem.getFileInfo(tempPath);\n if (info?.exists) {\n await fileSystem.deleteFile(tempPath);\n }\n } catch {\n // Ignore cleanup errors\n }\n throw downloadError;\n }\n }\n\n // Web path: fetch as blob\n const response = await fetch(signedUrl);\n if (!response.ok) {\n throw new Error(`Download failed with status ${response.status}: ${remotePath}`);\n }\n const blob = await response.blob();\n return {\n type: 'blob',\n data: blob\n };\n }\n\n /**\n * Upload a file to remote storage.\n *\n * Supports both native file URIs and web blob URLs.\n */\n async function upload(remotePath: string, localUri: string, contentType: string, options?: StorageUploadOptions): Promise<void> {\n // Normalize the path to remove any leading slashes\n const normalizedPath = normalizeStoragePath(remotePath);\n const bucket = getBucket(normalizedPath);\n const {\n signal,\n onProgress\n } = options ?? {};\n\n // Read file content\n let fileData: Blob;\n if (fileSystem && localUri.startsWith('file://')) {\n // Native: read file as base64, convert to blob\n const base64Content = await fileSystem.readFile(localUri, 'base64');\n const binaryString = atob(base64Content);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n fileData = new Blob([bytes], {\n type: contentType\n });\n } else if (localUri.startsWith('blob:') || localUri.startsWith('http')) {\n // Web: fetch blob URL\n const response = await fetch(localUri);\n fileData = await response.blob();\n } else {\n throw new Error(`Unsupported URI format: ${localUri}`);\n }\n\n // Check for cancellation\n if (signal?.aborted) {\n throw new Error('Upload cancelled');\n }\n\n // Report initial progress\n onProgress?.({\n loaded: 0,\n total: fileData.size\n });\n\n // Upload to Supabase\n const {\n error\n } = await client.storage.from(bucket).upload(normalizedPath, fileData, {\n contentType,\n upsert: true\n });\n if (error) {\n const errorMessage = getStorageErrorMessage(error);\n throw new Error(`Upload failed for '${normalizedPath}' in bucket '${bucket}': ${errorMessage}`);\n }\n\n // Report completion\n onProgress?.({\n loaded: fileData.size,\n total: fileData.size\n });\n }\n\n /**\n * Delete a file from remote storage.\n */\n async function deleteFile(remotePath: string): Promise<void> {\n // Normalize the path to remove any leading slashes\n const normalizedPath = normalizeStoragePath(remotePath);\n const bucket = getBucket(normalizedPath);\n const {\n error\n } = await client.storage.from(bucket).remove([normalizedPath]);\n if (error) {\n const errorMessage = getStorageErrorMessage(error);\n throw new Error(`Delete failed for '${normalizedPath}' in bucket '${bucket}': ${errorMessage}`);\n }\n }\n return {\n download,\n upload,\n delete: deleteFile,\n resolveBucket: getBucket\n };\n}\n\n// ─── Type Guard Utilities ───────────────────────────────────────────────────\n\n/**\n * Type guard to check if download result is a file URI.\n */\nexport function isFileResult(result: DownloadResult): result is {\n type: 'file';\n uri: string;\n} {\n return result.type === 'file';\n}\n\n/**\n * Type guard to check if download result is a blob.\n */\nexport function isBlobResult(result: DownloadResult): result is {\n type: 'blob';\n data: Blob;\n} {\n return result.type === 'blob';\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":["options"]}
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=chunk-YHTZ7VMV.js.map