@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.
- package/README.md +933 -0
- package/dist/CacheSettingsManager-uz-kbnRH.d.ts +461 -0
- package/dist/attachments/index.d.ts +745 -332
- package/dist/attachments/index.js +152 -6
- package/dist/{types-Cd7RhNqf.d.ts → background-sync-ChCXW-EV.d.ts} +53 -2
- package/dist/chunk-24RDMMCL.js +44 -0
- package/dist/chunk-24RDMMCL.js.map +1 -0
- package/dist/chunk-4TXTAEF2.js +2060 -0
- package/dist/chunk-4TXTAEF2.js.map +1 -0
- package/dist/chunk-63PXSPIN.js +358 -0
- package/dist/chunk-63PXSPIN.js.map +1 -0
- package/dist/chunk-654ERHA7.js +1 -0
- package/dist/chunk-A4IBBWGO.js +377 -0
- package/dist/chunk-A4IBBWGO.js.map +1 -0
- package/dist/chunk-BRXQNASY.js +1720 -0
- package/dist/chunk-BRXQNASY.js.map +1 -0
- package/dist/chunk-CAB26E6F.js +142 -0
- package/dist/chunk-CAB26E6F.js.map +1 -0
- package/dist/{chunk-EJ23MXPQ.js → chunk-CGL33PL4.js} +3 -1
- package/dist/chunk-CGL33PL4.js.map +1 -0
- package/dist/{chunk-R4YFWQ3Q.js → chunk-CUCAYK7Z.js} +309 -92
- package/dist/chunk-CUCAYK7Z.js.map +1 -0
- package/dist/chunk-FV2HXEIY.js +124 -0
- package/dist/chunk-FV2HXEIY.js.map +1 -0
- package/dist/chunk-HWSNV45P.js +279 -0
- package/dist/chunk-HWSNV45P.js.map +1 -0
- package/dist/{chunk-62J2DPKX.js → chunk-KN2IZERF.js} +530 -413
- package/dist/chunk-KN2IZERF.js.map +1 -0
- package/dist/{chunk-7EMDVIZX.js → chunk-N75DEF5J.js} +19 -1
- package/dist/chunk-N75DEF5J.js.map +1 -0
- package/dist/chunk-P4HZA6ZT.js +83 -0
- package/dist/chunk-P4HZA6ZT.js.map +1 -0
- package/dist/chunk-P6WOZO7H.js +49 -0
- package/dist/chunk-P6WOZO7H.js.map +1 -0
- package/dist/chunk-T4AO7JIG.js +1 -0
- package/dist/chunk-TGBT5XBE.js +1 -0
- package/dist/{chunk-FPTDATY5.js → chunk-VACPAAQZ.js} +54 -12
- package/dist/chunk-VACPAAQZ.js.map +1 -0
- package/dist/chunk-WGHNIAF7.js +329 -0
- package/dist/chunk-WGHNIAF7.js.map +1 -0
- package/dist/{chunk-3AYXHQ4W.js → chunk-WN5ZJ3E2.js} +108 -47
- package/dist/chunk-WN5ZJ3E2.js.map +1 -0
- package/dist/chunk-XAEII4ZX.js +456 -0
- package/dist/chunk-XAEII4ZX.js.map +1 -0
- package/dist/chunk-XOY2CJ67.js +289 -0
- package/dist/chunk-XOY2CJ67.js.map +1 -0
- package/dist/chunk-YHTZ7VMV.js +1 -0
- package/dist/chunk-YSTEESEG.js +676 -0
- package/dist/chunk-YSTEESEG.js.map +1 -0
- package/dist/chunk-Z6VOBGTU.js +32 -0
- package/dist/chunk-Z6VOBGTU.js.map +1 -0
- package/dist/chunk-ZM4ENYMF.js +230 -0
- package/dist/chunk-ZM4ENYMF.js.map +1 -0
- package/dist/connector/index.d.ts +236 -4
- package/dist/connector/index.js +15 -4
- package/dist/core/index.d.ts +16 -3
- package/dist/core/index.js +6 -2
- package/dist/error/index.d.ts +54 -0
- package/dist/error/index.js +7 -0
- package/dist/error/index.js.map +1 -0
- package/dist/index.d.ts +102 -12
- package/dist/index.js +309 -37
- package/dist/index.native.d.ts +22 -10
- package/dist/index.native.js +309 -38
- package/dist/index.web.d.ts +22 -10
- package/dist/index.web.js +310 -38
- package/dist/maintenance/index.d.ts +118 -0
- package/dist/maintenance/index.js +16 -0
- package/dist/maintenance/index.js.map +1 -0
- package/dist/platform/index.d.ts +16 -1
- package/dist/platform/index.js.map +1 -1
- package/dist/platform/index.native.d.ts +2 -2
- package/dist/platform/index.native.js +1 -1
- package/dist/platform/index.web.d.ts +1 -1
- package/dist/platform/index.web.js +1 -1
- package/dist/pol-attachment-queue-BVAIueoP.d.ts +817 -0
- package/dist/provider/index.d.ts +451 -21
- package/dist/provider/index.js +32 -13
- package/dist/react/index.d.ts +372 -0
- package/dist/react/index.js +25 -0
- package/dist/react/index.js.map +1 -0
- package/dist/storage/index.d.ts +6 -0
- package/dist/storage/index.js +42 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/index.native.d.ts +6 -0
- package/dist/storage/index.native.js +40 -0
- package/dist/storage/index.native.js.map +1 -0
- package/dist/storage/index.web.d.ts +6 -0
- package/dist/storage/index.web.js +40 -0
- package/dist/storage/index.web.js.map +1 -0
- package/dist/storage/upload/index.d.ts +54 -0
- package/dist/storage/upload/index.js +15 -0
- package/dist/storage/upload/index.js.map +1 -0
- package/dist/storage/upload/index.native.d.ts +56 -0
- package/dist/storage/upload/index.native.js +15 -0
- package/dist/storage/upload/index.native.js.map +1 -0
- package/dist/storage/upload/index.web.d.ts +2 -0
- package/dist/storage/upload/index.web.js +14 -0
- package/dist/storage/upload/index.web.js.map +1 -0
- package/dist/supabase-connector-T9vHq_3i.d.ts +202 -0
- package/dist/sync/index.d.ts +288 -23
- package/dist/sync/index.js +22 -10
- package/dist/{index-l3iL9Jte.d.ts → types-B212hgfA.d.ts} +101 -158
- package/dist/{types-afHtE1U_.d.ts → types-CDqWh56B.d.ts} +2 -0
- package/dist/types-CyvBaAl8.d.ts +60 -0
- package/dist/types-D0WcHrq6.d.ts +234 -0
- package/package.json +89 -5
- package/dist/chunk-32OLICZO.js +0 -1
- package/dist/chunk-3AYXHQ4W.js.map +0 -1
- package/dist/chunk-5FIMA26D.js +0 -1
- package/dist/chunk-62J2DPKX.js.map +0 -1
- package/dist/chunk-7EMDVIZX.js.map +0 -1
- package/dist/chunk-EJ23MXPQ.js.map +0 -1
- package/dist/chunk-FPTDATY5.js.map +0 -1
- package/dist/chunk-KCDG2MNP.js +0 -1431
- package/dist/chunk-KCDG2MNP.js.map +0 -1
- package/dist/chunk-OLHGI472.js +0 -1
- package/dist/chunk-PAFBKNL3.js +0 -99
- package/dist/chunk-PAFBKNL3.js.map +0 -1
- package/dist/chunk-R4YFWQ3Q.js.map +0 -1
- package/dist/chunk-V6LJ6MR2.js +0 -740
- package/dist/chunk-V6LJ6MR2.js.map +0 -1
- package/dist/chunk-VJCL2SWD.js +0 -1
- package/dist/failed-upload-store-C0cLxxPz.d.ts +0 -33
- /package/dist/{chunk-32OLICZO.js.map → chunk-654ERHA7.js.map} +0 -0
- /package/dist/{chunk-5FIMA26D.js.map → chunk-T4AO7JIG.js.map} +0 -0
- /package/dist/{chunk-OLHGI472.js.map → chunk-TGBT5XBE.js.map} +0 -0
- /package/dist/{chunk-VJCL2SWD.js.map → chunk-YHTZ7VMV.js.map} +0 -0
|
@@ -1,399 +1,812 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { f as AttachmentStorageAdapter, d as PolAttachmentRecord, h as UploadHandler, U as UploadConfig, t as UploadStatus, k as CacheConfig, W as WatchConfig } from '../pol-attachment-queue-BVAIueoP.js';
|
|
2
|
+
export { e as AttachmentConfig, z as AttachmentRecord, A as AttachmentSourceConfig, w as AttachmentStatsRow, v as AttachmentSyncStats, u as AttachmentSyncStatus, B as BatchFilterContext, m as CACHE_SIZE_PRESETS, x as CacheFileRow, n as CacheSizePreset, o as CacheSizeValue, y as CachedSizeRow, C as CompressionConfig, l as DEFAULT_CACHE_CONFIG, D as DEFAULT_COMPRESSION_CONFIG, j as DEFAULT_DOWNLOAD_CONFIG, g as DEFAULT_UPLOAD_CONFIG, i as DownloadConfig, q as DownloadPhase, r as DownloadStatus, E as EvictRow, I as IdRow, P as PolAttachmentQueue, a as PolAttachmentQueueOptions, b as PolAttachmentState, S as SkipDownloadContext, s as UploadPhase, c as createPolAttachmentQueue, p as formatCacheSize } from '../pol-attachment-queue-BVAIueoP.js';
|
|
3
|
+
import { StorageAdapter, EncodingType, AttachmentRecord } from '@powersync/attachments';
|
|
4
|
+
export { ATTACHMENT_TABLE, AbstractAttachmentQueue, AttachmentState, AttachmentTable, AttachmentTableOptions, AttachmentQueueOptions as BaseAttachmentQueueOptions, DEFAULT_ATTACHMENT_QUEUE_OPTIONS, EncodingType, AttachmentRecord as OfficialAttachmentRecord, StorageAdapter } from '@powersync/attachments';
|
|
5
|
+
import { PlatformAdapter, LoggerAdapter } from '../platform/index.js';
|
|
6
|
+
import { AbstractPowerSyncDatabase } from '@powersync/common';
|
|
7
|
+
export { AbstractPowerSyncDatabase as PowerSyncDBInterface } from '@powersync/common';
|
|
8
|
+
import '../types-CDqWh56B.js';
|
|
3
9
|
|
|
4
10
|
/**
|
|
5
|
-
*
|
|
11
|
+
* POL Storage Adapter
|
|
6
12
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*/
|
|
14
|
-
declare enum AttachmentState {
|
|
15
|
-
/** Waiting to be downloaded */
|
|
16
|
-
QUEUED_DOWNLOAD = 0,
|
|
17
|
-
/** Waiting for initial sync */
|
|
18
|
-
QUEUED_SYNC = 1,
|
|
19
|
-
/** Waiting to be uploaded */
|
|
20
|
-
QUEUED_UPLOAD = 2,
|
|
21
|
-
/** Fully synced (downloaded or uploaded) */
|
|
22
|
-
SYNCED = 3,
|
|
23
|
-
/** Archived (removed from sync but record kept) */
|
|
24
|
-
ARCHIVED = 4
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Record representing an attachment in the queue database.
|
|
28
|
-
*/
|
|
29
|
-
interface AttachmentRecord {
|
|
30
|
-
/** Unique identifier (typically storage path) */
|
|
31
|
-
id: string;
|
|
32
|
-
/** Filename for display and type inference */
|
|
33
|
-
filename: string;
|
|
34
|
-
/** MIME type of the file */
|
|
35
|
-
media_type: string;
|
|
36
|
-
/** Current state in the queue */
|
|
37
|
-
state: AttachmentState;
|
|
38
|
-
/** Local file URI (set after download) */
|
|
39
|
-
local_uri?: string | null;
|
|
40
|
-
/** File size in bytes */
|
|
41
|
-
size?: number;
|
|
42
|
-
/** Timestamp when the attachment was created */
|
|
43
|
-
timestamp?: number;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Configuration for the source table that contains attachment references.
|
|
47
|
-
* This makes the attachment queue reusable across different tables/projects.
|
|
13
|
+
* Implements the official @powersync/attachments StorageAdapter interface,
|
|
14
|
+
* bridging our PlatformAdapter file system and remote storage adapters.
|
|
15
|
+
*
|
|
16
|
+
* This adapter combines:
|
|
17
|
+
* - Local file operations via PlatformAdapter.fileSystem
|
|
18
|
+
* - Remote upload/download via AttachmentStorageAdapter (e.g., Supabase)
|
|
48
19
|
*/
|
|
49
|
-
|
|
20
|
+
|
|
21
|
+
interface PolStorageAdapterOptions {
|
|
50
22
|
/**
|
|
51
|
-
*
|
|
52
|
-
* @example "EquipmentUnitMediaContent"
|
|
23
|
+
* Platform adapter for local file system operations.
|
|
53
24
|
*/
|
|
54
|
-
|
|
25
|
+
platform: PlatformAdapter;
|
|
55
26
|
/**
|
|
56
|
-
*
|
|
57
|
-
* @example "storagePath"
|
|
27
|
+
* Remote storage adapter for upload/download operations.
|
|
58
28
|
*/
|
|
59
|
-
|
|
29
|
+
remoteStorage: AttachmentStorageAdapter;
|
|
60
30
|
/**
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
* @example "takenOn"
|
|
31
|
+
* Base directory name for attachments within the cache directory.
|
|
32
|
+
* Defaults to 'attachments'.
|
|
64
33
|
*/
|
|
65
|
-
|
|
34
|
+
attachmentDirectoryName?: string;
|
|
66
35
|
/**
|
|
67
|
-
* Optional
|
|
68
|
-
*
|
|
69
|
-
* only attachments belonging to synced projects are downloaded.
|
|
36
|
+
* Optional logger for diagnostic messages.
|
|
37
|
+
* If provided, will log warnings when deprecated code paths are hit.
|
|
70
38
|
*/
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
foreignKey: string;
|
|
74
|
-
/** Intermediary table to JOIN through (e.g., "EquipmentFixtureUnit") */
|
|
75
|
-
intermediaryTable: string;
|
|
76
|
-
/** Column in intermediary table that links to ProjectDatabase (e.g., "projectDatabaseId") */
|
|
77
|
-
projectForeignKey: string;
|
|
39
|
+
logger?: {
|
|
40
|
+
warn(message: string, ...args: unknown[]): void;
|
|
78
41
|
};
|
|
79
42
|
}
|
|
80
43
|
/**
|
|
81
|
-
*
|
|
44
|
+
* Storage adapter that implements the official @powersync/attachments interface.
|
|
45
|
+
*
|
|
46
|
+
* Combines local file system operations (via PlatformAdapter) with remote
|
|
47
|
+
* storage operations (via AttachmentStorageAdapter like Supabase).
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* const storageAdapter = new PolStorageAdapter({
|
|
52
|
+
* platform: platformAdapter,
|
|
53
|
+
* remoteStorage: supabaseStorageAdapter,
|
|
54
|
+
* });
|
|
55
|
+
* ```
|
|
82
56
|
*/
|
|
83
|
-
|
|
57
|
+
declare class PolStorageAdapter implements StorageAdapter {
|
|
58
|
+
private readonly platform;
|
|
59
|
+
private readonly remoteStorage;
|
|
60
|
+
private readonly attachmentDirectoryName;
|
|
61
|
+
private readonly userStorageDirectory;
|
|
62
|
+
private readonly logger?;
|
|
63
|
+
constructor(options: PolStorageAdapterOptions);
|
|
64
|
+
/**
|
|
65
|
+
* Upload a file to remote storage.
|
|
66
|
+
*/
|
|
67
|
+
uploadFile(filePath: string, data: ArrayBuffer, options?: {
|
|
68
|
+
mediaType?: string;
|
|
69
|
+
}): Promise<void>;
|
|
84
70
|
/**
|
|
85
71
|
* Download a file from remote storage.
|
|
86
|
-
*
|
|
87
|
-
*
|
|
72
|
+
*
|
|
73
|
+
* NOTE: This method implements the official @powersync/attachments StorageAdapter
|
|
74
|
+
* interface which requires returning Promise<Blob>. For the memory-optimized
|
|
75
|
+
* file path passthrough, PolAttachmentQueue.downloadRecord() calls
|
|
76
|
+
* remoteStorage.downloadFile() directly to get the file:// path.
|
|
77
|
+
*
|
|
78
|
+
* This method handles base64 string → Blob conversion for backward compatibility.
|
|
79
|
+
*/
|
|
80
|
+
downloadFile(filePath: string): Promise<Blob>;
|
|
81
|
+
/**
|
|
82
|
+
* Write data to a local file.
|
|
83
|
+
*/
|
|
84
|
+
writeFile(fileUri: string, base64Data: string, options?: {
|
|
85
|
+
encoding?: EncodingType;
|
|
86
|
+
}): Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* Read a local file's contents.
|
|
89
|
+
*/
|
|
90
|
+
readFile(fileUri: string, options?: {
|
|
91
|
+
encoding?: EncodingType;
|
|
92
|
+
mediaType?: string;
|
|
93
|
+
}): Promise<ArrayBuffer>;
|
|
94
|
+
/**
|
|
95
|
+
* Delete a local file.
|
|
96
|
+
*/
|
|
97
|
+
deleteFile(uri: string, _options?: {
|
|
98
|
+
filename?: string;
|
|
99
|
+
}): Promise<void>;
|
|
100
|
+
/**
|
|
101
|
+
* Check if a local file exists.
|
|
102
|
+
*/
|
|
103
|
+
fileExists(fileUri: string): Promise<boolean>;
|
|
104
|
+
/**
|
|
105
|
+
* Create a directory (with intermediate directories).
|
|
88
106
|
*/
|
|
89
|
-
|
|
107
|
+
makeDir(uri: string): Promise<void>;
|
|
90
108
|
/**
|
|
91
|
-
*
|
|
92
|
-
* @param filePath - The storage path to upload to
|
|
93
|
-
* @param data - The file data to upload
|
|
109
|
+
* Copy a file from source to destination.
|
|
94
110
|
*/
|
|
95
|
-
|
|
111
|
+
copyFile(sourceUri: string, targetUri: string): Promise<void>;
|
|
96
112
|
/**
|
|
97
|
-
*
|
|
98
|
-
*
|
|
113
|
+
* Get the user's storage directory for attachments.
|
|
114
|
+
* Returns the cache directory path ending with '/'.
|
|
99
115
|
*/
|
|
100
|
-
|
|
116
|
+
getUserStorageDirectory(): string;
|
|
101
117
|
/**
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
* @param filePath - The file path to resolve
|
|
105
|
-
* @returns The bucket name
|
|
118
|
+
* Warning 8: Optimized base64 encoding using batch processing.
|
|
119
|
+
* Processes in chunks of 1024 bytes for better performance with large files.
|
|
106
120
|
*/
|
|
107
|
-
|
|
121
|
+
private _arrayBufferToBase64;
|
|
122
|
+
private _base64ToArrayBuffer;
|
|
108
123
|
}
|
|
124
|
+
|
|
109
125
|
/**
|
|
110
|
-
*
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
/** Max width before resizing (default: 2048) */
|
|
118
|
-
maxWidth: number;
|
|
119
|
-
/** Skip files under this size in bytes (default: 100KB) */
|
|
120
|
-
skipSizeBytes: number;
|
|
121
|
-
/** Skip if already under this size in bytes (default: 300KB) */
|
|
122
|
-
targetSizeBytes: number;
|
|
123
|
-
}
|
|
126
|
+
* Attachment State Machine
|
|
127
|
+
*
|
|
128
|
+
* Defines state transitions, protected states, and validation logic
|
|
129
|
+
* for the POL attachment queue system.
|
|
130
|
+
*
|
|
131
|
+
* @module attachments/state-machine
|
|
132
|
+
*/
|
|
124
133
|
/**
|
|
125
|
-
*
|
|
134
|
+
* States that represent active upload workflows.
|
|
135
|
+
* Records in these states should NEVER be demoted to download states.
|
|
136
|
+
*
|
|
137
|
+
* This fixes a race condition in the parent AbstractAttachmentQueue.watchAttachmentIds():
|
|
138
|
+
* - Upload records have `local_uri = null` (they use `upload_source_uri` instead)
|
|
139
|
+
* - When the CRUD record syncs back, `onAttachmentIdsChange` fires
|
|
140
|
+
* - Parent checks `record.local_uri == null` → true for uploads
|
|
141
|
+
* - Parent changes state from QUEUED_UPLOAD to QUEUED_DOWNLOAD
|
|
142
|
+
* - Upload is abandoned, download fails (file doesn't exist in remote storage yet)
|
|
143
|
+
*
|
|
144
|
+
* By protecting these states, we prevent the parent's logic from interfering
|
|
145
|
+
* with in-progress or queued uploads.
|
|
146
|
+
*
|
|
147
|
+
* @see https://github.com/powersync-ja/powersync-js/blob/main/packages/attachments/src/AbstractAttachmentQueue.ts
|
|
126
148
|
*/
|
|
127
|
-
declare const
|
|
149
|
+
declare const PROTECTED_UPLOAD_STATES: Set<number>;
|
|
128
150
|
/**
|
|
129
|
-
*
|
|
151
|
+
* States that indicate a download is pending or in progress.
|
|
130
152
|
*/
|
|
131
|
-
|
|
132
|
-
/** Maximum concurrent downloads (default: 50) */
|
|
133
|
-
concurrency: number;
|
|
134
|
-
/** Download timeout per file in ms (default: 60000) */
|
|
135
|
-
timeoutMs: number;
|
|
136
|
-
/** Retry delay between batches in ms (default: 5000) */
|
|
137
|
-
retryDelayMs: number;
|
|
138
|
-
}
|
|
153
|
+
declare const PENDING_DOWNLOAD_STATES: Set<number>;
|
|
139
154
|
/**
|
|
140
|
-
*
|
|
155
|
+
* States that indicate the attachment is locally available.
|
|
141
156
|
*/
|
|
142
|
-
declare const
|
|
157
|
+
declare const LOCALLY_AVAILABLE_STATES: Set<number>;
|
|
143
158
|
/**
|
|
144
|
-
*
|
|
159
|
+
* Check if a record is in a protected upload state.
|
|
160
|
+
* Protected states should not be demoted to download states.
|
|
145
161
|
*/
|
|
146
|
-
|
|
147
|
-
/** Maximum cache size in bytes (default: 5GB) */
|
|
148
|
-
maxSize: number;
|
|
149
|
-
/** Stop downloads at this percentage of max (default: 0.95 = 95%) */
|
|
150
|
-
downloadStopThreshold: number;
|
|
151
|
-
/** Trigger eviction at this percentage (default: 1.0 = 100%) */
|
|
152
|
-
evictionTriggerThreshold: number;
|
|
153
|
-
}
|
|
162
|
+
declare function isProtectedUploadState(state: number): boolean;
|
|
154
163
|
/**
|
|
155
|
-
*
|
|
164
|
+
* Check if a record is in a pending download state.
|
|
156
165
|
*/
|
|
157
|
-
declare
|
|
166
|
+
declare function isPendingDownloadState(state: number): boolean;
|
|
158
167
|
/**
|
|
159
|
-
*
|
|
168
|
+
* Check if a record has a locally available file.
|
|
160
169
|
*/
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
170
|
+
declare function isLocallyAvailable(state: number): boolean;
|
|
171
|
+
/**
|
|
172
|
+
* Check if a state transition is allowed.
|
|
173
|
+
* Prevents protected upload states from being demoted to download states.
|
|
174
|
+
*
|
|
175
|
+
* @param currentState - The current state of the record
|
|
176
|
+
* @param newState - The proposed new state
|
|
177
|
+
* @returns true if the transition is allowed
|
|
178
|
+
*/
|
|
179
|
+
declare function isStateTransitionAllowed(currentState: number, newState: number): boolean;
|
|
180
|
+
/**
|
|
181
|
+
* Get the appropriate state for a new attachment based on context.
|
|
182
|
+
*
|
|
183
|
+
* @param hasLocalUri - Whether the attachment has a local URI
|
|
184
|
+
* @param hasUploadSourceUri - Whether the attachment has an upload source URI
|
|
185
|
+
* @param currentState - The current state (if any)
|
|
186
|
+
* @returns The appropriate state for the attachment
|
|
187
|
+
*/
|
|
188
|
+
declare function determineAttachmentState(hasLocalUri: boolean, hasUploadSourceUri: boolean, currentState?: number): number;
|
|
189
|
+
/**
|
|
190
|
+
* Validate that a string is a safe SQL identifier.
|
|
191
|
+
* Prevents SQL injection via config values.
|
|
192
|
+
*
|
|
193
|
+
* @param value - The value to validate
|
|
194
|
+
* @param name - The name of the parameter (for error messages)
|
|
195
|
+
* @throws Error if the value is not a valid SQL identifier
|
|
196
|
+
*/
|
|
197
|
+
declare function validateSqlIdentifier$1(value: string, name: string): void;
|
|
198
|
+
/**
|
|
199
|
+
* Build a SQL IN clause with protected upload states excluded.
|
|
200
|
+
* Used for queries that should not affect upload records.
|
|
201
|
+
*/
|
|
202
|
+
declare function getProtectedStatesInClause(): string;
|
|
203
|
+
/**
|
|
204
|
+
* Build a SQL condition that excludes protected upload states.
|
|
205
|
+
*/
|
|
206
|
+
declare function getExcludeProtectedStatesCondition(stateColumn?: string): string;
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Download Manager
|
|
210
|
+
*
|
|
211
|
+
* Handles download-related logic including batch filtering,
|
|
212
|
+
* download filter application, and download record processing.
|
|
213
|
+
*
|
|
214
|
+
* @module attachments/download-manager
|
|
215
|
+
*/
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Dependencies required by the download manager.
|
|
219
|
+
*/
|
|
220
|
+
interface DownloadManagerDeps {
|
|
221
|
+
/** PowerSync database instance */
|
|
222
|
+
powersync: AbstractPowerSyncDatabase;
|
|
223
|
+
/** Platform adapter for file system operations */
|
|
224
|
+
platform: PlatformAdapter;
|
|
225
|
+
/** Logger adapter */
|
|
226
|
+
logger: LoggerAdapter;
|
|
227
|
+
/** Remote storage adapter for downloading files */
|
|
228
|
+
remoteStorage: AttachmentStorageAdapter;
|
|
229
|
+
/** Storage adapter with file operations */
|
|
230
|
+
storage: {
|
|
231
|
+
fileExists(uri: string): Promise<boolean>;
|
|
232
|
+
writeFile(uri: string, data: string, options?: {
|
|
233
|
+
encoding?: EncodingType;
|
|
234
|
+
}): Promise<void>;
|
|
235
|
+
makeDir(uri: string): Promise<void>;
|
|
236
|
+
copyFile(src: string, dest: string): Promise<void>;
|
|
237
|
+
};
|
|
238
|
+
/** Attachment table name */
|
|
239
|
+
tableName: string;
|
|
240
|
+
/** Function to get local URI from local path */
|
|
241
|
+
getLocalUri: (localPath: string) => string;
|
|
242
|
+
/** Function to get local file path suffix */
|
|
243
|
+
getLocalFilePathSuffix: (filename: string) => string;
|
|
244
|
+
/** Function to update a record */
|
|
245
|
+
update: (record: AttachmentRecord) => Promise<void>;
|
|
246
|
+
/** Whether downloads are enabled */
|
|
247
|
+
downloadAttachments?: boolean;
|
|
248
|
+
/** Callback when download errors occur */
|
|
249
|
+
onDownloadError?: (record: AttachmentRecord, error: Error) => Promise<{
|
|
250
|
+
retry?: boolean;
|
|
182
251
|
}>;
|
|
183
|
-
/**
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
252
|
+
/** Function to notify progress updates */
|
|
253
|
+
notify: (immediate: boolean) => void;
|
|
254
|
+
/** Function to invalidate stats cache */
|
|
255
|
+
invalidateStatsCache: () => void;
|
|
187
256
|
}
|
|
188
257
|
/**
|
|
189
|
-
*
|
|
258
|
+
* Convert a Blob to ArrayBuffer with fallback for React Native.
|
|
259
|
+
*
|
|
260
|
+
* Blob.arrayBuffer() is a web API not available in React Native's Hermes engine.
|
|
261
|
+
* Falls back to FileReader.readAsArrayBuffer() which works better than readAsDataURL()
|
|
262
|
+
* in React Native (readAsDataURL hangs but readAsArrayBuffer typically works).
|
|
190
263
|
*/
|
|
191
|
-
|
|
264
|
+
declare function blobToArrayBuffer(blob: Blob): Promise<ArrayBuffer>;
|
|
192
265
|
/**
|
|
193
|
-
*
|
|
266
|
+
* Download a single attachment record.
|
|
267
|
+
*
|
|
268
|
+
* Avoids FileReader.readAsDataURL() which hangs in React Native.
|
|
269
|
+
* The parent implementation uses FileReader to convert Blob to base64,
|
|
270
|
+
* but FileReader hangs indefinitely in React Native environments.
|
|
271
|
+
* This override writes the downloaded file directly to the file system
|
|
272
|
+
* using platform-native methods.
|
|
273
|
+
*
|
|
274
|
+
* Note: Filtering is handled by skipDownload callback in the queue.
|
|
194
275
|
*/
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
276
|
+
declare function downloadRecord(deps: DownloadManagerDeps, record: AttachmentRecord): Promise<boolean>;
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Upload Manager
|
|
280
|
+
*
|
|
281
|
+
* Handles upload processing, retry scheduling, error handling,
|
|
282
|
+
* and upload lifecycle management.
|
|
283
|
+
*
|
|
284
|
+
* @module attachments/upload-manager
|
|
285
|
+
*/
|
|
286
|
+
|
|
203
287
|
/**
|
|
204
|
-
*
|
|
205
|
-
*/
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
|
|
209
|
-
*/
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
|
|
225
|
-
/** Whether downloads are paused */
|
|
226
|
-
isPaused: boolean;
|
|
227
|
-
/** Whether currently processing downloads */
|
|
228
|
-
isProcessing: boolean;
|
|
229
|
-
/** Currently active downloads */
|
|
230
|
-
activeDownloads: DownloadStatus[];
|
|
288
|
+
* Dependencies required by the upload manager.
|
|
289
|
+
*/
|
|
290
|
+
interface UploadManagerDeps {
|
|
291
|
+
/** PowerSync database instance */
|
|
292
|
+
powersync: AbstractPowerSyncDatabase;
|
|
293
|
+
/** Platform adapter for file system operations */
|
|
294
|
+
platform: PlatformAdapter;
|
|
295
|
+
/** Logger adapter */
|
|
296
|
+
logger: LoggerAdapter;
|
|
297
|
+
/** Attachment table name */
|
|
298
|
+
tableName: string;
|
|
299
|
+
/** Upload handler for uploading files */
|
|
300
|
+
uploadHandler?: UploadHandler;
|
|
301
|
+
/** Upload configuration */
|
|
302
|
+
uploadConfig: UploadConfig;
|
|
303
|
+
/** Callback when upload completes */
|
|
304
|
+
onUploadComplete?: (record: PolAttachmentRecord) => Promise<void>;
|
|
305
|
+
/** Callback when upload fails permanently */
|
|
306
|
+
onUploadFailed?: (record: PolAttachmentRecord, error: Error) => void;
|
|
307
|
+
/** Function to notify progress updates */
|
|
308
|
+
notify: (immediate: boolean) => void;
|
|
231
309
|
}
|
|
232
|
-
/**
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
310
|
+
/**
|
|
311
|
+
* State for the upload manager.
|
|
312
|
+
*/
|
|
313
|
+
interface UploadManagerState {
|
|
314
|
+
/** Whether upload processing is active */
|
|
315
|
+
processing: boolean;
|
|
316
|
+
/** Whether uploads are paused */
|
|
317
|
+
paused: boolean;
|
|
318
|
+
/** Abort controller for cancellation */
|
|
319
|
+
abortController: AbortController;
|
|
320
|
+
/** Map of active uploads */
|
|
321
|
+
activeUploads: Map<string, UploadStatus>;
|
|
322
|
+
/** Set of active upload promises for cleanup during dispose */
|
|
323
|
+
activePromises: Set<Promise<void>>;
|
|
237
324
|
}
|
|
238
|
-
/**
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
325
|
+
/**
|
|
326
|
+
* Check if an error is permanent (should not retry).
|
|
327
|
+
*/
|
|
328
|
+
declare function isPermanentError(error: Error): boolean;
|
|
329
|
+
/**
|
|
330
|
+
* Extract HTTP status code from error message.
|
|
331
|
+
* Uses specific patterns to avoid false positives from numbers in other contexts.
|
|
332
|
+
*/
|
|
333
|
+
declare function extractErrorCode(error: Error): string | undefined;
|
|
334
|
+
/**
|
|
335
|
+
* Get pending uploads that need retry.
|
|
336
|
+
*/
|
|
337
|
+
declare function getPendingUploads(powersync: AbstractPowerSyncDatabase, tableName: string): Promise<PolAttachmentRecord[]>;
|
|
338
|
+
/**
|
|
339
|
+
* Get the soonest retry time for all uploads currently in backoff.
|
|
340
|
+
* Returns null if there are no uploads waiting for retry.
|
|
341
|
+
*/
|
|
342
|
+
declare function getSoonestRetryTime(powersync: AbstractPowerSyncDatabase, tableName: string): Promise<number | null>;
|
|
343
|
+
/**
|
|
344
|
+
* Get uploads that have permanently failed.
|
|
345
|
+
*/
|
|
346
|
+
declare function getFailedPermanentUploads(powersync: AbstractPowerSyncDatabase, tableName: string): Promise<PolAttachmentRecord[]>;
|
|
347
|
+
/**
|
|
348
|
+
* Get stale uploads (failing for > staleDaysThreshold).
|
|
349
|
+
*/
|
|
350
|
+
declare function getStaleUploads(powersync: AbstractPowerSyncDatabase, tableName: string, staleDaysThreshold: number): Promise<PolAttachmentRecord[]>;
|
|
351
|
+
/**
|
|
352
|
+
* Get SYNCED uploads that have pending onComplete callbacks.
|
|
353
|
+
*/
|
|
354
|
+
declare function getSyncedUploadsWithPendingCallback(powersync: AbstractPowerSyncDatabase, tableName: string): Promise<PolAttachmentRecord[]>;
|
|
355
|
+
/**
|
|
356
|
+
* Clear the onCompleteCallback flag from a record's metadata.
|
|
357
|
+
*/
|
|
358
|
+
declare function clearUploadCallback(powersync: AbstractPowerSyncDatabase, tableName: string, id: string, uploadMetadata?: string | null): Promise<void>;
|
|
359
|
+
/**
|
|
360
|
+
* Mark an upload as synced (complete).
|
|
361
|
+
*/
|
|
362
|
+
declare function markUploadSynced(deps: UploadManagerDeps, record: PolAttachmentRecord): Promise<void>;
|
|
363
|
+
/**
|
|
364
|
+
* Mark an upload as permanently failed.
|
|
365
|
+
*/
|
|
366
|
+
declare function markUploadPermanentFailure(deps: UploadManagerDeps, record: PolAttachmentRecord, errorMessage: string, errorCode?: string): Promise<void>;
|
|
367
|
+
/**
|
|
368
|
+
* Schedule an upload retry with exponential backoff.
|
|
369
|
+
*/
|
|
370
|
+
declare function scheduleUploadRetry(deps: UploadManagerDeps, record: PolAttachmentRecord, error: Error): Promise<void>;
|
|
371
|
+
/**
|
|
372
|
+
* Upload a single record.
|
|
373
|
+
*/
|
|
374
|
+
declare function uploadOne(deps: UploadManagerDeps, state: UploadManagerState, record: PolAttachmentRecord): Promise<void>;
|
|
375
|
+
/**
|
|
376
|
+
* Start the upload processing loop.
|
|
377
|
+
*/
|
|
378
|
+
declare function startUploadProcessing(deps: UploadManagerDeps, state: UploadManagerState): Promise<void>;
|
|
379
|
+
/**
|
|
380
|
+
* Create initial upload manager state.
|
|
381
|
+
*/
|
|
382
|
+
declare function createUploadManagerState(): UploadManagerState;
|
|
383
|
+
/**
|
|
384
|
+
* Create upload manager dependencies with defaults.
|
|
385
|
+
*/
|
|
386
|
+
declare function createUploadManagerDeps(partial: Omit<UploadManagerDeps, 'uploadConfig'> & {
|
|
387
|
+
uploadConfig?: Partial<UploadConfig>;
|
|
388
|
+
}): UploadManagerDeps;
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Cache Manager
|
|
392
|
+
*
|
|
393
|
+
* Handles cache eviction, cleanup logic, and cache management utilities.
|
|
394
|
+
*
|
|
395
|
+
* @module attachments/cache-manager
|
|
396
|
+
*/
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Ensure a path has the `file://` URI prefix.
|
|
400
|
+
* Used to standardize URI format throughout the attachment system.
|
|
401
|
+
*/
|
|
402
|
+
declare function ensureFileUri(path: string): string;
|
|
403
|
+
/**
|
|
404
|
+
* Strip the `file://` prefix from a URI to get the raw file path.
|
|
405
|
+
* Used when APIs require raw paths instead of URIs.
|
|
406
|
+
*/
|
|
407
|
+
declare function stripFileUri(uri: string): string;
|
|
408
|
+
/**
|
|
409
|
+
* Dependencies required by the cache manager.
|
|
410
|
+
*/
|
|
411
|
+
interface CacheManagerDeps {
|
|
412
|
+
/** PowerSync database instance */
|
|
413
|
+
powersync: AbstractPowerSyncDatabase;
|
|
414
|
+
/** Platform adapter for file system operations */
|
|
415
|
+
platform: PlatformAdapter;
|
|
416
|
+
/** Logger adapter */
|
|
417
|
+
logger: LoggerAdapter;
|
|
418
|
+
/** Attachment table name */
|
|
419
|
+
tableName: string;
|
|
420
|
+
/** Cache configuration */
|
|
421
|
+
cacheConfig: CacheConfig;
|
|
422
|
+
/** Function to get local URI from local path */
|
|
423
|
+
getLocalUri: (localPath: string) => string;
|
|
424
|
+
/** Function to notify progress updates */
|
|
425
|
+
notify: (immediate: boolean) => void;
|
|
426
|
+
/** Function to invalidate stats cache */
|
|
427
|
+
invalidateStatsCache: () => void;
|
|
242
428
|
}
|
|
243
|
-
/**
|
|
244
|
-
|
|
429
|
+
/**
|
|
430
|
+
* Get total size of cached files.
|
|
431
|
+
*/
|
|
432
|
+
declare function getCachedSize(powersync: AbstractPowerSyncDatabase, tableName: string): Promise<number>;
|
|
433
|
+
/**
|
|
434
|
+
* Get files eligible for eviction, ordered by timestamp (oldest first).
|
|
435
|
+
*/
|
|
436
|
+
declare function getEvictionCandidates(powersync: AbstractPowerSyncDatabase, tableName: string): Promise<Array<{
|
|
245
437
|
id: string;
|
|
246
438
|
local_uri: string;
|
|
247
439
|
size: number;
|
|
248
|
-
}
|
|
249
|
-
/**
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
440
|
+
}>>;
|
|
441
|
+
/**
|
|
442
|
+
* Enforce the cache size limit by evicting oldest files.
|
|
443
|
+
*
|
|
444
|
+
* This function checks if the current cache size exceeds `cacheConfig.maxSize`.
|
|
445
|
+
* If so, it evicts files (oldest first by timestamp) until the cache is below
|
|
446
|
+
* the max size. Evicted files have their `local_uri` cleared and state reset
|
|
447
|
+
* to `QUEUED_DOWNLOAD` so they can be re-downloaded later if needed.
|
|
448
|
+
*
|
|
449
|
+
* @returns Object with eviction stats: { evictedCount, freedBytes }
|
|
450
|
+
*/
|
|
451
|
+
declare function enforceCacheLimit(deps: CacheManagerDeps): Promise<{
|
|
452
|
+
evictedCount: number;
|
|
453
|
+
freedBytes: number;
|
|
454
|
+
}>;
|
|
455
|
+
/**
|
|
456
|
+
* Check if cache is near capacity (at downloadStopThreshold).
|
|
457
|
+
* Used to decide whether to skip starting new downloads.
|
|
458
|
+
*
|
|
459
|
+
* @returns true if cache is at or above the download stop threshold
|
|
460
|
+
*/
|
|
461
|
+
declare function isCacheNearCapacity(deps: CacheManagerDeps): Promise<boolean>;
|
|
462
|
+
/**
|
|
463
|
+
* Clear all cached files and re-queue for download.
|
|
464
|
+
* Preserves upload records (QUEUED_UPLOAD, FAILED_PERMANENT).
|
|
465
|
+
*/
|
|
466
|
+
declare function clearCache(deps: CacheManagerDeps): Promise<void>;
|
|
467
|
+
/**
|
|
468
|
+
* Cache a local file into the attachment cache.
|
|
469
|
+
* Used to cache uploaded files to avoid redundant downloads.
|
|
470
|
+
*/
|
|
471
|
+
declare function cacheLocalFile(deps: CacheManagerDeps, storagePath: string, sourceUri: string): Promise<void>;
|
|
472
|
+
/**
|
|
473
|
+
* Get the local file URI for a storage path.
|
|
474
|
+
* Checks both downloaded files (SYNCED state) and pending uploads (QUEUED_UPLOAD state).
|
|
475
|
+
*/
|
|
476
|
+
declare function getLocalUriForStoragePath(deps: CacheManagerDeps, storagePath: string, storage: {
|
|
477
|
+
fileExists(uri: string): Promise<boolean>;
|
|
478
|
+
}): Promise<string | null>;
|
|
479
|
+
/**
|
|
480
|
+
* Copy source file to managed cache for durable uploads.
|
|
481
|
+
*/
|
|
482
|
+
declare function copyToManagedCache(platform: PlatformAdapter, logger: LoggerAdapter, sourceUri: string, storagePath: string): Promise<string>;
|
|
483
|
+
/**
|
|
484
|
+
* Create cache manager dependencies with defaults.
|
|
485
|
+
*/
|
|
486
|
+
declare function createCacheManagerDeps(partial: Omit<CacheManagerDeps, 'cacheConfig'> & {
|
|
487
|
+
cacheConfig?: Partial<CacheConfig>;
|
|
488
|
+
}): CacheManagerDeps;
|
|
257
489
|
|
|
258
490
|
/**
|
|
259
|
-
*
|
|
491
|
+
* Query Builder for Attachment Watch Queries
|
|
260
492
|
*
|
|
261
|
-
*
|
|
262
|
-
* -
|
|
263
|
-
* - Cache management with eviction
|
|
264
|
-
* - Image compression
|
|
265
|
-
* - Pause/resume functionality
|
|
266
|
-
* - Progress tracking
|
|
493
|
+
* Generates SQL queries from WatchConfig objects.
|
|
494
|
+
* Provides type-safe query generation without raw SQL strings.
|
|
267
495
|
*/
|
|
268
496
|
|
|
269
497
|
/**
|
|
270
|
-
*
|
|
498
|
+
* Validates that a string is a safe SQL identifier.
|
|
499
|
+
* Throws an error if the identifier is invalid or potentially dangerous.
|
|
500
|
+
*
|
|
501
|
+
* @param identifier - The identifier to validate
|
|
502
|
+
* @param context - Description of where this identifier is used (for error messages)
|
|
503
|
+
* @throws Error if identifier is invalid
|
|
504
|
+
*/
|
|
505
|
+
declare function validateSqlIdentifier(identifier: string, context: string): void;
|
|
506
|
+
/**
|
|
507
|
+
* Validates a WHERE clause fragment for basic safety.
|
|
508
|
+
* Note: This is a best-effort validation. Complex WHERE clauses should be reviewed.
|
|
509
|
+
*
|
|
510
|
+
* @param whereClause - The WHERE clause fragment to validate
|
|
511
|
+
* @throws Error if the clause contains dangerous patterns
|
|
512
|
+
*/
|
|
513
|
+
declare function validateWhereClause(whereClause: string): void;
|
|
514
|
+
/**
|
|
515
|
+
* Build a SQL watch query from a WatchConfig.
|
|
516
|
+
*
|
|
517
|
+
* Generates a SELECT statement that:
|
|
518
|
+
* - Selects the ID column (aliased as `id`)
|
|
519
|
+
* - Optionally selects additional columns
|
|
520
|
+
* - Applies an optional WHERE clause
|
|
521
|
+
* - Optionally orders by a column
|
|
522
|
+
*
|
|
523
|
+
* @param config - The WatchConfig to build a query from
|
|
524
|
+
* @returns SQL query string
|
|
271
525
|
*
|
|
272
526
|
* @example
|
|
273
527
|
* ```typescript
|
|
274
|
-
* const
|
|
275
|
-
*
|
|
276
|
-
*
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
-
*
|
|
280
|
-
* idColumn: 'storagePath',
|
|
281
|
-
* orderByColumn: 'takenOn',
|
|
282
|
-
* },
|
|
283
|
-
* storage: storageAdapter,
|
|
284
|
-
* },
|
|
528
|
+
* const query = buildWatchQuery({
|
|
529
|
+
* table: 'EquipmentUnitMediaContent',
|
|
530
|
+
* idColumn: 'storagePath',
|
|
531
|
+
* selectColumns: ['equipmentUnitId', 'takenOn'],
|
|
532
|
+
* where: 'storagePath IS NOT NULL',
|
|
533
|
+
* orderBy: { column: 'takenOn', direction: 'DESC' },
|
|
285
534
|
* });
|
|
286
535
|
*
|
|
287
|
-
*
|
|
536
|
+
* // Result:
|
|
537
|
+
* // SELECT storagePath AS id, equipmentUnitId, takenOn
|
|
538
|
+
* // FROM EquipmentUnitMediaContent
|
|
539
|
+
* // WHERE storagePath IS NOT NULL
|
|
540
|
+
* // ORDER BY takenOn DESC
|
|
288
541
|
* ```
|
|
289
542
|
*/
|
|
290
|
-
declare
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
543
|
+
declare function buildWatchQuery(config: WatchConfig): string;
|
|
544
|
+
/**
|
|
545
|
+
* Build a simpler ID-only watch query.
|
|
546
|
+
* Use this when you only need IDs without additional columns.
|
|
547
|
+
*
|
|
548
|
+
* @param config - The WatchConfig to build a query from
|
|
549
|
+
* @returns SQL query string that selects only IDs
|
|
550
|
+
*
|
|
551
|
+
* @example
|
|
552
|
+
* ```typescript
|
|
553
|
+
* const query = buildIdOnlyWatchQuery({
|
|
554
|
+
* table: 'EquipmentUnitMediaContent',
|
|
555
|
+
* idColumn: 'storagePath',
|
|
556
|
+
* where: 'storagePath IS NOT NULL',
|
|
557
|
+
* });
|
|
558
|
+
*
|
|
559
|
+
* // Result:
|
|
560
|
+
* // SELECT storagePath AS id
|
|
561
|
+
* // FROM EquipmentUnitMediaContent
|
|
562
|
+
* // WHERE storagePath IS NOT NULL AND storagePath != ''
|
|
563
|
+
* ```
|
|
564
|
+
*/
|
|
565
|
+
declare function buildIdOnlyWatchQuery(config: WatchConfig): string;
|
|
566
|
+
/**
|
|
567
|
+
* Build a query to fetch records with their IDs and additional columns.
|
|
568
|
+
* Used for populating the BatchFilterContext.records map.
|
|
569
|
+
*
|
|
570
|
+
* @param config - The WatchConfig to build a query from
|
|
571
|
+
* @param ids - Optional list of IDs to filter to (for efficiency)
|
|
572
|
+
* @returns SQL query string and parameters
|
|
573
|
+
*
|
|
574
|
+
* @example
|
|
575
|
+
* ```typescript
|
|
576
|
+
* const { query, params } = buildRecordFetchQuery(
|
|
577
|
+
* {
|
|
578
|
+
* table: 'EquipmentUnitMediaContent',
|
|
579
|
+
* idColumn: 'storagePath',
|
|
580
|
+
* selectColumns: ['equipmentUnitId'],
|
|
581
|
+
* },
|
|
582
|
+
* ['path/to/file1.jpg', 'path/to/file2.jpg']
|
|
583
|
+
* );
|
|
584
|
+
* ```
|
|
585
|
+
*/
|
|
586
|
+
declare function buildRecordFetchQuery(config: WatchConfig, ids?: string[]): {
|
|
587
|
+
query: string;
|
|
588
|
+
params: unknown[];
|
|
589
|
+
};
|
|
590
|
+
/**
|
|
591
|
+
* Convert WatchConfig to the legacy AttachmentSourceConfig format.
|
|
592
|
+
* Useful during migration to maintain backwards compatibility.
|
|
593
|
+
*
|
|
594
|
+
* @param watchConfig - The new WatchConfig
|
|
595
|
+
* @returns Legacy AttachmentSourceConfig
|
|
596
|
+
*/
|
|
597
|
+
declare function watchConfigToSourceConfig(watchConfig: WatchConfig): {
|
|
598
|
+
table: string;
|
|
599
|
+
idColumn: string;
|
|
600
|
+
orderByColumn?: string | null;
|
|
601
|
+
};
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* Migration Utilities for @pol-studios/powersync Attachments
|
|
605
|
+
*
|
|
606
|
+
* This module provides utilities for migrating from the old attachment API
|
|
607
|
+
* to the new callback-based API. It includes:
|
|
608
|
+
*
|
|
609
|
+
* - State mapping constants for old → new state transitions
|
|
610
|
+
* - `migrateAttachmentState()` for converting state values
|
|
611
|
+
* - Validation helpers for migration safety
|
|
612
|
+
*
|
|
613
|
+
* @example
|
|
614
|
+
* ```typescript
|
|
615
|
+
* import { migrateAttachmentState, isValidAttachmentState } from '@pol-studios/powersync/attachments';
|
|
616
|
+
*
|
|
617
|
+
* // Migrate a single state value
|
|
618
|
+
* const newState = migrateAttachmentState(oldState);
|
|
619
|
+
*
|
|
620
|
+
* // Validate before migration
|
|
621
|
+
* if (isValidAttachmentState(value)) {
|
|
622
|
+
* const migrated = migrateAttachmentState(value);
|
|
623
|
+
* }
|
|
624
|
+
* ```
|
|
625
|
+
*/
|
|
626
|
+
/**
|
|
627
|
+
* Maps old state values to new state values.
|
|
628
|
+
*
|
|
629
|
+
* The official @powersync/attachments AttachmentState enum has values 0-4:
|
|
630
|
+
* QUEUED_SYNC=0, QUEUED_UPLOAD=1, QUEUED_DOWNLOAD=2, SYNCED=3, ARCHIVED=4
|
|
631
|
+
*
|
|
632
|
+
* POL extensions add:
|
|
633
|
+
* FAILED_PERMANENT=5, DOWNLOAD_SKIPPED=6
|
|
634
|
+
*
|
|
635
|
+
* For migration purposes, most states map 1:1. The mapping exists to:
|
|
636
|
+
* 1. Document the relationship between old and new states
|
|
637
|
+
* 2. Provide a clear upgrade path for custom state handling code
|
|
638
|
+
* 3. Allow future state reorganization if needed
|
|
639
|
+
*/
|
|
640
|
+
declare const STATE_MAPPING: ReadonlyMap<number, number>;
|
|
641
|
+
/**
|
|
642
|
+
* Human-readable names for attachment states.
|
|
643
|
+
* Useful for logging and debugging during migration.
|
|
644
|
+
*/
|
|
645
|
+
declare const STATE_NAMES: ReadonlyMap<number, string>;
|
|
646
|
+
/**
|
|
647
|
+
* All valid state values (official + POL extensions).
|
|
648
|
+
*/
|
|
649
|
+
declare const VALID_STATES: ReadonlySet<number>;
|
|
650
|
+
/**
|
|
651
|
+
* States that indicate an active upload workflow.
|
|
652
|
+
* Records in these states should not be migrated to download states.
|
|
653
|
+
*/
|
|
654
|
+
declare const UPLOAD_WORKFLOW_STATES: ReadonlySet<number>;
|
|
655
|
+
/**
|
|
656
|
+
* States that indicate an active download workflow.
|
|
657
|
+
*/
|
|
658
|
+
declare const DOWNLOAD_WORKFLOW_STATES: ReadonlySet<number>;
|
|
659
|
+
/**
|
|
660
|
+
* Terminal states (no further processing needed).
|
|
661
|
+
*/
|
|
662
|
+
declare const TERMINAL_STATES: ReadonlySet<number>;
|
|
663
|
+
/**
|
|
664
|
+
* Migrates an attachment state from the old API to the new API.
|
|
665
|
+
*
|
|
666
|
+
* Currently, this is a 1:1 mapping since the state values haven't changed.
|
|
667
|
+
* This function exists to:
|
|
668
|
+
* 1. Provide a clear migration path for apps using custom state handling
|
|
669
|
+
* 2. Document the state relationship
|
|
670
|
+
* 3. Allow future state reorganization without breaking existing code
|
|
671
|
+
*
|
|
672
|
+
* @param oldState - The state value from the old API
|
|
673
|
+
* @returns The corresponding state value in the new API
|
|
674
|
+
* @throws Error if the state value is invalid
|
|
675
|
+
*
|
|
676
|
+
* @example
|
|
677
|
+
* ```typescript
|
|
678
|
+
* import { migrateAttachmentState } from '@pol-studios/powersync/attachments';
|
|
679
|
+
*
|
|
680
|
+
* // Migrate a record's state
|
|
681
|
+
* const newState = migrateAttachmentState(record.state);
|
|
682
|
+
*
|
|
683
|
+
* // Migrate with fallback for unknown states
|
|
684
|
+
* const safeState = isValidAttachmentState(record.state)
|
|
685
|
+
* ? migrateAttachmentState(record.state)
|
|
686
|
+
* : PolAttachmentState.QUEUED_SYNC;
|
|
687
|
+
* ```
|
|
688
|
+
*/
|
|
689
|
+
declare function migrateAttachmentState(oldState: number): number;
|
|
690
|
+
/**
|
|
691
|
+
* Safely migrates an attachment state with a fallback.
|
|
692
|
+
*
|
|
693
|
+
* Unlike `migrateAttachmentState`, this function never throws.
|
|
694
|
+
* Invalid states are mapped to the provided fallback.
|
|
695
|
+
*
|
|
696
|
+
* @param oldState - The state value from the old API
|
|
697
|
+
* @param fallback - State to use if oldState is invalid (default: QUEUED_SYNC)
|
|
698
|
+
* @returns The corresponding state value in the new API, or the fallback
|
|
699
|
+
*
|
|
700
|
+
* @example
|
|
701
|
+
* ```typescript
|
|
702
|
+
* // Safely migrate with QUEUED_SYNC as fallback
|
|
703
|
+
* const state = migrateAttachmentStateSafe(unknownValue);
|
|
704
|
+
*
|
|
705
|
+
* // Use custom fallback
|
|
706
|
+
* const state = migrateAttachmentStateSafe(unknownValue, PolAttachmentState.ARCHIVED);
|
|
707
|
+
* ```
|
|
708
|
+
*/
|
|
709
|
+
declare function migrateAttachmentStateSafe(oldState: number, fallback?: number): number;
|
|
710
|
+
/**
|
|
711
|
+
* Checks if a value is a valid attachment state.
|
|
712
|
+
*
|
|
713
|
+
* @param value - The value to check
|
|
714
|
+
* @returns true if the value is a valid attachment state
|
|
715
|
+
*
|
|
716
|
+
* @example
|
|
717
|
+
* ```typescript
|
|
718
|
+
* if (isValidAttachmentState(record.state)) {
|
|
719
|
+
* // Safe to use record.state
|
|
720
|
+
* } else {
|
|
721
|
+
* console.warn(`Invalid state: ${record.state}`);
|
|
722
|
+
* }
|
|
723
|
+
* ```
|
|
724
|
+
*/
|
|
725
|
+
declare function isValidAttachmentState(value: unknown): value is number;
|
|
726
|
+
/**
|
|
727
|
+
* Checks if a state represents an upload workflow.
|
|
728
|
+
*
|
|
729
|
+
* Records in upload workflow states should not be demoted to download states.
|
|
730
|
+
*
|
|
731
|
+
* @param state - The state to check
|
|
732
|
+
* @returns true if the state is part of an upload workflow
|
|
733
|
+
*/
|
|
734
|
+
declare function isUploadWorkflowState(state: number): boolean;
|
|
735
|
+
/**
|
|
736
|
+
* Checks if a state represents a download workflow.
|
|
737
|
+
*
|
|
738
|
+
* @param state - The state to check
|
|
739
|
+
* @returns true if the state is part of a download workflow
|
|
740
|
+
*/
|
|
741
|
+
declare function isDownloadWorkflowState(state: number): boolean;
|
|
742
|
+
/**
|
|
743
|
+
* Checks if a state is terminal (no further processing needed).
|
|
744
|
+
*
|
|
745
|
+
* @param state - The state to check
|
|
746
|
+
* @returns true if the state is terminal
|
|
747
|
+
*/
|
|
748
|
+
declare function isTerminalState(state: number): boolean;
|
|
749
|
+
/**
|
|
750
|
+
* Gets the human-readable name of a state.
|
|
751
|
+
*
|
|
752
|
+
* @param state - The state value
|
|
753
|
+
* @returns The state name, or "UNKNOWN" for invalid states
|
|
754
|
+
*
|
|
755
|
+
* @example
|
|
756
|
+
* ```typescript
|
|
757
|
+
* console.log(`State: ${getStateName(record.state)}`); // "State: SYNCED"
|
|
758
|
+
* ```
|
|
759
|
+
*/
|
|
760
|
+
declare function getStateName(state: number): string;
|
|
761
|
+
/**
|
|
762
|
+
* Statistics about a batch migration.
|
|
763
|
+
*/
|
|
764
|
+
interface MigrationStats {
|
|
765
|
+
/** Total records processed */
|
|
766
|
+
total: number;
|
|
767
|
+
/** Records successfully migrated */
|
|
768
|
+
migrated: number;
|
|
769
|
+
/** Records with invalid states (used fallback) */
|
|
770
|
+
invalid: number;
|
|
771
|
+
/** Breakdown by state */
|
|
772
|
+
byState: Map<number, number>;
|
|
397
773
|
}
|
|
774
|
+
/**
|
|
775
|
+
* Creates empty migration stats.
|
|
776
|
+
*/
|
|
777
|
+
declare function createMigrationStats(): MigrationStats;
|
|
778
|
+
/**
|
|
779
|
+
* Records a migration result in the stats.
|
|
780
|
+
*
|
|
781
|
+
* @param stats - The stats object to update
|
|
782
|
+
* @param oldState - The original state
|
|
783
|
+
* @param newState - The migrated state
|
|
784
|
+
* @param wasValid - Whether the original state was valid
|
|
785
|
+
*/
|
|
786
|
+
declare function recordMigration(stats: MigrationStats, oldState: number, newState: number, wasValid: boolean): void;
|
|
787
|
+
/**
|
|
788
|
+
* Formats migration stats as a human-readable summary.
|
|
789
|
+
*
|
|
790
|
+
* @param stats - The stats to format
|
|
791
|
+
* @returns A formatted string summary
|
|
792
|
+
*
|
|
793
|
+
* @example
|
|
794
|
+
* ```typescript
|
|
795
|
+
* const stats = createMigrationStats();
|
|
796
|
+
* // ... process records ...
|
|
797
|
+
* console.log(formatMigrationStats(stats));
|
|
798
|
+
* // Output:
|
|
799
|
+
* // Migration Summary:
|
|
800
|
+
* // Total: 100
|
|
801
|
+
* // Migrated: 98
|
|
802
|
+
* // Invalid (used fallback): 2
|
|
803
|
+
* // By State:
|
|
804
|
+
* // SYNCED: 50
|
|
805
|
+
* // QUEUED_DOWNLOAD: 30
|
|
806
|
+
* // QUEUED_UPLOAD: 18
|
|
807
|
+
* // QUEUED_SYNC: 2
|
|
808
|
+
* ```
|
|
809
|
+
*/
|
|
810
|
+
declare function formatMigrationStats(stats: MigrationStats): string;
|
|
398
811
|
|
|
399
|
-
export {
|
|
812
|
+
export { AttachmentStorageAdapter, CacheConfig, type CacheManagerDeps, DOWNLOAD_WORKFLOW_STATES, type DownloadManagerDeps, LOCALLY_AVAILABLE_STATES, type MigrationStats, PENDING_DOWNLOAD_STATES, PROTECTED_UPLOAD_STATES, PolAttachmentRecord, PolStorageAdapter, type PolStorageAdapterOptions, STATE_MAPPING, STATE_NAMES, TERMINAL_STATES, UPLOAD_WORKFLOW_STATES, UploadConfig, UploadHandler, type UploadManagerDeps, type UploadManagerState, UploadStatus, VALID_STATES, WatchConfig, blobToArrayBuffer, buildIdOnlyWatchQuery, buildRecordFetchQuery, buildWatchQuery, cacheLocalFile, clearCache, clearUploadCallback, copyToManagedCache, createCacheManagerDeps, createMigrationStats, createUploadManagerDeps, createUploadManagerState, determineAttachmentState, downloadRecord, enforceCacheLimit, ensureFileUri, extractErrorCode, formatMigrationStats, getCachedSize, getEvictionCandidates, getExcludeProtectedStatesCondition, getFailedPermanentUploads, getLocalUriForStoragePath, getPendingUploads, getProtectedStatesInClause, getSoonestRetryTime, getStaleUploads, getStateName, getSyncedUploadsWithPendingCallback, isCacheNearCapacity, isDownloadWorkflowState, isLocallyAvailable, isPendingDownloadState, isPermanentError, isProtectedUploadState, isStateTransitionAllowed, isTerminalState, isUploadWorkflowState, isValidAttachmentState, markUploadPermanentFailure, markUploadSynced, migrateAttachmentState, migrateAttachmentStateSafe, recordMigration, scheduleUploadRetry, startUploadProcessing, stripFileUri, uploadOne, validateSqlIdentifier, validateSqlIdentifier$1 as validateSqlIdentifierFromStateMachine, validateWhereClause, watchConfigToSourceConfig };
|