applesauce-relay 0.0.0-next-20250522030625 → 0.0.0-next-20250606170247

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.
@@ -144,7 +144,7 @@ describe("req", () => {
144
144
  // Verify the second subscription received the event and EOSE
145
145
  expect(secondSub.getValues()).toEqual([expect.objectContaining(mockEvent), "EOSE"]);
146
146
  });
147
- it("should wait for authentication if relay info document has limitations.auth_required = true", async () => {
147
+ it("should open connection and wait for authentication if relay info document has limitations.auth_required = true", async () => {
148
148
  // Mock the fetchInformationDocument method to return a document with auth_required = true
149
149
  vi.spyOn(Relay, "fetchInformationDocument").mockImplementation(() => of({
150
150
  name: "Auth Required Relay",
@@ -162,10 +162,20 @@ describe("req", () => {
162
162
  const sub = subscribeSpyTo(relay.req([{ kinds: [1] }], "sub1"));
163
163
  // Wait 10ms to ensure the information document is fetched
164
164
  await new Promise((resolve) => setTimeout(resolve, 10));
165
+ // Wait for connection
166
+ await server.connected;
165
167
  // Verify no REQ message was sent yet (waiting for auth)
166
168
  expect(server).not.toHaveReceivedMessages(["REQ", "sub1", { kinds: [1] }]);
169
+ // Send AUTH challenge
170
+ server.send(["AUTH", "challenge"]);
171
+ // Send auth response
172
+ subscribeSpyTo(relay.auth(mockEvent));
173
+ // Verify the auth event was sent
174
+ await expect(server.nextMessage).resolves.toEqual(["AUTH", mockEvent]);
175
+ // Accept auth
176
+ server.send(["OK", mockEvent.id, true, ""]);
167
177
  // Simulate successful authentication
168
- relay.authenticated$.next(true);
178
+ expect(relay.authenticated).toBe(true);
169
179
  // Now the REQ should be sent
170
180
  await expect(server).toReceiveMessage(["REQ", "sub1", { kinds: [1] }]);
171
181
  // Send EVENT and EOSE to complete the subscription
@@ -1,8 +1,8 @@
1
- import { ISyncEventStore } from "applesauce-core";
1
+ import { IEventStoreRead } from "applesauce-core";
2
2
  import { Filter } from "nostr-tools";
3
3
  import { MultiplexWebSocket } from "./types.js";
4
4
  import { NegentropyStorageVector } from "./lib/negentropy.js";
5
- export declare function buildStorageFromFilter(store: ISyncEventStore, filter: Filter): NegentropyStorageVector;
5
+ export declare function buildStorageFromFilter(store: IEventStoreRead, filter: Filter): NegentropyStorageVector;
6
6
  export declare function buildStorageVector(items: {
7
7
  id: string;
8
8
  created_at: number;
@@ -5,7 +5,7 @@ import { Negentropy, NegentropyStorageVector } from "./lib/negentropy.js";
5
5
  const log = logger.extend("negentropy");
6
6
  export function buildStorageFromFilter(store, filter) {
7
7
  const storage = new NegentropyStorageVector();
8
- for (const event of store.getAll(filter))
8
+ for (const event of store.getByFilters(filter))
9
9
  storage.insert(event.created_at, event.id);
10
10
  storage.seal();
11
11
  return storage;
package/dist/relay.d.ts CHANGED
@@ -61,12 +61,12 @@ export declare class Relay implements IRelay {
61
61
  protected authRequiredForReq: Observable<boolean>;
62
62
  protected authRequiredForEvent: Observable<boolean>;
63
63
  protected resetState(): void;
64
- /** An internal observable that is responsible for watching all messages and updating state */
64
+ /** An internal observable that is responsible for watching all messages and updating state, subscribing to it will trigger a connection to the relay */
65
65
  protected watchTower: Observable<never>;
66
66
  constructor(url: string, opts?: RelayOptions);
67
67
  /** Set ready = false and start the reconnect timer */
68
68
  protected startReconnectTimer(error: Error | CloseEvent): void;
69
- /** Wait for ready and authenticated */
69
+ /** Wait for authentication state, make connection and then wait for authentication if required */
70
70
  protected waitForAuth<T extends unknown = unknown>(requireAuth: Observable<boolean>, observable: Observable<T>): Observable<T>;
71
71
  /** Wait for the relay to be ready to accept connections */
72
72
  protected waitForReady<T extends unknown = unknown>(observable: Observable<T>): Observable<T>;
package/dist/relay.js CHANGED
@@ -2,7 +2,7 @@ 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, 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, 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
7
  import { completeOnEose } from "./operators/complete-on-eose.js";
8
8
  import { markFromRelay } from "./operators/mark-from-relay.js";
@@ -85,7 +85,7 @@ export class Relay {
85
85
  if (this.receivedAuthRequiredForEvent.value)
86
86
  this.receivedAuthRequiredForEvent.next(false);
87
87
  }
88
- /** An internal observable that is responsible for watching all messages and updating state */
88
+ /** An internal observable that is responsible for watching all messages and updating state, subscribing to it will trigger a connection to the relay */
89
89
  watchTower;
90
90
  constructor(url, opts) {
91
91
  this.url = url;
@@ -190,11 +190,13 @@ export class Relay {
190
190
  .pipe(take(1))
191
191
  .subscribe(() => this.ready$.next(true));
192
192
  }
193
- /** Wait for ready and authenticated */
193
+ /** Wait for authentication state, make connection and then wait for authentication if required */
194
194
  waitForAuth(
195
195
  // NOTE: require BehaviorSubject so it always has a value
196
196
  requireAuth, observable) {
197
197
  return combineLatest([requireAuth, this.authenticated$]).pipe(
198
+ // Once the auth state is known, make a connection and watch for auth challenges
199
+ mergeWith(this.watchTower),
198
200
  // wait for auth not required or authenticated
199
201
  filter(([required, authenticated]) => !required || authenticated),
200
202
  // complete after the first value so this does not repeat
@@ -284,10 +286,8 @@ export class Relay {
284
286
  // format OK message
285
287
  map((m) => ({ ok: m[2], message: m[3], from: this.url })));
286
288
  });
287
- // Start the watch tower with the observable
288
- const withWatchTower = merge(this.watchTower, base);
289
- // Add complete operators
290
- const observable = withWatchTower.pipe(
289
+ // Start the watch tower and add complete operators
290
+ const observable = merge(this.watchTower, base).pipe(
291
291
  // complete on first value
292
292
  take(1),
293
293
  // listen for OK auth-required
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "applesauce-relay",
3
- "version": "0.0.0-next-20250522030625",
3
+ "version": "0.0.0-next-20250606170247",
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": "0.0.0-next-20250522030625",
57
+ "applesauce-core": "0.0.0-next-20250606170247",
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": "0.0.0-next-20250522030625",
64
+ "applesauce-signers": "0.0.0-next-20250606170247",
65
65
  "@vitest/expect": "^3.1.1",
66
66
  "typescript": "^5.7.3",
67
67
  "vitest": "^3.1.1",