applesauce-core 0.0.0-next-20250828145754 → 0.0.0-next-20250912090040

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.
@@ -0,0 +1,36 @@
1
+ import { NostrEvent } from "nostr-tools";
2
+ import { EncryptionMethod } from "./encrypted-content.js";
3
+ import { HiddenContentSigner } from "./hidden-content.js";
4
+ export declare const APP_DATA_KIND = 30078;
5
+ export declare const AppDataContentSymbol: unique symbol;
6
+ /** Checks if an event has application data */
7
+ export declare function hasAppData<T extends {
8
+ kind: number;
9
+ content: string;
10
+ }>(event: T): boolean;
11
+ /** Checks if the application data is encrypted */
12
+ export declare function getAppDataEncryption<T extends {
13
+ kind: number;
14
+ content: string;
15
+ }>(event: T): EncryptionMethod | undefined;
16
+ /** Checks if the application data is locked (encrypted and not decrypted) */
17
+ export declare function isAppDataLocked<T extends object>(event: T): boolean;
18
+ /** Returns the parsed application data for an event if it's unlocked */
19
+ export declare function getAppDataContent<R extends unknown = unknown, T extends {
20
+ kind: number;
21
+ content: string;
22
+ } = NostrEvent>(event: T): R | undefined;
23
+ /**
24
+ * Unlocks the encrypted application data in the event
25
+ * @param event The event with encrypted content to decrypt
26
+ * @param signer A signer to use to decrypt the content
27
+ * @param override The encryption method to use instead of the default
28
+ * @returns The decrypted application data
29
+ */
30
+ export declare function unlockAppData<R extends unknown = unknown, T extends {
31
+ kind: number;
32
+ pubkey: string;
33
+ content: string;
34
+ } = NostrEvent>(event: T, signer: HiddenContentSigner, override?: EncryptionMethod): Promise<R>;
35
+ /** Removes the unencrypted application data cache on an event */
36
+ export declare function lockAppData<T extends object>(event: T): void;
@@ -0,0 +1,67 @@
1
+ import { isNIP04Encrypted } from "./encryption.js";
2
+ import { getHiddenContent, isHiddenContentLocked, lockHiddenContent, setHiddenContentEncryptionMethod, unlockHiddenContent, } from "./hidden-content.js";
3
+ import { safeParse } from "./json.js";
4
+ // NIP-78 Application Data event kind
5
+ export const APP_DATA_KIND = 30078;
6
+ export const AppDataContentSymbol = Symbol.for("app-data-content");
7
+ // Set the encryption method for app data events (default to nip44)
8
+ setHiddenContentEncryptionMethod(APP_DATA_KIND, "nip44");
9
+ /** Checks if an event has application data */
10
+ export function hasAppData(event) {
11
+ return event.kind === APP_DATA_KIND && event.content.length > 0;
12
+ }
13
+ /** Checks if the application data is encrypted */
14
+ export function getAppDataEncryption(event) {
15
+ // If content is empty, it can't be encrypted
16
+ if (event.content.length === 0)
17
+ return undefined;
18
+ // Try to parse as JSON - if it fails, it's likely encrypted
19
+ const parsed = safeParse(event.content);
20
+ if (parsed !== undefined)
21
+ return undefined;
22
+ return isNIP04Encrypted(event.content) ? "nip04" : "nip44";
23
+ }
24
+ /** Checks if the application data is locked (encrypted and not decrypted) */
25
+ export function isAppDataLocked(event) {
26
+ return isHiddenContentLocked(event);
27
+ }
28
+ /** Returns the parsed application data for an event if it's unlocked */
29
+ export function getAppDataContent(event) {
30
+ const cached = Reflect.get(event, AppDataContentSymbol);
31
+ if (cached)
32
+ return cached;
33
+ // If content is empty, return undefined
34
+ if (event.content.length === 0)
35
+ return undefined;
36
+ let data = getAppDataEncryption(event) ? undefined : safeParse(event.content);
37
+ if (!data) {
38
+ const decrypted = getHiddenContent(event);
39
+ if (decrypted)
40
+ data = safeParse(decrypted);
41
+ }
42
+ if (!data)
43
+ return undefined;
44
+ Reflect.set(event, AppDataContentSymbol, data);
45
+ return data;
46
+ }
47
+ /**
48
+ * Unlocks the encrypted application data in the event
49
+ * @param event The event with encrypted content to decrypt
50
+ * @param signer A signer to use to decrypt the content
51
+ * @param override The encryption method to use instead of the default
52
+ * @returns The decrypted application data
53
+ */
54
+ export async function unlockAppData(event, signer, override) {
55
+ if (!getAppDataEncryption(event))
56
+ return getAppDataContent(event);
57
+ const method = override ?? getAppDataEncryption(event);
58
+ const plaintext = await unlockHiddenContent(event, signer, method);
59
+ const parsed = safeParse(plaintext);
60
+ if (parsed === undefined)
61
+ throw new Error("Failed to parse decrypted application data as JSON");
62
+ return parsed;
63
+ }
64
+ /** Removes the unencrypted application data cache on an event */
65
+ export function lockAppData(event) {
66
+ lockHiddenContent(event);
67
+ }
@@ -9,7 +9,9 @@ import { IEventStoreStreams } from "../event-store/interface.js";
9
9
  * @param opts.maxBatchSize - The maximum number of events to write in a batch
10
10
  * @returns A function to stop the process
11
11
  */
12
- export declare function presistEventsToCache(eventStore: IEventStoreStreams, write: (events: NostrEvent[]) => Promise<void>, opts?: {
12
+ export declare function persistEventsToCache(eventStore: IEventStoreStreams, write: (events: NostrEvent[]) => Promise<void>, opts?: {
13
13
  maxBatchSize?: number;
14
14
  batchTime?: number;
15
15
  }): () => void;
16
+ /** @deprecated Use persistEventsToCache instead */
17
+ export declare const presistEventsToCache: typeof persistEventsToCache;
@@ -11,7 +11,7 @@ const log = logger.extend("event-cache");
11
11
  * @param opts.maxBatchSize - The maximum number of events to write in a batch
12
12
  * @returns A function to stop the process
13
13
  */
14
- export function presistEventsToCache(eventStore, write, opts) {
14
+ export function persistEventsToCache(eventStore, write, opts) {
15
15
  const time = opts?.batchTime ?? 5_000;
16
16
  // Save all new events to the cache
17
17
  const sub = eventStore.insert$
@@ -30,3 +30,5 @@ export function presistEventsToCache(eventStore, write, opts) {
30
30
  });
31
31
  return () => sub.unsubscribe();
32
32
  }
33
+ /** @deprecated Use persistEventsToCache instead */
34
+ export const presistEventsToCache = persistEventsToCache;
@@ -10,5 +10,11 @@ export declare function getTagValue<T extends {
10
10
  tags: string[][];
11
11
  content: string;
12
12
  }>(event: T, name: string): string | undefined;
13
+ /** Checks if an event has a public name / value tag*/
14
+ export declare function hasNameValueTag<T extends {
15
+ kind: number;
16
+ tags: string[][];
17
+ content: string;
18
+ }>(event: T, name: string, value: string): boolean;
13
19
  /** Returns a Set of tag names and values that are indexable */
14
20
  export declare function getIndexableTags(event: NostrEvent): Set<string>;
@@ -13,6 +13,10 @@ export function getTagValue(event, name) {
13
13
  return hiddenValue;
14
14
  return event.tags.find((t) => t[0] === name)?.[1];
15
15
  }
16
+ /** Checks if an event has a public name / value tag*/
17
+ export function hasNameValueTag(event, name, value) {
18
+ return event.tags.some((t) => t[0] === name && t[1] === value);
19
+ }
16
20
  /** Returns a Set of tag names and values that are indexable */
17
21
  export function getIndexableTags(event) {
18
22
  let indexable = Reflect.get(event, EventIndexableTagsSymbol);
@@ -1,5 +1,7 @@
1
1
  import { NostrEvent, VerifiedEvent } from "nostr-tools";
2
2
  import { IEventStore } from "../event-store/interface.js";
3
+ export { NostrEvent, EventTemplate, UnsignedEvent, verifiedSymbol } from "nostr-tools/pure";
4
+ export * as kinds from "nostr-tools/kinds";
3
5
  /** A symbol on an event that marks which event store its part of */
4
6
  export declare const EventStoreSymbol: unique symbol;
5
7
  export declare const EventUIDSymbol: unique symbol;
@@ -1,6 +1,9 @@
1
1
  import { verifiedSymbol } from "nostr-tools";
2
2
  import { isAddressableKind, isReplaceableKind } from "nostr-tools/kinds";
3
3
  import { getOrComputeCachedValue } from "./cache.js";
4
+ // Re-export types from nostr-tools
5
+ export { verifiedSymbol } from "nostr-tools/pure";
6
+ export * as kinds from "nostr-tools/kinds";
4
7
  /** A symbol on an event that marks which event store its part of */
5
8
  export const EventStoreSymbol = Symbol.for("event-store");
6
9
  export const EventUIDSymbol = Symbol.for("event-uid");
@@ -1,4 +1,5 @@
1
1
  import { Filter, NostrEvent } from "nostr-tools";
2
+ export { Filter } from "nostr-tools/filter";
2
3
  /**
3
4
  * Copied from nostr-tools and modified to use getIndexableTags
4
5
  * @see https://github.com/nbd-wtf/nostr-tools/blob/a61cde77eacc9518001f11d7f67f1a50ae05fd80/filter.ts
@@ -12,4 +12,6 @@ export declare function getSeenRelays(event: NostrEvent): Set<string> | undefine
12
12
  /** A fast check to make sure relay hints are safe to connect to */
13
13
  export declare function isSafeRelayURL(relay: string): boolean;
14
14
  /** Merge multiple sets of relays and remove duplicates (ignores invalid URLs) */
15
- export declare function mergeRelaySets(...sources: (Iterable<string> | undefined)[]): string[];
15
+ export declare function mergeRelaySets(...sources: (Iterable<string> | string | undefined)[]): string[];
16
+ /** Alias for {@link mergeRelaySets} */
17
+ export declare const relaySet: typeof mergeRelaySets;
@@ -23,9 +23,10 @@ export function mergeRelaySets(...sources) {
23
23
  for (const src of sources) {
24
24
  if (!src)
25
25
  continue;
26
- for (const url of src) {
26
+ if (typeof src === "string") {
27
+ // Source is a string
27
28
  try {
28
- const safe = normalizeURL(url).toString();
29
+ const safe = normalizeURL(src).toString();
29
30
  if (safe)
30
31
  set.add(safe);
31
32
  }
@@ -33,6 +34,21 @@ export function mergeRelaySets(...sources) {
33
34
  // failed to parse URL, ignore
34
35
  }
35
36
  }
37
+ else {
38
+ // Source is iterable
39
+ for (const url of src) {
40
+ try {
41
+ const safe = normalizeURL(url).toString();
42
+ if (safe)
43
+ set.add(safe);
44
+ }
45
+ catch (error) {
46
+ // failed to parse URL, ignore
47
+ }
48
+ }
49
+ }
36
50
  }
37
51
  return Array.from(set);
38
52
  }
53
+ /** Alias for {@link mergeRelaySets} */
54
+ export const relaySet = mergeRelaySets;
@@ -1,7 +1,7 @@
1
1
  import { firstValueFrom, lastValueFrom } from "rxjs";
2
2
  export * from "./defined.js";
3
3
  export * from "./get-observable-value.js";
4
- export * from "./map-events-timeline.js";
4
+ export * from "./map-events-to-timeline.js";
5
5
  export * from "./map-events-to-store.js";
6
6
  export * from "./simple-timeout.js";
7
7
  export * from "./watch-event-updates.js";
@@ -1,7 +1,7 @@
1
1
  import { firstValueFrom, lastValueFrom } from "rxjs";
2
2
  export * from "./defined.js";
3
3
  export * from "./get-observable-value.js";
4
- export * from "./map-events-timeline.js";
4
+ export * from "./map-events-to-timeline.js";
5
5
  export * from "./map-events-to-store.js";
6
6
  export * from "./simple-timeout.js";
7
7
  export * from "./watch-event-updates.js";
@@ -1,5 +1,7 @@
1
- import { MonoTypeOperatorFunction } from "rxjs";
2
1
  import { NostrEvent } from "nostr-tools";
3
- import { IEventStore } from "../event-store/interface.js";
2
+ import { MonoTypeOperatorFunction } from "rxjs";
3
+ import { IEventStoreActions } from "../event-store/interface.js";
4
4
  /** Saves all events to an event store and filters out invalid events */
5
- export declare function mapEventsToStore(store: IEventStore, removeDuplicates?: boolean): MonoTypeOperatorFunction<NostrEvent>;
5
+ export declare function mapEventsToStore(store: IEventStoreActions, removeDuplicates?: boolean): MonoTypeOperatorFunction<NostrEvent>;
6
+ /** Alias for {@link mapEventsToStore} */
7
+ export declare const filterDuplicateEvents: (store: IEventStoreActions) => MonoTypeOperatorFunction<import("nostr-tools").Event>;
@@ -3,10 +3,12 @@ import { distinct, filter, identity, map } from "rxjs";
3
3
  export function mapEventsToStore(store, removeDuplicates = true) {
4
4
  return (source) => source.pipe(
5
5
  // Map all events to the store
6
- // NOTE: map is used here because we want to return the single cononical version of the event so that distinct() can be used later
6
+ // NOTE: map is used here because we want to return the single instance of the event so that distinct() can be used later
7
7
  map((event) => store.add(event)),
8
8
  // Ignore invalid events
9
9
  filter((e) => e !== null),
10
10
  // Remove duplicates if requested
11
11
  removeDuplicates ? distinct() : identity);
12
12
  }
13
+ /** Alias for {@link mapEventsToStore} */
14
+ export const filterDuplicateEvents = (store) => mapEventsToStore(store, true);
@@ -0,0 +1,7 @@
1
+ import { NostrEvent } from "nostr-tools";
2
+ import { OperatorFunction } from "rxjs";
3
+ /**
4
+ * Accumulate events into an ordered timeline
5
+ * @note This does not remove duplicate events
6
+ */
7
+ export declare function mapEventsToTimeline(): OperatorFunction<NostrEvent, NostrEvent[]>;
@@ -0,0 +1,12 @@
1
+ import { insertEventIntoDescendingList } from "nostr-tools/utils";
2
+ import { pipe, scan } from "rxjs";
3
+ import { withImmediateValueOrDefault } from "./with-immediate-value.js";
4
+ /**
5
+ * Accumulate events into an ordered timeline
6
+ * @note This does not remove duplicate events
7
+ */
8
+ export function mapEventsToTimeline() {
9
+ return pipe(scan((timeline, event) => insertEventIntoDescendingList(timeline, event), []),
10
+ // Emit an empty array first. This is to prevent empty observables completing without a value (EMPTY)
11
+ withImmediateValueOrDefault([]));
12
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "applesauce-core",
3
- "version": "0.0.0-next-20250828145754",
3
+ "version": "0.0.0-next-20250912090040",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -72,7 +72,7 @@
72
72
  "@types/debug": "^4.1.12",
73
73
  "@types/hash-sum": "^1.0.2",
74
74
  "typescript": "^5.8.3",
75
- "vitest": "^3.2.3"
75
+ "vitest": "^3.2.4"
76
76
  },
77
77
  "funding": {
78
78
  "type": "lightning",