applesauce-actions 5.1.1 → 6.0.0

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 { User } from "applesauce-common/casts/user";
2
- import { EventFactory, EventSigner } from "applesauce-core/event-factory";
2
+ import { EventSigner } from "applesauce-core";
3
3
  import { EventModels, IEventStoreActions, IEventStoreRead, IEventStoreStreams, IEventSubscriptions } from "applesauce-core/event-store";
4
4
  import { EventTemplate, NostrEvent, UnsignedEvent } from "applesauce-core/helpers/event";
5
5
  import { Observable } from "rxjs";
@@ -17,10 +17,8 @@ export type ActionContext = {
17
17
  /** The {@link User} cast that is signing the events */
18
18
  user: User;
19
19
  /** The event signer used to sign events */
20
- signer?: EventSigner;
21
- /** The event factory used to build and modify events */
22
- factory: EventFactory;
23
- /** Sign an event using the event factory */
20
+ signer: EventSigner;
21
+ /** Sign an event using the signer */
24
22
  sign: (draft: EventTemplate | UnsignedEvent) => Promise<NostrEvent>;
25
23
  /** The method to publish events to an optional list of relays */
26
24
  publish: (event: NostrEvent | NostrEvent[], relays?: string[]) => Promise<void>;
@@ -34,21 +32,13 @@ export type ActionBuilder<Args extends Array<any>> = (...args: Args) => Action;
34
32
  /** The main class that runs actions */
35
33
  export declare class ActionRunner {
36
34
  events: IEventStoreRead & IEventStoreStreams & IEventSubscriptions & IEventStoreActions & EventModels;
37
- factory: EventFactory;
35
+ signer: EventSigner;
38
36
  private publishMethod?;
39
37
  /** Whether to save all events created by actions to the event store */
40
38
  saveToStore: boolean;
41
- constructor(events: IEventStoreRead & IEventStoreStreams & IEventSubscriptions & IEventStoreActions & EventModels, factory: EventFactory, publishMethod?: UpstreamPool | undefined);
42
- protected getContext(): Promise<{
43
- self: string;
44
- user: User;
45
- events: IEventStoreRead & IEventStoreStreams & IEventSubscriptions & IEventStoreActions & EventModels<import("applesauce-core/event-store").IEventStore | import("applesauce-core/event-store").IAsyncEventStore>;
46
- signer: EventSigner;
47
- factory: EventFactory;
48
- publish: (event: NostrEvent | NostrEvent[], relays?: string[]) => Promise<void>;
49
- run: <Args extends Array<any>>(builder: ActionBuilder<Args>, ...args: Args) => Promise<void>;
50
- sign: (draft: EventTemplate | UnsignedEvent) => Promise<NostrEvent>;
51
- }>;
39
+ private _context;
40
+ constructor(events: IEventStoreRead & IEventStoreStreams & IEventSubscriptions & IEventStoreActions & EventModels, signer: EventSigner, publishMethod?: UpstreamPool | undefined);
41
+ protected getContext(): Promise<ActionContext>;
52
42
  /** Internal method for publishing events to relays */
53
43
  publish(event: NostrEvent | NostrEvent[], relays?: string[]): Promise<void>;
54
44
  /** Run an action and publish events using the publish method */
@@ -3,30 +3,31 @@ import { from, identity, isObservable, lastValueFrom, Observable, switchMap, tap
3
3
  /** The main class that runs actions */
4
4
  export class ActionRunner {
5
5
  events;
6
- factory;
6
+ signer;
7
7
  publishMethod;
8
8
  /** Whether to save all events created by actions to the event store */
9
9
  saveToStore = true;
10
- constructor(events, factory, publishMethod) {
10
+ _context;
11
+ constructor(events, signer, publishMethod) {
11
12
  this.events = events;
12
- this.factory = factory;
13
+ this.signer = signer;
13
14
  this.publishMethod = publishMethod;
14
15
  }
15
16
  async getContext() {
16
- if (!this.factory.context.signer)
17
- throw new Error("Missing signer");
18
- const self = await this.factory.context.signer.getPublicKey();
17
+ if (this._context)
18
+ return this._context;
19
+ const self = await this.signer.getPublicKey();
19
20
  const user = castUser(self, this.events);
20
- return {
21
+ this._context = {
21
22
  self,
22
23
  user,
23
24
  events: this.events,
24
- signer: this.factory.context.signer,
25
- factory: this.factory,
25
+ signer: this.signer,
26
26
  publish: this.publish.bind(this),
27
27
  run: this.run.bind(this),
28
- sign: this.factory.sign.bind(this.factory),
28
+ sign: (draft) => this.signer.signEvent(draft),
29
29
  };
30
+ return this._context;
30
31
  }
31
32
  /** Internal method for publishing events to relays */
32
33
  async publish(event, relays) {
@@ -1,13 +1,12 @@
1
- import { AppDataBlueprint } from "applesauce-common/blueprints/app-data";
1
+ import { AppDataFactory } from "applesauce-common/factories";
2
2
  import { APP_DATA_KIND, getAppDataEncryption } from "applesauce-common/helpers/app-data";
3
- import * as AppData from "applesauce-common/operations/app-data";
4
3
  export function UpdateAppData(identifier, data) {
5
- return async ({ self, factory, events, user, publish, sign }) => {
6
- const event = events.getReplaceable(APP_DATA_KIND, self, identifier);
4
+ return async ({ signer, user, publish }) => {
5
+ const event = await user.replaceable(APP_DATA_KIND, identifier).$first(1000, undefined);
7
6
  const encryption = !!event && getAppDataEncryption(event);
8
7
  const signed = event
9
- ? await factory.modify(event, AppData.setContent(data, encryption)).then(sign)
10
- : await factory.create(AppDataBlueprint, identifier, data, encryption).then(sign);
8
+ ? await AppDataFactory.modify(event).data(data, encryption).sign(signer)
9
+ : await AppDataFactory.create(identifier, data, encryption).sign(signer);
11
10
  await publish(signed, await user.outboxes$.$first(1000, undefined));
12
11
  };
13
12
  }
@@ -1,42 +1,27 @@
1
- import { firstValueFrom } from "applesauce-core";
1
+ import { BlockedRelaysFactory } from "applesauce-common/factories";
2
2
  import { kinds } from "applesauce-core/helpers/event";
3
- import { modifyHiddenTags, modifyPublicTags } from "applesauce-core/operations";
4
- import { addRelayTag, removeRelayTag } from "applesauce-core/operations/tag/relay";
5
- import { of, timeout } from "rxjs";
6
- // Action to generally modify the blocked relays event
7
- function ModifyBlockedRelaysEvent(operations) {
8
- return async ({ events, factory, user, publish, sign }) => {
9
- const [event, outboxes] = await Promise.all([
10
- firstValueFrom(events
11
- .replaceable(kinds.BlockedRelaysList, user.pubkey)
12
- .pipe(timeout({ first: 1000, with: () => of(undefined) }))),
13
- user.outboxes$.$first(1000, undefined),
14
- ]);
15
- // Modify or build new event
16
- const signed = event
17
- ? await factory.modify(event, ...operations).then(sign)
18
- : await factory.build({ kind: kinds.BlockedRelaysList }, ...operations).then(sign);
19
- // Publish the event to the user's outboxes
20
- await publish(signed, outboxes);
21
- };
3
+ async function modifyBlockedRelays({ user }) {
4
+ const [event, outboxes] = await Promise.all([
5
+ user.replaceable(kinds.BlockedRelaysList).$first(1000, undefined),
6
+ user.outboxes$.$first(1000, undefined),
7
+ ]);
8
+ return [event ? BlockedRelaysFactory.modify(event) : BlockedRelaysFactory.create(), outboxes];
22
9
  }
23
10
  /** An action that adds a relay to the 10006 blocked relays event */
24
11
  export function AddBlockedRelay(relay, hidden = false) {
25
- return async ({ run }) => {
26
- const tagOperations = Array.isArray(relay)
27
- ? relay.map((r) => addRelayTag(r))
28
- : [addRelayTag(relay)];
29
- const operation = hidden ? modifyHiddenTags(...tagOperations) : modifyPublicTags(...tagOperations);
30
- await run(ModifyBlockedRelaysEvent, [operation]);
12
+ const relays = Array.isArray(relay) ? relay : [relay];
13
+ return async (context) => {
14
+ const [factory, outboxes] = await modifyBlockedRelays(context);
15
+ const signed = await factory.addRelay(relays, hidden).sign(context.signer);
16
+ await context.publish(signed, outboxes);
31
17
  };
32
18
  }
33
19
  /** An action that removes a relay from the 10006 blocked relays event */
34
20
  export function RemoveBlockedRelay(relay, hidden = false) {
35
- return async ({ run }) => {
36
- const tagOperations = Array.isArray(relay)
37
- ? relay.map((r) => removeRelayTag(r))
38
- : [removeRelayTag(relay)];
39
- const operation = hidden ? modifyHiddenTags(...tagOperations) : modifyPublicTags(...tagOperations);
40
- await run(ModifyBlockedRelaysEvent, [operation]);
21
+ const relays = Array.isArray(relay) ? relay : [relay];
22
+ return async (context) => {
23
+ const [factory, outboxes] = await modifyBlockedRelays(context);
24
+ const signed = await factory.removeRelay(relays, hidden).sign(context.signer);
25
+ await context.publish(signed, outboxes);
41
26
  };
42
27
  }
@@ -1,9 +1,9 @@
1
- import { Action } from "../action-runner.js";
1
+ import type { Action } from "../action-runner.js";
2
2
  /** An action that adds a server to the Blossom servers event */
3
3
  export declare function AddBlossomServer(server: string | URL | (string | URL)[]): Action;
4
4
  /** An action that removes a server from the Blossom servers event */
5
5
  export declare function RemoveBlossomServer(server: string | URL | (string | URL)[]): Action;
6
- /** Makes a specific Blossom server the default server (move it to the top of the list) */
6
+ /** Makes a specific Blossom server the default server (moves it to the top of the list) */
7
7
  export declare function SetDefaultBlossomServer(server: string | URL): Action;
8
8
  /** Creates a new Blossom servers event */
9
9
  export declare function NewBlossomServers(servers?: (string | URL)[]): Action;
@@ -1,44 +1,48 @@
1
+ import { BlossomServerListFactory } from "applesauce-common/factories";
1
2
  import { BLOSSOM_SERVER_LIST_KIND } from "applesauce-common/helpers/blossom";
2
- import { addBlossomServer, removeBlossomServer } from "applesauce-common/operations/blossom";
3
- // Action to modify or create a new Blossom servers event
4
- function ModifyBlossomServersEvent(operations) {
5
- return async ({ factory, user, publish, sign }) => {
6
- const [event, outboxes] = await Promise.all([
7
- user.replaceable(BLOSSOM_SERVER_LIST_KIND).$first(1000, undefined),
8
- user.outboxes$.$first(1000, undefined),
9
- ]);
10
- // Modify or build new event
11
- const signed = event
12
- ? await factory.modify(event, ...operations).then(sign)
13
- : await factory.build({ kind: BLOSSOM_SERVER_LIST_KIND }, ...operations).then(sign);
14
- // Publish the event to the user's outboxes
15
- await publish(signed, outboxes);
16
- };
3
+ async function modifyBlossomServers({ user, }) {
4
+ const [event, outboxes] = await Promise.all([
5
+ user.replaceable(BLOSSOM_SERVER_LIST_KIND).$first(1000, undefined),
6
+ user.outboxes$.$first(1000, undefined),
7
+ ]);
8
+ return [event ? BlossomServerListFactory.modify(event) : BlossomServerListFactory.create(), outboxes];
17
9
  }
18
10
  /** An action that adds a server to the Blossom servers event */
19
11
  export function AddBlossomServer(server) {
20
- return ModifyBlossomServersEvent(Array.isArray(server) ? server.map((s) => addBlossomServer(s)) : [addBlossomServer(server)]);
12
+ const servers = Array.isArray(server) ? server : [server];
13
+ return async (context) => {
14
+ const [factory, outboxes] = await modifyBlossomServers(context);
15
+ const signed = await servers.reduce((f, s) => f.addServer(s), factory).sign(context.signer);
16
+ await context.publish(signed, outboxes);
17
+ };
21
18
  }
22
19
  /** An action that removes a server from the Blossom servers event */
23
20
  export function RemoveBlossomServer(server) {
24
- return ModifyBlossomServersEvent(Array.isArray(server) ? server.map((s) => removeBlossomServer(s)) : [removeBlossomServer(server)]);
25
- }
26
- // Small event operation to prepend a tag to the events tags
27
- function prependTag(tag) {
28
- return (draft) => ({ ...draft, tags: [tag, ...draft.tags] });
21
+ const servers = Array.isArray(server) ? server : [server];
22
+ return async (context) => {
23
+ const [factory, outboxes] = await modifyBlossomServers(context);
24
+ const signed = await servers.reduce((f, s) => f.removeServer(s), factory).sign(context.signer);
25
+ await context.publish(signed, outboxes);
26
+ };
29
27
  }
30
- /** Makes a specific Blossom server the default server (move it to the top of the list) */
28
+ /** Makes a specific Blossom server the default server (moves it to the top of the list) */
31
29
  export function SetDefaultBlossomServer(server) {
32
- return ModifyBlossomServersEvent([removeBlossomServer(server), prependTag(["server", String(server)])]);
30
+ return async (context) => {
31
+ const [factory, outboxes] = await modifyBlossomServers(context);
32
+ const signed = await factory.setDefaultServer(server).sign(context.signer);
33
+ await context.publish(signed, outboxes);
34
+ };
33
35
  }
34
36
  /** Creates a new Blossom servers event */
35
37
  export function NewBlossomServers(servers) {
36
- return async ({ events, factory, self, user, publish, sign }) => {
38
+ return async ({ events, signer, self, user, publish }) => {
37
39
  const existing = events.getReplaceable(BLOSSOM_SERVER_LIST_KIND, self);
38
40
  if (existing)
39
41
  throw new Error("Blossom servers event already exists");
40
- const operations = servers ? servers.map((s) => addBlossomServer(s)) : [];
41
- const signed = await factory.build({ kind: BLOSSOM_SERVER_LIST_KIND }, ...operations).then(sign);
42
+ let factory = BlossomServerListFactory.create();
43
+ if (servers?.length)
44
+ factory = servers.reduce((f, s) => f.addServer(s), factory);
45
+ const signed = await factory.sign(signer);
42
46
  await publish(signed, await user.outboxes$.$first(1000, undefined));
43
47
  };
44
48
  }
@@ -1,37 +1,18 @@
1
- import * as List from "applesauce-common/operations/list";
2
- import { addEventBookmarkTag, removeEventBookmarkTag } from "applesauce-common/operations/tag/bookmarks";
1
+ import { BookmarkListFactory, BookmarkSetFactory } from "applesauce-common/factories";
3
2
  import { getReplaceableIdentifier, kinds } from "applesauce-core/helpers/event";
4
- import { modifyHiddenTags, modifyPublicTags } from "applesauce-core/operations";
5
- function ModifyBookmarkSetEvent(operations, set, hidden = false) {
6
- const identifier = typeof set === "string" ? set : getReplaceableIdentifier(set);
7
- return async ({ factory, user, publish, sign }) => {
8
- const [event, outboxes] = await Promise.all([
9
- user.replaceable(kinds.Bookmarksets, identifier).$first(1000, undefined),
10
- user.outboxes$.$first(1000, undefined),
11
- ]);
12
- const operation = hidden ? modifyHiddenTags(...operations) : modifyPublicTags(...operations);
13
- // Modify or build new event
14
- const signed = event
15
- ? await factory.modify(event, operation).then(sign)
16
- : await factory.build({ kind: kinds.Bookmarksets }, operation).then(sign);
17
- // Publish the event to the user's outboxes
18
- await publish(signed, outboxes);
19
- };
3
+ async function modifyBookmarkList({ user }) {
4
+ const [event, outboxes] = await Promise.all([
5
+ user.replaceable(kinds.BookmarkList).$first(1000, undefined),
6
+ user.outboxes$.$first(1000, undefined),
7
+ ]);
8
+ return [event ? BookmarkListFactory.modify(event) : BookmarkListFactory.create(), outboxes];
20
9
  }
21
- function ModifyBookmarkListEvent(operations, hidden = false) {
22
- return async ({ factory, user, publish, sign }) => {
23
- const [event, outboxes] = await Promise.all([
24
- user.replaceable(kinds.BookmarkList).$first(1000, undefined),
25
- user.outboxes$.$first(1000, undefined),
26
- ]);
27
- const operation = hidden ? modifyHiddenTags(...operations) : modifyPublicTags(...operations);
28
- // Modify or build new event
29
- const signed = event
30
- ? await factory.modify(event, operation).then(sign)
31
- : await factory.build({ kind: kinds.BookmarkList }, operation).then(sign);
32
- // Publish the event to the user's outboxes
33
- await publish(signed, outboxes);
34
- };
10
+ async function modifyBookmarkSet(identifier, { user }) {
11
+ const [event, outboxes] = await Promise.all([
12
+ user.replaceable(kinds.Bookmarksets, identifier).$first(1000, undefined),
13
+ user.outboxes$.$first(1000, undefined),
14
+ ]);
15
+ return [event ? BookmarkSetFactory.modify(event) : BookmarkSetFactory.create(), outboxes];
35
16
  }
36
17
  /**
37
18
  * An action that adds a note or article to the bookmark list or a bookmark set
@@ -40,12 +21,20 @@ function ModifyBookmarkListEvent(operations, hidden = false) {
40
21
  * @param hidden set to true to add to hidden bookmarks
41
22
  */
42
23
  export function BookmarkEvent(event, identifier, hidden) {
43
- const operation = addEventBookmarkTag(event);
44
24
  if (typeof identifier === "string" || identifier?.kind === kinds.Bookmarksets) {
45
- return ModifyBookmarkSetEvent([operation], identifier, hidden);
25
+ const id = typeof identifier === "string" ? identifier : getReplaceableIdentifier(identifier);
26
+ return async (context) => {
27
+ const [factory, outboxes] = await modifyBookmarkSet(id, context);
28
+ const signed = await factory.bookmarkEvent(event, hidden).sign(context.signer);
29
+ await context.publish(signed, outboxes);
30
+ };
46
31
  }
47
32
  else if (identifier === undefined || identifier?.kind === kinds.BookmarkList) {
48
- return ModifyBookmarkListEvent([operation], hidden);
33
+ return async (context) => {
34
+ const [factory, outboxes] = await modifyBookmarkList(context);
35
+ const signed = await factory.bookmarkEvent(event, hidden).sign(context.signer);
36
+ await context.publish(signed, outboxes);
37
+ };
49
38
  }
50
39
  else {
51
40
  throw new Error(`Event kind ${identifier.kind} is not a bookmark list or bookmark set`);
@@ -58,12 +47,20 @@ export function BookmarkEvent(event, identifier, hidden) {
58
47
  * @param hidden set to true to remove from hidden bookmarks
59
48
  */
60
49
  export function UnbookmarkEvent(event, identifier, hidden) {
61
- const operation = removeEventBookmarkTag(event);
62
50
  if (typeof identifier === "string" || identifier?.kind === kinds.Bookmarksets) {
63
- return ModifyBookmarkSetEvent([operation], identifier, hidden);
51
+ const id = typeof identifier === "string" ? identifier : getReplaceableIdentifier(identifier);
52
+ return async (context) => {
53
+ const [factory, outboxes] = await modifyBookmarkSet(id, context);
54
+ const signed = await factory.unbookmarkEvent(event, hidden).sign(context.signer);
55
+ await context.publish(signed, outboxes);
56
+ };
64
57
  }
65
58
  else if (identifier === undefined || identifier?.kind === kinds.BookmarkList) {
66
- return ModifyBookmarkListEvent([operation], hidden);
59
+ return async (context) => {
60
+ const [factory, outboxes] = await modifyBookmarkList(context);
61
+ const signed = await factory.unbookmarkEvent(event, hidden).sign(context.signer);
62
+ await context.publish(signed, outboxes);
63
+ };
67
64
  }
68
65
  else {
69
66
  throw new Error(`Event kind ${identifier.kind} is not a bookmark list or bookmark set`);
@@ -71,22 +68,28 @@ export function UnbookmarkEvent(event, identifier, hidden) {
71
68
  }
72
69
  /** An action that creates a new bookmark list for a user */
73
70
  export function CreateBookmarkList(bookmarks) {
74
- return async ({ events, factory, self, user, publish, sign }) => {
75
- const existing = events.getReplaceable(kinds.BookmarkList, self);
71
+ return async ({ user, signer, publish }) => {
72
+ const existing = await user.replaceable(kinds.BookmarkList).$first(1000, undefined);
76
73
  if (existing)
77
74
  throw new Error("Bookmark list already exists");
78
- const signed = await factory
79
- .build({ kind: kinds.BookmarkList }, bookmarks ? modifyPublicTags(...bookmarks.map(addEventBookmarkTag)) : undefined)
80
- .then(sign);
75
+ let factory = BookmarkListFactory.create();
76
+ if (bookmarks)
77
+ factory = bookmarks.reduce((f, b) => f.bookmarkEvent(b), factory);
78
+ const signed = await factory.sign(signer);
81
79
  await publish(signed, await user.outboxes$.$first(1000, undefined));
82
80
  };
83
81
  }
84
82
  /** An action that creates a new bookmark set for a user */
85
83
  export function CreateBookmarkSet(title, description, additional) {
86
- return async ({ factory, user, publish, sign }) => {
87
- const signed = await factory
88
- .build({ kind: kinds.BookmarkList }, List.setTitle(title), List.setDescription(description), additional.image ? List.setImage(additional.image) : undefined, additional.public ? modifyPublicTags(...additional.public.map(addEventBookmarkTag)) : undefined, additional.hidden ? modifyHiddenTags(...additional.hidden.map(addEventBookmarkTag)) : undefined)
89
- .then(sign);
84
+ return async ({ signer, user, publish }) => {
85
+ let factory = BookmarkSetFactory.create().title(title).description(description);
86
+ if (additional.image)
87
+ factory = factory.image(additional.image);
88
+ if (additional.public)
89
+ factory = additional.public.reduce((f, b) => f.bookmarkEvent(b), factory);
90
+ if (additional.hidden)
91
+ factory = additional.hidden.reduce((f, b) => f.bookmarkEvent(b, true), factory);
92
+ const signed = await factory.sign(signer);
90
93
  await publish(signed, await user.outboxes$.$first(1000, undefined));
91
94
  };
92
95
  }
@@ -5,5 +5,5 @@ import { Action } from "../action-runner.js";
5
5
  export declare function AddEventToCalendar(calendar: NostrEvent | AddressPointer, event: NostrEvent | AddressPointer): Action;
6
6
  /** Removes a calendar event from a calendar */
7
7
  export declare function RemoveEventFromCalendar(calendar: NostrEvent | AddressPointer, event: NostrEvent | AddressPointer): Action;
8
- /** Creates a new calendar event with title and events */
8
+ /** Creates a new calendar with a title and optional events */
9
9
  export declare function CreateCalendar(title: string, events?: (NostrEvent | AddressPointer)[]): Action;
@@ -1,39 +1,45 @@
1
+ import { CalendarFactory } from "applesauce-common/factories";
1
2
  import { DATE_BASED_CALENDAR_EVENT_KIND, TIME_BASED_CALENDAR_EVENT_KIND, } from "applesauce-common/helpers/calendar-event";
2
- import * as Calendar from "applesauce-common/operations/calendar";
3
- import { isEvent, kinds } from "applesauce-core/helpers/event";
3
+ import { isEvent } from "applesauce-core/helpers/event";
4
4
  import { firstValueFrom, of, timeout } from "rxjs";
5
- function ModifyCalendarEvent(calendar, operations) {
6
- return async ({ factory, user, publish, events, sign }) => {
7
- const [event, outboxes] = await Promise.all([
8
- isEvent(calendar)
9
- ? Promise.resolve(calendar)
10
- : firstValueFrom(events.replaceable(kinds.Calendar, user.pubkey).pipe(timeout({ first: 1000, with: () => of(undefined) }))),
11
- user.outboxes$.$first(1000, undefined),
12
- ]);
13
- if (!event)
14
- throw new Error("Calendar event not found");
15
- const signed = await factory.modify(event, ...operations).then(sign);
16
- await publish(signed, outboxes);
17
- };
5
+ async function modifyCalendar(calendar, { events, user }) {
6
+ const [calendarEvent, outboxes] = await Promise.all([
7
+ isEvent(calendar)
8
+ ? Promise.resolve(calendar)
9
+ : firstValueFrom(events.replaceable(calendar).pipe(timeout({ first: 1000, with: () => of(undefined) }))),
10
+ user.outboxes$.$first(1000, undefined),
11
+ ]);
12
+ if (!calendarEvent)
13
+ throw new Error("Calendar event not found");
14
+ return [CalendarFactory.modify(calendarEvent), outboxes];
18
15
  }
19
16
  /** Adds a calendar event to a calendar */
20
17
  export function AddEventToCalendar(calendar, event) {
21
18
  if (event.kind !== DATE_BASED_CALENDAR_EVENT_KIND && event.kind !== TIME_BASED_CALENDAR_EVENT_KIND)
22
19
  throw new Error("Event is not a calendar event");
23
- return ModifyCalendarEvent(calendar, [Calendar.addEvent(event)]);
20
+ return async (context) => {
21
+ const [factory, outboxes] = await modifyCalendar(calendar, context);
22
+ const signed = await factory.addEvent(event).sign(context.signer);
23
+ await context.publish(signed, outboxes);
24
+ };
24
25
  }
25
26
  /** Removes a calendar event from a calendar */
26
27
  export function RemoveEventFromCalendar(calendar, event) {
27
28
  if (event.kind !== DATE_BASED_CALENDAR_EVENT_KIND && event.kind !== TIME_BASED_CALENDAR_EVENT_KIND)
28
29
  throw new Error("Event is not a calendar event");
29
- return ModifyCalendarEvent(calendar, [Calendar.removeEvent(event)]);
30
+ return async (context) => {
31
+ const [factory, outboxes] = await modifyCalendar(calendar, context);
32
+ const signed = await factory.removeEvent(event).sign(context.signer);
33
+ await context.publish(signed, outboxes);
34
+ };
30
35
  }
31
- /** Creates a new calendar event with title and events */
36
+ /** Creates a new calendar with a title and optional events */
32
37
  export function CreateCalendar(title, events) {
33
- return async ({ factory, sign, publish, user }) => {
34
- const event = await factory
35
- .build({ kind: kinds.Calendar }, Calendar.setTitle(title), ...(events?.map((event) => Calendar.addEvent(event)) ?? []))
36
- .then(sign);
37
- await publish(event, await user.outboxes$.$first(1000, undefined));
38
+ return async ({ signer, publish, user }) => {
39
+ let factory = CalendarFactory.create(title);
40
+ for (const event of events ?? [])
41
+ factory = factory.addEvent(event);
42
+ const signed = await factory.sign(signer);
43
+ await publish(signed, await user.outboxes$.$first(1000, undefined));
38
44
  };
39
45
  }
@@ -1,4 +1,4 @@
1
- import { CommentBlueprintOptions } from "applesauce-common/blueprints";
1
+ import { CommentBlueprintOptions } from "applesauce-common/factories";
2
2
  import { CommentPointer } from "applesauce-common/helpers/comment";
3
3
  import { NostrEvent } from "applesauce-core/helpers/event";
4
4
  import { Action } from "../action-runner.js";
@@ -1,4 +1,4 @@
1
- import { CommentBlueprint } from "applesauce-common/blueprints";
1
+ import { CommentFactory } from "applesauce-common/factories";
2
2
  import { castUser } from "applesauce-common/casts";
3
3
  import { isCommentAddressPointer, isCommentEventPointer } from "applesauce-common/helpers/comment";
4
4
  import { relaySet } from "applesauce-core/helpers";
@@ -23,7 +23,9 @@ function getParentPubkey(parent) {
23
23
  * - The current user's outboxes
24
24
  */
25
25
  export function CreateComment(parent, content, options) {
26
- return async ({ factory, user, publish, events, sign }) => {
26
+ return async ({ signer, user, publish, events }) => {
27
+ if (!signer)
28
+ throw new Error("Missing signer");
27
29
  // Get the parent author's pubkey from the pointer/event (without loading the full event)
28
30
  const parentAuthorPubkey = getParentPubkey(parent);
29
31
  // Get the parent author's inboxes in parallel with resolving the event
@@ -34,7 +36,7 @@ export function CreateComment(parent, content, options) {
34
36
  user.outboxes$.$first(1_000, undefined),
35
37
  ]);
36
38
  // Create and sign the comment
37
- const comment = await factory.create(CommentBlueprint, parent, content, options).then(sign);
39
+ const comment = await CommentFactory.create(parent, content, options).sign(signer);
38
40
  // Combine all relay lists (remove duplicates)
39
41
  const relays = relaySet(parentAuthorInboxes, userOutboxes);
40
42
  // Publish to all relays (inboxes and outboxes)
@@ -1,8 +1,8 @@
1
1
  import { ProfilePointer } from "applesauce-core/helpers/pointers";
2
2
  import { Action } from "../action-runner.js";
3
3
  /** An action that adds a pubkey to a users contacts event */
4
- export declare function FollowUser(user: string | ProfilePointer): Action;
4
+ export declare function FollowUser(pointer: string | ProfilePointer): Action;
5
5
  /** An action that removes a pubkey from a users contacts event */
6
- export declare function UnfollowUser(user: string | ProfilePointer): Action;
7
- /** An action that creates a new kind 3 contacts lists, throws if a contact list already exists */
6
+ export declare function UnfollowUser(pointer: string | ProfilePointer): Action;
7
+ /** An action that creates a new kind 3 contacts list, throws if a contact list already exists */
8
8
  export declare function NewContacts(pubkeys?: (string | ProfilePointer)[]): Action;
@@ -1,40 +1,38 @@
1
- import { kinds } from "applesauce-core/helpers/event";
2
- import { modifyPublicTags } from "applesauce-core/operations";
3
- import { addProfilePointerTag, removeProfilePointerTag } from "applesauce-core/operations/tag/common";
4
- import { firstValueFrom, of, timeout } from "rxjs";
5
- function ModifyContactsEvent(operations) {
6
- return async ({ events, factory, user, publish, sign }) => {
7
- const [event, outboxes] = await Promise.all([
8
- firstValueFrom(events.replaceable(kinds.Contacts, user.pubkey).pipe(timeout({ first: 1000, with: () => of(undefined) }))),
9
- user.outboxes$.$first(1000, undefined),
10
- ]);
11
- const operation = modifyPublicTags(...operations);
12
- // Modify or build new event
13
- const signed = event
14
- ? await factory.modify(event, operation).then(sign)
15
- : await factory.build({ kind: kinds.Contacts }, operation).then(sign);
16
- // Publish the event to the user's outboxes
17
- await publish(signed, outboxes);
18
- };
1
+ import { ContactsFactory } from "applesauce-common/factories";
2
+ import { kinds } from "applesauce-core/helpers";
3
+ async function modifyContacts({ user }) {
4
+ const [event, outboxes] = await Promise.all([
5
+ user.replaceable(kinds.Contacts).$first(1000, undefined),
6
+ user.outboxes$.$first(1000, undefined),
7
+ ]);
8
+ return [event ? ContactsFactory.modify(event) : ContactsFactory.create(), outboxes];
19
9
  }
20
10
  /** An action that adds a pubkey to a users contacts event */
21
- export function FollowUser(user) {
22
- return ModifyContactsEvent([addProfilePointerTag(user)]);
11
+ export function FollowUser(pointer) {
12
+ return async (context) => {
13
+ const [factory, outboxes] = await modifyContacts(context);
14
+ const signed = await factory.addContact(pointer).sign(context.signer);
15
+ await context.publish(signed, outboxes);
16
+ };
23
17
  }
24
18
  /** An action that removes a pubkey from a users contacts event */
25
- export function UnfollowUser(user) {
26
- return ModifyContactsEvent([removeProfilePointerTag(user)]);
19
+ export function UnfollowUser(pointer) {
20
+ return async (context) => {
21
+ const [factory, outboxes] = await modifyContacts(context);
22
+ const signed = await factory.removeContact(pointer).sign(context.signer);
23
+ await context.publish(signed, outboxes);
24
+ };
27
25
  }
28
- /** An action that creates a new kind 3 contacts lists, throws if a contact list already exists */
26
+ /** An action that creates a new kind 3 contacts list, throws if a contact list already exists */
29
27
  export function NewContacts(pubkeys) {
30
- return async ({ events, factory, self, user, publish, sign }) => {
31
- const contacts = events.getReplaceable(kinds.Contacts, self);
32
- if (contacts)
28
+ return async ({ user, signer, publish }) => {
29
+ const existing = await user.replaceable(kinds.Contacts).$first(1000, undefined);
30
+ if (existing)
33
31
  throw new Error("Contact list already exists");
34
- const signed = await factory
35
- .build({ kind: kinds.Contacts }, pubkeys ? modifyPublicTags(...pubkeys.map((p) => addProfilePointerTag(p))) : undefined)
36
- .then(sign);
37
- // Publish the event to the user's outboxes
32
+ let factory = ContactsFactory.create();
33
+ if (pubkeys?.length)
34
+ factory = pubkeys.reduce((f, p) => f.addContact(p), factory);
35
+ const signed = await factory.sign(signer);
38
36
  await publish(signed, await user.outboxes$.$first(1000, undefined));
39
37
  };
40
38
  }