@docstack/pouchdb-adapter-googledrive 0.0.8 → 0.0.9

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 (168) hide show
  1. package/compaction_test.log +725 -0
  2. package/docs/DEBUG_BIDIRECTIONAL_REPLICATION.ipynb +481 -0
  3. package/docs/DOCUMENTATION.md +115 -0
  4. package/docs/PROMISE_SUPPORT.md +75 -0
  5. package/docs/REPLICATION_ISSUE.md +63 -0
  6. package/emulation-test.log +163 -0
  7. package/failing_test.log +31 -0
  8. package/final_test.log +2620 -0
  9. package/lib/adapter.d.ts +20 -0
  10. package/lib/adapter.js +650 -0
  11. package/lib/cache.d.ts +12 -0
  12. package/lib/cache.js +42 -0
  13. package/lib/client.d.ts +37 -0
  14. package/lib/client.js +189 -0
  15. package/lib/drive.d.ts +82 -0
  16. package/lib/drive.js +737 -0
  17. package/lib/index.d.ts +10 -0
  18. package/lib/index.js +56 -0
  19. package/lib/types.d.ts +92 -0
  20. package/lib/types.js +2 -0
  21. package/live_test.log +1209 -0
  22. package/package.json +1 -1
  23. package/test_output.log +563 -0
  24. package/test_output_2.log +1408 -0
  25. package/test_output_3.log +2445 -0
  26. package/.test-drive-integration/1xssnxhy3akj +0 -1
  27. package/.test-drive-integration/8p8eymf8afm +0 -1
  28. package/.test-drive-integration/d1a4udbbuh +0 -1
  29. package/.test-drive-integration/usx93j46xtl +0 -1
  30. package/.test-drive-integration/vc0pq3g8vp +0 -1
  31. package/.test-drive-integration/zenra4v6i +0 -1
  32. package/.test-drive-root/05wzn5mtlrzt +0 -1
  33. package/.test-drive-root/0axnnh1gmn2d +0 -1
  34. package/.test-drive-root/0l2pw73vk4i +0 -1
  35. package/.test-drive-root/0tzush8sunaj +0 -1
  36. package/.test-drive-root/143bh2d29rnl +0 -1
  37. package/.test-drive-root/1synnvu59il +0 -1
  38. package/.test-drive-root/239cd47eh23i +0 -1
  39. package/.test-drive-root/275ocoaj6nq +0 -1
  40. package/.test-drive-root/29d78af16s4 +0 -1
  41. package/.test-drive-root/2gzvpzclnwu +0 -1
  42. package/.test-drive-root/2pmk0leotvp +0 -1
  43. package/.test-drive-root/38ijn3s7p33 +0 -1
  44. package/.test-drive-root/3jm64la13rp +0 -1
  45. package/.test-drive-root/3l4zrzi5bm2 +0 -1
  46. package/.test-drive-root/3of67xqpsfh +0 -1
  47. package/.test-drive-root/3pi1rk70we5 +0 -1
  48. package/.test-drive-root/3w3n7tpdn4n +0 -1
  49. package/.test-drive-root/3xg31irodim +0 -1
  50. package/.test-drive-root/50asm455hsa +0 -1
  51. package/.test-drive-root/51ldbder4dm +0 -1
  52. package/.test-drive-root/5l7dt9r491r +0 -1
  53. package/.test-drive-root/65mfhb9yuq5 +0 -1
  54. package/.test-drive-root/6iocm2rs118 +0 -1
  55. package/.test-drive-root/6o6vlpa6r6j +0 -1
  56. package/.test-drive-root/6rrcl4sdhoi +0 -1
  57. package/.test-drive-root/6ucq10yu9bx +0 -1
  58. package/.test-drive-root/7de4gtsch5b +0 -1
  59. package/.test-drive-root/7j4j3eq54q +0 -1
  60. package/.test-drive-root/7n3ai8wgsvy +0 -1
  61. package/.test-drive-root/7v4b3eyitw3 +0 -1
  62. package/.test-drive-root/8e15eu4xksq +0 -1
  63. package/.test-drive-root/8pu2c63yh1j +0 -1
  64. package/.test-drive-root/8ryxg058q8g +0 -1
  65. package/.test-drive-root/99l00ber08g +0 -1
  66. package/.test-drive-root/9gxcumnvepb +0 -1
  67. package/.test-drive-root/a4xxhwpe2cp +0 -1
  68. package/.test-drive-root/a57knn0ufon +0 -1
  69. package/.test-drive-root/a7gszl8y5ir +0 -1
  70. package/.test-drive-root/b0nddw4fdbu +0 -1
  71. package/.test-drive-root/b3b1d1yuolh +0 -1
  72. package/.test-drive-root/b4syq7nig1f +0 -1
  73. package/.test-drive-root/bcc8mhlffkg +0 -1
  74. package/.test-drive-root/bmngbpsk34 +0 -1
  75. package/.test-drive-root/c9i4hvcll2s +0 -1
  76. package/.test-drive-root/cao688yanw +0 -1
  77. package/.test-drive-root/cdtduwukrek +0 -1
  78. package/.test-drive-root/ckzeli8w7ej +0 -1
  79. package/.test-drive-root/ctywezu2fi5 +0 -1
  80. package/.test-drive-root/cyxiv5vgtle +0 -1
  81. package/.test-drive-root/d83g0suoz08 +0 -1
  82. package/.test-drive-root/d9tefhps5m6 +0 -1
  83. package/.test-drive-root/dac156l068 +0 -1
  84. package/.test-drive-root/daqsvyj5cu9 +0 -1
  85. package/.test-drive-root/df0wbnhhz1 +0 -1
  86. package/.test-drive-root/difkbp1duv +0 -1
  87. package/.test-drive-root/djrry1wk98v +0 -1
  88. package/.test-drive-root/dx42jrz7ty9 +0 -1
  89. package/.test-drive-root/e0s76kp3ena +0 -1
  90. package/.test-drive-root/e9xvdv0mqig +0 -1
  91. package/.test-drive-root/f3xo9hy1956 +0 -1
  92. package/.test-drive-root/f4scgrpgejw +0 -1
  93. package/.test-drive-root/f9kbt63p7xp +0 -1
  94. package/.test-drive-root/fe07yvs6p14 +0 -1
  95. package/.test-drive-root/ff5suiec8xv +0 -1
  96. package/.test-drive-root/fwc1qm37as +0 -1
  97. package/.test-drive-root/gh39v4lzxjp +0 -1
  98. package/.test-drive-root/gxvkr1qq21b +0 -1
  99. package/.test-drive-root/h4p64z7djk5 +0 -1
  100. package/.test-drive-root/habe7525tnl +0 -1
  101. package/.test-drive-root/hhzddxj31ar +0 -1
  102. package/.test-drive-root/hyj9crn9sb +0 -1
  103. package/.test-drive-root/igey5y5f3mi +0 -1
  104. package/.test-drive-root/isvxwzkgym +0 -1
  105. package/.test-drive-root/javyqnt07ws +0 -1
  106. package/.test-drive-root/jevlhmyaczl +0 -1
  107. package/.test-drive-root/jve7ypin7bb +0 -1
  108. package/.test-drive-root/koycie6jmyr +0 -1
  109. package/.test-drive-root/kvlad8ps1l +0 -1
  110. package/.test-drive-root/l13wzs51qi +0 -1
  111. package/.test-drive-root/lbwwk07et6i +0 -1
  112. package/.test-drive-root/m3uoxcsft2g +0 -1
  113. package/.test-drive-root/m7l8z61tnei +0 -1
  114. package/.test-drive-root/mmwpyz6aa2e +0 -1
  115. package/.test-drive-root/mqbyniatwu +0 -1
  116. package/.test-drive-root/mz3jbwwr12 +0 -1
  117. package/.test-drive-root/mza04oxze7 +0 -1
  118. package/.test-drive-root/ndqlafk0c0c +0 -1
  119. package/.test-drive-root/noojz8gst2 +0 -1
  120. package/.test-drive-root/o8ujk9otq7 +0 -1
  121. package/.test-drive-root/oa54zbip13m +0 -1
  122. package/.test-drive-root/ore7c15j64a +0 -1
  123. package/.test-drive-root/oxj3tt9q16 +0 -1
  124. package/.test-drive-root/pac4f4x1r9 +0 -1
  125. package/.test-drive-root/pqawj7k06i +0 -1
  126. package/.test-drive-root/qujzt0hpj6i +0 -1
  127. package/.test-drive-root/r5sdb4w0d3 +0 -1
  128. package/.test-drive-root/r8pybcnme1r +0 -1
  129. package/.test-drive-root/rpht4r0nk9 +0 -1
  130. package/.test-drive-root/rru3wcrfved +0 -1
  131. package/.test-drive-root/rtq2tifpvgt +0 -1
  132. package/.test-drive-root/ru00ubalaar +0 -1
  133. package/.test-drive-root/rx65wqybqlm +0 -1
  134. package/.test-drive-root/s585nksqc5 +0 -1
  135. package/.test-drive-root/scvyemdb9gh +0 -1
  136. package/.test-drive-root/si2b3ac0lve +0 -1
  137. package/.test-drive-root/sjbanmc5v5k +0 -1
  138. package/.test-drive-root/sl2coirs8zo +0 -1
  139. package/.test-drive-root/so3w2nrxm7 +0 -1
  140. package/.test-drive-root/t3y2vj69hz9 +0 -1
  141. package/.test-drive-root/t95zgk2fl8f +0 -1
  142. package/.test-drive-root/t9f08z6ayj +0 -1
  143. package/.test-drive-root/ta501uh71xi +0 -1
  144. package/.test-drive-root/taqhm9suyu +0 -1
  145. package/.test-drive-root/tya2ijynx5k +0 -1
  146. package/.test-drive-root/u4llyu4o7en +0 -1
  147. package/.test-drive-root/u5wco26a6lb +0 -1
  148. package/.test-drive-root/u6sricrto +0 -1
  149. package/.test-drive-root/ukcmmzglxa +0 -1
  150. package/.test-drive-root/uvsiktw52p +0 -1
  151. package/.test-drive-root/uylv1bn9swb +0 -1
  152. package/.test-drive-root/uzkzgxo3k5b +0 -1
  153. package/.test-drive-root/vf68w1pfrv +0 -1
  154. package/.test-drive-root/vp4g881bu7 +0 -1
  155. package/.test-drive-root/vuv8aavujb +0 -1
  156. package/.test-drive-root/wg24h3o6df +0 -1
  157. package/.test-drive-root/wyi5oftc8nh +0 -1
  158. package/.test-drive-root/x5zl3x2eh +0 -1
  159. package/.test-drive-root/xb3bpq9xtk +0 -1
  160. package/.test-drive-root/xfn089pthf9 +0 -1
  161. package/.test-drive-root/xrs7jul0mdl +0 -1
  162. package/.test-drive-root/y5qtilrbuzq +0 -1
  163. package/.test-drive-root/ysxlnyjuav +0 -1
  164. package/.test-drive-root/z2loakinuyk +0 -1
  165. package/.test-drive-root/z6lxmw8opjo +0 -1
  166. package/.test-drive-root/z74cnyignf9 +0 -1
  167. package/.test-drive-root/zi9agjhrfw +0 -1
  168. package/.test-drive-root/zspmm1wmo5l +0 -1
package/lib/cache.js ADDED
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LRUCache = void 0;
4
+ /**
5
+ * Simple Least Recently Used (LRU) Cache
6
+ */
7
+ class LRUCache {
8
+ constructor(capacity) {
9
+ this.capacity = capacity;
10
+ this.map = new Map();
11
+ }
12
+ get(key) {
13
+ const value = this.map.get(key);
14
+ if (value !== undefined) {
15
+ // Refresh: delete and re-add to end (most contiguous)
16
+ this.map.delete(key);
17
+ this.map.set(key, value);
18
+ }
19
+ return value;
20
+ }
21
+ put(key, value) {
22
+ if (this.map.has(key)) {
23
+ // Update existing
24
+ this.map.delete(key);
25
+ }
26
+ else if (this.map.size >= this.capacity) {
27
+ // Evict least recently used (first item)
28
+ const firstKey = this.map.keys().next().value;
29
+ if (firstKey !== undefined) {
30
+ this.map.delete(firstKey);
31
+ }
32
+ }
33
+ this.map.set(key, value);
34
+ }
35
+ remove(key) {
36
+ this.map.delete(key);
37
+ }
38
+ clear() {
39
+ this.map.clear();
40
+ }
41
+ }
42
+ exports.LRUCache = LRUCache;
@@ -0,0 +1,37 @@
1
+ export interface DriveFile {
2
+ id: string;
3
+ name: string;
4
+ mimeType: string;
5
+ parents?: string[];
6
+ etag?: string;
7
+ modifiedTime?: string;
8
+ }
9
+ export interface DriveClientOptions {
10
+ accessToken: string | (() => Promise<string>);
11
+ baseUrl?: string;
12
+ uploadUrl?: string;
13
+ }
14
+ export declare class GoogleDriveClient {
15
+ private options;
16
+ constructor(options: DriveClientOptions);
17
+ private getToken;
18
+ private fetch;
19
+ private get baseUrl();
20
+ private get uploadUrl();
21
+ listFiles(q: string): Promise<DriveFile[]>;
22
+ getFile(fileId: string): Promise<any>;
23
+ getFileMetadata(fileId: string): Promise<DriveFile>;
24
+ createFile(name: string, parents: string[] | undefined, mimeType: string, content: string): Promise<{
25
+ id: string;
26
+ etag: string;
27
+ modifiedTime: string;
28
+ }>;
29
+ updateFile(fileId: string, content: string, expectedEtag?: string): Promise<{
30
+ id: string;
31
+ etag: string;
32
+ modifiedTime: string;
33
+ }>;
34
+ private extractEtag;
35
+ deleteFile(fileId: string): Promise<void>;
36
+ private buildMultipart;
37
+ }
package/lib/client.js ADDED
@@ -0,0 +1,189 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GoogleDriveClient = void 0;
4
+ const DEFAULT_BASE_URL = 'https://www.googleapis.com/drive/v3/files';
5
+ const DEFAULT_UPLOAD_URL = 'https://www.googleapis.com/upload/drive/v3/files';
6
+ class GoogleDriveClient {
7
+ constructor(options) {
8
+ this.options = options;
9
+ }
10
+ async getToken() {
11
+ if (typeof this.options.accessToken === 'function') {
12
+ return await this.options.accessToken();
13
+ }
14
+ return this.options.accessToken;
15
+ }
16
+ async fetch(url, init) {
17
+ const method = init.method || 'GET';
18
+ const token = await this.getToken();
19
+ const validHeaders = {
20
+ 'Authorization': `Bearer ${token}`
21
+ };
22
+ if (init.headers) {
23
+ // manual merge if needed, or just iterate
24
+ new Headers(init.headers).forEach((v, k) => validHeaders[k] = v);
25
+ }
26
+ let res;
27
+ try {
28
+ res = await fetch(url, { ...init, headers: validHeaders });
29
+ }
30
+ catch (networkErr) {
31
+ const err = new Error(`Network Error: ${networkErr.message} (${method} ${url})`);
32
+ err.code = 'network_error';
33
+ err.url = url;
34
+ err.method = method;
35
+ throw err;
36
+ }
37
+ if (!res.ok) {
38
+ const text = await res.text();
39
+ let errorMsg = `Drive API Error: ${res.status} ${res.statusText} (${method} ${url})`;
40
+ let reason = res.statusText;
41
+ try {
42
+ const json = JSON.parse(text);
43
+ const gError = json.error;
44
+ if (gError) {
45
+ errorMsg += ` - ${gError.message || 'Unknown Error'}`;
46
+ if (Array.isArray(gError.errors) && gError.errors.length > 0) {
47
+ reason = gError.errors[0].reason || reason;
48
+ if (gError.errors[0].message && gError.errors[0].message !== gError.message) {
49
+ errorMsg += ` (${gError.errors[0].message})`;
50
+ }
51
+ }
52
+ }
53
+ }
54
+ catch { }
55
+ const err = new Error(errorMsg);
56
+ err.status = res.status;
57
+ err.code = reason;
58
+ err.url = url;
59
+ err.method = method;
60
+ throw err;
61
+ }
62
+ return res;
63
+ }
64
+ get baseUrl() {
65
+ return this.options.baseUrl || DEFAULT_BASE_URL;
66
+ }
67
+ get uploadUrl() {
68
+ return this.options.uploadUrl || DEFAULT_UPLOAD_URL;
69
+ }
70
+ async listFiles(q) {
71
+ const params = new URLSearchParams({
72
+ q,
73
+ fields: 'files(id,name,mimeType,parents,modifiedTime)'
74
+ });
75
+ // FIX: URLSearchParams uses '+', but Drive API is safer with '%20'
76
+ const queryString = params.toString().replace(/\+/g, '%20');
77
+ console.log(`[GoogleDriveClient] listFiles query: ${queryString}`);
78
+ const res = await this.fetch(`${this.baseUrl}?${queryString}`, { method: 'GET' });
79
+ const data = await res.json();
80
+ return data.files || [];
81
+ }
82
+ async getFile(fileId) {
83
+ // Try getting media
84
+ try {
85
+ const params = new URLSearchParams({ alt: 'media' });
86
+ const queryString = params.toString().replace(/\+/g, '%20');
87
+ const res = await this.fetch(`${this.baseUrl}/${fileId}?${queryString}`, { method: 'GET' });
88
+ // Standard fetch handles JSON/Text transparency?
89
+ // We expect JSON mostly, but sometimes we might want text.
90
+ // PouchDB adapter flow: downloadJson, downloadNdjson
91
+ // Let's rely on content-type or caller expectation?
92
+ // The usage in `drive.ts` expects parsed JSON/NDJSON lines.
93
+ // Let's return the raw Text or JSON based on Content-Type?
94
+ const contentType = res.headers.get('content-type');
95
+ if (contentType && contentType.includes('application/json')) {
96
+ return await res.json();
97
+ }
98
+ return await res.text();
99
+ }
100
+ catch (e) {
101
+ throw e;
102
+ }
103
+ }
104
+ // Single metadata get (for etag check)
105
+ async getFileMetadata(fileId) {
106
+ const params = new URLSearchParams({ fields: 'id,name,mimeType,parents,modifiedTime' });
107
+ const queryString = params.toString().replace(/\+/g, '%20');
108
+ const res = await this.fetch(`${this.baseUrl}/${fileId}?${queryString}`, { method: 'GET' });
109
+ const data = await res.json();
110
+ return {
111
+ ...data,
112
+ etag: this.extractEtag(res, data)
113
+ };
114
+ }
115
+ async createFile(name, parents, mimeType, content) {
116
+ const metadata = {
117
+ name,
118
+ mimeType,
119
+ parents
120
+ };
121
+ // Folders or empty content can use simple metadata-only POST
122
+ if (!content && mimeType === 'application/vnd.google-apps.folder') {
123
+ const res = await this.fetch(`${this.baseUrl}?fields=id,modifiedTime`, {
124
+ method: 'POST',
125
+ headers: { 'Content-Type': 'application/json' },
126
+ body: JSON.stringify(metadata)
127
+ });
128
+ const data = await res.json();
129
+ return {
130
+ id: data.id,
131
+ etag: this.extractEtag(res, data),
132
+ modifiedTime: data.modifiedTime || res.headers.get('Last-Modified') || ''
133
+ };
134
+ }
135
+ const multipartBody = this.buildMultipart(metadata, content, mimeType);
136
+ const res = await this.fetch(`${this.uploadUrl}?uploadType=multipart&fields=id,modifiedTime`, {
137
+ method: 'POST',
138
+ headers: {
139
+ 'Content-Type': `multipart/related; boundary=${multipartBody.boundary}`
140
+ },
141
+ body: multipartBody.body
142
+ });
143
+ const data = await res.json();
144
+ return {
145
+ id: data.id,
146
+ etag: this.extractEtag(res, data),
147
+ modifiedTime: data.modifiedTime || res.headers.get('Last-Modified') || ''
148
+ };
149
+ }
150
+ async updateFile(fileId, content, expectedEtag) {
151
+ // Update content (media) usually, but sometimes meta?
152
+ // In our usage (saveMeta), we update body.
153
+ const res = await this.fetch(`${this.uploadUrl}/${fileId}?uploadType=media&fields=id,modifiedTime`, {
154
+ method: 'PATCH',
155
+ headers: expectedEtag ? { 'If-Match': `"${expectedEtag}"`, 'Content-Type': 'application/json' } : { 'Content-Type': 'application/json' },
156
+ body: content
157
+ });
158
+ const data = await res.json();
159
+ return {
160
+ id: data.id,
161
+ etag: this.extractEtag(res, data),
162
+ modifiedTime: data.modifiedTime || res.headers.get('Last-Modified') || ''
163
+ };
164
+ }
165
+ extractEtag(res, data) {
166
+ const headerEtag = res.headers.get('ETag');
167
+ if (headerEtag) {
168
+ return headerEtag.replace(/"/g, '');
169
+ }
170
+ return data.etag || '';
171
+ }
172
+ async deleteFile(fileId) {
173
+ await this.fetch(`${this.baseUrl}/${fileId}`, { method: 'DELETE' });
174
+ }
175
+ buildMultipart(metadata, content, contentType) {
176
+ const boundary = '-------' + Math.random().toString(36).substring(2);
177
+ const delimiter = `\r\n--${boundary}\r\n`;
178
+ const closeDelimiter = `\r\n--${boundary}--`;
179
+ const body = delimiter +
180
+ 'Content-Type: application/json\r\n\r\n' +
181
+ JSON.stringify(metadata) +
182
+ delimiter +
183
+ `Content-Type: ${contentType}\r\n\r\n` +
184
+ content +
185
+ closeDelimiter;
186
+ return { body, boundary };
187
+ }
188
+ }
189
+ exports.GoogleDriveClient = GoogleDriveClient;
package/lib/drive.d.ts ADDED
@@ -0,0 +1,82 @@
1
+ import { GoogleDriveAdapterOptions, ChangeEntry, IndexEntry } from './types';
2
+ /**
3
+ * DriveHandler - Lazy Loading Implementation
4
+ *
5
+ * Storage structure:
6
+ * /db-folder/
7
+ * ├── _meta.json
8
+ * ├── snapshot-index.json # Map<DocId, IndexEntry>
9
+ * ├── snapshot-data.json # Map<DocId, DocBody>
10
+ * └── changes-*.ndjson # Append logs
11
+ */
12
+ export declare class DriveHandler {
13
+ private client;
14
+ private options;
15
+ private folderId;
16
+ private folderName;
17
+ private parents;
18
+ private compactionThreshold;
19
+ private compactionSizeThreshold;
20
+ private meta;
21
+ private metaEtag;
22
+ private metaModifiedTime;
23
+ private index;
24
+ private docCache;
25
+ private pendingChanges;
26
+ private currentLogSizeEstimate;
27
+ private listeners;
28
+ private pollingInterval;
29
+ private loadingPromise;
30
+ private isPollingActive;
31
+ private fileCache;
32
+ private processedLogIds;
33
+ private currentSnapshotIndexId;
34
+ private debug;
35
+ private isCompacting;
36
+ private log;
37
+ constructor(options: GoogleDriveAdapterOptions, dbName: string);
38
+ get seq(): number;
39
+ /** Load the database (Index Only) */
40
+ load(): Promise<void>;
41
+ private filesFromLegacySnapshot;
42
+ /**
43
+ * Get a document body.
44
+ * Index -> Cache -> Fetch
45
+ */
46
+ get(id: string): Promise<any | null>;
47
+ /** Generic Download with Caching and Parsing */
48
+ private fetchFile;
49
+ /** Get multiple docs (Atomic-ish) used for _allDocs */
50
+ getMulti(ids: string[]): Promise<any[]>;
51
+ /** Return all keys in Index */
52
+ getIndexKeys(): Promise<string[]>;
53
+ /** Get metadata for a specific ID from Index */
54
+ getIndexEntry(id: string): IndexEntry | undefined;
55
+ /** Single change wrapper */
56
+ appendChange(change: ChangeEntry): Promise<void>;
57
+ /** Append changes with OCC */
58
+ appendChanges(changes: ChangeEntry[]): Promise<void>;
59
+ private tryAppendChanges;
60
+ /** Update Index with a new change */
61
+ private updateIndex;
62
+ private checkConflicts;
63
+ /** Compact: Create SnapshotIndex + SnapshotData */
64
+ compact(): Promise<void>;
65
+ private atomicUpdateMeta;
66
+ private findOrCreateFolder;
67
+ private findFile;
68
+ private downloadJson;
69
+ private downloadFileAny;
70
+ private downloadNdjson;
71
+ private writeChangeFile;
72
+ private saveMeta;
73
+ private countTotalChanges;
74
+ private cleanupOldFiles;
75
+ private startPolling;
76
+ private notifyListeners;
77
+ onChange(cb: (changes: Record<string, any>) => void): () => void;
78
+ stopPolling(): void;
79
+ private escapeQuery;
80
+ deleteFolder(): Promise<void>;
81
+ getNextSeq(): number;
82
+ }