@graffiti-garden/implementation-decentralized 0.0.2 → 0.0.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.
Files changed (48) hide show
  1. package/dist/1-services/4-inboxes-tests.d.ts.map +1 -1
  2. package/dist/1-services/4-inboxes.d.ts +3 -3
  3. package/dist/1-services/4-inboxes.d.ts.map +1 -1
  4. package/dist/3-protocol/3-object-encoding.d.ts.map +1 -1
  5. package/dist/3-protocol/4-graffiti.d.ts +2 -1
  6. package/dist/3-protocol/4-graffiti.d.ts.map +1 -1
  7. package/dist/3-protocol/login-dialog.html.d.ts +1 -1
  8. package/dist/3-protocol/login-dialog.html.d.ts.map +1 -1
  9. package/dist/browser/index.js +7 -7
  10. package/dist/browser/index.js.map +3 -3
  11. package/dist/browser/login-dialog.html-VTDKJZBG.js +44 -0
  12. package/dist/browser/login-dialog.html-VTDKJZBG.js.map +7 -0
  13. package/dist/browser/{style-YUTCEBZV-RWYJV575.js → style-RMTPI5KV-Y5KAOOZR.js} +19 -36
  14. package/dist/browser/style-RMTPI5KV-Y5KAOOZR.js.map +7 -0
  15. package/dist/cjs/1-services/4-inboxes-tests.js +2 -0
  16. package/dist/cjs/1-services/4-inboxes-tests.js.map +2 -2
  17. package/dist/cjs/1-services/4-inboxes.js +17 -8
  18. package/dist/cjs/1-services/4-inboxes.js.map +2 -2
  19. package/dist/cjs/3-protocol/1-sessions.js +1 -1
  20. package/dist/cjs/3-protocol/1-sessions.js.map +2 -2
  21. package/dist/cjs/3-protocol/3-object-encoding.js +3 -2
  22. package/dist/cjs/3-protocol/3-object-encoding.js.map +2 -2
  23. package/dist/cjs/3-protocol/4-graffiti.js +193 -135
  24. package/dist/cjs/3-protocol/4-graffiti.js.map +3 -3
  25. package/dist/cjs/3-protocol/login-dialog.html.js +9 -9
  26. package/dist/cjs/3-protocol/login-dialog.html.js.map +1 -1
  27. package/dist/esm/1-services/4-inboxes-tests.js +2 -0
  28. package/dist/esm/1-services/4-inboxes-tests.js.map +2 -2
  29. package/dist/esm/1-services/4-inboxes.js +19 -9
  30. package/dist/esm/1-services/4-inboxes.js.map +2 -2
  31. package/dist/esm/3-protocol/1-sessions.js +1 -1
  32. package/dist/esm/3-protocol/1-sessions.js.map +2 -2
  33. package/dist/esm/3-protocol/3-object-encoding.js +3 -2
  34. package/dist/esm/3-protocol/3-object-encoding.js.map +2 -2
  35. package/dist/esm/3-protocol/4-graffiti.js +194 -135
  36. package/dist/esm/3-protocol/4-graffiti.js.map +3 -3
  37. package/dist/esm/3-protocol/login-dialog.html.js +9 -9
  38. package/dist/esm/3-protocol/login-dialog.html.js.map +1 -1
  39. package/package.json +7 -7
  40. package/src/1-services/4-inboxes-tests.ts +2 -0
  41. package/src/1-services/4-inboxes.ts +25 -15
  42. package/src/3-protocol/1-sessions.ts +1 -1
  43. package/src/3-protocol/3-object-encoding.ts +4 -2
  44. package/src/3-protocol/4-graffiti.ts +260 -170
  45. package/src/3-protocol/login-dialog.html.ts +9 -9
  46. package/dist/browser/login-dialog.html-XUWYDNNI.js +0 -44
  47. package/dist/browser/login-dialog.html-XUWYDNNI.js.map +0 -7
  48. package/dist/browser/style-YUTCEBZV-RWYJV575.js.map +0 -7
@@ -21,6 +21,7 @@ import { Authorization } from "../1-services/1-authorization";
21
21
  import { StorageBuckets } from "../1-services/3-storage-buckets";
22
22
  import {
23
23
  Inboxes,
24
+ LABELED_MESSAGE_LABEL_KEY,
24
25
  LABELED_MESSAGE_MESSAGE_KEY,
25
26
  MESSAGE_METADATA_KEY,
26
27
  MESSAGE_OBJECT_KEY,
@@ -104,6 +105,7 @@ const MESSAGE_LABEL_UNLABELED = 0;
104
105
  const MESSAGE_LABEL_VALID = 1;
105
106
  const MESSAGE_LABEL_TRASH = 2;
106
107
  const MESSAGE_LABEL_INVALID = 3;
108
+ const CONCURRENCY = 16;
107
109
  class GraffitiDecentralized {
108
110
  dids = new DecentralizedIdentifiers();
109
111
  authorization = new Authorization();
@@ -194,11 +196,7 @@ class GraffitiDecentralized {
194
196
  );
195
197
  input?.setAttribute("value", proposedHandle);
196
198
  input?.addEventListener("focus", () => input?.select());
197
- new Promise((r) => {
198
- setTimeout(() => r(), 0);
199
- }).then(() => {
200
- input?.focus();
201
- });
199
+ setTimeout(() => input?.focus(), 0);
202
200
  template?.querySelector("#graffiti-login-handle-form")?.addEventListener("submit", async (e) => {
203
201
  e.preventDefault();
204
202
  input?.setAttribute("disabled", "true");
@@ -239,11 +237,12 @@ class GraffitiDecentralized {
239
237
  e.preventDefault();
240
238
  this.login_("");
241
239
  });
242
- new Promise((r) => {
243
- setTimeout(() => r(), 0);
244
- }).then(() => {
245
- template?.querySelector("#graffiti-login-new")?.focus();
246
- });
240
+ setTimeout(
241
+ () => template?.querySelector(
242
+ "#graffiti-login-new"
243
+ )?.focus(),
244
+ 0
245
+ );
247
246
  }
248
247
  const createUrl = new URL(this.identityCreatorEndpoint);
249
248
  createUrl.searchParams.set(
@@ -617,14 +616,14 @@ class GraffitiDecentralized {
617
616
  cursor: JSON.stringify({
618
617
  channels,
619
618
  cursors
620
- }),
621
- continue: (session2) => this.discoverMeta(channels, schema, cursors, session2)
619
+ })
622
620
  };
623
621
  }
624
622
  discover = (...args) => {
625
623
  const [channels, schema, session] = args;
626
624
  return this.discoverMeta(channels, schema, {}, session);
627
625
  };
626
+ // @ts-ignore
628
627
  continueDiscover = (...args) => {
629
628
  const [cursor, session] = args;
630
629
  let channels;
@@ -771,150 +770,210 @@ class GraffitiDecentralized {
771
770
  queryArguments.cursor,
772
771
  inboxToken
773
772
  );
773
+ const inFlight = [];
774
+ let doneValue = null;
774
775
  while (true) {
775
- const itResult = await iterator.next();
776
- if (itResult.done) return itResult.value;
777
- const result = itResult.value;
778
- const label = result.l;
779
- if (label !== MESSAGE_LABEL_VALID && label !== MESSAGE_LABEL_UNLABELED)
780
- continue;
781
- const messageId = result.id;
782
- const { o: object, m: metadataBytes, t: receivedTags } = result.m;
783
- let metadata;
784
- try {
785
- const metadataRaw = dagCborDecode(metadataBytes);
786
- metadata = MessageMetadataSchema.parse(metadataRaw);
787
- } catch (e) {
776
+ while (doneValue === null && inFlight.length < CONCURRENCY) {
777
+ const itResult = await iterator.next();
778
+ if (itResult.done) {
779
+ doneValue = itResult.value;
780
+ break;
781
+ }
782
+ const processPromise = this.processOneLabeledMessage(
783
+ inboxEndpoint,
784
+ itResult.value,
785
+ inboxToken,
786
+ recipient
787
+ ).catch((e) => {
788
+ throw e;
789
+ });
790
+ inFlight.push(processPromise);
791
+ }
792
+ const nextProcessedPromise = inFlight.shift();
793
+ if (!nextProcessedPromise) {
794
+ if (doneValue !== null) return doneValue;
795
+ throw new Error("Process queue empty but no return value");
796
+ }
797
+ const processed = await nextProcessedPromise;
798
+ if (processed) yield processed;
799
+ }
800
+ }
801
+ async processOneLabeledMessage(inboxEndpoint, result, inboxToken, recipient) {
802
+ const label = result.l;
803
+ if (label !== MESSAGE_LABEL_VALID && label !== MESSAGE_LABEL_UNLABELED && label !== MESSAGE_LABEL_TRASH)
804
+ return;
805
+ const messageId = result.id;
806
+ const { o: object, m: metadataBytes, t: receivedTags } = result.m;
807
+ let metadata;
808
+ try {
809
+ const metadataRaw = dagCborDecode(metadataBytes);
810
+ metadata = MessageMetadataSchema.parse(metadataRaw);
811
+ } catch (e) {
812
+ this.inboxes.label(
813
+ inboxEndpoint,
814
+ messageId,
815
+ MESSAGE_LABEL_INVALID,
816
+ inboxToken
817
+ );
818
+ return;
819
+ }
820
+ const {
821
+ [MESSAGE_DATA_STORAGE_BUCKET_KEY]: storageBucketKey,
822
+ [MESSAGE_DATA_TOMBSTONED_MESSAGE_ID_KEY]: tombstonedMessageId
823
+ } = metadata;
824
+ const allowedTickets = MESSAGE_DATA_ALLOWED_TICKETS_KEY in metadata ? metadata[MESSAGE_DATA_ALLOWED_TICKETS_KEY] : void 0;
825
+ const announcements = MESSAGE_DATA_ANNOUNCEMENTS_KEY in metadata ? metadata[MESSAGE_DATA_ANNOUNCEMENTS_KEY] : void 0;
826
+ if (label === MESSAGE_LABEL_VALID) {
827
+ return {
828
+ messageId,
829
+ object,
830
+ storageBucketKey,
831
+ allowedTickets,
832
+ tags: receivedTags,
833
+ announcements
834
+ };
835
+ } else if (label === MESSAGE_LABEL_TRASH) {
836
+ if (!tombstonedMessageId) return;
837
+ const past = await this.inboxes.get(
838
+ inboxEndpoint,
839
+ tombstonedMessageId,
840
+ inboxToken
841
+ );
842
+ if (!past || past[LABELED_MESSAGE_MESSAGE_KEY][MESSAGE_OBJECT_KEY].url !== object.url)
843
+ return;
844
+ if (past[LABELED_MESSAGE_LABEL_KEY] !== MESSAGE_LABEL_TRASH) {
788
845
  this.inboxes.label(
789
846
  inboxEndpoint,
790
- messageId,
791
- MESSAGE_LABEL_INVALID,
847
+ tombstonedMessageId,
848
+ MESSAGE_LABEL_TRASH,
792
849
  inboxToken
793
850
  );
794
- continue;
795
- }
796
- const {
797
- [MESSAGE_DATA_STORAGE_BUCKET_KEY]: storageBucketKey,
798
- [MESSAGE_DATA_TOMBSTONED_MESSAGE_ID_KEY]: tombstonedMessageId
799
- } = metadata;
800
- const allowedTickets = MESSAGE_DATA_ALLOWED_TICKETS_KEY in metadata ? metadata[MESSAGE_DATA_ALLOWED_TICKETS_KEY] : void 0;
801
- const announcements = MESSAGE_DATA_ANNOUNCEMENTS_KEY in metadata ? metadata[MESSAGE_DATA_ANNOUNCEMENTS_KEY] : void 0;
802
- if (label === MESSAGE_LABEL_VALID) {
803
- yield {
804
- messageId,
805
- object,
806
- storageBucketKey,
807
- allowedTickets,
808
- tags: receivedTags,
809
- announcements
810
- };
811
- continue;
812
851
  }
813
- let validationError = void 0;
814
- try {
815
- const actor = object.actor;
816
- const actorDocument = await this.dids.resolve(actor);
817
- const storageBucketService = actorDocument?.service?.find(
818
- (service) => service.id === DID_SERVICE_ID_GRAFFITI_STORAGE_BUCKET && service.type === DID_SERVICE_TYPE_GRAFFITI_STORAGE_BUCKET
852
+ return {
853
+ messageId,
854
+ tombstone: true,
855
+ object,
856
+ storageBucketKey,
857
+ allowedTickets,
858
+ tags: receivedTags,
859
+ announcements
860
+ };
861
+ }
862
+ let validationError = void 0;
863
+ try {
864
+ const actor = object.actor;
865
+ const actorDocument = await this.dids.resolve(actor);
866
+ const storageBucketService = actorDocument?.service?.find(
867
+ (service) => service.id === DID_SERVICE_ID_GRAFFITI_STORAGE_BUCKET && service.type === DID_SERVICE_TYPE_GRAFFITI_STORAGE_BUCKET
868
+ );
869
+ if (!storageBucketService) {
870
+ throw new GraffitiErrorNotFound(
871
+ `Actor ${actor} has no storage bucket service`
819
872
  );
820
- if (!storageBucketService) {
821
- throw new GraffitiErrorNotFound(
822
- `Actor ${actor} has no storage bucket service`
823
- );
824
- }
825
- if (typeof storageBucketService.serviceEndpoint !== "string") {
826
- throw new GraffitiErrorNotFound(
827
- `Actor ${actor} does not have a valid storage bucket endpoint`
828
- );
829
- }
830
- const storageBucketEndpoint = storageBucketService.serviceEndpoint;
831
- const objectBytes = await this.storageBuckets.get(
832
- storageBucketEndpoint,
833
- storageBucketKey,
834
- MAX_OBJECT_SIZE_BYTES
873
+ }
874
+ if (typeof storageBucketService.serviceEndpoint !== "string") {
875
+ throw new GraffitiErrorNotFound(
876
+ `Actor ${actor} does not have a valid storage bucket endpoint`
835
877
  );
836
- if (MESSAGE_DATA_ALLOWED_TICKET_KEY in metadata && !recipient) {
837
- throw new GraffitiErrorForbidden(
838
- `Recipient is required when allowed ticket is present`
839
- );
840
- }
841
- const privateObjectInfo = allowedTickets ? { allowedTickets } : MESSAGE_DATA_ALLOWED_TICKET_KEY in metadata ? {
842
- recipient: recipient ?? "null",
843
- allowedTicket: metadata[MESSAGE_DATA_ALLOWED_TICKET_KEY],
844
- allowedIndex: metadata[MESSAGE_DATA_ALLOWED_TICKET_INDEX_KEY]
845
- } : void 0;
846
- await this.objectEncoding.validate(
847
- object,
848
- receivedTags,
849
- objectBytes,
850
- privateObjectInfo
878
+ }
879
+ const storageBucketEndpoint = storageBucketService.serviceEndpoint;
880
+ const objectBytes = await this.storageBuckets.get(
881
+ storageBucketEndpoint,
882
+ storageBucketKey,
883
+ MAX_OBJECT_SIZE_BYTES
884
+ );
885
+ if (MESSAGE_DATA_ALLOWED_TICKET_KEY in metadata && !recipient) {
886
+ throw new GraffitiErrorForbidden(
887
+ `Recipient is required when allowed ticket is present`
851
888
  );
852
- } catch (e) {
853
- validationError = e;
854
889
  }
855
- if (tombstonedMessageId) {
856
- if (validationError instanceof GraffitiErrorNotFound) {
857
- this.inboxes.get(inboxEndpoint, tombstonedMessageId, inboxToken).then((result2) => {
858
- if (result2 && result2[LABELED_MESSAGE_MESSAGE_KEY][MESSAGE_OBJECT_KEY].url === object.url) {
859
- this.inboxes.label(
860
- inboxEndpoint,
861
- tombstonedMessageId,
862
- MESSAGE_LABEL_TRASH,
863
- inboxToken
864
- );
865
- }
890
+ const privateObjectInfo = allowedTickets ? { allowedTickets } : MESSAGE_DATA_ALLOWED_TICKET_KEY in metadata ? {
891
+ recipient: recipient ?? "null",
892
+ allowedTicket: metadata[MESSAGE_DATA_ALLOWED_TICKET_KEY],
893
+ allowedIndex: metadata[MESSAGE_DATA_ALLOWED_TICKET_INDEX_KEY]
894
+ } : void 0;
895
+ await this.objectEncoding.validate(
896
+ object,
897
+ receivedTags,
898
+ objectBytes,
899
+ privateObjectInfo
900
+ );
901
+ } catch (e) {
902
+ validationError = e;
903
+ }
904
+ if (tombstonedMessageId) {
905
+ if (validationError instanceof GraffitiErrorNotFound) {
906
+ this.inboxes.get(inboxEndpoint, tombstonedMessageId, inboxToken).then((result2) => {
907
+ if (
908
+ // Make sure that it actually references the object being deleted
909
+ result2 && result2[LABELED_MESSAGE_MESSAGE_KEY][MESSAGE_OBJECT_KEY].url === object.url && // And that the object is not already marked as trash
910
+ result2[LABELED_MESSAGE_LABEL_KEY] !== MESSAGE_LABEL_TRASH
911
+ ) {
866
912
  this.inboxes.label(
867
913
  inboxEndpoint,
868
- messageId,
914
+ tombstonedMessageId,
869
915
  MESSAGE_LABEL_TRASH,
870
916
  inboxToken
871
917
  );
872
- });
873
- yield {
874
- messageId,
875
- tombstone: true,
876
- object,
877
- storageBucketKey,
878
- allowedTickets,
879
- tags: receivedTags,
880
- announcements
881
- };
882
- } else {
883
- console.error("Recieved an incorrect object");
884
- console.error(validationError);
918
+ }
885
919
  this.inboxes.label(
886
920
  inboxEndpoint,
887
921
  messageId,
888
- MESSAGE_LABEL_INVALID,
922
+ MESSAGE_LABEL_TRASH,
889
923
  inboxToken
890
924
  );
891
- }
925
+ });
926
+ return {
927
+ messageId,
928
+ tombstone: true,
929
+ object,
930
+ storageBucketKey,
931
+ allowedTickets,
932
+ tags: receivedTags,
933
+ announcements
934
+ };
892
935
  } else {
893
- if (validationError === void 0) {
894
- this.inboxes.label(
895
- inboxEndpoint,
896
- messageId,
897
- MESSAGE_LABEL_VALID,
898
- inboxToken
899
- );
900
- yield {
901
- messageId,
902
- object,
903
- storageBucketKey,
904
- tags: receivedTags,
905
- allowedTickets,
906
- announcements
907
- };
908
- } else {
909
- console.error("Recieved an incorrect object");
910
- console.error(validationError);
911
- this.inboxes.label(
912
- inboxEndpoint,
913
- messageId,
914
- MESSAGE_LABEL_INVALID,
915
- inboxToken
916
- );
917
- }
936
+ console.error("Recieved an incorrect tombstone object");
937
+ console.error(validationError);
938
+ this.inboxes.label(
939
+ inboxEndpoint,
940
+ messageId,
941
+ MESSAGE_LABEL_INVALID,
942
+ inboxToken
943
+ );
944
+ }
945
+ } else {
946
+ if (validationError === void 0) {
947
+ this.inboxes.label(
948
+ inboxEndpoint,
949
+ messageId,
950
+ MESSAGE_LABEL_VALID,
951
+ inboxToken
952
+ );
953
+ return {
954
+ messageId,
955
+ object,
956
+ storageBucketKey,
957
+ tags: receivedTags,
958
+ allowedTickets,
959
+ announcements
960
+ };
961
+ } else if (validationError instanceof GraffitiErrorNotFound) {
962
+ this.inboxes.label(
963
+ inboxEndpoint,
964
+ messageId,
965
+ MESSAGE_LABEL_TRASH,
966
+ inboxToken
967
+ );
968
+ } else {
969
+ console.error("Recieved an incorrect object");
970
+ console.error(validationError);
971
+ this.inboxes.label(
972
+ inboxEndpoint,
973
+ messageId,
974
+ MESSAGE_LABEL_INVALID,
975
+ inboxToken
976
+ );
918
977
  }
919
978
  }
920
979
  }