@docstack/pouchdb-adapter-googledrive 0.0.5 → 0.0.8

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 (160) hide show
  1. package/.env.example +3 -0
  2. package/.test-drive-integration/1xssnxhy3akj +1 -0
  3. package/.test-drive-integration/8p8eymf8afm +1 -0
  4. package/.test-drive-integration/d1a4udbbuh +1 -0
  5. package/.test-drive-integration/usx93j46xtl +1 -0
  6. package/.test-drive-integration/vc0pq3g8vp +1 -0
  7. package/.test-drive-integration/zenra4v6i +1 -0
  8. package/.test-drive-root/05wzn5mtlrzt +1 -0
  9. package/.test-drive-root/0axnnh1gmn2d +1 -0
  10. package/.test-drive-root/0l2pw73vk4i +1 -0
  11. package/.test-drive-root/0tzush8sunaj +1 -0
  12. package/.test-drive-root/143bh2d29rnl +1 -0
  13. package/.test-drive-root/1synnvu59il +1 -0
  14. package/.test-drive-root/239cd47eh23i +1 -0
  15. package/.test-drive-root/275ocoaj6nq +1 -0
  16. package/.test-drive-root/29d78af16s4 +1 -0
  17. package/.test-drive-root/2gzvpzclnwu +1 -0
  18. package/.test-drive-root/2pmk0leotvp +1 -0
  19. package/.test-drive-root/38ijn3s7p33 +1 -0
  20. package/.test-drive-root/3jm64la13rp +1 -0
  21. package/.test-drive-root/3l4zrzi5bm2 +1 -0
  22. package/.test-drive-root/3of67xqpsfh +1 -0
  23. package/.test-drive-root/3pi1rk70we5 +1 -0
  24. package/.test-drive-root/3w3n7tpdn4n +1 -0
  25. package/.test-drive-root/3xg31irodim +1 -0
  26. package/.test-drive-root/50asm455hsa +1 -0
  27. package/.test-drive-root/51ldbder4dm +1 -0
  28. package/.test-drive-root/5l7dt9r491r +1 -0
  29. package/.test-drive-root/65mfhb9yuq5 +1 -0
  30. package/.test-drive-root/6iocm2rs118 +1 -0
  31. package/.test-drive-root/6o6vlpa6r6j +1 -0
  32. package/.test-drive-root/6rrcl4sdhoi +1 -0
  33. package/.test-drive-root/6ucq10yu9bx +1 -0
  34. package/.test-drive-root/7de4gtsch5b +1 -0
  35. package/.test-drive-root/7j4j3eq54q +1 -0
  36. package/.test-drive-root/7n3ai8wgsvy +1 -0
  37. package/.test-drive-root/7v4b3eyitw3 +1 -0
  38. package/.test-drive-root/8e15eu4xksq +1 -0
  39. package/.test-drive-root/8pu2c63yh1j +1 -0
  40. package/.test-drive-root/8ryxg058q8g +1 -0
  41. package/.test-drive-root/99l00ber08g +1 -0
  42. package/.test-drive-root/9gxcumnvepb +1 -0
  43. package/.test-drive-root/a4xxhwpe2cp +1 -0
  44. package/.test-drive-root/a57knn0ufon +1 -0
  45. package/.test-drive-root/a7gszl8y5ir +1 -0
  46. package/.test-drive-root/b0nddw4fdbu +1 -0
  47. package/.test-drive-root/b3b1d1yuolh +1 -0
  48. package/.test-drive-root/b4syq7nig1f +1 -0
  49. package/.test-drive-root/bcc8mhlffkg +1 -0
  50. package/.test-drive-root/bmngbpsk34 +1 -0
  51. package/.test-drive-root/c9i4hvcll2s +1 -0
  52. package/.test-drive-root/cao688yanw +1 -0
  53. package/.test-drive-root/cdtduwukrek +1 -0
  54. package/.test-drive-root/ckzeli8w7ej +1 -0
  55. package/.test-drive-root/ctywezu2fi5 +1 -0
  56. package/.test-drive-root/cyxiv5vgtle +1 -0
  57. package/.test-drive-root/d83g0suoz08 +1 -0
  58. package/.test-drive-root/d9tefhps5m6 +1 -0
  59. package/.test-drive-root/dac156l068 +1 -0
  60. package/.test-drive-root/daqsvyj5cu9 +1 -0
  61. package/.test-drive-root/df0wbnhhz1 +1 -0
  62. package/.test-drive-root/difkbp1duv +1 -0
  63. package/.test-drive-root/djrry1wk98v +1 -0
  64. package/.test-drive-root/dx42jrz7ty9 +1 -0
  65. package/.test-drive-root/e0s76kp3ena +1 -0
  66. package/.test-drive-root/e9xvdv0mqig +1 -0
  67. package/.test-drive-root/f3xo9hy1956 +1 -0
  68. package/.test-drive-root/f4scgrpgejw +1 -0
  69. package/.test-drive-root/f9kbt63p7xp +1 -0
  70. package/.test-drive-root/fe07yvs6p14 +1 -0
  71. package/.test-drive-root/ff5suiec8xv +1 -0
  72. package/.test-drive-root/fwc1qm37as +1 -0
  73. package/.test-drive-root/gh39v4lzxjp +1 -0
  74. package/.test-drive-root/gxvkr1qq21b +1 -0
  75. package/.test-drive-root/h4p64z7djk5 +1 -0
  76. package/.test-drive-root/habe7525tnl +1 -0
  77. package/.test-drive-root/hhzddxj31ar +1 -0
  78. package/.test-drive-root/hyj9crn9sb +1 -0
  79. package/.test-drive-root/igey5y5f3mi +1 -0
  80. package/.test-drive-root/isvxwzkgym +1 -0
  81. package/.test-drive-root/javyqnt07ws +1 -0
  82. package/.test-drive-root/jevlhmyaczl +1 -0
  83. package/.test-drive-root/jve7ypin7bb +1 -0
  84. package/.test-drive-root/koycie6jmyr +1 -0
  85. package/.test-drive-root/kvlad8ps1l +1 -0
  86. package/.test-drive-root/l13wzs51qi +1 -0
  87. package/.test-drive-root/lbwwk07et6i +1 -0
  88. package/.test-drive-root/m3uoxcsft2g +1 -0
  89. package/.test-drive-root/m7l8z61tnei +1 -0
  90. package/.test-drive-root/mmwpyz6aa2e +1 -0
  91. package/.test-drive-root/mqbyniatwu +1 -0
  92. package/.test-drive-root/mz3jbwwr12 +1 -0
  93. package/.test-drive-root/mza04oxze7 +1 -0
  94. package/.test-drive-root/ndqlafk0c0c +1 -0
  95. package/.test-drive-root/noojz8gst2 +1 -0
  96. package/.test-drive-root/o8ujk9otq7 +1 -0
  97. package/.test-drive-root/oa54zbip13m +1 -0
  98. package/.test-drive-root/ore7c15j64a +1 -0
  99. package/.test-drive-root/oxj3tt9q16 +1 -0
  100. package/.test-drive-root/pac4f4x1r9 +1 -0
  101. package/.test-drive-root/pqawj7k06i +1 -0
  102. package/.test-drive-root/qujzt0hpj6i +1 -0
  103. package/.test-drive-root/r5sdb4w0d3 +1 -0
  104. package/.test-drive-root/r8pybcnme1r +1 -0
  105. package/.test-drive-root/rpht4r0nk9 +1 -0
  106. package/.test-drive-root/rru3wcrfved +1 -0
  107. package/.test-drive-root/rtq2tifpvgt +1 -0
  108. package/.test-drive-root/ru00ubalaar +1 -0
  109. package/.test-drive-root/rx65wqybqlm +1 -0
  110. package/.test-drive-root/s585nksqc5 +1 -0
  111. package/.test-drive-root/scvyemdb9gh +1 -0
  112. package/.test-drive-root/si2b3ac0lve +1 -0
  113. package/.test-drive-root/sjbanmc5v5k +1 -0
  114. package/.test-drive-root/sl2coirs8zo +1 -0
  115. package/.test-drive-root/so3w2nrxm7 +1 -0
  116. package/.test-drive-root/t3y2vj69hz9 +1 -0
  117. package/.test-drive-root/t95zgk2fl8f +1 -0
  118. package/.test-drive-root/t9f08z6ayj +1 -0
  119. package/.test-drive-root/ta501uh71xi +1 -0
  120. package/.test-drive-root/taqhm9suyu +1 -0
  121. package/.test-drive-root/tya2ijynx5k +1 -0
  122. package/.test-drive-root/u4llyu4o7en +1 -0
  123. package/.test-drive-root/u5wco26a6lb +1 -0
  124. package/.test-drive-root/u6sricrto +1 -0
  125. package/.test-drive-root/ukcmmzglxa +1 -0
  126. package/.test-drive-root/uvsiktw52p +1 -0
  127. package/.test-drive-root/uylv1bn9swb +1 -0
  128. package/.test-drive-root/uzkzgxo3k5b +1 -0
  129. package/.test-drive-root/vf68w1pfrv +1 -0
  130. package/.test-drive-root/vp4g881bu7 +1 -0
  131. package/.test-drive-root/vuv8aavujb +1 -0
  132. package/.test-drive-root/wg24h3o6df +1 -0
  133. package/.test-drive-root/wyi5oftc8nh +1 -0
  134. package/.test-drive-root/x5zl3x2eh +1 -0
  135. package/.test-drive-root/xb3bpq9xtk +1 -0
  136. package/.test-drive-root/xfn089pthf9 +1 -0
  137. package/.test-drive-root/xrs7jul0mdl +1 -0
  138. package/.test-drive-root/y5qtilrbuzq +1 -0
  139. package/.test-drive-root/ysxlnyjuav +1 -0
  140. package/.test-drive-root/z2loakinuyk +1 -0
  141. package/.test-drive-root/z6lxmw8opjo +1 -0
  142. package/.test-drive-root/z74cnyignf9 +1 -0
  143. package/.test-drive-root/zi9agjhrfw +1 -0
  144. package/.test-drive-root/zspmm1wmo5l +1 -0
  145. package/README.md +72 -72
  146. package/jest.config.js +8 -8
  147. package/package.json +47 -40
  148. package/DOCUMENTATION.md +0 -54
  149. package/lib/adapter.d.ts +0 -17
  150. package/lib/adapter.js +0 -440
  151. package/lib/cache.d.ts +0 -12
  152. package/lib/cache.js +0 -42
  153. package/lib/client.d.ts +0 -29
  154. package/lib/client.js +0 -129
  155. package/lib/drive.d.ts +0 -71
  156. package/lib/drive.js +0 -545
  157. package/lib/index.d.ts +0 -10
  158. package/lib/index.js +0 -55
  159. package/lib/types.d.ts +0 -86
  160. package/lib/types.js +0 -2
package/lib/adapter.js DELETED
@@ -1,440 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.GoogleDriveAdapter = GoogleDriveAdapter;
4
- const drive_1 = require("./drive");
5
- /**
6
- * Schedule a function to run asynchronously.
7
- */
8
- function nextTick(fn) {
9
- queueMicrotask(fn);
10
- }
11
- /**
12
- * GoogleDriveAdapter - PouchDB adapter for Google Drive storage.
13
- * Updated for Lazy Loading (Async Access).
14
- */
15
- function GoogleDriveAdapter(PouchDB) {
16
- function GoogleDrivePouch(opts, callback) {
17
- const api = this;
18
- const name = opts.name;
19
- // Clone options to avoid mutation
20
- const adapterOpts = Object.assign({}, opts);
21
- // Internal state
22
- let instanceId;
23
- let db;
24
- // Initialize DriveHandler
25
- db = new drive_1.DriveHandler(adapterOpts, name);
26
- // After database is initialized
27
- function afterDBCreated() {
28
- instanceId = 'gdrive-' + name + '-' + Date.now().toString(36);
29
- nextTick(function () {
30
- callback(null, api);
31
- });
32
- }
33
- // Load data from Drive and initialize
34
- db.load().then(() => {
35
- afterDBCreated();
36
- }).catch((err) => {
37
- callback(err);
38
- });
39
- // ============ PouchDB Adapter API Methods ============
40
- api._remote = false;
41
- api.type = function () {
42
- return 'googledrive';
43
- };
44
- api._id = function (callback) {
45
- callback(null, instanceId);
46
- };
47
- // Info now must be async-ish (calculated from Index)
48
- api._info = function (callback) {
49
- const keys = db.getIndexKeys();
50
- const docCount = keys.length; // Approximate (doesn't account for deleted unless filtered)
51
- // Filter deleted for accurate count
52
- let alive = 0;
53
- for (const k of keys) {
54
- const entry = db.getIndexEntry(k);
55
- if (entry && !entry.deleted)
56
- alive++;
57
- }
58
- const res = {
59
- doc_count: alive,
60
- update_seq: db.seq,
61
- backend_adapter: 'googledrive'
62
- };
63
- nextTick(function () {
64
- callback(null, res);
65
- });
66
- };
67
- // Get a single document by ID (Async fetch)
68
- api._get = function (id, opts, callback) {
69
- if (typeof opts === 'function') {
70
- callback = opts;
71
- opts = {};
72
- }
73
- db.get(id).then(doc => {
74
- if (!doc) {
75
- return callback({
76
- status: 404,
77
- error: true,
78
- name: 'not_found',
79
- message: 'missing',
80
- reason: 'missing'
81
- });
82
- }
83
- const metadata = {
84
- id: doc._id,
85
- rev: doc._rev,
86
- winningRev: doc._rev,
87
- deleted: !!doc._deleted
88
- };
89
- callback(null, { doc, metadata });
90
- }).catch(err => {
91
- callback(err);
92
- });
93
- };
94
- // Get all documents (Lazy stream or fetch)
95
- api._allDocs = function (opts, callback) {
96
- if (typeof opts === 'function') {
97
- callback = opts;
98
- opts = {};
99
- }
100
- const keys = db.getIndexKeys();
101
- const total = keys.length; // Total keys (including deleted?)
102
- let startIndex = opts.skip || 0;
103
- let limit = typeof opts.limit === 'number' ? opts.limit : keys.length;
104
- let filteredKeys = keys;
105
- if (opts.startkey)
106
- filteredKeys = filteredKeys.filter(k => k >= opts.startkey);
107
- if (opts.endkey)
108
- filteredKeys = filteredKeys.filter(k => k <= opts.endkey);
109
- if (opts.key)
110
- filteredKeys = filteredKeys.filter(k => k === opts.key);
111
- if (opts.keys)
112
- filteredKeys = opts.keys;
113
- filteredKeys.sort();
114
- if (opts.descending)
115
- filteredKeys.reverse();
116
- const sliced = filteredKeys.slice(startIndex, startIndex + limit);
117
- // Fetch actual docs if needed
118
- if (opts.include_docs) {
119
- db.getMulti(sliced).then(docs => {
120
- const rows = sliced.map((id, i) => {
121
- const doc = docs[i];
122
- const entry = db.getIndexEntry(id);
123
- if (!doc && (!entry || entry.deleted))
124
- return { key: id, error: 'not_found' };
125
- if (!doc && entry) {
126
- // This implies fetch failed but exists in index? Or null result.
127
- return { key: id, error: 'not_found' };
128
- }
129
- const row = {
130
- id,
131
- key: id,
132
- value: { rev: entry?.rev || doc._rev }
133
- };
134
- row.doc = doc;
135
- return row;
136
- });
137
- const result = {
138
- total_rows: total,
139
- offset: startIndex,
140
- rows: rows.filter(r => !r.error || !opts.keys) // Filter errored unless specifically asked via keys?
141
- // CouchDB usually returns error row if distinct keys requested.
142
- };
143
- if (opts.update_seq)
144
- result.update_seq = db.seq;
145
- callback(null, result);
146
- }).catch(err => callback(err));
147
- }
148
- else {
149
- // Index only (Fast!)
150
- const rows = sliced.map(id => {
151
- const entry = db.getIndexEntry(id);
152
- if (!entry || entry.deleted)
153
- return { key: id, error: 'not_found' };
154
- return {
155
- id,
156
- key: id,
157
- value: { rev: entry.rev }
158
- };
159
- });
160
- const result = {
161
- total_rows: total,
162
- offset: startIndex,
163
- rows
164
- };
165
- if (opts.update_seq)
166
- result.update_seq = db.seq;
167
- nextTick(() => callback(null, result));
168
- }
169
- };
170
- // Bulk document operations
171
- api._bulkDocs = function (req, opts, callback) {
172
- const docs = req.docs;
173
- const results = [];
174
- const newEdits = opts.new_edits !== false;
175
- const changes = [];
176
- // We need to validate revisions against Index
177
- // This does NOT require fetching bodies usually
178
- for (const doc of docs) {
179
- const id = doc._id;
180
- const seq = db.getNextSeq() + changes.length;
181
- const entry = db.getIndexEntry(id);
182
- if (doc._deleted) {
183
- if (!entry || entry.deleted) {
184
- results.push({
185
- ok: false,
186
- id,
187
- error: 'not_found',
188
- reason: 'missing'
189
- });
190
- continue;
191
- }
192
- // Check rev
193
- const oldRev = entry.rev || '0-0'; // Index has latest
194
- // If mismatch? PouchDB handles conflict logic before calling us sometimes?
195
- // But we should verify.
196
- // If doc._rev matches entry.rev, we are good.
197
- const revNum = parseInt(oldRev.split('-')[0], 10) + 1;
198
- const newRev = revNum + '-' + generateRevId();
199
- changes.push({
200
- seq,
201
- id,
202
- rev: newRev,
203
- deleted: true,
204
- timestamp: Date.now()
205
- });
206
- results.push({ ok: true, id, rev: newRev });
207
- }
208
- else {
209
- let newRev;
210
- if (newEdits) {
211
- const oldRev = entry?.rev || '0-0';
212
- const revNum = parseInt(oldRev.split('-')[0], 10) + 1;
213
- newRev = revNum + '-' + generateRevId();
214
- }
215
- else {
216
- newRev = doc._rev;
217
- }
218
- const savedDoc = Object.assign({}, doc, { _rev: newRev });
219
- changes.push({
220
- seq,
221
- id,
222
- rev: newRev,
223
- doc: savedDoc,
224
- timestamp: Date.now()
225
- });
226
- results.push({ ok: true, id, rev: newRev });
227
- }
228
- }
229
- // Append changes to log
230
- db.appendChanges(changes).then(() => {
231
- nextTick(() => callback(null, results));
232
- }).catch((err) => {
233
- callback(err);
234
- });
235
- };
236
- // Changes feed
237
- api._changes = function (opts) {
238
- opts = Object.assign({}, opts);
239
- const since = opts.since || 0;
240
- const limit = typeof opts.limit === 'number' ? opts.limit : Infinity;
241
- const returnDocs = opts.return_docs !== false;
242
- const results = [];
243
- let lastSeq = since;
244
- let complete = false;
245
- // Should we iterate Index or Logs?
246
- // "Index" only has LATEST state. _changes usually wants history if `since` is old.
247
- // But this adapter is an "Index + Log" adapter.
248
- // If `since` is 0, we can walk the Index.
249
- // If `since` is recent, we can maybe walk pending changes?
250
- // Correct implementation of `_changes` with Append-Only Log requires reading the log files essentially.
251
- // BUT, standard PouchDB `_changes` often just iterates all docs if it can't stream.
252
- // For now, let's iterate the INDEX (Winning Revisions) which implies "since=0" behavior effectively (State of the World).
253
- function processChanges() {
254
- const keys = db.getIndexKeys(); // IDs
255
- let processed = 0;
256
- // Index-based iteration
257
- for (const id of keys) {
258
- if (complete || processed >= limit)
259
- break;
260
- const entry = db.getIndexEntry(id);
261
- if (!entry)
262
- continue;
263
- // Filter by seq?
264
- if (entry.seq <= since)
265
- continue; // Already seen
266
- const change = {
267
- id: id,
268
- seq: entry.seq,
269
- changes: [{ rev: entry.rev }],
270
- };
271
- if (opts.include_docs) {
272
- // We need to fetch it!
273
- // This makes _changes with include_docs SLOW.
274
- // We can't do this synchronously here easily because `processChanges` is sync in original code?
275
- // Wait, original was `nextTick(processChanges)`.
276
- // We need to be async here.
277
- }
278
- // Supporting async processChanges is cleaner.
279
- }
280
- // ... This requires rewrite for async iteration ...
281
- }
282
- // Simplified Async Version
283
- async function processChangesAsync() {
284
- const keys = db.getIndexKeys();
285
- let processed = 0;
286
- for (const id of keys) {
287
- if (complete || processed >= limit)
288
- break;
289
- const entry = db.getIndexEntry(id);
290
- if (!entry || entry.seq <= since)
291
- continue;
292
- const change = {
293
- id: id,
294
- seq: entry.seq,
295
- changes: [{ rev: entry.rev }]
296
- };
297
- if (opts.include_docs) {
298
- change.doc = await db.get(id);
299
- }
300
- if (opts.onChange)
301
- opts.onChange(change);
302
- if (returnDocs)
303
- results.push(change);
304
- processed++;
305
- lastSeq = Math.max(lastSeq, entry.seq);
306
- }
307
- if (opts.complete && !complete) {
308
- opts.complete(null, { results, last_seq: lastSeq });
309
- }
310
- }
311
- if (opts.live) {
312
- db.onChange((changes) => {
313
- // Update feed
314
- // ...
315
- });
316
- }
317
- nextTick(() => {
318
- processChangesAsync().catch(err => {
319
- console.error('Changes feed error', err);
320
- if (opts.complete)
321
- opts.complete(err);
322
- });
323
- });
324
- return {
325
- cancel() {
326
- complete = true;
327
- }
328
- };
329
- };
330
- // Manual compaction trigger
331
- api._compact = function (callback) {
332
- db.compact().then(() => {
333
- callback(null, { ok: true });
334
- }).catch((err) => {
335
- callback(err);
336
- });
337
- };
338
- api._getRevisionTree = function (docId, callback) {
339
- db.get(docId).then(doc => {
340
- if (!doc) {
341
- return callback({ status: 404, error: true, name: 'not_found', message: 'missing' });
342
- }
343
- const revTree = [{
344
- pos: 1,
345
- ids: [doc._rev.split('-')[1], { status: 'available' }, []]
346
- }];
347
- callback(null, revTree);
348
- }).catch(callback);
349
- };
350
- api._close = function (callback) {
351
- db.stopPolling();
352
- nextTick(callback);
353
- };
354
- api._destroy = function (opts, callback) {
355
- if (typeof opts === 'function') {
356
- callback = opts;
357
- opts = {};
358
- }
359
- db.stopPolling();
360
- if (opts.deleteFolder) {
361
- db.deleteFolder().then(() => {
362
- callback(null, { ok: true });
363
- }).catch((err) => {
364
- callback(err);
365
- });
366
- }
367
- else {
368
- nextTick(() => callback(null, { ok: true }));
369
- }
370
- };
371
- api._putLocal = function (doc, opts, callback) {
372
- if (typeof opts === 'function') {
373
- callback = opts;
374
- opts = {};
375
- }
376
- const id = doc._id;
377
- const rev = '0-1';
378
- const savedDoc = Object.assign({}, doc, { _rev: rev });
379
- const change = {
380
- seq: db.getNextSeq(),
381
- id,
382
- rev,
383
- doc: savedDoc,
384
- timestamp: Date.now()
385
- };
386
- db.appendChanges([change]).then(() => {
387
- callback(null, { ok: true, id, rev });
388
- }).catch((err) => {
389
- callback(err);
390
- });
391
- };
392
- api._getLocal = function (id, callback) {
393
- db.get(id).then(doc => {
394
- if (!doc)
395
- return callback({ status: 404, error: true, name: 'not_found' });
396
- callback(null, doc);
397
- }).catch(callback);
398
- };
399
- api._removeLocal = function (doc, opts, callback) {
400
- // ... Similar async update ...
401
- if (typeof opts === 'function') {
402
- callback = opts;
403
- opts = {};
404
- }
405
- const id = doc._id;
406
- // Check existence async if we want to be strict, but index check is ok
407
- if (!db.getIndexEntry(id)) {
408
- return callback({ status: 404, error: true, name: 'not_found' });
409
- }
410
- // ...
411
- // Simplified removeLocal
412
- const change = {
413
- seq: db.getNextSeq(),
414
- id,
415
- rev: '0-0',
416
- deleted: true,
417
- timestamp: Date.now()
418
- };
419
- db.appendChanges([change]).then(() => {
420
- callback(null, { ok: true, id, rev: '0-0' });
421
- }).catch((err) => {
422
- callback(err);
423
- });
424
- };
425
- }
426
- // Static properties
427
- GoogleDrivePouch.valid = function () {
428
- return true;
429
- };
430
- GoogleDrivePouch.use_prefix = false;
431
- return GoogleDrivePouch;
432
- }
433
- /**
434
- * Generate a random revision ID
435
- */
436
- function generateRevId() {
437
- return Math.random().toString(36).substring(2, 11) +
438
- Math.random().toString(36).substring(2, 11);
439
- }
440
- exports.default = GoogleDriveAdapter;
package/lib/cache.d.ts DELETED
@@ -1,12 +0,0 @@
1
- /**
2
- * Simple Least Recently Used (LRU) Cache
3
- */
4
- export declare class LRUCache<K, V> {
5
- private capacity;
6
- private map;
7
- constructor(capacity: number);
8
- get(key: K): V | undefined;
9
- put(key: K, value: V): void;
10
- remove(key: K): void;
11
- clear(): void;
12
- }
package/lib/cache.js DELETED
@@ -1,42 +0,0 @@
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;
package/lib/client.d.ts DELETED
@@ -1,29 +0,0 @@
1
- export interface DriveFile {
2
- id: string;
3
- name: string;
4
- mimeType: string;
5
- parents?: string[];
6
- etag?: string;
7
- }
8
- export interface DriveClientOptions {
9
- accessToken: string | (() => Promise<string>);
10
- }
11
- export declare class GoogleDriveClient {
12
- private options;
13
- constructor(options: DriveClientOptions);
14
- private getToken;
15
- private fetch;
16
- listFiles(q: string): Promise<DriveFile[]>;
17
- getFile(fileId: string): Promise<any>;
18
- getFileMetadata(fileId: string): Promise<DriveFile>;
19
- createFile(name: string, parents: string[] | undefined, mimeType: string, content: string): Promise<{
20
- id: string;
21
- etag: string;
22
- }>;
23
- updateFile(fileId: string, content: string, expectedEtag?: string): Promise<{
24
- id: string;
25
- etag: string;
26
- }>;
27
- deleteFile(fileId: string): Promise<void>;
28
- private buildMultipart;
29
- }
package/lib/client.js DELETED
@@ -1,129 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.GoogleDriveClient = void 0;
4
- const BASE_URL = 'https://www.googleapis.com/drive/v3/files';
5
- const 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 token = await this.getToken();
18
- const headers = new Headers(init.headers);
19
- headers.set('Authorization', `Bearer ${token}`);
20
- const res = await fetch(url, { ...init, headers });
21
- const method = init.method || 'GET';
22
- if (!res.ok) {
23
- // Basic error handling
24
- const text = await res.text();
25
- let errorMsg = `Drive API Error: ${res.status} ${res.statusText} (${method} ${url})`;
26
- try {
27
- const json = JSON.parse(text);
28
- if (json.error && json.error.message) {
29
- errorMsg += ` - ${json.error.message}`;
30
- }
31
- }
32
- catch { }
33
- const err = new Error(errorMsg);
34
- err.status = res.status;
35
- throw err;
36
- }
37
- return res;
38
- }
39
- async listFiles(q) {
40
- const params = new URLSearchParams({
41
- q,
42
- fields: 'files(id, name, mimeType, parents, etag)',
43
- spaces: 'drive',
44
- pageSize: '1000' // Ensure we get enough
45
- });
46
- const res = await this.fetch(`${BASE_URL}?${params.toString()}`, { method: 'GET' });
47
- const data = await res.json();
48
- return data.files || [];
49
- }
50
- async getFile(fileId) {
51
- // Try getting media
52
- try {
53
- const params = new URLSearchParams({ alt: 'media' });
54
- const res = await this.fetch(`${BASE_URL}/${fileId}?${params.toString()}`, { method: 'GET' });
55
- // Standard fetch handles JSON/Text transparency?
56
- // We expect JSON mostly, but sometimes we might want text.
57
- // PouchDB adapter flow: downloadJson, downloadNdjson
58
- // Let's rely on content-type or caller expectation?
59
- // The usage in `drive.ts` expects parsed JSON/NDJSON lines.
60
- // Let's return the raw Text or JSON based on Content-Type?
61
- const contentType = res.headers.get('content-type');
62
- if (contentType && contentType.includes('application/json')) {
63
- return await res.json();
64
- }
65
- return await res.text();
66
- }
67
- catch (e) {
68
- throw e;
69
- }
70
- }
71
- // Single metadata get (for etag check)
72
- async getFileMetadata(fileId) {
73
- const params = new URLSearchParams({ fields: 'id, name, mimeType, parents, etag' });
74
- const res = await this.fetch(`${BASE_URL}/${fileId}?${params.toString()}`, { method: 'GET' });
75
- return await res.json();
76
- }
77
- async createFile(name, parents, mimeType, content) {
78
- const metadata = {
79
- name,
80
- mimeType,
81
- parents
82
- };
83
- // Folders or empty content can use simple metadata-only POST
84
- if (!content && mimeType === 'application/vnd.google-apps.folder') {
85
- const res = await this.fetch(`${BASE_URL}?fields=id,etag`, {
86
- method: 'POST',
87
- headers: { 'Content-Type': 'application/json' },
88
- body: JSON.stringify(metadata)
89
- });
90
- return await res.json();
91
- }
92
- const multipartBody = this.buildMultipart(metadata, content, mimeType);
93
- const res = await this.fetch(`${UPLOAD_URL}?uploadType=multipart&fields=id,etag`, {
94
- method: 'POST',
95
- headers: {
96
- 'Content-Type': `multipart/related; boundary=${multipartBody.boundary}`
97
- },
98
- body: multipartBody.body
99
- });
100
- return await res.json();
101
- }
102
- async updateFile(fileId, content, expectedEtag) {
103
- // Update content (media) usually, but sometimes meta?
104
- // In our usage (saveMeta), we update body.
105
- const res = await this.fetch(`${UPLOAD_URL}/${fileId}?uploadType=media&fields=id,etag`, {
106
- method: 'PATCH',
107
- headers: expectedEtag ? { 'If-Match': expectedEtag, 'Content-Type': 'application/json' } : { 'Content-Type': 'application/json' },
108
- body: content
109
- });
110
- return await res.json();
111
- }
112
- async deleteFile(fileId) {
113
- await this.fetch(`${BASE_URL}/${fileId}`, { method: 'DELETE' });
114
- }
115
- buildMultipart(metadata, content, contentType) {
116
- const boundary = '-------' + Math.random().toString(36).substring(2);
117
- const delimiter = `\r\n--${boundary}\r\n`;
118
- const closeDelimiter = `\r\n--${boundary}--`;
119
- const body = delimiter +
120
- 'Content-Type: application/json\r\n\r\n' +
121
- JSON.stringify(metadata) +
122
- delimiter +
123
- `Content-Type: ${contentType}\r\n\r\n` +
124
- content +
125
- closeDelimiter;
126
- return { body, boundary };
127
- }
128
- }
129
- exports.GoogleDriveClient = GoogleDriveClient;