@graffiti-garden/implementation-local 0.6.2 → 0.6.4

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/src/database.ts CHANGED
@@ -63,9 +63,17 @@ export interface GraffitiLocalOptions {
63
63
  * If not provided, an internal instance will be created.
64
64
  */
65
65
  ajv?: Ajv;
66
+ /**
67
+ * Wait at least this long (in milliseconds) before continuing a stream.
68
+ * A basic form of rate limiting. Defaults to 1 seconds.
69
+ */
70
+ continueBuffer?: number;
66
71
  }
67
72
 
68
73
  const DEFAULT_ORIGIN = "graffiti:local:";
74
+
75
+ // During stream continuations, return objects
76
+ // that have possibly already been seen over this window
69
77
  const LAST_MODIFIED_BUFFER = 60000;
70
78
 
71
79
  type GraffitiObjectWithTombstone = GraffitiObjectBase & { tombstone: boolean };
@@ -240,6 +248,9 @@ export class GraffitiLocalDatabase
240
248
  get: Graffiti["get"] = async (...args) => {
241
249
  const [urlObject, schema, session] = args;
242
250
 
251
+ // TODO: Rate limit getting the same object
252
+ // over and over
253
+
243
254
  const docsAll = await this.allDocsAtLocation(urlObject);
244
255
 
245
256
  // Filter out ones not allowed
@@ -596,7 +607,10 @@ export class GraffitiLocalDatabase
596
607
  channels?: string[],
597
608
  processedIds?: Set<string>,
598
609
  ): AsyncGenerator<GraffitiObjectStreamContinueEntry<Schema>> {
599
- const showTombstones = ifModifiedSince !== undefined;
610
+ if (ifModifiedSince !== undefined) {
611
+ // Subtract a minute to make sure we don't miss any objects
612
+ ifModifiedSince -= LAST_MODIFIED_BUFFER;
613
+ }
600
614
 
601
615
  const result = await (
602
616
  await this.db
@@ -613,7 +627,8 @@ export class GraffitiLocalDatabase
613
627
  if (processedIds?.has(doc._id)) continue;
614
628
  processedIds?.add(doc._id);
615
629
 
616
- if (!showTombstones && doc.tombstone) continue;
630
+ // If this is not a continuation, skip tombstones
631
+ if (ifModifiedSince === undefined && doc.tombstone) continue;
617
632
 
618
633
  const object = this.extractGraffitiObject(doc);
619
634
 
@@ -636,6 +651,19 @@ export class GraffitiLocalDatabase
636
651
  }
637
652
  }
638
653
 
654
+ protected async waitToContinue(ifModifiedSince: number | undefined) {
655
+ if (ifModifiedSince === undefined) return;
656
+ const continueBuffer = this.options.continueBuffer ?? 1000;
657
+ const timeElapsedSinceContinue = Date.now() - ifModifiedSince;
658
+ if (timeElapsedSinceContinue < continueBuffer) {
659
+ // Continue was called too soon,
660
+ // wait a bit before continuing
661
+ await new Promise((resolve) =>
662
+ setTimeout(resolve, continueBuffer - timeElapsedSinceContinue),
663
+ );
664
+ }
665
+ }
666
+
639
667
  protected async *discoverMeta<Schema extends JSONSchema>(
640
668
  args: Parameters<typeof Graffiti.prototype.discover<Schema>>,
641
669
  ifModifiedSince?: number,
@@ -643,6 +671,8 @@ export class GraffitiLocalDatabase
643
671
  GraffitiObjectStreamContinueEntry<Schema>,
644
672
  number | undefined
645
673
  > {
674
+ await this.waitToContinue(ifModifiedSince);
675
+
646
676
  const [channels, schema, session] = args;
647
677
  const validate = compileGraffitiObjectSchema(await this.ajv, schema);
648
678
  const { startKeySuffix, endKeySuffix } = this.queryLastModifiedSuffixes(
@@ -673,8 +703,7 @@ export class GraffitiLocalDatabase
673
703
  for await (const result of iterator) yield result;
674
704
  }
675
705
 
676
- // Subtract a minute to make sure we don't miss any objects
677
- return startTime - LAST_MODIFIED_BUFFER;
706
+ return startTime;
678
707
  }
679
708
 
680
709
  protected async *recoverOrphansMeta<Schema extends JSONSchema>(
@@ -684,6 +713,8 @@ export class GraffitiLocalDatabase
684
713
  GraffitiObjectStreamContinueEntry<Schema>,
685
714
  number | undefined
686
715
  > {
716
+ await this.waitToContinue(ifModifiedSince);
717
+
687
718
  const [schema, session] = args;
688
719
  const { startKeySuffix, endKeySuffix } = this.queryLastModifiedSuffixes(
689
720
  schema,
@@ -708,7 +739,7 @@ export class GraffitiLocalDatabase
708
739
 
709
740
  for await (const result of iterator) yield result;
710
741
 
711
- return startTime - LAST_MODIFIED_BUFFER;
742
+ return startTime;
712
743
  }
713
744
 
714
745
  protected discoverCursor(