@docstack/pouchdb-adapter-googledrive 0.1.3 → 0.1.5
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/.env.example +0 -0
- package/README.md +0 -0
- package/lib/adapter.d.ts +0 -0
- package/lib/adapter.js +71 -66
- package/lib/cache.d.ts +0 -0
- package/lib/cache.js +0 -0
- package/lib/client.d.ts +0 -0
- package/lib/client.js +0 -0
- package/lib/drive.d.ts +0 -0
- package/lib/drive.js +32 -2
- package/lib/index.d.ts +0 -0
- package/lib/index.js +0 -0
- package/lib/types.d.ts +0 -0
- package/lib/types.js +0 -0
- package/package.json +4 -2
package/.env.example
CHANGED
|
File without changes
|
package/README.md
CHANGED
|
File without changes
|
package/lib/adapter.d.ts
CHANGED
|
File without changes
|
package/lib/adapter.js
CHANGED
|
@@ -193,74 +193,72 @@ function GoogleDriveAdapter(PouchDB) {
|
|
|
193
193
|
opts = {};
|
|
194
194
|
}
|
|
195
195
|
const promise = (async () => {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
if (opts.include_docs) {
|
|
215
|
-
const docs = await db.getMulti(sliced);
|
|
216
|
-
const rows = sliced.map((id, i) => {
|
|
217
|
-
const doc = docs[i];
|
|
218
|
-
const entry = db.getIndexEntry(id);
|
|
219
|
-
if (!doc && (!entry || entry.deleted))
|
|
220
|
-
return { key: id, error: 'not_found' };
|
|
221
|
-
if (!doc && entry) {
|
|
222
|
-
// This implies fetch failed but exists in index? Or null result.
|
|
223
|
-
return { key: id, error: 'not_found' };
|
|
224
|
-
}
|
|
225
|
-
const row = {
|
|
226
|
-
id,
|
|
227
|
-
key: id,
|
|
228
|
-
value: { rev: entry?.rev || doc._rev }
|
|
229
|
-
};
|
|
230
|
-
row.doc = doc;
|
|
231
|
-
return row;
|
|
232
|
-
});
|
|
233
|
-
const result = {
|
|
234
|
-
total_rows: total,
|
|
235
|
-
offset: startIndex,
|
|
236
|
-
rows: rows.filter(r => !r.error || !opts.keys) // Filter errored unless specifically asked via keys?
|
|
237
|
-
// CouchDB usually returns error row if distinct keys requested.
|
|
238
|
-
};
|
|
239
|
-
if (opts.update_seq)
|
|
240
|
-
result.update_seq = db.seq;
|
|
241
|
-
return result;
|
|
196
|
+
// _local/* docs live in a separate namespace and never appear in allDocs,
|
|
197
|
+
// same as CouchDB - they aren't part of the B-tree of regular documents.
|
|
198
|
+
const indexKeys = (await db.getIndexKeys()).filter(k => !k.startsWith('_local/'));
|
|
199
|
+
// total_rows reflects live (non-deleted) documents, matching db.info().doc_count -
|
|
200
|
+
// deleted entries stay in the index forever but were never meant to count here.
|
|
201
|
+
let total = 0;
|
|
202
|
+
for (const k of indexKeys) {
|
|
203
|
+
const entry = db.getIndexEntry(k);
|
|
204
|
+
if (entry && !entry.deleted)
|
|
205
|
+
total++;
|
|
206
|
+
}
|
|
207
|
+
const startIndex = opts.skip || 0;
|
|
208
|
+
let candidateKeys;
|
|
209
|
+
if (opts.keys) {
|
|
210
|
+
// Explicit keys: return exactly these, in the given order. Deleted docs are
|
|
211
|
+
// included here (flagged via value.deleted), not treated as errors - only
|
|
212
|
+
// keys absent from the index entirely are 'not_found'.
|
|
213
|
+
candidateKeys = opts.keys;
|
|
242
214
|
}
|
|
243
215
|
else {
|
|
244
|
-
//
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
return {
|
|
250
|
-
id,
|
|
251
|
-
key: id,
|
|
252
|
-
value: { rev: entry.rev }
|
|
253
|
-
};
|
|
216
|
+
// Default listing: deleted docs never appear, same as a real CouchDB/PouchDB
|
|
217
|
+
// allDocs() with no keys specified.
|
|
218
|
+
candidateKeys = indexKeys.filter(k => {
|
|
219
|
+
const entry = db.getIndexEntry(k);
|
|
220
|
+
return entry && !entry.deleted;
|
|
254
221
|
});
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
222
|
+
if (opts.startkey)
|
|
223
|
+
candidateKeys = candidateKeys.filter(k => k >= opts.startkey);
|
|
224
|
+
if (opts.endkey)
|
|
225
|
+
candidateKeys = candidateKeys.filter(k => k <= opts.endkey);
|
|
226
|
+
if (opts.key)
|
|
227
|
+
candidateKeys = candidateKeys.filter(k => k === opts.key);
|
|
228
|
+
candidateKeys.sort();
|
|
229
|
+
if (opts.descending)
|
|
230
|
+
candidateKeys.reverse();
|
|
263
231
|
}
|
|
232
|
+
const limit = typeof opts.limit === 'number' ? opts.limit : candidateKeys.length;
|
|
233
|
+
const sliced = opts.keys ? candidateKeys : candidateKeys.slice(startIndex, startIndex + limit);
|
|
234
|
+
const docs = opts.include_docs ? await db.getMulti(sliced) : null;
|
|
235
|
+
const rows = sliced.map((id, i) => {
|
|
236
|
+
const entry = db.getIndexEntry(id);
|
|
237
|
+
if (!entry)
|
|
238
|
+
return { key: id, error: 'not_found' };
|
|
239
|
+
if (entry.deleted) {
|
|
240
|
+
const row = { id, key: id, value: { rev: entry.rev, deleted: true } };
|
|
241
|
+
if (opts.include_docs)
|
|
242
|
+
row.doc = null;
|
|
243
|
+
return row;
|
|
244
|
+
}
|
|
245
|
+
const row = { id, key: id, value: { rev: entry.rev } };
|
|
246
|
+
if (opts.include_docs) {
|
|
247
|
+
const doc = docs[i];
|
|
248
|
+
if (!doc)
|
|
249
|
+
return { key: id, error: 'not_found' };
|
|
250
|
+
row.doc = doc;
|
|
251
|
+
}
|
|
252
|
+
return row;
|
|
253
|
+
});
|
|
254
|
+
const result = {
|
|
255
|
+
total_rows: total,
|
|
256
|
+
offset: startIndex,
|
|
257
|
+
rows
|
|
258
|
+
};
|
|
259
|
+
if (opts.update_seq)
|
|
260
|
+
result.update_seq = db.seq;
|
|
261
|
+
return result;
|
|
264
262
|
})();
|
|
265
263
|
if (callback) {
|
|
266
264
|
promise.then(res => callback(null, res)).catch(err => callback(err));
|
|
@@ -314,7 +312,10 @@ function GoogleDriveAdapter(PouchDB) {
|
|
|
314
312
|
api._bulkDocs = function (req, opts, callback) {
|
|
315
313
|
const docs = req.docs;
|
|
316
314
|
const results = [];
|
|
317
|
-
|
|
315
|
+
// new_edits lives on `req` (the CouchDB _bulk_docs request body shape), not `opts`.
|
|
316
|
+
// api.bulkDocs = api._bulkDocs below means callers reach this directly, bypassing
|
|
317
|
+
// AbstractPouchDB.prototype.bulkDocs's req->opts normalization - so read it from req.
|
|
318
|
+
const newEdits = req.new_edits !== false;
|
|
318
319
|
const changes = [];
|
|
319
320
|
// We need to validate revisions against Index
|
|
320
321
|
// This does NOT require fetching bodies usually
|
|
@@ -498,7 +499,11 @@ function GoogleDriveAdapter(PouchDB) {
|
|
|
498
499
|
};
|
|
499
500
|
};
|
|
500
501
|
// Manual compaction trigger
|
|
501
|
-
api._compact = function (callback) {
|
|
502
|
+
api._compact = function (opts, callback) {
|
|
503
|
+
if (typeof opts === 'function') {
|
|
504
|
+
callback = opts;
|
|
505
|
+
opts = {};
|
|
506
|
+
}
|
|
502
507
|
const promise = db.compact().then(() => {
|
|
503
508
|
const result = { ok: true };
|
|
504
509
|
if (callback)
|
package/lib/cache.d.ts
CHANGED
|
File without changes
|
package/lib/cache.js
CHANGED
|
File without changes
|
package/lib/client.d.ts
CHANGED
|
File without changes
|
package/lib/client.js
CHANGED
|
File without changes
|
package/lib/drive.d.ts
CHANGED
|
File without changes
|
package/lib/drive.js
CHANGED
|
@@ -287,6 +287,12 @@ class DriveHandler {
|
|
|
287
287
|
doc = content;
|
|
288
288
|
}
|
|
289
289
|
if (doc) {
|
|
290
|
+
// HEAL: Ensure PouchDB core validation doesn't fail due to history corruption
|
|
291
|
+
// This prevents the infinite replicator retry loop when start < ids.length
|
|
292
|
+
if (doc._revisions && doc._revisions.start < doc._revisions.ids.length) {
|
|
293
|
+
const start = doc._revisions.start || 1;
|
|
294
|
+
doc._revisions.ids = doc._revisions.ids.slice(0, start);
|
|
295
|
+
}
|
|
290
296
|
this.docCache.put(id, doc);
|
|
291
297
|
doc._rev = entry.rev;
|
|
292
298
|
}
|
|
@@ -622,6 +628,27 @@ class DriveHandler {
|
|
|
622
628
|
const snapshotSeq = this.meta.seq;
|
|
623
629
|
const oldLogIds = [...this.meta.changeLogIds];
|
|
624
630
|
const oldIndexId = this.meta.snapshotIndexId;
|
|
631
|
+
// Resolve which snapshot-data file(s) the OLD index points to, so we can
|
|
632
|
+
// delete them too once the new snapshot is safely in place. Without this,
|
|
633
|
+
// every compaction leaves its predecessor's data file behind as orphaned
|
|
634
|
+
// clutter (the index gets cleaned up, but the (often much larger) data
|
|
635
|
+
// file it pointed to never does).
|
|
636
|
+
let oldDataFileIds = [];
|
|
637
|
+
if (oldIndexId) {
|
|
638
|
+
try {
|
|
639
|
+
const oldIndex = await this.downloadJson(oldIndexId, true);
|
|
640
|
+
const ids = new Set();
|
|
641
|
+
for (const entry of Object.values(oldIndex.entries || {})) {
|
|
642
|
+
const fid = entry.location?.fileId;
|
|
643
|
+
if (fid && fid !== 'LEGACY_MEMORY')
|
|
644
|
+
ids.add(fid);
|
|
645
|
+
}
|
|
646
|
+
oldDataFileIds = [...ids];
|
|
647
|
+
}
|
|
648
|
+
catch (e) {
|
|
649
|
+
this.log('Failed to load old snapshot index for data-file cleanup', oldIndexId, e);
|
|
650
|
+
}
|
|
651
|
+
}
|
|
625
652
|
// 1. Fetch ALL active documents
|
|
626
653
|
// We need them to build the new large snapshot-data file
|
|
627
654
|
// This is the one time we download everything if not cached.
|
|
@@ -677,8 +704,11 @@ class DriveHandler {
|
|
|
677
704
|
lastCompaction: Date.now()
|
|
678
705
|
};
|
|
679
706
|
});
|
|
680
|
-
// 5. Cleanup - Only delete files that were confirmed removed from metadata
|
|
681
|
-
|
|
707
|
+
// 5. Cleanup - Only delete files that were confirmed removed from metadata.
|
|
708
|
+
// Also delete the old snapshot-data file(s) the old index pointed to (excluding
|
|
709
|
+
// the freshly-created one, which can't appear here since it's brand new).
|
|
710
|
+
const staleDataFileIds = oldDataFileIds.filter(id => id !== dataFileId);
|
|
711
|
+
await this.cleanupOldFiles(oldIndexId, [...filesToDelete, ...staleDataFileIds]);
|
|
682
712
|
this.currentLogSizeEstimate = 0;
|
|
683
713
|
}
|
|
684
714
|
finally {
|
package/lib/index.d.ts
CHANGED
|
File without changes
|
package/lib/index.js
CHANGED
|
File without changes
|
package/lib/types.d.ts
CHANGED
|
File without changes
|
package/lib/types.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@docstack/pouchdb-adapter-googledrive",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "PouchDB adapter for Google Drive",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"build": "tsc",
|
|
9
9
|
"test": "jest",
|
|
10
|
-
"test:prod": "TEST_ENV=production jest"
|
|
10
|
+
"test:prod": "TEST_ENV=production jest",
|
|
11
|
+
"test:prod:explore": "TEST_ENV=production jest tests/production.explore.test.ts",
|
|
12
|
+
"test:prod:replication": "TEST_ENV=production jest tests/production.replication.test.ts"
|
|
11
13
|
},
|
|
12
14
|
"keywords": [
|
|
13
15
|
"pouchdb",
|