clone

nostr relays on demand at <name>.bind.ws: claim one with your key, pay in zaps past the free allowance

dependabot/github_actions/actions-9b61906d8b
bindws / test / object / delivery.test.ts
delivery.test.ts 4.0K
1import { env, runInDurableObject } from "cloudflare:test";2import { deliveryTick, queueDelivery } from "../../src/delivery.ts";3import type { Relay } from "../../src/relay.ts";4import { describe, expect, it } from "vitest";5import { generateSecretKey } from "nostr-tools/pure";6import { ev, pk, rpc, alarm, sleep } from "../helpers/relay.ts";7import { WS } from "../helpers/ws.ts";89describe("NIP-65 automatic delivery", () => {10 it("retries a refused target to its finite limit and stops on private relay policy", async () => {11 const owner = generateSecretKey(), targetOwner = generateSecretKey();12 const source = "retry-source.bind.ws", target = "retry-target.bind.ws";13 await rpc(source, owner, "claim"); await rpc(target, targetOwner, "claim");14 await rpc(target, targetOwner, "setpolicy", { writes: "owner" });15 await rpc(source, owner, "setpolicy", { delivery: { enabled: true, maxTargets: 1 } });16 await runInDurableObject(env.RELAY.getByName("retry-source"), async (relay: Relay) => {17 relay.store.save(ev(owner, 10002, "", [["r", "wss://" + target]]), 1);18 const note = ev(owner, 1, "retry me"); relay.store.save(note, 1);19 expect(queueDelivery(relay, note)).toBe(true);20 for (let i = 0; i < 4; i++) {21 relay.sql.exec(`UPDATE delivery_queue SET due=0`);22 await deliveryTick(relay);23 }24 expect(relay.sql.exec(`SELECT status,attempts FROM delivery_queue WHERE event_id=?`, note.id).one()).toMatchObject({ status: "rejected", attempts: 4 });25 relay.settings.update({ reads: "members" });26 expect(queueDelivery(relay, ev(owner, 1, "private relay note"))).toBe(false);27 });28 });2930 it("routes public events to the author's write relay and exposes target status", async () => {31 const owner = generateSecretKey();32 const source = "auto-source.bind.ws", target = "auto-target.bind.ws";33 await rpc(target, generateSecretKey(), "claim");34 await rpc(source, owner, "claim");35 await rpc(source, owner, "setpolicy", { delivery: { enabled: true, maxTargets: 4 } });36 const targetSocket = await WS.connect(target);37 const sourceSocket = await WS.connect(source);38 const list = ev(owner, 10002, "", [["r", "wss://" + target, "write"]]);39 expect((await sourceSocket.ok(list)).ok).toBe(true);40 const note = ev(owner, 1, "routed");41 expect((await sourceSocket.ok(note)).ok).toBe(true);42 for (let attempt = 0; attempt < 40; attempt++) {43 await alarm("auto-source");44 const status = await runInDurableObject(env.RELAY.getByName("auto-source"), (relay: Relay) => relay.sql.exec<{ status: string }>(`SELECT status FROM delivery_queue WHERE event_id=?`, note.id).toArray()[0]?.status ?? "");45 if (status !== "pending") break;46 await sleep(25);47 }48 expect((await targetSocket.req({ ids: [note.id] })).map((e) => e.id)).toEqual([note.id]);49 const status = await rpc(source, owner, "deliverystatus");50 expect(status.result).toEqual(expect.arrayContaining([expect.objectContaining({ event_id: note.id, target: "wss://" + target, status: "accepted" })]));51 });5253 it("does not queue private or protected events", async () => {54 const owner = generateSecretKey(), friend = generateSecretKey();55 const source = "auto-filter.bind.ws", target = "auto-filter-target.bind.ws";56 await rpc(target, generateSecretKey(), "claim");57 await rpc(source, owner, "claim");58 await rpc(source, owner, "setpolicy", { delivery: { enabled: true, maxTargets: 4 } });59 const socket = await WS.connect(source);60 expect((await socket.ok(ev(owner, 10002, "", [["r", "wss://" + target, "write"]]))).ok).toBe(true);61 const dm = ev(owner, 4, "secret", [["p", pk(friend)]]);62 const protectedEvent = ev(owner, 1, "protected", [["-", ""]]);63 expect((await socket.ok(dm)).ok).toBe(true);64 expect((await socket.ok(protectedEvent)).ok).toBe(false);65 const status = await rpc(source, owner, "deliverystatus");66 expect(status.result.filter((x: any) => [dm.id, protectedEvent.id].includes(x.event_id))).toEqual([]);67 });68});