@graffiti-garden/implementation-decentralized 0.0.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.
Files changed (193) hide show
  1. package/LICENSE +674 -0
  2. package/dist/1-services/1-authorization.d.ts +37 -0
  3. package/dist/1-services/1-authorization.d.ts.map +1 -0
  4. package/dist/1-services/2-dids-tests.d.ts +2 -0
  5. package/dist/1-services/2-dids-tests.d.ts.map +1 -0
  6. package/dist/1-services/2-dids.d.ts +9 -0
  7. package/dist/1-services/2-dids.d.ts.map +1 -0
  8. package/dist/1-services/3-storage-buckets-tests.d.ts +2 -0
  9. package/dist/1-services/3-storage-buckets-tests.d.ts.map +1 -0
  10. package/dist/1-services/3-storage-buckets.d.ts +11 -0
  11. package/dist/1-services/3-storage-buckets.d.ts.map +1 -0
  12. package/dist/1-services/4-inboxes-tests.d.ts +2 -0
  13. package/dist/1-services/4-inboxes-tests.d.ts.map +1 -0
  14. package/dist/1-services/4-inboxes.d.ts +87 -0
  15. package/dist/1-services/4-inboxes.d.ts.map +1 -0
  16. package/dist/1-services/utilities.d.ts +7 -0
  17. package/dist/1-services/utilities.d.ts.map +1 -0
  18. package/dist/2-primitives/1-string-encoding-tests.d.ts +2 -0
  19. package/dist/2-primitives/1-string-encoding-tests.d.ts.map +1 -0
  20. package/dist/2-primitives/1-string-encoding.d.ts +6 -0
  21. package/dist/2-primitives/1-string-encoding.d.ts.map +1 -0
  22. package/dist/2-primitives/2-content-addresses-tests.d.ts +2 -0
  23. package/dist/2-primitives/2-content-addresses-tests.d.ts.map +1 -0
  24. package/dist/2-primitives/2-content-addresses.d.ts +8 -0
  25. package/dist/2-primitives/2-content-addresses.d.ts.map +1 -0
  26. package/dist/2-primitives/3-channel-attestations-tests.d.ts +2 -0
  27. package/dist/2-primitives/3-channel-attestations-tests.d.ts.map +1 -0
  28. package/dist/2-primitives/3-channel-attestations.d.ts +13 -0
  29. package/dist/2-primitives/3-channel-attestations.d.ts.map +1 -0
  30. package/dist/2-primitives/4-allowed-attestations-tests.d.ts +2 -0
  31. package/dist/2-primitives/4-allowed-attestations-tests.d.ts.map +1 -0
  32. package/dist/2-primitives/4-allowed-attestations.d.ts +9 -0
  33. package/dist/2-primitives/4-allowed-attestations.d.ts.map +1 -0
  34. package/dist/3-protocol/1-sessions.d.ts +81 -0
  35. package/dist/3-protocol/1-sessions.d.ts.map +1 -0
  36. package/dist/3-protocol/2-handles-tests.d.ts +2 -0
  37. package/dist/3-protocol/2-handles-tests.d.ts.map +1 -0
  38. package/dist/3-protocol/2-handles.d.ts +13 -0
  39. package/dist/3-protocol/2-handles.d.ts.map +1 -0
  40. package/dist/3-protocol/3-object-encoding-tests.d.ts +2 -0
  41. package/dist/3-protocol/3-object-encoding-tests.d.ts.map +1 -0
  42. package/dist/3-protocol/3-object-encoding.d.ts +43 -0
  43. package/dist/3-protocol/3-object-encoding.d.ts.map +1 -0
  44. package/dist/3-protocol/4-graffiti.d.ts +79 -0
  45. package/dist/3-protocol/4-graffiti.d.ts.map +1 -0
  46. package/dist/3-protocol/login-dialog.html.d.ts +2 -0
  47. package/dist/3-protocol/login-dialog.html.d.ts.map +1 -0
  48. package/dist/browser/ajv-QBSREQSI.js +9 -0
  49. package/dist/browser/ajv-QBSREQSI.js.map +7 -0
  50. package/dist/browser/build-BXWPS7VK.js +2 -0
  51. package/dist/browser/build-BXWPS7VK.js.map +7 -0
  52. package/dist/browser/chunk-RFBBAUMM.js +2 -0
  53. package/dist/browser/chunk-RFBBAUMM.js.map +7 -0
  54. package/dist/browser/graffiti-KV3G3O72-URO7SJIJ.js +2 -0
  55. package/dist/browser/graffiti-KV3G3O72-URO7SJIJ.js.map +7 -0
  56. package/dist/browser/index.js +16 -0
  57. package/dist/browser/index.js.map +7 -0
  58. package/dist/browser/login-dialog.html-XUWYDNNI.js +44 -0
  59. package/dist/browser/login-dialog.html-XUWYDNNI.js.map +7 -0
  60. package/dist/browser/rock-salt-LI7DAH66-KPFEBIBO.js +2 -0
  61. package/dist/browser/rock-salt-LI7DAH66-KPFEBIBO.js.map +7 -0
  62. package/dist/browser/style-YUTCEBZV-RWYJV575.js +287 -0
  63. package/dist/browser/style-YUTCEBZV-RWYJV575.js.map +7 -0
  64. package/dist/cjs/1-services/1-authorization.js +317 -0
  65. package/dist/cjs/1-services/1-authorization.js.map +7 -0
  66. package/dist/cjs/1-services/2-dids-tests.js +44 -0
  67. package/dist/cjs/1-services/2-dids-tests.js.map +7 -0
  68. package/dist/cjs/1-services/2-dids.js +47 -0
  69. package/dist/cjs/1-services/2-dids.js.map +7 -0
  70. package/dist/cjs/1-services/3-storage-buckets-tests.js +123 -0
  71. package/dist/cjs/1-services/3-storage-buckets-tests.js.map +7 -0
  72. package/dist/cjs/1-services/3-storage-buckets.js +148 -0
  73. package/dist/cjs/1-services/3-storage-buckets.js.map +7 -0
  74. package/dist/cjs/1-services/4-inboxes-tests.js +145 -0
  75. package/dist/cjs/1-services/4-inboxes-tests.js.map +7 -0
  76. package/dist/cjs/1-services/4-inboxes.js +539 -0
  77. package/dist/cjs/1-services/4-inboxes.js.map +7 -0
  78. package/dist/cjs/1-services/utilities.js +75 -0
  79. package/dist/cjs/1-services/utilities.js.map +7 -0
  80. package/dist/cjs/2-primitives/1-string-encoding-tests.js +50 -0
  81. package/dist/cjs/2-primitives/1-string-encoding-tests.js.map +7 -0
  82. package/dist/cjs/2-primitives/1-string-encoding.js +46 -0
  83. package/dist/cjs/2-primitives/1-string-encoding.js.map +7 -0
  84. package/dist/cjs/2-primitives/2-content-addresses-tests.js +62 -0
  85. package/dist/cjs/2-primitives/2-content-addresses-tests.js.map +7 -0
  86. package/dist/cjs/2-primitives/2-content-addresses.js +53 -0
  87. package/dist/cjs/2-primitives/2-content-addresses.js.map +7 -0
  88. package/dist/cjs/2-primitives/3-channel-attestations-tests.js +130 -0
  89. package/dist/cjs/2-primitives/3-channel-attestations-tests.js.map +7 -0
  90. package/dist/cjs/2-primitives/3-channel-attestations.js +84 -0
  91. package/dist/cjs/2-primitives/3-channel-attestations.js.map +7 -0
  92. package/dist/cjs/2-primitives/4-allowed-attestations-tests.js +96 -0
  93. package/dist/cjs/2-primitives/4-allowed-attestations-tests.js.map +7 -0
  94. package/dist/cjs/2-primitives/4-allowed-attestations.js +68 -0
  95. package/dist/cjs/2-primitives/4-allowed-attestations.js.map +7 -0
  96. package/dist/cjs/3-protocol/1-sessions.js +473 -0
  97. package/dist/cjs/3-protocol/1-sessions.js.map +7 -0
  98. package/dist/cjs/3-protocol/2-handles-tests.js +39 -0
  99. package/dist/cjs/3-protocol/2-handles-tests.js.map +7 -0
  100. package/dist/cjs/3-protocol/2-handles.js +65 -0
  101. package/dist/cjs/3-protocol/2-handles.js.map +7 -0
  102. package/dist/cjs/3-protocol/3-object-encoding-tests.js +253 -0
  103. package/dist/cjs/3-protocol/3-object-encoding-tests.js.map +7 -0
  104. package/dist/cjs/3-protocol/3-object-encoding.js +287 -0
  105. package/dist/cjs/3-protocol/3-object-encoding.js.map +7 -0
  106. package/dist/cjs/3-protocol/4-graffiti.js +937 -0
  107. package/dist/cjs/3-protocol/4-graffiti.js.map +7 -0
  108. package/dist/cjs/3-protocol/login-dialog.html.js +67 -0
  109. package/dist/cjs/3-protocol/login-dialog.html.js.map +7 -0
  110. package/dist/cjs/index.js +32 -0
  111. package/dist/cjs/index.js.map +7 -0
  112. package/dist/cjs/index.spec.js +130 -0
  113. package/dist/cjs/index.spec.js.map +7 -0
  114. package/dist/esm/1-services/1-authorization.js +304 -0
  115. package/dist/esm/1-services/1-authorization.js.map +7 -0
  116. package/dist/esm/1-services/2-dids-tests.js +24 -0
  117. package/dist/esm/1-services/2-dids-tests.js.map +7 -0
  118. package/dist/esm/1-services/2-dids.js +27 -0
  119. package/dist/esm/1-services/2-dids.js.map +7 -0
  120. package/dist/esm/1-services/3-storage-buckets-tests.js +103 -0
  121. package/dist/esm/1-services/3-storage-buckets-tests.js.map +7 -0
  122. package/dist/esm/1-services/3-storage-buckets.js +132 -0
  123. package/dist/esm/1-services/3-storage-buckets.js.map +7 -0
  124. package/dist/esm/1-services/4-inboxes-tests.js +125 -0
  125. package/dist/esm/1-services/4-inboxes-tests.js.map +7 -0
  126. package/dist/esm/1-services/4-inboxes.js +533 -0
  127. package/dist/esm/1-services/4-inboxes.js.map +7 -0
  128. package/dist/esm/1-services/utilities.js +60 -0
  129. package/dist/esm/1-services/utilities.js.map +7 -0
  130. package/dist/esm/2-primitives/1-string-encoding-tests.js +33 -0
  131. package/dist/esm/2-primitives/1-string-encoding-tests.js.map +7 -0
  132. package/dist/esm/2-primitives/1-string-encoding.js +26 -0
  133. package/dist/esm/2-primitives/1-string-encoding.js.map +7 -0
  134. package/dist/esm/2-primitives/2-content-addresses-tests.js +45 -0
  135. package/dist/esm/2-primitives/2-content-addresses-tests.js.map +7 -0
  136. package/dist/esm/2-primitives/2-content-addresses.js +33 -0
  137. package/dist/esm/2-primitives/2-content-addresses.js.map +7 -0
  138. package/dist/esm/2-primitives/3-channel-attestations-tests.js +116 -0
  139. package/dist/esm/2-primitives/3-channel-attestations-tests.js.map +7 -0
  140. package/dist/esm/2-primitives/3-channel-attestations.js +69 -0
  141. package/dist/esm/2-primitives/3-channel-attestations.js.map +7 -0
  142. package/dist/esm/2-primitives/4-allowed-attestations-tests.js +82 -0
  143. package/dist/esm/2-primitives/4-allowed-attestations-tests.js.map +7 -0
  144. package/dist/esm/2-primitives/4-allowed-attestations.js +51 -0
  145. package/dist/esm/2-primitives/4-allowed-attestations.js.map +7 -0
  146. package/dist/esm/3-protocol/1-sessions.js +465 -0
  147. package/dist/esm/3-protocol/1-sessions.js.map +7 -0
  148. package/dist/esm/3-protocol/2-handles-tests.js +19 -0
  149. package/dist/esm/3-protocol/2-handles-tests.js.map +7 -0
  150. package/dist/esm/3-protocol/2-handles.js +45 -0
  151. package/dist/esm/3-protocol/2-handles.js.map +7 -0
  152. package/dist/esm/3-protocol/3-object-encoding-tests.js +248 -0
  153. package/dist/esm/3-protocol/3-object-encoding-tests.js.map +7 -0
  154. package/dist/esm/3-protocol/3-object-encoding.js +280 -0
  155. package/dist/esm/3-protocol/3-object-encoding.js.map +7 -0
  156. package/dist/esm/3-protocol/4-graffiti.js +957 -0
  157. package/dist/esm/3-protocol/4-graffiti.js.map +7 -0
  158. package/dist/esm/3-protocol/login-dialog.html.js +47 -0
  159. package/dist/esm/3-protocol/login-dialog.html.js.map +7 -0
  160. package/dist/esm/index.js +14 -0
  161. package/dist/esm/index.js.map +7 -0
  162. package/dist/esm/index.spec.js +133 -0
  163. package/dist/esm/index.spec.js.map +7 -0
  164. package/dist/index.d.ts +10 -0
  165. package/dist/index.d.ts.map +1 -0
  166. package/dist/index.spec.d.ts +2 -0
  167. package/dist/index.spec.d.ts.map +1 -0
  168. package/package.json +62 -0
  169. package/src/1-services/1-authorization.ts +399 -0
  170. package/src/1-services/2-dids-tests.ts +24 -0
  171. package/src/1-services/2-dids.ts +30 -0
  172. package/src/1-services/3-storage-buckets-tests.ts +121 -0
  173. package/src/1-services/3-storage-buckets.ts +183 -0
  174. package/src/1-services/4-inboxes-tests.ts +154 -0
  175. package/src/1-services/4-inboxes.ts +722 -0
  176. package/src/1-services/utilities.ts +65 -0
  177. package/src/2-primitives/1-string-encoding-tests.ts +33 -0
  178. package/src/2-primitives/1-string-encoding.ts +33 -0
  179. package/src/2-primitives/2-content-addresses-tests.ts +46 -0
  180. package/src/2-primitives/2-content-addresses.ts +42 -0
  181. package/src/2-primitives/3-channel-attestations-tests.ts +125 -0
  182. package/src/2-primitives/3-channel-attestations.ts +95 -0
  183. package/src/2-primitives/4-allowed-attestations-tests.ts +86 -0
  184. package/src/2-primitives/4-allowed-attestations.ts +69 -0
  185. package/src/3-protocol/1-sessions.ts +601 -0
  186. package/src/3-protocol/2-handles-tests.ts +17 -0
  187. package/src/3-protocol/2-handles.ts +60 -0
  188. package/src/3-protocol/3-object-encoding-tests.ts +269 -0
  189. package/src/3-protocol/3-object-encoding.ts +396 -0
  190. package/src/3-protocol/4-graffiti.ts +1265 -0
  191. package/src/3-protocol/login-dialog.html.ts +43 -0
  192. package/src/index.spec.ts +158 -0
  193. package/src/index.ts +16 -0
@@ -0,0 +1,957 @@
1
+ import {
2
+ GraffitiErrorNotFound,
3
+ maskGraffitiObject,
4
+ unpackObjectUrl,
5
+ compileGraffitiObjectSchema,
6
+ GraffitiErrorSchemaMismatch,
7
+ GraffitiErrorForbidden,
8
+ GraffitiErrorTooLarge,
9
+ isMediaAcceptable,
10
+ GraffitiErrorNotAcceptable,
11
+ GraffitiErrorCursorExpired,
12
+ GraffitiErrorInvalidSchema
13
+ } from "@graffiti-garden/api";
14
+ import { randomBytes } from "@noble/hashes/utils.js";
15
+ import {
16
+ encode as dagCborEncode,
17
+ decode as dagCborDecode
18
+ } from "@ipld/dag-cbor";
19
+ import { DecentralizedIdentifiers } from "../1-services/2-dids";
20
+ import { Authorization } from "../1-services/1-authorization";
21
+ import { StorageBuckets } from "../1-services/3-storage-buckets";
22
+ import {
23
+ Inboxes,
24
+ LABELED_MESSAGE_MESSAGE_KEY,
25
+ MESSAGE_METADATA_KEY,
26
+ MESSAGE_OBJECT_KEY,
27
+ MESSAGE_TAGS_KEY
28
+ } from "../1-services/4-inboxes";
29
+ import {
30
+ StringEncoder,
31
+ STRING_ENCODER_METHOD_BASE64URL
32
+ } from "../2-primitives/1-string-encoding";
33
+ import { ContentAddresses } from "../2-primitives/2-content-addresses";
34
+ import {
35
+ CHANNEL_ATTESTATION_METHOD_SHA256_ED25519,
36
+ ChannelAttestations
37
+ } from "../2-primitives/3-channel-attestations";
38
+ import { AllowedAttestations } from "../2-primitives/4-allowed-attestations";
39
+ import { Handles } from "./2-handles";
40
+ import {
41
+ Sessions,
42
+ DID_SERVICE_ID_GRAFFITI_PERSONAL_INBOX,
43
+ DID_SERVICE_TYPE_GRAFFITI_INBOX,
44
+ DID_SERVICE_ID_GRAFFITI_STORAGE_BUCKET,
45
+ DID_SERVICE_TYPE_GRAFFITI_STORAGE_BUCKET
46
+ } from "./1-sessions";
47
+ import {
48
+ decodeObjectUrl,
49
+ MAX_OBJECT_SIZE_BYTES,
50
+ ObjectEncoding
51
+ } from "./3-object-encoding";
52
+ import { GraffitiModal } from "@graffiti-garden/modal";
53
+ import {
54
+ custom,
55
+ string,
56
+ boolean,
57
+ strictObject,
58
+ array,
59
+ int,
60
+ nonnegative,
61
+ optional,
62
+ extend,
63
+ union,
64
+ record,
65
+ url
66
+ } from "zod/mini";
67
+ const Uint8ArraySchema = custom(
68
+ (v) => v instanceof Uint8Array
69
+ );
70
+ const MESSAGE_DATA_STORAGE_BUCKET_KEY = "k";
71
+ const MESSAGE_DATA_TOMBSTONED_MESSAGE_ID_KEY = "t";
72
+ const MessageMetadataBaseSchema = strictObject({
73
+ [MESSAGE_DATA_STORAGE_BUCKET_KEY]: string(),
74
+ [MESSAGE_DATA_TOMBSTONED_MESSAGE_ID_KEY]: optional(string())
75
+ });
76
+ const MESSAGE_DATA_ANNOUNCEMENT_MESSAGE_ID_KEY = "id";
77
+ const MESSAGE_DATA_ANNOUNCEMENT_ENDPOINT_KEY = "e";
78
+ const MESSAGE_DATA_ANNOUNCEMENT_ACTOR_KEY = "a";
79
+ const MessageMetadataAnnouncementsSchema = array(
80
+ strictObject({
81
+ [MESSAGE_DATA_ANNOUNCEMENT_MESSAGE_ID_KEY]: string(),
82
+ [MESSAGE_DATA_ANNOUNCEMENT_ENDPOINT_KEY]: optional(url()),
83
+ [MESSAGE_DATA_ANNOUNCEMENT_ACTOR_KEY]: optional(url())
84
+ })
85
+ );
86
+ const MESSAGE_DATA_ALLOWED_TICKETS_KEY = "s";
87
+ const MESSAGE_DATA_ANNOUNCEMENTS_KEY = "n";
88
+ const MessageMetaDataSelfSchema = extend(MessageMetadataBaseSchema, {
89
+ [MESSAGE_DATA_ALLOWED_TICKETS_KEY]: optional(array(Uint8ArraySchema)),
90
+ [MESSAGE_DATA_ANNOUNCEMENTS_KEY]: MessageMetadataAnnouncementsSchema
91
+ });
92
+ const MESSAGE_DATA_ALLOWED_TICKET_KEY = "a";
93
+ const MESSAGE_DATA_ALLOWED_TICKET_INDEX_KEY = "i";
94
+ const MessageMetadataPrivateSchema = extend(MessageMetadataBaseSchema, {
95
+ [MESSAGE_DATA_ALLOWED_TICKET_KEY]: Uint8ArraySchema,
96
+ [MESSAGE_DATA_ALLOWED_TICKET_INDEX_KEY]: int().check(nonnegative())
97
+ });
98
+ const MessageMetadataSchema = union([
99
+ MessageMetadataBaseSchema,
100
+ MessageMetaDataSelfSchema,
101
+ MessageMetadataPrivateSchema
102
+ ]);
103
+ const MESSAGE_LABEL_UNLABELED = 0;
104
+ const MESSAGE_LABEL_VALID = 1;
105
+ const MESSAGE_LABEL_TRASH = 2;
106
+ const MESSAGE_LABEL_INVALID = 3;
107
+ class GraffitiDecentralized {
108
+ dids = new DecentralizedIdentifiers();
109
+ authorization = new Authorization();
110
+ storageBuckets = new StorageBuckets();
111
+ inboxes = new Inboxes();
112
+ stringEncoder = new StringEncoder();
113
+ contentAddresses = new ContentAddresses();
114
+ channelAttestations = new ChannelAttestations();
115
+ allowedAttestations = new AllowedAttestations();
116
+ sessions = new Sessions({
117
+ dids: this.dids,
118
+ authorization: this.authorization,
119
+ storageBuckets: this.storageBuckets,
120
+ inboxes: this.inboxes
121
+ });
122
+ handles = new Handles({ dids: this.dids });
123
+ objectEncoding = new ObjectEncoding({
124
+ stringEncoder: this.stringEncoder,
125
+ contentAddresses: this.contentAddresses,
126
+ channelAttestations: this.channelAttestations,
127
+ allowedAttestations: this.allowedAttestations
128
+ });
129
+ modal = typeof window === "undefined" ? void 0 : new GraffitiModal({
130
+ useTemplateHTML: () => import("./login-dialog.html").then(({ template }) => template),
131
+ onManualClose: () => {
132
+ const event = new CustomEvent("login", {
133
+ detail: {
134
+ error: new Error("User cancelled login"),
135
+ manual: true
136
+ }
137
+ });
138
+ this.sessionEvents.dispatchEvent(event);
139
+ }
140
+ });
141
+ defaultInboxEndpoints;
142
+ identityCreatorEndpoint;
143
+ constructor(options) {
144
+ this.defaultInboxEndpoints = options?.defaultInboxEndpoints ?? [
145
+ "https://graffiti.actor/i/shared"
146
+ ];
147
+ this.identityCreatorEndpoint = options?.identityCreatorEndpoint ?? "https://graffiti.actor/create";
148
+ this.sessionEvents.addEventListener("login", async (event) => {
149
+ if (!(event instanceof CustomEvent)) return;
150
+ const detail = event.detail;
151
+ if (detail.error !== void 0 && !("manual" in detail && detail.manual)) {
152
+ alert("Login failed: " + detail.error.message);
153
+ const actor = detail.session?.actor;
154
+ let handle;
155
+ if (actor) {
156
+ try {
157
+ handle = await this.actorToHandle(actor);
158
+ } catch (error) {
159
+ console.error("Failed to handle actor:", error);
160
+ }
161
+ }
162
+ this.login_(handle);
163
+ }
164
+ });
165
+ }
166
+ actorToHandle = this.handles.actorToHandle.bind(this.handles);
167
+ handleToActor = this.handles.handleToActor.bind(this.handles);
168
+ sessionEvents = this.sessions.sessionEvents;
169
+ login = async (actor) => {
170
+ try {
171
+ let proposedHandle;
172
+ try {
173
+ proposedHandle = actor ? await this.actorToHandle(actor) : void 0;
174
+ } catch (error) {
175
+ console.error("Error fetching handle for actor:", error);
176
+ }
177
+ await this.login_(proposedHandle);
178
+ } catch (e) {
179
+ const loginError = new CustomEvent("login", {
180
+ detail: {
181
+ error: e instanceof Error ? e : new Error(String(e))
182
+ }
183
+ });
184
+ this.sessionEvents.dispatchEvent(loginError);
185
+ }
186
+ };
187
+ async login_(proposedHandle) {
188
+ if (typeof window !== "undefined") {
189
+ let template;
190
+ if (proposedHandle !== void 0) {
191
+ template = await this.modal?.displayTemplate("graffiti-login-handle");
192
+ const input = template?.querySelector(
193
+ "#username"
194
+ );
195
+ input?.setAttribute("value", proposedHandle);
196
+ input?.addEventListener("focus", () => input?.select());
197
+ new Promise((r) => {
198
+ setTimeout(() => r(), 0);
199
+ }).then(() => {
200
+ input?.focus();
201
+ });
202
+ template?.querySelector("#graffiti-login-handle-form")?.addEventListener("submit", async (e) => {
203
+ e.preventDefault();
204
+ input?.setAttribute("disabled", "true");
205
+ const submitButton = template?.querySelector(
206
+ "#graffiti-login-handle-submit"
207
+ );
208
+ submitButton?.setAttribute("disabled", "true");
209
+ submitButton && (submitButton.innerHTML = "Logging in...");
210
+ if (!input?.value) {
211
+ alert("No handle provided");
212
+ this.login_("");
213
+ return;
214
+ }
215
+ let handle = input.value;
216
+ if (!handle.includes(".") && !handle.startsWith("localhost")) {
217
+ const defaultHost = new URL(this.identityCreatorEndpoint).host;
218
+ handle = `${handle}.${defaultHost}`;
219
+ }
220
+ let actor;
221
+ try {
222
+ actor = await this.handleToActor(handle);
223
+ } catch (e2) {
224
+ alert("Could not find an identity associated with that handle.");
225
+ this.login_(handle);
226
+ return;
227
+ }
228
+ try {
229
+ await this.sessions.login(actor);
230
+ } catch (e2) {
231
+ alert("Error logging in.");
232
+ console.error(e2);
233
+ this.login_(handle);
234
+ }
235
+ });
236
+ } else {
237
+ template = await this.modal?.displayTemplate("graffiti-login-welcome");
238
+ template?.querySelector("#graffiti-login-existing")?.addEventListener("click", (e) => {
239
+ e.preventDefault();
240
+ this.login_("");
241
+ });
242
+ new Promise((r) => {
243
+ setTimeout(() => r(), 0);
244
+ }).then(() => {
245
+ template?.querySelector("#graffiti-login-new")?.focus();
246
+ });
247
+ }
248
+ const createUrl = new URL(this.identityCreatorEndpoint);
249
+ createUrl.searchParams.set(
250
+ "redirect_uri",
251
+ encodeURIComponent(window.location.toString())
252
+ );
253
+ template?.querySelector("#graffiti-login-new")?.setAttribute("href", createUrl.toString());
254
+ await this.modal?.open();
255
+ } else {
256
+ const readline = await import("readline").catch((e) => {
257
+ throw new Error(
258
+ "Unrecognized environment: neither window nor readline"
259
+ );
260
+ });
261
+ console.log(
262
+ "If you do not already have a Graffiti handle, you can create one here:"
263
+ );
264
+ console.log(this.identityCreatorEndpoint);
265
+ const rl = readline.createInterface({
266
+ input: process.stdin,
267
+ output: process.stdout
268
+ });
269
+ const handle = await new Promise((resolve) => {
270
+ rl.question(
271
+ `Please enter your handle${proposedHandle ? ` (default: ${proposedHandle})` : ""}: `,
272
+ (input) => {
273
+ rl.close();
274
+ resolve(input || proposedHandle);
275
+ }
276
+ );
277
+ });
278
+ if (!handle) {
279
+ throw new Error("No handle provided");
280
+ }
281
+ const actor = await this.handleToActor(handle);
282
+ await this.sessions.login(actor);
283
+ }
284
+ }
285
+ logout = async (session) => {
286
+ await this.sessions.logout(session.actor);
287
+ };
288
+ // @ts-ignore
289
+ post = async (...args) => {
290
+ const [partialObject, session] = args;
291
+ const resolvedSession = this.sessions.resolveSession(session);
292
+ const { object, tags, objectBytes, allowedTickets } = await this.objectEncoding.encode(partialObject, session.actor);
293
+ const storageBucketKeyBytes = randomBytes();
294
+ const storageBucketKey = await this.stringEncoder.encode(
295
+ STRING_ENCODER_METHOD_BASE64URL,
296
+ storageBucketKeyBytes
297
+ );
298
+ await this.storageBuckets.put(
299
+ resolvedSession.storageBucket.serviceEndpoint,
300
+ storageBucketKey,
301
+ objectBytes,
302
+ resolvedSession.storageBucket.token
303
+ );
304
+ await this.announceObject(
305
+ object,
306
+ tags,
307
+ allowedTickets,
308
+ storageBucketKey,
309
+ session
310
+ );
311
+ return object;
312
+ };
313
+ get = async (...args) => {
314
+ const [url2, schema, session] = args;
315
+ let services;
316
+ const validator = await compileGraffitiObjectSchema(schema);
317
+ if (session) {
318
+ const resolvedSession = this.sessions.resolveSession(session);
319
+ services = [
320
+ resolvedSession.personalInbox,
321
+ ...resolvedSession.sharedInboxes
322
+ ];
323
+ } else {
324
+ services = this.defaultInboxEndpoints.map((s) => ({
325
+ serviceEndpoint: s
326
+ }));
327
+ }
328
+ const objectUrl = unpackObjectUrl(url2);
329
+ const tags = [new TextEncoder().encode(objectUrl)];
330
+ for (const service of services) {
331
+ let object = void 0;
332
+ const iterator = this.querySingleEndpoint(
333
+ service.serviceEndpoint,
334
+ {
335
+ tags,
336
+ objectSchema: {}
337
+ },
338
+ service.token,
339
+ session?.actor
340
+ );
341
+ for await (const result of iterator) {
342
+ if (result.object.url !== objectUrl) continue;
343
+ if (result.tombstone) {
344
+ object = void 0;
345
+ } else {
346
+ object = result.object;
347
+ }
348
+ }
349
+ if (object) {
350
+ if (!validator(object)) {
351
+ throw new GraffitiErrorSchemaMismatch(
352
+ "Object exists but does not match the supplied schema"
353
+ );
354
+ }
355
+ return object;
356
+ }
357
+ }
358
+ throw new GraffitiErrorNotFound("Object not found");
359
+ };
360
+ delete = async (url2, session) => {
361
+ const resolvedSession = this.sessions.resolveSession(session);
362
+ const objectUrl = unpackObjectUrl(url2);
363
+ const { actor } = decodeObjectUrl(objectUrl);
364
+ if (actor !== session.actor) {
365
+ throw new GraffitiErrorForbidden("Cannot delete someone else's actor");
366
+ }
367
+ const iterator = this.querySingleEndpoint(
368
+ resolvedSession.personalInbox.serviceEndpoint,
369
+ {
370
+ tags: [new TextEncoder().encode(objectUrl)],
371
+ objectSchema: {}
372
+ },
373
+ resolvedSession.personalInbox.token
374
+ );
375
+ let existing;
376
+ for await (const result of iterator) {
377
+ if (result.object.url !== objectUrl) continue;
378
+ if (result.tombstone) {
379
+ existing = void 0;
380
+ } else {
381
+ existing = result;
382
+ }
383
+ }
384
+ if (!existing) {
385
+ throw new GraffitiErrorNotFound(`Object ${objectUrl} not found`);
386
+ }
387
+ const {
388
+ object,
389
+ storageBucketKey,
390
+ tags,
391
+ allowedTickets,
392
+ announcements,
393
+ messageId
394
+ } = existing;
395
+ await this.storageBuckets.delete(
396
+ resolvedSession.storageBucket.serviceEndpoint,
397
+ storageBucketKey,
398
+ resolvedSession.storageBucket.token
399
+ );
400
+ await this.announceObject(
401
+ object,
402
+ tags,
403
+ allowedTickets,
404
+ storageBucketKey,
405
+ session,
406
+ [
407
+ ...announcements ?? [],
408
+ // Make sure we delete from our own inbox too
409
+ {
410
+ [MESSAGE_DATA_ANNOUNCEMENT_ACTOR_KEY]: session.actor,
411
+ [MESSAGE_DATA_ANNOUNCEMENT_MESSAGE_ID_KEY]: messageId
412
+ }
413
+ ]
414
+ );
415
+ return object;
416
+ };
417
+ postMedia = async (...args) => {
418
+ const [media, session] = args;
419
+ const type = media.data.type;
420
+ const resolvedSession = this.sessions.resolveSession(session);
421
+ const keyBytes = randomBytes();
422
+ const key = await this.stringEncoder.encode(
423
+ STRING_ENCODER_METHOD_BASE64URL,
424
+ keyBytes
425
+ );
426
+ await this.storageBuckets.put(
427
+ resolvedSession.storageBucket.serviceEndpoint,
428
+ key,
429
+ new Uint8Array(await media.data.arrayBuffer()),
430
+ resolvedSession.storageBucket.token
431
+ );
432
+ const { url: url2 } = await this.post(
433
+ {
434
+ value: {
435
+ key,
436
+ type,
437
+ size: media.data.size
438
+ },
439
+ channels: [],
440
+ allowed: media.allowed
441
+ },
442
+ session
443
+ );
444
+ return url2;
445
+ };
446
+ getMedia = async (...args) => {
447
+ const [mediaUrl, accept, session] = args;
448
+ const object = await this.get(
449
+ mediaUrl,
450
+ MEDIA_OBJECT_SCHEMA,
451
+ session
452
+ );
453
+ const { key, type, size } = object.value;
454
+ if (accept?.maxBytes && size > accept.maxBytes) {
455
+ throw new GraffitiErrorTooLarge("File size exceeds limit");
456
+ }
457
+ if (accept?.types) {
458
+ if (!isMediaAcceptable(type, accept.types)) {
459
+ throw new GraffitiErrorNotAcceptable(
460
+ `Unacceptable media type, ${type}`
461
+ );
462
+ }
463
+ }
464
+ const actorDocument = await this.dids.resolve(object.actor);
465
+ const storageBucketService = actorDocument?.service?.find(
466
+ (service) => service.id === DID_SERVICE_ID_GRAFFITI_STORAGE_BUCKET && service.type === DID_SERVICE_TYPE_GRAFFITI_STORAGE_BUCKET
467
+ );
468
+ if (!storageBucketService) {
469
+ throw new GraffitiErrorNotFound(
470
+ `Actor ${object.actor} has no storage bucket service`
471
+ );
472
+ }
473
+ if (typeof storageBucketService.serviceEndpoint !== "string") {
474
+ throw new GraffitiErrorNotFound(
475
+ `Actor ${object.actor} does not have a valid storage bucket endpoint`
476
+ );
477
+ }
478
+ const storageBucketEndpoint = storageBucketService.serviceEndpoint;
479
+ const data = await this.storageBuckets.get(
480
+ storageBucketEndpoint,
481
+ key,
482
+ size
483
+ );
484
+ const blob = new Blob([data.slice()], { type });
485
+ return {
486
+ data: blob,
487
+ actor: object.actor,
488
+ allowed: object.allowed
489
+ };
490
+ };
491
+ deleteMedia = async (...args) => {
492
+ const [mediaUrl, session] = args;
493
+ const resolvedSession = this.sessions.resolveSession(session);
494
+ const result = await this.delete(mediaUrl, session);
495
+ if (!("key" in result.value && typeof result.value.key === "string"))
496
+ throw new Error(
497
+ "Deleted object was not media: " + JSON.stringify(result, null, 2)
498
+ );
499
+ await this.storageBuckets.delete(
500
+ resolvedSession.storageBucket.serviceEndpoint,
501
+ result.value.key,
502
+ resolvedSession.storageBucket.token
503
+ );
504
+ };
505
+ async *discoverMeta(channels, schema, cursors, session) {
506
+ const tombstones = /* @__PURE__ */ new Map();
507
+ let allInboxes;
508
+ if (session) {
509
+ const resolvedSession = this.sessions.resolveSession(session);
510
+ allInboxes = [
511
+ resolvedSession.personalInbox,
512
+ ...resolvedSession.sharedInboxes
513
+ ];
514
+ } else {
515
+ allInboxes = this.defaultInboxEndpoints.map((e) => ({
516
+ serviceEndpoint: e
517
+ }));
518
+ }
519
+ for (const endpoint in cursors) {
520
+ if (!allInboxes.some((i) => i.serviceEndpoint === endpoint)) {
521
+ throw new GraffitiErrorForbidden(
522
+ "Cursor does not match actor's inboxes"
523
+ );
524
+ }
525
+ }
526
+ const tags = await Promise.all(
527
+ channels.map(
528
+ (c) => this.channelAttestations.register(
529
+ CHANNEL_ATTESTATION_METHOD_SHA256_ED25519,
530
+ c
531
+ )
532
+ )
533
+ );
534
+ const iterators = allInboxes.map(
535
+ (i) => {
536
+ const cursor = cursors[i.serviceEndpoint];
537
+ return this.querySingleEndpoint(
538
+ i.serviceEndpoint,
539
+ cursor ? {
540
+ cursor
541
+ } : {
542
+ tags,
543
+ objectSchema: schema
544
+ },
545
+ i.token,
546
+ session?.actor
547
+ );
548
+ }
549
+ );
550
+ let indexedIteratorNexts = iterators.map(async (it, index) => indexedSingleEndpointQueryNext(it, index));
551
+ let active = indexedIteratorNexts.length;
552
+ while (active > 0) {
553
+ const next = await Promise.race(indexedIteratorNexts);
554
+ if (next.error !== void 0) {
555
+ indexedIteratorNexts[next.index] = new Promise(() => {
556
+ });
557
+ active--;
558
+ yield {
559
+ error: next.error,
560
+ origin: allInboxes[next.index].serviceEndpoint
561
+ };
562
+ } else if (next.result.done) {
563
+ const inbox = allInboxes[next.index];
564
+ cursors[inbox.serviceEndpoint] = next.result.value;
565
+ indexedIteratorNexts[next.index] = new Promise(() => {
566
+ });
567
+ active--;
568
+ } else {
569
+ indexedIteratorNexts[next.index] = indexedSingleEndpointQueryNext(
570
+ iterators[next.index],
571
+ next.index
572
+ );
573
+ const { object, tombstone, tags: receivedTags } = next.result.value;
574
+ if (tombstone) {
575
+ if (tombstones.get(object.url) === true) continue;
576
+ tombstones.set(object.url, true);
577
+ yield {
578
+ tombstone,
579
+ object: { url: object.url }
580
+ };
581
+ } else {
582
+ if (tombstones.get(object.url) === false) continue;
583
+ const matchedTagIndices = tags.reduce(
584
+ (acc, tag, tagIndex) => {
585
+ for (const receivedTag of receivedTags) {
586
+ if (tag.length === receivedTag.length && tag.every((b, i) => receivedTag[i] === b)) {
587
+ acc.push(tagIndex);
588
+ break;
589
+ }
590
+ }
591
+ return acc;
592
+ },
593
+ []
594
+ );
595
+ const matchedChannels = matchedTagIndices.map(
596
+ (index) => channels[index]
597
+ );
598
+ if (matchedChannels.length === 0) {
599
+ yield {
600
+ error: new Error(
601
+ "Inbox returned object without matching channels"
602
+ ),
603
+ origin: allInboxes[next.index].serviceEndpoint
604
+ };
605
+ }
606
+ tombstones.set(object.url, false);
607
+ yield {
608
+ object: {
609
+ ...object,
610
+ channels: matchedChannels
611
+ }
612
+ };
613
+ }
614
+ }
615
+ }
616
+ return {
617
+ cursor: JSON.stringify({
618
+ channels,
619
+ cursors
620
+ }),
621
+ continue: (session2) => this.discoverMeta(channels, schema, cursors, session2)
622
+ };
623
+ }
624
+ discover = (...args) => {
625
+ const [channels, schema, session] = args;
626
+ return this.discoverMeta(channels, schema, {}, session);
627
+ };
628
+ continueDiscover = (...args) => {
629
+ const [cursor, session] = args;
630
+ let channels;
631
+ let cursors;
632
+ try {
633
+ const json = JSON.parse(cursor);
634
+ const parsed = CursorSchema.parse(json);
635
+ channels = parsed.channels;
636
+ cursors = parsed.cursors;
637
+ } catch (error) {
638
+ return (async function* () {
639
+ throw new GraffitiErrorCursorExpired("Invalid cursor");
640
+ })();
641
+ }
642
+ return this.discoverMeta(channels, {}, cursors, session);
643
+ };
644
+ async announceObject(object, tags, allowedTickets, storageBucketKey, session, priorAnnouncements) {
645
+ const resolvedSession = this.sessions.resolveSession(session);
646
+ const metadataBase = {
647
+ [MESSAGE_DATA_STORAGE_BUCKET_KEY]: storageBucketKey
648
+ };
649
+ const announcements = [];
650
+ const allowed = object.allowed;
651
+ if (Array.isArray(allowed)) {
652
+ if (!allowedTickets || allowedTickets.length !== allowed.length) {
653
+ throw new Error(
654
+ "If allowed actors are specified, there must be a corresponding ticket for each allowed actor"
655
+ );
656
+ }
657
+ const results = await Promise.allSettled(
658
+ allowed.map(async (recipient, recipientIndex) => {
659
+ const copy = JSON.parse(JSON.stringify(object));
660
+ const masked = maskGraffitiObject(copy, [], recipient);
661
+ const actorDocument = await this.dids.resolve(recipient);
662
+ const personalInbox = actorDocument.service?.find(
663
+ (service) => service.type === DID_SERVICE_TYPE_GRAFFITI_INBOX && service.id === DID_SERVICE_ID_GRAFFITI_PERSONAL_INBOX
664
+ );
665
+ if (!personalInbox) {
666
+ throw new Error(
667
+ `Recipient ${recipient} does not have a personal inbox`
668
+ );
669
+ }
670
+ if (typeof personalInbox.serviceEndpoint !== "string") {
671
+ throw new Error(
672
+ `Recipient ${recipient} does not have a valid personal inbox endpoint`
673
+ );
674
+ }
675
+ const tombstonedMessageId2 = priorAnnouncements ? priorAnnouncements.find(
676
+ (a) => a[MESSAGE_DATA_ANNOUNCEMENT_ACTOR_KEY] === recipient
677
+ )?.[MESSAGE_DATA_ANNOUNCEMENT_MESSAGE_ID_KEY] : void 0;
678
+ const privateMetadata = {
679
+ ...metadataBase,
680
+ ...tombstonedMessageId2 ? {
681
+ [MESSAGE_DATA_TOMBSTONED_MESSAGE_ID_KEY]: tombstonedMessageId2
682
+ } : {},
683
+ [MESSAGE_DATA_ALLOWED_TICKET_KEY]: allowedTickets[recipientIndex],
684
+ [MESSAGE_DATA_ALLOWED_TICKET_INDEX_KEY]: recipientIndex
685
+ };
686
+ const messageId = await this.inboxes.send(
687
+ personalInbox.serviceEndpoint,
688
+ {
689
+ [MESSAGE_TAGS_KEY]: tags,
690
+ [MESSAGE_OBJECT_KEY]: masked,
691
+ [MESSAGE_METADATA_KEY]: dagCborEncode(privateMetadata)
692
+ }
693
+ );
694
+ announcements.push({
695
+ [MESSAGE_DATA_ANNOUNCEMENT_MESSAGE_ID_KEY]: messageId,
696
+ [MESSAGE_DATA_ANNOUNCEMENT_ACTOR_KEY]: recipient
697
+ });
698
+ })
699
+ );
700
+ for (const [index, result] of results.entries()) {
701
+ if (result.status === "rejected") {
702
+ const recipient = allowed[index];
703
+ console.error("Error sending to recipient:", recipient);
704
+ console.error(result.reason);
705
+ }
706
+ }
707
+ } else {
708
+ const copy = JSON.parse(JSON.stringify(object));
709
+ const masked = maskGraffitiObject(copy, []);
710
+ const sharedInboxes = resolvedSession.sharedInboxes;
711
+ const results = await Promise.allSettled(
712
+ sharedInboxes.map(async (inbox) => {
713
+ const tombstonedMessageId2 = priorAnnouncements ? priorAnnouncements.find(
714
+ (a) => a[MESSAGE_DATA_ANNOUNCEMENT_ENDPOINT_KEY] === inbox.serviceEndpoint
715
+ )?.[MESSAGE_DATA_ANNOUNCEMENT_MESSAGE_ID_KEY] : void 0;
716
+ const metadata = {
717
+ ...metadataBase,
718
+ ...tombstonedMessageId2 ? {
719
+ [MESSAGE_DATA_TOMBSTONED_MESSAGE_ID_KEY]: tombstonedMessageId2
720
+ } : {}
721
+ };
722
+ const messageId = await this.inboxes.send(inbox.serviceEndpoint, {
723
+ ...tombstonedMessageId2 ? {
724
+ [MESSAGE_DATA_TOMBSTONED_MESSAGE_ID_KEY]: tombstonedMessageId2
725
+ } : {},
726
+ [MESSAGE_TAGS_KEY]: tags,
727
+ [MESSAGE_OBJECT_KEY]: masked,
728
+ [MESSAGE_METADATA_KEY]: dagCborEncode(metadata)
729
+ });
730
+ announcements.push({
731
+ [MESSAGE_DATA_ANNOUNCEMENT_MESSAGE_ID_KEY]: messageId,
732
+ [MESSAGE_DATA_ANNOUNCEMENT_ENDPOINT_KEY]: inbox.serviceEndpoint
733
+ });
734
+ })
735
+ );
736
+ for (const [index, result] of results.entries()) {
737
+ if (result.status === "rejected") {
738
+ const inbox = sharedInboxes[index];
739
+ console.error("Error sending to inbox:", inbox);
740
+ console.error(result.reason);
741
+ }
742
+ }
743
+ }
744
+ const tombstonedMessageId = priorAnnouncements ? priorAnnouncements.find(
745
+ (a) => a[MESSAGE_DATA_ANNOUNCEMENT_ACTOR_KEY] === session.actor
746
+ )?.[MESSAGE_DATA_ANNOUNCEMENT_MESSAGE_ID_KEY] : void 0;
747
+ const selfMetadata = {
748
+ ...metadataBase,
749
+ ...allowedTickets ? {
750
+ [MESSAGE_DATA_ALLOWED_TICKETS_KEY]: allowedTickets
751
+ } : {},
752
+ ...tombstonedMessageId ? {
753
+ [MESSAGE_DATA_TOMBSTONED_MESSAGE_ID_KEY]: tombstonedMessageId
754
+ } : {},
755
+ [MESSAGE_DATA_ANNOUNCEMENTS_KEY]: announcements
756
+ };
757
+ await this.inboxes.send(resolvedSession.personalInbox.serviceEndpoint, {
758
+ [MESSAGE_TAGS_KEY]: tags,
759
+ [MESSAGE_OBJECT_KEY]: object,
760
+ [MESSAGE_METADATA_KEY]: dagCborEncode(selfMetadata)
761
+ });
762
+ }
763
+ async *querySingleEndpoint(inboxEndpoint, queryArguments, inboxToken, recipient) {
764
+ const iterator = "tags" in queryArguments ? this.inboxes.query(
765
+ inboxEndpoint,
766
+ queryArguments.tags,
767
+ queryArguments.objectSchema,
768
+ inboxToken
769
+ ) : this.inboxes.continueQuery(
770
+ inboxEndpoint,
771
+ queryArguments.cursor,
772
+ inboxToken
773
+ );
774
+ 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) {
788
+ this.inboxes.label(
789
+ inboxEndpoint,
790
+ messageId,
791
+ MESSAGE_LABEL_INVALID,
792
+ inboxToken
793
+ );
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
+ }
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
819
+ );
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
835
+ );
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
851
+ );
852
+ } catch (e) {
853
+ validationError = e;
854
+ }
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
+ }
866
+ this.inboxes.label(
867
+ inboxEndpoint,
868
+ messageId,
869
+ MESSAGE_LABEL_TRASH,
870
+ inboxToken
871
+ );
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);
885
+ this.inboxes.label(
886
+ inboxEndpoint,
887
+ messageId,
888
+ MESSAGE_LABEL_INVALID,
889
+ inboxToken
890
+ );
891
+ }
892
+ } 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
+ }
918
+ }
919
+ }
920
+ }
921
+ }
922
+ const MEDIA_OBJECT_SCHEMA = {
923
+ properties: {
924
+ value: {
925
+ properties: {
926
+ type: { type: "string" },
927
+ size: { type: "number" },
928
+ key: { type: "string" }
929
+ },
930
+ required: ["type", "size", "key"]
931
+ }
932
+ }
933
+ };
934
+ const CursorSchema = strictObject({
935
+ cursors: record(url(), string()),
936
+ channels: array(string())
937
+ });
938
+ async function indexedSingleEndpointQueryNext(it, index) {
939
+ try {
940
+ return {
941
+ index,
942
+ result: await it.next()
943
+ };
944
+ } catch (e) {
945
+ if (e instanceof GraffitiErrorCursorExpired || e instanceof GraffitiErrorInvalidSchema) {
946
+ throw e;
947
+ }
948
+ return {
949
+ index,
950
+ error: e instanceof Error ? e : new Error(String(e))
951
+ };
952
+ }
953
+ }
954
+ export {
955
+ GraffitiDecentralized
956
+ };
957
+ //# sourceMappingURL=4-graffiti.js.map