applesauce-core 0.0.0-next-20241213171848 → 0.0.0-next-20241219164005

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.
@@ -2,6 +2,7 @@ import { NostrEvent, VerifiedEvent } from "nostr-tools";
2
2
  export declare const EventUIDSymbol: unique symbol;
3
3
  export declare const EventIndexableTagsSymbol: unique symbol;
4
4
  export declare const FromCacheSymbol: unique symbol;
5
+ export declare const ReplaceableIdentifierSymbol: unique symbol;
5
6
  declare module "nostr-tools" {
6
7
  interface Event {
7
8
  [EventUIDSymbol]?: string;
@@ -40,3 +41,8 @@ export declare function fakeVerifyEvent(event: NostrEvent): event is VerifiedEve
40
41
  export declare function markFromCache(event: NostrEvent): void;
41
42
  /** Returns if an event was from a cache */
42
43
  export declare function isFromCache(event: NostrEvent): boolean;
44
+ /**
45
+ * Returns the replaceable identifier for a replaceable event
46
+ * @throws
47
+ */
48
+ export declare function getReplaceableIdentifier(event: NostrEvent): string;
@@ -1,9 +1,12 @@
1
1
  import { kinds, verifiedSymbol } from "nostr-tools";
2
2
  import { INDEXABLE_TAGS } from "../event-store/common.js";
3
3
  import { getHiddenTags } from "./hidden-tags.js";
4
+ import { getOrComputeCachedValue } from "./cache.js";
5
+ import { isParameterizedReplaceableKind } from "nostr-tools/kinds";
4
6
  export const EventUIDSymbol = Symbol.for("event-uid");
5
7
  export const EventIndexableTagsSymbol = Symbol.for("indexable-tags");
6
8
  export const FromCacheSymbol = Symbol.for("from-cache");
9
+ export const ReplaceableIdentifierSymbol = Symbol.for("replaceable-identifier");
7
10
  /**
8
11
  * Checks if an object is a nostr event
9
12
  * NOTE: does not validation the signature on the event
@@ -86,3 +89,17 @@ export function markFromCache(event) {
86
89
  export function isFromCache(event) {
87
90
  return !!event[FromCacheSymbol];
88
91
  }
92
+ /**
93
+ * Returns the replaceable identifier for a replaceable event
94
+ * @throws
95
+ */
96
+ export function getReplaceableIdentifier(event) {
97
+ if (!isParameterizedReplaceableKind(event.kind))
98
+ throw new Error("Event is not replaceable");
99
+ return getOrComputeCachedValue(event, ReplaceableIdentifierSymbol, () => {
100
+ const d = getTagValue(event, "d");
101
+ if (d === undefined)
102
+ throw new Error("Event missing identifier");
103
+ return d;
104
+ });
105
+ }
@@ -9,6 +9,7 @@ export * from "./external-id.js";
9
9
  export * from "./filter.js";
10
10
  export * from "./hashtag.js";
11
11
  export * from "./hidden-tags.js";
12
+ export * from "./json.js";
12
13
  export * from "./lnurl.js";
13
14
  export * from "./lru.js";
14
15
  export * from "./mailboxes.js";
@@ -9,6 +9,7 @@ export * from "./external-id.js";
9
9
  export * from "./filter.js";
10
10
  export * from "./hashtag.js";
11
11
  export * from "./hidden-tags.js";
12
+ export * from "./json.js";
12
13
  export * from "./lnurl.js";
13
14
  export * from "./lru.js";
14
15
  export * from "./mailboxes.js";
@@ -0,0 +1,10 @@
1
+ export type Pipe = {
2
+ <A>(a: A): A;
3
+ <A, B>(a: A, ab: (a: A) => B): B;
4
+ <A, B, C>(a: A, ab: (a: A) => B, bc: (b: B) => C): C;
5
+ <A, B, C, D>(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D): D;
6
+ <A, B, C, D, E>(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E): E;
7
+ <A, B, C, D, E, F>(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F): F;
8
+ <A, B, C, D, E, F, G>(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G): G;
9
+ };
10
+ export declare const pipe: Pipe;
@@ -0,0 +1,3 @@
1
+ export const pipe = (initial, ...fns) => {
2
+ return fns.reduce((acc, fn) => fn(acc), initial);
3
+ };
@@ -1,7 +1,7 @@
1
1
  import { naddrEncode, neventEncode, noteEncode, nprofileEncode, npubEncode, nsecEncode, } from "nostr-tools/nip19";
2
2
  import { getPublicKey, kinds } from "nostr-tools";
3
+ import { getReplaceableIdentifier } from "./event.js";
3
4
  import { safeRelayUrls } from "./relays.js";
4
- import { getTagValue } from "./index.js";
5
5
  import { isParameterizedReplaceableKind } from "nostr-tools/kinds";
6
6
  export function parseCoordinate(a, requireD = false, silent = true) {
7
7
  const parts = a.split(":");
@@ -157,9 +157,7 @@ export function getCoordinateFromAddressPointer(pointer) {
157
157
  export function getAddressPointerForEvent(event, relays) {
158
158
  if (!isParameterizedReplaceableKind(event.kind))
159
159
  throw new Error("Cant get AddressPointer for non-replaceable event");
160
- const d = getTagValue(event, "d");
161
- if (!d)
162
- throw new Error("Event missing identifier");
160
+ const d = getReplaceableIdentifier(event);
163
161
  return {
164
162
  identifier: d,
165
163
  kind: event.kind,
@@ -182,9 +180,7 @@ export function getEventPointerForEvent(event, relays) {
182
180
  /** Returns a pointer for a given event */
183
181
  export function getPointerForEvent(event, relays) {
184
182
  if (kinds.isParameterizedReplaceableKind(event.kind)) {
185
- const d = getTagValue(event, "d");
186
- if (!d)
187
- throw new Error("Event missing identifier");
183
+ const d = getReplaceableIdentifier(event);
188
184
  return {
189
185
  type: "naddr",
190
186
  data: {
@@ -10,3 +10,16 @@ export declare function isDTag(tag: string[]): tag is ["d", string, ...string[]]
10
10
  export declare function isATag(tag: string[]): tag is ["a", string, ...string[]];
11
11
  /** Checks if tag is an "a" tag and has at least one value */
12
12
  export declare function isTTag(tag: string[]): tag is ["t", string, ...string[]];
13
+ /** A pipeline that filters and maps each tag */
14
+ type TagPipe = {
15
+ <A>(tags: string[][], ta: (tag: string[]) => A | undefined): A[];
16
+ <A, B>(tags: string[][], ta: (tag: string[]) => A | undefined, ab: (a: A) => B | undefined): B[];
17
+ <A, B, C>(tags: string[][], ta: (tag: string[]) => A | undefined, ab: (a: A) => B | undefined, bc: (b: B) => C | undefined): C[];
18
+ <A, B, C, D>(tags: string[][], ta: (tag: string[]) => A | undefined, ab: (a: A) => B | undefined, bc: (b: B) => C | undefined, cd: (c: C) => D | undefined): D[];
19
+ <A, B, C, D, E>(tags: string[][], ta: (tag: string[]) => A | undefined, ab: (a: A) => B | undefined, bc: (b: B) => C | undefined, cd: (c: C) => D | undefined, de: (d: D) => E | undefined): E[];
20
+ <A, B, C, D, E, F>(tags: string[][], ta: (tag: string[]) => A | undefined, ab: (a: A) => B | undefined, bc: (b: B) => C | undefined, cd: (c: C) => D | undefined, de: (d: D) => E | undefined, ef: (e: E) => F | undefined): F[];
21
+ <A, B, C, D, E, F, G>(tags: string[][], ta: (tag: string[]) => A | undefined, ab: (a: A) => B | undefined, bc: (b: B) => C | undefined, cd: (c: C) => D | undefined, de: (d: D) => E | undefined, ef: (e: E) => F | undefined, fg: (f: F) => G | undefined): G[];
22
+ };
23
+ /** Filter and transform tags */
24
+ export declare const processTags: TagPipe;
25
+ export {};
@@ -22,3 +22,21 @@ export function isATag(tag) {
22
22
  export function isTTag(tag) {
23
23
  return tag[0] === "a" && tag[1] !== undefined;
24
24
  }
25
+ /** Filter and transform tags */
26
+ export const processTags = (tags, ...fns) => {
27
+ return fns.reduce((step, fn) => {
28
+ const next = [];
29
+ for (const value of step) {
30
+ try {
31
+ const result = fn(value);
32
+ if (result === undefined)
33
+ continue; // value is undefined, ignore
34
+ next.push(result);
35
+ }
36
+ catch (error) {
37
+ // failed to process value, ignore
38
+ }
39
+ }
40
+ return next;
41
+ }, tags);
42
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,16 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { isATag, processTags } from "./tags.js";
3
+ import { getAddressPointerFromATag } from "./pointers.js";
4
+ describe("tag helpers", () => {
5
+ describe("processTags", () => {
6
+ it("should filter out errors", () => {
7
+ expect(processTags([["a", "bad coordinate"], ["e"], ["a", "30000:pubkey:list"]], getAddressPointerFromATag)).toEqual([{ identifier: "list", kind: 30000, pubkey: "pubkey" }]);
8
+ });
9
+ it("should filter out undefined", () => {
10
+ expect(processTags([["a", "bad coordinate"], ["e"], ["a", "30000:pubkey:list"]], (tag) => isATag(tag) ? tag : undefined)).toEqual([
11
+ ["a", "bad coordinate"],
12
+ ["a", "30000:pubkey:list"],
13
+ ]);
14
+ });
15
+ });
16
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "applesauce-core",
3
- "version": "0.0.0-next-20241213171848",
3
+ "version": "0.0.0-next-20241219164005",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",