applesauce-core 0.0.0-next-20250210210633 → 0.0.0-next-20250211165042

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.
@@ -1,3 +1,7 @@
1
+ /** A tag with at least two indexes, the first being the name, the second the value */
2
+ export type NameValueTag<Name extends string = string> = [Name, string, ...string[]];
3
+ /** Tests if a tag has at least two indexes, and optionally the value of the first */
4
+ export declare function isNameValueTag<Name extends string>(tag: string[], name?: Name): tag is NameValueTag<Name>;
1
5
  /** Checks if tag is an "e" tag and has at least one value */
2
6
  export declare function isETag(tag: string[]): tag is ["e", string, ...string[]];
3
7
  /** Checks if tag is an "p" tag and has at least one value */
@@ -1,26 +1,30 @@
1
+ /** Tests if a tag has at least two indexes, and optionally the value of the first */
2
+ export function isNameValueTag(tag, name) {
3
+ return tag[0] !== undefined && tag[1] !== undefined && (name ? tag[0] === name : true);
4
+ }
1
5
  /** Checks if tag is an "e" tag and has at least one value */
2
6
  export function isETag(tag) {
3
- return tag[0] === "e" && tag[1] !== undefined;
7
+ return isNameValueTag(tag, "e");
4
8
  }
5
9
  /** Checks if tag is an "p" tag and has at least one value */
6
10
  export function isPTag(tag) {
7
- return tag[0] === "p" && tag[1] !== undefined;
11
+ return isNameValueTag(tag, "p");
8
12
  }
9
13
  /** Checks if tag is an "r" tag and has at least one value */
10
14
  export function isRTag(tag) {
11
- return tag[0] === "r" && tag[1] !== undefined;
15
+ return isNameValueTag(tag, "r");
12
16
  }
13
17
  /** Checks if tag is an "d" tag and has at least one value */
14
18
  export function isDTag(tag) {
15
- return tag[0] === "d" && tag[1] !== undefined;
19
+ return isNameValueTag(tag, "d");
16
20
  }
17
21
  /** Checks if tag is an "a" tag and has at least one value */
18
22
  export function isATag(tag) {
19
- return tag[0] === "a" && tag[1] !== undefined;
23
+ return isNameValueTag(tag, "a");
20
24
  }
21
25
  /** Checks if tag is an "a" tag and has at least one value */
22
26
  export function isTTag(tag) {
23
- return tag[0] === "a" && tag[1] !== undefined;
27
+ return isNameValueTag(tag, "t");
24
28
  }
25
29
  /** Filter and transform tags */
26
30
  export const processTags = (tags, ...fns) => {
@@ -1,16 +1,24 @@
1
1
  import { describe, expect, it } from "vitest";
2
- import { isATag, processTags } from "./tags.js";
2
+ import { isATag, isNameValueTag, processTags } from "./tags.js";
3
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
- });
4
+ describe("isNameValueTag", () => {
5
+ it("should return true if tag has at least two indexes", () => {
6
+ expect(isNameValueTag(["a", "30000:pubkey:list"])).toBe(true);
7
+ expect(isNameValueTag(["title", "article", "other-value"])).toBe(true);
8
+ });
9
+ it("should ignore tags without values", () => {
10
+ expect(isNameValueTag(["a"])).toBe(false);
11
+ expect(isNameValueTag(["title"])).toBe(false);
12
+ });
13
+ });
14
+ describe("processTags", () => {
15
+ it("should filter out errors", () => {
16
+ expect(processTags([["a", "bad coordinate"], ["e"], ["a", "30000:pubkey:list"]], getAddressPointerFromATag)).toEqual([{ identifier: "list", kind: 30000, pubkey: "pubkey" }]);
17
+ });
18
+ it("should filter out undefined", () => {
19
+ expect(processTags([["a", "bad coordinate"], ["e"], ["a", "30000:pubkey:list"]], (tag) => isATag(tag) ? tag : undefined)).toEqual([
20
+ ["a", "bad coordinate"],
21
+ ["a", "30000:pubkey:list"],
22
+ ]);
15
23
  });
16
24
  });
@@ -12,3 +12,10 @@ export declare function isVideoURL(url: string | URL): boolean;
12
12
  export declare function isStreamURL(url: string | URL): boolean;
13
13
  /** Checks if a url is a audio URL */
14
14
  export declare function isAudioURL(url: string | URL): boolean;
15
+ /** Tests if two URLs are the same */
16
+ export declare function isSameURL(a: string | URL, b: string | URL): boolean;
17
+ /**
18
+ * Normalizes a string into a relay URL
19
+ * Does not remove the trailing slash
20
+ */
21
+ export declare function normalizeURL(url: string | URL): URL;
@@ -28,3 +28,33 @@ export function isAudioURL(url) {
28
28
  const filename = getURLFilename(url);
29
29
  return !!filename && AUDIO_EXT.some((ext) => filename.endsWith(ext));
30
30
  }
31
+ /** Tests if two URLs are the same */
32
+ export function isSameURL(a, b) {
33
+ try {
34
+ a = normalizeURL(a).toString();
35
+ b = normalizeURL(b).toString();
36
+ return a === b;
37
+ }
38
+ catch (error) {
39
+ return false;
40
+ }
41
+ }
42
+ /**
43
+ * Normalizes a string into a relay URL
44
+ * Does not remove the trailing slash
45
+ */
46
+ export function normalizeURL(url) {
47
+ if (typeof url === "string" && url.indexOf("://") === -1)
48
+ url = "wss://" + url;
49
+ let p = new URL(url);
50
+ // remove any double slashes
51
+ p.pathname = p.pathname.replace(/\/+/g, "/");
52
+ // drop the port if its not needed
53
+ if ((p.port === "80" && p.protocol === "ws:") || (p.port === "443" && p.protocol === "wss:"))
54
+ p.port = "";
55
+ // sort the query params
56
+ p.searchParams.sort();
57
+ // remove the hash
58
+ p.hash = "";
59
+ return p;
60
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "applesauce-core",
3
- "version": "0.0.0-next-20250210210633",
3
+ "version": "0.0.0-next-20250211165042",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -62,20 +62,20 @@
62
62
  }
63
63
  },
64
64
  "dependencies": {
65
- "@scure/base": "^1.1.9",
66
- "debug": "^4.3.7",
65
+ "@scure/base": "^1.2.4",
66
+ "debug": "^4.4.0",
67
67
  "fast-deep-equal": "^3.1.3",
68
68
  "hash-sum": "^2.0.0",
69
69
  "light-bolt11-decoder": "^3.2.0",
70
- "nanoid": "^5.0.7",
71
- "nostr-tools": "^2.10.3",
70
+ "nanoid": "^5.0.9",
71
+ "nostr-tools": "^2.10.4",
72
72
  "rxjs": "^7.8.1"
73
73
  },
74
74
  "devDependencies": {
75
75
  "@types/debug": "^4.1.12",
76
76
  "@types/hash-sum": "^1.0.2",
77
- "typescript": "^5.6.3",
78
- "vitest": "^2.1.8"
77
+ "typescript": "^5.7.3",
78
+ "vitest": "^3.0.5"
79
79
  },
80
80
  "funding": {
81
81
  "type": "lightning",