applesauce-core 0.0.0-next-20250221172959 → 0.0.0-next-20250308144838

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.
@@ -69,7 +69,7 @@ describe("verifyEvent", () => {
69
69
  expect(verifyEvent).toHaveBeenCalledTimes(1);
70
70
  });
71
71
  });
72
- describe("deleted", () => {
72
+ describe("removed", () => {
73
73
  it("should complete when event is removed", () => {
74
74
  eventStore.add(profile);
75
75
  const spy = subscribeSpyTo(eventStore.removed(profile.id));
@@ -223,6 +223,19 @@ describe("timeline", () => {
223
223
  eventStore.add(user.profile({ name: "old-name" }, { created_at: profile.created_at - 1000 }));
224
224
  expect(spy.getValues()).toEqual([[profile]]);
225
225
  });
226
+ it("should return new array for every value", () => {
227
+ const first = user.note("first note");
228
+ const second = user.note("second note");
229
+ const third = user.note("third note");
230
+ eventStore.add(first);
231
+ const spy = subscribeSpyTo(eventStore.timeline({ kinds: [0] }));
232
+ eventStore.add(second);
233
+ eventStore.add(third);
234
+ const hasDuplicates = (arr) => {
235
+ return new Set(arr).size !== arr.length;
236
+ };
237
+ expect(hasDuplicates(spy.getValues())).toBe(false);
238
+ });
226
239
  });
227
240
  describe("replaceableSet", () => {
228
241
  it("should not emit if there are not events", () => {
@@ -60,7 +60,7 @@ export declare class Database {
60
60
  iterateIds(ids: Iterable<string>): Generator<NostrEvent>;
61
61
  /** Returns all events that match the filter */
62
62
  getEventsForFilter(filter: Filter): Set<NostrEvent>;
63
- getForFilters(filters: Filter[]): Set<NostrEvent>;
63
+ getEventsForFilters(filters: Filter[]): Set<NostrEvent>;
64
64
  /** Remove the oldest events that are not claimed */
65
65
  prune(limit?: number): number;
66
66
  }
@@ -287,7 +287,7 @@ export class Database {
287
287
  }
288
288
  return events;
289
289
  }
290
- getForFilters(filters) {
290
+ getEventsForFilters(filters) {
291
291
  if (filters.length === 0)
292
292
  throw new Error("No Filters");
293
293
  let events = new Set();
@@ -36,6 +36,8 @@ export declare class EventStore {
36
36
  getReplaceable(kind: number, pubkey: string, d?: string): NostrEvent | undefined;
37
37
  /** Returns all versions of a replaceable event */
38
38
  getReplaceableHistory(kind: number, pubkey: string, d?: string): NostrEvent[] | undefined;
39
+ /** Returns a timeline of events that match filters */
40
+ getTimeline(filters: Filter | Filter[]): NostrEvent[];
39
41
  /**
40
42
  * Creates an observable that streams all events that match the filter and remains open
41
43
  * @param filters
@@ -117,7 +117,7 @@ export class EventStore {
117
117
  }
118
118
  /** Get all events matching a filter */
119
119
  getAll(filters) {
120
- return this.database.getForFilters(filters);
120
+ return this.database.getEventsForFilters(filters);
121
121
  }
122
122
  /** Check if the store has an event */
123
123
  hasEvent(uid) {
@@ -138,6 +138,10 @@ export class EventStore {
138
138
  getReplaceableHistory(kind, pubkey, d) {
139
139
  return this.database.getReplaceable(kind, pubkey, d);
140
140
  }
141
+ /** Returns a timeline of events that match filters */
142
+ getTimeline(filters) {
143
+ return Array.from(this.database.getEventsForFilters(Array.isArray(filters) ? filters : [filters])).sort(sortDesc);
144
+ }
141
145
  /**
142
146
  * Creates an observable that streams all events that match the filter and remains open
143
147
  * @param filters
@@ -278,7 +282,7 @@ export class EventStore {
278
282
  filters = Array.isArray(filters) ? filters : [filters];
279
283
  const seen = new Map();
280
284
  // get current events
281
- return defer(() => of(Array.from(this.database.getForFilters(filters)).sort(sortDesc))).pipe(
285
+ return defer(() => of(Array.from(this.database.getEventsForFilters(filters)).sort(sortDesc))).pipe(
282
286
  // claim existing events
283
287
  claimEvents(this.database),
284
288
  // subscribe to newer events
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,42 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { bytesToHex } from "@noble/hashes/utils";
3
+ import { normalizeToPubkey, normalizeToSecretKey } from "../nip-19.js";
4
+ describe("normalizeToPubkey", () => {
5
+ it("should get pubkey from npub", () => {
6
+ expect(normalizeToPubkey("npub1ye5ptcxfyyxl5vjvdjar2ua3f0hynkjzpx552mu5snj3qmx5pzjscpknpr")).toEqual("266815e0c9210dfa324c6cba3573b14bee49da4209a9456f9484e5106cd408a5");
7
+ });
8
+ it("should get pubkey from nprofile", () => {
9
+ expect(normalizeToPubkey("nprofile1qyw8wumn8ghj7umpw3jkcmrfw3jju6r6wfjrzdpe9e3k7mf0qyf8wumn8ghj7mn0wd68yat99e3k7mf0qqszv6q4uryjzr06xfxxew34wwc5hmjfmfpqn229d72gfegsdn2q3fg5g7lja")).toEqual("266815e0c9210dfa324c6cba3573b14bee49da4209a9456f9484e5106cd408a5");
10
+ });
11
+ it("should return hex pubkey", () => {
12
+ expect(normalizeToPubkey("266815e0c9210dfa324c6cba3573b14bee49da4209a9456f9484e5106cd408a5")).toEqual("266815e0c9210dfa324c6cba3573b14bee49da4209a9456f9484e5106cd408a5");
13
+ });
14
+ it("should throw on invalid hex pubkey", () => {
15
+ expect(() => {
16
+ normalizeToPubkey("5028372");
17
+ }).toThrow();
18
+ });
19
+ it("should throw on invalid string", () => {
20
+ expect(() => {
21
+ normalizeToPubkey("testing");
22
+ }).toThrow();
23
+ });
24
+ });
25
+ describe("normalizeToSecretKey", () => {
26
+ it("should get secret key from nsec", () => {
27
+ expect(bytesToHex(normalizeToSecretKey("nsec1xe7znq745x5n68566l32ru72aajz3pk2cys9lnf3tuexvkw0dldsj8v2lm"))).toEqual("367c2983d5a1a93d1e9ad7e2a1f3caef642886cac1205fcd315f326659cf6fdb");
28
+ });
29
+ it("should get secret key from raw hex", () => {
30
+ expect(bytesToHex(normalizeToSecretKey("367c2983d5a1a93d1e9ad7e2a1f3caef642886cac1205fcd315f326659cf6fdb"))).toEqual("367c2983d5a1a93d1e9ad7e2a1f3caef642886cac1205fcd315f326659cf6fdb");
31
+ });
32
+ it("should throw on invalid hex key", () => {
33
+ expect(() => {
34
+ normalizeToSecretKey("209573290");
35
+ }).toThrow();
36
+ });
37
+ it("should throw on npub", () => {
38
+ expect(() => {
39
+ normalizeToSecretKey("npub1ye5ptcxfyyxl5vjvdjar2ua3f0hynkjzpx552mu5snj3qmx5pzjscpknpr");
40
+ }).toThrow();
41
+ });
42
+ });
@@ -6,7 +6,7 @@ export const HiddenTagsSymbol = Symbol.for("hidden-tags");
6
6
  /** Various event kinds that can have encrypted tags in their content and which encryption method they use */
7
7
  export const EventEncryptionMethod = {
8
8
  // NIP-60 wallet
9
- 37375: "nip44",
9
+ 17375: "nip44",
10
10
  // NIP-51 lists
11
11
  [kinds.BookmarkList]: "nip04",
12
12
  [kinds.InterestsList]: "nip04",
@@ -0,0 +1,4 @@
1
+ /** Gets the hex pubkey from any nip-19 encoded string */
2
+ export declare function normalizeToPubkey(str: string): string;
3
+ /** Converts hex to nsec strings into Uint8 secret keys */
4
+ export declare function normalizeToSecretKey(str: string): Uint8Array;
@@ -0,0 +1,27 @@
1
+ import { nip19 } from "nostr-tools";
2
+ import { hexToBytes } from "@noble/hashes/utils";
3
+ import { isHexKey } from "./string.js";
4
+ import { getPubkeyFromDecodeResult } from "./pointers.js";
5
+ /** Gets the hex pubkey from any nip-19 encoded string */
6
+ export function normalizeToPubkey(str) {
7
+ if (isHexKey(str))
8
+ return str;
9
+ else {
10
+ const decode = nip19.decode(str);
11
+ const pubkey = getPubkeyFromDecodeResult(decode);
12
+ if (!pubkey)
13
+ throw new Error(`Cant find pubkey in ${decode.type}`);
14
+ return pubkey;
15
+ }
16
+ }
17
+ /** Converts hex to nsec strings into Uint8 secret keys */
18
+ export function normalizeToSecretKey(str) {
19
+ if (isHexKey(str))
20
+ return hexToBytes(str);
21
+ else {
22
+ const decode = nip19.decode(str);
23
+ if (decode.type !== "nsec")
24
+ throw new Error(`Cant get secret key from ${decode.type}`);
25
+ return decode.data;
26
+ }
27
+ }
@@ -45,6 +45,8 @@ export declare class QueryStore {
45
45
  inboxes: string[];
46
46
  outboxes: string[];
47
47
  } | undefined>;
48
+ /** Creates a query for a users blossom servers */
49
+ blossomServers(pubkey: string): Observable<URL[] | undefined>;
48
50
  /** Creates a ThreadQuery */
49
51
  thread(root: string | EventPointer | AddressPointer): Observable<Queries.Thread | undefined>;
50
52
  }
@@ -80,6 +80,10 @@ export class QueryStore {
80
80
  mailboxes(pubkey) {
81
81
  return this.createQuery(Queries.MailboxesQuery, pubkey);
82
82
  }
83
+ /** Creates a query for a users blossom servers */
84
+ blossomServers(pubkey) {
85
+ return this.createQuery(Queries.UserBlossomServersQuery, pubkey);
86
+ }
83
87
  /** Creates a ThreadQuery */
84
88
  thread(root) {
85
89
  return this.createQuery(Queries.ThreadQuery, root);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "applesauce-core",
3
- "version": "0.0.0-next-20250221172959",
3
+ "version": "0.0.0-next-20250308144838",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -62,6 +62,7 @@
62
62
  }
63
63
  },
64
64
  "dependencies": {
65
+ "@noble/hashes": "^1.7.1",
65
66
  "@scure/base": "^1.2.4",
66
67
  "debug": "^4.4.0",
67
68
  "fast-deep-equal": "^3.1.3",