@graffiti-garden/implementation-decentralized 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/1-services/4-inboxes/cache.d.ts +34 -0
  2. package/dist/1-services/4-inboxes/cache.d.ts.map +1 -0
  3. package/dist/1-services/4-inboxes/messages.d.ts +70 -0
  4. package/dist/1-services/4-inboxes/messages.d.ts.map +1 -0
  5. package/dist/1-services/4-inboxes.d.ts +28 -67
  6. package/dist/1-services/4-inboxes.d.ts.map +1 -1
  7. package/dist/3-protocol/4-graffiti.d.ts +1 -0
  8. package/dist/3-protocol/4-graffiti.d.ts.map +1 -1
  9. package/dist/browser/index.js +7 -7
  10. package/dist/browser/index.js.map +4 -4
  11. package/dist/cjs/1-services/1-authorization.js +1 -1
  12. package/dist/cjs/1-services/1-authorization.js.map +2 -2
  13. package/dist/cjs/1-services/4-inboxes/cache.js +186 -0
  14. package/dist/cjs/1-services/4-inboxes/cache.js.map +7 -0
  15. package/dist/cjs/1-services/4-inboxes/messages.js +69 -0
  16. package/dist/cjs/1-services/4-inboxes/messages.js.map +7 -0
  17. package/dist/cjs/1-services/4-inboxes-tests.js +339 -9
  18. package/dist/cjs/1-services/4-inboxes-tests.js.map +3 -3
  19. package/dist/cjs/1-services/4-inboxes.js +210 -399
  20. package/dist/cjs/1-services/4-inboxes.js.map +3 -3
  21. package/dist/cjs/3-protocol/4-graffiti.js +19 -10
  22. package/dist/cjs/3-protocol/4-graffiti.js.map +2 -2
  23. package/dist/cjs/index.spec.js +1 -0
  24. package/dist/cjs/index.spec.js.map +2 -2
  25. package/dist/esm/1-services/1-authorization.js +1 -1
  26. package/dist/esm/1-services/1-authorization.js.map +2 -2
  27. package/dist/esm/1-services/4-inboxes/cache.js +156 -0
  28. package/dist/esm/1-services/4-inboxes/cache.js.map +7 -0
  29. package/dist/esm/1-services/4-inboxes/messages.js +60 -0
  30. package/dist/esm/1-services/4-inboxes/messages.js.map +7 -0
  31. package/dist/esm/1-services/4-inboxes-tests.js +340 -10
  32. package/dist/esm/1-services/4-inboxes-tests.js.map +3 -3
  33. package/dist/esm/1-services/4-inboxes.js +222 -383
  34. package/dist/esm/1-services/4-inboxes.js.map +3 -3
  35. package/dist/esm/3-protocol/4-graffiti.js +19 -10
  36. package/dist/esm/3-protocol/4-graffiti.js.map +2 -2
  37. package/dist/esm/index.spec.js +2 -1
  38. package/dist/esm/index.spec.js.map +2 -2
  39. package/package.json +1 -1
  40. package/src/1-services/1-authorization.ts +1 -1
  41. package/src/1-services/4-inboxes/cache.ts +227 -0
  42. package/src/1-services/4-inboxes/messages.ts +63 -0
  43. package/src/1-services/4-inboxes-tests.ts +387 -2
  44. package/src/1-services/4-inboxes.ts +297 -512
  45. package/src/3-protocol/4-graffiti.ts +26 -10
  46. package/src/index.spec.ts +3 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/1-services/4-inboxes.ts"],
4
- "sourcesContent": ["import type { JSONSchema, GraffitiObject } from \"@graffiti-garden/api\";\nimport {\n getAuthorizationEndpoint,\n fetchWithErrorHandling,\n verifyHTTPSEndpoint,\n} from \"./utilities\";\nimport {\n compileGraffitiObjectSchema,\n GraffitiErrorCursorExpired,\n GraffitiErrorNotFound,\n} from \"@graffiti-garden/api\";\nimport {\n encode as dagCborEncode,\n decode as dagCborDecode,\n} from \"@ipld/dag-cbor\";\nimport {\n type infer as infer_,\n string,\n url,\n array,\n optional,\n nullable,\n strictObject,\n looseObject,\n nonnegative,\n int,\n boolean,\n custom,\n number,\n union,\n} from \"zod/mini\";\n\nexport class Inboxes {\n getAuthorizationEndpoint = getAuthorizationEndpoint;\n protected cache_: Promise<Cache> | null = null;\n protected get cache() {\n if (!this.cache_) {\n this.cache_ = createCache();\n }\n return this.cache_;\n }\n\n async send(inboxUrl: string, message: Message<{}>): Promise<string> {\n verifyHTTPSEndpoint(inboxUrl);\n const url = `${inboxUrl}/send`;\n\n const response = await fetchWithErrorHandling(url, {\n method: \"PUT\",\n headers: {\n \"Content-Type\": \"application/cbor\",\n },\n body: new Uint8Array(dagCborEncode({ m: message })),\n });\n\n const blob = await response.blob();\n const cbor = dagCborDecode(await blob.arrayBuffer());\n const parsed = SendResponseSchema.parse(cbor);\n return parsed.id;\n }\n\n async get(\n inboxUrl: string,\n messageId: string,\n inboxToken?: string | null,\n ): Promise<LabeledMessageBase | null> {\n const messageCacheKey = getMessageCacheKey(inboxUrl, messageId);\n const cache = await this.cache;\n const cached = await cache.messages.get(messageCacheKey);\n if (cached !== undefined) return cached;\n\n const url = `${inboxUrl}/message/${messageId}`;\n let response: Response | null = null;\n try {\n response = await fetchWithErrorHandling(url, {\n method: \"GET\",\n headers: {\n ...(inboxToken\n ? {\n Authorization: `Bearer ${inboxToken}`,\n }\n : {}),\n },\n });\n } catch (e) {\n if (e instanceof GraffitiErrorNotFound) {\n await cache.messages.set(messageCacheKey, null);\n return null;\n }\n throw e;\n }\n\n const blob = await response.blob();\n const cbor = dagCborDecode(await blob.arrayBuffer());\n const parsed = LabeledMessageBaseSchema.parse(cbor);\n\n await cache.messages.set(messageCacheKey, parsed);\n return parsed;\n }\n\n async label(\n inboxUrl: string,\n messageId: string,\n label: number,\n inboxToken?: string | null,\n ): Promise<void> {\n verifyHTTPSEndpoint(inboxUrl);\n\n if (inboxToken) {\n const url = `${inboxUrl}/label/${messageId}`;\n\n await fetchWithErrorHandling(url, {\n method: \"PUT\",\n headers: {\n \"Content-Type\": \"application/cbor\",\n Authorization: `Bearer ${inboxToken}`,\n },\n body: new Uint8Array(dagCborEncode({ l: label })),\n });\n }\n\n // Update the cache, even if no token.\n // Therefore people not logged in do not need to\n // repeatedly re-validate objects.\n const cache = await this.cache;\n const messageCacheKey = getMessageCacheKey(inboxUrl, messageId);\n const result = await cache.messages.get(messageCacheKey);\n if (result) {\n await cache.messages.set(messageCacheKey, {\n ...result,\n l: label,\n });\n }\n }\n\n protected async fetchMessageBatch(\n inboxUrl: string,\n type: \"query\" | \"export\",\n body: Uint8Array<ArrayBuffer> | undefined,\n inboxToken?: string | null,\n cursor?: string,\n signal?: AbortSignal,\n ) {\n const response = await fetchWithErrorHandling(\n `${inboxUrl}/${type}${cursor ? `?cursor=${encodeURIComponent(cursor)}` : \"\"}`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/cbor\",\n ...(inboxToken\n ? {\n Authorization: `Bearer ${inboxToken}`,\n }\n : {}),\n },\n body,\n signal,\n },\n );\n const retryAfterHeader = response.headers.get(\"Retry-After\");\n const retryAfter = retryAfterHeader\n ? parseInt(retryAfterHeader)\n : undefined;\n\n const waitTil =\n retryAfter && Number.isFinite(retryAfter)\n ? Date.now() + retryAfter * 1000\n : undefined;\n\n return { response, waitTil };\n }\n\n protected async *yieldFromCache(\n cache: Cache,\n inboxUrl: string,\n messageIdsCacheKey: string,\n cachedMessageIds: CacheQueryValue,\n cacheNumSeen: number = 0,\n ): AsyncGenerator<LabeledMessageBase> {\n // Filter out all messageIds before\n // the number already seen\n const messageIds = cachedMessageIds.messageIds.slice(cacheNumSeen);\n\n // Get all the messages pointed to in the cache\n const messages = await Promise.all(\n messageIds.map(async (id) => {\n const message = await cache.messages.get(\n getMessageCacheKey(inboxUrl, id),\n );\n if (!message) {\n // Something is very wrong with the cache,\n // it refers to message IDs that are not cached\n try {\n await cache.messageIds.del(messageIdsCacheKey);\n } catch {}\n throw new Error(\"Cache out of sync - perhaps clear browser storage\");\n }\n return message;\n }),\n );\n\n yield* messages;\n }\n\n protected async *lockedMessageStreamer<Schema extends JSONSchema>(\n ...args: Parameters<typeof this.messageStreamer<Schema>>\n ): MessageStream<Schema> {\n if (typeof window === \"undefined\" || !(await canUseIDB())) {\n // TODO: implement locking in node as well, but not\n // high priority since most use will be in browser\n const streamer = this.messageStreamer<Schema>(...args);\n while (true) {\n const next = await streamer.next();\n if (next.done) return next.value;\n yield next.value;\n }\n }\n\n // Request the lock\n const messageIdsCacheKey = await args[0];\n const lockKey = `graffiti:inbox:${messageIdsCacheKey}`;\n let releaseLock = () => {};\n let hasLock: boolean = false;\n await new Promise<void>((resolvehasLock) => {\n window.navigator.locks.request(\n lockKey,\n {\n mode: \"exclusive\",\n ifAvailable: true,\n },\n async (lock) => {\n // Immediately return whether we\n // acquired the lock or not\n hasLock = !!lock;\n resolvehasLock();\n\n // Then wait for the release to be called\n await new Promise<void>((r) => (releaseLock = r));\n },\n );\n });\n if (hasLock) {\n // If we have the lock, simply proceed with the regular streamer\n try {\n const streamer = this.messageStreamer<Schema>(...args);\n while (true) {\n const next = await streamer.next();\n if (next.done) return next.value;\n yield next.value;\n }\n } finally {\n // Release the lock when all done\n releaseLock();\n }\n }\n\n // Someone else has the lock,\n // so wait until the lock is released,\n // then just return from the cache\n releaseLock();\n await window.navigator.locks.request(lockKey, () => {});\n\n // TODO: the arguments here are brittle\n // at some point, refactor things\n const inboxUrl = args[1];\n const objectSchema = args[5] ?? {};\n const cacheVersion = args[6];\n const cacheNumSeen = args[7];\n\n const cache = await this.cache;\n const cachedMessageIds = await cache.messageIds.get(messageIdsCacheKey);\n if (!cachedMessageIds) {\n throw new Error(\"Cache not found\");\n }\n if (\n cacheVersion !== undefined &&\n cacheVersion !== cachedMessageIds.version\n ) {\n throw new GraffitiErrorCursorExpired(\"Cursor is stale\");\n }\n\n const iterator = this.yieldFromCache(\n cache,\n inboxUrl,\n messageIdsCacheKey,\n cachedMessageIds,\n cacheNumSeen,\n );\n for await (const m of iterator) yield m as LabeledMessage<Schema>;\n\n const outputCursor: infer_<typeof CursorSchema> = {\n numSeen: cachedMessageIds.messageIds.length,\n version: cachedMessageIds.version,\n messageIdsCacheKey,\n objectSchema,\n };\n\n return JSON.stringify(outputCursor);\n }\n\n protected async *messageStreamer<Schema extends JSONSchema>(\n messageIdsCacheKey_: Promise<string>,\n inboxUrl: string,\n type: \"export\" | \"query\",\n body: Uint8Array<ArrayBuffer> | undefined,\n inboxToken?: string | null,\n objectSchema: Schema = {} as Schema,\n cacheVersion?: string,\n cacheNumSeen: number = 0,\n ): MessageStream<Schema> {\n const validator = await compileGraffitiObjectSchema(objectSchema);\n const messageIdsCacheKey = await messageIdsCacheKey_;\n const cache = await this.cache;\n\n let cachedMessageIds = await cache.messageIds.get(messageIdsCacheKey);\n if (\n cacheVersion !== undefined &&\n cacheVersion !== cachedMessageIds?.version\n ) {\n throw new GraffitiErrorCursorExpired(\"Cursor is stale\");\n }\n\n // If we are rate-limited, wait\n let waitTil = cachedMessageIds?.waitTil;\n await waitFor(waitTil);\n\n // See if the cursor is still active by\n // requesting an initial batch of messages\n const cachedCursor = cachedMessageIds?.cursor;\n let firstResponse: Response | undefined = undefined;\n try {\n const out = await this.fetchMessageBatch(\n inboxUrl,\n type,\n body,\n inboxToken,\n cachedCursor,\n );\n firstResponse = out.response;\n waitTil = out.waitTil;\n } catch (e) {\n if (!(e instanceof GraffitiErrorCursorExpired && cachedCursor)) {\n console.error(\n \"Unexpected error in stream, waiting 5 seconds before continuing...\",\n );\n await new Promise((resolve) => setTimeout(resolve, 5000));\n throw e;\n }\n\n // The cursor is stale\n await cache.messageIds.del(messageIdsCacheKey);\n if (cacheVersion === undefined) {\n // The query is not a continuation\n // so we can effectively ignore the error\n cachedMessageIds = undefined;\n } else {\n // Otherwise propogate it up so the\n // consumer can clear their message history\n throw e;\n }\n }\n\n if (firstResponse !== undefined && cachedMessageIds) {\n // Cursor is valid! Yield from the cache\n const iterator = this.yieldFromCache(\n cache,\n inboxUrl,\n messageIdsCacheKey,\n cachedMessageIds,\n cacheNumSeen,\n );\n for await (const m of iterator) yield m as LabeledMessage<Schema>;\n }\n\n if (firstResponse === undefined) {\n // The cursor was stale: try again\n const out = await this.fetchMessageBatch(\n inboxUrl,\n type,\n body,\n inboxToken,\n );\n firstResponse = out.response;\n waitTil = out.waitTil;\n }\n\n // Continue streaming results\n let response = firstResponse;\n let cursor: string;\n const version = cachedMessageIds?.version ?? crypto.randomUUID();\n let messageIds = cachedMessageIds?.messageIds ?? [];\n while (true) {\n const blob = await response.blob();\n const decoded = dagCborDecode(await blob.arrayBuffer());\n const {\n results,\n hasMore,\n cursor: nextCursor,\n } = MessageResultSchema.parse(decoded);\n cursor = nextCursor;\n\n const labeledMessages: LabeledMessage<Schema>[] = results.map(\n (result) => {\n const object =\n result[LABELED_MESSAGE_MESSAGE_KEY][MESSAGE_OBJECT_KEY];\n if (!validator(object)) {\n throw new Error(\"Server returned data that does not match schema\");\n }\n return {\n ...result,\n [LABELED_MESSAGE_MESSAGE_KEY]: {\n ...result[LABELED_MESSAGE_MESSAGE_KEY],\n [MESSAGE_OBJECT_KEY]: object,\n },\n };\n },\n );\n\n // First cache the messages with their labels\n await cache.messages.setMany(\n labeledMessages.map((m: LabeledMessageBase) => [\n getMessageCacheKey(inboxUrl, m[LABELED_MESSAGE_ID_KEY]),\n m,\n ]),\n );\n // Then store all the messageids\n messageIds = [\n ...messageIds,\n ...labeledMessages.map(\n (m: LabeledMessageBase) => m[LABELED_MESSAGE_ID_KEY],\n ),\n ];\n await cache.messageIds.set(messageIdsCacheKey, {\n cursor,\n version,\n messageIds,\n waitTil,\n });\n\n // Update how many we've seen\n cacheNumSeen += labeledMessages.length;\n\n // Fetch the next page while the caller processes the current page.\n const prefetchController = new AbortController();\n // Otherwise get another response (after waiting for rate-limit)\n const nextPage = hasMore\n ? waitFor(waitTil)\n .then(() => this.fetchMessageBatch(\n inboxUrl,\n type,\n undefined, // Body is never past the first time\n inboxToken,\n cursor,\n prefetchController.signal,\n ))\n // A consumer may stop before awaiting this request.\n .then((value) => ({ value }), (error) => ({ error }))\n : null;\n\n // Return the values\n let consumedPage = false;\n try {\n for (const m of labeledMessages) yield m;\n consumedPage = true;\n } finally {\n if (!consumedPage) prefetchController.abort();\n }\n\n if (!hasMore) break;\n\n const out = await nextPage!;\n if (\"error\" in out) throw out.error;\n response = out.value.response;\n waitTil = out.value.waitTil;\n }\n\n const outputCursor: infer_<typeof CursorSchema> = {\n numSeen: cacheNumSeen,\n version,\n messageIdsCacheKey,\n objectSchema,\n };\n\n return JSON.stringify(outputCursor);\n }\n\n query<Schema extends JSONSchema>(\n inboxUrl: string,\n tags: Uint8Array[],\n objectSchema: Schema,\n inboxToken?: string | null,\n ): MessageStream<Schema> {\n verifyHTTPSEndpoint(inboxUrl);\n\n const body = dagCborEncode({\n tags,\n schema: objectSchema,\n });\n\n const messageIdsCacheKey = getMessageIdsCacheKey(inboxUrl, \"query\", body);\n return this.lockedMessageStreamer<Schema>(\n messageIdsCacheKey,\n inboxUrl,\n \"query\",\n new Uint8Array(body),\n inboxToken,\n objectSchema,\n );\n }\n\n continueQuery(\n inboxUrl: string,\n cursor: string,\n inboxToken?: string | null,\n ): MessageStream<{}> {\n verifyHTTPSEndpoint(inboxUrl);\n\n const decodedCursor = JSON.parse(cursor);\n const { messageIdsCacheKey, numSeen, objectSchema, version } =\n CursorSchema.parse(decodedCursor);\n\n return this.lockedMessageStreamer<{}>(\n Promise.resolve(messageIdsCacheKey),\n inboxUrl,\n \"query\",\n undefined,\n inboxToken,\n objectSchema,\n version,\n numSeen,\n );\n }\n\n export(inboxUrl: string, inboxToken: string): MessageStream<{}> {\n verifyHTTPSEndpoint(inboxUrl);\n const messageIdsCacheKey = getMessageIdsCacheKey(inboxUrl, \"export\");\n return this.lockedMessageStreamer<{}>(\n messageIdsCacheKey,\n inboxUrl,\n \"export\",\n undefined,\n inboxToken,\n );\n }\n}\n\nconst GraffitiObjectSchema = strictObject({\n value: looseObject({}),\n channels: array(string()),\n allowed: optional(nullable(array(url()))),\n url: url(),\n actor: url(),\n});\nexport const Uint8ArraySchema = custom<Uint8Array>(\n (v): v is Uint8Array => v instanceof Uint8Array,\n);\nexport const TagsSchema = array(Uint8ArraySchema);\n\nexport const MESSAGE_TAGS_KEY = \"t\";\nexport const MESSAGE_OBJECT_KEY = \"o\";\nexport const MESSAGE_METADATA_KEY = \"m\";\nexport const MessageBaseSchema = strictObject({\n [MESSAGE_TAGS_KEY]: TagsSchema,\n [MESSAGE_OBJECT_KEY]: GraffitiObjectSchema,\n [MESSAGE_METADATA_KEY]: Uint8ArraySchema,\n});\ntype MessageBase = infer_<typeof MessageBaseSchema>;\n\nexport const LABELED_MESSAGE_ID_KEY = \"id\";\nexport const LABELED_MESSAGE_MESSAGE_KEY = \"m\";\nexport const LABELED_MESSAGE_LABEL_KEY = \"l\";\nexport const LabeledMessageBaseSchema = strictObject({\n [LABELED_MESSAGE_ID_KEY]: string(),\n [LABELED_MESSAGE_MESSAGE_KEY]: MessageBaseSchema,\n [LABELED_MESSAGE_LABEL_KEY]: number(),\n});\ntype LabeledMessageBase = infer_<typeof LabeledMessageBaseSchema>;\n\nexport type Message<Schema extends JSONSchema> = MessageBase & {\n [MESSAGE_OBJECT_KEY]: GraffitiObject<Schema>;\n};\nexport type LabeledMessage<Schema extends JSONSchema> = LabeledMessageBase & {\n [LABELED_MESSAGE_MESSAGE_KEY]: {\n [MESSAGE_OBJECT_KEY]: GraffitiObject<Schema>;\n };\n};\n\nconst SendResponseSchema = strictObject({ id: string() });\n\nconst MessageResultSchema = strictObject({\n results: array(LabeledMessageBaseSchema),\n hasMore: boolean(),\n cursor: string(),\n});\n\nconst CursorSchema = strictObject({\n messageIdsCacheKey: string(),\n version: string(),\n numSeen: int().check(nonnegative()),\n objectSchema: union([looseObject({}), boolean()]),\n});\n\nexport interface MessageStream<\n Schema extends JSONSchema,\n> extends AsyncGenerator<LabeledMessage<Schema>, string> {}\n\ntype CacheQueryValue = {\n cursor: string;\n version: string;\n messageIds: string[];\n waitTil?: number;\n};\n\nasync function canUseIDB(): Promise<boolean> {\n try {\n if (!globalThis.indexedDB) return false;\n\n // Small probe database\n await new Promise<void>((resolve, reject) => {\n const req = indexedDB.open(\"__idb_probe__\", 1);\n req.onupgradeneeded = () => req.result.createObjectStore(\"k\");\n req.onsuccess = () => {\n req.result.close();\n resolve();\n };\n req.onerror = () => reject(req.error);\n });\n\n return true;\n } catch {\n return false;\n }\n}\n\ntype Cache = {\n messages: {\n get(k: string): Promise<LabeledMessageBase | null | undefined>;\n set(k: string, value: LabeledMessageBase | null): Promise<void>;\n setMany(entries: [string, LabeledMessageBase][]): Promise<void>;\n del(k: string): Promise<void>;\n };\n messageIds: {\n get(k: string): Promise<CacheQueryValue | undefined>;\n set(k: string, value: CacheQueryValue): Promise<void>;\n del(k: string): Promise<void>;\n };\n};\n\nfunction getMessageCacheKey(inboxUrl: string, messageId: string) {\n return `${encodeURIComponent(inboxUrl)}:${encodeURIComponent(messageId)}`;\n}\nasync function getMessageIdsCacheKey(\n inboxUrl: string,\n type: \"query\" | \"export\",\n body?: Uint8Array,\n): Promise<string> {\n const cacheIdData = dagCborEncode({\n inboxUrl,\n type,\n body: body ?? null,\n });\n return crypto.subtle\n .digest(\"SHA-256\", new Uint8Array(cacheIdData))\n .then((bytes) =>\n Array.from(new Uint8Array(bytes))\n .map((byte) => byte.toString(16).padStart(2, \"0\"))\n .join(\"\"),\n );\n}\n\nasync function resetCacheDB() {\n await new Promise<void>((resolve) => {\n const req = indexedDB.deleteDatabase(\"graffiti-inbox-cache\");\n req.onsuccess = () => resolve();\n req.onerror = () => resolve(); // best effort\n req.onblocked = () => resolve(); // best effort\n });\n}\n\nasync function createCache(): Promise<Cache> {\n if (await canUseIDB()) {\n const { openDB } = await import(\"idb\");\n const db = await openDB(\"graffiti-inbox-cache\", 1, {\n upgrade(db) {\n if (!db.objectStoreNames.contains(\"m\")) db.createObjectStore(\"m\");\n if (!db.objectStoreNames.contains(\"q\")) db.createObjectStore(\"q\");\n },\n });\n\n return {\n messages: {\n get: async (k) => {\n try {\n return db.get(\"m\", k);\n } catch (error) {\n console.error(\"Error getting message from cache:\", error);\n console.error(\"resetting cache...\");\n await resetCacheDB();\n return undefined;\n }\n },\n set: async (k, v) => {\n await db.put(\"m\", v, k);\n },\n setMany: async (entries) => {\n if (entries.length === 0) return;\n const tx = db.transaction(\"m\", \"readwrite\");\n await Promise.all([\n ...entries.map(([k, v]) => tx.store.put(v, k)),\n tx.done,\n ]);\n },\n del: (k) => db.delete(\"m\", k),\n },\n messageIds: {\n get: async (k) => {\n try {\n return await db.get(\"q\", k);\n } catch (error) {\n console.error(\"Error getting message IDs from cache:\", error);\n console.error(\"resetting cache...\");\n await resetCacheDB();\n return undefined;\n }\n },\n set: async (k, v) => {\n await db.put(\"q\", v, k);\n },\n del: (k) => db.delete(\"q\", k),\n },\n };\n }\n\n const m = new Map<string, LabeledMessageBase | null>();\n const q = new Map<string, CacheQueryValue>();\n\n return {\n messages: {\n get: async (k) => m.get(k),\n set: async (k, v) => void m.set(k, v),\n setMany: async (entries) => {\n for (const [k, v] of entries) m.set(k, v);\n },\n del: async (k) => void m.delete(k),\n },\n messageIds: {\n get: async (k) => q.get(k),\n set: async (k, v) => void q.set(k, v),\n del: async (k) => void q.delete(k),\n },\n };\n}\n\nasync function waitFor(waitTil?: number) {\n if (waitTil !== undefined) {\n const waitFor = waitTil - Date.now();\n if (waitFor > 0) {\n await new Promise((resolve) => setTimeout(resolve, waitFor));\n }\n }\n}\n"],
5
- "mappings": "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",
6
- "names": ["url", "db", "waitFor"]
4
+ "sourcesContent": ["import type { JSONSchema } from \"@graffiti-garden/api\";\nimport {\n getAuthorizationEndpoint,\n fetchWithErrorHandling,\n verifyHTTPSEndpoint,\n} from \"./utilities\";\nimport {\n compileGraffitiObjectSchema,\n GraffitiErrorCursorExpired,\n GraffitiErrorNotFound,\n} from \"@graffiti-garden/api\";\nimport {\n encode as dagCborEncode,\n decode as dagCborDecode,\n} from \"@ipld/dag-cbor\";\nimport {\n type infer as infer_,\n string,\n strictObject,\n looseObject,\n nonnegative,\n int,\n boolean,\n union,\n} from \"zod/mini\";\nimport {\n LabeledMessageBaseSchema,\n SendResponseSchema,\n MessageResultSchema,\n LABELED_MESSAGE_MESSAGE_KEY,\n MESSAGE_OBJECT_KEY,\n} from \"./4-inboxes/messages\";\nimport type {\n LabeledMessageBase,\n LabeledMessage,\n Message,\n} from \"./4-inboxes/messages\";\nimport {\n canUseIDB,\n createCache,\n getMessageCacheKey,\n getMessageIdsCacheKey,\n replayQuery,\n storeQueryPage,\n} from \"./4-inboxes/cache\";\nimport type { Cache, CacheQueryValue } from \"./4-inboxes/cache\";\n\nexport {\n Uint8ArraySchema,\n TagsSchema,\n MESSAGE_TAGS_KEY,\n MESSAGE_OBJECT_KEY,\n MESSAGE_METADATA_KEY,\n MessageBaseSchema,\n LABELED_MESSAGE_ID_KEY,\n LABELED_MESSAGE_MESSAGE_KEY,\n LABELED_MESSAGE_LABEL_KEY,\n LabeledMessageBaseSchema,\n} from \"./4-inboxes/messages\";\nexport type { Message, LabeledMessage } from \"./4-inboxes/messages\";\n\n// One batch may be slow on a mobile connection. This bounds the network request\n// and response-body read, not IndexedDB or time spent yielding messages.\nconst INBOX_REQUEST_TIMEOUT_MS = 30_000;\n// A stalled tab should not make peers wait indefinitely. This only bounds\n// lock acquisition; the request above bounds work after acquisition.\nconst INBOX_LOCK_WAIT_TIMEOUT_MS = 30_000;\n\ntype StreamSource<Schema extends JSONSchema> =\n | {\n kind: \"query\";\n inboxUrl: string;\n body: Uint8Array<ArrayBuffer>;\n schema: Schema;\n inboxToken?: string | null;\n }\n | {\n kind: \"continue\";\n inboxUrl: string;\n cursor: infer_<typeof CursorSchema>;\n inboxToken?: string | null;\n }\n | {\n kind: \"export\";\n inboxUrl: string;\n inboxToken: string;\n };\n\nexport class Inboxes {\n getAuthorizationEndpoint = getAuthorizationEndpoint;\n protected cache_: Promise<Cache> | null = null;\n protected get cache() {\n if (!this.cache_) {\n this.cache_ = createCache();\n }\n return this.cache_;\n }\n\n async send(inboxUrl: string, message: Message<{}>): Promise<string> {\n verifyHTTPSEndpoint(inboxUrl);\n const url = `${inboxUrl}/send`;\n\n const response = await fetchWithErrorHandling(url, {\n method: \"PUT\",\n headers: {\n \"Content-Type\": \"application/cbor\",\n },\n body: new Uint8Array(dagCborEncode({ m: message })),\n });\n\n const blob = await response.blob();\n const cbor = dagCborDecode(await blob.arrayBuffer());\n const parsed = SendResponseSchema.parse(cbor);\n return parsed.id;\n }\n\n async get(\n inboxUrl: string,\n messageId: string,\n inboxToken?: string | null,\n ): Promise<LabeledMessageBase | null> {\n const messageCacheKey = getMessageCacheKey(inboxUrl, messageId);\n const cache = await this.cache;\n const cached = await cache.messages.get(messageCacheKey);\n if (cached !== undefined) return cached;\n\n const url = `${inboxUrl}/message/${messageId}`;\n let response: Response | null = null;\n try {\n response = await fetchWithErrorHandling(url, {\n method: \"GET\",\n headers: {\n ...(inboxToken\n ? {\n Authorization: `Bearer ${inboxToken}`,\n }\n : {}),\n },\n });\n } catch (e) {\n if (e instanceof GraffitiErrorNotFound) {\n await cache.messages.set(messageCacheKey, null);\n return null;\n }\n throw e;\n }\n\n const blob = await response.blob();\n const cbor = dagCborDecode(await blob.arrayBuffer());\n const parsed = LabeledMessageBaseSchema.parse(cbor);\n\n await cache.messages.set(messageCacheKey, parsed);\n return parsed;\n }\n\n async label(\n inboxUrl: string,\n messageId: string,\n label: number,\n inboxToken?: string | null,\n ): Promise<void> {\n verifyHTTPSEndpoint(inboxUrl);\n\n if (inboxToken) {\n const url = `${inboxUrl}/label/${messageId}`;\n\n await fetchWithErrorHandling(url, {\n method: \"PUT\",\n headers: {\n \"Content-Type\": \"application/cbor\",\n Authorization: `Bearer ${inboxToken}`,\n },\n body: new Uint8Array(dagCborEncode({ l: label })),\n });\n }\n\n // Update the cache, even if no token.\n // Therefore people not logged in do not need to\n // repeatedly re-validate objects.\n const cache = await this.cache;\n const messageCacheKey = getMessageCacheKey(inboxUrl, messageId);\n const result = await cache.messages.get(messageCacheKey);\n if (result) {\n await cache.messages.set(messageCacheKey, {\n ...result,\n l: label,\n });\n }\n }\n\n protected async fetchMessageBatch(\n inboxUrl: string,\n type: \"query\" | \"export\",\n body: Uint8Array<ArrayBuffer> | undefined,\n inboxToken?: string | null,\n cursor?: string,\n signal?: AbortSignal,\n ) {\n // Keep the deadline active while the response body is being read, too.\n const timeout = AbortSignal.timeout(INBOX_REQUEST_TIMEOUT_MS);\n const response = await fetchWithErrorHandling(\n `${inboxUrl}/${type}${cursor ? `?cursor=${encodeURIComponent(cursor)}` : \"\"}`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/cbor\",\n ...(inboxToken\n ? {\n Authorization: `Bearer ${inboxToken}`,\n }\n : {}),\n },\n body,\n signal: signal ? AbortSignal.any([signal, timeout]) : timeout,\n },\n );\n const retryAfterHeader = response.headers.get(\"Retry-After\");\n const retryAfter = retryAfterHeader\n ? parseInt(retryAfterHeader)\n : undefined;\n\n const waitTil =\n retryAfter && Number.isFinite(retryAfter)\n ? Date.now() + retryAfter * 1000\n : undefined;\n\n return { response, waitTil };\n }\n\n protected async withQueryLock<T>(\n messageIdsCacheKey: string,\n useLock: boolean,\n work: () => Promise<T>,\n signal?: AbortSignal,\n ): Promise<T> {\n if (!useLock) return work();\n\n // The lock follows one page of network and cache work; yielding cannot\n // prolong it.\n const timeout = AbortSignal.timeout(INBOX_LOCK_WAIT_TIMEOUT_MS);\n let acquired = false;\n try {\n return await window.navigator.locks.request(\n `graffiti:inbox:${messageIdsCacheKey}`,\n {\n mode: \"exclusive\",\n signal: signal ? AbortSignal.any([signal, timeout]) : timeout,\n },\n async () => {\n acquired = true;\n return work();\n },\n );\n } catch (error) {\n if (!acquired && timeout.aborted) {\n throw new Error(\"Timed out waiting for another tab's inbox query\", {\n cause: error,\n });\n }\n throw error;\n }\n }\n\n protected async *messageStreamer<Schema extends JSONSchema>(\n source: StreamSource<Schema>,\n ): MessageStream<Schema> {\n const { inboxUrl, inboxToken } = source;\n const type = source.kind === \"export\" ? \"export\" : \"query\";\n // Continuations carry their validated schema in the cursor; export uses\n // the empty schema. Both callers instantiate this stream with Schema = {}.\n const objectSchema = (\n source.kind === \"query\"\n ? source.schema\n : source.kind === \"continue\" ? source.cursor.objectSchema : {}\n ) as Schema;\n const validator = await compileGraffitiObjectSchema(objectSchema);\n const body = source.kind === \"query\" ? source.body : undefined;\n const messageIdsCacheKey = source.kind === \"continue\"\n ? source.cursor.messageIdsCacheKey\n : await getMessageIdsCacheKey(inboxUrl, type, body);\n const cacheVersion = source.kind === \"continue\"\n ? source.cursor.version\n : undefined;\n // Opening IndexedDB can wait on another tab, so do it before holding a lock.\n const cache = await this.cache;\n // TODO: implement locking in node as well, but not\n // high priority since most use will be in browser\n const useLock = typeof window !== \"undefined\" && (await canUseIDB());\n const initialQuery = await cache.messageIds.get(messageIdsCacheKey);\n // Version identifies a query history; generation changes on each page\n // written to that history, including an empty page.\n let seenGeneration = initialQuery?.generation;\n let seenVersion = initialQuery?.version;\n let numSeen = source.kind === \"continue\" ? source.cursor.numSeen : 0;\n let firstPage = true;\n\n // Advance one page at most. Recheck the cache under the lock so a tab\n // waiting for another tab's fetch can reuse its result.\n const fetchPage = async (signal?: AbortSignal): Promise<CacheQueryValue> => {\n while (true) {\n signal?.throwIfAborted();\n const step = await this.withQueryLock(\n messageIdsCacheKey,\n useLock,\n async () => {\n signal?.throwIfAborted();\n // A different tab may have fetched a page while we waited for the lock.\n let query = await cache.messageIds.get(messageIdsCacheKey);\n if (cacheVersion !== undefined && cacheVersion !== query?.version) {\n throw new GraffitiErrorCursorExpired(\"Cursor is stale\");\n }\n if (query?.version !== seenVersion) {\n // A cache reset after this stream yielded messages would replay\n // them. Report the stale cursor as a midstream expiry instead.\n if (!firstPage) throw new GraffitiErrorCursorExpired(\"Cursor is stale\");\n numSeen = 0;\n }\n if (query?.generation && query.generation !== seenGeneration) {\n return { query };\n }\n\n // A cached Retry-After should not keep other tabs waiting on this lock.\n if (query?.waitTil !== undefined && query.waitTil > Date.now()) {\n return { waitTil: query.waitTil };\n }\n\n // See if the cursor is still active by requesting the next batch.\n let batch: { response: Response; waitTil?: number };\n try {\n batch = await this.fetchMessageBatch(\n inboxUrl,\n type,\n firstPage ? body : undefined, // Later pages send no body.\n inboxToken,\n query?.cursor,\n signal,\n );\n } catch (error) {\n if (\n !(error instanceof GraffitiErrorCursorExpired && query?.cursor)\n ) {\n // Preserve the old initial-page error backoff, but wait only\n // after releasing the Web Lock.\n if (firstPage && !signal?.aborted) {\n return { initialFetchError: error };\n }\n throw error;\n }\n // Only an initial cached cursor is retried. A cursor that\n // expires midstream must be reported to the caller.\n if (!firstPage) throw error;\n\n // The cursor is stale. A continuation must report that to its caller.\n await cache.messageIds.del(messageIdsCacheKey);\n if (cacheVersion !== undefined) throw error;\n query = undefined;\n numSeen = 0;\n batch = await this.fetchMessageBatch(\n inboxUrl,\n type,\n body,\n inboxToken,\n undefined,\n signal,\n );\n }\n\n const decoded = dagCborDecode(\n new Uint8Array(await batch.response.arrayBuffer()),\n );\n const { results, hasMore, cursor } =\n MessageResultSchema.parse(decoded);\n const labeledMessages: LabeledMessage<Schema>[] = results.map(\n (result) => {\n const object =\n result[LABELED_MESSAGE_MESSAGE_KEY][MESSAGE_OBJECT_KEY];\n if (!validator(object)) {\n throw new Error(\"Server returned data that does not match schema\");\n }\n return {\n ...result,\n [LABELED_MESSAGE_MESSAGE_KEY]: {\n ...result[LABELED_MESSAGE_MESSAGE_KEY],\n [MESSAGE_OBJECT_KEY]: object,\n },\n };\n },\n );\n\n query = await storeQueryPage(\n cache,\n inboxUrl,\n messageIdsCacheKey,\n query,\n {\n messages: labeledMessages,\n cursor,\n hasMore,\n waitTil: batch.waitTil,\n },\n );\n return { query };\n },\n signal,\n );\n\n if (\"initialFetchError\" in step) {\n console.error(\n \"Unexpected error in stream, waiting 5 seconds before continuing...\",\n );\n await new Promise((resolve) => setTimeout(resolve, 5000));\n throw step.initialFetchError;\n }\n if (\"waitTil\" in step) {\n await waitFor(step.waitTil);\n continue;\n }\n return step.query;\n }\n };\n\n type PageResult = { query: CacheQueryValue } | { error: unknown };\n let nextPage: Promise<PageResult> | undefined;\n while (true) {\n const result = nextPage\n ? await nextPage\n : await fetchPage().then(\n (query) => ({ query }),\n (error) => ({ error }),\n );\n nextPage = undefined;\n if (\"error\" in result) throw result.error;\n\n const query = result.query;\n // Replay all unseen messages after releasing the lock.\n const messages = await replayQuery(\n cache,\n inboxUrl,\n messageIdsCacheKey,\n query,\n numSeen,\n );\n numSeen = query.messageIds.length;\n seenGeneration = query.generation;\n seenVersion = query.version;\n firstPage = false;\n // The current page's lock is released. Fetch the next page while the\n // caller processes these messages; closing the stream aborts that fetch.\n const prefetchController = new AbortController();\n if (query.hasMore) {\n // The caller may close before awaiting this request; handle rejection\n // here so an aborted prefetch does not become unhandled.\n nextPage = fetchPage(prefetchController.signal).then(\n (query) => ({ query }),\n (error) => ({ error }),\n );\n }\n let consumedPage = false;\n try {\n for (const message of messages) {\n yield message as LabeledMessage<Schema>;\n }\n consumedPage = true;\n } finally {\n if (!consumedPage) prefetchController.abort();\n }\n\n if (!query.hasMore) {\n const outputCursor: infer_<typeof CursorSchema> = {\n numSeen,\n version: query.version,\n messageIdsCacheKey,\n objectSchema,\n };\n return JSON.stringify(outputCursor);\n }\n }\n }\n\n query<Schema extends JSONSchema>(\n inboxUrl: string,\n tags: Uint8Array[],\n objectSchema: Schema,\n inboxToken?: string | null,\n ): MessageStream<Schema> {\n verifyHTTPSEndpoint(inboxUrl);\n const body = new Uint8Array(dagCborEncode({\n tags,\n schema: objectSchema,\n }));\n return this.messageStreamer<Schema>({\n kind: \"query\",\n inboxUrl,\n body,\n schema: objectSchema,\n inboxToken,\n });\n }\n\n continueQuery(\n inboxUrl: string,\n cursor: string,\n inboxToken?: string | null,\n ): MessageStream<{}> {\n verifyHTTPSEndpoint(inboxUrl);\n\n const decodedCursor = JSON.parse(cursor);\n const parsedCursor = CursorSchema.parse(decodedCursor);\n return this.messageStreamer<{}>({\n kind: \"continue\",\n inboxUrl,\n cursor: parsedCursor,\n inboxToken,\n });\n }\n\n export(inboxUrl: string, inboxToken: string): MessageStream<{}> {\n verifyHTTPSEndpoint(inboxUrl);\n return this.messageStreamer<{}>({\n kind: \"export\",\n inboxUrl,\n inboxToken,\n });\n }\n}\n\nconst CursorSchema = strictObject({\n messageIdsCacheKey: string(),\n version: string(),\n numSeen: int().check(nonnegative()),\n objectSchema: union([looseObject({}), boolean()]),\n});\n\nexport interface MessageStream<\n Schema extends JSONSchema,\n> extends AsyncGenerator<LabeledMessage<Schema>, string> {}\n\nasync function waitFor(waitTil?: number) {\n if (waitTil !== undefined) {\n const waitFor = waitTil - Date.now();\n if (waitFor > 0) {\n await new Promise((resolve) => setTimeout(resolve, waitFor));\n }\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["MESSAGE_OBJECT_KEY", "LABELED_MESSAGE_MESSAGE_KEY", "LabeledMessageBaseSchema", "query", "waitFor"]
7
7
  }
@@ -903,6 +903,13 @@ class GraffitiDecentralized {
903
903
  await iterator.return("");
904
904
  }
905
905
  }
906
+ // Labeling is advisory and should not hold up discovery, but its failure
907
+ // must be handled even if the caller has already stopped reading the stream.
908
+ labelInboxMessage(inboxEndpoint, messageId, label, inboxToken) {
909
+ void this.inboxes.label(inboxEndpoint, messageId, label, inboxToken).catch(
910
+ (error) => console.error("Could not label inbox message:", error)
911
+ );
912
+ }
906
913
  async processOneLabeledMessage(inboxEndpoint, result, inboxToken, recipient) {
907
914
  const label = result.l;
908
915
  if (label !== MESSAGE_LABEL_VALID && label !== MESSAGE_LABEL_UNLABELED && label !== MESSAGE_LABEL_TRASH)
@@ -914,7 +921,7 @@ class GraffitiDecentralized {
914
921
  const metadataRaw = dagCborDecode(metadataBytes);
915
922
  metadata = MessageMetadataSchema.parse(metadataRaw);
916
923
  } catch (e) {
917
- this.inboxes.label(
924
+ this.labelInboxMessage(
918
925
  inboxEndpoint,
919
926
  messageId,
920
927
  MESSAGE_LABEL_INVALID,
@@ -947,7 +954,7 @@ class GraffitiDecentralized {
947
954
  if (!past || past[LABELED_MESSAGE_MESSAGE_KEY][MESSAGE_OBJECT_KEY].url !== object.url)
948
955
  return;
949
956
  if (past[LABELED_MESSAGE_LABEL_KEY] !== MESSAGE_LABEL_TRASH) {
950
- this.inboxes.label(
957
+ this.labelInboxMessage(
951
958
  inboxEndpoint,
952
959
  tombstonedMessageId,
953
960
  MESSAGE_LABEL_TRASH,
@@ -1008,26 +1015,28 @@ class GraffitiDecentralized {
1008
1015
  }
1009
1016
  if (tombstonedMessageId) {
1010
1017
  if (validationError instanceof GraffitiErrorNotFound) {
1011
- this.inboxes.get(inboxEndpoint, tombstonedMessageId, inboxToken).then((result2) => {
1018
+ void this.inboxes.get(inboxEndpoint, tombstonedMessageId, inboxToken).then((result2) => {
1012
1019
  if (
1013
1020
  // Make sure that it actually references the object being deleted
1014
1021
  result2 && result2[LABELED_MESSAGE_MESSAGE_KEY][MESSAGE_OBJECT_KEY].url === object.url && // And that the object is not already marked as trash
1015
1022
  result2[LABELED_MESSAGE_LABEL_KEY] !== MESSAGE_LABEL_TRASH
1016
1023
  ) {
1017
- this.inboxes.label(
1024
+ this.labelInboxMessage(
1018
1025
  inboxEndpoint,
1019
1026
  tombstonedMessageId,
1020
1027
  MESSAGE_LABEL_TRASH,
1021
1028
  inboxToken
1022
1029
  );
1023
1030
  }
1024
- this.inboxes.label(
1031
+ this.labelInboxMessage(
1025
1032
  inboxEndpoint,
1026
1033
  messageId,
1027
1034
  MESSAGE_LABEL_TRASH,
1028
1035
  inboxToken
1029
1036
  );
1030
- });
1037
+ }).catch(
1038
+ (error) => console.error("Could not inspect tombstone message:", error)
1039
+ );
1031
1040
  return {
1032
1041
  messageId,
1033
1042
  tombstone: true,
@@ -1040,7 +1049,7 @@ class GraffitiDecentralized {
1040
1049
  } else {
1041
1050
  console.error("Recieved an incorrect tombstone object");
1042
1051
  console.error(validationError);
1043
- this.inboxes.label(
1052
+ this.labelInboxMessage(
1044
1053
  inboxEndpoint,
1045
1054
  messageId,
1046
1055
  MESSAGE_LABEL_INVALID,
@@ -1049,7 +1058,7 @@ class GraffitiDecentralized {
1049
1058
  }
1050
1059
  } else {
1051
1060
  if (validationError === void 0) {
1052
- this.inboxes.label(
1061
+ this.labelInboxMessage(
1053
1062
  inboxEndpoint,
1054
1063
  messageId,
1055
1064
  MESSAGE_LABEL_VALID,
@@ -1064,7 +1073,7 @@ class GraffitiDecentralized {
1064
1073
  announcements
1065
1074
  };
1066
1075
  } else if (validationError instanceof GraffitiErrorNotFound) {
1067
- this.inboxes.label(
1076
+ this.labelInboxMessage(
1068
1077
  inboxEndpoint,
1069
1078
  messageId,
1070
1079
  MESSAGE_LABEL_TRASH,
@@ -1073,7 +1082,7 @@ class GraffitiDecentralized {
1073
1082
  } else {
1074
1083
  console.error("Recieved an incorrect object");
1075
1084
  console.error(validationError);
1076
- this.inboxes.label(
1085
+ this.labelInboxMessage(
1077
1086
  inboxEndpoint,
1078
1087
  messageId,
1079
1088
  MESSAGE_LABEL_INVALID,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/3-protocol/4-graffiti.ts"],
4
- "sourcesContent": ["import type { JSONSchema } from \"json-schema-to-ts\";\nimport {\n GraffitiErrorNotFound,\n maskGraffitiObject,\n type Graffiti,\n type GraffitiLoginEvent,\n type GraffitiObjectBase,\n type GraffitiSession,\n type GraffitiObject,\n unpackObjectUrl,\n compileGraffitiObjectSchema,\n GraffitiErrorSchemaMismatch,\n GraffitiErrorForbidden,\n GraffitiErrorTooLarge,\n isMediaAcceptable,\n GraffitiErrorNotAcceptable,\n GraffitiErrorCursorExpired,\n GraffitiErrorInvalidSchema,\n type GraffitiObjectStream,\n} from \"@graffiti-garden/api\";\nimport { randomBytes } from \"@noble/hashes/utils.js\";\nimport {\n encode as dagCborEncode,\n decode as dagCborDecode,\n} from \"@ipld/dag-cbor\";\n\nimport { DecentralizedIdentifiers } from \"../1-services/2-dids\";\nimport { Authorization } from \"../1-services/1-authorization\";\nimport { StorageBuckets } from \"../1-services/3-storage-buckets\";\nimport {\n Inboxes,\n LABELED_MESSAGE_LABEL_KEY,\n LABELED_MESSAGE_MESSAGE_KEY,\n MESSAGE_METADATA_KEY,\n MESSAGE_OBJECT_KEY,\n MESSAGE_TAGS_KEY,\n type LabeledMessage,\n type MessageStream,\n} from \"../1-services/4-inboxes\";\nimport { GraffitiErrorUnauthorized } from \"../1-services/utilities\";\n\nimport {\n StringEncoder,\n STRING_ENCODER_METHOD_BASE64URL,\n} from \"../2-primitives/1-string-encoding\";\nimport { ContentAddresses } from \"../2-primitives/2-content-addresses\";\nimport {\n CHANNEL_ATTESTATION_METHOD_SHA256_ED25519,\n ChannelAttestations,\n} from \"../2-primitives/3-channel-attestations\";\nimport { AllowedAttestations } from \"../2-primitives/4-allowed-attestations\";\n\nimport { Handles } from \"./2-handles\";\nimport {\n Sessions,\n DID_SERVICE_ID_GRAFFITI_PERSONAL_INBOX,\n DID_SERVICE_TYPE_GRAFFITI_INBOX,\n DID_SERVICE_ID_GRAFFITI_STORAGE_BUCKET,\n DID_SERVICE_TYPE_GRAFFITI_STORAGE_BUCKET,\n} from \"./1-sessions\";\nimport {\n decodeObjectUrl,\n MAX_OBJECT_SIZE_BYTES,\n ObjectEncoding,\n} from \"./3-object-encoding\";\n\nimport { GraffitiModal } from \"@graffiti-garden/modal\";\nimport {\n type infer as infer_,\n custom,\n string,\n boolean,\n strictObject,\n array,\n int,\n nonnegative,\n optional,\n extend,\n union,\n record,\n url,\n} from \"zod/mini\";\n\nconst Uint8ArraySchema = custom<Uint8Array>(\n (v): v is Uint8Array => v instanceof Uint8Array,\n);\nconst MESSAGE_DATA_STORAGE_BUCKET_KEY = \"k\";\nconst MESSAGE_DATA_TOMBSTONED_MESSAGE_ID_KEY = \"t\";\nconst MessageMetadataBaseSchema = strictObject({\n [MESSAGE_DATA_STORAGE_BUCKET_KEY]: string(),\n [MESSAGE_DATA_TOMBSTONED_MESSAGE_ID_KEY]: optional(string()),\n});\nconst MESSAGE_DATA_ANNOUNCEMENT_MESSAGE_ID_KEY = \"id\";\nconst MESSAGE_DATA_ANNOUNCEMENT_ENDPOINT_KEY = \"e\";\nconst MESSAGE_DATA_ANNOUNCEMENT_ACTOR_KEY = \"a\";\nconst MessageMetadataAnnouncementsSchema = array(\n strictObject({\n [MESSAGE_DATA_ANNOUNCEMENT_MESSAGE_ID_KEY]: string(),\n [MESSAGE_DATA_ANNOUNCEMENT_ENDPOINT_KEY]: optional(url()),\n [MESSAGE_DATA_ANNOUNCEMENT_ACTOR_KEY]: optional(url()),\n }),\n);\nconst MESSAGE_DATA_ALLOWED_TICKETS_KEY = \"s\";\nconst MESSAGE_DATA_ANNOUNCEMENTS_KEY = \"n\";\nconst MessageMetaDataSelfSchema = extend(MessageMetadataBaseSchema, {\n [MESSAGE_DATA_ALLOWED_TICKETS_KEY]: optional(array(Uint8ArraySchema)),\n [MESSAGE_DATA_ANNOUNCEMENTS_KEY]: MessageMetadataAnnouncementsSchema,\n});\nconst MESSAGE_DATA_ALLOWED_TICKET_KEY = \"a\";\nconst MESSAGE_DATA_ALLOWED_TICKET_INDEX_KEY = \"i\";\nconst MessageMetadataPrivateSchema = extend(MessageMetadataBaseSchema, {\n [MESSAGE_DATA_ALLOWED_TICKET_KEY]: Uint8ArraySchema,\n [MESSAGE_DATA_ALLOWED_TICKET_INDEX_KEY]: int().check(nonnegative()),\n});\nconst MessageMetadataSchema = union([\n MessageMetadataBaseSchema,\n MessageMetaDataSelfSchema,\n MessageMetadataPrivateSchema,\n]);\ntype MessageMetadataBase = infer_<typeof MessageMetadataBaseSchema>;\ntype MessageMetadata = infer_<typeof MessageMetadataSchema>;\ntype MessageMetadataAnnouncements = infer_<\n typeof MessageMetadataAnnouncementsSchema\n>;\n\nconst MESSAGE_LABEL_UNLABELED = 0;\nconst MESSAGE_LABEL_VALID = 1;\nconst MESSAGE_LABEL_TRASH = 2;\nconst MESSAGE_LABEL_INVALID = 3;\n\nexport interface GraffitiDecentralizedOptions {\n identityCreatorEndpoint?: string;\n defaultInboxEndpoints?: string[];\n}\n\nconst CONCURRENCY = 128;\nconst LOCAL_STORAGE_REMEMBERED_HANDLE_KEY = \"graffiti-login-remembered-handle\";\n\nexport class GraffitiDecentralized implements Graffiti {\n protected readonly dids = new DecentralizedIdentifiers();\n protected readonly authorization = new Authorization();\n protected readonly storageBuckets = new StorageBuckets();\n protected readonly inboxes = new Inboxes();\n\n protected readonly stringEncoder = new StringEncoder();\n protected readonly contentAddresses = new ContentAddresses();\n protected readonly channelAttestations = new ChannelAttestations();\n protected readonly allowedAttestations = new AllowedAttestations();\n\n protected readonly sessions = new Sessions({\n dids: this.dids,\n authorization: this.authorization,\n storageBuckets: this.storageBuckets,\n inboxes: this.inboxes,\n });\n protected readonly handles = new Handles({ dids: this.dids });\n protected readonly objectEncoding = new ObjectEncoding({\n stringEncoder: this.stringEncoder,\n contentAddresses: this.contentAddresses,\n channelAttestations: this.channelAttestations,\n allowedAttestations: this.allowedAttestations,\n });\n\n protected readonly modal: GraffitiModal | undefined =\n typeof window === \"undefined\"\n ? undefined\n : new GraffitiModal({\n useTemplateHTML: () =>\n import(\"./login-dialog.html\").then(({ template }) => template),\n onManualClose: () => {\n const event = new CustomEvent(\"login\", {\n detail: {\n error: new Error(\"User cancelled login\"),\n manual: true,\n },\n });\n this.sessionEvents.dispatchEvent(event);\n },\n });\n\n protected readonly defaultInboxEndpoints: string[];\n protected readonly identityCreatorEndpoint: string;\n constructor(options?: GraffitiDecentralizedOptions) {\n this.defaultInboxEndpoints = options?.defaultInboxEndpoints ?? [\n \"https://graffiti.actor/i/shared\",\n ];\n this.identityCreatorEndpoint =\n options?.identityCreatorEndpoint ?? \"https://graffiti.actor/create\";\n\n this.sessionEvents.addEventListener(\"login\", async (event) => {\n if (!(event instanceof CustomEvent)) return;\n const detail = event.detail as GraffitiLoginEvent[\"detail\"];\n\n if (detail.error !== undefined) {\n // If \"manual\", the window was closed by the user, nothing to do\n if (\"manual\" in detail && detail.manual) return;\n\n alert(\"Login failed: \" + detail.error.message);\n const actor = detail.session?.actor;\n let handle: string | undefined;\n if (actor) {\n try {\n handle = await this.actorToHandle(actor);\n } catch (error) {\n console.error(\"Failed to handle actor:\", error);\n }\n }\n // Open the login window again with the failed actor\n this.login_(handle);\n return;\n }\n\n const actor = detail.session.actor;\n\n let handle: string | undefined;\n try {\n handle = await this.actorToHandle(actor);\n } catch (error) {\n console.error(\"Failed to load handle from actor:\", error);\n }\n\n if (handle) {\n this.rememberHandleInBrowserStorage(handle);\n }\n });\n\n // If any methods throw an unauthorized error,\n // log out the used session\n for (const method of [\n \"post\",\n \"get\",\n \"delete\",\n \"postMedia\",\n \"getMedia\",\n \"deleteMedia\",\n ]) {\n const fn = (this as any)[method];\n (this as any)[method] = async (...args: unknown[]) => {\n try {\n return await fn(...args);\n } catch (e) {\n const session = args[args.length - 1] as any;\n await this.tryLogoutIfUnauthorized(e, session);\n throw e;\n }\n };\n }\n }\n\n readonly actorToHandle: Graffiti[\"actorToHandle\"] =\n this.handles.actorToHandle.bind(this.handles);\n readonly handleToActor: Graffiti[\"handleToActor\"] =\n this.handles.handleToActor.bind(this.handles);\n readonly sessionEvents: Graffiti[\"sessionEvents\"] =\n this.sessions.sessionEvents;\n\n login: Graffiti[\"login\"] = async (actor?: string) => {\n try {\n let proposedHandle: string | undefined;\n try {\n proposedHandle = actor ? await this.actorToHandle(actor) : undefined;\n } catch (error) {\n console.error(\"Error fetching handle for actor:\", error);\n }\n\n await this.login_(proposedHandle);\n } catch (e) {\n const loginError: GraffitiLoginEvent = new CustomEvent(\"login\", {\n detail: {\n error: e instanceof Error ? e : new Error(String(e)),\n },\n });\n this.sessionEvents.dispatchEvent(loginError);\n }\n };\n protected async login_(proposedHandle?: string) {\n if (typeof window !== \"undefined\") {\n let template: HTMLElement | undefined;\n if (proposedHandle !== undefined) {\n template = await this.modal?.displayTemplate(\"graffiti-login-handle\");\n const input = template?.querySelector(\n \"#username\",\n ) as HTMLInputElement | null;\n const rememberedHandle =\n proposedHandle || this.getRememberedHandleFromBrowserStorage();\n if (input) input.value = rememberedHandle ?? \"\";\n input?.addEventListener(\"focus\", () => input?.select());\n setTimeout(() => input?.focus(), 0);\n\n template\n ?.querySelector(\"#graffiti-login-handle-form\")\n ?.addEventListener(\"submit\", async (e) => {\n e.preventDefault();\n input?.setAttribute(\"disabled\", \"true\");\n const submitButton = template?.querySelector(\n \"#graffiti-login-handle-submit\",\n ) as HTMLButtonElement | null;\n submitButton?.setAttribute(\"disabled\", \"true\");\n submitButton && (submitButton.innerHTML = \"Logging in...\");\n\n if (!input?.value) {\n alert(\"No handle provided\");\n this.login_(\"\");\n return;\n }\n\n let handle = input.value;\n if (!handle.includes(\".\") && !handle.startsWith(\"localhost\")) {\n const defaultHost = new URL(this.identityCreatorEndpoint).host;\n handle = `${handle}.${defaultHost}`;\n }\n\n let actor: string;\n try {\n actor = await this.handleToActor(handle);\n } catch (e) {\n alert(\"Could not find an identity associated with that handle.\");\n this.login_(handle);\n return;\n }\n\n try {\n await this.sessions.login(actor);\n } catch (e) {\n alert(\"Error logging in.\");\n console.error(e);\n this.login_(handle);\n }\n });\n template\n ?.querySelector(\"#graffiti-login-forgot\")\n ?.addEventListener(\"click\", (e) => {\n e.preventDefault();\n void this.loginWithoutHandle();\n });\n } else {\n template = await this.modal?.displayTemplate(\"graffiti-login-welcome\");\n template\n ?.querySelector(\"#graffiti-login-existing\")\n ?.addEventListener(\"click\", (e) => {\n e.preventDefault();\n this.login_(\"\");\n });\n\n setTimeout(\n () =>\n (\n template?.querySelector(\n \"#graffiti-login-new\",\n ) as HTMLAnchorElement\n )?.focus(),\n 0,\n );\n }\n\n const createUrl = new URL(this.identityCreatorEndpoint);\n createUrl.searchParams.set(\n \"redirect_uri\",\n encodeURIComponent(window.location.toString()),\n );\n template\n ?.querySelector(\"#graffiti-login-new\")\n ?.setAttribute(\"href\", createUrl.toString());\n\n await this.modal?.open();\n } else {\n // Node.js environment\n const readline = await import(\"readline\").catch((e) => {\n throw new Error(\n \"Unrecognized environment: neither window nor readline\",\n );\n });\n\n console.log(\n \"If you do not already have a Graffiti handle, you can create one here:\",\n );\n console.log(this.identityCreatorEndpoint);\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n const handle: string | undefined = await new Promise((resolve) => {\n rl.question(\n `Please enter your handle${proposedHandle ? ` (default: ${proposedHandle})` : \"\"}: `,\n (input) => {\n rl.close();\n resolve(input || proposedHandle);\n },\n );\n });\n\n if (!handle) {\n throw new Error(\"No handle provided\");\n }\n\n // Convert the handle to an actor\n const actor = await this.handleToActor(handle);\n\n await this.sessions.login(actor);\n }\n }\n\n protected async loginWithoutHandle() {\n const template = await this.modal?.displayTemplate(\"graffiti-login-provider\");\n const defaultProvider = new URL(\"/\", this.identityCreatorEndpoint);\n const provider = template?.querySelector(\"#graffiti-provider\") as HTMLInputElement | null;\n if (provider) provider.value = defaultProvider.host;\n provider?.addEventListener(\"focus\", () => provider.select());\n setTimeout(() => provider?.focus(), 0);\n\n template\n ?.querySelector(\"#graffiti-login-provider-form\")\n ?.addEventListener(\"submit\", (event) => {\n event.preventDefault();\n try {\n const domain = provider?.value.trim() ?? \"\";\n const origin = domain === defaultProvider.host\n ? defaultProvider\n : new URL(`https://${domain}`);\n if (\n !origin.hostname || origin.username || origin.password ||\n origin.pathname !== \"/\" || origin.search || origin.hash\n ) throw new Error(\"Invalid provider domain\");\n\n const url = new URL(\"/forgot-handle\", origin);\n url.searchParams.set(\"redirect_uri\", window.location.toString());\n window.location.assign(url.toString());\n } catch {\n alert(\"Enter a valid provider domain.\");\n }\n });\n\n template\n ?.querySelector(\"#graffiti-login-provider-back\")\n ?.addEventListener(\"click\", (event) => {\n event.preventDefault();\n void this.login_(\"\");\n });\n\n await this.modal?.open();\n }\n\n protected rememberHandleInBrowserStorage(handle: string) {\n if (typeof window === \"undefined\") return;\n\n try {\n window.localStorage.setItem(LOCAL_STORAGE_REMEMBERED_HANDLE_KEY, handle);\n } catch (error) {\n console.error(\"Failed to remember handle in browser storage:\", error);\n }\n }\n\n protected getRememberedHandleFromBrowserStorage() {\n if (typeof window === \"undefined\") return undefined;\n\n try {\n return (\n window.localStorage.getItem(LOCAL_STORAGE_REMEMBERED_HANDLE_KEY) ??\n undefined\n );\n } catch (error) {\n console.error(\"Failed to load handle from browser storage:\", error);\n return undefined;\n }\n }\n\n logout: Graffiti[\"logout\"] = async (session) => {\n await this.sessions.logout(session.actor);\n };\n\n // @ts-ignore\n post: Graffiti[\"post\"] = async (...args) => {\n const [partialObject, session] = args;\n const resolvedSession = this.sessions.resolveSession(session);\n\n // Encode the object\n const { object, tags, objectBytes, allowedTickets } =\n await this.objectEncoding.encode<{}>(partialObject, session.actor);\n\n // Generate a random key under which to store the object\n // If the object is private, this means no one will be able to\n // fetch the object, even if they know its URL.\n // If the object is public but in some secret channel, the storage\n // location means the object can be moved around or \"rotated\"\n // without changing its URL.\n const storageBucketKeyBytes = randomBytes();\n const storageBucketKey = await this.stringEncoder.encode(\n STRING_ENCODER_METHOD_BASE64URL,\n storageBucketKeyBytes,\n );\n\n // Store the object at the random key\n await this.storageBuckets.put(\n resolvedSession.storageBucket.serviceEndpoint,\n storageBucketKey,\n objectBytes,\n resolvedSession.storageBucket.token,\n );\n\n // Announce the object, its key,\n // and other metadata to appropriate inboxes\n await this.announceObject(\n object,\n tags,\n allowedTickets,\n storageBucketKey,\n session,\n );\n\n return object;\n };\n\n get: Graffiti[\"get\"] = async (...args) => {\n const [url, schema, session] = args;\n let services: { token?: string; serviceEndpoint: string }[];\n const validator = await compileGraffitiObjectSchema(schema);\n\n if (session) {\n // If logged in, first search one's\n // personal inbox, then any shared inboxes\n const resolvedSession = this.sessions.resolveSession(session);\n services = [\n resolvedSession.personalInbox,\n ...resolvedSession.sharedInboxes,\n ];\n } else {\n // Otherwise, search the default inboxes\n services = this.defaultInboxEndpoints.map((s) => ({\n serviceEndpoint: s,\n }));\n }\n\n // Search the inboxes for all objects\n // matching the tag, object.url\n const objectUrl = unpackObjectUrl(url);\n const tags = [new TextEncoder().encode(objectUrl)];\n for (const service of services) {\n let object: GraffitiObjectBase | undefined = undefined;\n\n const iterator = this.querySingleEndpoint<{}>(\n service.serviceEndpoint,\n {\n tags,\n objectSchema: {},\n },\n service.token,\n session?.actor,\n );\n\n for await (const result of iterator) {\n if (result.object.url !== objectUrl) continue;\n if (result.tombstone) {\n object = undefined;\n } else {\n object = result.object;\n }\n }\n\n if (object) {\n if (!validator(object)) {\n throw new GraffitiErrorSchemaMismatch(\n \"Object exists but does not match the supplied schema\",\n );\n }\n\n return object;\n }\n }\n\n throw new GraffitiErrorNotFound(\"Object not found\");\n };\n\n delete: Graffiti[\"delete\"] = async (url, session) => {\n const resolvedSession = this.sessions.resolveSession(session);\n\n const objectUrl = unpackObjectUrl(url);\n\n const { actor } = decodeObjectUrl(objectUrl);\n if (actor !== session.actor) {\n throw new GraffitiErrorForbidden(\"Cannot delete someone else's actor\");\n }\n\n // Look in one's personal inbox for the object\n const iterator = this.querySingleEndpoint<{}>(\n resolvedSession.personalInbox.serviceEndpoint,\n {\n tags: [new TextEncoder().encode(objectUrl)],\n objectSchema: {},\n },\n resolvedSession.personalInbox.token,\n );\n let existing: SingleEndpointQueryResult<{}> | undefined;\n for await (const result of iterator) {\n if (result.object.url !== objectUrl) continue;\n if (result.tombstone) {\n existing = undefined;\n } else {\n existing = result;\n }\n }\n if (!existing) {\n throw new GraffitiErrorNotFound(`Object ${objectUrl} not found`);\n }\n const {\n object,\n storageBucketKey,\n tags,\n allowedTickets,\n announcements,\n messageId,\n } = existing;\n\n // Delete the object from the actor's own storage bucket\n await this.storageBuckets.delete(\n resolvedSession.storageBucket.serviceEndpoint,\n storageBucketKey,\n resolvedSession.storageBucket.token,\n );\n\n // Announce the deletion to all inboxes\n await this.announceObject(\n object,\n tags,\n allowedTickets,\n storageBucketKey,\n session,\n [\n ...(announcements ?? []),\n // Make sure we delete from our own inbox too\n {\n [MESSAGE_DATA_ANNOUNCEMENT_ACTOR_KEY]: session.actor,\n [MESSAGE_DATA_ANNOUNCEMENT_MESSAGE_ID_KEY]: messageId,\n },\n ],\n );\n\n return object;\n };\n\n postMedia: Graffiti[\"postMedia\"] = async (...args) => {\n const [media, session] = args;\n\n const type = media.data.type;\n\n const resolvedSession = this.sessions.resolveSession(session);\n\n // Generate a random storage key\n const keyBytes = randomBytes();\n const key = await this.stringEncoder.encode(\n STRING_ENCODER_METHOD_BASE64URL,\n keyBytes,\n );\n\n // Store the media at that key\n await this.storageBuckets.put(\n resolvedSession.storageBucket.serviceEndpoint,\n key,\n new Uint8Array(await media.data.arrayBuffer()),\n resolvedSession.storageBucket.token,\n );\n\n // Create an object\n const { url } = await this.post<typeof MEDIA_OBJECT_SCHEMA>(\n {\n value: {\n key,\n type,\n size: media.data.size,\n },\n channels: [],\n allowed: media.allowed,\n },\n session,\n );\n\n return url;\n };\n\n getMedia: Graffiti[\"getMedia\"] = async (...args) => {\n const [mediaUrl, accept, session] = args;\n\n if (\n accept?.maxBytes !== undefined &&\n (!Number.isSafeInteger(accept.maxBytes) || accept.maxBytes < 0)\n ) {\n throw new TypeError(\"maxBytes must be a nonnegative safe integer\");\n }\n\n const object = await this.get<typeof MEDIA_OBJECT_SCHEMA>(\n mediaUrl,\n MEDIA_OBJECT_SCHEMA,\n session,\n );\n\n const { key, type, size } = object.value;\n\n if (accept?.maxBytes !== undefined && size > accept.maxBytes) {\n throw new GraffitiErrorTooLarge(\"File size exceeds limit\");\n }\n\n // Make sure it adheres to requirements.accept\n if (accept?.types) {\n if (!isMediaAcceptable(type, accept.types)) {\n throw new GraffitiErrorNotAcceptable(\n `Unacceptable media type, ${type}`,\n );\n }\n }\n\n // Get the actor's storage bucket endpoint\n const actorDocument = await this.dids.resolve(object.actor);\n const storageBucketService = actorDocument?.service?.find(\n (service) =>\n service.id === DID_SERVICE_ID_GRAFFITI_STORAGE_BUCKET &&\n service.type === DID_SERVICE_TYPE_GRAFFITI_STORAGE_BUCKET,\n );\n if (!storageBucketService) {\n throw new GraffitiErrorNotFound(\n `Actor ${object.actor} has no storage bucket service`,\n );\n }\n if (typeof storageBucketService.serviceEndpoint !== \"string\") {\n throw new GraffitiErrorNotFound(\n `Actor ${object.actor} does not have a valid storage bucket endpoint`,\n );\n }\n const storageBucketEndpoint = storageBucketService.serviceEndpoint;\n\n const data = await this.storageBuckets.get(\n storageBucketEndpoint,\n key,\n size,\n );\n\n const blob = new Blob([data.slice()], { type });\n\n return {\n data: blob,\n actor: object.actor,\n allowed: object.allowed,\n };\n };\n\n deleteMedia: Graffiti[\"deleteMedia\"] = async (...args) => {\n const [mediaUrl, session] = args;\n\n const resolvedSession = this.sessions.resolveSession(session);\n\n const result = await this.delete(mediaUrl, session);\n\n if (!(\"key\" in result.value && typeof result.value.key === \"string\"))\n throw new Error(\n \"Deleted object was not media: \" + JSON.stringify(result, null, 2),\n );\n\n await this.storageBuckets.delete(\n resolvedSession.storageBucket.serviceEndpoint,\n result.value.key,\n resolvedSession.storageBucket.token,\n );\n };\n\n async *discoverMeta<Schema extends JSONSchema>(\n channels: string[],\n schema: Schema,\n cursors: {\n [endpoint: string]: string;\n },\n session?: GraffitiSession | null,\n ): GraffitiObjectStream<Schema> {\n const tombstones = new Map<string, boolean>();\n\n let allInboxes: { serviceEndpoint: string; token?: string }[];\n if (session) {\n const resolvedSession = this.sessions.resolveSession(session);\n allInboxes = [\n resolvedSession.personalInbox,\n ...resolvedSession.sharedInboxes,\n ];\n } else {\n allInboxes = this.defaultInboxEndpoints.map((e) => ({\n serviceEndpoint: e,\n }));\n }\n\n // Make sure all cursors are represented by an inbox\n for (const endpoint in cursors) {\n if (!allInboxes.some((i) => i.serviceEndpoint === endpoint)) {\n throw new GraffitiErrorForbidden(\n \"Cursor does not match actor's inboxes\",\n );\n }\n }\n\n // Turn the channels into tags\n const tags = await Promise.all(\n channels.map((c) =>\n this.channelAttestations.register(\n CHANNEL_ATTESTATION_METHOD_SHA256_ED25519,\n c,\n ),\n ),\n );\n\n const iterators: SingleEndpointQueryIterator<Schema>[] = allInboxes.map(\n (i) => {\n const cursor = cursors[i.serviceEndpoint];\n return this.querySingleEndpoint<Schema>(\n i.serviceEndpoint,\n cursor\n ? {\n cursor,\n }\n : {\n tags,\n objectSchema: schema,\n },\n i.token,\n session?.actor,\n );\n },\n );\n\n let indexedIteratorNexts = iterators.map<\n Promise<IndexedSingleEndpointQueryResult<Schema>>\n >(async (it, index) => indexedSingleEndpointQueryNext<Schema>(it, index));\n let active = indexedIteratorNexts.length;\n\n try {\n while (active > 0) {\n const next: IndexedSingleEndpointQueryResult<Schema> =\n await Promise.race<any>(indexedIteratorNexts);\n if (next.error !== undefined) {\n // Remove it from the race\n indexedIteratorNexts[next.index] = new Promise(() => {});\n active--;\n yield {\n error: next.error,\n origin: allInboxes[next.index].serviceEndpoint,\n };\n this.tryLogoutIfUnauthorized(next.error, session);\n } else if (next.result.done) {\n // Store the cursor for future use\n const inbox = allInboxes[next.index];\n cursors[inbox.serviceEndpoint] = next.result.value;\n // Remove it from the race\n indexedIteratorNexts[next.index] = new Promise(() => {});\n active--;\n } else {\n // Re-arm the iterator\n indexedIteratorNexts[next.index] =\n indexedSingleEndpointQueryNext<Schema>(\n iterators[next.index],\n next.index,\n );\n const { object, tombstone, tags: receivedTags } = next.result.value;\n if (tombstone) {\n if (tombstones.get(object.url) === true) continue;\n tombstones.set(object.url, true);\n yield {\n tombstone,\n object: { url: object.url },\n };\n } else {\n // Filter already seen\n if (tombstones.get(object.url) === false) continue;\n\n // Fill in the matched channels\n const matchedTagIndices = tags.reduce<number[]>(\n (acc, tag, tagIndex) => {\n for (const receivedTag of receivedTags) {\n if (\n tag.length === receivedTag.length &&\n tag.every((b, i) => receivedTag[i] === b)\n ) {\n acc.push(tagIndex);\n break;\n }\n }\n return acc;\n },\n [],\n );\n const matchedChannels = matchedTagIndices.map(\n (index) => channels[index],\n );\n if (matchedChannels.length === 0) {\n yield {\n error: new Error(\n \"Inbox returned object without matching channels\",\n ),\n origin: allInboxes[next.index].serviceEndpoint,\n };\n }\n tombstones.set(object.url, false);\n yield {\n object: {\n ...object,\n channels: matchedChannels,\n },\n };\n }\n }\n }\n } catch (e) {\n this.tryLogoutIfUnauthorized(e, session);\n throw e;\n } finally {\n await Promise.all(\n iterators.map<Promise<void>>(async (it) => {\n await it.return(\"\");\n }),\n );\n }\n\n return {\n cursor: JSON.stringify({\n channels,\n cursors,\n } satisfies infer_<typeof CursorSchema>),\n };\n }\n\n discover: Graffiti[\"discover\"] = (...args) => {\n const [channels, schema, session] = args;\n return this.discoverMeta<(typeof args)[1]>(channels, schema, {}, session);\n };\n\n // @ts-ignore\n continueDiscover: Graffiti[\"continueDiscover\"] = (...args) => {\n const [cursor, session] = args;\n // Extract the channels from the cursor\n let channels: string[];\n let cursors: { [endpoint: string]: string };\n try {\n const json = JSON.parse(cursor);\n const parsed = CursorSchema.parse(json);\n channels = parsed.channels;\n cursors = parsed.cursors;\n } catch (error) {\n return (async function* () {\n throw new GraffitiErrorCursorExpired(\"Invalid cursor\");\n })();\n }\n return this.discoverMeta<{}>(channels, {}, cursors, session);\n };\n\n protected async tryLogoutIfUnauthorized(\n e: unknown,\n session?: GraffitiSession | null,\n ) {\n if (e instanceof GraffitiErrorUnauthorized && session) {\n await this.sessions.logout(session.actor);\n }\n }\n\n async announceObject(\n object: GraffitiObjectBase,\n tags: Uint8Array[],\n allowedTickets: Uint8Array[] | undefined,\n storageBucketKey: string,\n session: GraffitiSession,\n priorAnnouncements?: MessageMetadataAnnouncements,\n ): Promise<void> {\n const resolvedSession = this.sessions.resolveSession(session);\n\n const metadataBase: MessageMetadataBase = {\n [MESSAGE_DATA_STORAGE_BUCKET_KEY]: storageBucketKey,\n };\n\n const announcements: MessageMetadataAnnouncements = [];\n const allowed = object.allowed;\n if (Array.isArray(allowed)) {\n if (!allowedTickets || allowedTickets.length !== allowed.length) {\n throw new Error(\n \"If allowed actors are specified, there must be a corresponding ticket for each allowed actor\",\n );\n }\n\n // Send the object to each allowed recipient's personal inbox\n const results = await Promise.allSettled(\n allowed.map(async (recipient, recipientIndex) => {\n // Mask the object to not include any channels\n // and only include the recipient actor on the allowed list\n const copy = JSON.parse(JSON.stringify(object)) as GraffitiObjectBase;\n const masked = maskGraffitiObject(copy, [], recipient);\n\n // Get the recipient's inbox\n const actorDocument = await this.dids.resolve(recipient);\n const personalInbox = actorDocument.service?.find(\n (service) =>\n service.type === DID_SERVICE_TYPE_GRAFFITI_INBOX &&\n service.id === DID_SERVICE_ID_GRAFFITI_PERSONAL_INBOX,\n );\n if (!personalInbox) {\n throw new Error(\n `Recipient ${recipient} does not have a personal inbox`,\n );\n }\n if (typeof personalInbox.serviceEndpoint !== \"string\") {\n throw new Error(\n `Recipient ${recipient} does not have a valid personal inbox endpoint`,\n );\n }\n\n const tombstonedMessageId = priorAnnouncements\n ? priorAnnouncements.find(\n (a) => a[MESSAGE_DATA_ANNOUNCEMENT_ACTOR_KEY] === recipient,\n )?.[MESSAGE_DATA_ANNOUNCEMENT_MESSAGE_ID_KEY]\n : undefined;\n\n // Announce to the inbox\n const privateMetadata: MessageMetadata = {\n ...metadataBase,\n ...(tombstonedMessageId\n ? {\n [MESSAGE_DATA_TOMBSTONED_MESSAGE_ID_KEY]: tombstonedMessageId,\n }\n : {}),\n [MESSAGE_DATA_ALLOWED_TICKET_KEY]: allowedTickets[recipientIndex],\n [MESSAGE_DATA_ALLOWED_TICKET_INDEX_KEY]: recipientIndex,\n };\n const messageId = await this.inboxes.send(\n personalInbox.serviceEndpoint,\n {\n [MESSAGE_TAGS_KEY]: tags,\n [MESSAGE_OBJECT_KEY]: masked,\n [MESSAGE_METADATA_KEY]: dagCborEncode(privateMetadata),\n },\n );\n\n announcements.push({\n [MESSAGE_DATA_ANNOUNCEMENT_MESSAGE_ID_KEY]: messageId,\n [MESSAGE_DATA_ANNOUNCEMENT_ACTOR_KEY]: recipient,\n });\n }),\n );\n\n for (const [index, result] of results.entries()) {\n if (result.status === \"rejected\") {\n const recipient = allowed[index];\n console.error(\"Error sending to recipient:\", recipient);\n console.error(result.reason);\n }\n }\n } else {\n // Mask the object to not include any channels\n // and only include the recipient actor on the allowed list\n const copy = JSON.parse(JSON.stringify(object)) as GraffitiObjectBase;\n const masked = maskGraffitiObject(copy, []);\n\n // Send the object to each shared inbox\n const sharedInboxes = resolvedSession.sharedInboxes;\n const results = await Promise.allSettled(\n sharedInboxes.map(async (inbox) => {\n const tombstonedMessageId = priorAnnouncements\n ? priorAnnouncements.find(\n (a) =>\n a[MESSAGE_DATA_ANNOUNCEMENT_ENDPOINT_KEY] ===\n inbox.serviceEndpoint,\n )?.[MESSAGE_DATA_ANNOUNCEMENT_MESSAGE_ID_KEY]\n : undefined;\n const metadata: MessageMetadata = {\n ...metadataBase,\n ...(tombstonedMessageId\n ? {\n [MESSAGE_DATA_TOMBSTONED_MESSAGE_ID_KEY]: tombstonedMessageId,\n }\n : {}),\n };\n\n const messageId = await this.inboxes.send(inbox.serviceEndpoint, {\n ...(tombstonedMessageId\n ? {\n [MESSAGE_DATA_TOMBSTONED_MESSAGE_ID_KEY]: tombstonedMessageId,\n }\n : {}),\n [MESSAGE_TAGS_KEY]: tags,\n [MESSAGE_OBJECT_KEY]: masked,\n [MESSAGE_METADATA_KEY]: dagCborEncode(metadata),\n });\n announcements.push({\n [MESSAGE_DATA_ANNOUNCEMENT_MESSAGE_ID_KEY]: messageId,\n [MESSAGE_DATA_ANNOUNCEMENT_ENDPOINT_KEY]: inbox.serviceEndpoint,\n });\n }),\n );\n\n for (const [index, result] of results.entries()) {\n if (result.status === \"rejected\") {\n const inbox = sharedInboxes[index];\n console.error(\"Error sending to inbox:\", inbox);\n console.error(result.reason);\n }\n }\n }\n\n // Send the complete object to my own personal inbox\n // along with its key and allowed tickets\n const tombstonedMessageId = priorAnnouncements\n ? priorAnnouncements.find(\n (a) => a[MESSAGE_DATA_ANNOUNCEMENT_ACTOR_KEY] === session.actor,\n )?.[MESSAGE_DATA_ANNOUNCEMENT_MESSAGE_ID_KEY]\n : undefined;\n const selfMetadata: MessageMetadata = {\n ...metadataBase,\n ...(allowedTickets\n ? {\n [MESSAGE_DATA_ALLOWED_TICKETS_KEY]: allowedTickets,\n }\n : {}),\n ...(tombstonedMessageId\n ? {\n [MESSAGE_DATA_TOMBSTONED_MESSAGE_ID_KEY]: tombstonedMessageId,\n }\n : {}),\n [MESSAGE_DATA_ANNOUNCEMENTS_KEY]: announcements,\n };\n await this.inboxes.send(resolvedSession.personalInbox.serviceEndpoint, {\n [MESSAGE_TAGS_KEY]: tags,\n [MESSAGE_OBJECT_KEY]: object,\n [MESSAGE_METADATA_KEY]: dagCborEncode(selfMetadata),\n });\n }\n\n protected async *querySingleEndpoint<Schema extends JSONSchema>(\n inboxEndpoint: string,\n queryArguments:\n | {\n tags: Uint8Array[];\n objectSchema: Schema;\n }\n | {\n cursor: string;\n },\n inboxToken?: string | null,\n recipient?: string | null,\n ): SingleEndpointQueryIterator<Schema> {\n const iterator: MessageStream<Schema> =\n \"tags\" in queryArguments\n ? this.inboxes.query<Schema>(\n inboxEndpoint,\n queryArguments.tags,\n queryArguments.objectSchema,\n inboxToken,\n )\n : (this.inboxes.continueQuery(\n inboxEndpoint,\n queryArguments.cursor,\n inboxToken,\n ) as unknown as MessageStream<Schema>);\n\n const inFlight: Promise<SingleEndpointQueryResult<Schema> | void>[] = [];\n let doneValue: string | null = null;\n\n try {\n while (true) {\n while (doneValue === null && inFlight.length < CONCURRENCY) {\n const itResult = await iterator.next();\n if (itResult.done) {\n doneValue = itResult.value;\n break;\n }\n\n const processPromise = this.processOneLabeledMessage<Schema>(\n inboxEndpoint,\n itResult.value,\n inboxToken,\n recipient,\n ).catch((e) => {\n throw e;\n });\n\n inFlight.push(processPromise);\n }\n\n const nextProcessedPromise = inFlight.shift();\n\n if (!nextProcessedPromise) {\n if (doneValue !== null) return doneValue;\n\n throw new Error(\"Process queue empty but no return value\");\n }\n\n const processed = await nextProcessedPromise;\n if (processed) yield processed;\n }\n } finally {\n await iterator.return(\"\");\n }\n }\n\n protected async processOneLabeledMessage<Schema extends JSONSchema>(\n inboxEndpoint: string,\n result: LabeledMessage<Schema>,\n inboxToken?: string | null,\n recipient?: string | null,\n ): Promise<SingleEndpointQueryResult<Schema> | void> {\n const label = result.l;\n // Anything invalid or unexpected, we can skip\n if (\n label !== MESSAGE_LABEL_VALID &&\n label !== MESSAGE_LABEL_UNLABELED &&\n label !== MESSAGE_LABEL_TRASH\n )\n return;\n\n const messageId = result.id;\n const { o: object, m: metadataBytes, t: receivedTags } = result.m;\n\n let metadata: MessageMetadata;\n try {\n const metadataRaw = dagCborDecode(metadataBytes);\n metadata = MessageMetadataSchema.parse(metadataRaw);\n } catch (e) {\n this.inboxes.label(\n inboxEndpoint,\n messageId,\n MESSAGE_LABEL_INVALID,\n inboxToken,\n );\n return;\n }\n\n const {\n [MESSAGE_DATA_STORAGE_BUCKET_KEY]: storageBucketKey,\n [MESSAGE_DATA_TOMBSTONED_MESSAGE_ID_KEY]: tombstonedMessageId,\n } = metadata;\n\n const allowedTickets =\n MESSAGE_DATA_ALLOWED_TICKETS_KEY in metadata\n ? metadata[MESSAGE_DATA_ALLOWED_TICKETS_KEY]\n : undefined;\n const announcements =\n MESSAGE_DATA_ANNOUNCEMENTS_KEY in metadata\n ? metadata[MESSAGE_DATA_ANNOUNCEMENTS_KEY]\n : undefined;\n\n if (label === MESSAGE_LABEL_VALID) {\n return {\n messageId,\n object,\n storageBucketKey,\n allowedTickets,\n tags: receivedTags,\n announcements,\n };\n } else if (label === MESSAGE_LABEL_TRASH) {\n // If it is simply trash, just continue.\n if (!tombstonedMessageId) return;\n\n // Make sure the tombstone points to a real message\n const past = await this.inboxes.get(\n inboxEndpoint,\n tombstonedMessageId,\n inboxToken,\n );\n if (\n !past ||\n past[LABELED_MESSAGE_MESSAGE_KEY][MESSAGE_OBJECT_KEY].url !== object.url\n )\n return;\n\n // If the referred to message isn't labeled as trash, trash it\n // This may happen if a trash message is processed on another\n // device and the device cache is out of date.\n if (past[LABELED_MESSAGE_LABEL_KEY] !== MESSAGE_LABEL_TRASH) {\n // Label the message as trash\n this.inboxes.label(\n inboxEndpoint,\n tombstonedMessageId,\n MESSAGE_LABEL_TRASH,\n inboxToken,\n );\n }\n\n // Return the tombstone\n return {\n messageId,\n tombstone: true,\n object,\n storageBucketKey,\n allowedTickets,\n tags: receivedTags,\n announcements,\n };\n }\n\n // Otherwise, unlabeled: try to validate the object\n let validationError: unknown | undefined = undefined;\n try {\n const actor = object.actor;\n const actorDocument = await this.dids.resolve(actor);\n const storageBucketService = actorDocument?.service?.find(\n (service) =>\n service.id === DID_SERVICE_ID_GRAFFITI_STORAGE_BUCKET &&\n service.type === DID_SERVICE_TYPE_GRAFFITI_STORAGE_BUCKET,\n );\n if (!storageBucketService) {\n throw new GraffitiErrorNotFound(\n `Actor ${actor} has no storage bucket service`,\n );\n }\n if (typeof storageBucketService.serviceEndpoint !== \"string\") {\n throw new GraffitiErrorNotFound(\n `Actor ${actor} does not have a valid storage bucket endpoint`,\n );\n }\n const storageBucketEndpoint = storageBucketService.serviceEndpoint;\n\n const objectBytes = await this.storageBuckets.get(\n storageBucketEndpoint,\n storageBucketKey,\n MAX_OBJECT_SIZE_BYTES,\n );\n\n if (MESSAGE_DATA_ALLOWED_TICKET_KEY in metadata && !recipient) {\n throw new GraffitiErrorForbidden(\n `Recipient is required when allowed ticket is present`,\n );\n }\n const privateObjectInfo = allowedTickets\n ? { allowedTickets }\n : MESSAGE_DATA_ALLOWED_TICKET_KEY in metadata\n ? {\n recipient: recipient ?? \"null\",\n allowedTicket: metadata[MESSAGE_DATA_ALLOWED_TICKET_KEY],\n allowedIndex: metadata[MESSAGE_DATA_ALLOWED_TICKET_INDEX_KEY],\n }\n : undefined;\n\n await this.objectEncoding.validate(\n object,\n receivedTags,\n objectBytes,\n privateObjectInfo,\n );\n } catch (e) {\n validationError = e;\n }\n\n if (tombstonedMessageId) {\n if (validationError instanceof GraffitiErrorNotFound) {\n // Not found == The tombstone is correct\n this.inboxes\n // Get the referenced message\n .get(inboxEndpoint, tombstonedMessageId, inboxToken)\n .then((result) => {\n if (\n // Make sure that it actually references the object being deleted\n result &&\n result[LABELED_MESSAGE_MESSAGE_KEY][MESSAGE_OBJECT_KEY].url ===\n object.url &&\n // And that the object is not already marked as trash\n result[LABELED_MESSAGE_LABEL_KEY] !== MESSAGE_LABEL_TRASH\n ) {\n // If valid but not yet trash, label the message as trash\n this.inboxes.label(\n inboxEndpoint,\n tombstonedMessageId,\n MESSAGE_LABEL_TRASH,\n inboxToken,\n );\n }\n\n // Then, label the tombstone message as trash\n this.inboxes.label(\n inboxEndpoint,\n messageId,\n MESSAGE_LABEL_TRASH,\n inboxToken,\n );\n });\n\n return {\n messageId,\n tombstone: true,\n object,\n storageBucketKey,\n allowedTickets,\n tags: receivedTags,\n announcements,\n };\n } else {\n console.error(\"Recieved an incorrect tombstone object\");\n console.error(validationError);\n this.inboxes.label(\n inboxEndpoint,\n messageId,\n MESSAGE_LABEL_INVALID,\n inboxToken,\n );\n }\n } else {\n if (validationError === undefined) {\n this.inboxes.label(\n inboxEndpoint,\n messageId,\n MESSAGE_LABEL_VALID,\n inboxToken,\n );\n return {\n messageId,\n object,\n storageBucketKey,\n tags: receivedTags,\n allowedTickets,\n announcements,\n };\n } else if (validationError instanceof GraffitiErrorNotFound) {\n // Item was deleted before we got a chance to\n // validate it. Just label the message as trash.\n this.inboxes.label(\n inboxEndpoint,\n messageId,\n MESSAGE_LABEL_TRASH,\n inboxToken,\n );\n } else {\n console.error(\"Recieved an incorrect object\");\n console.error(validationError);\n this.inboxes.label(\n inboxEndpoint,\n messageId,\n MESSAGE_LABEL_INVALID,\n inboxToken,\n );\n }\n }\n }\n}\n\nconst MEDIA_OBJECT_SCHEMA = {\n properties: {\n value: {\n properties: {\n type: { type: \"string\" },\n size: { type: \"number\" },\n key: { type: \"string\" },\n },\n required: [\"type\", \"size\", \"key\"],\n },\n },\n} as const satisfies JSONSchema;\n\nconst CursorSchema = strictObject({\n cursors: record(url(), string()),\n channels: array(string()),\n});\n\ninterface SingleEndpointQueryResult<Schema extends JSONSchema> {\n messageId: string;\n object: GraffitiObject<Schema>;\n storageBucketKey: string;\n tags: Uint8Array[];\n allowedTickets: Uint8Array[] | undefined;\n tombstone?: boolean;\n announcements?: MessageMetadataAnnouncements | undefined;\n}\ninterface SingleEndpointQueryIterator<\n Schema extends JSONSchema,\n> extends AsyncGenerator<SingleEndpointQueryResult<Schema>, string> {}\ntype IndexedSingleEndpointQueryResult<Schema extends JSONSchema> =\n | {\n index: number;\n error?: undefined;\n result: IteratorResult<SingleEndpointQueryResult<Schema>, string>;\n }\n | {\n index: number;\n error: Error;\n result?: undefined;\n };\n\nasync function indexedSingleEndpointQueryNext<Schema extends JSONSchema>(\n it: SingleEndpointQueryIterator<Schema>,\n index: number,\n): Promise<IndexedSingleEndpointQueryResult<Schema>> {\n try {\n return {\n index: index,\n result: await it.next(),\n };\n } catch (e) {\n if (\n e instanceof GraffitiErrorCursorExpired ||\n e instanceof GraffitiErrorInvalidSchema\n ) {\n // Propogate these errors to the root\n throw e;\n }\n // Otherwise, silently pass them in the stream\n return {\n index,\n error: e instanceof Error ? e : new Error(String(e)),\n };\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { JSONSchema } from \"json-schema-to-ts\";\nimport {\n GraffitiErrorNotFound,\n maskGraffitiObject,\n type Graffiti,\n type GraffitiLoginEvent,\n type GraffitiObjectBase,\n type GraffitiSession,\n type GraffitiObject,\n unpackObjectUrl,\n compileGraffitiObjectSchema,\n GraffitiErrorSchemaMismatch,\n GraffitiErrorForbidden,\n GraffitiErrorTooLarge,\n isMediaAcceptable,\n GraffitiErrorNotAcceptable,\n GraffitiErrorCursorExpired,\n GraffitiErrorInvalidSchema,\n type GraffitiObjectStream,\n} from \"@graffiti-garden/api\";\nimport { randomBytes } from \"@noble/hashes/utils.js\";\nimport {\n encode as dagCborEncode,\n decode as dagCborDecode,\n} from \"@ipld/dag-cbor\";\n\nimport { DecentralizedIdentifiers } from \"../1-services/2-dids\";\nimport { Authorization } from \"../1-services/1-authorization\";\nimport { StorageBuckets } from \"../1-services/3-storage-buckets\";\nimport {\n Inboxes,\n LABELED_MESSAGE_LABEL_KEY,\n LABELED_MESSAGE_MESSAGE_KEY,\n MESSAGE_METADATA_KEY,\n MESSAGE_OBJECT_KEY,\n MESSAGE_TAGS_KEY,\n type LabeledMessage,\n type MessageStream,\n} from \"../1-services/4-inboxes\";\nimport { GraffitiErrorUnauthorized } from \"../1-services/utilities\";\n\nimport {\n StringEncoder,\n STRING_ENCODER_METHOD_BASE64URL,\n} from \"../2-primitives/1-string-encoding\";\nimport { ContentAddresses } from \"../2-primitives/2-content-addresses\";\nimport {\n CHANNEL_ATTESTATION_METHOD_SHA256_ED25519,\n ChannelAttestations,\n} from \"../2-primitives/3-channel-attestations\";\nimport { AllowedAttestations } from \"../2-primitives/4-allowed-attestations\";\n\nimport { Handles } from \"./2-handles\";\nimport {\n Sessions,\n DID_SERVICE_ID_GRAFFITI_PERSONAL_INBOX,\n DID_SERVICE_TYPE_GRAFFITI_INBOX,\n DID_SERVICE_ID_GRAFFITI_STORAGE_BUCKET,\n DID_SERVICE_TYPE_GRAFFITI_STORAGE_BUCKET,\n} from \"./1-sessions\";\nimport {\n decodeObjectUrl,\n MAX_OBJECT_SIZE_BYTES,\n ObjectEncoding,\n} from \"./3-object-encoding\";\n\nimport { GraffitiModal } from \"@graffiti-garden/modal\";\nimport {\n type infer as infer_,\n custom,\n string,\n boolean,\n strictObject,\n array,\n int,\n nonnegative,\n optional,\n extend,\n union,\n record,\n url,\n} from \"zod/mini\";\n\nconst Uint8ArraySchema = custom<Uint8Array>(\n (v): v is Uint8Array => v instanceof Uint8Array,\n);\nconst MESSAGE_DATA_STORAGE_BUCKET_KEY = \"k\";\nconst MESSAGE_DATA_TOMBSTONED_MESSAGE_ID_KEY = \"t\";\nconst MessageMetadataBaseSchema = strictObject({\n [MESSAGE_DATA_STORAGE_BUCKET_KEY]: string(),\n [MESSAGE_DATA_TOMBSTONED_MESSAGE_ID_KEY]: optional(string()),\n});\nconst MESSAGE_DATA_ANNOUNCEMENT_MESSAGE_ID_KEY = \"id\";\nconst MESSAGE_DATA_ANNOUNCEMENT_ENDPOINT_KEY = \"e\";\nconst MESSAGE_DATA_ANNOUNCEMENT_ACTOR_KEY = \"a\";\nconst MessageMetadataAnnouncementsSchema = array(\n strictObject({\n [MESSAGE_DATA_ANNOUNCEMENT_MESSAGE_ID_KEY]: string(),\n [MESSAGE_DATA_ANNOUNCEMENT_ENDPOINT_KEY]: optional(url()),\n [MESSAGE_DATA_ANNOUNCEMENT_ACTOR_KEY]: optional(url()),\n }),\n);\nconst MESSAGE_DATA_ALLOWED_TICKETS_KEY = \"s\";\nconst MESSAGE_DATA_ANNOUNCEMENTS_KEY = \"n\";\nconst MessageMetaDataSelfSchema = extend(MessageMetadataBaseSchema, {\n [MESSAGE_DATA_ALLOWED_TICKETS_KEY]: optional(array(Uint8ArraySchema)),\n [MESSAGE_DATA_ANNOUNCEMENTS_KEY]: MessageMetadataAnnouncementsSchema,\n});\nconst MESSAGE_DATA_ALLOWED_TICKET_KEY = \"a\";\nconst MESSAGE_DATA_ALLOWED_TICKET_INDEX_KEY = \"i\";\nconst MessageMetadataPrivateSchema = extend(MessageMetadataBaseSchema, {\n [MESSAGE_DATA_ALLOWED_TICKET_KEY]: Uint8ArraySchema,\n [MESSAGE_DATA_ALLOWED_TICKET_INDEX_KEY]: int().check(nonnegative()),\n});\nconst MessageMetadataSchema = union([\n MessageMetadataBaseSchema,\n MessageMetaDataSelfSchema,\n MessageMetadataPrivateSchema,\n]);\ntype MessageMetadataBase = infer_<typeof MessageMetadataBaseSchema>;\ntype MessageMetadata = infer_<typeof MessageMetadataSchema>;\ntype MessageMetadataAnnouncements = infer_<\n typeof MessageMetadataAnnouncementsSchema\n>;\n\nconst MESSAGE_LABEL_UNLABELED = 0;\nconst MESSAGE_LABEL_VALID = 1;\nconst MESSAGE_LABEL_TRASH = 2;\nconst MESSAGE_LABEL_INVALID = 3;\n\nexport interface GraffitiDecentralizedOptions {\n identityCreatorEndpoint?: string;\n defaultInboxEndpoints?: string[];\n}\n\nconst CONCURRENCY = 128;\nconst LOCAL_STORAGE_REMEMBERED_HANDLE_KEY = \"graffiti-login-remembered-handle\";\n\nexport class GraffitiDecentralized implements Graffiti {\n protected readonly dids = new DecentralizedIdentifiers();\n protected readonly authorization = new Authorization();\n protected readonly storageBuckets = new StorageBuckets();\n protected readonly inboxes = new Inboxes();\n\n protected readonly stringEncoder = new StringEncoder();\n protected readonly contentAddresses = new ContentAddresses();\n protected readonly channelAttestations = new ChannelAttestations();\n protected readonly allowedAttestations = new AllowedAttestations();\n\n protected readonly sessions = new Sessions({\n dids: this.dids,\n authorization: this.authorization,\n storageBuckets: this.storageBuckets,\n inboxes: this.inboxes,\n });\n protected readonly handles = new Handles({ dids: this.dids });\n protected readonly objectEncoding = new ObjectEncoding({\n stringEncoder: this.stringEncoder,\n contentAddresses: this.contentAddresses,\n channelAttestations: this.channelAttestations,\n allowedAttestations: this.allowedAttestations,\n });\n\n protected readonly modal: GraffitiModal | undefined =\n typeof window === \"undefined\"\n ? undefined\n : new GraffitiModal({\n useTemplateHTML: () =>\n import(\"./login-dialog.html\").then(({ template }) => template),\n onManualClose: () => {\n const event = new CustomEvent(\"login\", {\n detail: {\n error: new Error(\"User cancelled login\"),\n manual: true,\n },\n });\n this.sessionEvents.dispatchEvent(event);\n },\n });\n\n protected readonly defaultInboxEndpoints: string[];\n protected readonly identityCreatorEndpoint: string;\n constructor(options?: GraffitiDecentralizedOptions) {\n this.defaultInboxEndpoints = options?.defaultInboxEndpoints ?? [\n \"https://graffiti.actor/i/shared\",\n ];\n this.identityCreatorEndpoint =\n options?.identityCreatorEndpoint ?? \"https://graffiti.actor/create\";\n\n this.sessionEvents.addEventListener(\"login\", async (event) => {\n if (!(event instanceof CustomEvent)) return;\n const detail = event.detail as GraffitiLoginEvent[\"detail\"];\n\n if (detail.error !== undefined) {\n // If \"manual\", the window was closed by the user, nothing to do\n if (\"manual\" in detail && detail.manual) return;\n\n alert(\"Login failed: \" + detail.error.message);\n const actor = detail.session?.actor;\n let handle: string | undefined;\n if (actor) {\n try {\n handle = await this.actorToHandle(actor);\n } catch (error) {\n console.error(\"Failed to handle actor:\", error);\n }\n }\n // Open the login window again with the failed actor\n this.login_(handle);\n return;\n }\n\n const actor = detail.session.actor;\n\n let handle: string | undefined;\n try {\n handle = await this.actorToHandle(actor);\n } catch (error) {\n console.error(\"Failed to load handle from actor:\", error);\n }\n\n if (handle) {\n this.rememberHandleInBrowserStorage(handle);\n }\n });\n\n // If any methods throw an unauthorized error,\n // log out the used session\n for (const method of [\n \"post\",\n \"get\",\n \"delete\",\n \"postMedia\",\n \"getMedia\",\n \"deleteMedia\",\n ]) {\n const fn = (this as any)[method];\n (this as any)[method] = async (...args: unknown[]) => {\n try {\n return await fn(...args);\n } catch (e) {\n const session = args[args.length - 1] as any;\n await this.tryLogoutIfUnauthorized(e, session);\n throw e;\n }\n };\n }\n }\n\n readonly actorToHandle: Graffiti[\"actorToHandle\"] =\n this.handles.actorToHandle.bind(this.handles);\n readonly handleToActor: Graffiti[\"handleToActor\"] =\n this.handles.handleToActor.bind(this.handles);\n readonly sessionEvents: Graffiti[\"sessionEvents\"] =\n this.sessions.sessionEvents;\n\n login: Graffiti[\"login\"] = async (actor?: string) => {\n try {\n let proposedHandle: string | undefined;\n try {\n proposedHandle = actor ? await this.actorToHandle(actor) : undefined;\n } catch (error) {\n console.error(\"Error fetching handle for actor:\", error);\n }\n\n await this.login_(proposedHandle);\n } catch (e) {\n const loginError: GraffitiLoginEvent = new CustomEvent(\"login\", {\n detail: {\n error: e instanceof Error ? e : new Error(String(e)),\n },\n });\n this.sessionEvents.dispatchEvent(loginError);\n }\n };\n protected async login_(proposedHandle?: string) {\n if (typeof window !== \"undefined\") {\n let template: HTMLElement | undefined;\n if (proposedHandle !== undefined) {\n template = await this.modal?.displayTemplate(\"graffiti-login-handle\");\n const input = template?.querySelector(\n \"#username\",\n ) as HTMLInputElement | null;\n const rememberedHandle =\n proposedHandle || this.getRememberedHandleFromBrowserStorage();\n if (input) input.value = rememberedHandle ?? \"\";\n input?.addEventListener(\"focus\", () => input?.select());\n setTimeout(() => input?.focus(), 0);\n\n template\n ?.querySelector(\"#graffiti-login-handle-form\")\n ?.addEventListener(\"submit\", async (e) => {\n e.preventDefault();\n input?.setAttribute(\"disabled\", \"true\");\n const submitButton = template?.querySelector(\n \"#graffiti-login-handle-submit\",\n ) as HTMLButtonElement | null;\n submitButton?.setAttribute(\"disabled\", \"true\");\n submitButton && (submitButton.innerHTML = \"Logging in...\");\n\n if (!input?.value) {\n alert(\"No handle provided\");\n this.login_(\"\");\n return;\n }\n\n let handle = input.value;\n if (!handle.includes(\".\") && !handle.startsWith(\"localhost\")) {\n const defaultHost = new URL(this.identityCreatorEndpoint).host;\n handle = `${handle}.${defaultHost}`;\n }\n\n let actor: string;\n try {\n actor = await this.handleToActor(handle);\n } catch (e) {\n alert(\"Could not find an identity associated with that handle.\");\n this.login_(handle);\n return;\n }\n\n try {\n await this.sessions.login(actor);\n } catch (e) {\n alert(\"Error logging in.\");\n console.error(e);\n this.login_(handle);\n }\n });\n template\n ?.querySelector(\"#graffiti-login-forgot\")\n ?.addEventListener(\"click\", (e) => {\n e.preventDefault();\n void this.loginWithoutHandle();\n });\n } else {\n template = await this.modal?.displayTemplate(\"graffiti-login-welcome\");\n template\n ?.querySelector(\"#graffiti-login-existing\")\n ?.addEventListener(\"click\", (e) => {\n e.preventDefault();\n this.login_(\"\");\n });\n\n setTimeout(\n () =>\n (\n template?.querySelector(\n \"#graffiti-login-new\",\n ) as HTMLAnchorElement\n )?.focus(),\n 0,\n );\n }\n\n const createUrl = new URL(this.identityCreatorEndpoint);\n createUrl.searchParams.set(\n \"redirect_uri\",\n encodeURIComponent(window.location.toString()),\n );\n template\n ?.querySelector(\"#graffiti-login-new\")\n ?.setAttribute(\"href\", createUrl.toString());\n\n await this.modal?.open();\n } else {\n // Node.js environment\n const readline = await import(\"readline\").catch((e) => {\n throw new Error(\n \"Unrecognized environment: neither window nor readline\",\n );\n });\n\n console.log(\n \"If you do not already have a Graffiti handle, you can create one here:\",\n );\n console.log(this.identityCreatorEndpoint);\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n const handle: string | undefined = await new Promise((resolve) => {\n rl.question(\n `Please enter your handle${proposedHandle ? ` (default: ${proposedHandle})` : \"\"}: `,\n (input) => {\n rl.close();\n resolve(input || proposedHandle);\n },\n );\n });\n\n if (!handle) {\n throw new Error(\"No handle provided\");\n }\n\n // Convert the handle to an actor\n const actor = await this.handleToActor(handle);\n\n await this.sessions.login(actor);\n }\n }\n\n protected async loginWithoutHandle() {\n const template = await this.modal?.displayTemplate(\"graffiti-login-provider\");\n const defaultProvider = new URL(\"/\", this.identityCreatorEndpoint);\n const provider = template?.querySelector(\"#graffiti-provider\") as HTMLInputElement | null;\n if (provider) provider.value = defaultProvider.host;\n provider?.addEventListener(\"focus\", () => provider.select());\n setTimeout(() => provider?.focus(), 0);\n\n template\n ?.querySelector(\"#graffiti-login-provider-form\")\n ?.addEventListener(\"submit\", (event) => {\n event.preventDefault();\n try {\n const domain = provider?.value.trim() ?? \"\";\n const origin = domain === defaultProvider.host\n ? defaultProvider\n : new URL(`https://${domain}`);\n if (\n !origin.hostname || origin.username || origin.password ||\n origin.pathname !== \"/\" || origin.search || origin.hash\n ) throw new Error(\"Invalid provider domain\");\n\n const url = new URL(\"/forgot-handle\", origin);\n url.searchParams.set(\"redirect_uri\", window.location.toString());\n window.location.assign(url.toString());\n } catch {\n alert(\"Enter a valid provider domain.\");\n }\n });\n\n template\n ?.querySelector(\"#graffiti-login-provider-back\")\n ?.addEventListener(\"click\", (event) => {\n event.preventDefault();\n void this.login_(\"\");\n });\n\n await this.modal?.open();\n }\n\n protected rememberHandleInBrowserStorage(handle: string) {\n if (typeof window === \"undefined\") return;\n\n try {\n window.localStorage.setItem(LOCAL_STORAGE_REMEMBERED_HANDLE_KEY, handle);\n } catch (error) {\n console.error(\"Failed to remember handle in browser storage:\", error);\n }\n }\n\n protected getRememberedHandleFromBrowserStorage() {\n if (typeof window === \"undefined\") return undefined;\n\n try {\n return (\n window.localStorage.getItem(LOCAL_STORAGE_REMEMBERED_HANDLE_KEY) ??\n undefined\n );\n } catch (error) {\n console.error(\"Failed to load handle from browser storage:\", error);\n return undefined;\n }\n }\n\n logout: Graffiti[\"logout\"] = async (session) => {\n await this.sessions.logout(session.actor);\n };\n\n // @ts-ignore\n post: Graffiti[\"post\"] = async (...args) => {\n const [partialObject, session] = args;\n const resolvedSession = this.sessions.resolveSession(session);\n\n // Encode the object\n const { object, tags, objectBytes, allowedTickets } =\n await this.objectEncoding.encode<{}>(partialObject, session.actor);\n\n // Generate a random key under which to store the object\n // If the object is private, this means no one will be able to\n // fetch the object, even if they know its URL.\n // If the object is public but in some secret channel, the storage\n // location means the object can be moved around or \"rotated\"\n // without changing its URL.\n const storageBucketKeyBytes = randomBytes();\n const storageBucketKey = await this.stringEncoder.encode(\n STRING_ENCODER_METHOD_BASE64URL,\n storageBucketKeyBytes,\n );\n\n // Store the object at the random key\n await this.storageBuckets.put(\n resolvedSession.storageBucket.serviceEndpoint,\n storageBucketKey,\n objectBytes,\n resolvedSession.storageBucket.token,\n );\n\n // Announce the object, its key,\n // and other metadata to appropriate inboxes\n await this.announceObject(\n object,\n tags,\n allowedTickets,\n storageBucketKey,\n session,\n );\n\n return object;\n };\n\n get: Graffiti[\"get\"] = async (...args) => {\n const [url, schema, session] = args;\n let services: { token?: string; serviceEndpoint: string }[];\n const validator = await compileGraffitiObjectSchema(schema);\n\n if (session) {\n // If logged in, first search one's\n // personal inbox, then any shared inboxes\n const resolvedSession = this.sessions.resolveSession(session);\n services = [\n resolvedSession.personalInbox,\n ...resolvedSession.sharedInboxes,\n ];\n } else {\n // Otherwise, search the default inboxes\n services = this.defaultInboxEndpoints.map((s) => ({\n serviceEndpoint: s,\n }));\n }\n\n // Search the inboxes for all objects\n // matching the tag, object.url\n const objectUrl = unpackObjectUrl(url);\n const tags = [new TextEncoder().encode(objectUrl)];\n for (const service of services) {\n let object: GraffitiObjectBase | undefined = undefined;\n\n const iterator = this.querySingleEndpoint<{}>(\n service.serviceEndpoint,\n {\n tags,\n objectSchema: {},\n },\n service.token,\n session?.actor,\n );\n\n for await (const result of iterator) {\n if (result.object.url !== objectUrl) continue;\n if (result.tombstone) {\n object = undefined;\n } else {\n object = result.object;\n }\n }\n\n if (object) {\n if (!validator(object)) {\n throw new GraffitiErrorSchemaMismatch(\n \"Object exists but does not match the supplied schema\",\n );\n }\n\n return object;\n }\n }\n\n throw new GraffitiErrorNotFound(\"Object not found\");\n };\n\n delete: Graffiti[\"delete\"] = async (url, session) => {\n const resolvedSession = this.sessions.resolveSession(session);\n\n const objectUrl = unpackObjectUrl(url);\n\n const { actor } = decodeObjectUrl(objectUrl);\n if (actor !== session.actor) {\n throw new GraffitiErrorForbidden(\"Cannot delete someone else's actor\");\n }\n\n // Look in one's personal inbox for the object\n const iterator = this.querySingleEndpoint<{}>(\n resolvedSession.personalInbox.serviceEndpoint,\n {\n tags: [new TextEncoder().encode(objectUrl)],\n objectSchema: {},\n },\n resolvedSession.personalInbox.token,\n );\n let existing: SingleEndpointQueryResult<{}> | undefined;\n for await (const result of iterator) {\n if (result.object.url !== objectUrl) continue;\n if (result.tombstone) {\n existing = undefined;\n } else {\n existing = result;\n }\n }\n if (!existing) {\n throw new GraffitiErrorNotFound(`Object ${objectUrl} not found`);\n }\n const {\n object,\n storageBucketKey,\n tags,\n allowedTickets,\n announcements,\n messageId,\n } = existing;\n\n // Delete the object from the actor's own storage bucket\n await this.storageBuckets.delete(\n resolvedSession.storageBucket.serviceEndpoint,\n storageBucketKey,\n resolvedSession.storageBucket.token,\n );\n\n // Announce the deletion to all inboxes\n await this.announceObject(\n object,\n tags,\n allowedTickets,\n storageBucketKey,\n session,\n [\n ...(announcements ?? []),\n // Make sure we delete from our own inbox too\n {\n [MESSAGE_DATA_ANNOUNCEMENT_ACTOR_KEY]: session.actor,\n [MESSAGE_DATA_ANNOUNCEMENT_MESSAGE_ID_KEY]: messageId,\n },\n ],\n );\n\n return object;\n };\n\n postMedia: Graffiti[\"postMedia\"] = async (...args) => {\n const [media, session] = args;\n\n const type = media.data.type;\n\n const resolvedSession = this.sessions.resolveSession(session);\n\n // Generate a random storage key\n const keyBytes = randomBytes();\n const key = await this.stringEncoder.encode(\n STRING_ENCODER_METHOD_BASE64URL,\n keyBytes,\n );\n\n // Store the media at that key\n await this.storageBuckets.put(\n resolvedSession.storageBucket.serviceEndpoint,\n key,\n new Uint8Array(await media.data.arrayBuffer()),\n resolvedSession.storageBucket.token,\n );\n\n // Create an object\n const { url } = await this.post<typeof MEDIA_OBJECT_SCHEMA>(\n {\n value: {\n key,\n type,\n size: media.data.size,\n },\n channels: [],\n allowed: media.allowed,\n },\n session,\n );\n\n return url;\n };\n\n getMedia: Graffiti[\"getMedia\"] = async (...args) => {\n const [mediaUrl, accept, session] = args;\n\n if (\n accept?.maxBytes !== undefined &&\n (!Number.isSafeInteger(accept.maxBytes) || accept.maxBytes < 0)\n ) {\n throw new TypeError(\"maxBytes must be a nonnegative safe integer\");\n }\n\n const object = await this.get<typeof MEDIA_OBJECT_SCHEMA>(\n mediaUrl,\n MEDIA_OBJECT_SCHEMA,\n session,\n );\n\n const { key, type, size } = object.value;\n\n if (accept?.maxBytes !== undefined && size > accept.maxBytes) {\n throw new GraffitiErrorTooLarge(\"File size exceeds limit\");\n }\n\n // Make sure it adheres to requirements.accept\n if (accept?.types) {\n if (!isMediaAcceptable(type, accept.types)) {\n throw new GraffitiErrorNotAcceptable(\n `Unacceptable media type, ${type}`,\n );\n }\n }\n\n // Get the actor's storage bucket endpoint\n const actorDocument = await this.dids.resolve(object.actor);\n const storageBucketService = actorDocument?.service?.find(\n (service) =>\n service.id === DID_SERVICE_ID_GRAFFITI_STORAGE_BUCKET &&\n service.type === DID_SERVICE_TYPE_GRAFFITI_STORAGE_BUCKET,\n );\n if (!storageBucketService) {\n throw new GraffitiErrorNotFound(\n `Actor ${object.actor} has no storage bucket service`,\n );\n }\n if (typeof storageBucketService.serviceEndpoint !== \"string\") {\n throw new GraffitiErrorNotFound(\n `Actor ${object.actor} does not have a valid storage bucket endpoint`,\n );\n }\n const storageBucketEndpoint = storageBucketService.serviceEndpoint;\n\n const data = await this.storageBuckets.get(\n storageBucketEndpoint,\n key,\n size,\n );\n\n const blob = new Blob([data.slice()], { type });\n\n return {\n data: blob,\n actor: object.actor,\n allowed: object.allowed,\n };\n };\n\n deleteMedia: Graffiti[\"deleteMedia\"] = async (...args) => {\n const [mediaUrl, session] = args;\n\n const resolvedSession = this.sessions.resolveSession(session);\n\n const result = await this.delete(mediaUrl, session);\n\n if (!(\"key\" in result.value && typeof result.value.key === \"string\"))\n throw new Error(\n \"Deleted object was not media: \" + JSON.stringify(result, null, 2),\n );\n\n await this.storageBuckets.delete(\n resolvedSession.storageBucket.serviceEndpoint,\n result.value.key,\n resolvedSession.storageBucket.token,\n );\n };\n\n async *discoverMeta<Schema extends JSONSchema>(\n channels: string[],\n schema: Schema,\n cursors: {\n [endpoint: string]: string;\n },\n session?: GraffitiSession | null,\n ): GraffitiObjectStream<Schema> {\n const tombstones = new Map<string, boolean>();\n\n let allInboxes: { serviceEndpoint: string; token?: string }[];\n if (session) {\n const resolvedSession = this.sessions.resolveSession(session);\n allInboxes = [\n resolvedSession.personalInbox,\n ...resolvedSession.sharedInboxes,\n ];\n } else {\n allInboxes = this.defaultInboxEndpoints.map((e) => ({\n serviceEndpoint: e,\n }));\n }\n\n // Make sure all cursors are represented by an inbox\n for (const endpoint in cursors) {\n if (!allInboxes.some((i) => i.serviceEndpoint === endpoint)) {\n throw new GraffitiErrorForbidden(\n \"Cursor does not match actor's inboxes\",\n );\n }\n }\n\n // Turn the channels into tags\n const tags = await Promise.all(\n channels.map((c) =>\n this.channelAttestations.register(\n CHANNEL_ATTESTATION_METHOD_SHA256_ED25519,\n c,\n ),\n ),\n );\n\n const iterators: SingleEndpointQueryIterator<Schema>[] = allInboxes.map(\n (i) => {\n const cursor = cursors[i.serviceEndpoint];\n return this.querySingleEndpoint<Schema>(\n i.serviceEndpoint,\n cursor\n ? {\n cursor,\n }\n : {\n tags,\n objectSchema: schema,\n },\n i.token,\n session?.actor,\n );\n },\n );\n\n let indexedIteratorNexts = iterators.map<\n Promise<IndexedSingleEndpointQueryResult<Schema>>\n >(async (it, index) => indexedSingleEndpointQueryNext<Schema>(it, index));\n let active = indexedIteratorNexts.length;\n\n try {\n while (active > 0) {\n const next: IndexedSingleEndpointQueryResult<Schema> =\n await Promise.race<any>(indexedIteratorNexts);\n if (next.error !== undefined) {\n // Remove it from the race\n indexedIteratorNexts[next.index] = new Promise(() => {});\n active--;\n yield {\n error: next.error,\n origin: allInboxes[next.index].serviceEndpoint,\n };\n this.tryLogoutIfUnauthorized(next.error, session);\n } else if (next.result.done) {\n // Store the cursor for future use\n const inbox = allInboxes[next.index];\n cursors[inbox.serviceEndpoint] = next.result.value;\n // Remove it from the race\n indexedIteratorNexts[next.index] = new Promise(() => {});\n active--;\n } else {\n // Re-arm the iterator\n indexedIteratorNexts[next.index] =\n indexedSingleEndpointQueryNext<Schema>(\n iterators[next.index],\n next.index,\n );\n const { object, tombstone, tags: receivedTags } = next.result.value;\n if (tombstone) {\n if (tombstones.get(object.url) === true) continue;\n tombstones.set(object.url, true);\n yield {\n tombstone,\n object: { url: object.url },\n };\n } else {\n // Filter already seen\n if (tombstones.get(object.url) === false) continue;\n\n // Fill in the matched channels\n const matchedTagIndices = tags.reduce<number[]>(\n (acc, tag, tagIndex) => {\n for (const receivedTag of receivedTags) {\n if (\n tag.length === receivedTag.length &&\n tag.every((b, i) => receivedTag[i] === b)\n ) {\n acc.push(tagIndex);\n break;\n }\n }\n return acc;\n },\n [],\n );\n const matchedChannels = matchedTagIndices.map(\n (index) => channels[index],\n );\n if (matchedChannels.length === 0) {\n yield {\n error: new Error(\n \"Inbox returned object without matching channels\",\n ),\n origin: allInboxes[next.index].serviceEndpoint,\n };\n }\n tombstones.set(object.url, false);\n yield {\n object: {\n ...object,\n channels: matchedChannels,\n },\n };\n }\n }\n }\n } catch (e) {\n this.tryLogoutIfUnauthorized(e, session);\n throw e;\n } finally {\n await Promise.all(\n iterators.map<Promise<void>>(async (it) => {\n await it.return(\"\");\n }),\n );\n }\n\n return {\n cursor: JSON.stringify({\n channels,\n cursors,\n } satisfies infer_<typeof CursorSchema>),\n };\n }\n\n discover: Graffiti[\"discover\"] = (...args) => {\n const [channels, schema, session] = args;\n return this.discoverMeta<(typeof args)[1]>(channels, schema, {}, session);\n };\n\n // @ts-ignore\n continueDiscover: Graffiti[\"continueDiscover\"] = (...args) => {\n const [cursor, session] = args;\n // Extract the channels from the cursor\n let channels: string[];\n let cursors: { [endpoint: string]: string };\n try {\n const json = JSON.parse(cursor);\n const parsed = CursorSchema.parse(json);\n channels = parsed.channels;\n cursors = parsed.cursors;\n } catch (error) {\n return (async function* () {\n throw new GraffitiErrorCursorExpired(\"Invalid cursor\");\n })();\n }\n return this.discoverMeta<{}>(channels, {}, cursors, session);\n };\n\n protected async tryLogoutIfUnauthorized(\n e: unknown,\n session?: GraffitiSession | null,\n ) {\n if (e instanceof GraffitiErrorUnauthorized && session) {\n await this.sessions.logout(session.actor);\n }\n }\n\n async announceObject(\n object: GraffitiObjectBase,\n tags: Uint8Array[],\n allowedTickets: Uint8Array[] | undefined,\n storageBucketKey: string,\n session: GraffitiSession,\n priorAnnouncements?: MessageMetadataAnnouncements,\n ): Promise<void> {\n const resolvedSession = this.sessions.resolveSession(session);\n\n const metadataBase: MessageMetadataBase = {\n [MESSAGE_DATA_STORAGE_BUCKET_KEY]: storageBucketKey,\n };\n\n const announcements: MessageMetadataAnnouncements = [];\n const allowed = object.allowed;\n if (Array.isArray(allowed)) {\n if (!allowedTickets || allowedTickets.length !== allowed.length) {\n throw new Error(\n \"If allowed actors are specified, there must be a corresponding ticket for each allowed actor\",\n );\n }\n\n // Send the object to each allowed recipient's personal inbox\n const results = await Promise.allSettled(\n allowed.map(async (recipient, recipientIndex) => {\n // Mask the object to not include any channels\n // and only include the recipient actor on the allowed list\n const copy = JSON.parse(JSON.stringify(object)) as GraffitiObjectBase;\n const masked = maskGraffitiObject(copy, [], recipient);\n\n // Get the recipient's inbox\n const actorDocument = await this.dids.resolve(recipient);\n const personalInbox = actorDocument.service?.find(\n (service) =>\n service.type === DID_SERVICE_TYPE_GRAFFITI_INBOX &&\n service.id === DID_SERVICE_ID_GRAFFITI_PERSONAL_INBOX,\n );\n if (!personalInbox) {\n throw new Error(\n `Recipient ${recipient} does not have a personal inbox`,\n );\n }\n if (typeof personalInbox.serviceEndpoint !== \"string\") {\n throw new Error(\n `Recipient ${recipient} does not have a valid personal inbox endpoint`,\n );\n }\n\n const tombstonedMessageId = priorAnnouncements\n ? priorAnnouncements.find(\n (a) => a[MESSAGE_DATA_ANNOUNCEMENT_ACTOR_KEY] === recipient,\n )?.[MESSAGE_DATA_ANNOUNCEMENT_MESSAGE_ID_KEY]\n : undefined;\n\n // Announce to the inbox\n const privateMetadata: MessageMetadata = {\n ...metadataBase,\n ...(tombstonedMessageId\n ? {\n [MESSAGE_DATA_TOMBSTONED_MESSAGE_ID_KEY]: tombstonedMessageId,\n }\n : {}),\n [MESSAGE_DATA_ALLOWED_TICKET_KEY]: allowedTickets[recipientIndex],\n [MESSAGE_DATA_ALLOWED_TICKET_INDEX_KEY]: recipientIndex,\n };\n const messageId = await this.inboxes.send(\n personalInbox.serviceEndpoint,\n {\n [MESSAGE_TAGS_KEY]: tags,\n [MESSAGE_OBJECT_KEY]: masked,\n [MESSAGE_METADATA_KEY]: dagCborEncode(privateMetadata),\n },\n );\n\n announcements.push({\n [MESSAGE_DATA_ANNOUNCEMENT_MESSAGE_ID_KEY]: messageId,\n [MESSAGE_DATA_ANNOUNCEMENT_ACTOR_KEY]: recipient,\n });\n }),\n );\n\n for (const [index, result] of results.entries()) {\n if (result.status === \"rejected\") {\n const recipient = allowed[index];\n console.error(\"Error sending to recipient:\", recipient);\n console.error(result.reason);\n }\n }\n } else {\n // Mask the object to not include any channels\n // and only include the recipient actor on the allowed list\n const copy = JSON.parse(JSON.stringify(object)) as GraffitiObjectBase;\n const masked = maskGraffitiObject(copy, []);\n\n // Send the object to each shared inbox\n const sharedInboxes = resolvedSession.sharedInboxes;\n const results = await Promise.allSettled(\n sharedInboxes.map(async (inbox) => {\n const tombstonedMessageId = priorAnnouncements\n ? priorAnnouncements.find(\n (a) =>\n a[MESSAGE_DATA_ANNOUNCEMENT_ENDPOINT_KEY] ===\n inbox.serviceEndpoint,\n )?.[MESSAGE_DATA_ANNOUNCEMENT_MESSAGE_ID_KEY]\n : undefined;\n const metadata: MessageMetadata = {\n ...metadataBase,\n ...(tombstonedMessageId\n ? {\n [MESSAGE_DATA_TOMBSTONED_MESSAGE_ID_KEY]: tombstonedMessageId,\n }\n : {}),\n };\n\n const messageId = await this.inboxes.send(inbox.serviceEndpoint, {\n ...(tombstonedMessageId\n ? {\n [MESSAGE_DATA_TOMBSTONED_MESSAGE_ID_KEY]: tombstonedMessageId,\n }\n : {}),\n [MESSAGE_TAGS_KEY]: tags,\n [MESSAGE_OBJECT_KEY]: masked,\n [MESSAGE_METADATA_KEY]: dagCborEncode(metadata),\n });\n announcements.push({\n [MESSAGE_DATA_ANNOUNCEMENT_MESSAGE_ID_KEY]: messageId,\n [MESSAGE_DATA_ANNOUNCEMENT_ENDPOINT_KEY]: inbox.serviceEndpoint,\n });\n }),\n );\n\n for (const [index, result] of results.entries()) {\n if (result.status === \"rejected\") {\n const inbox = sharedInboxes[index];\n console.error(\"Error sending to inbox:\", inbox);\n console.error(result.reason);\n }\n }\n }\n\n // Send the complete object to my own personal inbox\n // along with its key and allowed tickets\n const tombstonedMessageId = priorAnnouncements\n ? priorAnnouncements.find(\n (a) => a[MESSAGE_DATA_ANNOUNCEMENT_ACTOR_KEY] === session.actor,\n )?.[MESSAGE_DATA_ANNOUNCEMENT_MESSAGE_ID_KEY]\n : undefined;\n const selfMetadata: MessageMetadata = {\n ...metadataBase,\n ...(allowedTickets\n ? {\n [MESSAGE_DATA_ALLOWED_TICKETS_KEY]: allowedTickets,\n }\n : {}),\n ...(tombstonedMessageId\n ? {\n [MESSAGE_DATA_TOMBSTONED_MESSAGE_ID_KEY]: tombstonedMessageId,\n }\n : {}),\n [MESSAGE_DATA_ANNOUNCEMENTS_KEY]: announcements,\n };\n await this.inboxes.send(resolvedSession.personalInbox.serviceEndpoint, {\n [MESSAGE_TAGS_KEY]: tags,\n [MESSAGE_OBJECT_KEY]: object,\n [MESSAGE_METADATA_KEY]: dagCborEncode(selfMetadata),\n });\n }\n\n protected async *querySingleEndpoint<Schema extends JSONSchema>(\n inboxEndpoint: string,\n queryArguments:\n | {\n tags: Uint8Array[];\n objectSchema: Schema;\n }\n | {\n cursor: string;\n },\n inboxToken?: string | null,\n recipient?: string | null,\n ): SingleEndpointQueryIterator<Schema> {\n const iterator: MessageStream<Schema> =\n \"tags\" in queryArguments\n ? this.inboxes.query<Schema>(\n inboxEndpoint,\n queryArguments.tags,\n queryArguments.objectSchema,\n inboxToken,\n )\n : (this.inboxes.continueQuery(\n inboxEndpoint,\n queryArguments.cursor,\n inboxToken,\n ) as unknown as MessageStream<Schema>);\n\n const inFlight: Promise<SingleEndpointQueryResult<Schema> | void>[] = [];\n let doneValue: string | null = null;\n\n try {\n while (true) {\n while (doneValue === null && inFlight.length < CONCURRENCY) {\n const itResult = await iterator.next();\n if (itResult.done) {\n doneValue = itResult.value;\n break;\n }\n\n const processPromise = this.processOneLabeledMessage<Schema>(\n inboxEndpoint,\n itResult.value,\n inboxToken,\n recipient,\n ).catch((e) => {\n throw e;\n });\n\n inFlight.push(processPromise);\n }\n\n const nextProcessedPromise = inFlight.shift();\n\n if (!nextProcessedPromise) {\n if (doneValue !== null) return doneValue;\n\n throw new Error(\"Process queue empty but no return value\");\n }\n\n const processed = await nextProcessedPromise;\n if (processed) yield processed;\n }\n } finally {\n await iterator.return(\"\");\n }\n }\n\n // Labeling is advisory and should not hold up discovery, but its failure\n // must be handled even if the caller has already stopped reading the stream.\n protected labelInboxMessage(\n inboxEndpoint: string,\n messageId: string,\n label: number,\n inboxToken?: string | null,\n ): void {\n void this.inboxes.label(inboxEndpoint, messageId, label, inboxToken).catch(\n (error) => console.error(\"Could not label inbox message:\", error),\n );\n }\n\n protected async processOneLabeledMessage<Schema extends JSONSchema>(\n inboxEndpoint: string,\n result: LabeledMessage<Schema>,\n inboxToken?: string | null,\n recipient?: string | null,\n ): Promise<SingleEndpointQueryResult<Schema> | void> {\n const label = result.l;\n // Anything invalid or unexpected, we can skip\n if (\n label !== MESSAGE_LABEL_VALID &&\n label !== MESSAGE_LABEL_UNLABELED &&\n label !== MESSAGE_LABEL_TRASH\n )\n return;\n\n const messageId = result.id;\n const { o: object, m: metadataBytes, t: receivedTags } = result.m;\n\n let metadata: MessageMetadata;\n try {\n const metadataRaw = dagCborDecode(metadataBytes);\n metadata = MessageMetadataSchema.parse(metadataRaw);\n } catch (e) {\n this.labelInboxMessage(\n inboxEndpoint,\n messageId,\n MESSAGE_LABEL_INVALID,\n inboxToken,\n );\n return;\n }\n\n const {\n [MESSAGE_DATA_STORAGE_BUCKET_KEY]: storageBucketKey,\n [MESSAGE_DATA_TOMBSTONED_MESSAGE_ID_KEY]: tombstonedMessageId,\n } = metadata;\n\n const allowedTickets =\n MESSAGE_DATA_ALLOWED_TICKETS_KEY in metadata\n ? metadata[MESSAGE_DATA_ALLOWED_TICKETS_KEY]\n : undefined;\n const announcements =\n MESSAGE_DATA_ANNOUNCEMENTS_KEY in metadata\n ? metadata[MESSAGE_DATA_ANNOUNCEMENTS_KEY]\n : undefined;\n\n if (label === MESSAGE_LABEL_VALID) {\n return {\n messageId,\n object,\n storageBucketKey,\n allowedTickets,\n tags: receivedTags,\n announcements,\n };\n } else if (label === MESSAGE_LABEL_TRASH) {\n // If it is simply trash, just continue.\n if (!tombstonedMessageId) return;\n\n // Make sure the tombstone points to a real message\n const past = await this.inboxes.get(\n inboxEndpoint,\n tombstonedMessageId,\n inboxToken,\n );\n if (\n !past ||\n past[LABELED_MESSAGE_MESSAGE_KEY][MESSAGE_OBJECT_KEY].url !== object.url\n )\n return;\n\n // If the referred to message isn't labeled as trash, trash it\n // This may happen if a trash message is processed on another\n // device and the device cache is out of date.\n if (past[LABELED_MESSAGE_LABEL_KEY] !== MESSAGE_LABEL_TRASH) {\n // Label the message as trash\n this.labelInboxMessage(\n inboxEndpoint,\n tombstonedMessageId,\n MESSAGE_LABEL_TRASH,\n inboxToken,\n );\n }\n\n // Return the tombstone\n return {\n messageId,\n tombstone: true,\n object,\n storageBucketKey,\n allowedTickets,\n tags: receivedTags,\n announcements,\n };\n }\n\n // Otherwise, unlabeled: try to validate the object\n let validationError: unknown | undefined = undefined;\n try {\n const actor = object.actor;\n const actorDocument = await this.dids.resolve(actor);\n const storageBucketService = actorDocument?.service?.find(\n (service) =>\n service.id === DID_SERVICE_ID_GRAFFITI_STORAGE_BUCKET &&\n service.type === DID_SERVICE_TYPE_GRAFFITI_STORAGE_BUCKET,\n );\n if (!storageBucketService) {\n throw new GraffitiErrorNotFound(\n `Actor ${actor} has no storage bucket service`,\n );\n }\n if (typeof storageBucketService.serviceEndpoint !== \"string\") {\n throw new GraffitiErrorNotFound(\n `Actor ${actor} does not have a valid storage bucket endpoint`,\n );\n }\n const storageBucketEndpoint = storageBucketService.serviceEndpoint;\n\n const objectBytes = await this.storageBuckets.get(\n storageBucketEndpoint,\n storageBucketKey,\n MAX_OBJECT_SIZE_BYTES,\n );\n\n if (MESSAGE_DATA_ALLOWED_TICKET_KEY in metadata && !recipient) {\n throw new GraffitiErrorForbidden(\n `Recipient is required when allowed ticket is present`,\n );\n }\n const privateObjectInfo = allowedTickets\n ? { allowedTickets }\n : MESSAGE_DATA_ALLOWED_TICKET_KEY in metadata\n ? {\n recipient: recipient ?? \"null\",\n allowedTicket: metadata[MESSAGE_DATA_ALLOWED_TICKET_KEY],\n allowedIndex: metadata[MESSAGE_DATA_ALLOWED_TICKET_INDEX_KEY],\n }\n : undefined;\n\n await this.objectEncoding.validate(\n object,\n receivedTags,\n objectBytes,\n privateObjectInfo,\n );\n } catch (e) {\n validationError = e;\n }\n\n if (tombstonedMessageId) {\n if (validationError instanceof GraffitiErrorNotFound) {\n // Not found == The tombstone is correct\n void this.inboxes\n // Get the referenced message\n .get(inboxEndpoint, tombstonedMessageId, inboxToken)\n .then((result) => {\n if (\n // Make sure that it actually references the object being deleted\n result &&\n result[LABELED_MESSAGE_MESSAGE_KEY][MESSAGE_OBJECT_KEY].url ===\n object.url &&\n // And that the object is not already marked as trash\n result[LABELED_MESSAGE_LABEL_KEY] !== MESSAGE_LABEL_TRASH\n ) {\n // If valid but not yet trash, label the message as trash\n this.labelInboxMessage(\n inboxEndpoint,\n tombstonedMessageId,\n MESSAGE_LABEL_TRASH,\n inboxToken,\n );\n }\n\n // Then, label the tombstone message as trash\n this.labelInboxMessage(\n inboxEndpoint,\n messageId,\n MESSAGE_LABEL_TRASH,\n inboxToken,\n );\n })\n .catch((error) =>\n console.error(\"Could not inspect tombstone message:\", error),\n );\n\n return {\n messageId,\n tombstone: true,\n object,\n storageBucketKey,\n allowedTickets,\n tags: receivedTags,\n announcements,\n };\n } else {\n console.error(\"Recieved an incorrect tombstone object\");\n console.error(validationError);\n this.labelInboxMessage(\n inboxEndpoint,\n messageId,\n MESSAGE_LABEL_INVALID,\n inboxToken,\n );\n }\n } else {\n if (validationError === undefined) {\n this.labelInboxMessage(\n inboxEndpoint,\n messageId,\n MESSAGE_LABEL_VALID,\n inboxToken,\n );\n return {\n messageId,\n object,\n storageBucketKey,\n tags: receivedTags,\n allowedTickets,\n announcements,\n };\n } else if (validationError instanceof GraffitiErrorNotFound) {\n // Item was deleted before we got a chance to\n // validate it. Just label the message as trash.\n this.labelInboxMessage(\n inboxEndpoint,\n messageId,\n MESSAGE_LABEL_TRASH,\n inboxToken,\n );\n } else {\n console.error(\"Recieved an incorrect object\");\n console.error(validationError);\n this.labelInboxMessage(\n inboxEndpoint,\n messageId,\n MESSAGE_LABEL_INVALID,\n inboxToken,\n );\n }\n }\n }\n}\n\nconst MEDIA_OBJECT_SCHEMA = {\n properties: {\n value: {\n properties: {\n type: { type: \"string\" },\n size: { type: \"number\" },\n key: { type: \"string\" },\n },\n required: [\"type\", \"size\", \"key\"],\n },\n },\n} as const satisfies JSONSchema;\n\nconst CursorSchema = strictObject({\n cursors: record(url(), string()),\n channels: array(string()),\n});\n\ninterface SingleEndpointQueryResult<Schema extends JSONSchema> {\n messageId: string;\n object: GraffitiObject<Schema>;\n storageBucketKey: string;\n tags: Uint8Array[];\n allowedTickets: Uint8Array[] | undefined;\n tombstone?: boolean;\n announcements?: MessageMetadataAnnouncements | undefined;\n}\ninterface SingleEndpointQueryIterator<\n Schema extends JSONSchema,\n> extends AsyncGenerator<SingleEndpointQueryResult<Schema>, string> {}\ntype IndexedSingleEndpointQueryResult<Schema extends JSONSchema> =\n | {\n index: number;\n error?: undefined;\n result: IteratorResult<SingleEndpointQueryResult<Schema>, string>;\n }\n | {\n index: number;\n error: Error;\n result?: undefined;\n };\n\nasync function indexedSingleEndpointQueryNext<Schema extends JSONSchema>(\n it: SingleEndpointQueryIterator<Schema>,\n index: number,\n): Promise<IndexedSingleEndpointQueryResult<Schema>> {\n try {\n return {\n index: index,\n result: await it.next(),\n };\n } catch (e) {\n if (\n e instanceof GraffitiErrorCursorExpired ||\n e instanceof GraffitiErrorInvalidSchema\n ) {\n // Propogate these errors to the root\n throw e;\n }\n // Otherwise, silently pass them in the stream\n return {\n index,\n error: e instanceof Error ? e : new Error(String(e)),\n };\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["actor", "handle", "e", "url", "tombstonedMessageId", "result"]
7
7
  }