@kehto/services 0.13.2 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -231,9 +231,9 @@ function createNotificationService(options) {
231
231
 
232
232
  // src/identity-service.ts
233
233
  var IDENTITY_SERVICE_VERSION = "1.0.0";
234
- function sendProviderError(send, result, fallback, err2) {
234
+ function sendProviderError(send, result2, fallback, err2) {
235
235
  send({
236
- ...result,
236
+ ...result2,
237
237
  error: err2?.message ?? fallback
238
238
  });
239
239
  }
@@ -251,7 +251,7 @@ function sendOptionalProviderResult(options, send, fallbackResult, errorFallback
251
251
  send(fallbackResult);
252
252
  return;
253
253
  }
254
- Promise.resolve(getCurrentPubkey(options)).then((pubkey) => buildResult(pubkey)).then((result) => send(result)).catch((err2) => sendProviderError(send, fallbackResult, errorFallback, err2));
254
+ Promise.resolve(getCurrentPubkey(options)).then((pubkey) => buildResult(pubkey)).then((result2) => send(result2)).catch((err2) => sendProviderError(send, fallbackResult, errorFallback, err2));
255
255
  }
256
256
  function sendIdentityError(send, id, typeBase, error) {
257
257
  send({ type: `${typeBase}.error`, id, error });
@@ -262,21 +262,21 @@ function sendSignerError(send, id, typeBase, fallback, err2) {
262
262
  function handleGetPublicKey(options, id, send) {
263
263
  const signer = options.getSigner();
264
264
  if (!signer) {
265
- const result = {
265
+ const result2 = {
266
266
  type: "identity.getPublicKey.result",
267
267
  id,
268
268
  pubkey: ""
269
269
  };
270
- send(result);
270
+ send(result2);
271
271
  return;
272
272
  }
273
273
  Promise.resolve(signer.getPublicKey?.()).then((pubkey) => {
274
- const result = {
274
+ const result2 = {
275
275
  type: "identity.getPublicKey.result",
276
276
  id,
277
277
  pubkey: pubkey ?? ""
278
278
  };
279
- send(result);
279
+ send(result2);
280
280
  }).catch((err2) => sendSignerError(send, id, "identity.getPublicKey", "getPublicKey failed", err2));
281
281
  }
282
282
  function handleGetRelays(options, id, send) {
@@ -286,12 +286,12 @@ function handleGetRelays(options, id, send) {
286
286
  return;
287
287
  }
288
288
  Promise.resolve(signer.getRelays?.() ?? {}).then((relays) => {
289
- const result = {
289
+ const result2 = {
290
290
  type: "identity.getRelays.result",
291
291
  id,
292
292
  relays
293
293
  };
294
- send(result);
294
+ send(result2);
295
295
  }).catch((err2) => sendSignerError(send, id, "identity.getRelays", "getRelays failed", err2));
296
296
  }
297
297
  function handleReadProvider(options, id, message, send) {
@@ -426,6 +426,7 @@ function createIdentityService(options) {
426
426
  }
427
427
 
428
428
  // src/relay-pool-service.ts
429
+ import { createRelayEventResultWithHints } from "@kehto/runtime";
429
430
  var EOSE_FALLBACK_MS = 15e3;
430
431
  function createRelayPoolService(options) {
431
432
  const tracked = /* @__PURE__ */ new Map();
@@ -470,7 +471,7 @@ function createRelayPoolService(options) {
470
471
  }
471
472
  return;
472
473
  }
473
- send({ type: "relay.event", subId, event: item });
474
+ send({ type: "relay.event", subId, result: createRelayEventResultWithHints(item, relayUrls2) });
474
475
  }, relayUrls2);
475
476
  tracked.set(subKey, { handle, eoseTimer });
476
477
  return;
@@ -516,6 +517,7 @@ function createRelayPoolService(options) {
516
517
  }
517
518
 
518
519
  // src/cache-service.ts
520
+ import { createRelayEventResult } from "@kehto/runtime";
519
521
  function createCacheService(options) {
520
522
  return {
521
523
  descriptor: {
@@ -535,7 +537,7 @@ function createCacheService(options) {
535
537
  }
536
538
  options.query(filters).then((events) => {
537
539
  for (const event of events) {
538
- send({ type: "relay.event", subId, event });
540
+ send({ type: "relay.event", subId, result: createRelayEventResult(event) });
539
541
  }
540
542
  send({ type: "relay.eose", subId });
541
543
  }).catch(() => {
@@ -560,7 +562,94 @@ function createCacheService(options) {
560
562
  };
561
563
  }
562
564
 
565
+ // src/count-service.ts
566
+ var DEFAULT_MAX_FILTERS = 16;
567
+ function createCountService(options) {
568
+ return {
569
+ descriptor: {
570
+ name: "count",
571
+ version: "1.0.0",
572
+ description: "Runtime-mediated NIP-01 filter counts"
573
+ },
574
+ handleMessage(windowId, message, send) {
575
+ if (message.type !== "count.query") return;
576
+ const countMessage = message;
577
+ const id = typeof countMessage.id === "string" ? countMessage.id : "";
578
+ const filters = countMessage.filters;
579
+ if (!isValidFilterArray(filters)) {
580
+ send(result(id, { ok: false, error: "invalid-filter", reason: "count.query requires a non-empty filters array" }));
581
+ return;
582
+ }
583
+ const maxFilters = options.maxFilters ?? DEFAULT_MAX_FILTERS;
584
+ if (filters.length > maxFilters) {
585
+ send(result(id, { ok: false, error: "too-expensive", reason: `count.query accepts at most ${maxFilters} filters` }));
586
+ return;
587
+ }
588
+ for (let i = 0; i < filters.length; i++) {
589
+ const supported = options.isFilterSupported?.(filters[i], i) ?? true;
590
+ if (supported !== true) {
591
+ send(result(id, {
592
+ ok: false,
593
+ error: "unsupported-filter",
594
+ reason: typeof supported === "string" ? supported : `filter ${i} is not supported by this count backend`
595
+ }));
596
+ return;
597
+ }
598
+ }
599
+ const request = {
600
+ filters,
601
+ windowId,
602
+ ...isPlainObject(countMessage.options) ? { options: countMessage.options } : {}
603
+ };
604
+ Promise.resolve(options.count(request)).then((countResult) => {
605
+ send(result(id, normalizeCountResult(countResult)));
606
+ }).catch((error) => {
607
+ send(result(id, {
608
+ ok: false,
609
+ error: "count-unavailable",
610
+ reason: error instanceof Error ? error.message : "count backend failed"
611
+ }));
612
+ });
613
+ }
614
+ };
615
+ }
616
+ function result(id, value) {
617
+ return {
618
+ type: "count.query.result",
619
+ id,
620
+ ok: value.ok,
621
+ ...typeof value.count === "number" ? { count: value.count } : {},
622
+ ...typeof value.approximate === "boolean" ? { approximate: value.approximate } : {},
623
+ ...typeof value.hll === "string" ? { hll: value.hll } : {},
624
+ ...Array.isArray(value.relays) ? { relays: value.relays.filter((relay) => typeof relay === "string") } : {},
625
+ ...typeof value.error === "string" ? { error: value.error } : {},
626
+ ...typeof value.reason === "string" ? { reason: value.reason } : {}
627
+ };
628
+ }
629
+ function normalizeCountResult(value) {
630
+ if (typeof value === "number") {
631
+ return Number.isFinite(value) && value >= 0 ? { ok: true, count: Math.floor(value), approximate: false } : { ok: false, error: "count-unavailable", reason: "count backend returned an invalid count" };
632
+ }
633
+ const count = typeof value.count === "number" && Number.isFinite(value.count) && value.count >= 0 ? Math.floor(value.count) : void 0;
634
+ return {
635
+ ok: value.ok === true,
636
+ ...count !== void 0 ? { count } : {},
637
+ ...typeof value.approximate === "boolean" ? { approximate: value.approximate } : {},
638
+ ...typeof value.hll === "string" ? { hll: value.hll } : {},
639
+ ...Array.isArray(value.relays) ? { relays: value.relays } : {},
640
+ ...typeof value.error === "string" ? { error: value.error } : {},
641
+ ...typeof value.reason === "string" ? { reason: value.reason } : {}
642
+ };
643
+ }
644
+ function isValidFilterArray(value) {
645
+ return Array.isArray(value) && value.length > 0 && value.every((filter) => isPlainObject(filter));
646
+ }
647
+ function isPlainObject(value) {
648
+ return typeof value === "object" && value !== null && !Array.isArray(value);
649
+ }
650
+
563
651
  // src/coordinated-relay.ts
652
+ import { createRelayEventResult as createRelayEventResult2, createRelayEventResultWithHints as createRelayEventResultWithHints2 } from "@kehto/runtime";
564
653
  var DEFAULT_EOSE_TIMEOUT_MS = 15e3;
565
654
  function createCoordinatedRelay(options) {
566
655
  const timeoutMs = options.eoseTimeoutMs ?? DEFAULT_EOSE_TIMEOUT_MS;
@@ -583,10 +672,13 @@ function createCoordinatedRelay(options) {
583
672
  handleMessage(windowId, message, send) {
584
673
  const relayMessage = message;
585
674
  if (message.type === "relay.subscribe") {
586
- let deliver2 = function(event) {
675
+ let deliver2 = function(event, relayHints) {
587
676
  if (tracked.seenIds.has(event.id)) return;
588
677
  tracked.seenIds.add(event.id);
589
- if (subs.has(subKey)) send({ type: "relay.event", subId, event });
678
+ if (subs.has(subKey)) {
679
+ const result2 = relayHints ? createRelayEventResultWithHints2(event, relayHints) : createRelayEventResult2(event);
680
+ send({ type: "relay.event", subId, result: result2 });
681
+ }
590
682
  };
591
683
  var deliver = deliver2;
592
684
  const subId = relayMessage.subId;
@@ -642,7 +734,7 @@ function createCoordinatedRelay(options) {
642
734
  maybeSendEose(subKey, subId, send);
643
735
  return;
644
736
  }
645
- deliver2(item);
737
+ deliver2(item, relayUrls2);
646
738
  if (cacheAvailable) {
647
739
  try {
648
740
  options.cache.store(item);
@@ -807,13 +899,13 @@ function createKeysService(options = {}) {
807
899
  return;
808
900
  }
809
901
  }
810
- const result = {
902
+ const result2 = {
811
903
  type: "keys.registerAction.result",
812
904
  id: m.id,
813
905
  actionId: m.action.id,
814
906
  ...m.action.defaultKey ? { binding: m.action.defaultKey } : {}
815
907
  };
816
- send(result);
908
+ send(result2);
817
909
  return;
818
910
  }
819
911
  case "keys.unregisterAction": {
@@ -954,13 +1046,13 @@ function createKeysService(options = {}) {
954
1046
  return;
955
1047
  }
956
1048
  }
957
- const result = {
1049
+ const result2 = {
958
1050
  type: "keys.registerAction.result",
959
1051
  id: m.id,
960
1052
  actionId: m.action.id,
961
1053
  ...m.action.defaultKey ? { binding: m.action.defaultKey } : {}
962
1054
  };
963
- send(result);
1055
+ send(result2);
964
1056
  return;
965
1057
  }
966
1058
  case "keys.unregisterAction": {
@@ -1391,12 +1483,12 @@ function createNotifyService(options = {}) {
1391
1483
  case "notify.send": {
1392
1484
  const m = message;
1393
1485
  options.onSend?.(windowId, m);
1394
- const result = {
1486
+ const result2 = {
1395
1487
  type: "notify.send.result",
1396
1488
  id: m.id,
1397
1489
  notificationId: gen()
1398
1490
  };
1399
- send(result);
1491
+ send(result2);
1400
1492
  return;
1401
1493
  }
1402
1494
  case "notify.dismiss":
@@ -1405,12 +1497,12 @@ function createNotifyService(options = {}) {
1405
1497
  return;
1406
1498
  case "notify.permission.request": {
1407
1499
  const m = message;
1408
- const result = {
1500
+ const result2 = {
1409
1501
  type: "notify.permission.result",
1410
1502
  id: m.id,
1411
1503
  granted: defaultGrant
1412
1504
  };
1413
- send(result);
1505
+ send(result2);
1414
1506
  return;
1415
1507
  }
1416
1508
  default: {
@@ -1451,12 +1543,12 @@ function createThemeService(options = {}) {
1451
1543
  handleMessage(_windowId, message, send) {
1452
1544
  const id = message.id ?? "";
1453
1545
  if (message.type === "theme.get") {
1454
- const result = {
1546
+ const result2 = {
1455
1547
  type: "theme.get.result",
1456
1548
  id,
1457
1549
  theme: currentTheme
1458
1550
  };
1459
- send(result);
1551
+ send(result2);
1460
1552
  return;
1461
1553
  }
1462
1554
  send({
@@ -1580,14 +1672,14 @@ function createConfigService(options) {
1580
1672
  case "config.registerSchema": {
1581
1673
  const m = message;
1582
1674
  const validation = options.registerSchema ? options.registerSchema(windowId, m.schema, m.version) : validateCoreSubset(m.schema);
1583
- const result = validation.ok ? { type: "config.registerSchema.result", id: m.id, ok: true } : {
1675
+ const result2 = validation.ok ? { type: "config.registerSchema.result", id: m.id, ok: true } : {
1584
1676
  type: "config.registerSchema.result",
1585
1677
  id: m.id,
1586
1678
  ok: false,
1587
1679
  code: validation.code,
1588
1680
  error: validation.error
1589
1681
  };
1590
- send(result);
1682
+ send(result2);
1591
1683
  return;
1592
1684
  }
1593
1685
  case "config.openSettings": {
@@ -1958,45 +2050,42 @@ function buildEventQuery(eventId, eventOptions) {
1958
2050
  if (eventOptions?.timeoutMs !== void 0) queryOptions.timeoutMs = eventOptions.timeoutMs;
1959
2051
  return { filter, queryOptions };
1960
2052
  }
1961
- function eventResultFromQuery(eventId, result) {
1962
- const event = result.events.find((candidate) => candidate.id === eventId);
1963
- const eventResult = {
1964
- relays: event ? result.relays[eventId] ?? [] : []
1965
- };
1966
- if (event) eventResult.event = event;
1967
- if (!event) eventResult.error = result.error ?? "not found";
1968
- else if (result.error !== void 0) eventResult.error = result.error;
1969
- if (result.incomplete !== void 0) eventResult.incomplete = result.incomplete;
2053
+ function eventResultFromQuery(eventId, result2) {
2054
+ const relayResult = result2.events.find((candidate) => candidate.event.id === eventId);
2055
+ const eventResult = {};
2056
+ if (relayResult) eventResult.result = relayResult;
2057
+ if (!relayResult) eventResult.error = result2.error ?? "not found";
2058
+ else if (result2.error !== void 0) eventResult.error = result2.error;
2059
+ if (result2.incomplete !== void 0) eventResult.incomplete = result2.incomplete;
1970
2060
  return eventResult;
1971
2061
  }
1972
2062
  function fallbackGetEvent(router, eventId, eventOptions) {
1973
2063
  const { filter, queryOptions } = buildEventQuery(eventId, eventOptions);
1974
- return router.query([filter], queryOptions).then((result) => eventResultFromQuery(eventId, result));
2064
+ return router.query([filter], queryOptions).then((result2) => eventResultFromQuery(eventId, result2));
1975
2065
  }
1976
- function sendEventResult(id, eventId, result, send) {
1977
- if (result.event && result.event.id !== eventId) {
1978
- send({ type: "outbox.getEvent.result", id, relays: [], error: "not found" });
2066
+ function sendEventResult(id, eventId, result2, send) {
2067
+ if (result2.result && result2.result.event.id !== eventId) {
2068
+ send({ type: "outbox.getEvent.result", id, error: "not found" });
1979
2069
  return;
1980
2070
  }
1981
2071
  send({
1982
2072
  type: "outbox.getEvent.result",
1983
2073
  id,
1984
- ...result.event === void 0 ? {} : { event: result.event },
1985
- relays: result.relays,
1986
- ...result.incomplete === void 0 ? {} : { incomplete: result.incomplete },
1987
- ...result.error === void 0 ? {} : { error: result.error }
2074
+ ...result2.result === void 0 ? {} : { result: result2.result },
2075
+ ...result2.incomplete === void 0 ? {} : { incomplete: result2.incomplete },
2076
+ ...result2.error === void 0 ? {} : { error: result2.error }
1988
2077
  });
1989
2078
  }
1990
2079
  function handleGetEvent(router, msg, send) {
1991
2080
  const m = msg;
1992
2081
  const id = m.id ?? "";
1993
2082
  if (typeof m.eventId !== "string" || m.eventId.length === 0) {
1994
- send({ type: "outbox.getEvent.result", id, relays: [], error: "invalid filter" });
2083
+ send({ type: "outbox.getEvent.result", id, error: "invalid filter" });
1995
2084
  return;
1996
2085
  }
1997
2086
  const getEvent = router.getEvent ?? ((eventId, eventOptions) => fallbackGetEvent(router, eventId, eventOptions));
1998
- void getEvent(m.eventId, m.options).then((result) => sendEventResult(id, m.eventId, result, send)).catch(
1999
- (err2) => send({ type: "outbox.getEvent.result", id, relays: [], error: toErrorMessage(err2) })
2087
+ void getEvent(m.eventId, m.options).then((result2) => sendEventResult(id, m.eventId, result2, send)).catch(
2088
+ (err2) => send({ type: "outbox.getEvent.result", id, error: toErrorMessage(err2) })
2000
2089
  );
2001
2090
  }
2002
2091
  function createOutboxService(options) {
@@ -2010,20 +2099,19 @@ function createOutboxService(options) {
2010
2099
  const id = m.id ?? "";
2011
2100
  const filters = normalizeFilters(m.filters);
2012
2101
  if (!filters) {
2013
- send({ type: "outbox.query.result", id, events: [], relays: {}, error: "invalid filter" });
2102
+ send({ type: "outbox.query.result", id, events: [], error: "invalid filter" });
2014
2103
  return;
2015
2104
  }
2016
2105
  void router.query(filters, m.options).then(
2017
- (result) => send({
2106
+ (result2) => send({
2018
2107
  type: "outbox.query.result",
2019
2108
  id,
2020
- events: result.events,
2021
- relays: result.relays,
2022
- ...result.incomplete === void 0 ? {} : { incomplete: result.incomplete },
2023
- ...result.error === void 0 ? {} : { error: result.error }
2109
+ events: result2.events,
2110
+ ...result2.incomplete === void 0 ? {} : { incomplete: result2.incomplete },
2111
+ ...result2.error === void 0 ? {} : { error: result2.error }
2024
2112
  })
2025
2113
  ).catch(
2026
- (err2) => send({ type: "outbox.query.result", id, events: [], relays: {}, error: toErrorMessage(err2) })
2114
+ (err2) => send({ type: "outbox.query.result", id, events: [], error: toErrorMessage(err2) })
2027
2115
  );
2028
2116
  }
2029
2117
  function handleSubscribe(windowId, msg, send) {
@@ -2039,8 +2127,7 @@ function createOutboxService(options) {
2039
2127
  return;
2040
2128
  }
2041
2129
  const sink = {
2042
- event: (event, relay) => send({ type: "outbox.event", subId, event, ...relay === void 0 ? {} : { relay } }),
2043
- eose: () => send({ type: "outbox.eose", subId }),
2130
+ event: (result2) => send({ type: "outbox.event", subId, result: result2 }),
2044
2131
  closed: (reason) => {
2045
2132
  subscriptions.delete(subKey);
2046
2133
  send({ type: "outbox.closed", subId, ...reason === void 0 ? {} : { reason } });
@@ -2065,14 +2152,14 @@ function createOutboxService(options) {
2065
2152
  return;
2066
2153
  }
2067
2154
  void router.publish(m.event, m.options).then(
2068
- (result) => send({
2155
+ (result2) => send({
2069
2156
  type: "outbox.publish.result",
2070
2157
  id,
2071
- ok: result.ok,
2072
- ...result.event === void 0 ? {} : { event: result.event },
2073
- ...result.eventId === void 0 ? {} : { eventId: result.eventId },
2074
- ...result.relays === void 0 ? {} : { relays: result.relays },
2075
- ...result.error === void 0 ? {} : { error: result.error }
2158
+ ok: result2.ok,
2159
+ ...result2.event === void 0 ? {} : { event: result2.event },
2160
+ ...result2.eventId === void 0 ? {} : { eventId: result2.eventId },
2161
+ ...result2.relays === void 0 ? {} : { relays: result2.relays },
2162
+ ...result2.error === void 0 ? {} : { error: result2.error }
2076
2163
  })
2077
2164
  ).catch(
2078
2165
  (err2) => send({ type: "outbox.publish.result", id, ok: false, error: toErrorMessage(err2) })
@@ -2133,6 +2220,7 @@ function toErrorMessage(err2) {
2133
2220
  }
2134
2221
 
2135
2222
  // src/relay-pool-outbox-router.ts
2223
+ import { createRelayEventResultWithHints as createRelayEventResultWithHints3 } from "@kehto/runtime";
2136
2224
  var DEFAULT_QUERY_TIMEOUT_MS = 4e3;
2137
2225
  function defaultRelayAllowed(url) {
2138
2226
  return typeof url === "string" && (url.startsWith("wss://") || url.startsWith("ws://"));
@@ -2206,10 +2294,10 @@ function admitEvent(ctx, collector, event) {
2206
2294
  );
2207
2295
  }
2208
2296
  function buildCollectResult(collector, timedOut) {
2209
- const events = [...collector.seen.values()];
2210
- const relayObj = {};
2211
- for (const event of events) relayObj[event.id] = [...collector.relayMap.get(event.id) ?? []];
2212
- return { events, relayMap: relayObj, incomplete: timedOut };
2297
+ const events = [...collector.seen.values()].map(
2298
+ (event) => createRelayEventResultWithHints3(event, [...collector.relayMap.get(event.id) ?? []])
2299
+ );
2300
+ return { events, incomplete: timedOut };
2213
2301
  }
2214
2302
  function collectFromRelays(ctx, filters, relayUrls2, timeoutMs) {
2215
2303
  return new Promise((resolve) => {
@@ -2254,28 +2342,28 @@ function relayPoolSubscribe(ctx, filters, relayUrl, cb) {
2254
2342
  }
2255
2343
  async function queryImpl(ctx, filters, options) {
2256
2344
  if (!ctx.relayPool.isAvailable()) {
2257
- return { events: [], relays: {}, incomplete: true, error: "relay list unavailable" };
2345
+ return { events: [], incomplete: true, error: "relay list unavailable" };
2258
2346
  }
2259
2347
  const strategy = options?.strategy ?? "auto";
2260
2348
  const authors = deriveAuthors(filters, options?.authors);
2261
2349
  const plan = await resolvePlan(ctx, authors, "read", strategy, options?.relays);
2262
2350
  if (plan.relays.length === 0) {
2263
- return { events: [], relays: {}, incomplete: true, error: "relay list unavailable" };
2351
+ return { events: [], incomplete: true, error: "relay list unavailable" };
2264
2352
  }
2265
2353
  const timeoutMs = options?.timeoutMs ?? ctx.defaultTimeoutMs;
2266
2354
  const collected = await collectFromRelays(ctx, filters, plan.relays, timeoutMs);
2267
2355
  const incomplete = collected.incomplete || (plan.missingAuthors?.length ?? 0) > 0;
2268
2356
  let events = collected.events;
2269
2357
  if (options?.limit !== void 0 && events.length > options.limit) {
2270
- events = [...events].sort((a, b) => b.created_at - a.created_at).slice(0, options.limit);
2358
+ events = [...events].sort((a, b) => b.event.created_at - a.event.created_at).slice(0, options.limit);
2271
2359
  }
2272
- const result = { events, relays: collected.relayMap };
2273
- if (incomplete) result.incomplete = true;
2274
- return result;
2360
+ const result2 = { events };
2361
+ if (incomplete) result2.incomplete = true;
2362
+ return result2;
2275
2363
  }
2276
2364
  async function getEventImpl(ctx, eventId, options) {
2277
2365
  if (typeof eventId !== "string" || eventId.length === 0) {
2278
- return { relays: [], error: "invalid filter" };
2366
+ return { error: "invalid filter" };
2279
2367
  }
2280
2368
  const filter = { ids: [eventId] };
2281
2369
  const queryOptions = { limit: 1 };
@@ -2287,15 +2375,13 @@ async function getEventImpl(ctx, eventId, options) {
2287
2375
  if (options?.strategy !== void 0) queryOptions.strategy = options.strategy;
2288
2376
  if (options?.timeoutMs !== void 0) queryOptions.timeoutMs = options.timeoutMs;
2289
2377
  const queryResult = await queryImpl(ctx, [filter], queryOptions);
2290
- const event = queryResult.events.find((candidate) => candidate.id === eventId);
2291
- const result = {
2292
- relays: event ? queryResult.relays[eventId] ?? [] : []
2293
- };
2294
- if (event) result.event = event;
2295
- if (!event) result.error = queryResult.error ?? "not found";
2296
- else if (queryResult.error !== void 0) result.error = queryResult.error;
2297
- if (queryResult.incomplete !== void 0) result.incomplete = queryResult.incomplete;
2298
- return result;
2378
+ const eventResult = queryResult.events.find((candidate) => candidate.event.id === eventId);
2379
+ const result2 = {};
2380
+ if (eventResult) result2.result = eventResult;
2381
+ if (!eventResult) result2.error = queryResult.error ?? "not found";
2382
+ else if (queryResult.error !== void 0) result2.error = queryResult.error;
2383
+ if (queryResult.incomplete !== void 0) result2.incomplete = queryResult.incomplete;
2384
+ return result2;
2299
2385
  }
2300
2386
  function closeLiveSub(sub) {
2301
2387
  for (const handle of sub.handles) {
@@ -2313,7 +2399,6 @@ function attachLiveRelay(ctx, sub, filters, relayUrl, live, sink) {
2313
2399
  sub.eoseCount += 1;
2314
2400
  if (!sub.eoseSent && sub.eoseCount >= sub.relayCount) {
2315
2401
  sub.eoseSent = true;
2316
- sink.eose();
2317
2402
  if (!live) {
2318
2403
  sub.closed = true;
2319
2404
  closeLiveSub(sub);
@@ -2326,7 +2411,7 @@ function attachLiveRelay(ctx, sub, filters, relayUrl, live, sink) {
2326
2411
  void ctx.verify(item).then((ok) => {
2327
2412
  if (!ok || sub.closed || sub.seen.has(item.id)) return;
2328
2413
  sub.seen.add(item.id);
2329
- sink.event(item, relayUrl);
2414
+ sink.event(createRelayEventResultWithHints3(item, [relayUrl]));
2330
2415
  });
2331
2416
  }));
2332
2417
  }
@@ -2384,9 +2469,9 @@ async function publishImpl(ctx, template, options) {
2384
2469
  return { ok: false, event: signed, eventId: signed.id, error: err2 instanceof Error ? err2.message : "publish failed" };
2385
2470
  }
2386
2471
  const ok = Object.values(relays).some(Boolean);
2387
- const result = { ok, event: signed, eventId: signed.id, relays };
2388
- if (!ok) result.error = "publish denied";
2389
- return result;
2472
+ const result2 = { ok, event: signed, eventId: signed.id, relays };
2473
+ if (!ok) result2.error = "publish denied";
2474
+ return result2;
2390
2475
  }
2391
2476
  function createRelayPoolOutboxRouter(options) {
2392
2477
  if (!options || typeof options.relayPool !== "object" || options.relayPool === null) {
@@ -2496,8 +2581,8 @@ function createUploadService(options) {
2496
2581
  send({ type: "upload.status.changed", status: stamped });
2497
2582
  }
2498
2583
  };
2499
- void uploader.upload(request, ctx).then((result) => {
2500
- const stamped = { ...result, uploadId };
2584
+ void uploader.upload(request, ctx).then((result2) => {
2585
+ const stamped = { ...result2, uploadId };
2501
2586
  const entry = entries.get(key);
2502
2587
  if (entry) entry.status = { ...stamped, updatedAt: now() };
2503
2588
  send({ type: "upload.upload.result", id, result: stamped });
@@ -2634,7 +2719,7 @@ async function uploadNip96(args) {
2634
2719
  function fromNip94Tags(uploadId, rail, tags, fallbackSize, fallbackSha) {
2635
2720
  const get = (name) => tags.find((t) => t[0] === name)?.[1];
2636
2721
  const url = get("url");
2637
- const result = {
2722
+ const result2 = {
2638
2723
  ok: Boolean(url),
2639
2724
  uploadId,
2640
2725
  status: url ? "complete" : "failed",
@@ -2642,19 +2727,19 @@ function fromNip94Tags(uploadId, rail, tags, fallbackSize, fallbackSha) {
2642
2727
  sha256: get("x") ?? fallbackSha,
2643
2728
  nip94: tags
2644
2729
  };
2645
- if (url) result.url = url;
2730
+ if (url) result2.url = url;
2646
2731
  const ox = get("ox");
2647
- if (ox) result.originalSha256 = ox;
2732
+ if (ox) result2.originalSha256 = ox;
2648
2733
  const size = get("size");
2649
- result.size = size ? Number(size) : fallbackSize;
2734
+ result2.size = size ? Number(size) : fallbackSize;
2650
2735
  const m = get("m");
2651
- if (m) result.mimeType = m;
2736
+ if (m) result2.mimeType = m;
2652
2737
  const dim = parseDimensions(get("dim"));
2653
- if (dim) result.dimensions = dim;
2738
+ if (dim) result2.dimensions = dim;
2654
2739
  const blurhash = get("blurhash");
2655
- if (blurhash) result.blurhash = blurhash;
2656
- if (!url) result.error = "server returned no url";
2657
- return result;
2740
+ if (blurhash) result2.blurhash = blurhash;
2741
+ if (!url) result2.error = "server returned no url";
2742
+ return result2;
2658
2743
  }
2659
2744
  async function uploadBlossom(args) {
2660
2745
  const { request, ctx, server, bytes, sha256, signEvent, fetchFn, nowS } = args;
@@ -2683,7 +2768,7 @@ async function uploadBlossom(args) {
2683
2768
  if (!blob.url) {
2684
2769
  return failed(ctx.uploadId, "blossom", "server returned no url", sha256);
2685
2770
  }
2686
- const result = {
2771
+ const result2 = {
2687
2772
  ok: true,
2688
2773
  uploadId: ctx.uploadId,
2689
2774
  status: "complete",
@@ -2692,8 +2777,8 @@ async function uploadBlossom(args) {
2692
2777
  sha256: blob.sha256 ?? sha256,
2693
2778
  size: blob.size ?? bytes.byteLength
2694
2779
  };
2695
- if (blob.type) result.mimeType = blob.type;
2696
- return result;
2780
+ if (blob.type) result2.mimeType = blob.type;
2781
+ return result2;
2697
2782
  }
2698
2783
  function failed(uploadId, rail, error, sha256) {
2699
2784
  return { ok: false, uploadId, status: "failed", rail, error, ...sha256 ? { sha256 } : {} };
@@ -2781,7 +2866,7 @@ function createIntentService(options) {
2781
2866
  send,
2782
2867
  "intent.invoke.result",
2783
2868
  id,
2784
- (result) => ({ type: "intent.invoke.result", id, result })
2869
+ (result2) => ({ type: "intent.invoke.result", id, result: result2 })
2785
2870
  );
2786
2871
  }
2787
2872
  function handleAvailable(msg, send) {
@@ -3111,12 +3196,12 @@ async function handleOpen(options, windowId, message, send) {
3111
3196
  return;
3112
3197
  }
3113
3198
  try {
3114
- const result = await options.open({ windowId, url: parsed, options: message.options });
3199
+ const result2 = await options.open({ windowId, url: parsed, options: message.options });
3115
3200
  send({
3116
3201
  type: "link.open.result",
3117
3202
  id: message.id,
3118
- status: result.status,
3119
- ...result.status === "denied" ? { error: "blocked-by-policy" } : {}
3203
+ status: result2.status,
3204
+ ...result2.status === "denied" ? { error: "blocked-by-policy" } : {}
3120
3205
  });
3121
3206
  } catch {
3122
3207
  send(denied(message.id, "blocked-by-policy"));
@@ -3188,7 +3273,7 @@ function settleMutation(hook, message, context, send, resultType) {
3188
3273
  () => hook(message.list, message.items, message.options, context),
3189
3274
  send,
3190
3275
  (error) => ({ type: resultType, id: message.id, ok: false, error: "list-unavailable", reason: error }),
3191
- (result) => ({ type: resultType, id: message.id, ...result })
3276
+ (result2) => ({ type: resultType, id: message.id, ...result2 })
3192
3277
  );
3193
3278
  }
3194
3279
  function createListsService(options = {}) {
@@ -3274,7 +3359,7 @@ function createSerialService(options = {}) {
3274
3359
  () => options.open(serialMessage.request, context),
3275
3360
  send,
3276
3361
  (error) => ({ type: "serial.open.result", id, error }),
3277
- (result) => ({ type: "serial.open.result", id, session: result.session })
3362
+ (result2) => ({ type: "serial.open.result", id, session: result2.session })
3278
3363
  );
3279
3364
  return;
3280
3365
  }
@@ -3371,7 +3456,7 @@ function createBleService(options = {}) {
3371
3456
  () => options.open(bleMessage.request, context),
3372
3457
  send,
3373
3458
  (error) => ({ type: "ble.open.result", id, error }),
3374
- (result) => ({ type: "ble.open.result", id, session: result.session })
3459
+ (result2) => ({ type: "ble.open.result", id, session: result2.session })
3375
3460
  );
3376
3461
  return;
3377
3462
  }
@@ -3524,7 +3609,7 @@ function createWebrtcService(options = {}) {
3524
3609
  () => options.open(webrtcMessage.request, context),
3525
3610
  send,
3526
3611
  (error) => ({ type: "webrtc.open.result", id, error }),
3527
- (result) => ({ type: "webrtc.open.result", id, session: result.session })
3612
+ (result2) => ({ type: "webrtc.open.result", id, session: result2.session })
3528
3613
  );
3529
3614
  return;
3530
3615
  }
@@ -3675,7 +3760,7 @@ function decodeNrelay(value) {
3675
3760
  function convertBits(data, fromBits, toBits, pad) {
3676
3761
  let acc = 0;
3677
3762
  let bits = 0;
3678
- const result = [];
3763
+ const result2 = [];
3679
3764
  const maxv = (1 << toBits) - 1;
3680
3765
  const maxAcc = (1 << fromBits + toBits - 1) - 1;
3681
3766
  for (const value of data) {
@@ -3684,15 +3769,15 @@ function convertBits(data, fromBits, toBits, pad) {
3684
3769
  bits += fromBits;
3685
3770
  while (bits >= toBits) {
3686
3771
  bits -= toBits;
3687
- result.push(acc >> bits & maxv);
3772
+ result2.push(acc >> bits & maxv);
3688
3773
  }
3689
3774
  }
3690
3775
  if (pad) {
3691
- if (bits > 0) result.push(acc << toBits - bits & maxv);
3776
+ if (bits > 0) result2.push(acc << toBits - bits & maxv);
3692
3777
  } else if (bits >= fromBits || (acc << toBits - bits & maxv) !== 0) {
3693
3778
  throw new Error("invalid bech32 padding");
3694
3779
  }
3695
- return result;
3780
+ return result2;
3696
3781
  }
3697
3782
  function settle5(call, send, okFalse, onValue) {
3698
3783
  let pending;
@@ -3712,14 +3797,14 @@ function createCommonService(options = {}) {
3712
3797
  const context = { windowId };
3713
3798
  if (message.type === "common.encodeNip19") {
3714
3799
  const input = message.input;
3715
- const result = input ? encodeNip19(input) : { ok: false, error: "invalid input" };
3716
- send({ type: "common.encodeNip19.result", id, ...result });
3800
+ const result2 = input ? encodeNip19(input) : { ok: false, error: "invalid input" };
3801
+ send({ type: "common.encodeNip19.result", id, ...result2 });
3717
3802
  return;
3718
3803
  }
3719
3804
  if (message.type === "common.decodeNip19") {
3720
3805
  const value = message.value;
3721
- const result = typeof value === "string" ? decodeNip19Value(value) : { ok: false, error: "invalid value" };
3722
- send({ type: "common.decodeNip19.result", id, ...result });
3806
+ const result2 = typeof value === "string" ? decodeNip19Value(value) : { ok: false, error: "invalid value" };
3807
+ send({ type: "common.decodeNip19.result", id, ...result2 });
3723
3808
  return;
3724
3809
  }
3725
3810
  if (message.type === "common.getProfile") {
@@ -3732,7 +3817,7 @@ function createCommonService(options = {}) {
3732
3817
  () => options.getProfile(target, context),
3733
3818
  send,
3734
3819
  (error) => ({ type: "common.getProfile.result", id, ok: false, pubkey: target ?? "", error }),
3735
- (result) => ({ type: "common.getProfile.result", id, ...result })
3820
+ (result2) => ({ type: "common.getProfile.result", id, ...result2 })
3736
3821
  );
3737
3822
  return;
3738
3823
  }
@@ -3745,7 +3830,7 @@ function createCommonService(options = {}) {
3745
3830
  () => options.follows(context),
3746
3831
  send,
3747
3832
  (error) => ({ type: "common.follows.result", id, ok: false, pubkeys: [], error }),
3748
- (result) => ({ type: "common.follows.result", id, ...result })
3833
+ (result2) => ({ type: "common.follows.result", id, ...result2 })
3749
3834
  );
3750
3835
  return;
3751
3836
  }
@@ -3769,7 +3854,7 @@ function createCommonService(options = {}) {
3769
3854
  () => options.react(m.targetEventId, m.reaction, m.customEmojiHref, context),
3770
3855
  send,
3771
3856
  (error) => ({ type: "common.react.result", id, ok: false, error }),
3772
- (result) => ({ type: "common.react.result", id, ...result })
3857
+ (result2) => ({ type: "common.react.result", id, ...result2 })
3773
3858
  );
3774
3859
  return;
3775
3860
  }
@@ -3783,7 +3868,7 @@ function createCommonService(options = {}) {
3783
3868
  () => options.report(m.target, m.reason, m.text, context),
3784
3869
  send,
3785
3870
  (error) => ({ type: "common.report.result", id, ok: false, error }),
3786
- (result) => ({ type: "common.report.result", id, ...result })
3871
+ (result2) => ({ type: "common.report.result", id, ...result2 })
3787
3872
  );
3788
3873
  return;
3789
3874
  }
@@ -3806,7 +3891,7 @@ function settleAction(action, pubkeys, context, send, resultType, id, unavailabl
3806
3891
  () => action(pubkeys, context),
3807
3892
  send,
3808
3893
  (error) => ({ type: resultType, id, ok: false, error }),
3809
- (result) => ({ type: resultType, id, ...result })
3894
+ (result2) => ({ type: resultType, id, ...result2 })
3810
3895
  );
3811
3896
  }
3812
3897
 
@@ -3861,7 +3946,7 @@ function createDmService(options) {
3861
3946
  );
3862
3947
  return;
3863
3948
  case "dm.send":
3864
- void adapter.send(message).then((result) => send({ type: "dm.send.result", id: requestId, ...result })).catch((error) => send({ type: "dm.send.result", id: requestId, error: err(error) }));
3949
+ void adapter.send(message).then((result2) => send({ type: "dm.send.result", id: requestId, ...result2 })).catch((error) => send({ type: "dm.send.result", id: requestId, error: err(error) }));
3865
3950
  return;
3866
3951
  case "dm.subscribe": {
3867
3952
  let activeSubscriptionId = "";
@@ -4463,6 +4548,7 @@ export {
4463
4548
  createCoordinatedRelay,
4464
4549
  createCordnDmAdapter,
4465
4550
  createCordnRelayCoordinatorClient,
4551
+ createCountService,
4466
4552
  createCvmService,
4467
4553
  createDmService,
4468
4554
  createHttpUploader,