@kehto/services 0.14.1 → 0.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +9 -35
- package/dist/index.js +109 -79
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ServiceHandler, Signer } from '@kehto/runtime';
|
|
1
|
+
import { ServiceHandler, Signer, RelayEventResult } from '@kehto/runtime';
|
|
2
2
|
import { IdentityGetProfileMessage, IdentityGetProfileResultMessage, IdentityGetFollowsMessage, IdentityGetFollowsResultMessage, IdentityGetListMessage, IdentityGetListResultMessage, IdentityGetZapsMessage, IdentityGetZapsResultMessage, IdentityGetMutesMessage, IdentityGetMutesResultMessage, IdentityGetBlockedMessage, IdentityGetBlockedResultMessage, IdentityGetBadgesMessage, IdentityGetBadgesResultMessage } from '@napplet/nap/identity/types';
|
|
3
3
|
import { NostrFilter, NostrEvent, EventTemplate, LinkOpenOptions, LinkOpenResult, ListSupport, ListRef, ListItem, ListOptions, ListMutationResult, SerialOpenRequest, SerialOpenResult, BleEvent, BleOpenRequest, BleOpenResult, BleService, BleAttribute, BleWriteOptions, WebrtcEvent, WebrtcOpenRequest, WebrtcOpenResult, CommonProfileTarget, CommonProfileResult, CommonFollowsResult, CommonActionResult, CommonReaction, CommonReportTarget, CommonReportReason } from '@napplet/core';
|
|
4
4
|
import { MediaMetadata, MediaAction } from '@napplet/nap/media/types';
|
|
@@ -1635,7 +1635,7 @@ declare function createResourceService(options: ResourceServiceOptions): Resourc
|
|
|
1635
1635
|
* Inbound: outbox.getEvent, outbox.query, outbox.subscribe, outbox.close,
|
|
1636
1636
|
* outbox.publish, outbox.resolveRelays
|
|
1637
1637
|
* Outbound: outbox.getEvent.result, outbox.query.result, outbox.event,
|
|
1638
|
-
* outbox.
|
|
1638
|
+
* outbox.closed, outbox.publish.result,
|
|
1639
1639
|
* outbox.resolveRelays.result
|
|
1640
1640
|
*
|
|
1641
1641
|
* The shell owns relay discovery, routing, fallback, deduplication, signature
|
|
@@ -1653,21 +1653,12 @@ declare function createResourceService(options: ResourceServiceOptions): Resourc
|
|
|
1653
1653
|
* @packageDocumentation
|
|
1654
1654
|
*/
|
|
1655
1655
|
|
|
1656
|
-
/**
|
|
1657
|
-
* Relay-selection strategy:
|
|
1658
|
-
* - `outbox` — query/publish via author write relays (the outbox model)
|
|
1659
|
-
* - `inbox` — query/publish via recipient read relays (the inbox model)
|
|
1660
|
-
* - `auto` — let the shell choose per its policy and relay intelligence
|
|
1661
|
-
*/
|
|
1662
|
-
type OutboxStrategy = 'outbox' | 'inbox' | 'auto';
|
|
1663
1656
|
/** Options for a single-event outbox lookup. */
|
|
1664
1657
|
interface OutboxEventOptions {
|
|
1665
1658
|
/** Author hint for routing through the author's outbox relays. */
|
|
1666
1659
|
author?: string;
|
|
1667
1660
|
/** Relay hints; treated as a hint subject to shell validation, not a bypass. */
|
|
1668
1661
|
relays?: string[];
|
|
1669
|
-
/** Relay-selection strategy. */
|
|
1670
|
-
strategy?: OutboxStrategy;
|
|
1671
1662
|
/** Wall-clock budget for the lookup, in milliseconds. */
|
|
1672
1663
|
timeoutMs?: number;
|
|
1673
1664
|
}
|
|
@@ -1677,8 +1668,6 @@ interface OutboxQueryOptions {
|
|
|
1677
1668
|
authors?: string[];
|
|
1678
1669
|
/** Relay hints; treated as a hint subject to shell validation, not a bypass. */
|
|
1679
1670
|
relays?: string[];
|
|
1680
|
-
/** Relay-selection strategy. */
|
|
1681
|
-
strategy?: OutboxStrategy;
|
|
1682
1671
|
/** Maximum events to collect. */
|
|
1683
1672
|
limit?: number;
|
|
1684
1673
|
/** Wall-clock budget for the query, in milliseconds. */
|
|
@@ -1686,8 +1675,6 @@ interface OutboxQueryOptions {
|
|
|
1686
1675
|
}
|
|
1687
1676
|
/** Options for a live outbox subscription. */
|
|
1688
1677
|
interface OutboxSubscribeOptions extends OutboxQueryOptions {
|
|
1689
|
-
/** Keep the subscription open for real-time events after EOSE. */
|
|
1690
|
-
live?: boolean;
|
|
1691
1678
|
}
|
|
1692
1679
|
/** Options for an outbox publish. */
|
|
1693
1680
|
interface OutboxPublishOptions {
|
|
@@ -1695,8 +1682,6 @@ interface OutboxPublishOptions {
|
|
|
1695
1682
|
relays?: string[];
|
|
1696
1683
|
/** Recipient authors whose inbox relays should be included for directed events. */
|
|
1697
1684
|
targetAuthors?: string[];
|
|
1698
|
-
/** Relay-selection strategy. */
|
|
1699
|
-
strategy?: OutboxStrategy;
|
|
1700
1685
|
}
|
|
1701
1686
|
/** A read/write target for relay-plan resolution. */
|
|
1702
1687
|
interface OutboxTarget {
|
|
@@ -1706,8 +1691,6 @@ interface OutboxTarget {
|
|
|
1706
1691
|
pubkey?: string;
|
|
1707
1692
|
/** Whether the plan is for reading (their write relays) or writing (their read relays). */
|
|
1708
1693
|
direction?: 'read' | 'write';
|
|
1709
|
-
/** Relay-selection strategy. */
|
|
1710
|
-
strategy?: OutboxStrategy;
|
|
1711
1694
|
}
|
|
1712
1695
|
/** The relay plan the shell would use for a target. */
|
|
1713
1696
|
interface OutboxRelayPlan {
|
|
@@ -1720,10 +1703,8 @@ interface OutboxRelayPlan {
|
|
|
1720
1703
|
}
|
|
1721
1704
|
/** Outcome of a single-event outbox lookup. */
|
|
1722
1705
|
interface OutboxEventResult {
|
|
1723
|
-
/** The signature-validated event matching the requested event id, when found. */
|
|
1724
|
-
|
|
1725
|
-
/** Relay URLs where the shell observed the event. */
|
|
1726
|
-
relays: string[];
|
|
1706
|
+
/** The signature-validated event result matching the requested event id, when found. */
|
|
1707
|
+
result?: RelayEventResult;
|
|
1727
1708
|
/** True when some relay lists or connections failed and the lookup was partial. */
|
|
1728
1709
|
incomplete?: boolean;
|
|
1729
1710
|
/** Error reason when the lookup could not complete or did not find the event. */
|
|
@@ -1731,10 +1712,8 @@ interface OutboxEventResult {
|
|
|
1731
1712
|
}
|
|
1732
1713
|
/** Outcome of an outbox query, as returned by the {@link OutboxRouter}. */
|
|
1733
1714
|
interface OutboxResult {
|
|
1734
|
-
/** Deduplicated, signature-validated
|
|
1735
|
-
events:
|
|
1736
|
-
/** Map of event id -> relay URLs where the shell observed the event. */
|
|
1737
|
-
relays: Record<string, string[]>;
|
|
1715
|
+
/** Deduplicated, signature-validated event results. */
|
|
1716
|
+
events: RelayEventResult[];
|
|
1738
1717
|
/** True when some relay lists or connections failed and results are partial. */
|
|
1739
1718
|
incomplete?: boolean;
|
|
1740
1719
|
/** Error reason when the query could not complete. */
|
|
@@ -1755,10 +1734,8 @@ interface OutboxPublishResult {
|
|
|
1755
1734
|
}
|
|
1756
1735
|
/** Sink an {@link OutboxRouter} streams subscription lifecycle through. */
|
|
1757
1736
|
interface OutboxSubscriptionSink {
|
|
1758
|
-
/** Deliver a matching event
|
|
1759
|
-
event(
|
|
1760
|
-
/** Signal end-of-stored-events. */
|
|
1761
|
-
eose(): void;
|
|
1737
|
+
/** Deliver a matching event result. */
|
|
1738
|
+
event(result: RelayEventResult): void;
|
|
1762
1739
|
/** Signal that the subscription was closed upstream; `reason` is optional. */
|
|
1763
1740
|
closed(reason?: string): void;
|
|
1764
1741
|
}
|
|
@@ -1818,9 +1795,6 @@ declare function createOutboxService(options: OutboxServiceOptions): ServiceHand
|
|
|
1818
1795
|
* - reading an author's events → their **write** relays (where they publish)
|
|
1819
1796
|
* - writing to reach an author → their **read** relays (their inbox)
|
|
1820
1797
|
*
|
|
1821
|
-
* `strategy` overrides the direction default: `outbox` forces write relays,
|
|
1822
|
-
* `inbox` forces read relays, `auto` (default) follows the read/write direction.
|
|
1823
|
-
*
|
|
1824
1798
|
* @example
|
|
1825
1799
|
* ```ts
|
|
1826
1800
|
* import { createOutboxService, createRelayPoolOutboxRouter } from '@kehto/services';
|
|
@@ -3027,4 +3001,4 @@ declare function createCordnRelayCoordinatorClient(options: CordnRelayCoordinato
|
|
|
3027
3001
|
/** Create a Cordn/ContextVM-backed NAP-DM adapter. */
|
|
3028
3002
|
declare function createCordnDmAdapter(options: CordnDmAdapterOptions): DmAdapter;
|
|
3029
3003
|
|
|
3030
|
-
export { type AudioServiceOptions, type AudioSource, type BleServiceContext, type BleServiceOptions, type CacheServiceOptions, type CatalogIntentResolver, type CatalogIntentResolverOptions, type CommonServiceContext, type CommonServiceOptions, type ConfigSchemaValidation, type ConfigService, type ConfigServiceOptions, type CoordinatedRelayOptions, type CordnCodecResult, type CordnCoordinatorClient, type CordnCoordinatorSubscription, type CordnDmAdapterOptions, type CordnDmClient, type CordnGroupMessage, type CordnRelayCoordinatorOptions, type CountRequest, type CountResult, type CountServiceOptions, type DmAdapter, type DmConversation, type DmConversationPage, type DmConversationQuery, type DmHexPubkey, DmMemoryStore, type DmMessage, type DmMessagePage, type DmMessageQuery, type DmMessageStatus, type DmOk, type DmPeer, type DmRelayPool, type DmSendRequest, type DmSendResult, type DmService, type DmServiceOptions, type DmStatus, type DmSubscribeRequest, type DmSubscription, type DmTimestamp, type HostCacheBridge, type HostKeyEvent, type HostKeysBridge, type HostMediaBridge, type HttpUploaderOptions, type HttpUploaderRails, type IdentityServiceOptions, type IntentArchetypeSupport, type IntentAvailability, type IntentBehavior, type IntentCandidate, type IntentCatalogEntry, type IntentHandlerPreference, type IntentOpenParams, type IntentRequest, type IntentResolver, type IntentResolverContext, type IntentResult, type IntentServiceOptions, type IntentWindowController, type KeysServiceOptions, type LinkOpenContext, type LinkServiceOptions, type ListsServiceContext, type ListsServiceOptions, type ManifestArchetypeInput, type MaybePromise, type MediaMetadataLike, type MediaPlaybackOwner, type MediaServiceOptions, type MediaSessionCreateOptions, type MediaSessionTarget, type MediaSourceRef, type NdrDmAdapterOptions, type NdrRelayTransport, type NdrRelayTransportOptions, type NdrRumorLike, type NdrRuntimeLike, type Nip17DmAdapterOptions, type NostrTag, type Notification, type NotificationServiceOptions, type NotifyServiceOptions, type OutboxEventOptions, type OutboxEventResult, type OutboxPublishOptions, type OutboxPublishResult, type OutboxQueryOptions, type OutboxRelayPlan, type OutboxRelayPool, type OutboxResult, type OutboxRouter, type OutboxRouterSubscription, type OutboxServiceOptions, type
|
|
3004
|
+
export { type AudioServiceOptions, type AudioSource, type BleServiceContext, type BleServiceOptions, type CacheServiceOptions, type CatalogIntentResolver, type CatalogIntentResolverOptions, type CommonServiceContext, type CommonServiceOptions, type ConfigSchemaValidation, type ConfigService, type ConfigServiceOptions, type CoordinatedRelayOptions, type CordnCodecResult, type CordnCoordinatorClient, type CordnCoordinatorSubscription, type CordnDmAdapterOptions, type CordnDmClient, type CordnGroupMessage, type CordnRelayCoordinatorOptions, type CountRequest, type CountResult, type CountServiceOptions, type DmAdapter, type DmConversation, type DmConversationPage, type DmConversationQuery, type DmHexPubkey, DmMemoryStore, type DmMessage, type DmMessagePage, type DmMessageQuery, type DmMessageStatus, type DmOk, type DmPeer, type DmRelayPool, type DmSendRequest, type DmSendResult, type DmService, type DmServiceOptions, type DmStatus, type DmSubscribeRequest, type DmSubscription, type DmTimestamp, type HostCacheBridge, type HostKeyEvent, type HostKeysBridge, type HostMediaBridge, type HttpUploaderOptions, type HttpUploaderRails, type IdentityServiceOptions, type IntentArchetypeSupport, type IntentAvailability, type IntentBehavior, type IntentCandidate, type IntentCatalogEntry, type IntentHandlerPreference, type IntentOpenParams, type IntentRequest, type IntentResolver, type IntentResolverContext, type IntentResult, type IntentServiceOptions, type IntentWindowController, type KeysServiceOptions, type LinkOpenContext, type LinkServiceOptions, type ListsServiceContext, type ListsServiceOptions, type ManifestArchetypeInput, type MaybePromise, type MediaMetadataLike, type MediaPlaybackOwner, type MediaServiceOptions, type MediaSessionCreateOptions, type MediaSessionTarget, type MediaSourceRef, type NdrDmAdapterOptions, type NdrRelayTransport, type NdrRelayTransportOptions, type NdrRumorLike, type NdrRuntimeLike, type Nip17DmAdapterOptions, type NostrTag, type Notification, type NotificationServiceOptions, type NotifyServiceOptions, type OutboxEventOptions, type OutboxEventResult, type OutboxPublishOptions, type OutboxPublishResult, type OutboxQueryOptions, type OutboxRelayPlan, type OutboxRelayPool, type OutboxResult, type OutboxRouter, type OutboxRouterSubscription, type OutboxServiceOptions, type OutboxSubscribeOptions, type OutboxSubscriptionSink, type OutboxTarget, type RailServerConfig, type RelayListEntry, type RelayPoolOutboxRouterOptions, type RelayPoolServiceOptions, type ResourceInfo, type ResourceInfoContext, type ResourceInfoProvider, type ResourceSchemeInfo, type ResourceService, type ResourceServiceOptions, type SerialServiceContext, type SerialServiceOptions, type SignEvent, type ThemeService, type ThemeServiceOptions, type UploadDimensions, type UploadInfo, type UploadInfoContext, type UploadInfoProvider, type UploadRail, type UploadRailInfo, type UploadRequest, type UploadResult, type UploadServiceOptions, type UploadState, type UploadStatus, type Uploader, type UploaderContext, type WebrtcServiceContext, type WebrtcServiceOptions, createAudioService, createBleService, createBrowserMediaBridge, createCacheService, createCatalogIntentResolver, createCommonService, createConfigService, createCoordinatedRelay, createCordnDmAdapter, createCordnRelayCoordinatorClient, createCountService, createDmService, createHttpUploader, createIdentityService, createIntentService, createKeysService, createLinkService, createListsService, createMediaService, createNdrDmAdapter, createNdrRelayTransport, createNip17DmAdapter, createNotificationService, createNotifyService, createOutboxService, createRelayPoolOutboxRouter, createRelayPoolService, createResourceService, createSerialService, createThemeService, createUploadService, createWebrtcService, manifestToIntentCatalogEntry };
|
package/dist/index.js
CHANGED
|
@@ -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,
|
|
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(() => {
|
|
@@ -647,6 +649,7 @@ function isPlainObject(value) {
|
|
|
647
649
|
}
|
|
648
650
|
|
|
649
651
|
// src/coordinated-relay.ts
|
|
652
|
+
import { createRelayEventResult as createRelayEventResult2, createRelayEventResultWithHints as createRelayEventResultWithHints2 } from "@kehto/runtime";
|
|
650
653
|
var DEFAULT_EOSE_TIMEOUT_MS = 15e3;
|
|
651
654
|
function createCoordinatedRelay(options) {
|
|
652
655
|
const timeoutMs = options.eoseTimeoutMs ?? DEFAULT_EOSE_TIMEOUT_MS;
|
|
@@ -669,10 +672,13 @@ function createCoordinatedRelay(options) {
|
|
|
669
672
|
handleMessage(windowId, message, send) {
|
|
670
673
|
const relayMessage = message;
|
|
671
674
|
if (message.type === "relay.subscribe") {
|
|
672
|
-
let deliver2 = function(event) {
|
|
675
|
+
let deliver2 = function(event, relayHints) {
|
|
673
676
|
if (tracked.seenIds.has(event.id)) return;
|
|
674
677
|
tracked.seenIds.add(event.id);
|
|
675
|
-
if (subs.has(subKey))
|
|
678
|
+
if (subs.has(subKey)) {
|
|
679
|
+
const result2 = relayHints ? createRelayEventResultWithHints2(event, relayHints) : createRelayEventResult2(event);
|
|
680
|
+
send({ type: "relay.event", subId, result: result2 });
|
|
681
|
+
}
|
|
676
682
|
};
|
|
677
683
|
var deliver = deliver2;
|
|
678
684
|
const subId = relayMessage.subId;
|
|
@@ -728,7 +734,7 @@ function createCoordinatedRelay(options) {
|
|
|
728
734
|
maybeSendEose(subKey, subId, send);
|
|
729
735
|
return;
|
|
730
736
|
}
|
|
731
|
-
deliver2(item);
|
|
737
|
+
deliver2(item, relayUrls2);
|
|
732
738
|
if (cacheAvailable) {
|
|
733
739
|
try {
|
|
734
740
|
options.cache.store(item);
|
|
@@ -2024,6 +2030,59 @@ var OUTBOX_DESCRIPTOR = {
|
|
|
2024
2030
|
version: OUTBOX_SERVICE_VERSION,
|
|
2025
2031
|
description: "NAP-OUTBOX outbox-aware relay routing \u2014 getEvent/query/subscribe/publish/resolveRelays"
|
|
2026
2032
|
};
|
|
2033
|
+
function isRecord(value) {
|
|
2034
|
+
return typeof value === "object" && value !== null;
|
|
2035
|
+
}
|
|
2036
|
+
function stringArray(value) {
|
|
2037
|
+
if (!Array.isArray(value)) return void 0;
|
|
2038
|
+
const strings = value.filter((item) => typeof item === "string");
|
|
2039
|
+
return strings.length > 0 ? strings : void 0;
|
|
2040
|
+
}
|
|
2041
|
+
function uint(value) {
|
|
2042
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : void 0;
|
|
2043
|
+
}
|
|
2044
|
+
function sanitizeEventOptions(raw) {
|
|
2045
|
+
if (!isRecord(raw)) return void 0;
|
|
2046
|
+
const out = {};
|
|
2047
|
+
if (typeof raw.author === "string") out.author = raw.author;
|
|
2048
|
+
const relays = stringArray(raw.relays);
|
|
2049
|
+
if (relays) out.relays = relays;
|
|
2050
|
+
const timeoutMs = uint(raw.timeoutMs);
|
|
2051
|
+
if (timeoutMs !== void 0) out.timeoutMs = timeoutMs;
|
|
2052
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
2053
|
+
}
|
|
2054
|
+
function sanitizeQueryOptions(raw) {
|
|
2055
|
+
if (!isRecord(raw)) return void 0;
|
|
2056
|
+
const out = {};
|
|
2057
|
+
const authors = stringArray(raw.authors);
|
|
2058
|
+
if (authors) out.authors = authors;
|
|
2059
|
+
const relays = stringArray(raw.relays);
|
|
2060
|
+
if (relays) out.relays = relays;
|
|
2061
|
+
const limit = uint(raw.limit);
|
|
2062
|
+
if (limit !== void 0) out.limit = limit;
|
|
2063
|
+
const timeoutMs = uint(raw.timeoutMs);
|
|
2064
|
+
if (timeoutMs !== void 0) out.timeoutMs = timeoutMs;
|
|
2065
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
2066
|
+
}
|
|
2067
|
+
var sanitizeSubscribeOptions = sanitizeQueryOptions;
|
|
2068
|
+
function sanitizePublishOptions(raw) {
|
|
2069
|
+
if (!isRecord(raw)) return void 0;
|
|
2070
|
+
const out = {};
|
|
2071
|
+
const relays = stringArray(raw.relays);
|
|
2072
|
+
if (relays) out.relays = relays;
|
|
2073
|
+
const targetAuthors = stringArray(raw.targetAuthors);
|
|
2074
|
+
if (targetAuthors) out.targetAuthors = targetAuthors;
|
|
2075
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
2076
|
+
}
|
|
2077
|
+
function sanitizeTarget(raw) {
|
|
2078
|
+
if (!isRecord(raw)) return void 0;
|
|
2079
|
+
const out = {};
|
|
2080
|
+
const authors = stringArray(raw.authors);
|
|
2081
|
+
if (authors) out.authors = authors;
|
|
2082
|
+
if (typeof raw.pubkey === "string") out.pubkey = raw.pubkey;
|
|
2083
|
+
if (raw.direction === "read" || raw.direction === "write") out.direction = raw.direction;
|
|
2084
|
+
return out;
|
|
2085
|
+
}
|
|
2027
2086
|
function normalizeFilters(raw) {
|
|
2028
2087
|
if (Array.isArray(raw)) {
|
|
2029
2088
|
const filters = raw.filter((f) => typeof f === "object" && f !== null);
|
|
@@ -2040,17 +2099,14 @@ function buildEventQuery(eventId, eventOptions) {
|
|
|
2040
2099
|
queryOptions.authors = [eventOptions.author];
|
|
2041
2100
|
}
|
|
2042
2101
|
if (Array.isArray(eventOptions?.relays)) queryOptions.relays = eventOptions.relays;
|
|
2043
|
-
if (eventOptions?.strategy !== void 0) queryOptions.strategy = eventOptions.strategy;
|
|
2044
2102
|
if (eventOptions?.timeoutMs !== void 0) queryOptions.timeoutMs = eventOptions.timeoutMs;
|
|
2045
2103
|
return { filter, queryOptions };
|
|
2046
2104
|
}
|
|
2047
2105
|
function eventResultFromQuery(eventId, result2) {
|
|
2048
|
-
const
|
|
2049
|
-
const eventResult = {
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
if (event) eventResult.event = event;
|
|
2053
|
-
if (!event) eventResult.error = result2.error ?? "not found";
|
|
2106
|
+
const relayResult = result2.events.find((candidate) => candidate.event.id === eventId);
|
|
2107
|
+
const eventResult = {};
|
|
2108
|
+
if (relayResult) eventResult.result = relayResult;
|
|
2109
|
+
if (!relayResult) eventResult.error = result2.error ?? "not found";
|
|
2054
2110
|
else if (result2.error !== void 0) eventResult.error = result2.error;
|
|
2055
2111
|
if (result2.incomplete !== void 0) eventResult.incomplete = result2.incomplete;
|
|
2056
2112
|
return eventResult;
|
|
@@ -2060,15 +2116,14 @@ function fallbackGetEvent(router, eventId, eventOptions) {
|
|
|
2060
2116
|
return router.query([filter], queryOptions).then((result2) => eventResultFromQuery(eventId, result2));
|
|
2061
2117
|
}
|
|
2062
2118
|
function sendEventResult(id, eventId, result2, send) {
|
|
2063
|
-
if (result2.
|
|
2064
|
-
send({ type: "outbox.getEvent.result", id,
|
|
2119
|
+
if (result2.result && result2.result.event.id !== eventId) {
|
|
2120
|
+
send({ type: "outbox.getEvent.result", id, error: "not found" });
|
|
2065
2121
|
return;
|
|
2066
2122
|
}
|
|
2067
2123
|
send({
|
|
2068
2124
|
type: "outbox.getEvent.result",
|
|
2069
2125
|
id,
|
|
2070
|
-
...result2.
|
|
2071
|
-
relays: result2.relays,
|
|
2126
|
+
...result2.result === void 0 ? {} : { result: result2.result },
|
|
2072
2127
|
...result2.incomplete === void 0 ? {} : { incomplete: result2.incomplete },
|
|
2073
2128
|
...result2.error === void 0 ? {} : { error: result2.error }
|
|
2074
2129
|
});
|
|
@@ -2077,12 +2132,12 @@ function handleGetEvent(router, msg, send) {
|
|
|
2077
2132
|
const m = msg;
|
|
2078
2133
|
const id = m.id ?? "";
|
|
2079
2134
|
if (typeof m.eventId !== "string" || m.eventId.length === 0) {
|
|
2080
|
-
send({ type: "outbox.getEvent.result", id,
|
|
2135
|
+
send({ type: "outbox.getEvent.result", id, error: "invalid filter" });
|
|
2081
2136
|
return;
|
|
2082
2137
|
}
|
|
2083
2138
|
const getEvent = router.getEvent ?? ((eventId, eventOptions) => fallbackGetEvent(router, eventId, eventOptions));
|
|
2084
|
-
void getEvent(m.eventId, m.options).then((result2) => sendEventResult(id, m.eventId, result2, send)).catch(
|
|
2085
|
-
(err2) => send({ type: "outbox.getEvent.result", id,
|
|
2139
|
+
void getEvent(m.eventId, sanitizeEventOptions(m.options)).then((result2) => sendEventResult(id, m.eventId, result2, send)).catch(
|
|
2140
|
+
(err2) => send({ type: "outbox.getEvent.result", id, error: toErrorMessage(err2) })
|
|
2086
2141
|
);
|
|
2087
2142
|
}
|
|
2088
2143
|
function createOutboxService(options) {
|
|
@@ -2096,20 +2151,19 @@ function createOutboxService(options) {
|
|
|
2096
2151
|
const id = m.id ?? "";
|
|
2097
2152
|
const filters = normalizeFilters(m.filters);
|
|
2098
2153
|
if (!filters) {
|
|
2099
|
-
send({ type: "outbox.query.result", id, events: [],
|
|
2154
|
+
send({ type: "outbox.query.result", id, events: [], error: "invalid filter" });
|
|
2100
2155
|
return;
|
|
2101
2156
|
}
|
|
2102
|
-
void router.query(filters, m.options).then(
|
|
2157
|
+
void router.query(filters, sanitizeQueryOptions(m.options)).then(
|
|
2103
2158
|
(result2) => send({
|
|
2104
2159
|
type: "outbox.query.result",
|
|
2105
2160
|
id,
|
|
2106
2161
|
events: result2.events,
|
|
2107
|
-
relays: result2.relays,
|
|
2108
2162
|
...result2.incomplete === void 0 ? {} : { incomplete: result2.incomplete },
|
|
2109
2163
|
...result2.error === void 0 ? {} : { error: result2.error }
|
|
2110
2164
|
})
|
|
2111
2165
|
).catch(
|
|
2112
|
-
(err2) => send({ type: "outbox.query.result", id, events: [],
|
|
2166
|
+
(err2) => send({ type: "outbox.query.result", id, events: [], error: toErrorMessage(err2) })
|
|
2113
2167
|
);
|
|
2114
2168
|
}
|
|
2115
2169
|
function handleSubscribe(windowId, msg, send) {
|
|
@@ -2125,14 +2179,13 @@ function createOutboxService(options) {
|
|
|
2125
2179
|
return;
|
|
2126
2180
|
}
|
|
2127
2181
|
const sink = {
|
|
2128
|
-
event: (
|
|
2129
|
-
eose: () => send({ type: "outbox.eose", subId }),
|
|
2182
|
+
event: (result2) => send({ type: "outbox.event", subId, result: result2 }),
|
|
2130
2183
|
closed: (reason) => {
|
|
2131
2184
|
subscriptions.delete(subKey);
|
|
2132
2185
|
send({ type: "outbox.closed", subId, ...reason === void 0 ? {} : { reason } });
|
|
2133
2186
|
}
|
|
2134
2187
|
};
|
|
2135
|
-
subscriptions.set(subKey, router.subscribe(filters, m.options, sink));
|
|
2188
|
+
subscriptions.set(subKey, router.subscribe(filters, sanitizeSubscribeOptions(m.options), sink));
|
|
2136
2189
|
}
|
|
2137
2190
|
function handleClose(windowId, msg, send) {
|
|
2138
2191
|
const m = msg;
|
|
@@ -2150,7 +2203,7 @@ function createOutboxService(options) {
|
|
|
2150
2203
|
send({ type: "outbox.publish.result", id, ok: false, error: "invalid filter" });
|
|
2151
2204
|
return;
|
|
2152
2205
|
}
|
|
2153
|
-
void router.publish(m.event, m.options).then(
|
|
2206
|
+
void router.publish(m.event, sanitizePublishOptions(m.options)).then(
|
|
2154
2207
|
(result2) => send({
|
|
2155
2208
|
type: "outbox.publish.result",
|
|
2156
2209
|
id,
|
|
@@ -2167,11 +2220,12 @@ function createOutboxService(options) {
|
|
|
2167
2220
|
function handleResolveRelays(msg, send) {
|
|
2168
2221
|
const m = msg;
|
|
2169
2222
|
const id = m.id ?? "";
|
|
2170
|
-
|
|
2223
|
+
const target = sanitizeTarget(m.target);
|
|
2224
|
+
if (!target) {
|
|
2171
2225
|
send({ type: "outbox.resolveRelays.result", id, error: "invalid filter" });
|
|
2172
2226
|
return;
|
|
2173
2227
|
}
|
|
2174
|
-
void router.resolveRelays(
|
|
2228
|
+
void router.resolveRelays(target).then((plan) => send({ type: "outbox.resolveRelays.result", id, plan })).catch(
|
|
2175
2229
|
(err2) => send({ type: "outbox.resolveRelays.result", id, error: toErrorMessage(err2) })
|
|
2176
2230
|
);
|
|
2177
2231
|
}
|
|
@@ -2219,6 +2273,7 @@ function toErrorMessage(err2) {
|
|
|
2219
2273
|
}
|
|
2220
2274
|
|
|
2221
2275
|
// src/relay-pool-outbox-router.ts
|
|
2276
|
+
import { createRelayEventResultWithHints as createRelayEventResultWithHints3 } from "@kehto/runtime";
|
|
2222
2277
|
var DEFAULT_QUERY_TIMEOUT_MS = 4e3;
|
|
2223
2278
|
function defaultRelayAllowed(url) {
|
|
2224
2279
|
return typeof url === "string" && (url.startsWith("wss://") || url.startsWith("ws://"));
|
|
@@ -2231,11 +2286,6 @@ function deriveAuthors(filters, optionAuthors) {
|
|
|
2231
2286
|
for (const author of optionAuthors ?? []) authors.add(author);
|
|
2232
2287
|
return [...authors];
|
|
2233
2288
|
}
|
|
2234
|
-
function wantsWriteRelays(direction, strategy) {
|
|
2235
|
-
if (strategy === "outbox") return true;
|
|
2236
|
-
if (strategy === "inbox") return false;
|
|
2237
|
-
return direction === "read";
|
|
2238
|
-
}
|
|
2239
2289
|
function allowed(ctx, urls) {
|
|
2240
2290
|
const out = /* @__PURE__ */ new Set();
|
|
2241
2291
|
for (const url of urls) {
|
|
@@ -2243,8 +2293,8 @@ function allowed(ctx, urls) {
|
|
|
2243
2293
|
}
|
|
2244
2294
|
return [...out];
|
|
2245
2295
|
}
|
|
2246
|
-
async function resolvePlan(ctx, pubkeys, direction,
|
|
2247
|
-
const useWrite =
|
|
2296
|
+
async function resolvePlan(ctx, pubkeys, direction, relayHints) {
|
|
2297
|
+
const useWrite = direction === "read";
|
|
2248
2298
|
const collected = /* @__PURE__ */ new Set();
|
|
2249
2299
|
const missingAuthors = [];
|
|
2250
2300
|
let sawNip65 = false;
|
|
@@ -2292,10 +2342,10 @@ function admitEvent(ctx, collector, event) {
|
|
|
2292
2342
|
);
|
|
2293
2343
|
}
|
|
2294
2344
|
function buildCollectResult(collector, timedOut) {
|
|
2295
|
-
const events = [...collector.seen.values()]
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
return { events,
|
|
2345
|
+
const events = [...collector.seen.values()].map(
|
|
2346
|
+
(event) => createRelayEventResultWithHints3(event, [...collector.relayMap.get(event.id) ?? []])
|
|
2347
|
+
);
|
|
2348
|
+
return { events, incomplete: timedOut };
|
|
2299
2349
|
}
|
|
2300
2350
|
function collectFromRelays(ctx, filters, relayUrls2, timeoutMs) {
|
|
2301
2351
|
return new Promise((resolve) => {
|
|
@@ -2340,28 +2390,27 @@ function relayPoolSubscribe(ctx, filters, relayUrl, cb) {
|
|
|
2340
2390
|
}
|
|
2341
2391
|
async function queryImpl(ctx, filters, options) {
|
|
2342
2392
|
if (!ctx.relayPool.isAvailable()) {
|
|
2343
|
-
return { events: [],
|
|
2393
|
+
return { events: [], incomplete: true, error: "relay list unavailable" };
|
|
2344
2394
|
}
|
|
2345
|
-
const strategy = options?.strategy ?? "auto";
|
|
2346
2395
|
const authors = deriveAuthors(filters, options?.authors);
|
|
2347
|
-
const plan = await resolvePlan(ctx, authors, "read",
|
|
2396
|
+
const plan = await resolvePlan(ctx, authors, "read", options?.relays);
|
|
2348
2397
|
if (plan.relays.length === 0) {
|
|
2349
|
-
return { events: [],
|
|
2398
|
+
return { events: [], incomplete: true, error: "relay list unavailable" };
|
|
2350
2399
|
}
|
|
2351
2400
|
const timeoutMs = options?.timeoutMs ?? ctx.defaultTimeoutMs;
|
|
2352
2401
|
const collected = await collectFromRelays(ctx, filters, plan.relays, timeoutMs);
|
|
2353
2402
|
const incomplete = collected.incomplete || (plan.missingAuthors?.length ?? 0) > 0;
|
|
2354
2403
|
let events = collected.events;
|
|
2355
2404
|
if (options?.limit !== void 0 && events.length > options.limit) {
|
|
2356
|
-
events = [...events].sort((a, b) => b.created_at - a.created_at).slice(0, options.limit);
|
|
2405
|
+
events = [...events].sort((a, b) => b.event.created_at - a.event.created_at).slice(0, options.limit);
|
|
2357
2406
|
}
|
|
2358
|
-
const result2 = { events
|
|
2407
|
+
const result2 = { events };
|
|
2359
2408
|
if (incomplete) result2.incomplete = true;
|
|
2360
2409
|
return result2;
|
|
2361
2410
|
}
|
|
2362
2411
|
async function getEventImpl(ctx, eventId, options) {
|
|
2363
2412
|
if (typeof eventId !== "string" || eventId.length === 0) {
|
|
2364
|
-
return {
|
|
2413
|
+
return { error: "invalid filter" };
|
|
2365
2414
|
}
|
|
2366
2415
|
const filter = { ids: [eventId] };
|
|
2367
2416
|
const queryOptions = { limit: 1 };
|
|
@@ -2370,15 +2419,12 @@ async function getEventImpl(ctx, eventId, options) {
|
|
|
2370
2419
|
queryOptions.authors = [options.author];
|
|
2371
2420
|
}
|
|
2372
2421
|
if (Array.isArray(options?.relays)) queryOptions.relays = options.relays;
|
|
2373
|
-
if (options?.strategy !== void 0) queryOptions.strategy = options.strategy;
|
|
2374
2422
|
if (options?.timeoutMs !== void 0) queryOptions.timeoutMs = options.timeoutMs;
|
|
2375
2423
|
const queryResult = await queryImpl(ctx, [filter], queryOptions);
|
|
2376
|
-
const
|
|
2377
|
-
const result2 = {
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
if (event) result2.event = event;
|
|
2381
|
-
if (!event) result2.error = queryResult.error ?? "not found";
|
|
2424
|
+
const eventResult = queryResult.events.find((candidate) => candidate.event.id === eventId);
|
|
2425
|
+
const result2 = {};
|
|
2426
|
+
if (eventResult) result2.result = eventResult;
|
|
2427
|
+
if (!eventResult) result2.error = queryResult.error ?? "not found";
|
|
2382
2428
|
else if (queryResult.error !== void 0) result2.error = queryResult.error;
|
|
2383
2429
|
if (queryResult.incomplete !== void 0) result2.incomplete = queryResult.incomplete;
|
|
2384
2430
|
return result2;
|
|
@@ -2392,43 +2438,28 @@ function closeLiveSub(sub) {
|
|
|
2392
2438
|
}
|
|
2393
2439
|
sub.handles.length = 0;
|
|
2394
2440
|
}
|
|
2395
|
-
function attachLiveRelay(ctx, sub, filters, relayUrl,
|
|
2441
|
+
function attachLiveRelay(ctx, sub, filters, relayUrl, sink) {
|
|
2396
2442
|
sub.handles.push(relayPoolSubscribe(ctx, filters, relayUrl, (item) => {
|
|
2397
2443
|
if (sub.closed) return;
|
|
2398
|
-
if (item === "EOSE")
|
|
2399
|
-
sub.eoseCount += 1;
|
|
2400
|
-
if (!sub.eoseSent && sub.eoseCount >= sub.relayCount) {
|
|
2401
|
-
sub.eoseSent = true;
|
|
2402
|
-
sink.eose();
|
|
2403
|
-
if (!live) {
|
|
2404
|
-
sub.closed = true;
|
|
2405
|
-
closeLiveSub(sub);
|
|
2406
|
-
sink.closed();
|
|
2407
|
-
}
|
|
2408
|
-
}
|
|
2409
|
-
return;
|
|
2410
|
-
}
|
|
2444
|
+
if (item === "EOSE") return;
|
|
2411
2445
|
if (sub.seen.has(item.id)) return;
|
|
2412
2446
|
void ctx.verify(item).then((ok) => {
|
|
2413
2447
|
if (!ok || sub.closed || sub.seen.has(item.id)) return;
|
|
2414
2448
|
sub.seen.add(item.id);
|
|
2415
|
-
sink.event(item, relayUrl);
|
|
2449
|
+
sink.event(createRelayEventResultWithHints3(item, [relayUrl]));
|
|
2416
2450
|
});
|
|
2417
2451
|
}));
|
|
2418
2452
|
}
|
|
2419
2453
|
function startSubscription(ctx, filters, options, sink) {
|
|
2420
|
-
const live = options?.live ?? true;
|
|
2421
|
-
const strategy = options?.strategy ?? "auto";
|
|
2422
2454
|
const authors = deriveAuthors(filters, options?.authors);
|
|
2423
|
-
const sub = { handles: [], seen: /* @__PURE__ */ new Set(), closed: false
|
|
2424
|
-
void resolvePlan(ctx, authors, "read",
|
|
2455
|
+
const sub = { handles: [], seen: /* @__PURE__ */ new Set(), closed: false };
|
|
2456
|
+
void resolvePlan(ctx, authors, "read", options?.relays).then((plan) => {
|
|
2425
2457
|
if (sub.closed) return;
|
|
2426
2458
|
if (plan.relays.length === 0) {
|
|
2427
2459
|
sink.closed("relay list unavailable");
|
|
2428
2460
|
return;
|
|
2429
2461
|
}
|
|
2430
|
-
|
|
2431
|
-
for (const relayUrl of plan.relays) attachLiveRelay(ctx, sub, filters, relayUrl, live, sink);
|
|
2462
|
+
for (const relayUrl of plan.relays) attachLiveRelay(ctx, sub, filters, relayUrl, sink);
|
|
2432
2463
|
}).catch((err2) => {
|
|
2433
2464
|
if (!sub.closed) sink.closed(err2 instanceof Error ? err2.message : "subscribe failed");
|
|
2434
2465
|
});
|
|
@@ -2441,12 +2472,11 @@ function startSubscription(ctx, filters, options, sink) {
|
|
|
2441
2472
|
};
|
|
2442
2473
|
}
|
|
2443
2474
|
async function resolvePublishTargets(ctx, signed, options) {
|
|
2444
|
-
const strategy = options?.strategy ?? "auto";
|
|
2445
2475
|
const targets = /* @__PURE__ */ new Set();
|
|
2446
|
-
const authorPlan = await resolvePlan(ctx, [signed.pubkey], "read"
|
|
2476
|
+
const authorPlan = await resolvePlan(ctx, [signed.pubkey], "read");
|
|
2447
2477
|
for (const url of authorPlan.relays) targets.add(url);
|
|
2448
2478
|
if (options?.targetAuthors && options.targetAuthors.length > 0) {
|
|
2449
|
-
const inboxPlan = await resolvePlan(ctx, options.targetAuthors, "write"
|
|
2479
|
+
const inboxPlan = await resolvePlan(ctx, options.targetAuthors, "write");
|
|
2450
2480
|
for (const url of inboxPlan.relays) targets.add(url);
|
|
2451
2481
|
}
|
|
2452
2482
|
for (const url of options?.relays ?? []) targets.add(url);
|
|
@@ -2508,7 +2538,7 @@ function createRelayPoolOutboxRouter(options) {
|
|
|
2508
2538
|
publish: (template, publishOptions) => publishImpl(ctx, template, publishOptions),
|
|
2509
2539
|
resolveRelays: (target) => {
|
|
2510
2540
|
const pubkeys = target.authors ?? (target.pubkey ? [target.pubkey] : []);
|
|
2511
|
-
return resolvePlan(ctx, pubkeys, target.direction ?? "read"
|
|
2541
|
+
return resolvePlan(ctx, pubkeys, target.direction ?? "read");
|
|
2512
2542
|
}
|
|
2513
2543
|
};
|
|
2514
2544
|
}
|