applesauce-actions 0.0.0-next-20250703183032 → 0.0.0-next-20250718170433

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,5 +1,5 @@
1
1
  import { from, Subject } from "rxjs";
2
- import { beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { describe, expect, it, vi } from "vitest";
3
3
  import { subscribeSpyTo } from "@hirez_io/observer-spy";
4
4
  import { EventFactory } from "applesauce-factory";
5
5
  import { EventStore } from "applesauce-core";
@@ -7,12 +7,8 @@ import { FakeUser } from "./fake-user.js";
7
7
  import { ActionHub } from "../action-hub.js";
8
8
  import { CreateProfile } from "../actions/profile.js";
9
9
  const user = new FakeUser();
10
- let events = new EventStore();
11
- let factory = new EventFactory({ signer: user });
12
- beforeEach(() => {
13
- events = new EventStore();
14
- factory = new EventFactory({ signer: user });
15
- });
10
+ const events = new EventStore();
11
+ const factory = new EventFactory({ signer: user });
16
12
  describe("runAction", () => {
17
13
  it("should handle action that return observables", async () => {
18
14
  const e = [user.note(), user.profile({ name: "testing" })];
@@ -44,10 +44,6 @@ describe("exports", () => {
44
44
  "RemoveRelayFromRelaySet",
45
45
  "RemoveSearchRelay",
46
46
  "RemoveUserFromFollowSet",
47
- "ReplyToLegacyMessage",
48
- "ReplyToWrappedMessage",
49
- "SendLegacyMessage",
50
- "SendWrappedMessage",
51
47
  "SetDefaultBlossomServer",
52
48
  "SetListMetadata",
53
49
  "UnbookmarkEvent",
@@ -1,4 +1,4 @@
1
- import { beforeEach, describe, expect, it, vi } from "vitest";
1
+ import { beforeEach, describe, expect, it } from "vitest";
2
2
  import { EventStore } from "applesauce-core";
3
3
  import { EventFactory } from "applesauce-factory";
4
4
  import { kinds } from "nostr-tools";
@@ -24,7 +24,6 @@ beforeEach(() => {
24
24
  created_at: Math.floor(Date.now() / 1000),
25
25
  });
26
26
  events.add(muteList);
27
- vi.useFakeTimers();
28
27
  });
29
28
  describe("MuteThread", () => {
30
29
  it("should add an event to public tags in mute list", async () => {
@@ -44,12 +43,9 @@ describe("MuteThread", () => {
44
43
  });
45
44
  describe("UnmuteThread", () => {
46
45
  it("should remove an event from public tags in mute list", async () => {
47
- vi.setSystemTime(new Date("2025-01-01T00:00:00Z"));
48
46
  // First add the thread to mute list
49
47
  const addSpy = subscribeSpyTo(hub.exec(MuteThread, testEventId), { expectErrors: false });
50
48
  await addSpy.onComplete();
51
- // Wait a second to ensure events have newer created_at
52
- await vi.advanceTimersByTime(1000);
53
49
  // Then unmute it
54
50
  const spy = subscribeSpyTo(hub.exec(UnmuteThread, testEventId), { expectErrors: false });
55
51
  await spy.onComplete();
@@ -58,12 +54,9 @@ describe("UnmuteThread", () => {
58
54
  expect(mutedThings.threads).not.toContain(testEventId);
59
55
  });
60
56
  it("should remove an event from hidden tags in mute list", async () => {
61
- vi.setSystemTime(new Date("2025-01-01T00:00:00Z"));
62
57
  // First add the thread to hidden mute list
63
58
  const addSpy = subscribeSpyTo(hub.exec(MuteThread, testEventId, true), { expectErrors: false });
64
59
  await addSpy.onComplete();
65
- // Wait a second to ensure events have newer created_at
66
- await vi.advanceTimersByTime(2000);
67
60
  // Then unmute it
68
61
  const spy = subscribeSpyTo(hub.exec(UnmuteThread, testEventId, true), { expectErrors: false });
69
62
  await spy.onComplete();
@@ -1,41 +1,41 @@
1
1
  import { BLOSSOM_SERVER_LIST_KIND } from "applesauce-core/helpers/blossom";
2
- import { modifyPublicTags } from "applesauce-factory/operations/event";
2
+ import { modifyPublicTags, modifyTags } from "applesauce-factory/operations/event";
3
3
  import { addBlossomServerTag, removeBlossomServerTag } from "applesauce-factory/operations/tag/blossom";
4
- function getBlossomServersEvent(events, self) {
5
- const event = events.getReplaceable(BLOSSOM_SERVER_LIST_KIND, self);
6
- if (!event)
7
- throw new Error("Can't find Blossom servers event");
8
- return event;
9
- }
10
4
  /** An action that adds a server to the Blossom servers event */
11
5
  export function AddBlossomServer(server) {
12
6
  return async function* ({ events, factory, self }) {
13
- const servers = getBlossomServersEvent(events, self);
7
+ const servers = events.getReplaceable(BLOSSOM_SERVER_LIST_KIND, self);
14
8
  const operation = Array.isArray(server) ? server.map((s) => addBlossomServerTag(s)) : addBlossomServerTag(server);
15
- const draft = await factory.modifyTags(servers, operation);
9
+ // Modify or build new event
10
+ const draft = servers
11
+ ? await factory.modifyTags(servers, operation)
12
+ : await factory.build({ kind: BLOSSOM_SERVER_LIST_KIND }, modifyTags(operation));
16
13
  yield await factory.sign(draft);
17
14
  };
18
15
  }
19
16
  /** An action that removes a server from the Blossom servers event */
20
17
  export function RemoveBlossomServer(server) {
21
18
  return async function* ({ events, factory, self }) {
22
- const servers = getBlossomServersEvent(events, self);
19
+ const servers = events.getReplaceable(BLOSSOM_SERVER_LIST_KIND, self);
23
20
  const operation = Array.isArray(server)
24
21
  ? server.map((s) => removeBlossomServerTag(s))
25
22
  : removeBlossomServerTag(server);
26
- const draft = await factory.modifyTags(servers, operation);
23
+ // Modify or build new event
24
+ const draft = servers
25
+ ? await factory.modifyTags(servers, operation)
26
+ : await factory.build({ kind: BLOSSOM_SERVER_LIST_KIND }, modifyTags(operation));
27
27
  yield await factory.sign(draft);
28
28
  };
29
29
  }
30
30
  /** Makes a specific Blossom server the default server (move it to the top of the list) */
31
31
  export function SetDefaultBlossomServer(server) {
32
32
  return async function* ({ events, factory, self }) {
33
- const servers = getBlossomServersEvent(events, self);
33
+ const servers = events.getReplaceable(BLOSSOM_SERVER_LIST_KIND, self);
34
34
  const prependTag = (tag) => (tags) => [tag, ...tags];
35
- const draft = await factory.modifyTags(servers, [
36
- removeBlossomServerTag(server),
37
- prependTag(["server", String(server)]),
38
- ]);
35
+ const operations = [removeBlossomServerTag(server), prependTag(["server", String(server)])];
36
+ const draft = servers
37
+ ? await factory.modifyTags(servers, operations)
38
+ : await factory.build({ kind: BLOSSOM_SERVER_LIST_KIND }, modifyTags(...operations));
39
39
  yield await factory.sign(draft);
40
40
  };
41
41
  }
@@ -3,17 +3,17 @@ import { Action } from "../action-hub.js";
3
3
  /**
4
4
  * An action that adds a note or article to the bookmark list or a bookmark set
5
5
  * @param event the event to bookmark
6
- * @param identifier the "d" tag of the bookmark set
6
+ * @param identifier the "d" tag of the bookmark set or `undefined` for the default bookmark list
7
7
  * @param hidden set to true to add to hidden bookmarks
8
8
  */
9
- export declare function BookmarkEvent(event: NostrEvent, identifier?: string, hidden?: boolean): Action;
9
+ export declare function BookmarkEvent(event: NostrEvent, identifier?: string | NostrEvent, hidden?: boolean): Action;
10
10
  /**
11
11
  * An action that removes a note or article from the bookmark list or bookmark set
12
12
  * @param event the event to remove from bookmarks
13
- * @param identifier the "d" tag of the bookmark set
13
+ * @param identifier the "d" tag of the bookmark set or `undefined` for the default bookmark list
14
14
  * @param hidden set to true to remove from hidden bookmarks
15
15
  */
16
- export declare function UnbookmarkEvent(event: NostrEvent, identifier?: string, hidden?: boolean): Action;
16
+ export declare function UnbookmarkEvent(event: NostrEvent, identifier?: string | NostrEvent, hidden?: boolean): Action;
17
17
  /** An action that creates a new bookmark list for a user */
18
18
  export declare function CreateBookmarkList(bookmarks?: NostrEvent[]): Action;
19
19
  /** An action that creates a new bookmark set for a user */
@@ -1,45 +1,72 @@
1
1
  import { modifyHiddenTags, modifyPublicTags, setListDescription, setListImage, setListTitle, } from "applesauce-factory/operations/event";
2
2
  import { addEventBookmarkTag, removeEventBookmarkTag } from "applesauce-factory/operations/tag";
3
3
  import { kinds } from "nostr-tools";
4
- function getBookmarkEvent(events, self, identifier) {
5
- return events.getReplaceable(identifier ? kinds.Bookmarksets : kinds.BookmarkList, self, identifier);
6
- }
7
4
  /**
8
5
  * An action that adds a note or article to the bookmark list or a bookmark set
9
6
  * @param event the event to bookmark
10
- * @param identifier the "d" tag of the bookmark set
7
+ * @param identifier the "d" tag of the bookmark set or `undefined` for the default bookmark list
11
8
  * @param hidden set to true to add to hidden bookmarks
12
9
  */
13
10
  export function BookmarkEvent(event, identifier, hidden = false) {
14
11
  return async function* ({ events, factory, self }) {
15
- const bookmarks = getBookmarkEvent(events, self, identifier);
16
- if (!bookmarks)
17
- throw new Error("Cant find bookmarks");
12
+ let draft;
18
13
  const operation = addEventBookmarkTag(event);
19
- const draft = await factory.modifyTags(bookmarks, hidden ? { hidden: operation } : operation);
14
+ if (typeof identifier === "string" || identifier?.kind === kinds.Bookmarksets) {
15
+ const list = typeof identifier === "string" ? events.getReplaceable(kinds.Bookmarksets, self, identifier) : identifier;
16
+ if (list && list.kind !== kinds.Bookmarksets)
17
+ throw new Error("Event is not a bookmark set");
18
+ // Modify or build new event bookmark set
19
+ draft = list
20
+ ? await factory.modifyTags(list, hidden ? { hidden: operation } : operation)
21
+ : await factory.build({ kind: kinds.Bookmarksets }, hidden ? modifyHiddenTags(operation) : modifyPublicTags(operation));
22
+ }
23
+ else if (identifier === undefined || identifier?.kind === kinds.BookmarkList) {
24
+ const list = identifier ? identifier : events.getReplaceable(kinds.BookmarkList, self);
25
+ if (list && list.kind !== kinds.BookmarkList)
26
+ throw new Error("Event is not a bookmark list");
27
+ // Modify or build new event bookmark list
28
+ draft = list
29
+ ? await factory.modifyTags(list, hidden ? { hidden: operation } : operation)
30
+ : await factory.build({ kind: kinds.BookmarkList }, hidden ? modifyHiddenTags(operation) : modifyPublicTags(operation));
31
+ }
32
+ else {
33
+ throw new Error(`Event kind ${identifier.kind} is not a bookmark list or bookmark set`);
34
+ }
20
35
  yield await factory.sign(draft);
21
36
  };
22
37
  }
23
38
  /**
24
39
  * An action that removes a note or article from the bookmark list or bookmark set
25
40
  * @param event the event to remove from bookmarks
26
- * @param identifier the "d" tag of the bookmark set
41
+ * @param identifier the "d" tag of the bookmark set or `undefined` for the default bookmark list
27
42
  * @param hidden set to true to remove from hidden bookmarks
28
43
  */
29
44
  export function UnbookmarkEvent(event, identifier, hidden = false) {
30
45
  return async function* ({ events, factory, self }) {
31
- const bookmarks = getBookmarkEvent(events, self, identifier);
32
- if (!bookmarks)
33
- throw new Error("Cant find bookmarks");
46
+ let list;
34
47
  const operation = removeEventBookmarkTag(event);
35
- const draft = await factory.modifyTags(bookmarks, hidden ? { hidden: operation } : operation);
48
+ if (typeof identifier === "string" || identifier?.kind === kinds.Bookmarksets) {
49
+ list = typeof identifier === "string" ? events.getReplaceable(kinds.Bookmarksets, self, identifier) : identifier;
50
+ }
51
+ else if (identifier === undefined || identifier?.kind === kinds.BookmarkList) {
52
+ list = identifier ? identifier : events.getReplaceable(kinds.BookmarkList, self);
53
+ if (!list)
54
+ return;
55
+ }
56
+ else {
57
+ throw new Error(`Event kind ${identifier.kind} is not a bookmark list or bookmark set`);
58
+ }
59
+ // If no list is found, return
60
+ if (!list)
61
+ return;
62
+ const draft = await factory.modifyTags(list, hidden ? { hidden: operation } : operation);
36
63
  yield await factory.sign(draft);
37
64
  };
38
65
  }
39
66
  /** An action that creates a new bookmark list for a user */
40
67
  export function CreateBookmarkList(bookmarks) {
41
68
  return async function* ({ events, factory, self }) {
42
- const existing = getBookmarkEvent(events, self);
69
+ const existing = events.getReplaceable(kinds.BookmarkList, self);
43
70
  if (existing)
44
71
  throw new Error("Bookmark list already exists");
45
72
  const draft = await factory.build({ kind: kinds.BookmarkList }, bookmarks ? modifyPublicTags(...bookmarks.map(addEventBookmarkTag)) : undefined);
@@ -48,10 +75,7 @@ export function CreateBookmarkList(bookmarks) {
48
75
  }
49
76
  /** An action that creates a new bookmark set for a user */
50
77
  export function CreateBookmarkSet(title, description, additional) {
51
- return async function* ({ events, factory, self }) {
52
- const existing = getBookmarkEvent(events, self);
53
- if (existing)
54
- throw new Error("Bookmark list already exists");
78
+ return async function* ({ factory }) {
55
79
  const draft = await factory.build({ kind: kinds.BookmarkList }, setListTitle(title), setListDescription(description), additional.image ? setListImage(additional.image) : undefined, additional.public ? modifyPublicTags(...additional.public.map(addEventBookmarkTag)) : undefined, additional.hidden ? modifyHiddenTags(...additional.hidden.map(addEventBookmarkTag)) : undefined);
56
80
  yield await factory.sign(draft);
57
81
  };
@@ -1,7 +1,8 @@
1
+ import { ProfilePointer } from "nostr-tools/nip19";
1
2
  import { Action } from "../action-hub.js";
2
3
  /** An action that adds a pubkey to a users contacts event */
3
4
  export declare function FollowUser(pubkey: string, relay?: string, hidden?: boolean): Action;
4
5
  /** An action that removes a pubkey from a users contacts event */
5
- export declare function UnfollowUser(pubkey: string, hidden?: boolean): Action;
6
+ export declare function UnfollowUser(user: string | ProfilePointer, hidden?: boolean): Action;
6
7
  /** An action that creates a new kind 3 contacts lists, throws if a contact list already exists */
7
- export declare function NewContacts(pubkeys?: string[]): Action;
8
+ export declare function NewContacts(pubkeys?: (string | ProfilePointer)[]): Action;
@@ -1,24 +1,29 @@
1
- import { kinds } from "nostr-tools";
1
+ import { modifyHiddenTags, modifyPublicTags } from "applesauce-factory/operations/event";
2
2
  import { addPubkeyTag, removePubkeyTag } from "applesauce-factory/operations/tag";
3
+ import { kinds } from "nostr-tools";
3
4
  /** An action that adds a pubkey to a users contacts event */
4
5
  export function FollowUser(pubkey, relay, hidden = false) {
5
6
  return async function* ({ events, factory, self }) {
6
- const contacts = events.getReplaceable(kinds.Contacts, self);
7
- if (!contacts)
8
- throw new Error("Missing contacts event");
7
+ let contacts = events.getReplaceable(kinds.Contacts, self);
9
8
  const pointer = { pubkey, relays: relay ? [relay] : undefined };
10
9
  const operation = addPubkeyTag(pointer);
11
- const draft = await factory.modifyTags(contacts, hidden ? { hidden: operation } : operation);
10
+ let draft;
11
+ // No contact list, create one
12
+ if (!contacts)
13
+ draft = await factory.build({ kind: kinds.Contacts }, hidden ? modifyHiddenTags(operation) : modifyPublicTags(operation));
14
+ else
15
+ draft = await factory.modifyTags(contacts, hidden ? { hidden: operation } : operation);
12
16
  yield await factory.sign(draft);
13
17
  };
14
18
  }
15
19
  /** An action that removes a pubkey from a users contacts event */
16
- export function UnfollowUser(pubkey, hidden = false) {
20
+ export function UnfollowUser(user, hidden = false) {
17
21
  return async function* ({ events, factory, self }) {
18
22
  const contacts = events.getReplaceable(kinds.Contacts, self);
23
+ // Unable to find a contacts event, so we can't unfollow
19
24
  if (!contacts)
20
- throw new Error("Missing contacts event");
21
- const operation = removePubkeyTag(pubkey);
25
+ return;
26
+ const operation = removePubkeyTag(user);
22
27
  const draft = await factory.modifyTags(contacts, hidden ? { hidden: operation } : operation);
23
28
  yield await factory.sign(draft);
24
29
  };
@@ -29,7 +34,7 @@ export function NewContacts(pubkeys) {
29
34
  const contacts = events.getReplaceable(kinds.Contacts, self);
30
35
  if (contacts)
31
36
  throw new Error("Contact list already exists");
32
- const draft = await factory.build({ kind: kinds.Contacts, tags: pubkeys?.map((p) => ["p", p]) });
37
+ const draft = await factory.build({ kind: kinds.Contacts }, pubkeys ? modifyPublicTags(...pubkeys.map((p) => addPubkeyTag(p))) : undefined);
33
38
  yield await factory.sign(draft);
34
39
  };
35
40
  }
@@ -1,6 +1,6 @@
1
1
  import { FAVORITE_RELAYS_KIND } from "applesauce-core/helpers/lists";
2
2
  import { modifyHiddenTags, modifyPublicTags } from "applesauce-factory/operations/event";
3
- import { addCoordinateTag, addRelayTag, removeCoordinateTag, removeRelayTag } from "applesauce-factory/operations/tag";
3
+ import { addAddressTag, addRelayTag, removeAddressTag, removeRelayTag } from "applesauce-factory/operations/tag";
4
4
  function getFavoriteRelaysEvent(events, self) {
5
5
  const event = events.getReplaceable(FAVORITE_RELAYS_KIND, self);
6
6
  if (!event)
@@ -29,7 +29,7 @@ export function RemoveFavoriteRelay(relay, hidden = false) {
29
29
  export function AddFavoriteRelaySet(addr, hidden = false) {
30
30
  return async function* ({ events, factory, self }) {
31
31
  const favorites = getFavoriteRelaysEvent(events, self);
32
- const operation = Array.isArray(addr) ? addr.map((a) => addCoordinateTag(a)) : addCoordinateTag(addr);
32
+ const operation = Array.isArray(addr) ? addr.map((a) => addAddressTag(a)) : addAddressTag(addr);
33
33
  const draft = await factory.modifyTags(favorites, hidden ? { hidden: operation } : operation);
34
34
  yield await factory.sign(draft);
35
35
  };
@@ -38,7 +38,7 @@ export function AddFavoriteRelaySet(addr, hidden = false) {
38
38
  export function RemoveFavoriteRelaySet(addr, hidden = false) {
39
39
  return async function* ({ events, factory, self }) {
40
40
  const favorites = getFavoriteRelaysEvent(events, self);
41
- const operation = Array.isArray(addr) ? addr.map((a) => removeCoordinateTag(a)) : removeCoordinateTag(addr);
41
+ const operation = Array.isArray(addr) ? addr.map((a) => removeAddressTag(a)) : removeAddressTag(addr);
42
42
  const draft = await factory.modifyTags(favorites, hidden ? { hidden: operation } : operation);
43
43
  yield await factory.sign(draft);
44
44
  };
@@ -61,13 +61,13 @@ export function NewFavoriteRelays(relays, sets) {
61
61
  hiddenOperations.push(...(relays?.hidden ?? []).map((r) => addRelayTag(r)));
62
62
  }
63
63
  if (Array.isArray(sets)) {
64
- publicOperations.push(...sets.map((s) => addCoordinateTag(s)));
64
+ publicOperations.push(...sets.map((s) => addAddressTag(s)));
65
65
  }
66
66
  else {
67
67
  if (sets?.public)
68
- publicOperations.push(...(sets?.public ?? []).map((s) => addCoordinateTag(s)));
68
+ publicOperations.push(...(sets?.public ?? []).map((s) => addAddressTag(s)));
69
69
  if (sets?.hidden)
70
- hiddenOperations.push(...(sets?.hidden ?? []).map((s) => addCoordinateTag(s)));
70
+ hiddenOperations.push(...(sets?.hidden ?? []).map((s) => addAddressTag(s)));
71
71
  }
72
72
  const draft = await factory.build({ kind: FAVORITE_RELAYS_KIND }, publicOperations.length ? modifyPublicTags(...publicOperations) : undefined, hiddenOperations.length ? modifyHiddenTags(...hiddenOperations) : undefined);
73
73
  yield await factory.sign(draft);
@@ -18,9 +18,9 @@ export function AddInboxRelay(relay) {
18
18
  if (typeof relay === "string")
19
19
  relay = [relay];
20
20
  const mailboxes = events.getReplaceable(kinds.RelayList, self);
21
- if (!mailboxes)
22
- throw new Error("Missing mailboxes event");
23
- const draft = await factory.modifyTags(mailboxes, ...relay.map(addInboxRelay));
21
+ const draft = mailboxes
22
+ ? await factory.modifyTags(mailboxes, ...relay.map(addInboxRelay))
23
+ : await factory.build({ kind: kinds.RelayList }, modifyPublicTags(...relay.map(addInboxRelay)));
24
24
  const signed = await factory.sign(draft);
25
25
  yield signed;
26
26
  };
@@ -32,7 +32,7 @@ export function RemoveInboxRelay(relay) {
32
32
  relay = [relay];
33
33
  const mailboxes = events.getReplaceable(kinds.RelayList, self);
34
34
  if (!mailboxes)
35
- throw new Error("Missing mailboxes event");
35
+ return;
36
36
  const draft = await factory.modifyTags(mailboxes, ...relay.map(removeInboxRelay));
37
37
  const signed = await factory.sign(draft);
38
38
  yield signed;
@@ -44,9 +44,9 @@ export function AddOutboxRelay(relay) {
44
44
  if (typeof relay === "string")
45
45
  relay = [relay];
46
46
  const mailboxes = events.getReplaceable(kinds.RelayList, self);
47
- if (!mailboxes)
48
- throw new Error("Missing mailboxes event");
49
- const draft = await factory.modifyTags(mailboxes, ...relay.map(addOutboxRelay));
47
+ const draft = mailboxes
48
+ ? await factory.modifyTags(mailboxes, ...relay.map(addOutboxRelay))
49
+ : await factory.build({ kind: kinds.RelayList }, modifyPublicTags(...relay.map(addOutboxRelay)));
50
50
  const signed = await factory.sign(draft);
51
51
  yield signed;
52
52
  };
@@ -58,7 +58,7 @@ export function RemoveOutboxRelay(relay) {
58
58
  relay = [relay];
59
59
  const mailboxes = events.getReplaceable(kinds.RelayList, self);
60
60
  if (!mailboxes)
61
- throw new Error("Missing mailboxes event");
61
+ return;
62
62
  const draft = await factory.modifyTags(mailboxes, ...relay.map(removeOutboxRelay));
63
63
  const signed = await factory.sign(draft);
64
64
  yield signed;
@@ -1,5 +1,6 @@
1
1
  import { NostrEvent } from "nostr-tools";
2
2
  import { Action } from "../action-hub.js";
3
+ export declare const ALLOWED_PIN_KINDS: number[];
3
4
  /** An action that pins a note to the users pin list */
4
5
  export declare function PinNote(note: NostrEvent): Action;
5
6
  /** An action that removes an event from the users pin list */
@@ -1,13 +1,18 @@
1
- import { kinds } from "nostr-tools";
2
- import { addEventTag, removeEventTag } from "applesauce-factory/operations/tag";
1
+ import { getReplaceableAddress, isReplaceable } from "applesauce-core/helpers";
3
2
  import { modifyPublicTags } from "applesauce-factory/operations/event";
3
+ import { addAddressTag, addEventTag, removeAddressTag, removeEventTag } from "applesauce-factory/operations/tag";
4
+ import { kinds } from "nostr-tools";
5
+ export const ALLOWED_PIN_KINDS = [kinds.ShortTextNote, kinds.LongFormArticle];
4
6
  /** An action that pins a note to the users pin list */
5
7
  export function PinNote(note) {
8
+ if (!ALLOWED_PIN_KINDS.includes(note.kind))
9
+ throw new Error(`Event kind ${note.kind} can not be pinned`);
6
10
  return async function* ({ events, factory, self }) {
7
11
  const pins = events.getReplaceable(kinds.Pinlist, self);
8
- if (!pins)
9
- throw new Error("Missing pin list");
10
- const draft = await factory.modifyTags(pins, addEventTag(note.id));
12
+ const operation = isReplaceable(note.kind) ? addAddressTag(getReplaceableAddress(note)) : addEventTag(note.id);
13
+ const draft = pins
14
+ ? await factory.modifyTags(pins, operation)
15
+ : await factory.build({ kind: kinds.Pinlist }, modifyPublicTags(operation));
11
16
  yield await factory.sign(draft);
12
17
  };
13
18
  }
@@ -16,8 +21,11 @@ export function UnpinNote(note) {
16
21
  return async function* ({ events, factory, self }) {
17
22
  const pins = events.getReplaceable(kinds.Pinlist, self);
18
23
  if (!pins)
19
- throw new Error("Missing pin list");
20
- const draft = await factory.modifyTags(pins, removeEventTag(note.id));
24
+ return;
25
+ const operation = isReplaceable(note.kind)
26
+ ? removeAddressTag(getReplaceableAddress(note))
27
+ : removeEventTag(note.id);
28
+ const draft = await factory.modifyTags(pins, operation);
21
29
  yield await factory.sign(draft);
22
30
  };
23
31
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "applesauce-actions",
3
- "version": "0.0.0-next-20250703183032",
3
+ "version": "0.0.0-next-20250718170433",
4
4
  "description": "A package for performing common nostr actions",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -32,15 +32,15 @@
32
32
  }
33
33
  },
34
34
  "dependencies": {
35
- "applesauce-core": "0.0.0-next-20250703183032",
36
- "applesauce-factory": "0.0.0-next-20250703183032",
35
+ "applesauce-core": "^2.3.0",
36
+ "applesauce-factory": "0.0.0-next-20250718170433",
37
37
  "nostr-tools": "^2.13",
38
38
  "rxjs": "^7.8.1"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@hirez_io/observer-spy": "^2.2.0",
42
42
  "@types/debug": "^4.1.12",
43
- "applesauce-signers": "^2.0.0",
43
+ "applesauce-signers": "0.0.0-next-20250718170433",
44
44
  "nanoid": "^5.1.5",
45
45
  "typescript": "^5.8.3",
46
46
  "vitest": "^3.2.3"