applesauce-relay 2.1.1 → 2.3.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/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
- /** Whether the client is authenticated with the relay */
28
- authenticated$: BehaviorSubject<boolean>;
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
- protected authRequiredForReq: Observable<boolean>;
62
- protected authRequiredForEvent: Observable<boolean>;
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>;
package/dist/relay.js CHANGED
@@ -24,8 +24,10 @@ export class Relay {
24
24
  connected$ = new BehaviorSubject(false);
25
25
  /** The authentication challenge string from the relay */
26
26
  challenge$ = new BehaviorSubject(null);
27
- /** Whether the client is authenticated with the relay */
28
- authenticated$ = new BehaviorSubject(false);
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);
29
31
  /** The notices from the relay */
30
32
  notices$ = new BehaviorSubject([]);
31
33
  /** The last connection error */
@@ -56,7 +58,10 @@ export class Relay {
56
58
  return this.notices$.value;
57
59
  }
58
60
  get authenticated() {
59
- return this.authenticated$.value;
61
+ return this.authenticationResponse?.ok === true;
62
+ }
63
+ get authenticationResponse() {
64
+ return this.authenticationResponse$.value;
60
65
  }
61
66
  get information() {
62
67
  return this._nip11;
@@ -67,18 +72,18 @@ export class Relay {
67
72
  eventTimeout = 10_000;
68
73
  /** How long to keep the connection alive after nothing is subscribed */
69
74
  keepAlive = 30_000;
70
- // subjects that track if an "auth-required" message has been received for REQ or EVENT
75
+ // Subjects that track if an "auth-required" message has been received for REQ or EVENT
71
76
  receivedAuthRequiredForReq = new BehaviorSubject(false);
72
77
  receivedAuthRequiredForEvent = new BehaviorSubject(false);
73
78
  // Computed observables that track if auth is required for REQ or EVENT
74
- authRequiredForReq;
75
- authRequiredForEvent;
79
+ authRequiredForRead$;
80
+ authRequiredForPublish$;
76
81
  resetState() {
77
82
  // NOTE: only update the values if they need to be changed, otherwise this will cause an infinite loop
78
83
  if (this.challenge$.value !== null)
79
84
  this.challenge$.next(null);
80
- if (this.authenticated$.value)
81
- this.authenticated$.next(false);
85
+ if (this.authenticationResponse$.value)
86
+ this.authenticationResponse$.next(null);
82
87
  if (this.notices$.value.length > 0)
83
88
  this.notices$.next([]);
84
89
  if (this.receivedAuthRequiredForReq.value)
@@ -91,6 +96,8 @@ export class Relay {
91
96
  constructor(url, opts) {
92
97
  this.url = url;
93
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));
94
101
  /** Use the static method to create a new reconnect method for this relay */
95
102
  this.reconnectTimer = Relay.createReconnectTimer(url);
96
103
  this.socket = webSocket({
@@ -130,8 +137,8 @@ export class Relay {
130
137
  tap((info) => (this._nip11 = info)));
131
138
  this.limitations$ = this.information$.pipe(map((info) => info?.limitation));
132
139
  // Create observables that track if auth is required for REQ or EVENT
133
- this.authRequiredForReq = combineLatest([this.receivedAuthRequiredForReq, this.limitations$]).pipe(map(([received, limitations]) => received || limitations?.auth_required === true), tap((required) => required && this.log("Auth required for REQ")), shareReplay(1));
134
- this.authRequiredForEvent = combineLatest([this.receivedAuthRequiredForEvent, this.limitations$]).pipe(map(([received, limitations]) => received || limitations?.auth_required === true), tap((required) => required && this.log("Auth required for EVENT")), shareReplay(1));
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));
135
142
  // Update the notices state
136
143
  const listenForNotice = this.socket.pipe(
137
144
  // listen for NOTICE messages
@@ -276,7 +283,7 @@ export class Relay {
276
283
  // Only create one upstream subscription
277
284
  share());
278
285
  // Wait for auth if required and make sure to start the watch tower
279
- return this.waitForReady(this.waitForAuth(this.authRequiredForReq, observable));
286
+ return this.waitForReady(this.waitForAuth(this.authRequiredForRead$, observable));
280
287
  }
281
288
  /** Send an EVENT or AUTH message and return an observable of PublishResponse that completes or errors */
282
289
  event(event, verb = "EVENT") {
@@ -309,13 +316,13 @@ export class Relay {
309
316
  if (verb === "AUTH")
310
317
  return this.waitForReady(observable);
311
318
  else
312
- return this.waitForReady(this.waitForAuth(this.authRequiredForEvent, observable));
319
+ return this.waitForReady(this.waitForAuth(this.authRequiredForPublish$, observable));
313
320
  }
314
321
  /** send and AUTH message */
315
322
  auth(event) {
316
323
  return this.event(event, "AUTH").pipe(
317
324
  // update authenticated
318
- tap((result) => this.authenticated$.next(result.ok)));
325
+ tap((result) => this.authenticationResponse$.next(result)));
319
326
  }
320
327
  /** Authenticate with the relay using a signer */
321
328
  authenticate(signer) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "applesauce-relay",
3
- "version": "2.1.1",
3
+ "version": "2.3.0",
4
4
  "description": "nostr relay communication framework built on rxjs",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -54,7 +54,7 @@
54
54
  },
55
55
  "dependencies": {
56
56
  "@noble/hashes": "^1.7.1",
57
- "applesauce-core": "^2.0.0",
57
+ "applesauce-core": "^2.3.0",
58
58
  "nanoid": "^5.0.9",
59
59
  "nostr-tools": "^2.13",
60
60
  "rxjs": "^7.8.1"