applesauce-core 0.0.0-next-20250828144630 → 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.
- package/dist/helpers/app-data.d.ts +36 -0
- package/dist/helpers/app-data.js +67 -0
- package/dist/helpers/event-cache.d.ts +3 -1
- package/dist/helpers/event-cache.js +3 -1
- package/dist/helpers/event-tags.d.ts +6 -0
- package/dist/helpers/event-tags.js +4 -0
- package/dist/helpers/event.d.ts +2 -0
- package/dist/helpers/event.js +3 -0
- package/dist/helpers/filter.d.ts +1 -0
- package/dist/helpers/relays.d.ts +3 -1
- package/dist/helpers/relays.js +18 -2
- package/dist/observable/index.d.ts +1 -1
- package/dist/observable/index.js +1 -1
- package/dist/observable/map-events-to-store.d.ts +5 -3
- package/dist/observable/map-events-to-store.js +3 -1
- package/dist/observable/map-events-to-timeline.d.ts +7 -0
- package/dist/observable/map-events-to-timeline.js +12 -0
- package/package.json +2 -2
|
@@ -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
|
|
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
|
|
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);
|
package/dist/helpers/event.d.ts
CHANGED
|
@@ -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;
|
package/dist/helpers/event.js
CHANGED
|
@@ -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");
|
package/dist/helpers/filter.d.ts
CHANGED
package/dist/helpers/relays.d.ts
CHANGED
|
@@ -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;
|
package/dist/helpers/relays.js
CHANGED
|
@@ -23,9 +23,10 @@ export function mergeRelaySets(...sources) {
|
|
|
23
23
|
for (const src of sources) {
|
|
24
24
|
if (!src)
|
|
25
25
|
continue;
|
|
26
|
-
|
|
26
|
+
if (typeof src === "string") {
|
|
27
|
+
// Source is a string
|
|
27
28
|
try {
|
|
28
|
-
const safe = normalizeURL(
|
|
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";
|
package/dist/observable/index.js
CHANGED
|
@@ -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 {
|
|
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:
|
|
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
|
|
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-
|
|
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.
|
|
75
|
+
"vitest": "^3.2.4"
|
|
76
76
|
},
|
|
77
77
|
"funding": {
|
|
78
78
|
"type": "lightning",
|