@graffiti-garden/implementation-local 0.5.1 → 0.6.1
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/dist/browser/index.js +2 -20
- package/dist/browser/index.js.map +4 -4
- package/dist/cjs/database.js +181 -90
- package/dist/cjs/database.js.map +3 -3
- package/dist/cjs/index.js +11 -0
- package/dist/cjs/index.js.map +2 -2
- package/dist/cjs/utilities.js +3 -7
- package/dist/cjs/utilities.js.map +2 -2
- package/dist/database.d.ts +28 -20
- package/dist/database.d.ts.map +1 -1
- package/dist/esm/database.js +182 -92
- package/dist/esm/database.js.map +3 -3
- package/dist/esm/index.js +11 -0
- package/dist/esm/index.js.map +2 -2
- package/dist/esm/utilities.js +3 -7
- package/dist/esm/utilities.js.map +2 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/utilities.d.ts +1 -2
- package/dist/utilities.d.ts.map +1 -1
- package/package.json +2 -3
- package/src/database.ts +285 -164
- package/src/index.ts +17 -1
- package/src/utilities.ts +2 -14
package/dist/cjs/database.js
CHANGED
|
@@ -33,9 +33,8 @@ __export(database_exports, {
|
|
|
33
33
|
module.exports = __toCommonJS(database_exports);
|
|
34
34
|
var import_api = require("@graffiti-garden/api");
|
|
35
35
|
var import_utilities = require("./utilities.js");
|
|
36
|
-
var import_repeater = require("@repeaterjs/repeater");
|
|
37
|
-
const DEFAULT_TOMBSTONE_RETENTION = 864e5;
|
|
38
36
|
const DEFAULT_ORIGIN = "graffiti:local:";
|
|
37
|
+
const LAST_MODIFIED_BUFFER = 6e4;
|
|
39
38
|
class GraffitiLocalDatabase {
|
|
40
39
|
db_;
|
|
41
40
|
applyPatch_;
|
|
@@ -116,6 +115,17 @@ class GraffitiLocalDatabase {
|
|
|
116
115
|
}
|
|
117
116
|
return this.ajv_;
|
|
118
117
|
}
|
|
118
|
+
extractGraffitiObject(object) {
|
|
119
|
+
const { value, channels, allowed, url, actor, lastModified } = object;
|
|
120
|
+
return {
|
|
121
|
+
value,
|
|
122
|
+
channels,
|
|
123
|
+
allowed,
|
|
124
|
+
url,
|
|
125
|
+
actor,
|
|
126
|
+
lastModified
|
|
127
|
+
};
|
|
128
|
+
}
|
|
119
129
|
constructor(options) {
|
|
120
130
|
this.options = options ?? {};
|
|
121
131
|
this.origin = this.options.origin ?? DEFAULT_ORIGIN;
|
|
@@ -123,11 +133,11 @@ class GraffitiLocalDatabase {
|
|
|
123
133
|
this.origin += "/";
|
|
124
134
|
}
|
|
125
135
|
}
|
|
126
|
-
async allDocsAtLocation(
|
|
127
|
-
const
|
|
136
|
+
async allDocsAtLocation(objectUrl) {
|
|
137
|
+
const url = (0, import_utilities.unpackObjectUrl)(objectUrl) + "/";
|
|
128
138
|
const results = await (await this.db).allDocs({
|
|
129
|
-
startkey:
|
|
130
|
-
endkey:
|
|
139
|
+
startkey: url,
|
|
140
|
+
endkey: url + "\uFFFF",
|
|
131
141
|
// \uffff is the last unicode character
|
|
132
142
|
include_docs: true
|
|
133
143
|
});
|
|
@@ -137,12 +147,12 @@ class GraffitiLocalDatabase {
|
|
|
137
147
|
}, []);
|
|
138
148
|
return docs;
|
|
139
149
|
}
|
|
140
|
-
docId(
|
|
141
|
-
return
|
|
150
|
+
docId(objectUrl) {
|
|
151
|
+
return objectUrl.url + "/" + (0, import_utilities.randomBase64)();
|
|
142
152
|
}
|
|
143
153
|
get = async (...args) => {
|
|
144
|
-
const [
|
|
145
|
-
const docsAll = await this.allDocsAtLocation(
|
|
154
|
+
const [urlObject, schema, session] = args;
|
|
155
|
+
const docsAll = await this.allDocsAtLocation(urlObject);
|
|
146
156
|
const docs = docsAll.filter(
|
|
147
157
|
(doc2) => (0, import_utilities.isActorAllowedGraffitiObject)(doc2, session)
|
|
148
158
|
);
|
|
@@ -150,8 +160,15 @@ class GraffitiLocalDatabase {
|
|
|
150
160
|
throw new import_api.GraffitiErrorNotFound(
|
|
151
161
|
"The object you are trying to get either does not exist or you are not allowed to see it"
|
|
152
162
|
);
|
|
153
|
-
const doc = docs.reduce(
|
|
154
|
-
|
|
163
|
+
const doc = docs.reduce(
|
|
164
|
+
(a, b) => a.lastModified > b.lastModified || a.lastModified === b.lastModified && !a.tombstone && b.tombstone ? a : b
|
|
165
|
+
);
|
|
166
|
+
if (doc.tombstone) {
|
|
167
|
+
throw new import_api.GraffitiErrorNotFound(
|
|
168
|
+
"The object you are trying to get either does not exist or you are not allowed to see it"
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
const object = this.extractGraffitiObject(doc);
|
|
155
172
|
(0, import_utilities.maskGraffitiObject)(object, [], session);
|
|
156
173
|
const validate = (0, import_utilities.compileGraffitiObjectSchema)(await this.ajv, schema);
|
|
157
174
|
if (!validate(object)) {
|
|
@@ -167,10 +184,10 @@ class GraffitiLocalDatabase {
|
|
|
167
184
|
* timestamp, the one with the highest `_id` will be
|
|
168
185
|
* spared.
|
|
169
186
|
*/
|
|
170
|
-
async deleteAtLocation(
|
|
187
|
+
async deleteAtLocation(url, options = {
|
|
171
188
|
keepLatest: false
|
|
172
189
|
}) {
|
|
173
|
-
const docsAtLocationAll = await this.allDocsAtLocation(
|
|
190
|
+
const docsAtLocationAll = await this.allDocsAtLocation(url);
|
|
174
191
|
const docsAtLocationAllowed = options.session ? docsAtLocationAll.filter(
|
|
175
192
|
(doc) => (0, import_utilities.isActorAllowedGraffitiObject)(doc, options.session)
|
|
176
193
|
) : docsAtLocationAll;
|
|
@@ -215,10 +232,8 @@ class GraffitiLocalDatabase {
|
|
|
215
232
|
const { id } = resultOrError;
|
|
216
233
|
const deletedDoc = docsToDelete.find((doc) => doc._id === id);
|
|
217
234
|
if (deletedDoc) {
|
|
218
|
-
const { _id, _rev, _conflicts, _attachments, ...object } = deletedDoc;
|
|
219
235
|
deletedObject = {
|
|
220
|
-
...
|
|
221
|
-
tombstone: true,
|
|
236
|
+
...this.extractGraffitiObject(deletedDoc),
|
|
222
237
|
lastModified
|
|
223
238
|
};
|
|
224
239
|
break;
|
|
@@ -228,8 +243,8 @@ class GraffitiLocalDatabase {
|
|
|
228
243
|
return deletedObject;
|
|
229
244
|
}
|
|
230
245
|
delete = async (...args) => {
|
|
231
|
-
const [
|
|
232
|
-
const deletedObject = await this.deleteAtLocation(
|
|
246
|
+
const [url, session] = args;
|
|
247
|
+
const deletedObject = await this.deleteAtLocation(url, {
|
|
233
248
|
session
|
|
234
249
|
});
|
|
235
250
|
if (!deletedObject) {
|
|
@@ -250,7 +265,7 @@ class GraffitiLocalDatabase {
|
|
|
250
265
|
oldObject = await this.get(objectPartial.url, {}, session);
|
|
251
266
|
} catch (e) {
|
|
252
267
|
if (e instanceof import_api.GraffitiErrorNotFound) {
|
|
253
|
-
if (!this.options.
|
|
268
|
+
if (!this.options.allowSettingArbitraryUrls) {
|
|
254
269
|
throw new import_api.GraffitiErrorNotFound(
|
|
255
270
|
"The object you are trying to replace does not exist or you are not allowed to see it"
|
|
256
271
|
);
|
|
@@ -295,10 +310,10 @@ class GraffitiLocalDatabase {
|
|
|
295
310
|
}
|
|
296
311
|
};
|
|
297
312
|
patch = async (...args) => {
|
|
298
|
-
const [patch,
|
|
313
|
+
const [patch, url, session] = args;
|
|
299
314
|
let originalObject;
|
|
300
315
|
try {
|
|
301
|
-
originalObject = await this.get(
|
|
316
|
+
originalObject = await this.get(url, {}, session);
|
|
302
317
|
} catch (e) {
|
|
303
318
|
if (e instanceof import_api.GraffitiErrorNotFound) {
|
|
304
319
|
throw new import_api.GraffitiErrorNotFound(
|
|
@@ -312,10 +327,6 @@ class GraffitiLocalDatabase {
|
|
|
312
327
|
throw new import_api.GraffitiErrorForbidden(
|
|
313
328
|
"The object you are trying to patch is owned by another actor"
|
|
314
329
|
);
|
|
315
|
-
} else if (originalObject.tombstone) {
|
|
316
|
-
throw new import_api.GraffitiErrorNotFound(
|
|
317
|
-
"The object you are trying to patch has been deleted"
|
|
318
|
-
);
|
|
319
330
|
}
|
|
320
331
|
const patchObject = { ...originalObject };
|
|
321
332
|
for (const prop of ["value", "channels", "allowed"]) {
|
|
@@ -337,6 +348,7 @@ class GraffitiLocalDatabase {
|
|
|
337
348
|
patchObject.lastModified = (/* @__PURE__ */ new Date()).getTime();
|
|
338
349
|
await (await this.db).put({
|
|
339
350
|
...patchObject,
|
|
351
|
+
tombstone: false,
|
|
340
352
|
_id: this.docId(patchObject)
|
|
341
353
|
});
|
|
342
354
|
await this.deleteAtLocation(patchObject, {
|
|
@@ -344,16 +356,15 @@ class GraffitiLocalDatabase {
|
|
|
344
356
|
});
|
|
345
357
|
return {
|
|
346
358
|
...originalObject,
|
|
347
|
-
tombstone: true,
|
|
348
359
|
lastModified: patchObject.lastModified
|
|
349
360
|
};
|
|
350
361
|
};
|
|
351
|
-
queryLastModifiedSuffixes(schema) {
|
|
362
|
+
queryLastModifiedSuffixes(schema, lastModified) {
|
|
352
363
|
let startKeySuffix = "";
|
|
353
364
|
let endKeySuffix = "\uFFFF";
|
|
354
365
|
if (typeof schema === "object" && schema.properties?.lastModified && typeof schema.properties.lastModified === "object") {
|
|
355
366
|
const lastModifiedSchema = schema.properties.lastModified;
|
|
356
|
-
const minimum = lastModifiedSchema.minimum;
|
|
367
|
+
const minimum = lastModified && lastModifiedSchema.minimum ? Math.max(lastModified, lastModifiedSchema.minimum) : lastModified ?? lastModifiedSchema.minimum;
|
|
357
368
|
const exclusiveMinimum = lastModifiedSchema.exclusiveMinimum;
|
|
358
369
|
let intMinimum;
|
|
359
370
|
if (exclusiveMinimum !== void 0) {
|
|
@@ -383,71 +394,150 @@ class GraffitiLocalDatabase {
|
|
|
383
394
|
endKeySuffix
|
|
384
395
|
};
|
|
385
396
|
}
|
|
386
|
-
|
|
387
|
-
const
|
|
388
|
-
const
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
for (const channel of channels) {
|
|
393
|
-
const keyPrefix = encodeURIComponent(channel) + "/";
|
|
394
|
-
const startkey = keyPrefix + startKeySuffix;
|
|
395
|
-
const endkey = keyPrefix + endKeySuffix;
|
|
396
|
-
const result = await (await this.db).query(
|
|
397
|
-
"indexes/objectsPerChannelAndLastModified",
|
|
398
|
-
{ startkey, endkey, include_docs: true }
|
|
399
|
-
);
|
|
400
|
-
for (const row of result.rows) {
|
|
401
|
-
const doc = row.doc;
|
|
402
|
-
if (!doc) continue;
|
|
403
|
-
const { _id, _rev, ...object } = doc;
|
|
404
|
-
if (processedIds.has(_id)) continue;
|
|
405
|
-
processedIds.add(_id);
|
|
406
|
-
if (!(0, import_utilities.isActorAllowedGraffitiObject)(doc, session)) continue;
|
|
407
|
-
(0, import_utilities.maskGraffitiObject)(object, channels, session);
|
|
408
|
-
if (validate(object)) {
|
|
409
|
-
await push({ value: object });
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
stop();
|
|
414
|
-
return {
|
|
415
|
-
tombstoneRetention: this.options.tombstoneRetention ?? DEFAULT_TOMBSTONE_RETENTION
|
|
416
|
-
};
|
|
397
|
+
async *streamObjects(index, startkey, endkey, validate, session, ifModifiedSince, channels, processedIds) {
|
|
398
|
+
const showTombstones = ifModifiedSince !== void 0;
|
|
399
|
+
const result = await (await this.db).query(index, {
|
|
400
|
+
startkey,
|
|
401
|
+
endkey,
|
|
402
|
+
include_docs: true
|
|
417
403
|
});
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
404
|
+
for (const row of result.rows) {
|
|
405
|
+
const doc = row.doc;
|
|
406
|
+
if (!doc) continue;
|
|
407
|
+
if (processedIds?.has(doc._id)) continue;
|
|
408
|
+
processedIds?.add(doc._id);
|
|
409
|
+
if (!showTombstones && doc.tombstone) continue;
|
|
410
|
+
const object = this.extractGraffitiObject(doc);
|
|
411
|
+
if (channels) {
|
|
412
|
+
if (!(0, import_utilities.isActorAllowedGraffitiObject)(object, session)) continue;
|
|
413
|
+
(0, import_utilities.maskGraffitiObject)(object, channels, session);
|
|
414
|
+
}
|
|
415
|
+
if (!validate(object)) continue;
|
|
416
|
+
yield doc.tombstone ? {
|
|
417
|
+
tombstone: true,
|
|
418
|
+
object: {
|
|
419
|
+
url: object.url,
|
|
420
|
+
lastModified: object.lastModified
|
|
421
|
+
}
|
|
422
|
+
} : { object };
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
async *discoverMeta(args, ifModifiedSince) {
|
|
426
|
+
const [channels, schema, session] = args;
|
|
427
|
+
const validate = (0, import_utilities.compileGraffitiObjectSchema)(await this.ajv, schema);
|
|
428
|
+
const { startKeySuffix, endKeySuffix } = this.queryLastModifiedSuffixes(
|
|
429
|
+
schema,
|
|
430
|
+
ifModifiedSince
|
|
431
|
+
);
|
|
432
|
+
const processedIds = /* @__PURE__ */ new Set();
|
|
433
|
+
const startTime = (/* @__PURE__ */ new Date()).getTime();
|
|
434
|
+
for (const channel of channels) {
|
|
435
|
+
const keyPrefix = encodeURIComponent(channel) + "/";
|
|
436
|
+
const startkey = keyPrefix + startKeySuffix;
|
|
437
|
+
const endkey = keyPrefix + endKeySuffix;
|
|
438
|
+
const iterator = this.streamObjects(
|
|
439
|
+
"indexes/objectsPerChannelAndLastModified",
|
|
440
|
+
startkey,
|
|
441
|
+
endkey,
|
|
442
|
+
validate,
|
|
443
|
+
session,
|
|
444
|
+
ifModifiedSince,
|
|
445
|
+
channels,
|
|
446
|
+
processedIds
|
|
447
|
+
);
|
|
448
|
+
for await (const result of iterator) yield result;
|
|
449
|
+
}
|
|
450
|
+
return startTime - LAST_MODIFIED_BUFFER;
|
|
451
|
+
}
|
|
452
|
+
async *recoverOrphansMeta(args, ifModifiedSince) {
|
|
453
|
+
const [schema, session] = args;
|
|
454
|
+
const { startKeySuffix, endKeySuffix } = this.queryLastModifiedSuffixes(
|
|
455
|
+
schema,
|
|
456
|
+
ifModifiedSince
|
|
457
|
+
);
|
|
422
458
|
const keyPrefix = encodeURIComponent(session.actor) + "/";
|
|
423
459
|
const startkey = keyPrefix + startKeySuffix;
|
|
424
460
|
const endkey = keyPrefix + endKeySuffix;
|
|
425
|
-
const
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
461
|
+
const validate = (0, import_utilities.compileGraffitiObjectSchema)(await this.ajv, schema);
|
|
462
|
+
const startTime = (/* @__PURE__ */ new Date()).getTime();
|
|
463
|
+
const iterator = this.streamObjects(
|
|
464
|
+
"indexes/orphansPerActorAndLastModified",
|
|
465
|
+
startkey,
|
|
466
|
+
endkey,
|
|
467
|
+
validate,
|
|
468
|
+
session,
|
|
469
|
+
ifModifiedSince
|
|
470
|
+
);
|
|
471
|
+
for await (const result of iterator) yield result;
|
|
472
|
+
return startTime - LAST_MODIFIED_BUFFER;
|
|
473
|
+
}
|
|
474
|
+
async *discoverContinue(args, ifModifiedSince) {
|
|
475
|
+
const iterator = this.discoverMeta(args, ifModifiedSince);
|
|
476
|
+
while (true) {
|
|
477
|
+
const result = await iterator.next();
|
|
478
|
+
if (result.done) {
|
|
479
|
+
const ifModifiedSince2 = result.value;
|
|
480
|
+
return {
|
|
481
|
+
continue: () => this.discoverContinue(args, ifModifiedSince2),
|
|
482
|
+
cursor: ""
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
yield result.value;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
discover = (...args) => {
|
|
489
|
+
const iterator = this.discoverMeta(args);
|
|
490
|
+
const this_ = this;
|
|
491
|
+
return async function* () {
|
|
492
|
+
while (true) {
|
|
493
|
+
const result = await iterator.next();
|
|
494
|
+
if (result.done) {
|
|
495
|
+
return {
|
|
496
|
+
continue: () => this_.discoverContinue(args, result.value),
|
|
497
|
+
cursor: ""
|
|
498
|
+
};
|
|
438
499
|
}
|
|
500
|
+
if (result.value.tombstone) continue;
|
|
501
|
+
yield result.value;
|
|
439
502
|
}
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
503
|
+
}();
|
|
504
|
+
};
|
|
505
|
+
async *recoverContinue(args, ifModifiedSince) {
|
|
506
|
+
const iterator = this.recoverOrphansMeta(args, ifModifiedSince);
|
|
507
|
+
while (true) {
|
|
508
|
+
const result = await iterator.next();
|
|
509
|
+
if (result.done) {
|
|
510
|
+
const ifModifiedSince2 = result.value;
|
|
511
|
+
return {
|
|
512
|
+
continue: () => this.recoverContinue(args, ifModifiedSince2),
|
|
513
|
+
cursor: ""
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
yield result.value;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
recoverOrphans = (...args) => {
|
|
520
|
+
const iterator = this.recoverOrphansMeta(args);
|
|
521
|
+
const this_ = this;
|
|
522
|
+
return async function* () {
|
|
523
|
+
while (true) {
|
|
524
|
+
const result = await iterator.next();
|
|
525
|
+
if (result.done) {
|
|
526
|
+
return {
|
|
527
|
+
continue: () => this_.recoverContinue(args, result.value),
|
|
528
|
+
cursor: ""
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
if (result.value.tombstone) continue;
|
|
532
|
+
yield result.value;
|
|
533
|
+
}
|
|
534
|
+
}();
|
|
446
535
|
};
|
|
447
536
|
channelStats = (session) => {
|
|
448
|
-
const
|
|
537
|
+
const this_ = this;
|
|
538
|
+
return async function* () {
|
|
449
539
|
const keyPrefix = encodeURIComponent(session.actor) + "/";
|
|
450
|
-
const result = await (await
|
|
540
|
+
const result = await (await this_.db).query("indexes/channelStatsPerActor", {
|
|
451
541
|
startkey: keyPrefix,
|
|
452
542
|
endkey: keyPrefix + "\uFFFF",
|
|
453
543
|
reduce: true,
|
|
@@ -459,17 +549,18 @@ class GraffitiLocalDatabase {
|
|
|
459
549
|
const { count, max: lastModified } = row.value;
|
|
460
550
|
if (typeof count !== "number" || typeof lastModified !== "number")
|
|
461
551
|
continue;
|
|
462
|
-
|
|
552
|
+
yield {
|
|
463
553
|
value: {
|
|
464
554
|
channel: decodeURIComponent(channelEncoded),
|
|
465
555
|
count,
|
|
466
556
|
lastModified
|
|
467
557
|
}
|
|
468
|
-
}
|
|
558
|
+
};
|
|
469
559
|
}
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
560
|
+
}();
|
|
561
|
+
};
|
|
562
|
+
continueObjectStream = (cursor, session) => {
|
|
563
|
+
throw new import_api.GraffitiErrorNotFound("Cursor not found");
|
|
473
564
|
};
|
|
474
565
|
}
|
|
475
566
|
//# sourceMappingURL=database.js.map
|
package/dist/cjs/database.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/database.ts"],
|
|
4
|
-
"sourcesContent": ["import type {\n Graffiti,\n GraffitiObjectBase,\n GraffitiObjectUrl,\n JSONSchema,\n GraffitiSession,\n} from \"@graffiti-garden/api\";\nimport {\n GraffitiErrorNotFound,\n GraffitiErrorSchemaMismatch,\n GraffitiErrorForbidden,\n GraffitiErrorPatchError,\n} from \"@graffiti-garden/api\";\nimport {\n randomBase64,\n applyGraffitiPatch,\n maskGraffitiObject,\n isActorAllowedGraffitiObject,\n isObjectNewer,\n compileGraffitiObjectSchema,\n unpackLocationOrUri,\n} from \"./utilities.js\";\nimport { Repeater } from \"@repeaterjs/repeater\";\nimport type Ajv from \"ajv\";\nimport type { applyPatch } from \"fast-json-patch\";\n\n/**\n * Constructor options for the GraffitiPoubchDB class.\n */\nexport interface GraffitiLocalOptions {\n /**\n * Options to pass to the PouchDB constructor.\n * Defaults to `{ name: \"graffitiDb\" }`.\n *\n * See the [PouchDB documentation](https://pouchdb.com/api.html#create_database)\n * for available options.\n */\n pouchDBOptions?: PouchDB.Configuration.DatabaseConfiguration;\n /**\n * Includes the scheme and other information (possibly domain name)\n * to prefix prefixes all URIs put in the system. Defaults to `graffiti:local`.\n */\n origin?: string;\n /**\n * Whether to allow putting objects at arbtirary URIs, i.e.\n * URIs that are *not* prefixed with the origin or not generated\n * by the system. Defaults to `false`.\n *\n * Allows this implementation to be used as a client-side cache\n * for remote sources.\n */\n allowSettingArbitraryUris?: boolean;\n /**\n * Whether to allow the user to set the lastModified field\n * when putting objects. Defaults to `false`.\n *\n * Allows this implementation to be used as a client-side cache\n * for remote sources.\n */\n allowSettinngLastModified?: boolean;\n /**\n * The time in milliseconds to keep tombstones before deleting them.\n * See the {@link https://api.graffiti.garden/classes/Graffiti.html#discover | `discover` }\n * documentation for more information.\n */\n tombstoneRetention?: number;\n /**\n * An optional Ajv instance to use for schema validation.\n * If not provided, an internal instance will be created.\n */\n ajv?: Ajv;\n}\n\nconst DEFAULT_TOMBSTONE_RETENTION = 86400000; // 1 day in milliseconds\nconst DEFAULT_ORIGIN = \"graffiti:local:\";\n\n/**\n * An implementation of only the database operations of the\n * GraffitiAPI without synchronization or session management.\n */\nexport class GraffitiLocalDatabase\n implements\n Pick<\n Graffiti,\n | \"get\"\n | \"put\"\n | \"patch\"\n | \"delete\"\n | \"discover\"\n | \"recoverOrphans\"\n | \"channelStats\"\n >\n{\n protected db_: Promise<PouchDB.Database<GraffitiObjectBase>> | undefined;\n protected applyPatch_: Promise<typeof applyPatch> | undefined;\n protected ajv_: Promise<Ajv> | undefined;\n protected readonly options: GraffitiLocalOptions;\n protected readonly origin: string;\n\n get db() {\n if (!this.db_) {\n this.db_ = (async () => {\n const { default: PouchDB } = await import(\"pouchdb\");\n const pouchDbOptions = {\n name: \"graffitiDb\",\n ...this.options.pouchDBOptions,\n };\n const db = new PouchDB<GraffitiObjectBase>(\n pouchDbOptions.name,\n pouchDbOptions,\n );\n await db\n //@ts-ignore\n .put({\n _id: \"_design/indexes\",\n views: {\n objectsPerChannelAndLastModified: {\n map: function (object: GraffitiObjectBase) {\n const paddedLastModified = object.lastModified\n .toString()\n .padStart(15, \"0\");\n object.channels.forEach(function (channel) {\n const id =\n encodeURIComponent(channel) + \"/\" + paddedLastModified;\n //@ts-ignore\n emit(id);\n });\n }.toString(),\n },\n orphansPerActorAndLastModified: {\n map: function (object: GraffitiObjectBase) {\n if (object.channels.length === 0) {\n const paddedLastModified = object.lastModified\n .toString()\n .padStart(15, \"0\");\n const id =\n encodeURIComponent(object.actor) +\n \"/\" +\n paddedLastModified;\n //@ts-ignore\n emit(id);\n }\n }.toString(),\n },\n channelStatsPerActor: {\n map: function (object: GraffitiObjectBase) {\n if (object.tombstone) return;\n object.channels.forEach(function (channel) {\n const id =\n encodeURIComponent(object.actor) +\n \"/\" +\n encodeURIComponent(channel);\n //@ts-ignore\n emit(id, object.lastModified);\n });\n }.toString(),\n reduce: \"_stats\",\n },\n },\n })\n //@ts-ignore\n .catch((error) => {\n if (\n error &&\n typeof error === \"object\" &&\n \"name\" in error &&\n error.name === \"conflict\"\n ) {\n // Design document already exists\n return;\n } else {\n throw error;\n }\n });\n return db;\n })();\n }\n return this.db_;\n }\n\n get applyPatch() {\n if (!this.applyPatch_) {\n this.applyPatch_ = (async () => {\n const { applyPatch } = await import(\"fast-json-patch\");\n return applyPatch;\n })();\n }\n return this.applyPatch_;\n }\n\n get ajv() {\n if (!this.ajv_) {\n this.ajv_ = this.options.ajv\n ? Promise.resolve(this.options.ajv)\n : (async () => {\n const { default: Ajv } = await import(\"ajv\");\n return new Ajv({ strict: false });\n })();\n }\n return this.ajv_;\n }\n\n constructor(options?: GraffitiLocalOptions) {\n this.options = options ?? {};\n this.origin = this.options.origin ?? DEFAULT_ORIGIN;\n if (!this.origin.endsWith(\":\") && !this.origin.endsWith(\"/\")) {\n this.origin += \"/\";\n }\n }\n\n protected async allDocsAtLocation(locationOrUri: GraffitiObjectUrl | string) {\n const uri = unpackLocationOrUri(locationOrUri) + \"/\";\n const results = await (\n await this.db\n ).allDocs({\n startkey: uri,\n endkey: uri + \"\\uffff\", // \\uffff is the last unicode character\n include_docs: true,\n });\n const docs = results.rows\n .map((row) => row.doc)\n // Remove undefined docs\n .reduce<\n PouchDB.Core.ExistingDocument<\n GraffitiObjectBase & PouchDB.Core.AllDocsMeta\n >[]\n >((acc, doc) => {\n if (doc) acc.push(doc);\n return acc;\n }, []);\n return docs;\n }\n\n protected docId(location: GraffitiObjectUrl) {\n return location.url + \"/\" + randomBase64();\n }\n\n get: Graffiti[\"get\"] = async (...args) => {\n const [locationOrUri, schema, session] = args;\n\n const docsAll = await this.allDocsAtLocation(locationOrUri);\n\n // Filter out ones not allowed\n const docs = docsAll.filter((doc) =>\n isActorAllowedGraffitiObject(doc, session),\n );\n if (!docs.length)\n throw new GraffitiErrorNotFound(\n \"The object you are trying to get either does not exist or you are not allowed to see it\",\n );\n\n // Get the most recent document\n const doc = docs.reduce((a, b) => (isObjectNewer(a, b) ? a : b));\n\n // Strip out the _id and _rev\n const { _id, _rev, _conflicts, _attachments, ...object } = doc;\n\n // Mask out the allowed list and channels\n // if the user is not the owner\n maskGraffitiObject(object, [], session);\n\n const validate = compileGraffitiObjectSchema(await this.ajv, schema);\n if (!validate(object)) {\n throw new GraffitiErrorSchemaMismatch();\n }\n return object;\n };\n\n /**\n * Deletes all docs at a particular location.\n * If the `keepLatest` flag is set to true,\n * the doc with the most recent timestamp will be\n * spared. If there are multiple docs with the same\n * timestamp, the one with the highest `_id` will be\n * spared.\n */\n protected async deleteAtLocation(\n locationOrUri: GraffitiObjectUrl | string,\n options: {\n keepLatest?: boolean;\n session?: GraffitiSession;\n } = {\n keepLatest: false,\n },\n ) {\n const docsAtLocationAll = await this.allDocsAtLocation(locationOrUri);\n const docsAtLocationAllowed = options.session\n ? docsAtLocationAll.filter((doc) =>\n isActorAllowedGraffitiObject(doc, options.session),\n )\n : docsAtLocationAll;\n if (!docsAtLocationAllowed.length) {\n throw new GraffitiErrorNotFound(\n \"The object you are trying to delete either does not exist or you are not allowed to see it\",\n );\n } else if (\n options.session &&\n docsAtLocationAllowed.some((doc) => doc.actor !== options.session?.actor)\n ) {\n throw new GraffitiErrorForbidden(\n \"You cannot delete an object owned by another actor\",\n );\n }\n const docsAtLocation = docsAtLocationAllowed.filter(\n (doc) => !doc.tombstone,\n );\n if (!docsAtLocation.length) return undefined;\n\n // Get the most recent lastModified timestamp.\n const latestModified = docsAtLocation\n .map((doc) => doc.lastModified)\n .reduce((a, b) => (a > b ? a : b));\n\n // Delete all old docs\n const docsToDelete = docsAtLocation.filter(\n (doc) => !options.keepLatest || doc.lastModified < latestModified,\n );\n\n // For docs with the same timestamp,\n // keep the one with the highest _id\n // to break concurrency ties\n const concurrentDocsAll = docsAtLocation.filter(\n (doc) => options.keepLatest && doc.lastModified === latestModified,\n );\n if (concurrentDocsAll.length) {\n const keepDocId = concurrentDocsAll\n .map((doc) => doc._id)\n .reduce((a, b) => (a > b ? a : b));\n const concurrentDocsToDelete = concurrentDocsAll.filter(\n (doc) => doc._id !== keepDocId,\n );\n docsToDelete.push(...concurrentDocsToDelete);\n }\n\n const lastModified = options.keepLatest\n ? latestModified\n : new Date().getTime();\n\n const deleteResults = await (\n await this.db\n ).bulkDocs<GraffitiObjectBase>(\n docsToDelete.map((doc) => ({\n ...doc,\n tombstone: true,\n lastModified,\n })),\n );\n\n // Get one of the docs that was deleted\n let deletedObject: GraffitiObjectBase | undefined = undefined;\n for (const resultOrError of deleteResults) {\n if (\"ok\" in resultOrError) {\n const { id } = resultOrError;\n const deletedDoc = docsToDelete.find((doc) => doc._id === id);\n if (deletedDoc) {\n const { _id, _rev, _conflicts, _attachments, ...object } = deletedDoc;\n deletedObject = {\n ...object,\n tombstone: true,\n lastModified,\n };\n break;\n }\n }\n }\n\n return deletedObject;\n }\n\n delete: Graffiti[\"delete\"] = async (...args) => {\n const [locationOrUri, session] = args;\n const deletedObject = await this.deleteAtLocation(locationOrUri, {\n session,\n });\n if (!deletedObject) {\n throw new GraffitiErrorNotFound(\"The object has already been deleted\");\n }\n return deletedObject;\n };\n\n put: Graffiti[\"put\"] = async (...args) => {\n const [objectPartial, session] = args;\n if (objectPartial.actor && objectPartial.actor !== session.actor) {\n throw new GraffitiErrorForbidden(\n \"Cannot put an object with a different actor than the session actor\",\n );\n }\n\n if (objectPartial.url) {\n let oldObject: GraffitiObjectBase | undefined;\n try {\n oldObject = await this.get(objectPartial.url, {}, session);\n } catch (e) {\n if (e instanceof GraffitiErrorNotFound) {\n if (!this.options.allowSettingArbitraryUris) {\n throw new GraffitiErrorNotFound(\n \"The object you are trying to replace does not exist or you are not allowed to see it\",\n );\n }\n } else {\n throw e;\n }\n }\n if (oldObject?.actor !== session.actor) {\n throw new GraffitiErrorForbidden(\n \"The object you are trying to replace is owned by another actor\",\n );\n }\n }\n\n const lastModified =\n ((this.options.allowSettinngLastModified ?? false) &&\n objectPartial.lastModified) ||\n new Date().getTime();\n\n const object: GraffitiObjectBase = {\n value: objectPartial.value,\n channels: objectPartial.channels,\n allowed: objectPartial.allowed,\n url: objectPartial.url ?? this.origin + randomBase64(),\n actor: session.actor,\n tombstone: false,\n lastModified,\n };\n\n await (\n await this.db\n ).put({\n _id: this.docId(object),\n ...object,\n });\n\n // Delete the old object\n const previousObject = await this.deleteAtLocation(object, {\n keepLatest: true,\n });\n if (previousObject) {\n return previousObject;\n } else {\n return {\n ...object,\n value: {},\n channels: [],\n allowed: [],\n tombstone: true,\n };\n }\n };\n\n patch: Graffiti[\"patch\"] = async (...args) => {\n const [patch, locationOrUri, session] = args;\n let originalObject: GraffitiObjectBase;\n try {\n originalObject = await this.get(locationOrUri, {}, session);\n } catch (e) {\n if (e instanceof GraffitiErrorNotFound) {\n throw new GraffitiErrorNotFound(\n \"The object you are trying to patch does not exist or you are not allowed to see it\",\n );\n } else {\n throw e;\n }\n }\n if (originalObject.actor !== session.actor) {\n throw new GraffitiErrorForbidden(\n \"The object you are trying to patch is owned by another actor\",\n );\n } else if (originalObject.tombstone) {\n throw new GraffitiErrorNotFound(\n \"The object you are trying to patch has been deleted\",\n );\n }\n\n // Patch it outside of the database\n const patchObject: GraffitiObjectBase = { ...originalObject };\n for (const prop of [\"value\", \"channels\", \"allowed\"] as const) {\n applyGraffitiPatch(await this.applyPatch, prop, patch, patchObject);\n }\n\n // Make sure the value is an object\n if (\n typeof patchObject.value !== \"object\" ||\n Array.isArray(patchObject.value) ||\n !patchObject.value\n ) {\n throw new GraffitiErrorPatchError(\"value is no longer an object\");\n }\n\n // Make sure the channels are an array of strings\n if (\n !Array.isArray(patchObject.channels) ||\n !patchObject.channels.every((channel) => typeof channel === \"string\")\n ) {\n throw new GraffitiErrorPatchError(\n \"channels are no longer an array of strings\",\n );\n }\n\n // Make sure the allowed list is an array of strings or undefined\n if (\n patchObject.allowed &&\n (!Array.isArray(patchObject.allowed) ||\n !patchObject.allowed.every((allowed) => typeof allowed === \"string\"))\n ) {\n throw new GraffitiErrorPatchError(\n \"allowed list is not an array of strings\",\n );\n }\n\n patchObject.lastModified = new Date().getTime();\n await (\n await this.db\n ).put({\n ...patchObject,\n _id: this.docId(patchObject),\n });\n\n // Delete the old object\n await this.deleteAtLocation(patchObject, {\n keepLatest: true,\n });\n\n return {\n ...originalObject,\n tombstone: true,\n lastModified: patchObject.lastModified,\n };\n };\n\n protected queryLastModifiedSuffixes(schema: JSONSchema) {\n // Use the index for queries over ranges of lastModified\n let startKeySuffix = \"\";\n let endKeySuffix = \"\\uffff\";\n if (\n typeof schema === \"object\" &&\n schema.properties?.lastModified &&\n typeof schema.properties.lastModified === \"object\"\n ) {\n const lastModifiedSchema = schema.properties.lastModified;\n\n const minimum = lastModifiedSchema.minimum;\n const exclusiveMinimum = lastModifiedSchema.exclusiveMinimum;\n\n let intMinimum: number | undefined;\n if (exclusiveMinimum !== undefined) {\n intMinimum = Math.ceil(exclusiveMinimum);\n intMinimum === exclusiveMinimum && intMinimum++;\n } else if (minimum !== undefined) {\n intMinimum = Math.ceil(minimum);\n }\n\n if (intMinimum !== undefined) {\n startKeySuffix = intMinimum.toString().padStart(15, \"0\");\n }\n\n const maximum = lastModifiedSchema.maximum;\n const exclusiveMaximum = lastModifiedSchema.exclusiveMaximum;\n\n let intMaximum: number | undefined;\n if (exclusiveMaximum !== undefined) {\n intMaximum = Math.floor(exclusiveMaximum);\n intMaximum === exclusiveMaximum && intMaximum--;\n } else if (maximum !== undefined) {\n intMaximum = Math.floor(maximum);\n }\n\n if (intMaximum !== undefined) {\n endKeySuffix = intMaximum.toString().padStart(15, \"0\");\n }\n }\n return {\n startKeySuffix,\n endKeySuffix,\n };\n }\n\n discover: Graffiti[\"discover\"] = (...args) => {\n const [channels, schema, session] = args;\n\n const { startKeySuffix, endKeySuffix } =\n this.queryLastModifiedSuffixes(schema);\n\n const repeater: ReturnType<\n typeof Graffiti.prototype.discover<typeof schema>\n > = new Repeater(async (push, stop) => {\n const validate = compileGraffitiObjectSchema(await this.ajv, schema);\n\n const processedIds = new Set<string>();\n\n for (const channel of channels) {\n const keyPrefix = encodeURIComponent(channel) + \"/\";\n const startkey = keyPrefix + startKeySuffix;\n const endkey = keyPrefix + endKeySuffix;\n\n const result = await (\n await this.db\n ).query<GraffitiObjectBase>(\n \"indexes/objectsPerChannelAndLastModified\",\n { startkey, endkey, include_docs: true },\n );\n\n for (const row of result.rows) {\n const doc = row.doc;\n if (!doc) continue;\n\n const { _id, _rev, ...object } = doc;\n\n // Don't double return the same object\n // (which can happen if it's in multiple channels)\n if (processedIds.has(_id)) continue;\n processedIds.add(_id);\n\n // Make sure the user is allowed to see it\n if (!isActorAllowedGraffitiObject(doc, session)) continue;\n\n // Mask out the allowed list and channels\n // if the user is not the owner\n maskGraffitiObject(object, channels, session);\n\n // Check that it matches the schema\n if (validate(object)) {\n await push({ value: object });\n }\n }\n }\n stop();\n return {\n tombstoneRetention:\n this.options.tombstoneRetention ?? DEFAULT_TOMBSTONE_RETENTION,\n };\n });\n\n return repeater;\n };\n\n recoverOrphans: Graffiti[\"recoverOrphans\"] = (schema, session) => {\n const { startKeySuffix, endKeySuffix } =\n this.queryLastModifiedSuffixes(schema);\n const keyPrefix = encodeURIComponent(session.actor) + \"/\";\n const startkey = keyPrefix + startKeySuffix;\n const endkey = keyPrefix + endKeySuffix;\n\n const repeater: ReturnType<\n typeof Graffiti.prototype.recoverOrphans<typeof schema>\n > = new Repeater(async (push, stop) => {\n const validate = compileGraffitiObjectSchema(await this.ajv, schema);\n\n const result = await (\n await this.db\n ).query<GraffitiObjectBase>(\"indexes/orphansPerActorAndLastModified\", {\n startkey,\n endkey,\n include_docs: true,\n });\n\n for (const row of result.rows) {\n const doc = row.doc;\n if (!doc) continue;\n\n // No masking/access necessary because\n // the objects are all owned by the querier\n\n const { _id, _rev, ...object } = doc;\n if (validate(object)) {\n await push({ value: object });\n }\n }\n stop();\n return {\n tombstoneRetention:\n this.options.tombstoneRetention ?? DEFAULT_TOMBSTONE_RETENTION,\n };\n });\n\n return repeater;\n };\n\n channelStats: Graffiti[\"channelStats\"] = (session) => {\n const repeater: ReturnType<typeof Graffiti.prototype.channelStats> =\n new Repeater(async (push, stop) => {\n const keyPrefix = encodeURIComponent(session.actor) + \"/\";\n const result = await (\n await this.db\n ).query(\"indexes/channelStatsPerActor\", {\n startkey: keyPrefix,\n endkey: keyPrefix + \"\\uffff\",\n reduce: true,\n group: true,\n });\n for (const row of result.rows) {\n const channelEncoded = row.key.split(\"/\")[1];\n if (typeof channelEncoded !== \"string\") continue;\n const { count, max: lastModified } = row.value;\n if (typeof count !== \"number\" || typeof lastModified !== \"number\")\n continue;\n await push({\n value: {\n channel: decodeURIComponent(channelEncoded),\n count,\n lastModified,\n },\n });\n }\n stop();\n });\n\n return repeater;\n };\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["doc"]
|
|
4
|
+
"sourcesContent": ["import type {\n Graffiti,\n GraffitiObjectBase,\n GraffitiObjectUrl,\n JSONSchema,\n GraffitiSession,\n GraffitiObjectStreamContinue,\n GraffitiObjectStreamContinueEntry,\n} from \"@graffiti-garden/api\";\nimport {\n GraffitiErrorNotFound,\n GraffitiErrorSchemaMismatch,\n GraffitiErrorForbidden,\n GraffitiErrorPatchError,\n} from \"@graffiti-garden/api\";\nimport {\n randomBase64,\n applyGraffitiPatch,\n maskGraffitiObject,\n isActorAllowedGraffitiObject,\n compileGraffitiObjectSchema,\n unpackObjectUrl,\n} from \"./utilities.js\";\nimport type Ajv from \"ajv\";\nimport type { applyPatch } from \"fast-json-patch\";\n\n/**\n * Constructor options for the GraffitiPoubchDB class.\n */\nexport interface GraffitiLocalOptions {\n /**\n * Options to pass to the PouchDB constructor.\n * Defaults to `{ name: \"graffitiDb\" }`.\n *\n * See the [PouchDB documentation](https://pouchdb.com/api.html#create_database)\n * for available options.\n */\n pouchDBOptions?: PouchDB.Configuration.DatabaseConfiguration;\n /**\n * Includes the scheme and other information (possibly domain name)\n * to prefix prefixes all URLs put in the system. Defaults to `graffiti:local`.\n */\n origin?: string;\n /**\n * Whether to allow putting objects at arbtirary URLs, i.e.\n * URLs that are *not* prefixed with the origin or not generated\n * by the system. Defaults to `false`.\n *\n * Allows this implementation to be used as a client-side cache\n * for remote sources.\n */\n allowSettingArbitraryUrls?: boolean;\n /**\n * Whether to allow the user to set the lastModified field\n * when putting objects. Defaults to `false`.\n *\n * Allows this implementation to be used as a client-side cache\n * for remote sources.\n */\n allowSettinngLastModified?: boolean;\n /**\n * An optional Ajv instance to use for schema validation.\n * If not provided, an internal instance will be created.\n */\n ajv?: Ajv;\n}\n\nconst DEFAULT_ORIGIN = \"graffiti:local:\";\nconst LAST_MODIFIED_BUFFER = 60000;\n\ntype GraffitiObjectWithTombstone = GraffitiObjectBase & { tombstone: boolean };\n\n/**\n * An implementation of only the database operations of the\n * GraffitiAPI without synchronization or session management.\n */\nexport class GraffitiLocalDatabase\n implements Omit<Graffiti, \"login\" | \"logout\" | \"sessionEvents\">\n{\n protected db_:\n | Promise<PouchDB.Database<GraffitiObjectWithTombstone>>\n | undefined;\n protected applyPatch_: Promise<typeof applyPatch> | undefined;\n protected ajv_: Promise<Ajv> | undefined;\n protected readonly options: GraffitiLocalOptions;\n protected readonly origin: string;\n\n get db() {\n if (!this.db_) {\n this.db_ = (async () => {\n const { default: PouchDB } = await import(\"pouchdb\");\n const pouchDbOptions = {\n name: \"graffitiDb\",\n ...this.options.pouchDBOptions,\n };\n const db = new PouchDB<GraffitiObjectWithTombstone>(\n pouchDbOptions.name,\n pouchDbOptions,\n );\n await db\n //@ts-ignore\n .put({\n _id: \"_design/indexes\",\n views: {\n objectsPerChannelAndLastModified: {\n map: function (object: GraffitiObjectWithTombstone) {\n const paddedLastModified = object.lastModified\n .toString()\n .padStart(15, \"0\");\n object.channels.forEach(function (channel) {\n const id =\n encodeURIComponent(channel) + \"/\" + paddedLastModified;\n //@ts-ignore\n emit(id);\n });\n }.toString(),\n },\n orphansPerActorAndLastModified: {\n map: function (object: GraffitiObjectWithTombstone) {\n if (object.channels.length === 0) {\n const paddedLastModified = object.lastModified\n .toString()\n .padStart(15, \"0\");\n const id =\n encodeURIComponent(object.actor) +\n \"/\" +\n paddedLastModified;\n //@ts-ignore\n emit(id);\n }\n }.toString(),\n },\n channelStatsPerActor: {\n map: function (object: GraffitiObjectWithTombstone) {\n if (object.tombstone) return;\n object.channels.forEach(function (channel) {\n const id =\n encodeURIComponent(object.actor) +\n \"/\" +\n encodeURIComponent(channel);\n //@ts-ignore\n emit(id, object.lastModified);\n });\n }.toString(),\n reduce: \"_stats\",\n },\n },\n })\n //@ts-ignore\n .catch((error) => {\n if (\n error &&\n typeof error === \"object\" &&\n \"name\" in error &&\n error.name === \"conflict\"\n ) {\n // Design document already exists\n return;\n } else {\n throw error;\n }\n });\n return db;\n })();\n }\n return this.db_;\n }\n\n protected get applyPatch() {\n if (!this.applyPatch_) {\n this.applyPatch_ = (async () => {\n const { applyPatch } = await import(\"fast-json-patch\");\n return applyPatch;\n })();\n }\n return this.applyPatch_;\n }\n\n protected get ajv() {\n if (!this.ajv_) {\n this.ajv_ = this.options.ajv\n ? Promise.resolve(this.options.ajv)\n : (async () => {\n const { default: Ajv } = await import(\"ajv\");\n return new Ajv({ strict: false });\n })();\n }\n return this.ajv_;\n }\n\n protected extractGraffitiObject(\n object: GraffitiObjectWithTombstone,\n ): GraffitiObjectBase {\n const { value, channels, allowed, url, actor, lastModified } = object;\n return {\n value,\n channels,\n allowed,\n url,\n actor,\n lastModified,\n };\n }\n\n constructor(options?: GraffitiLocalOptions) {\n this.options = options ?? {};\n this.origin = this.options.origin ?? DEFAULT_ORIGIN;\n if (!this.origin.endsWith(\":\") && !this.origin.endsWith(\"/\")) {\n this.origin += \"/\";\n }\n }\n\n protected async allDocsAtLocation(objectUrl: string | GraffitiObjectUrl) {\n const url = unpackObjectUrl(objectUrl) + \"/\";\n const results = await (\n await this.db\n ).allDocs({\n startkey: url,\n endkey: url + \"\\uffff\", // \\uffff is the last unicode character\n include_docs: true,\n });\n const docs = results.rows\n .map((row) => row.doc)\n // Remove undefined docs\n .reduce<\n PouchDB.Core.ExistingDocument<\n GraffitiObjectWithTombstone & PouchDB.Core.AllDocsMeta\n >[]\n >((acc, doc) => {\n if (doc) acc.push(doc);\n return acc;\n }, []);\n return docs;\n }\n\n protected docId(objectUrl: GraffitiObjectUrl) {\n return objectUrl.url + \"/\" + randomBase64();\n }\n\n get: Graffiti[\"get\"] = async (...args) => {\n const [urlObject, schema, session] = args;\n\n const docsAll = await this.allDocsAtLocation(urlObject);\n\n // Filter out ones not allowed\n const docs = docsAll.filter((doc) =>\n isActorAllowedGraffitiObject(doc, session),\n );\n if (!docs.length)\n throw new GraffitiErrorNotFound(\n \"The object you are trying to get either does not exist or you are not allowed to see it\",\n );\n\n // Get the most recent document\n const doc = docs.reduce((a, b) =>\n a.lastModified > b.lastModified ||\n (a.lastModified === b.lastModified && !a.tombstone && b.tombstone)\n ? a\n : b,\n );\n\n if (doc.tombstone) {\n throw new GraffitiErrorNotFound(\n \"The object you are trying to get either does not exist or you are not allowed to see it\",\n );\n }\n\n const object = this.extractGraffitiObject(doc);\n\n // Mask out the allowed list and channels\n // if the user is not the owner\n maskGraffitiObject(object, [], session);\n\n const validate = compileGraffitiObjectSchema(await this.ajv, schema);\n if (!validate(object)) {\n throw new GraffitiErrorSchemaMismatch();\n }\n return object;\n };\n\n /**\n * Deletes all docs at a particular location.\n * If the `keepLatest` flag is set to true,\n * the doc with the most recent timestamp will be\n * spared. If there are multiple docs with the same\n * timestamp, the one with the highest `_id` will be\n * spared.\n */\n protected async deleteAtLocation(\n url: GraffitiObjectUrl | string,\n options: {\n keepLatest?: boolean;\n session?: GraffitiSession;\n } = {\n keepLatest: false,\n },\n ) {\n const docsAtLocationAll = await this.allDocsAtLocation(url);\n const docsAtLocationAllowed = options.session\n ? docsAtLocationAll.filter((doc) =>\n isActorAllowedGraffitiObject(doc, options.session),\n )\n : docsAtLocationAll;\n if (!docsAtLocationAllowed.length) {\n throw new GraffitiErrorNotFound(\n \"The object you are trying to delete either does not exist or you are not allowed to see it\",\n );\n } else if (\n options.session &&\n docsAtLocationAllowed.some((doc) => doc.actor !== options.session?.actor)\n ) {\n throw new GraffitiErrorForbidden(\n \"You cannot delete an object owned by another actor\",\n );\n }\n const docsAtLocation = docsAtLocationAllowed.filter(\n (doc) => !doc.tombstone,\n );\n if (!docsAtLocation.length) return undefined;\n\n // Get the most recent lastModified timestamp.\n const latestModified = docsAtLocation\n .map((doc) => doc.lastModified)\n .reduce((a, b) => (a > b ? a : b));\n\n // Delete all old docs\n const docsToDelete = docsAtLocation.filter(\n (doc) => !options.keepLatest || doc.lastModified < latestModified,\n );\n\n // For docs with the same timestamp,\n // keep the one with the highest _id\n // to break concurrency ties\n const concurrentDocsAll = docsAtLocation.filter(\n (doc) => options.keepLatest && doc.lastModified === latestModified,\n );\n if (concurrentDocsAll.length) {\n const keepDocId = concurrentDocsAll\n .map((doc) => doc._id)\n .reduce((a, b) => (a > b ? a : b));\n const concurrentDocsToDelete = concurrentDocsAll.filter(\n (doc) => doc._id !== keepDocId,\n );\n docsToDelete.push(...concurrentDocsToDelete);\n }\n\n const lastModified = options.keepLatest\n ? latestModified\n : new Date().getTime();\n\n const deleteResults = await (\n await this.db\n ).bulkDocs<GraffitiObjectBase>(\n docsToDelete.map((doc) => ({\n ...doc,\n tombstone: true,\n lastModified,\n })),\n );\n\n // Get one of the docs that was deleted\n let deletedObject: GraffitiObjectBase | undefined = undefined;\n for (const resultOrError of deleteResults) {\n if (\"ok\" in resultOrError) {\n const { id } = resultOrError;\n const deletedDoc = docsToDelete.find((doc) => doc._id === id);\n if (deletedDoc) {\n deletedObject = {\n ...this.extractGraffitiObject(deletedDoc),\n lastModified,\n };\n break;\n }\n }\n }\n\n return deletedObject;\n }\n\n delete: Graffiti[\"delete\"] = async (...args) => {\n const [url, session] = args;\n const deletedObject = await this.deleteAtLocation(url, {\n session,\n });\n if (!deletedObject) {\n throw new GraffitiErrorNotFound(\"The object has already been deleted\");\n }\n return deletedObject;\n };\n\n put: Graffiti[\"put\"] = async (...args) => {\n const [objectPartial, session] = args;\n if (objectPartial.actor && objectPartial.actor !== session.actor) {\n throw new GraffitiErrorForbidden(\n \"Cannot put an object with a different actor than the session actor\",\n );\n }\n\n if (objectPartial.url) {\n let oldObject: GraffitiObjectBase | undefined;\n try {\n oldObject = await this.get(objectPartial.url, {}, session);\n } catch (e) {\n if (e instanceof GraffitiErrorNotFound) {\n if (!this.options.allowSettingArbitraryUrls) {\n throw new GraffitiErrorNotFound(\n \"The object you are trying to replace does not exist or you are not allowed to see it\",\n );\n }\n } else {\n throw e;\n }\n }\n if (oldObject?.actor !== session.actor) {\n throw new GraffitiErrorForbidden(\n \"The object you are trying to replace is owned by another actor\",\n );\n }\n }\n\n const lastModified =\n ((this.options.allowSettinngLastModified ?? false) &&\n objectPartial.lastModified) ||\n new Date().getTime();\n\n const object: GraffitiObjectWithTombstone = {\n value: objectPartial.value,\n channels: objectPartial.channels,\n allowed: objectPartial.allowed,\n url: objectPartial.url ?? this.origin + randomBase64(),\n actor: session.actor,\n tombstone: false,\n lastModified,\n };\n\n await (\n await this.db\n ).put({\n _id: this.docId(object),\n ...object,\n });\n\n // Delete the old object\n const previousObject = await this.deleteAtLocation(object, {\n keepLatest: true,\n });\n if (previousObject) {\n return previousObject;\n } else {\n return {\n ...object,\n value: {},\n channels: [],\n allowed: [],\n tombstone: true,\n };\n }\n };\n\n patch: Graffiti[\"patch\"] = async (...args) => {\n const [patch, url, session] = args;\n let originalObject: GraffitiObjectBase;\n try {\n originalObject = await this.get(url, {}, session);\n } catch (e) {\n if (e instanceof GraffitiErrorNotFound) {\n throw new GraffitiErrorNotFound(\n \"The object you are trying to patch does not exist or you are not allowed to see it\",\n );\n } else {\n throw e;\n }\n }\n if (originalObject.actor !== session.actor) {\n throw new GraffitiErrorForbidden(\n \"The object you are trying to patch is owned by another actor\",\n );\n }\n\n // Patch it outside of the database\n const patchObject: GraffitiObjectBase = { ...originalObject };\n for (const prop of [\"value\", \"channels\", \"allowed\"] as const) {\n applyGraffitiPatch(await this.applyPatch, prop, patch, patchObject);\n }\n\n // Make sure the value is an object\n if (\n typeof patchObject.value !== \"object\" ||\n Array.isArray(patchObject.value) ||\n !patchObject.value\n ) {\n throw new GraffitiErrorPatchError(\"value is no longer an object\");\n }\n\n // Make sure the channels are an array of strings\n if (\n !Array.isArray(patchObject.channels) ||\n !patchObject.channels.every((channel) => typeof channel === \"string\")\n ) {\n throw new GraffitiErrorPatchError(\n \"channels are no longer an array of strings\",\n );\n }\n\n // Make sure the allowed list is an array of strings or undefined\n if (\n patchObject.allowed &&\n (!Array.isArray(patchObject.allowed) ||\n !patchObject.allowed.every((allowed) => typeof allowed === \"string\"))\n ) {\n throw new GraffitiErrorPatchError(\n \"allowed list is not an array of strings\",\n );\n }\n\n patchObject.lastModified = new Date().getTime();\n await (\n await this.db\n ).put({\n ...patchObject,\n tombstone: false,\n _id: this.docId(patchObject),\n });\n\n // Delete the old object\n await this.deleteAtLocation(patchObject, {\n keepLatest: true,\n });\n\n return {\n ...originalObject,\n lastModified: patchObject.lastModified,\n };\n };\n\n protected queryLastModifiedSuffixes(\n schema: JSONSchema,\n lastModified?: number,\n ) {\n // Use the index for queries over ranges of lastModified\n let startKeySuffix = \"\";\n let endKeySuffix = \"\\uffff\";\n if (\n typeof schema === \"object\" &&\n schema.properties?.lastModified &&\n typeof schema.properties.lastModified === \"object\"\n ) {\n const lastModifiedSchema = schema.properties.lastModified;\n\n const minimum =\n lastModified && lastModifiedSchema.minimum\n ? Math.max(lastModified, lastModifiedSchema.minimum)\n : (lastModified ?? lastModifiedSchema.minimum);\n const exclusiveMinimum = lastModifiedSchema.exclusiveMinimum;\n\n let intMinimum: number | undefined;\n if (exclusiveMinimum !== undefined) {\n intMinimum = Math.ceil(exclusiveMinimum);\n intMinimum === exclusiveMinimum && intMinimum++;\n } else if (minimum !== undefined) {\n intMinimum = Math.ceil(minimum);\n }\n\n if (intMinimum !== undefined) {\n startKeySuffix = intMinimum.toString().padStart(15, \"0\");\n }\n\n const maximum = lastModifiedSchema.maximum;\n const exclusiveMaximum = lastModifiedSchema.exclusiveMaximum;\n\n let intMaximum: number | undefined;\n if (exclusiveMaximum !== undefined) {\n intMaximum = Math.floor(exclusiveMaximum);\n intMaximum === exclusiveMaximum && intMaximum--;\n } else if (maximum !== undefined) {\n intMaximum = Math.floor(maximum);\n }\n\n if (intMaximum !== undefined) {\n endKeySuffix = intMaximum.toString().padStart(15, \"0\");\n }\n }\n return {\n startKeySuffix,\n endKeySuffix,\n };\n }\n\n protected async *streamObjects<Schema extends JSONSchema>(\n index: string,\n startkey: string,\n endkey: string,\n validate: ReturnType<typeof compileGraffitiObjectSchema<Schema>>,\n session: GraffitiSession | undefined | null,\n ifModifiedSince: number | undefined,\n channels?: string[],\n processedIds?: Set<string>,\n ): AsyncGenerator<GraffitiObjectStreamContinueEntry<Schema>> {\n const showTombstones = ifModifiedSince !== undefined;\n\n const result = await (\n await this.db\n ).query<GraffitiObjectWithTombstone>(index, {\n startkey,\n endkey,\n include_docs: true,\n });\n\n for (const row of result.rows) {\n const doc = row.doc;\n if (!doc) continue;\n\n if (processedIds?.has(doc._id)) continue;\n processedIds?.add(doc._id);\n\n if (!showTombstones && doc.tombstone) continue;\n\n const object = this.extractGraffitiObject(doc);\n\n if (channels) {\n if (!isActorAllowedGraffitiObject(object, session)) continue;\n maskGraffitiObject(object, channels, session);\n }\n\n if (!validate(object)) continue;\n\n yield doc.tombstone\n ? {\n tombstone: true,\n object: {\n url: object.url,\n lastModified: object.lastModified,\n },\n }\n : { object };\n }\n }\n\n protected async *discoverMeta<Schema extends JSONSchema>(\n args: Parameters<typeof Graffiti.prototype.discover<Schema>>,\n ifModifiedSince?: number,\n ): AsyncGenerator<\n GraffitiObjectStreamContinueEntry<Schema>,\n number | undefined\n > {\n const [channels, schema, session] = args;\n const validate = compileGraffitiObjectSchema(await this.ajv, schema);\n const { startKeySuffix, endKeySuffix } = this.queryLastModifiedSuffixes(\n schema,\n ifModifiedSince,\n );\n\n const processedIds = new Set<string>();\n\n const startTime = new Date().getTime();\n\n for (const channel of channels) {\n const keyPrefix = encodeURIComponent(channel) + \"/\";\n const startkey = keyPrefix + startKeySuffix;\n const endkey = keyPrefix + endKeySuffix;\n\n const iterator = this.streamObjects<Schema>(\n \"indexes/objectsPerChannelAndLastModified\",\n startkey,\n endkey,\n validate,\n session,\n ifModifiedSince,\n channels,\n processedIds,\n );\n\n for await (const result of iterator) yield result;\n }\n\n // Subtract a minute to make sure we don't miss any objects\n return startTime - LAST_MODIFIED_BUFFER;\n }\n\n protected async *recoverOrphansMeta<Schema extends JSONSchema>(\n args: Parameters<typeof Graffiti.prototype.recoverOrphans<Schema>>,\n ifModifiedSince?: number,\n ): AsyncGenerator<\n GraffitiObjectStreamContinueEntry<Schema>,\n number | undefined\n > {\n const [schema, session] = args;\n const { startKeySuffix, endKeySuffix } = this.queryLastModifiedSuffixes(\n schema,\n ifModifiedSince,\n );\n const keyPrefix = encodeURIComponent(session.actor) + \"/\";\n const startkey = keyPrefix + startKeySuffix;\n const endkey = keyPrefix + endKeySuffix;\n\n const validate = compileGraffitiObjectSchema(await this.ajv, schema);\n\n const startTime = new Date().getTime();\n\n const iterator = this.streamObjects<Schema>(\n \"indexes/orphansPerActorAndLastModified\",\n startkey,\n endkey,\n validate,\n session,\n ifModifiedSince,\n );\n\n for await (const result of iterator) yield result;\n\n return startTime - LAST_MODIFIED_BUFFER;\n }\n\n protected async *discoverContinue<Schema extends JSONSchema>(\n args: Parameters<typeof Graffiti.prototype.discover<Schema>>,\n ifModifiedSince?: number,\n ): GraffitiObjectStreamContinue<Schema> {\n const iterator = this.discoverMeta(args, ifModifiedSince);\n\n while (true) {\n const result = await iterator.next();\n if (result.done) {\n const ifModifiedSince = result.value;\n return {\n continue: () => this.discoverContinue<Schema>(args, ifModifiedSince),\n cursor: \"\",\n };\n }\n yield result.value;\n }\n }\n\n discover: Graffiti[\"discover\"] = (...args) => {\n const iterator = this.discoverMeta(args);\n\n const this_ = this;\n return (async function* () {\n while (true) {\n const result = await iterator.next();\n if (result.done) {\n return {\n continue: () =>\n this_.discoverContinue<(typeof args)[1]>(args, result.value),\n cursor: \"\",\n };\n }\n // Make sure to filter out tombstones\n if (result.value.tombstone) continue;\n yield result.value;\n }\n })();\n };\n\n protected async *recoverContinue<Schema extends JSONSchema>(\n args: Parameters<typeof Graffiti.prototype.recoverOrphans<Schema>>,\n ifModifiedSince?: number,\n ): GraffitiObjectStreamContinue<Schema> {\n const iterator = this.recoverOrphansMeta(args, ifModifiedSince);\n\n while (true) {\n const result = await iterator.next();\n if (result.done) {\n const ifModifiedSince = result.value;\n return {\n continue: () => this.recoverContinue<Schema>(args, ifModifiedSince),\n cursor: \"\",\n };\n }\n yield result.value;\n }\n }\n\n recoverOrphans: Graffiti[\"recoverOrphans\"] = (...args) => {\n const iterator = this.recoverOrphansMeta(args);\n\n const this_ = this;\n return (async function* () {\n while (true) {\n const result = await iterator.next();\n if (result.done) {\n return {\n continue: () =>\n this_.recoverContinue<(typeof args)[0]>(args, result.value),\n cursor: \"\",\n };\n }\n // Make sure to filter out tombstones\n if (result.value.tombstone) continue;\n yield result.value;\n }\n })();\n };\n\n channelStats: Graffiti[\"channelStats\"] = (session) => {\n const this_ = this;\n return (async function* () {\n const keyPrefix = encodeURIComponent(session.actor) + \"/\";\n const result = await (\n await this_.db\n ).query(\"indexes/channelStatsPerActor\", {\n startkey: keyPrefix,\n endkey: keyPrefix + \"\\uffff\",\n reduce: true,\n group: true,\n });\n for (const row of result.rows) {\n const channelEncoded = row.key.split(\"/\")[1];\n if (typeof channelEncoded !== \"string\") continue;\n const { count, max: lastModified } = row.value;\n if (typeof count !== \"number\" || typeof lastModified !== \"number\")\n continue;\n yield {\n value: {\n channel: decodeURIComponent(channelEncoded),\n count,\n lastModified,\n },\n };\n }\n })();\n };\n\n continueObjectStream: Graffiti[\"continueObjectStream\"] = (\n cursor,\n session,\n ) => {\n // TODO: Implement this\n throw new GraffitiErrorNotFound(\"Cursor not found\");\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["doc", "ifModifiedSince"]
|
|
7
7
|
}
|
package/dist/cjs/index.js
CHANGED
|
@@ -36,6 +36,7 @@ class GraffitiLocal extends import_api.Graffiti {
|
|
|
36
36
|
discover;
|
|
37
37
|
recoverOrphans;
|
|
38
38
|
channelStats;
|
|
39
|
+
continueObjectStream;
|
|
39
40
|
constructor(options) {
|
|
40
41
|
super();
|
|
41
42
|
const graffitiPouchDbBase = new import_database.GraffitiLocalDatabase(options);
|
|
@@ -46,6 +47,16 @@ class GraffitiLocal extends import_api.Graffiti {
|
|
|
46
47
|
this.discover = graffitiPouchDbBase.discover.bind(graffitiPouchDbBase);
|
|
47
48
|
this.recoverOrphans = graffitiPouchDbBase.recoverOrphans.bind(graffitiPouchDbBase);
|
|
48
49
|
this.channelStats = graffitiPouchDbBase.channelStats.bind(graffitiPouchDbBase);
|
|
50
|
+
this.continueObjectStream = graffitiPouchDbBase.continueObjectStream.bind(graffitiPouchDbBase);
|
|
49
51
|
}
|
|
50
52
|
}
|
|
53
|
+
function myFunction(flag) {
|
|
54
|
+
if (!flag) {
|
|
55
|
+
return "Hello";
|
|
56
|
+
} else {
|
|
57
|
+
return 42;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const a = myFunction(false);
|
|
61
|
+
const b = myFunction(true);
|
|
51
62
|
//# sourceMappingURL=index.js.map
|
package/dist/cjs/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["import { Graffiti } from \"@graffiti-garden/api\";\nimport { GraffitiLocalSessionManager } from \"./session-manager.js\";\nimport {\n GraffitiLocalDatabase,\n type GraffitiLocalOptions,\n} from \"./database.js\";\n\nexport type { GraffitiLocalOptions };\n\n/**\n * A local implementation of the [Graffiti API](https://api.graffiti.garden/classes/Graffiti.html)\n * based on [PouchDB](https://pouchdb.com/). PouchDb will automatically persist data in a local\n * database, either in the browser or in Node.js.\n * It can also be configured to work with an external [CouchDB](https://couchdb.apache.org/) server,\n * although using it with a remote server will not be secure.\n */\nexport class GraffitiLocal extends Graffiti {\n protected sessionManagerLocal = new GraffitiLocalSessionManager();\n login = this.sessionManagerLocal.login.bind(this.sessionManagerLocal);\n logout = this.sessionManagerLocal.logout.bind(this.sessionManagerLocal);\n sessionEvents = this.sessionManagerLocal.sessionEvents;\n\n put: Graffiti[\"put\"];\n get: Graffiti[\"get\"];\n patch: Graffiti[\"patch\"];\n delete: Graffiti[\"delete\"];\n discover: Graffiti[\"discover\"];\n recoverOrphans: Graffiti[\"recoverOrphans\"];\n channelStats: Graffiti[\"channelStats\"];\n\n constructor(options?: GraffitiLocalOptions) {\n super();\n\n const graffitiPouchDbBase = new GraffitiLocalDatabase(options);\n\n this.put = graffitiPouchDbBase.put.bind(graffitiPouchDbBase);\n this.get = graffitiPouchDbBase.get.bind(graffitiPouchDbBase);\n this.patch = graffitiPouchDbBase.patch.bind(graffitiPouchDbBase);\n this.delete = graffitiPouchDbBase.delete.bind(graffitiPouchDbBase);\n this.discover = graffitiPouchDbBase.discover.bind(graffitiPouchDbBase);\n this.recoverOrphans =\n graffitiPouchDbBase.recoverOrphans.bind(graffitiPouchDbBase);\n this.channelStats =\n graffitiPouchDbBase.channelStats.bind(graffitiPouchDbBase);\n }\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,
|
|
4
|
+
"sourcesContent": ["import { Graffiti, type GraffitiSession } from \"@graffiti-garden/api\";\nimport { GraffitiLocalSessionManager } from \"./session-manager.js\";\nimport {\n GraffitiLocalDatabase,\n type GraffitiLocalOptions,\n} from \"./database.js\";\n\nexport type { GraffitiLocalOptions };\n\n/**\n * A local implementation of the [Graffiti API](https://api.graffiti.garden/classes/Graffiti.html)\n * based on [PouchDB](https://pouchdb.com/). PouchDb will automatically persist data in a local\n * database, either in the browser or in Node.js.\n * It can also be configured to work with an external [CouchDB](https://couchdb.apache.org/) server,\n * although using it with a remote server will not be secure.\n */\nexport class GraffitiLocal extends Graffiti {\n protected sessionManagerLocal = new GraffitiLocalSessionManager();\n login = this.sessionManagerLocal.login.bind(this.sessionManagerLocal);\n logout = this.sessionManagerLocal.logout.bind(this.sessionManagerLocal);\n sessionEvents = this.sessionManagerLocal.sessionEvents;\n\n put: Graffiti[\"put\"];\n get: Graffiti[\"get\"];\n patch: Graffiti[\"patch\"];\n delete: Graffiti[\"delete\"];\n discover: Graffiti[\"discover\"];\n recoverOrphans: Graffiti[\"recoverOrphans\"];\n channelStats: Graffiti[\"channelStats\"];\n continueObjectStream: Graffiti[\"continueObjectStream\"];\n\n constructor(options?: GraffitiLocalOptions) {\n super();\n\n const graffitiPouchDbBase = new GraffitiLocalDatabase(options);\n\n this.put = graffitiPouchDbBase.put.bind(graffitiPouchDbBase);\n this.get = graffitiPouchDbBase.get.bind(graffitiPouchDbBase);\n this.patch = graffitiPouchDbBase.patch.bind(graffitiPouchDbBase);\n this.delete = graffitiPouchDbBase.delete.bind(graffitiPouchDbBase);\n this.discover = graffitiPouchDbBase.discover.bind(graffitiPouchDbBase);\n this.recoverOrphans =\n graffitiPouchDbBase.recoverOrphans.bind(graffitiPouchDbBase);\n this.channelStats =\n graffitiPouchDbBase.channelStats.bind(graffitiPouchDbBase);\n this.continueObjectStream =\n graffitiPouchDbBase.continueObjectStream.bind(graffitiPouchDbBase);\n }\n}\n\nfunction myFunction<T extends boolean>(\n flag: T,\n): T extends true ? string : number {\n if (!flag) {\n return \"Hello\" as T extends true ? string : number;\n } else {\n return 42 as T extends true ? string : number;\n }\n}\n// Usage\nconst a = myFunction(false); // Type is number\nconst b = myFunction(true); // Type is string\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAA+C;AAC/C,6BAA4C;AAC5C,sBAGO;AAWA,MAAM,sBAAsB,oBAAS;AAAA,EAChC,sBAAsB,IAAI,mDAA4B;AAAA,EAChE,QAAQ,KAAK,oBAAoB,MAAM,KAAK,KAAK,mBAAmB;AAAA,EACpE,SAAS,KAAK,oBAAoB,OAAO,KAAK,KAAK,mBAAmB;AAAA,EACtE,gBAAgB,KAAK,oBAAoB;AAAA,EAEzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA,YAAY,SAAgC;AAC1C,UAAM;AAEN,UAAM,sBAAsB,IAAI,sCAAsB,OAAO;AAE7D,SAAK,MAAM,oBAAoB,IAAI,KAAK,mBAAmB;AAC3D,SAAK,MAAM,oBAAoB,IAAI,KAAK,mBAAmB;AAC3D,SAAK,QAAQ,oBAAoB,MAAM,KAAK,mBAAmB;AAC/D,SAAK,SAAS,oBAAoB,OAAO,KAAK,mBAAmB;AACjE,SAAK,WAAW,oBAAoB,SAAS,KAAK,mBAAmB;AACrE,SAAK,iBACH,oBAAoB,eAAe,KAAK,mBAAmB;AAC7D,SAAK,eACH,oBAAoB,aAAa,KAAK,mBAAmB;AAC3D,SAAK,uBACH,oBAAoB,qBAAqB,KAAK,mBAAmB;AAAA,EACrE;AACF;AAEA,SAAS,WACP,MACkC;AAClC,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,EACT,OAAO;AACL,WAAO;AAAA,EACT;AACF;AAEA,MAAM,IAAI,WAAW,KAAK;AAC1B,MAAM,IAAI,WAAW,IAAI;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|