applesauce-relay 1.0.0 → 1.0.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.
@@ -47,17 +47,33 @@ describe("req", () => {
47
47
  await firstValueFrom(relay.connected$.pipe(filter(Boolean)));
48
48
  expect(relay.connected).toBe(true);
49
49
  });
50
- it("should send REQ and CLOSE messages", async () => {
50
+ it("should send expected messages to relay", async () => {
51
+ subscribeSpyTo(relay.req([{ kinds: [1] }], "sub1"));
52
+ // Wait for all message to be sent
53
+ await new Promise((resolve) => setTimeout(resolve, 10));
54
+ expect(server.messages).toEqual([["REQ", "sub1", { kinds: [1] }]]);
55
+ });
56
+ it("should not close the REQ when EOSE is received", async () => {
51
57
  // Create subscription that completes after first EOSE
52
- const sub = relay.req([{ kinds: [1] }], "sub1").subscribe();
58
+ const sub = subscribeSpyTo(relay.req([{ kinds: [1] }], "sub1"));
53
59
  // Verify REQ was sent
54
- expect(await server.nextMessage).toEqual(["REQ", "sub1", { kinds: [1] }]);
60
+ await expect(server).toReceiveMessage(["REQ", "sub1", { kinds: [1] }]);
55
61
  // Send EOSE to complete subscription
62
+ server.send(["EVENT", "sub1", mockEvent]);
56
63
  server.send(["EOSE", "sub1"]);
64
+ // Verify the subscription did not complete
65
+ expect(sub.receivedComplete()).toBe(false);
66
+ expect(sub.getValues()).toEqual([expect.objectContaining(mockEvent), "EOSE"]);
67
+ });
68
+ it("should send CLOSE when unsubscribed", async () => {
69
+ // Create subscription that completes after first EOSE
70
+ const sub = subscribeSpyTo(relay.req([{ kinds: [1] }], "sub1"));
71
+ // Verify REQ was sent
72
+ await expect(server).toReceiveMessage(["REQ", "sub1", { kinds: [1] }]);
57
73
  // Complete the subscription
58
74
  sub.unsubscribe();
59
75
  // Verify CLOSE was sent
60
- expect(await server.nextMessage).toEqual(["CLOSE", "sub1"]);
76
+ await expect(server).toReceiveMessage(["CLOSE", "sub1"]);
61
77
  });
62
78
  it("should emit nostr event and EOSE", async () => {
63
79
  const spy = subscribeSpyTo(relay.req([{ kinds: [1] }], "sub1"));
@@ -99,6 +115,14 @@ describe("req", () => {
99
115
  // Verify the subscription completed
100
116
  expect(spy.receivedError()).toBe(true);
101
117
  });
118
+ it("should not send multiple REQ messages for multiple subscriptions", async () => {
119
+ const sub = relay.req([{ kinds: [1] }], "sub1");
120
+ sub.subscribe();
121
+ sub.subscribe();
122
+ // Wait for all messages to be sent
123
+ await new Promise((resolve) => setTimeout(resolve, 10));
124
+ expect(server.messages).toEqual([["REQ", "sub1", { kinds: [1] }]]);
125
+ });
102
126
  it("should wait for authentication if relay responds with auth-required", async () => {
103
127
  // First subscription to trigger auth-required
104
128
  const firstSub = subscribeSpyTo(relay.req([{ kinds: [1] }], "sub1"), { expectErrors: true });
package/dist/relay.js CHANGED
@@ -187,13 +187,17 @@ export class Relay {
187
187
  }
188
188
  /** Wait for the relay to be ready to accept connections */
189
189
  waitForReady(observable) {
190
- return this.ready$.pipe(
191
- // wait for ready to be true
192
- filter((ready) => ready),
193
- // complete after the first value so this does not repeat
194
- take(1),
195
- // switch to the observable
196
- switchMap(() => observable));
190
+ // Don't wait if the relay is already ready
191
+ if (this.ready$.value)
192
+ return observable;
193
+ else
194
+ return this.ready$.pipe(
195
+ // wait for ready to be true
196
+ filter((ready) => ready),
197
+ // complete after the first value so this does not repeat
198
+ take(1),
199
+ // switch to the observable
200
+ switchMap(() => observable));
197
201
  }
198
202
  multiplex(open, close, filter) {
199
203
  return this.socket.multiplex(open, close, filter);
@@ -234,7 +238,9 @@ export class Relay {
234
238
  timeout({
235
239
  first: this.eoseTimeout,
236
240
  with: () => merge(of("EOSE"), NEVER),
237
- }));
241
+ }),
242
+ // Only create one upstream subscription
243
+ share());
238
244
  // Wait for auth if required and make sure to start the watch tower
239
245
  return this.waitForReady(this.waitForAuth(this.authRequiredForReq, observable));
240
246
  }
@@ -264,7 +270,9 @@ export class Relay {
264
270
  timeout({
265
271
  first: this.eventTimeout,
266
272
  with: () => of({ ok: false, from: this.url, message: "Timeout" }),
267
- }));
273
+ }),
274
+ // Only create one upstream subscription
275
+ share());
268
276
  // skip wait for auth if verb is AUTH
269
277
  if (verb === "AUTH")
270
278
  return this.waitForReady(observable);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "applesauce-relay",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "nostr relay communication framework built on rxjs",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",