applesauce-common 0.0.0-next-20251220152312 → 0.0.0-next-20251231055351

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.
Files changed (58) hide show
  1. package/README.md +45 -4
  2. package/dist/blueprints/__register__.d.ts +1 -0
  3. package/dist/blueprints/__register__.js +1 -0
  4. package/dist/blueprints/comment.d.ts +3 -2
  5. package/dist/blueprints/torrent.d.ts +7 -0
  6. package/dist/blueprints/torrent.js +5 -1
  7. package/dist/casts/article.d.ts +2 -0
  8. package/dist/casts/article.js +6 -0
  9. package/dist/casts/bookmarks.d.ts +3 -3
  10. package/dist/casts/bookmarks.js +18 -6
  11. package/dist/casts/comment.d.ts +2 -0
  12. package/dist/casts/comment.js +5 -0
  13. package/dist/casts/groups.d.ts +19 -0
  14. package/dist/casts/groups.js +43 -0
  15. package/dist/casts/index.d.ts +6 -0
  16. package/dist/casts/index.js +6 -0
  17. package/dist/casts/note.d.ts +8 -0
  18. package/dist/casts/note.js +30 -0
  19. package/dist/casts/profile.d.ts +8 -0
  20. package/dist/casts/profile.js +12 -0
  21. package/dist/casts/reaction.d.ts +17 -0
  22. package/dist/casts/reaction.js +46 -0
  23. package/dist/casts/relay-discovery.d.ts +29 -0
  24. package/dist/casts/relay-discovery.js +54 -0
  25. package/dist/casts/relay-monitor.d.ts +21 -0
  26. package/dist/casts/relay-monitor.js +41 -0
  27. package/dist/casts/report.d.ts +31 -0
  28. package/dist/casts/report.js +74 -0
  29. package/dist/casts/share.d.ts +2 -0
  30. package/dist/casts/share.js +6 -0
  31. package/dist/casts/torrent.d.ts +31 -0
  32. package/dist/casts/torrent.js +62 -0
  33. package/dist/casts/user.d.ts +2 -0
  34. package/dist/casts/user.js +13 -1
  35. package/dist/helpers/calendar-event.d.ts +7 -1
  36. package/dist/helpers/calendar-event.js +8 -10
  37. package/dist/helpers/channels.d.ts +1 -1
  38. package/dist/helpers/channels.js +5 -8
  39. package/dist/helpers/comment.d.ts +3 -1
  40. package/dist/helpers/comment.js +12 -2
  41. package/dist/helpers/external-id.d.ts +32 -0
  42. package/dist/helpers/external-id.js +85 -0
  43. package/dist/helpers/file-metadata.d.ts +1 -4
  44. package/dist/helpers/file-metadata.js +1 -4
  45. package/dist/helpers/groups.d.ts +11 -1
  46. package/dist/helpers/groups.js +30 -5
  47. package/dist/helpers/reports.d.ts +4 -1
  48. package/dist/helpers/reports.js +14 -10
  49. package/dist/models/blossom.d.ts +2 -2
  50. package/dist/models/blossom.js +1 -1
  51. package/dist/models/channels.js +3 -9
  52. package/dist/models/comments.d.ts +3 -2
  53. package/dist/models/comments.js +19 -1
  54. package/dist/operations/comment.d.ts +3 -2
  55. package/dist/operations/comment.js +19 -5
  56. package/dist/operations/torrent.d.ts +2 -0
  57. package/dist/operations/torrent.js +4 -0
  58. package/package.json +2 -2
@@ -1,4 +1,5 @@
1
1
  import { NostrEvent } from "applesauce-core/helpers/event";
2
+ import { HiddenContentSigner } from "applesauce-core/helpers/hidden-content";
2
3
  export declare const GROUPS_LIST_KIND = 10009;
3
4
  export declare const GROUP_MESSAGE_KIND = 9;
4
5
  export declare const GROUP_METADATA_KIND = 39000;
@@ -35,8 +36,17 @@ export declare function getGroupPointerFromHTag(tag: string[], hint?: string): G
35
36
  export declare function getGroupPointerFromGroupTag(tag: string[]): GroupPointer;
36
37
  /** Returns all the public groups from a k:10009 list */
37
38
  export declare function getPublicGroups(bookmark: NostrEvent): GroupPointer[];
39
+ /** Type for unlocked groups */
40
+ export type UnlockedGroups = {
41
+ [GroupsHiddenSymbol]: GroupPointer[];
42
+ };
38
43
  /** Returns all the hidden groups from a k:10009 list */
39
- export declare function getHiddenGroups(bookmark: NostrEvent): GroupPointer[] | undefined;
44
+ export declare function getHiddenGroups<T extends NostrEvent & UnlockedGroups>(bookmark: T): GroupPointer[];
45
+ export declare function getHiddenGroups<T extends NostrEvent>(bookmark: T): GroupPointer[] | undefined;
46
+ /** Checks if the hidden groups are unlocked */
47
+ export declare function isHiddenGroupsUnlocked<T extends NostrEvent>(bookmark: T): bookmark is T & UnlockedGroups;
48
+ /** Unlocks the hidden groups on a groups event */
49
+ export declare function unlockHiddenGroups(bookmark: NostrEvent, signer: HiddenContentSigner): Promise<GroupPointer[]>;
40
50
  /** Gets a {@link GroupPointer} from a group event by reading the "h" tag */
41
51
  export declare function getGroupPointer(event: NostrEvent, relay?: string): GroupPointer | undefined;
42
52
  /** Gets the group id from a group event by reading the "h" tag */
@@ -1,6 +1,6 @@
1
- import { getOrComputeCachedValue } from "applesauce-core/helpers/cache";
1
+ import { getOrComputeCachedValue, notifyEventUpdate } from "applesauce-core/helpers";
2
2
  import { getReplaceableIdentifier, getTagValue } from "applesauce-core/helpers/event";
3
- import { getHiddenTags } from "applesauce-core/helpers/hidden-tags";
3
+ import { getHiddenTags, isHiddenTagsUnlocked, unlockHiddenTags } from "applesauce-core/helpers/hidden-tags";
4
4
  import { processTags } from "applesauce-core/helpers/tags";
5
5
  import { normalizeURL } from "applesauce-core/helpers/url";
6
6
  export const GROUPS_LIST_KIND = 10009;
@@ -56,14 +56,39 @@ export function getGroupPointerFromGroupTag(tag) {
56
56
  export function getPublicGroups(bookmark) {
57
57
  return getOrComputeCachedValue(bookmark, GroupsPublicSymbol, () => processTags(bookmark.tags.filter((t) => t[0] === "group"), getGroupPointerFromGroupTag));
58
58
  }
59
- /** Returns all the hidden groups from a k:10009 list */
60
59
  export function getHiddenGroups(bookmark) {
60
+ if (GroupsHiddenSymbol in bookmark)
61
+ return bookmark[GroupsHiddenSymbol];
61
62
  return getOrComputeCachedValue(bookmark, GroupsHiddenSymbol, () => {
63
+ //get hidden tags
62
64
  const tags = getHiddenTags(bookmark);
63
- return (tags &&
64
- processTags(bookmark.tags.filter((t) => t[0] === "group"), getGroupPointerFromGroupTag));
65
+ if (!tags)
66
+ return undefined;
67
+ // parse groups from hidden tags
68
+ const groups = processTags(tags.filter((t) => t[0] === "group"), getGroupPointerFromGroupTag);
69
+ // set cached value
70
+ Reflect.set(bookmark, GroupsHiddenSymbol, groups);
71
+ return groups;
65
72
  });
66
73
  }
74
+ /** Checks if the hidden groups are unlocked */
75
+ export function isHiddenGroupsUnlocked(bookmark) {
76
+ return isHiddenTagsUnlocked(bookmark) && (GroupsHiddenSymbol in bookmark || getHiddenGroups(bookmark) !== undefined);
77
+ }
78
+ /** Unlocks the hidden groups on a groups event */
79
+ export async function unlockHiddenGroups(bookmark, signer) {
80
+ if (isHiddenGroupsUnlocked(bookmark))
81
+ return bookmark[GroupsHiddenSymbol];
82
+ // unlock hidden tags
83
+ await unlockHiddenTags(bookmark, signer);
84
+ // get hidden groups
85
+ const groups = getHiddenGroups(bookmark);
86
+ if (!groups)
87
+ throw new Error("Failed to unlock hidden groups");
88
+ // notify event store
89
+ notifyEventUpdate(bookmark);
90
+ return groups;
91
+ }
67
92
  /** Gets a {@link GroupPointer} from a group event by reading the "h" tag */
68
93
  export function getGroupPointer(event, relay) {
69
94
  const hTag = event.tags.find((t) => t[0] === "h");
@@ -14,6 +14,7 @@ export type ReportedUser = {
14
14
  event: NostrEvent;
15
15
  pubkey: string;
16
16
  reason?: ReportReason;
17
+ comment?: string;
17
18
  };
18
19
  export type ReportedEvent = {
19
20
  type: "event";
@@ -25,4 +26,6 @@ export type ReportedEvent = {
25
26
  blobs?: string[];
26
27
  };
27
28
  /** Reads a report event as either a user or event report */
28
- export declare function getReported(report: NostrEvent): ReportedEvent | ReportedUser;
29
+ export declare function getReported(report: NostrEvent): ReportedEvent | ReportedUser | null;
30
+ /** Gets the server tags from a report event (for blob reports) */
31
+ export declare function getReportServers(report: NostrEvent): string[];
@@ -1,5 +1,5 @@
1
1
  import { getOrComputeCachedValue } from "applesauce-core/helpers/cache";
2
- import { isETag, isPTag } from "applesauce-core/helpers/tags";
2
+ import { isETag, isNameValueTag, isPTag } from "applesauce-core/helpers/tags";
3
3
  export const ParsedReportSymbol = Symbol("parsed-report");
4
4
  export var ReportReason;
5
5
  (function (ReportReason) {
@@ -14,25 +14,29 @@ export var ReportReason;
14
14
  /** Reads a report event as either a user or event report */
15
15
  export function getReported(report) {
16
16
  return getOrComputeCachedValue(report, ParsedReportSymbol, () => {
17
- const p = report.tags.find(isPTag);
18
- if (!p)
19
- throw new Error("Report missing p tag");
17
+ const pTag = report.tags.find(isPTag);
18
+ if (!pTag)
19
+ return null;
20
20
  const comment = report.content ? report.content.trim() : undefined;
21
- const e = report.tags.find(isETag);
21
+ const eTag = report.tags.find(isETag);
22
22
  // Event report
23
- if (e) {
23
+ if (eTag) {
24
24
  const blobs = report.tags.filter((t) => t[0] === "x" && t[1]).map((t) => t[1]);
25
25
  return {
26
26
  type: "event",
27
27
  event: report,
28
28
  comment,
29
- id: e[1],
30
- pubkey: p[1],
31
- reason: e[2],
29
+ id: eTag[1],
30
+ pubkey: pTag[1],
31
+ reason: eTag[2],
32
32
  blobs,
33
33
  };
34
34
  }
35
35
  // User report
36
- return { type: "user", event: report, comment, pubkey: p[1], reason: p[2] };
36
+ return { type: "user", event: report, comment, pubkey: pTag[1], reason: pTag[2] };
37
37
  });
38
38
  }
39
+ /** Gets the server tags from a report event (for blob reports) */
40
+ export function getReportServers(report) {
41
+ return report.tags.filter((t) => isNameValueTag(t, "server") && t[1]).map((t) => t[1]);
42
+ }
@@ -2,10 +2,10 @@ import { Model } from "applesauce-core/event-store";
2
2
  import { ProfilePointer } from "applesauce-core/helpers/pointers";
3
3
  import { type Observable } from "rxjs";
4
4
  /** A model that returns a users blossom servers */
5
- export declare function UserBlossomServersModel(user: string | ProfilePointer): Model<URL[]>;
5
+ export declare function UserBlossomServersModel(user: string | ProfilePointer): Model<URL[] | undefined>;
6
6
  declare module "applesauce-core/event-store" {
7
7
  interface EventModels {
8
8
  /** Subscribe to a users blossom servers */
9
- blossomServers(user: string | ProfilePointer): Observable<URL[]>;
9
+ blossomServers(user: string | ProfilePointer): Observable<URL[] | undefined>;
10
10
  }
11
11
  }
@@ -8,7 +8,7 @@ export function UserBlossomServersModel(user) {
8
8
  user = { pubkey: user };
9
9
  return (store) => store
10
10
  .replaceable({ kind: BLOSSOM_SERVER_LIST_KIND, pubkey: user.pubkey, relays: user.relays })
11
- .pipe(map((event) => (event ? getBlossomServersFromList(event) : [])));
11
+ .pipe(map((event) => event && getBlossomServersFromList(event)));
12
12
  }
13
13
  // Register this model with EventModels
14
14
  EventModels.prototype.blossomServers = function (user) {
@@ -31,15 +31,9 @@ export function ChannelMetadataModel(channel) {
31
31
  ];
32
32
  let latest = channel;
33
33
  return events.filters(filters).pipe(map((event) => {
34
- try {
35
- if (event.pubkey === latest.pubkey && event.created_at > latest.created_at) {
36
- latest = event;
37
- }
38
- return getChannelMetadataContent(latest);
39
- }
40
- catch (error) {
41
- return undefined;
42
- }
34
+ if (event.pubkey === latest.pubkey && event.created_at > latest.created_at)
35
+ latest = event;
36
+ return getChannelMetadataContent(latest) ?? undefined;
43
37
  }));
44
38
  };
45
39
  }
@@ -1,11 +1,12 @@
1
1
  import { Model } from "applesauce-core/event-store";
2
2
  import { NostrEvent } from "applesauce-core/helpers/event";
3
3
  import { type Observable } from "rxjs";
4
+ import { CommentPointer } from "../helpers/comment.js";
4
5
  /** A model that returns all NIP-22 comment replies for the event */
5
- export declare function CommentsModel(parent: NostrEvent): Model<NostrEvent[]>;
6
+ export declare function CommentsModel(parent: NostrEvent | CommentPointer): Model<NostrEvent[]>;
6
7
  declare module "applesauce-core/event-store" {
7
8
  interface EventModels {
8
9
  /** Subscribe to an event's comments */
9
- comments(event: NostrEvent): Observable<NostrEvent[]>;
10
+ comments(event: NostrEvent | CommentPointer): Observable<NostrEvent[]>;
10
11
  }
11
12
  }
@@ -1,9 +1,27 @@
1
1
  import { EventModels } from "applesauce-core/event-store";
2
+ import { createReplaceableAddress, isEvent } from "applesauce-core/helpers/event";
2
3
  import { buildCommonEventRelationFilters } from "applesauce-core/helpers/model";
4
+ import { of } from "rxjs";
3
5
  import { COMMENT_KIND } from "../helpers/comment.js";
4
6
  /** A model that returns all NIP-22 comment replies for the event */
5
7
  export function CommentsModel(parent) {
6
- return (events) => events.timeline(buildCommonEventRelationFilters({ kinds: [COMMENT_KIND] }, parent));
8
+ return (events) => {
9
+ if (isEvent(parent))
10
+ return events.timeline(buildCommonEventRelationFilters({ kinds: [COMMENT_KIND] }, parent));
11
+ else {
12
+ switch (parent.type) {
13
+ case "event":
14
+ return events.timeline({ kinds: [COMMENT_KIND], "#e": [parent.id] });
15
+ case "address":
16
+ return events.timeline({
17
+ kinds: [COMMENT_KIND],
18
+ "#a": [createReplaceableAddress(parent.kind, parent.pubkey, parent.identifier)],
19
+ });
20
+ default:
21
+ return of([]);
22
+ }
23
+ }
24
+ };
7
25
  }
8
26
  // Register this model with EventModels
9
27
  EventModels.prototype.comments = function (event) {
@@ -1,4 +1,5 @@
1
1
  import { EventOperation } from "applesauce-core/event-factory";
2
2
  import { NostrEvent } from "applesauce-core/helpers/event";
3
- /** Sets the necessary tags for a NIP-22 comment event to point to a parent event */
4
- export declare function setParent(parent: NostrEvent): EventOperation;
3
+ import { CommentPointer } from "../helpers/comment.js";
4
+ /** Sets the necessary tags for a NIP-22 comment event to point to a parent event or pointer */
5
+ export declare function setParent(parent: NostrEvent | CommentPointer): EventOperation;
@@ -1,11 +1,25 @@
1
- import { createCommentTagsForEvent } from "../helpers/comment.js";
2
- /** Sets the necessary tags for a NIP-22 comment event to point to a parent event */
1
+ import { isEvent } from "applesauce-core/helpers/event";
2
+ import { COMMENT_KIND, createCommentTagsForEvent, createCommentTagsFromCommentPointer, } from "../helpers/comment.js";
3
+ /** Sets the necessary tags for a NIP-22 comment event to point to a parent event or pointer */
3
4
  export function setParent(parent) {
4
5
  return async (draft, ctx) => {
5
- const relayHint = await ctx.getEventRelayHint?.(parent.id);
6
6
  let tags = Array.from(draft.tags);
7
- // add NIP-22 comment tags
8
- tags.push(...createCommentTagsForEvent(parent, relayHint));
7
+ // If parent is a CommentPointer (not a NostrEvent), handle it directly
8
+ if (!isEvent(parent)) {
9
+ if (parent.kind === COMMENT_KIND)
10
+ throw new Error("Comment pointer cannot be a comment kind. please pass the full nip-22 comment event");
11
+ // For CommentPointer, treat as root comment: both root and reply tags point to the same pointer
12
+ // Note: relay hints are already included in the pointer if available
13
+ // Add root tags (capitalized)
14
+ tags.push(...createCommentTagsFromCommentPointer(parent, true));
15
+ // Add reply tags (lowercase)
16
+ tags.push(...createCommentTagsFromCommentPointer(parent, false));
17
+ }
18
+ else {
19
+ // If parent is a NostrEvent, use existing logic
20
+ const relayHint = await ctx.getEventRelayHint?.(parent.id);
21
+ tags.push(...createCommentTagsForEvent(parent, relayHint));
22
+ }
9
23
  return { ...draft, tags };
10
24
  };
11
25
  }
@@ -22,6 +22,8 @@ export declare function addTorrentSearchTag(tag: string): EventOperation;
22
22
  export declare function removeTorrentSearchTag(tag: string): EventOperation;
23
23
  /** Sets the category path (tcat) */
24
24
  export declare function setTorrentCategoryPath(categoryPath: string): EventOperation;
25
+ /** Removes the category path (tcat) */
26
+ export declare function removeTorrentCategoryPath(): EventOperation;
25
27
  /** Adds an external identifier */
26
28
  export declare function addTorrentExternalIdentifier(identifier: TorrentExternalIdentifier): EventOperation;
27
29
  /**
@@ -48,6 +48,10 @@ export function removeTorrentSearchTag(tag) {
48
48
  export function setTorrentCategoryPath(categoryPath) {
49
49
  return modifyPublicTags(setSingletonTag(["i", `tcat:${categoryPath}`]));
50
50
  }
51
+ /** Removes the category path (tcat) */
52
+ export function removeTorrentCategoryPath() {
53
+ return modifyPublicTags((tags) => tags.filter((t) => !(t[0] === "i" && t[1]?.startsWith("tcat:"))));
54
+ }
51
55
  /** Adds an external identifier */
52
56
  export function addTorrentExternalIdentifier(identifier) {
53
57
  return modifyPublicTags(addNameValueTag(["i", identifier.identifier], false));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "applesauce-common",
3
- "version": "0.0.0-next-20251220152312",
3
+ "version": "0.0.0-next-20251231055351",
4
4
  "description": "Common NIP-specific helpers and models for applesauce",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -83,7 +83,7 @@
83
83
  },
84
84
  "dependencies": {
85
85
  "@scure/base": "^1.2.4",
86
- "applesauce-core": "0.0.0-next-20251220152312",
86
+ "applesauce-core": "0.0.0-next-20251231055351",
87
87
  "hash-sum": "^2.0.0",
88
88
  "light-bolt11-decoder": "^3.2.0",
89
89
  "rxjs": "^7.8.1"