Actions
Actions are common pre-built async operations apps can perform. they use the EventStore
as state, the EventFactory
to build new events, and a publish
method to publish or save the resulting events
Action Hub
The ActionHub
class is a simple manager that combines the event store, event factory, and an optional publish method into a single place to make it easier to run actions
import { ActionHub } from "applesauce-actions";
// Custom publish logic
const publish = async (label: string, event: NostrEvent, explicitRelays?: string[]) => {
console.log("Publishing", label, event);
if (explicitRelays) {
await app.relayPool.publish(event, explicitRelays);
} else {
await app.relayPool.publish(event, app.defaultRelays);
}
};
// Create a new action hub with an event store, event factory, and custom publish method
const hub = new ActionHub(eventStore, eventFactory, publish);
// Or don't provide a publish method and manually handle the publishing for each action
const hub = new ActionHub(eventStore, eventFactory);
INFO
For performance reasons, its recommended to only create a single ActionHub
instance for your whole app
What is an action
An Action is an AsyncIterator that reads from the EventStore
and yields nostr events to be published using the EventFactory
You can see the full list of built-in actions in the reference
WARNING
To avoid overriding replaceable events, actions will throw if an existing replaceable event cant be found
Running using async/await
ActionHub.run can be used to run actions and await
for them to complete
WARNING
ActionHub.run
will throw an error if a publish
method was not provided when creating the new ActionHub
import { FollowUser } from "applesauce-actions/actions";
// create a new contact list event
try {
await hub.run(NewContacts);
} catch (err) {
// this will throw if a contact list already exists
}
// follow a user
await hub.run(
FollowUser,
"3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d",
"wss://pyramid.fiatjaf.com/",
);
Running using observables
If your looking to manually handle publish events for each action run, then ActionHub.exec can be used to run an action and subscribe to a stream of nostr events to publish
INFO
The RxJS Observable.forEach method provides a clean way to pipe all the events to a single method an use await
to wait for completion
import { FollowUser } from "applesauce-actions/actions";
// custom one-off publish method
const publish = (event) => {
relayPool.push(["wss://relay.com"], event);
// Extra work to save the contact list to a local DB
localDatabase.saveNewContacts(event);
};
// run the action and send all events to a custom publish method, then wait for complete
await hub.exec(NewContacts).forEach(publish);
// manually handle rxjs subscription
const sub = hub
.exec(FollowUser, "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d", "wss://pyramid.fiatjaf.com/")
.subscribe({
// pass events to publish methode
next: publish,
// cleanup subscription on complete
complete: () => sub.unsubscribe(),
});
Custom actions
Custom actions are simply methods that take custom arguments and return an async iterator method that yields signed nostr events to publish
import { Action } from "applesauce-actions";
import { updateProfileContent } from "applesauce-factory/operations/event";
function CustomSetNameAction(newName = "fiatjaf"): Action {
return async function* ({ events, factory, self }) {
// get the profile event
const profile = events.getReplaceable(0, self);
// throw if the profile event cant be found
if (!profile) throw new Error("Cant find profile");
// create a new unsigned profile event with a new name
const draft = await factory.modify(profile, updateProfileContent({ name: newName }));
// request the user to sign the event
const signed = await factory.sign(draft);
// ask the app the publish the app
yield signed;
};
}