@openclaw/buzz 2026.9.2 → 2026.9.3

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.
@@ -151,8 +151,8 @@ function* parse(content) {
151
151
  if (h === 0 || content[h - 1].match(noCharacter)) {
152
152
  const m = content.slice(h + 1, h + MAX_HASHTAG_LENGTH).match(noCharacter);
153
153
  const end = m ? h + 1 + m.index : max;
154
- yield { type: "text", text: content.slice(prevIndex, h) };
155
- yield { type: "hashtag", value: content.slice(h + 1, end) };
154
+ yield { type: "text", text: content.slice(prevIndex, h), start: prevIndex, end: h };
155
+ yield { type: "hashtag", value: content.slice(h + 1, end), start: h, end };
156
156
  index = end;
157
157
  prevIndex = index;
158
158
  continue mainloop;
@@ -180,9 +180,9 @@ function* parse(content) {
180
180
  pointer = data;
181
181
  }
182
182
  if (prevIndex !== u - 5) {
183
- yield { type: "text", text: content.slice(prevIndex, u - 5) };
183
+ yield { type: "text", text: content.slice(prevIndex, u - 5), start: prevIndex, end: u - 5 };
184
184
  }
185
- yield { type: "reference", pointer };
185
+ yield { type: "reference", pointer, start: u - 5, end };
186
186
  index = end;
187
187
  prevIndex = index;
188
188
  continue mainloop;
@@ -200,27 +200,32 @@ function* parse(content) {
200
200
  throw new Error("invalid url");
201
201
  }
202
202
  if (prevIndex !== u - prefixLen) {
203
- yield { type: "text", text: content.slice(prevIndex, u - prefixLen) };
203
+ yield {
204
+ type: "text",
205
+ text: content.slice(prevIndex, u - prefixLen),
206
+ start: prevIndex,
207
+ end: u - prefixLen
208
+ };
204
209
  }
205
210
  if (/\.(png|jpe?g|gif|webp|heic|svg)$/i.test(url.pathname)) {
206
- yield { type: "image", url: url.toString() };
211
+ yield { type: "image", url: url.toString(), start: u - prefixLen, end };
207
212
  index = end;
208
213
  prevIndex = index;
209
214
  continue mainloop;
210
215
  }
211
216
  if (/\.(mp4|avi|webm|mkv|mov)$/i.test(url.pathname)) {
212
- yield { type: "video", url: url.toString() };
217
+ yield { type: "video", url: url.toString(), start: u - prefixLen, end };
213
218
  index = end;
214
219
  prevIndex = index;
215
220
  continue mainloop;
216
221
  }
217
222
  if (/\.(mp3|aac|ogg|opus|wav|flac)$/i.test(url.pathname)) {
218
- yield { type: "audio", url: url.toString() };
223
+ yield { type: "audio", url: url.toString(), start: u - prefixLen, end };
219
224
  index = end;
220
225
  prevIndex = index;
221
226
  continue mainloop;
222
227
  }
223
- yield { type: "url", url: url.toString() };
228
+ yield { type: "url", url: url.toString(), start: u - prefixLen, end };
224
229
  index = end;
225
230
  prevIndex = index;
226
231
  continue mainloop;
@@ -238,9 +243,14 @@ function* parse(content) {
238
243
  throw new Error("invalid ws url");
239
244
  }
240
245
  if (prevIndex !== u - prefixLen) {
241
- yield { type: "text", text: content.slice(prevIndex, u - prefixLen) };
246
+ yield {
247
+ type: "text",
248
+ text: content.slice(prevIndex, u - prefixLen),
249
+ start: prevIndex,
250
+ end: u - prefixLen
251
+ };
242
252
  }
243
- yield { type: "relay", url: url.toString() };
253
+ yield { type: "relay", url: url.toString(), start: u - prefixLen, end };
244
254
  index = end;
245
255
  prevIndex = index;
246
256
  continue mainloop;
@@ -253,9 +263,9 @@ function* parse(content) {
253
263
  const emoji = emojis[e];
254
264
  if (content[u + emoji.shortcode.length + 1] === ":" && content.slice(u + 1, u + emoji.shortcode.length + 1) === emoji.shortcode) {
255
265
  if (prevIndex !== u) {
256
- yield { type: "text", text: content.slice(prevIndex, u) };
266
+ yield { type: "text", text: content.slice(prevIndex, u), start: prevIndex, end: u };
257
267
  }
258
- yield emoji;
268
+ yield { ...emoji, start: u, end: u + emoji.shortcode.length + 2 };
259
269
  index = u + emoji.shortcode.length + 2;
260
270
  prevIndex = index;
261
271
  continue mainloop;
@@ -266,6 +276,6 @@ function* parse(content) {
266
276
  }
267
277
  }
268
278
  if (prevIndex !== max) {
269
- yield { type: "text", text: content.slice(prevIndex) };
279
+ yield { type: "text", text: content.slice(prevIndex), start: prevIndex, end: max };
270
280
  }
271
281
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../nip27.ts", "../../nip19.ts", "../../utils.ts"],
4
- "sourcesContent": ["import { NostrEvent } from './core.ts'\nimport { AddressPointer, EventPointer, ProfilePointer, decode } from './nip19.ts'\n\nexport type Block =\n | {\n type: 'text'\n text: string\n }\n | {\n type: 'reference'\n pointer: ProfilePointer | AddressPointer | EventPointer\n }\n | {\n type: 'url'\n url: string\n }\n | {\n type: 'relay'\n url: string\n }\n | {\n type: 'image'\n url: string\n }\n | {\n type: 'video'\n url: string\n }\n | {\n type: 'audio'\n url: string\n }\n | {\n type: 'emoji'\n shortcode: string\n url: string\n }\n | {\n type: 'hashtag'\n value: string\n }\n\nconst noCharacter = /\\W/m\nconst noURLCharacter = /[^\\w\\/] |[^\\w\\/]$|$|,| /m\nconst MAX_HASHTAG_LENGTH = 42\n\nexport function* parse(content: string | NostrEvent): Iterable<Block> {\n let emojis: { type: 'emoji'; shortcode: string; url: string }[] = []\n if (typeof content !== 'string') {\n for (let i = 0; i < content.tags.length; i++) {\n const tag = content.tags[i]\n if (tag[0] === 'emoji' && tag.length >= 3) {\n emojis.push({ type: 'emoji', shortcode: tag[1], url: tag[2] })\n }\n }\n content = content.content\n }\n\n const max = content.length\n let prevIndex = 0\n let index = 0\n mainloop: while (index < max) {\n const u = content.indexOf(':', index)\n const h = content.indexOf('#', index)\n if (u === -1 && h === -1) {\n // reached end\n break mainloop\n }\n\n if (u === -1 || (h >= 0 && h < u)) {\n // parse hashtag\n if (h === 0 || content[h - 1].match(noCharacter)) {\n const m = content.slice(h + 1, h + MAX_HASHTAG_LENGTH).match(noCharacter)\n const end = m ? h + 1 + m.index! : max\n yield { type: 'text', text: content.slice(prevIndex, h) }\n yield { type: 'hashtag', value: content.slice(h + 1, end) }\n index = end\n prevIndex = index\n continue mainloop\n }\n\n // ignore this, it is nothing\n index = h + 1\n continue mainloop\n }\n\n // otherwise parse things that have an \":\"\n if (content.slice(u - 5, u) === 'nostr') {\n const m = content.slice(u + 60).match(noCharacter)\n const end = m ? u + 60 + m.index! : max\n try {\n let pointer: ProfilePointer | AddressPointer | EventPointer\n let { data, type } = decode(content.slice(u + 1, end))\n\n switch (type) {\n case 'npub':\n pointer = { pubkey: data } as ProfilePointer\n break\n case 'note':\n pointer = { id: data } as EventPointer\n break\n case 'nsec':\n // ignore this, treat it as not a valid uri\n index = end + 1\n continue\n default:\n pointer = data as any\n }\n\n if (prevIndex !== u - 5) {\n yield { type: 'text', text: content.slice(prevIndex, u - 5) }\n }\n yield { type: 'reference', pointer }\n index = end\n prevIndex = index\n continue mainloop\n } catch (_err) {\n // ignore this, not a valid nostr uri\n index = u + 1\n continue mainloop\n }\n } else if (content.slice(u - 5, u) === 'https' || content.slice(u - 4, u) === 'http') {\n const m = content.slice(u + 4).match(noURLCharacter)\n const end = m ? u + 4 + m.index! : max\n const prefixLen = content[u - 1] === 's' ? 5 : 4\n try {\n let url = new URL(content.slice(u - prefixLen, end))\n if (url.hostname.indexOf('.') === -1) {\n throw new Error('invalid url')\n }\n\n if (prevIndex !== u - prefixLen) {\n yield { type: 'text', text: content.slice(prevIndex, u - prefixLen) }\n }\n\n if (/\\.(png|jpe?g|gif|webp|heic|svg)$/i.test(url.pathname)) {\n yield { type: 'image', url: url.toString() }\n index = end\n prevIndex = index\n continue mainloop\n }\n if (/\\.(mp4|avi|webm|mkv|mov)$/i.test(url.pathname)) {\n yield { type: 'video', url: url.toString() }\n index = end\n prevIndex = index\n continue mainloop\n }\n if (/\\.(mp3|aac|ogg|opus|wav|flac)$/i.test(url.pathname)) {\n yield { type: 'audio', url: url.toString() }\n index = end\n prevIndex = index\n continue mainloop\n }\n\n yield { type: 'url', url: url.toString() }\n index = end\n prevIndex = index\n continue mainloop\n } catch (_err) {\n // ignore this, not a valid url\n index = end + 1\n continue mainloop\n }\n } else if (content.slice(u - 3, u) === 'wss' || content.slice(u - 2, u) === 'ws') {\n const m = content.slice(u + 4).match(noURLCharacter)\n const end = m ? u + 4 + m.index! : max\n const prefixLen = content[u - 1] === 's' ? 3 : 2\n try {\n let url = new URL(content.slice(u - prefixLen, end))\n if (url.hostname.indexOf('.') === -1) {\n throw new Error('invalid ws url')\n }\n\n if (prevIndex !== u - prefixLen) {\n yield { type: 'text', text: content.slice(prevIndex, u - prefixLen) }\n }\n yield { type: 'relay', url: url.toString() }\n index = end\n prevIndex = index\n continue mainloop\n } catch (_err) {\n // ignore this, not a valid url\n index = end + 1\n continue mainloop\n }\n } else {\n // try to parse an emoji shortcode\n for (let e = 0; e < emojis.length; e++) {\n const emoji = emojis[e]\n if (\n content[u + emoji.shortcode.length + 1] === ':' &&\n content.slice(u + 1, u + emoji.shortcode.length + 1) === emoji.shortcode\n ) {\n // found an emoji\n if (prevIndex !== u) {\n yield { type: 'text', text: content.slice(prevIndex, u) }\n }\n yield emoji\n index = u + emoji.shortcode.length + 2\n prevIndex = index\n continue mainloop\n }\n }\n\n // ignore this, it is nothing\n index = u + 1\n continue mainloop\n }\n }\n\n if (prevIndex !== max) {\n yield { type: 'text', text: content.slice(prevIndex) }\n }\n}\n", "import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils.js'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport type NProfile = `nprofile1${string}`\nexport type NEvent = `nevent1${string}`\nexport type NAddr = `naddr1${string}`\nexport type NSec = `nsec1${string}`\nexport type NPub = `npub1${string}`\nexport type Note = `note1${string}`\nexport type Ncryptsec = `ncryptsec1${string}`\n\nexport const NostrTypeGuard = {\n isNProfile: (value?: string | null): value is NProfile => /^nprofile1[a-z\\d]+$/.test(value || ''),\n isNEvent: (value?: string | null): value is NEvent => /^nevent1[a-z\\d]+$/.test(value || ''),\n isNAddr: (value?: string | null): value is NAddr => /^naddr1[a-z\\d]+$/.test(value || ''),\n isNSec: (value?: string | null): value is NSec => /^nsec1[a-z\\d]{58}$/.test(value || ''),\n isNPub: (value?: string | null): value is NPub => /^npub1[a-z\\d]{58}$/.test(value || ''),\n isNote: (value?: string | null): value is Note => /^note1[a-z\\d]+$/.test(value || ''),\n isNcryptsec: (value?: string | null): value is Ncryptsec => /^ncryptsec1[a-z\\d]+$/.test(value || ''),\n}\n\nexport const Bech32MaxSize = 5000\n\n/**\n * Bech32 regex.\n * @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32\n */\nexport const BECH32_REGEX = /[\\x21-\\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/\n\nfunction integerToUint8Array(number: number) {\n // Create a Uint8Array with enough space to hold a 32-bit integer (4 bytes).\n const uint8Array = new Uint8Array(4)\n\n // Use bitwise operations to extract the bytes.\n uint8Array[0] = (number >> 24) & 0xff // Most significant byte (MSB)\n uint8Array[1] = (number >> 16) & 0xff\n uint8Array[2] = (number >> 8) & 0xff\n uint8Array[3] = number & 0xff // Least significant byte (LSB)\n\n return uint8Array\n}\n\nexport type ProfilePointer = {\n pubkey: string // hex\n relays?: string[]\n}\n\nexport type EventPointer = {\n id: string // hex\n relays?: string[]\n author?: string\n kind?: number\n}\n\nexport type AddressPointer = {\n identifier: string\n pubkey: string\n kind: number\n relays?: string[]\n}\n\nexport function decodeNostrURI(nip19code: string): ReturnType<typeof decode> | { type: 'invalid'; data: null } {\n try {\n if (nip19code.startsWith('nostr:')) nip19code = nip19code.substring(6)\n return decode(nip19code)\n } catch (_err) {\n return { type: 'invalid', data: null }\n }\n}\n\nexport type DecodedNevent = {\n type: 'nevent'\n data: EventPointer\n}\n\nexport type DecodedNprofile = {\n type: 'nprofile'\n data: ProfilePointer\n}\n\nexport type DecodedNaddr = {\n type: 'naddr'\n data: AddressPointer\n}\n\nexport type DecodedNsec = {\n type: 'nsec'\n data: Uint8Array\n}\n\nexport type DecodedNpub = {\n type: 'npub'\n data: string\n}\n\nexport type DecodedNote = {\n type: 'note'\n data: string\n}\n\nexport type DecodedResult = DecodedNevent | DecodedNprofile | DecodedNaddr | DecodedNpub | DecodedNsec | DecodedNote\n\nexport function decode(nip19: NEvent): DecodedNevent\nexport function decode(nip19: NProfile): DecodedNprofile\nexport function decode(nip19: NAddr): DecodedNaddr\nexport function decode(nip19: NSec): DecodedNsec\nexport function decode(nip19: NPub): DecodedNpub\nexport function decode(nip19: Note): DecodedNote\nexport function decode(code: string): DecodedResult\nexport function decode(code: string): DecodedResult {\n let { prefix, words } = bech32.decode(code as `${string}1${string}`, Bech32MaxSize)\n let data = new Uint8Array(bech32.fromWords(words))\n\n switch (prefix) {\n case 'nprofile': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nprofile')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n\n return {\n type: 'nprofile',\n data: {\n pubkey: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n case 'nevent': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nevent')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n if (tlv[2] && tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (tlv[3] && tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'nevent',\n data: {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : undefined,\n kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : undefined,\n },\n }\n }\n\n case 'naddr': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for naddr')\n if (!tlv[2]?.[0]) throw new Error('missing TLV 2 for naddr')\n if (tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (!tlv[3]?.[0]) throw new Error('missing TLV 3 for naddr')\n if (tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'naddr',\n data: {\n identifier: utf8Decoder.decode(tlv[0][0]),\n pubkey: bytesToHex(tlv[2][0]),\n kind: parseInt(bytesToHex(tlv[3][0]), 16),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n\n case 'nsec':\n return { type: prefix, data }\n\n case 'npub':\n case 'note':\n return { type: prefix, data: bytesToHex(data) }\n\n default:\n throw new Error(`unknown prefix ${prefix}`)\n }\n}\n\ntype TLV = { [t: number]: Uint8Array[] }\n\nfunction parseTLV(data: Uint8Array): TLV {\n let result: TLV = {}\n let rest = data\n while (rest.length > 0) {\n if (rest.length < 2) throw new Error('not enough data to read TLV')\n let t = rest[0]\n let l = rest[1]\n let v = rest.slice(2, 2 + l)\n rest = rest.slice(2 + l)\n if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)\n result[t] = result[t] || []\n result[t].push(v)\n }\n return result\n}\n\nexport function nsecEncode(key: Uint8Array): NSec {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): NPub {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): Note {\n return encodeBytes('note', hexToBytes(hex))\n}\n\nfunction encodeBech32<Prefix extends string>(prefix: Prefix, data: Uint8Array): `${Prefix}1${string}` {\n let words = bech32.toWords(data)\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`\n}\n\nexport function encodeBytes<Prefix extends string>(prefix: Prefix, bytes: Uint8Array): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes)\n}\n\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n let data = encodeTLV({\n 0: [hexToBytes(profile.pubkey)],\n 1: (profile.relays || []).map(url => utf8Encoder.encode(url)),\n })\n return encodeBech32('nprofile', data)\n}\n\nexport function neventEncode(event: EventPointer): NEvent {\n let kindArray\n if (event.kind !== undefined) {\n kindArray = integerToUint8Array(event.kind)\n }\n\n let data = encodeTLV({\n 0: [hexToBytes(event.id)],\n 1: (event.relays || []).map(url => utf8Encoder.encode(url)),\n 2: event.author ? [hexToBytes(event.author)] : [],\n 3: kindArray ? [new Uint8Array(kindArray)] : [],\n })\n\n return encodeBech32('nevent', data)\n}\n\nexport function naddrEncode(addr: AddressPointer): NAddr {\n let kind = new ArrayBuffer(4)\n new DataView(kind).setUint32(0, addr.kind, false)\n\n let data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays || []).map(url => utf8Encoder.encode(url)),\n 2: [hexToBytes(addr.pubkey)],\n 3: [new Uint8Array(kind)],\n })\n return encodeBech32('naddr', data)\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n let entries: Uint8Array[] = []\n\n Object.entries(tlv)\n .reverse()\n .forEach(([t, vs]) => {\n vs.forEach(v => {\n let entry = new Uint8Array(v.length + 2)\n entry.set([parseInt(t)], 0)\n entry.set([v.length], 1)\n entry.set(v, 2)\n entries.push(entry)\n })\n })\n\n return concatBytes(...entries)\n}\n", "import type { NostrEvent } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: NostrEvent[], event: NostrEvent): NostrEvent[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: NostrEvent[], event: NostrEvent): NostrEvent[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport function mergeReverseSortedLists(list1: NostrEvent[], list2: NostrEvent[]): NostrEvent[] {\n const result: NostrEvent[] = new Array(list1.length + list2.length)\n result.length = 0\n let i1 = 0\n let i2 = 0\n let sameTimestampIds: string[] = []\n\n while (i1 < list1.length && i2 < list2.length) {\n let next: NostrEvent\n if (list1[i1]?.created_at > list2[i2]?.created_at) {\n next = list1[i1]\n i1++\n } else {\n next = list2[i2]\n i2++\n }\n\n if (result.length > 0 && result[result.length - 1].created_at === next.created_at) {\n if (sameTimestampIds.includes(next.id)) continue\n } else {\n sameTimestampIds.length = 0\n }\n\n result.push(next)\n sameTimestampIds.push(next.id)\n }\n\n while (i1 < list1.length) {\n const next = list1[i1]\n i1++\n\n if (result.length > 0 && result[result.length - 1].created_at === next.created_at) {\n if (sameTimestampIds.includes(next.id)) continue\n } else {\n sameTimestampIds.length = 0\n }\n result.push(next)\n sameTimestampIds.push(next.id)\n }\n\n while (i2 < list2.length) {\n const next = list2[i2]\n i2++\n\n if (result.length > 0 && result[result.length - 1].created_at === next.created_at) {\n if (sameTimestampIds.includes(next.id)) continue\n } else {\n sameTimestampIds.length = 0\n }\n result.push(next)\n sameTimestampIds.push(next.id)\n }\n\n return result\n}\n\n/**\n * Checks if a string is a 64-char lowercase hex string as most Nostr ids and pubkeys.\n */\nexport function isHex32(input: string): boolean {\n if (input.length !== 64) return false\n for (let i = 0; i < 64; i++) {\n let cc = input.charCodeAt(i)\n if (isNaN(cc) || cc < 48 || cc > 102 || (cc > 57 && cc < 97)) {\n return false\n }\n }\n return true\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { NostrEvent } from './core.ts'\nimport { AddressPointer, EventPointer, ProfilePointer, decode } from './nip19.ts'\n\nexport type Block =\n | {\n type: 'text'\n text: string\n start: number\n end: number\n }\n | {\n type: 'reference'\n pointer: ProfilePointer | AddressPointer | EventPointer\n start: number\n end: number\n }\n | {\n type: 'url'\n url: string\n start: number\n end: number\n }\n | {\n type: 'relay'\n url: string\n start: number\n end: number\n }\n | {\n type: 'image'\n url: string\n start: number\n end: number\n }\n | {\n type: 'video'\n url: string\n start: number\n end: number\n }\n | {\n type: 'audio'\n url: string\n start: number\n end: number\n }\n | {\n type: 'emoji'\n shortcode: string\n url: string\n start: number\n end: number\n }\n | {\n type: 'hashtag'\n value: string\n start: number\n end: number\n }\n\nconst noCharacter = /\\W/m\nconst noURLCharacter = /[^\\w\\/] |[^\\w\\/]$|$|,| /m\nconst MAX_HASHTAG_LENGTH = 42\n\nexport function* parse(content: string | NostrEvent): Iterable<Block> {\n let emojis: { type: 'emoji'; shortcode: string; url: string }[] = []\n if (typeof content !== 'string') {\n for (let i = 0; i < content.tags.length; i++) {\n const tag = content.tags[i]\n if (tag[0] === 'emoji' && tag.length >= 3) {\n emojis.push({ type: 'emoji', shortcode: tag[1], url: tag[2] })\n }\n }\n content = content.content\n }\n\n const max = content.length\n let prevIndex = 0\n let index = 0\n mainloop: while (index < max) {\n const u = content.indexOf(':', index)\n const h = content.indexOf('#', index)\n if (u === -1 && h === -1) {\n // reached end\n break mainloop\n }\n\n if (u === -1 || (h >= 0 && h < u)) {\n // parse hashtag\n if (h === 0 || content[h - 1].match(noCharacter)) {\n const m = content.slice(h + 1, h + MAX_HASHTAG_LENGTH).match(noCharacter)\n const end = m ? h + 1 + m.index! : max\n yield { type: 'text', text: content.slice(prevIndex, h), start: prevIndex, end: h }\n yield { type: 'hashtag', value: content.slice(h + 1, end), start: h, end }\n index = end\n prevIndex = index\n continue mainloop\n }\n\n // ignore this, it is nothing\n index = h + 1\n continue mainloop\n }\n\n // otherwise parse things that have an \":\"\n if (content.slice(u - 5, u) === 'nostr') {\n const m = content.slice(u + 60).match(noCharacter)\n const end = m ? u + 60 + m.index! : max\n try {\n let pointer: ProfilePointer | AddressPointer | EventPointer\n let { data, type } = decode(content.slice(u + 1, end))\n\n switch (type) {\n case 'npub':\n pointer = { pubkey: data } as ProfilePointer\n break\n case 'note':\n pointer = { id: data } as EventPointer\n break\n case 'nsec':\n // ignore this, treat it as not a valid uri\n index = end + 1\n continue\n default:\n pointer = data as any\n }\n\n if (prevIndex !== u - 5) {\n yield { type: 'text', text: content.slice(prevIndex, u - 5), start: prevIndex, end: u - 5 }\n }\n yield { type: 'reference', pointer, start: u - 5, end }\n index = end\n prevIndex = index\n continue mainloop\n } catch (_err) {\n // ignore this, not a valid nostr uri\n index = u + 1\n continue mainloop\n }\n } else if (content.slice(u - 5, u) === 'https' || content.slice(u - 4, u) === 'http') {\n const m = content.slice(u + 4).match(noURLCharacter)\n const end = m ? u + 4 + m.index! : max\n const prefixLen = content[u - 1] === 's' ? 5 : 4\n try {\n let url = new URL(content.slice(u - prefixLen, end))\n if (url.hostname.indexOf('.') === -1) {\n throw new Error('invalid url')\n }\n\n if (prevIndex !== u - prefixLen) {\n yield {\n type: 'text',\n text: content.slice(prevIndex, u - prefixLen),\n start: prevIndex,\n end: u - prefixLen,\n }\n }\n\n if (/\\.(png|jpe?g|gif|webp|heic|svg)$/i.test(url.pathname)) {\n yield { type: 'image', url: url.toString(), start: u - prefixLen, end }\n index = end\n prevIndex = index\n continue mainloop\n }\n if (/\\.(mp4|avi|webm|mkv|mov)$/i.test(url.pathname)) {\n yield { type: 'video', url: url.toString(), start: u - prefixLen, end }\n index = end\n prevIndex = index\n continue mainloop\n }\n if (/\\.(mp3|aac|ogg|opus|wav|flac)$/i.test(url.pathname)) {\n yield { type: 'audio', url: url.toString(), start: u - prefixLen, end }\n index = end\n prevIndex = index\n continue mainloop\n }\n\n yield { type: 'url', url: url.toString(), start: u - prefixLen, end }\n index = end\n prevIndex = index\n continue mainloop\n } catch (_err) {\n // ignore this, not a valid url\n index = end + 1\n continue mainloop\n }\n } else if (content.slice(u - 3, u) === 'wss' || content.slice(u - 2, u) === 'ws') {\n const m = content.slice(u + 4).match(noURLCharacter)\n const end = m ? u + 4 + m.index! : max\n const prefixLen = content[u - 1] === 's' ? 3 : 2\n try {\n let url = new URL(content.slice(u - prefixLen, end))\n if (url.hostname.indexOf('.') === -1) {\n throw new Error('invalid ws url')\n }\n\n if (prevIndex !== u - prefixLen) {\n yield {\n type: 'text',\n text: content.slice(prevIndex, u - prefixLen),\n start: prevIndex,\n end: u - prefixLen,\n }\n }\n yield { type: 'relay', url: url.toString(), start: u - prefixLen, end }\n index = end\n prevIndex = index\n continue mainloop\n } catch (_err) {\n // ignore this, not a valid url\n index = end + 1\n continue mainloop\n }\n } else {\n // try to parse an emoji shortcode\n for (let e = 0; e < emojis.length; e++) {\n const emoji = emojis[e]\n if (\n content[u + emoji.shortcode.length + 1] === ':' &&\n content.slice(u + 1, u + emoji.shortcode.length + 1) === emoji.shortcode\n ) {\n // found an emoji\n if (prevIndex !== u) {\n yield { type: 'text', text: content.slice(prevIndex, u), start: prevIndex, end: u }\n }\n yield { ...emoji, start: u, end: u + emoji.shortcode.length + 2 }\n index = u + emoji.shortcode.length + 2\n prevIndex = index\n continue mainloop\n }\n }\n\n // ignore this, it is nothing\n index = u + 1\n continue mainloop\n }\n }\n\n if (prevIndex !== max) {\n yield { type: 'text', text: content.slice(prevIndex), start: prevIndex, end: max }\n }\n}\n", "import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils.js'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport type NProfile = `nprofile1${string}`\nexport type NEvent = `nevent1${string}`\nexport type NAddr = `naddr1${string}`\nexport type NSec = `nsec1${string}`\nexport type NPub = `npub1${string}`\nexport type Note = `note1${string}`\nexport type Ncryptsec = `ncryptsec1${string}`\n\nexport const NostrTypeGuard = {\n isNProfile: (value?: string | null): value is NProfile => /^nprofile1[a-z\\d]+$/.test(value || ''),\n isNEvent: (value?: string | null): value is NEvent => /^nevent1[a-z\\d]+$/.test(value || ''),\n isNAddr: (value?: string | null): value is NAddr => /^naddr1[a-z\\d]+$/.test(value || ''),\n isNSec: (value?: string | null): value is NSec => /^nsec1[a-z\\d]{58}$/.test(value || ''),\n isNPub: (value?: string | null): value is NPub => /^npub1[a-z\\d]{58}$/.test(value || ''),\n isNote: (value?: string | null): value is Note => /^note1[a-z\\d]+$/.test(value || ''),\n isNcryptsec: (value?: string | null): value is Ncryptsec => /^ncryptsec1[a-z\\d]+$/.test(value || ''),\n}\n\nexport const Bech32MaxSize = 5000\n\n/**\n * Bech32 regex.\n * @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32\n */\nexport const BECH32_REGEX = /[\\x21-\\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/\n\nfunction integerToUint8Array(number: number) {\n // Create a Uint8Array with enough space to hold a 32-bit integer (4 bytes).\n const uint8Array = new Uint8Array(4)\n\n // Use bitwise operations to extract the bytes.\n uint8Array[0] = (number >> 24) & 0xff // Most significant byte (MSB)\n uint8Array[1] = (number >> 16) & 0xff\n uint8Array[2] = (number >> 8) & 0xff\n uint8Array[3] = number & 0xff // Least significant byte (LSB)\n\n return uint8Array\n}\n\nexport type ProfilePointer = {\n pubkey: string // hex\n relays?: string[]\n}\n\nexport type EventPointer = {\n id: string // hex\n relays?: string[]\n author?: string\n kind?: number\n}\n\nexport type AddressPointer = {\n identifier: string\n pubkey: string\n kind: number\n relays?: string[]\n}\n\nexport function decodeNostrURI(nip19code: string): ReturnType<typeof decode> | { type: 'invalid'; data: null } {\n try {\n if (nip19code.startsWith('nostr:')) nip19code = nip19code.substring(6)\n return decode(nip19code)\n } catch (_err) {\n return { type: 'invalid', data: null }\n }\n}\n\nexport type DecodedNevent = {\n type: 'nevent'\n data: EventPointer\n}\n\nexport type DecodedNprofile = {\n type: 'nprofile'\n data: ProfilePointer\n}\n\nexport type DecodedNaddr = {\n type: 'naddr'\n data: AddressPointer\n}\n\nexport type DecodedNsec = {\n type: 'nsec'\n data: Uint8Array\n}\n\nexport type DecodedNpub = {\n type: 'npub'\n data: string\n}\n\nexport type DecodedNote = {\n type: 'note'\n data: string\n}\n\nexport type DecodedResult = DecodedNevent | DecodedNprofile | DecodedNaddr | DecodedNpub | DecodedNsec | DecodedNote\n\nexport function decode(nip19: NEvent): DecodedNevent\nexport function decode(nip19: NProfile): DecodedNprofile\nexport function decode(nip19: NAddr): DecodedNaddr\nexport function decode(nip19: NSec): DecodedNsec\nexport function decode(nip19: NPub): DecodedNpub\nexport function decode(nip19: Note): DecodedNote\nexport function decode(code: string): DecodedResult\nexport function decode(code: string): DecodedResult {\n let { prefix, words } = bech32.decode(code as `${string}1${string}`, Bech32MaxSize)\n let data = new Uint8Array(bech32.fromWords(words))\n\n switch (prefix) {\n case 'nprofile': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nprofile')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n\n return {\n type: 'nprofile',\n data: {\n pubkey: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n case 'nevent': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nevent')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n if (tlv[2] && tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (tlv[3] && tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'nevent',\n data: {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : undefined,\n kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : undefined,\n },\n }\n }\n\n case 'naddr': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for naddr')\n if (!tlv[2]?.[0]) throw new Error('missing TLV 2 for naddr')\n if (tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (!tlv[3]?.[0]) throw new Error('missing TLV 3 for naddr')\n if (tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'naddr',\n data: {\n identifier: utf8Decoder.decode(tlv[0][0]),\n pubkey: bytesToHex(tlv[2][0]),\n kind: parseInt(bytesToHex(tlv[3][0]), 16),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n\n case 'nsec':\n return { type: prefix, data }\n\n case 'npub':\n case 'note':\n return { type: prefix, data: bytesToHex(data) }\n\n default:\n throw new Error(`unknown prefix ${prefix}`)\n }\n}\n\ntype TLV = { [t: number]: Uint8Array[] }\n\nfunction parseTLV(data: Uint8Array): TLV {\n let result: TLV = {}\n let rest = data\n while (rest.length > 0) {\n if (rest.length < 2) throw new Error('not enough data to read TLV')\n let t = rest[0]\n let l = rest[1]\n let v = rest.slice(2, 2 + l)\n rest = rest.slice(2 + l)\n if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)\n result[t] = result[t] || []\n result[t].push(v)\n }\n return result\n}\n\nexport function nsecEncode(key: Uint8Array): NSec {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): NPub {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): Note {\n return encodeBytes('note', hexToBytes(hex))\n}\n\nfunction encodeBech32<Prefix extends string>(prefix: Prefix, data: Uint8Array): `${Prefix}1${string}` {\n let words = bech32.toWords(data)\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`\n}\n\nexport function encodeBytes<Prefix extends string>(prefix: Prefix, bytes: Uint8Array): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes)\n}\n\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n let data = encodeTLV({\n 0: [hexToBytes(profile.pubkey)],\n 1: (profile.relays || []).map(url => utf8Encoder.encode(url)),\n })\n return encodeBech32('nprofile', data)\n}\n\nexport function neventEncode(event: EventPointer): NEvent {\n let kindArray\n if (event.kind !== undefined) {\n kindArray = integerToUint8Array(event.kind)\n }\n\n let data = encodeTLV({\n 0: [hexToBytes(event.id)],\n 1: (event.relays || []).map(url => utf8Encoder.encode(url)),\n 2: event.author ? [hexToBytes(event.author)] : [],\n 3: kindArray ? [new Uint8Array(kindArray)] : [],\n })\n\n return encodeBech32('nevent', data)\n}\n\nexport function naddrEncode(addr: AddressPointer): NAddr {\n let kind = new ArrayBuffer(4)\n new DataView(kind).setUint32(0, addr.kind, false)\n\n let data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays || []).map(url => utf8Encoder.encode(url)),\n 2: [hexToBytes(addr.pubkey)],\n 3: [new Uint8Array(kind)],\n })\n return encodeBech32('naddr', data)\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n let entries: Uint8Array[] = []\n\n Object.entries(tlv)\n .reverse()\n .forEach(([t, vs]) => {\n vs.forEach(v => {\n let entry = new Uint8Array(v.length + 2)\n entry.set([parseInt(t)], 0)\n entry.set([v.length], 1)\n entry.set(v, 2)\n entries.push(entry)\n })\n })\n\n return concatBytes(...entries)\n}\n", "import type { NostrEvent } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: NostrEvent[], event: NostrEvent): NostrEvent[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: NostrEvent[], event: NostrEvent): NostrEvent[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport function mergeReverseSortedLists(list1: NostrEvent[], list2: NostrEvent[]): NostrEvent[] {\n const result: NostrEvent[] = new Array(list1.length + list2.length)\n result.length = 0\n let i1 = 0\n let i2 = 0\n let sameTimestampIds: string[] = []\n\n while (i1 < list1.length && i2 < list2.length) {\n let next: NostrEvent\n if (list1[i1]?.created_at > list2[i2]?.created_at) {\n next = list1[i1]\n i1++\n } else {\n next = list2[i2]\n i2++\n }\n\n if (result.length > 0 && result[result.length - 1].created_at === next.created_at) {\n if (sameTimestampIds.includes(next.id)) continue\n } else {\n sameTimestampIds.length = 0\n }\n\n result.push(next)\n sameTimestampIds.push(next.id)\n }\n\n while (i1 < list1.length) {\n const next = list1[i1]\n i1++\n\n if (result.length > 0 && result[result.length - 1].created_at === next.created_at) {\n if (sameTimestampIds.includes(next.id)) continue\n } else {\n sameTimestampIds.length = 0\n }\n result.push(next)\n sameTimestampIds.push(next.id)\n }\n\n while (i2 < list2.length) {\n const next = list2[i2]\n i2++\n\n if (result.length > 0 && result[result.length - 1].created_at === next.created_at) {\n if (sameTimestampIds.includes(next.id)) continue\n } else {\n sameTimestampIds.length = 0\n }\n result.push(next)\n sameTimestampIds.push(next.id)\n }\n\n return result\n}\n\n/**\n * Checks if a string is a 64-char lowercase hex string as most Nostr ids and pubkeys.\n */\nexport function isHex32(input: string): boolean {\n if (input.length !== 64) return false\n for (let i = 0; i < 64; i++) {\n let cc = input.charCodeAt(i)\n if (isNaN(cc) || cc < 48 || cc > 102 || (cc > 57 && cc < 97)) {\n return false\n }\n }\n return true\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["import_utils"]
7
7
  }
@@ -2901,8 +2901,8 @@ function* parse4(content) {
2901
2901
  if (h === 0 || content[h - 1].match(noCharacter)) {
2902
2902
  const m = content.slice(h + 1, h + MAX_HASHTAG_LENGTH).match(noCharacter);
2903
2903
  const end = m ? h + 1 + m.index : max;
2904
- yield { type: "text", text: content.slice(prevIndex, h) };
2905
- yield { type: "hashtag", value: content.slice(h + 1, end) };
2904
+ yield { type: "text", text: content.slice(prevIndex, h), start: prevIndex, end: h };
2905
+ yield { type: "hashtag", value: content.slice(h + 1, end), start: h, end };
2906
2906
  index = end;
2907
2907
  prevIndex = index;
2908
2908
  continue mainloop;
@@ -2930,9 +2930,9 @@ function* parse4(content) {
2930
2930
  pointer = data;
2931
2931
  }
2932
2932
  if (prevIndex !== u - 5) {
2933
- yield { type: "text", text: content.slice(prevIndex, u - 5) };
2933
+ yield { type: "text", text: content.slice(prevIndex, u - 5), start: prevIndex, end: u - 5 };
2934
2934
  }
2935
- yield { type: "reference", pointer };
2935
+ yield { type: "reference", pointer, start: u - 5, end };
2936
2936
  index = end;
2937
2937
  prevIndex = index;
2938
2938
  continue mainloop;
@@ -2950,27 +2950,32 @@ function* parse4(content) {
2950
2950
  throw new Error("invalid url");
2951
2951
  }
2952
2952
  if (prevIndex !== u - prefixLen) {
2953
- yield { type: "text", text: content.slice(prevIndex, u - prefixLen) };
2953
+ yield {
2954
+ type: "text",
2955
+ text: content.slice(prevIndex, u - prefixLen),
2956
+ start: prevIndex,
2957
+ end: u - prefixLen
2958
+ };
2954
2959
  }
2955
2960
  if (/\.(png|jpe?g|gif|webp|heic|svg)$/i.test(url.pathname)) {
2956
- yield { type: "image", url: url.toString() };
2961
+ yield { type: "image", url: url.toString(), start: u - prefixLen, end };
2957
2962
  index = end;
2958
2963
  prevIndex = index;
2959
2964
  continue mainloop;
2960
2965
  }
2961
2966
  if (/\.(mp4|avi|webm|mkv|mov)$/i.test(url.pathname)) {
2962
- yield { type: "video", url: url.toString() };
2967
+ yield { type: "video", url: url.toString(), start: u - prefixLen, end };
2963
2968
  index = end;
2964
2969
  prevIndex = index;
2965
2970
  continue mainloop;
2966
2971
  }
2967
2972
  if (/\.(mp3|aac|ogg|opus|wav|flac)$/i.test(url.pathname)) {
2968
- yield { type: "audio", url: url.toString() };
2973
+ yield { type: "audio", url: url.toString(), start: u - prefixLen, end };
2969
2974
  index = end;
2970
2975
  prevIndex = index;
2971
2976
  continue mainloop;
2972
2977
  }
2973
- yield { type: "url", url: url.toString() };
2978
+ yield { type: "url", url: url.toString(), start: u - prefixLen, end };
2974
2979
  index = end;
2975
2980
  prevIndex = index;
2976
2981
  continue mainloop;
@@ -2988,9 +2993,14 @@ function* parse4(content) {
2988
2993
  throw new Error("invalid ws url");
2989
2994
  }
2990
2995
  if (prevIndex !== u - prefixLen) {
2991
- yield { type: "text", text: content.slice(prevIndex, u - prefixLen) };
2996
+ yield {
2997
+ type: "text",
2998
+ text: content.slice(prevIndex, u - prefixLen),
2999
+ start: prevIndex,
3000
+ end: u - prefixLen
3001
+ };
2992
3002
  }
2993
- yield { type: "relay", url: url.toString() };
3003
+ yield { type: "relay", url: url.toString(), start: u - prefixLen, end };
2994
3004
  index = end;
2995
3005
  prevIndex = index;
2996
3006
  continue mainloop;
@@ -3003,9 +3013,9 @@ function* parse4(content) {
3003
3013
  const emoji = emojis[e];
3004
3014
  if (content[u + emoji.shortcode.length + 1] === ":" && content.slice(u + 1, u + emoji.shortcode.length + 1) === emoji.shortcode) {
3005
3015
  if (prevIndex !== u) {
3006
- yield { type: "text", text: content.slice(prevIndex, u) };
3016
+ yield { type: "text", text: content.slice(prevIndex, u), start: prevIndex, end: u };
3007
3017
  }
3008
- yield emoji;
3018
+ yield { ...emoji, start: u, end: u + emoji.shortcode.length + 2 };
3009
3019
  index = u + emoji.shortcode.length + 2;
3010
3020
  prevIndex = index;
3011
3021
  continue mainloop;
@@ -3016,7 +3026,7 @@ function* parse4(content) {
3016
3026
  }
3017
3027
  }
3018
3028
  if (prevIndex !== max) {
3019
- yield { type: "text", text: content.slice(prevIndex) };
3029
+ yield { type: "text", text: content.slice(prevIndex), start: prevIndex, end: max };
3020
3030
  }
3021
3031
  }
3022
3032