applesauce-relay 0.0.0-next-20250610194602 → 0.0.0-next-20250716144720
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/group.d.ts +2 -2
- package/dist/group.js +2 -2
- package/dist/pool.d.ts +1 -1
- package/dist/relay.d.ts +11 -8
- package/dist/relay.js +28 -20
- package/dist/types.d.ts +24 -25
- package/package.json +3 -3
package/dist/group.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type NostrEvent } from "nostr-tools";
|
|
2
2
|
import { Observable } from "rxjs";
|
|
3
|
-
import { IGroup, IRelay,
|
|
3
|
+
import { FilterInput, IGroup, IRelay, PublishOptions, PublishResponse, RequestOptions, SubscriptionOptions, SubscriptionResponse } from "./types.js";
|
|
4
4
|
export declare class RelayGroup implements IGroup {
|
|
5
5
|
relays: IRelay[];
|
|
6
6
|
constructor(relays: IRelay[]);
|
|
@@ -11,7 +11,7 @@ export declare class RelayGroup implements IGroup {
|
|
|
11
11
|
/** Send an event to all relays */
|
|
12
12
|
event(event: NostrEvent): Observable<PublishResponse>;
|
|
13
13
|
/** Publish an event to all relays with retries ( default 3 retries ) */
|
|
14
|
-
publish(event: NostrEvent, opts?: PublishOptions):
|
|
14
|
+
publish(event: NostrEvent, opts?: PublishOptions): Promise<PublishResponse[]>;
|
|
15
15
|
/** Request events from all relays with retries ( default 3 retries ) */
|
|
16
16
|
request(filters: FilterInput, opts?: RequestOptions): Observable<NostrEvent>;
|
|
17
17
|
/** Open a subscription to all relays with retries ( default 3 retries ) */
|
package/dist/group.js
CHANGED
|
@@ -35,9 +35,9 @@ export class RelayGroup {
|
|
|
35
35
|
}
|
|
36
36
|
/** Publish an event to all relays with retries ( default 3 retries ) */
|
|
37
37
|
publish(event, opts) {
|
|
38
|
-
return
|
|
38
|
+
return Promise.all(this.relays.map((relay) => relay.publish(event, opts).catch(
|
|
39
39
|
// Catch error and return as PublishResponse
|
|
40
|
-
|
|
40
|
+
(err) => ({ ok: false, from: relay.url, message: err?.message || "Unknown error" }))));
|
|
41
41
|
}
|
|
42
42
|
/** Request events from all relays with retries ( default 3 retries ) */
|
|
43
43
|
request(filters, opts) {
|
package/dist/pool.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ export declare class RelayPool implements IPool {
|
|
|
22
22
|
/** Send an EVENT message to multiple relays */
|
|
23
23
|
event(relays: string[], event: NostrEvent): Observable<PublishResponse>;
|
|
24
24
|
/** Publish an event to multiple relays */
|
|
25
|
-
publish(relays: string[], event: NostrEvent, opts?: PublishOptions):
|
|
25
|
+
publish(relays: string[], event: NostrEvent, opts?: PublishOptions): Promise<PublishResponse[]>;
|
|
26
26
|
/** Request events from multiple relays */
|
|
27
27
|
request(relays: string[], filters: FilterInput, opts?: RequestOptions): Observable<NostrEvent>;
|
|
28
28
|
/** Open a subscription to multiple relays */
|
package/dist/relay.d.ts
CHANGED
|
@@ -24,8 +24,10 @@ export declare class Relay implements IRelay {
|
|
|
24
24
|
connected$: BehaviorSubject<boolean>;
|
|
25
25
|
/** The authentication challenge string from the relay */
|
|
26
26
|
challenge$: BehaviorSubject<string | null>;
|
|
27
|
-
/**
|
|
28
|
-
authenticated$:
|
|
27
|
+
/** Boolean authentication state (will be false if auth failed) */
|
|
28
|
+
authenticated$: Observable<boolean>;
|
|
29
|
+
/** The response to the last AUTH message sent to the relay */
|
|
30
|
+
authenticationResponse$: BehaviorSubject<PublishResponse | null>;
|
|
29
31
|
/** The notices from the relay */
|
|
30
32
|
notices$: BehaviorSubject<string[]>;
|
|
31
33
|
/** The last connection error */
|
|
@@ -49,6 +51,7 @@ export declare class Relay implements IRelay {
|
|
|
49
51
|
get challenge(): string | null;
|
|
50
52
|
get notices(): string[];
|
|
51
53
|
get authenticated(): boolean;
|
|
54
|
+
get authenticationResponse(): PublishResponse | null;
|
|
52
55
|
get information(): RelayInformation | null;
|
|
53
56
|
/** If an EOSE message is not seen in this time, emit one locally */
|
|
54
57
|
eoseTimeout: number;
|
|
@@ -58,8 +61,8 @@ export declare class Relay implements IRelay {
|
|
|
58
61
|
keepAlive: number;
|
|
59
62
|
protected receivedAuthRequiredForReq: BehaviorSubject<boolean>;
|
|
60
63
|
protected receivedAuthRequiredForEvent: BehaviorSubject<boolean>;
|
|
61
|
-
|
|
62
|
-
|
|
64
|
+
authRequiredForRead$: Observable<boolean>;
|
|
65
|
+
authRequiredForPublish$: Observable<boolean>;
|
|
63
66
|
protected resetState(): void;
|
|
64
67
|
/** An internal observable that is responsible for watching all messages and updating state, subscribing to it will trigger a connection to the relay */
|
|
65
68
|
protected watchTower: Observable<never>;
|
|
@@ -72,21 +75,21 @@ export declare class Relay implements IRelay {
|
|
|
72
75
|
protected waitForReady<T extends unknown = unknown>(observable: Observable<T>): Observable<T>;
|
|
73
76
|
multiplex<T>(open: () => any, close: () => any, filter: (message: any) => boolean): Observable<T>;
|
|
74
77
|
/** Send a message to the relay */
|
|
75
|
-
|
|
78
|
+
send(message: any): void;
|
|
76
79
|
/** Create a REQ observable that emits events or "EOSE" or errors */
|
|
77
80
|
req(filters: FilterInput, id?: string): Observable<SubscriptionResponse>;
|
|
78
81
|
/** Send an EVENT or AUTH message and return an observable of PublishResponse that completes or errors */
|
|
79
82
|
event(event: NostrEvent, verb?: "EVENT" | "AUTH"): Observable<PublishResponse>;
|
|
80
83
|
/** send and AUTH message */
|
|
81
|
-
auth(event: NostrEvent):
|
|
84
|
+
auth(event: NostrEvent): Promise<PublishResponse>;
|
|
82
85
|
/** Authenticate with the relay using a signer */
|
|
83
|
-
authenticate(signer: AuthSigner):
|
|
86
|
+
authenticate(signer: AuthSigner): Promise<PublishResponse>;
|
|
84
87
|
/** Creates a REQ that retries when relay errors ( default 3 retries ) */
|
|
85
88
|
subscription(filters: Filter | Filter[], opts?: SubscriptionOptions): Observable<SubscriptionResponse>;
|
|
86
89
|
/** Makes a single request that retires on errors and completes on EOSE */
|
|
87
90
|
request(filters: Filter | Filter[], opts?: RequestOptions): Observable<NostrEvent>;
|
|
88
91
|
/** Publishes an event to the relay and retries when relay errors or responds with auth-required ( default 3 retries ) */
|
|
89
|
-
publish(event: NostrEvent, opts?: PublishOptions):
|
|
92
|
+
publish(event: NostrEvent, opts?: PublishOptions): Promise<PublishResponse>;
|
|
90
93
|
/** Static method to fetch the NIP-11 information document for a relay */
|
|
91
94
|
static fetchInformationDocument(url: string): Observable<RelayInformation | null>;
|
|
92
95
|
/** Static method to create a reconnection method for each relay */
|
package/dist/relay.js
CHANGED
|
@@ -2,8 +2,9 @@ import { logger } from "applesauce-core";
|
|
|
2
2
|
import { simpleTimeout } from "applesauce-core/observable";
|
|
3
3
|
import { nanoid } from "nanoid";
|
|
4
4
|
import { nip42 } from "nostr-tools";
|
|
5
|
-
import { BehaviorSubject, catchError, combineLatest, defer, endWith, filter, finalize, from, ignoreElements, isObservable, map, merge, mergeMap, mergeWith, NEVER, of, retry, scan, share, shareReplay, Subject, switchMap, take, takeUntil, tap, throwError, timeout, timer, } from "rxjs";
|
|
5
|
+
import { BehaviorSubject, catchError, combineLatest, defer, endWith, filter, finalize, from, ignoreElements, isObservable, lastValueFrom, map, merge, mergeMap, mergeWith, NEVER, of, retry, scan, share, shareReplay, Subject, switchMap, take, takeUntil, tap, throwError, timeout, timer, } from "rxjs";
|
|
6
6
|
import { webSocket } from "rxjs/webSocket";
|
|
7
|
+
import { ensureHttpURL } from "applesauce-core/helpers";
|
|
7
8
|
import { completeOnEose } from "./operators/complete-on-eose.js";
|
|
8
9
|
import { markFromRelay } from "./operators/mark-from-relay.js";
|
|
9
10
|
/** An error that is thrown when a REQ is closed from the relay side */
|
|
@@ -23,8 +24,10 @@ export class Relay {
|
|
|
23
24
|
connected$ = new BehaviorSubject(false);
|
|
24
25
|
/** The authentication challenge string from the relay */
|
|
25
26
|
challenge$ = new BehaviorSubject(null);
|
|
26
|
-
/**
|
|
27
|
-
authenticated
|
|
27
|
+
/** Boolean authentication state (will be false if auth failed) */
|
|
28
|
+
authenticated$;
|
|
29
|
+
/** The response to the last AUTH message sent to the relay */
|
|
30
|
+
authenticationResponse$ = new BehaviorSubject(null);
|
|
28
31
|
/** The notices from the relay */
|
|
29
32
|
notices$ = new BehaviorSubject([]);
|
|
30
33
|
/** The last connection error */
|
|
@@ -55,7 +58,10 @@ export class Relay {
|
|
|
55
58
|
return this.notices$.value;
|
|
56
59
|
}
|
|
57
60
|
get authenticated() {
|
|
58
|
-
return this.
|
|
61
|
+
return this.authenticationResponse?.ok === true;
|
|
62
|
+
}
|
|
63
|
+
get authenticationResponse() {
|
|
64
|
+
return this.authenticationResponse$.value;
|
|
59
65
|
}
|
|
60
66
|
get information() {
|
|
61
67
|
return this._nip11;
|
|
@@ -66,18 +72,18 @@ export class Relay {
|
|
|
66
72
|
eventTimeout = 10_000;
|
|
67
73
|
/** How long to keep the connection alive after nothing is subscribed */
|
|
68
74
|
keepAlive = 30_000;
|
|
69
|
-
//
|
|
75
|
+
// Subjects that track if an "auth-required" message has been received for REQ or EVENT
|
|
70
76
|
receivedAuthRequiredForReq = new BehaviorSubject(false);
|
|
71
77
|
receivedAuthRequiredForEvent = new BehaviorSubject(false);
|
|
72
78
|
// Computed observables that track if auth is required for REQ or EVENT
|
|
73
|
-
|
|
74
|
-
|
|
79
|
+
authRequiredForRead$;
|
|
80
|
+
authRequiredForPublish$;
|
|
75
81
|
resetState() {
|
|
76
82
|
// NOTE: only update the values if they need to be changed, otherwise this will cause an infinite loop
|
|
77
83
|
if (this.challenge$.value !== null)
|
|
78
84
|
this.challenge$.next(null);
|
|
79
|
-
if (this.
|
|
80
|
-
this.
|
|
85
|
+
if (this.authenticationResponse$.value)
|
|
86
|
+
this.authenticationResponse$.next(null);
|
|
81
87
|
if (this.notices$.value.length > 0)
|
|
82
88
|
this.notices$.next([]);
|
|
83
89
|
if (this.receivedAuthRequiredForReq.value)
|
|
@@ -90,6 +96,8 @@ export class Relay {
|
|
|
90
96
|
constructor(url, opts) {
|
|
91
97
|
this.url = url;
|
|
92
98
|
this.log = this.log.extend(url);
|
|
99
|
+
// Create an observable that tracks boolean authentication state
|
|
100
|
+
this.authenticated$ = this.authenticationResponse$.pipe(map((response) => response?.ok === true));
|
|
93
101
|
/** Use the static method to create a new reconnect method for this relay */
|
|
94
102
|
this.reconnectTimer = Relay.createReconnectTimer(url);
|
|
95
103
|
this.socket = webSocket({
|
|
@@ -129,8 +137,8 @@ export class Relay {
|
|
|
129
137
|
tap((info) => (this._nip11 = info)));
|
|
130
138
|
this.limitations$ = this.information$.pipe(map((info) => info?.limitation));
|
|
131
139
|
// Create observables that track if auth is required for REQ or EVENT
|
|
132
|
-
this.
|
|
133
|
-
this.
|
|
140
|
+
this.authRequiredForRead$ = this.receivedAuthRequiredForReq.pipe(tap((required) => required && this.log("Auth required for REQ")), shareReplay(1));
|
|
141
|
+
this.authRequiredForPublish$ = this.receivedAuthRequiredForEvent.pipe(tap((required) => required && this.log("Auth required for EVENT")), shareReplay(1));
|
|
134
142
|
// Update the notices state
|
|
135
143
|
const listenForNotice = this.socket.pipe(
|
|
136
144
|
// listen for NOTICE messages
|
|
@@ -222,7 +230,7 @@ export class Relay {
|
|
|
222
230
|
return this.socket.multiplex(open, close, filter);
|
|
223
231
|
}
|
|
224
232
|
/** Send a message to the relay */
|
|
225
|
-
|
|
233
|
+
send(message) {
|
|
226
234
|
this.socket.next(message);
|
|
227
235
|
}
|
|
228
236
|
/** Create a REQ observable that emits events or "EOSE" or errors */
|
|
@@ -275,7 +283,7 @@ export class Relay {
|
|
|
275
283
|
// Only create one upstream subscription
|
|
276
284
|
share());
|
|
277
285
|
// Wait for auth if required and make sure to start the watch tower
|
|
278
|
-
return this.waitForReady(this.waitForAuth(this.
|
|
286
|
+
return this.waitForReady(this.waitForAuth(this.authRequiredForRead$, observable));
|
|
279
287
|
}
|
|
280
288
|
/** Send an EVENT or AUTH message and return an observable of PublishResponse that completes or errors */
|
|
281
289
|
event(event, verb = "EVENT") {
|
|
@@ -308,13 +316,13 @@ export class Relay {
|
|
|
308
316
|
if (verb === "AUTH")
|
|
309
317
|
return this.waitForReady(observable);
|
|
310
318
|
else
|
|
311
|
-
return this.waitForReady(this.waitForAuth(this.
|
|
319
|
+
return this.waitForReady(this.waitForAuth(this.authRequiredForPublish$, observable));
|
|
312
320
|
}
|
|
313
321
|
/** send and AUTH message */
|
|
314
322
|
auth(event) {
|
|
315
|
-
return this.event(event, "AUTH").pipe(
|
|
323
|
+
return lastValueFrom(this.event(event, "AUTH").pipe(
|
|
316
324
|
// update authenticated
|
|
317
|
-
tap((result) => this.
|
|
325
|
+
tap((result) => this.authenticationResponse$.next(result))));
|
|
318
326
|
}
|
|
319
327
|
/** Authenticate with the relay using a signer */
|
|
320
328
|
authenticate(signer) {
|
|
@@ -322,7 +330,7 @@ export class Relay {
|
|
|
322
330
|
throw new Error("Have not received authentication challenge");
|
|
323
331
|
const p = signer.signEvent(nip42.makeAuthEvent(this.url, this.challenge));
|
|
324
332
|
const start = p instanceof Promise ? from(p) : of(p);
|
|
325
|
-
return start.pipe(switchMap((event) => this.auth(event)));
|
|
333
|
+
return lastValueFrom(start.pipe(switchMap((event) => this.auth(event))));
|
|
326
334
|
}
|
|
327
335
|
/** Creates a REQ that retries when relay errors ( default 3 retries ) */
|
|
328
336
|
subscription(filters, opts) {
|
|
@@ -340,18 +348,18 @@ export class Relay {
|
|
|
340
348
|
}
|
|
341
349
|
/** Publishes an event to the relay and retries when relay errors or responds with auth-required ( default 3 retries ) */
|
|
342
350
|
publish(event, opts) {
|
|
343
|
-
return this.event(event).pipe(mergeMap((result) => {
|
|
351
|
+
return lastValueFrom(this.event(event).pipe(mergeMap((result) => {
|
|
344
352
|
// If the relay responds with auth-required, throw an error for the retry operator to handle
|
|
345
353
|
if (result.ok === false && result.message?.startsWith("auth-required:"))
|
|
346
354
|
return throwError(() => new Error(result.message));
|
|
347
355
|
return of(result);
|
|
348
356
|
}),
|
|
349
357
|
// Retry the publish until it succeeds or the number of retries is reached
|
|
350
|
-
retry(opts?.retries ?? 3));
|
|
358
|
+
retry(opts?.retries ?? 3)));
|
|
351
359
|
}
|
|
352
360
|
/** Static method to fetch the NIP-11 information document for a relay */
|
|
353
361
|
static fetchInformationDocument(url) {
|
|
354
|
-
return from(fetch(url, { headers: { Accept: "application/nostr+json" } }).then((res) => res.json())).pipe(
|
|
362
|
+
return from(fetch(ensureHttpURL(url), { headers: { Accept: "application/nostr+json" } }).then((res) => res.json())).pipe(
|
|
355
363
|
// if the fetch fails, return null
|
|
356
364
|
catchError(() => of(null)),
|
|
357
365
|
// timeout after 10s
|
package/dist/types.d.ts
CHANGED
|
@@ -8,12 +8,6 @@ export type PublishResponse = {
|
|
|
8
8
|
from: string;
|
|
9
9
|
};
|
|
10
10
|
export type MultiplexWebSocket<T = any> = Pick<WebSocketSubject<T>, "multiplex">;
|
|
11
|
-
export interface IRelayState {
|
|
12
|
-
connected$: Observable<boolean>;
|
|
13
|
-
challenge$: Observable<string | null>;
|
|
14
|
-
authenticated$: Observable<boolean>;
|
|
15
|
-
notices$: Observable<string[]>;
|
|
16
|
-
}
|
|
17
11
|
export type PublishOptions = {
|
|
18
12
|
retries?: number;
|
|
19
13
|
};
|
|
@@ -30,29 +24,30 @@ export type AuthSigner = {
|
|
|
30
24
|
};
|
|
31
25
|
/** The type of input the REQ method accepts */
|
|
32
26
|
export type FilterInput = Filter | Filter[] | Observable<Filter | Filter[]>;
|
|
33
|
-
export interface
|
|
34
|
-
/** Send an EVENT message */
|
|
35
|
-
event(event: NostrEvent): Observable<PublishResponse>;
|
|
36
|
-
/** Send a REQ message */
|
|
37
|
-
req(filters: FilterInput, id?: string): Observable<SubscriptionResponse>;
|
|
38
|
-
}
|
|
39
|
-
export interface IRelay extends MultiplexWebSocket, Nip01Actions, IRelayState {
|
|
27
|
+
export interface IRelay extends MultiplexWebSocket {
|
|
40
28
|
url: string;
|
|
41
29
|
message$: Observable<any>;
|
|
42
30
|
notice$: Observable<string>;
|
|
31
|
+
connected$: Observable<boolean>;
|
|
32
|
+
challenge$: Observable<string | null>;
|
|
33
|
+
authenticated$: Observable<boolean>;
|
|
34
|
+
notices$: Observable<string[]>;
|
|
43
35
|
readonly connected: boolean;
|
|
44
36
|
readonly authenticated: boolean;
|
|
45
37
|
readonly challenge: string | null;
|
|
46
38
|
readonly notices: string[];
|
|
39
|
+
/** Send a REQ message */
|
|
40
|
+
req(filters: FilterInput, id?: string): Observable<SubscriptionResponse>;
|
|
41
|
+
/** Send an EVENT message */
|
|
42
|
+
event(event: NostrEvent): Observable<PublishResponse>;
|
|
47
43
|
/** Send an AUTH message */
|
|
48
|
-
auth(event: NostrEvent):
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}>;
|
|
44
|
+
auth(event: NostrEvent): Promise<PublishResponse>;
|
|
45
|
+
/** Authenticate with the relay using a signer */
|
|
46
|
+
authenticate(signer: AuthSigner): Promise<PublishResponse>;
|
|
52
47
|
/** Send an EVENT message with retries */
|
|
53
48
|
publish(event: NostrEvent, opts?: {
|
|
54
49
|
retries?: number;
|
|
55
|
-
}):
|
|
50
|
+
}): Promise<PublishResponse>;
|
|
56
51
|
/** Send a REQ message with retries */
|
|
57
52
|
request(filters: FilterInput, opts?: {
|
|
58
53
|
id?: string;
|
|
@@ -64,11 +59,15 @@ export interface IRelay extends MultiplexWebSocket, Nip01Actions, IRelayState {
|
|
|
64
59
|
retries?: number;
|
|
65
60
|
}): Observable<SubscriptionResponse>;
|
|
66
61
|
}
|
|
67
|
-
export interface IGroup
|
|
62
|
+
export interface IGroup {
|
|
63
|
+
/** Send a REQ message */
|
|
64
|
+
req(filters: FilterInput, id?: string): Observable<SubscriptionResponse>;
|
|
65
|
+
/** Send an EVENT message */
|
|
66
|
+
event(event: NostrEvent): Observable<PublishResponse>;
|
|
68
67
|
/** Send an EVENT message with retries */
|
|
69
68
|
publish(event: NostrEvent, opts?: {
|
|
70
69
|
retries?: number;
|
|
71
|
-
}):
|
|
70
|
+
}): Promise<PublishResponse[]>;
|
|
72
71
|
/** Send a REQ message with retries */
|
|
73
72
|
request(filters: FilterInput, opts?: {
|
|
74
73
|
id?: string;
|
|
@@ -81,18 +80,18 @@ export interface IGroup extends Nip01Actions {
|
|
|
81
80
|
}): Observable<SubscriptionResponse>;
|
|
82
81
|
}
|
|
83
82
|
export interface IPool {
|
|
84
|
-
/** Send an EVENT message */
|
|
85
|
-
event(relays: string[], event: NostrEvent): Observable<PublishResponse>;
|
|
86
|
-
/** Send a REQ message */
|
|
87
|
-
req(relays: string[], filters: FilterInput, id?: string): Observable<SubscriptionResponse>;
|
|
88
83
|
/** Get or create a relay */
|
|
89
84
|
relay(url: string): IRelay;
|
|
90
85
|
/** Create a relay group */
|
|
91
86
|
group(relays: string[]): IGroup;
|
|
87
|
+
/** Send a REQ message */
|
|
88
|
+
req(relays: string[], filters: FilterInput, id?: string): Observable<SubscriptionResponse>;
|
|
89
|
+
/** Send an EVENT message */
|
|
90
|
+
event(relays: string[], event: NostrEvent): Observable<PublishResponse>;
|
|
92
91
|
/** Send an EVENT message to relays with retries */
|
|
93
92
|
publish(relays: string[], event: NostrEvent, opts?: {
|
|
94
93
|
retries?: number;
|
|
95
|
-
}):
|
|
94
|
+
}): Promise<PublishResponse[]>;
|
|
96
95
|
/** Send a REQ message to relays with retries */
|
|
97
96
|
request(relays: string[], filters: FilterInput, opts?: {
|
|
98
97
|
id?: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "applesauce-relay",
|
|
3
|
-
"version": "0.0.0-next-
|
|
3
|
+
"version": "0.0.0-next-20250716144720",
|
|
4
4
|
"description": "nostr relay communication framework built on rxjs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -54,14 +54,14 @@
|
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"@noble/hashes": "^1.7.1",
|
|
57
|
-
"applesauce-core": "
|
|
57
|
+
"applesauce-core": "^2.3.0",
|
|
58
58
|
"nanoid": "^5.0.9",
|
|
59
59
|
"nostr-tools": "^2.13",
|
|
60
60
|
"rxjs": "^7.8.1"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
63
|
"@hirez_io/observer-spy": "^2.2.0",
|
|
64
|
-
"applesauce-signers": "
|
|
64
|
+
"applesauce-signers": "^2.0.0",
|
|
65
65
|
"@vitest/expect": "^3.1.1",
|
|
66
66
|
"typescript": "^5.7.3",
|
|
67
67
|
"vitest": "^3.2.3",
|