applesauce-actions 0.0.0-next-20251209200210 → 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.
- package/README.md +3 -3
- package/dist/action-runner.d.ts +53 -0
- package/dist/action-runner.js +91 -0
- package/dist/actions/app-data.d.ts +1 -1
- package/dist/actions/app-data.js +5 -5
- package/dist/actions/blocked-relays.d.ts +1 -6
- package/dist/actions/blocked-relays.js +30 -36
- package/dist/actions/blossom.d.ts +1 -1
- package/dist/actions/blossom.js +25 -32
- package/dist/actions/bookmarks.d.ts +4 -3
- package/dist/actions/bookmarks.js +64 -55
- package/dist/actions/calendar.d.ts +6 -3
- package/dist/actions/calendar.js +26 -12
- package/dist/actions/comment.d.ts +10 -0
- package/dist/actions/comment.js +43 -0
- package/dist/actions/contacts.d.ts +3 -3
- package/dist/actions/contacts.js +27 -27
- package/dist/actions/direct-message-relays.d.ts +7 -0
- package/dist/actions/direct-message-relays.js +47 -0
- package/dist/actions/favorite-relays.d.ts +1 -1
- package/dist/actions/favorite-relays.js +34 -33
- package/dist/actions/follow-sets.d.ts +1 -3
- package/dist/actions/follow-sets.js +32 -31
- package/dist/actions/index.d.ts +2 -1
- package/dist/actions/index.js +2 -1
- package/dist/actions/legacy-messages.d.ts +2 -2
- package/dist/actions/legacy-messages.js +24 -9
- package/dist/actions/lists.d.ts +1 -1
- package/dist/actions/lists.js +5 -3
- package/dist/actions/mailboxes.d.ts +1 -1
- package/dist/actions/mailboxes.js +31 -29
- package/dist/actions/mute.d.ts +1 -1
- package/dist/actions/mute.js +32 -60
- package/dist/actions/pins.d.ts +1 -3
- package/dist/actions/pins.js +20 -26
- package/dist/actions/profile.d.ts +1 -1
- package/dist/actions/profile.js +14 -9
- package/dist/actions/relay-sets.d.ts +1 -1
- package/dist/actions/relay-sets.js +36 -29
- package/dist/actions/search-relays.d.ts +1 -1
- package/dist/actions/search-relays.js +19 -19
- package/dist/actions/wrapped-messages.d.ts +4 -2
- package/dist/actions/wrapped-messages.js +35 -14
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +4 -4
- package/dist/action-hub.d.ts +0 -35
- package/dist/action-hub.js +0 -51
- package/dist/actions/dm-relays.d.ts +0 -7
- package/dist/actions/dm-relays.js +0 -38
package/README.md
CHANGED
|
@@ -18,12 +18,12 @@ Actions are common pre-built async operations that apps can perform. They use:
|
|
|
18
18
|
- `EventFactory` to build and sign new nostr events
|
|
19
19
|
- A `publish` method to publish or save the resulting events
|
|
20
20
|
|
|
21
|
-
The package provides an `
|
|
21
|
+
The package provides an `ActionRunner` class that combines these components into a single manager for easier action execution.
|
|
22
22
|
|
|
23
23
|
## Basic Usage
|
|
24
24
|
|
|
25
25
|
```typescript
|
|
26
|
-
import {
|
|
26
|
+
import { ActionRunner } from "applesauce-actions";
|
|
27
27
|
import { FollowUser } from "applesauce-actions/actions";
|
|
28
28
|
|
|
29
29
|
async function publishEvent(event: NostrEvent) {
|
|
@@ -31,7 +31,7 @@ async function publishEvent(event: NostrEvent) {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
// Create an action hub with your event store, factory and publish method
|
|
34
|
-
const hub = new
|
|
34
|
+
const hub = new ActionRunner(eventStore, eventFactory, publishEvent);
|
|
35
35
|
|
|
36
36
|
// Example: Follow a user
|
|
37
37
|
await hub
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { User } from "applesauce-common/casts/user";
|
|
2
|
+
import { EventFactory, EventSigner } from "applesauce-core/event-factory";
|
|
3
|
+
import { EventModels, IEventStoreActions, IEventStoreRead, IEventStoreStreams, IEventSubscriptions } from "applesauce-core/event-store";
|
|
4
|
+
import { EventTemplate, NostrEvent, UnsignedEvent } from "applesauce-core/helpers/event";
|
|
5
|
+
import { Observable } from "rxjs";
|
|
6
|
+
/** A callback used to tell the upstream app to publish an event */
|
|
7
|
+
export type PublishMethod = (event: NostrEvent, relays?: string[]) => void | Promise<any> | Observable<any>;
|
|
8
|
+
type UpstreamPool = PublishMethod | {
|
|
9
|
+
publish: PublishMethod;
|
|
10
|
+
};
|
|
11
|
+
/** The context that is passed to actions for them to use to preform actions */
|
|
12
|
+
export type ActionContext = {
|
|
13
|
+
/** The event store to load events from */
|
|
14
|
+
events: IEventStoreRead & IEventStoreStreams & IEventSubscriptions & EventModels;
|
|
15
|
+
/** The pubkey of the signer in the event factory */
|
|
16
|
+
self: string;
|
|
17
|
+
/** The {@link User} cast that is signing the events */
|
|
18
|
+
user: User;
|
|
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 */
|
|
24
|
+
sign: (draft: EventTemplate | UnsignedEvent) => Promise<NostrEvent>;
|
|
25
|
+
/** The method to publish events to an optional list of relays */
|
|
26
|
+
publish: (event: NostrEvent | NostrEvent[], relays?: string[]) => Promise<void>;
|
|
27
|
+
/** Run a sub-action within the current action context and return the events */
|
|
28
|
+
run: <Args extends Array<any>>(builder: ActionBuilder<Args>, ...args: Args) => Promise<void>;
|
|
29
|
+
};
|
|
30
|
+
/** An action that can be run in a context to preform an action */
|
|
31
|
+
export type Action = (context: ActionContext) => Promise<void>;
|
|
32
|
+
/** A function that takes arguments and returns an action */
|
|
33
|
+
export type ActionBuilder<Args extends Array<any>> = (...args: Args) => Action;
|
|
34
|
+
/** The main class that runs actions */
|
|
35
|
+
export declare class ActionRunner {
|
|
36
|
+
events: IEventStoreRead & IEventStoreStreams & IEventSubscriptions & IEventStoreActions & EventModels;
|
|
37
|
+
factory: EventFactory;
|
|
38
|
+
private publishMethod?;
|
|
39
|
+
/** Whether to save all events created by actions to the event store */
|
|
40
|
+
saveToStore: boolean;
|
|
41
|
+
constructor(events: IEventStoreRead & IEventStoreStreams & IEventSubscriptions & IEventStoreActions & EventModels, factory: EventFactory, publishMethod?: UpstreamPool | undefined);
|
|
42
|
+
protected context: ActionContext | undefined;
|
|
43
|
+
protected getContext(): Promise<ActionContext>;
|
|
44
|
+
/** Internal method for publishing events to relays */
|
|
45
|
+
publish(event: NostrEvent | NostrEvent[], relays?: string[]): Promise<void>;
|
|
46
|
+
/** Run an action and publish events using the publish method */
|
|
47
|
+
run<Args extends Array<any>>(builder: ActionBuilder<Args>, ...args: Args): Promise<void>;
|
|
48
|
+
/** Run an action without publishing the events */
|
|
49
|
+
exec<Args extends Array<any>>(builder: ActionBuilder<Args>, ...args: Args): Observable<NostrEvent>;
|
|
50
|
+
}
|
|
51
|
+
/** @deprecated Use ActionRunner instead */
|
|
52
|
+
export declare const ActionHub: typeof ActionRunner;
|
|
53
|
+
export {};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { castUser } from "applesauce-common/casts/user";
|
|
2
|
+
import { from, identity, isObservable, lastValueFrom, Observable, switchMap, tap } from "rxjs";
|
|
3
|
+
/** The main class that runs actions */
|
|
4
|
+
export class ActionRunner {
|
|
5
|
+
events;
|
|
6
|
+
factory;
|
|
7
|
+
publishMethod;
|
|
8
|
+
/** Whether to save all events created by actions to the event store */
|
|
9
|
+
saveToStore = true;
|
|
10
|
+
constructor(events, factory, publishMethod) {
|
|
11
|
+
this.events = events;
|
|
12
|
+
this.factory = factory;
|
|
13
|
+
this.publishMethod = publishMethod;
|
|
14
|
+
}
|
|
15
|
+
context = undefined;
|
|
16
|
+
async getContext() {
|
|
17
|
+
if (this.context)
|
|
18
|
+
return this.context;
|
|
19
|
+
else {
|
|
20
|
+
if (!this.factory.context.signer)
|
|
21
|
+
throw new Error("Missing signer");
|
|
22
|
+
const self = await this.factory.context.signer.getPublicKey();
|
|
23
|
+
const user = castUser(self, this.events);
|
|
24
|
+
this.context = {
|
|
25
|
+
self,
|
|
26
|
+
user,
|
|
27
|
+
events: this.events,
|
|
28
|
+
signer: this.factory.context.signer,
|
|
29
|
+
factory: this.factory,
|
|
30
|
+
publish: this.publish.bind(this),
|
|
31
|
+
run: this.run.bind(this),
|
|
32
|
+
sign: this.factory.sign.bind(this.factory),
|
|
33
|
+
};
|
|
34
|
+
return this.context;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/** Internal method for publishing events to relays */
|
|
38
|
+
async publish(event, relays) {
|
|
39
|
+
if (!this.publishMethod)
|
|
40
|
+
throw new Error("Missing publish method, use ActionRunner.exec");
|
|
41
|
+
// Unwrap array of events to publish
|
|
42
|
+
if (Array.isArray(event)) {
|
|
43
|
+
await Promise.all(event.map((e) => this.publish(e, relays)));
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (this.publishMethod) {
|
|
47
|
+
let result;
|
|
48
|
+
if ("publish" in this.publishMethod)
|
|
49
|
+
result = this.publishMethod.publish(event, relays);
|
|
50
|
+
else if (typeof this.publishMethod === "function")
|
|
51
|
+
result = this.publishMethod(event, relays);
|
|
52
|
+
else
|
|
53
|
+
throw new Error("Invalid publish method");
|
|
54
|
+
if (isObservable(result)) {
|
|
55
|
+
await lastValueFrom(result);
|
|
56
|
+
}
|
|
57
|
+
else if (result instanceof Promise) {
|
|
58
|
+
await result;
|
|
59
|
+
}
|
|
60
|
+
// Optionally save the event to the store
|
|
61
|
+
if (this.saveToStore)
|
|
62
|
+
this.events.add(event);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/** Run an action and publish events using the publish method */
|
|
66
|
+
async run(builder, ...args) {
|
|
67
|
+
// wait for action to complete and group events
|
|
68
|
+
const context = await this.getContext();
|
|
69
|
+
await builder(...args)(context);
|
|
70
|
+
}
|
|
71
|
+
/** Run an action without publishing the events */
|
|
72
|
+
exec(builder, ...args) {
|
|
73
|
+
return from(this.getContext()).pipe(
|
|
74
|
+
// Run the action
|
|
75
|
+
switchMap((ctx) => {
|
|
76
|
+
return new Observable((subscriber) => {
|
|
77
|
+
const context = {
|
|
78
|
+
...ctx,
|
|
79
|
+
publish: async (event) => Array.isArray(event) ? event.forEach((e) => subscriber.next(e)) : subscriber.next(event),
|
|
80
|
+
run: (builder, ...args) => builder(...args)(context),
|
|
81
|
+
};
|
|
82
|
+
builder(...args)(context).then(() => subscriber.complete(), (err) => subscriber.error(err));
|
|
83
|
+
});
|
|
84
|
+
}),
|
|
85
|
+
// NOTE: its necessary to add a tap() here because we are overwriting the publish method above
|
|
86
|
+
// Optionally save all events to the store
|
|
87
|
+
this.saveToStore ? tap((event) => this.events.add(event)) : identity);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/** @deprecated Use ActionRunner instead */
|
|
91
|
+
export const ActionHub = ActionRunner;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Action } from "../action-
|
|
1
|
+
import { Action } from "../action-runner.js";
|
|
2
2
|
export declare function UpdateAppData<T>(identifier: string, data: T): Action;
|
package/dist/actions/app-data.js
CHANGED
|
@@ -2,12 +2,12 @@ import { AppDataBlueprint } from "applesauce-common/blueprints/app-data";
|
|
|
2
2
|
import { APP_DATA_KIND, getAppDataEncryption } from "applesauce-common/helpers/app-data";
|
|
3
3
|
import * as AppData from "applesauce-common/operations/app-data";
|
|
4
4
|
export function UpdateAppData(identifier, data) {
|
|
5
|
-
return async
|
|
5
|
+
return async ({ self, factory, events, user, publish, sign }) => {
|
|
6
6
|
const event = events.getReplaceable(APP_DATA_KIND, self, identifier);
|
|
7
7
|
const encryption = !!event && getAppDataEncryption(event);
|
|
8
|
-
const
|
|
9
|
-
? await factory.modify(event, AppData.setContent(data, encryption))
|
|
10
|
-
: await factory.create(AppDataBlueprint, identifier, data, encryption);
|
|
11
|
-
|
|
8
|
+
const signed = event
|
|
9
|
+
? await factory.modify(event, AppData.setContent(data, encryption)).then(sign)
|
|
10
|
+
: await factory.create(AppDataBlueprint, identifier, data, encryption).then(sign);
|
|
11
|
+
await publish(signed, await user.outboxes$.$first(1000, undefined));
|
|
12
12
|
};
|
|
13
13
|
}
|
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
import { Action } from "../action-
|
|
1
|
+
import { Action } from "../action-runner.js";
|
|
2
2
|
/** An action that adds a relay to the 10006 blocked relays event */
|
|
3
3
|
export declare function AddBlockedRelay(relay: string | string[], hidden?: boolean): Action;
|
|
4
4
|
/** An action that removes a relay from the 10006 blocked relays event */
|
|
5
5
|
export declare function RemoveBlockedRelay(relay: string | string[], hidden?: boolean): Action;
|
|
6
|
-
/** Creates a new blocked relays event */
|
|
7
|
-
export declare function NewBlockedRelays(relays?: string[] | {
|
|
8
|
-
public?: string[];
|
|
9
|
-
hidden?: string[];
|
|
10
|
-
}): Action;
|
|
@@ -1,48 +1,42 @@
|
|
|
1
|
+
import { firstValueFrom } from "applesauce-core";
|
|
1
2
|
import { kinds } from "applesauce-core/helpers/event";
|
|
2
3
|
import { modifyHiddenTags, modifyPublicTags } from "applesauce-core/operations";
|
|
3
4
|
import { addRelayTag, removeRelayTag } from "applesauce-core/operations/tag/relay";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
+
};
|
|
9
22
|
}
|
|
10
23
|
/** An action that adds a relay to the 10006 blocked relays event */
|
|
11
24
|
export function AddBlockedRelay(relay, hidden = false) {
|
|
12
|
-
return async
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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]);
|
|
17
31
|
};
|
|
18
32
|
}
|
|
19
33
|
/** An action that removes a relay from the 10006 blocked relays event */
|
|
20
34
|
export function RemoveBlockedRelay(relay, hidden = false) {
|
|
21
|
-
return async
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
/** Creates a new blocked relays event */
|
|
29
|
-
export function NewBlockedRelays(relays) {
|
|
30
|
-
return async function* ({ events, factory, self }) {
|
|
31
|
-
const blocked = events.getReplaceable(kinds.BlockedRelaysList, self);
|
|
32
|
-
if (blocked)
|
|
33
|
-
throw new Error("Blocked relays event already exists");
|
|
34
|
-
let publicOperations = [];
|
|
35
|
-
let hiddenOperations = [];
|
|
36
|
-
if (Array.isArray(relays)) {
|
|
37
|
-
publicOperations.push(...relays.map((r) => addRelayTag(r)));
|
|
38
|
-
}
|
|
39
|
-
else {
|
|
40
|
-
if (relays?.public)
|
|
41
|
-
publicOperations.push(...(relays?.public ?? []).map((r) => addRelayTag(r)));
|
|
42
|
-
if (relays?.hidden)
|
|
43
|
-
hiddenOperations.push(...(relays?.hidden ?? []).map((r) => addRelayTag(r)));
|
|
44
|
-
}
|
|
45
|
-
const draft = await factory.build({ kind: kinds.BlockedRelaysList }, publicOperations.length ? modifyPublicTags(...publicOperations) : undefined, hiddenOperations.length ? modifyHiddenTags(...hiddenOperations) : undefined);
|
|
46
|
-
yield await factory.sign(draft);
|
|
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]);
|
|
47
41
|
};
|
|
48
42
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Action } from "../action-
|
|
1
|
+
import { 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 */
|
package/dist/actions/blossom.js
CHANGED
|
@@ -1,51 +1,44 @@
|
|
|
1
1
|
import { BLOSSOM_SERVER_LIST_KIND } from "applesauce-common/helpers/blossom";
|
|
2
2
|
import { addBlossomServer, removeBlossomServer } from "applesauce-common/operations/blossom";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
return async
|
|
6
|
-
const
|
|
7
|
-
|
|
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
|
+
]);
|
|
8
10
|
// Modify or build new event
|
|
9
|
-
const
|
|
10
|
-
? await factory.modify(
|
|
11
|
-
: await factory.build({ kind: BLOSSOM_SERVER_LIST_KIND }, ...operations);
|
|
12
|
-
|
|
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);
|
|
13
16
|
};
|
|
14
17
|
}
|
|
18
|
+
/** An action that adds a server to the Blossom servers event */
|
|
19
|
+
export function AddBlossomServer(server) {
|
|
20
|
+
return ModifyBlossomServersEvent(Array.isArray(server) ? server.map((s) => addBlossomServer(s)) : [addBlossomServer(server)]);
|
|
21
|
+
}
|
|
15
22
|
/** An action that removes a server from the Blossom servers event */
|
|
16
23
|
export function RemoveBlossomServer(server) {
|
|
17
|
-
return
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
// Modify or build new event
|
|
23
|
-
const draft = servers
|
|
24
|
-
? await factory.modify(servers, ...operations)
|
|
25
|
-
: await factory.build({ kind: BLOSSOM_SERVER_LIST_KIND }, ...operations);
|
|
26
|
-
yield await factory.sign(draft);
|
|
27
|
-
};
|
|
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] });
|
|
28
29
|
}
|
|
29
30
|
/** Makes a specific Blossom server the default server (move it to the top of the list) */
|
|
30
31
|
export function SetDefaultBlossomServer(server) {
|
|
31
|
-
return
|
|
32
|
-
const servers = events.getReplaceable(BLOSSOM_SERVER_LIST_KIND, self);
|
|
33
|
-
const prependTag = (tag) => (draft) => ({ ...draft, tags: [tag, ...draft.tags] });
|
|
34
|
-
const operations = [removeBlossomServer(server), prependTag(["server", String(server)])];
|
|
35
|
-
const draft = servers
|
|
36
|
-
? await factory.modify(servers, ...operations)
|
|
37
|
-
: await factory.build({ kind: BLOSSOM_SERVER_LIST_KIND }, ...operations);
|
|
38
|
-
yield await factory.sign(draft);
|
|
39
|
-
};
|
|
32
|
+
return ModifyBlossomServersEvent([removeBlossomServer(server), prependTag(["server", String(server)])]);
|
|
40
33
|
}
|
|
41
34
|
/** Creates a new Blossom servers event */
|
|
42
35
|
export function NewBlossomServers(servers) {
|
|
43
|
-
return async
|
|
36
|
+
return async ({ events, factory, self, user, publish, sign }) => {
|
|
44
37
|
const existing = events.getReplaceable(BLOSSOM_SERVER_LIST_KIND, self);
|
|
45
38
|
if (existing)
|
|
46
39
|
throw new Error("Blossom servers event already exists");
|
|
47
40
|
const operations = servers ? servers.map((s) => addBlossomServer(s)) : [];
|
|
48
|
-
const
|
|
49
|
-
|
|
41
|
+
const signed = await factory.build({ kind: BLOSSOM_SERVER_LIST_KIND }, ...operations).then(sign);
|
|
42
|
+
await publish(signed, await user.outboxes$.$first(1000, undefined));
|
|
50
43
|
};
|
|
51
44
|
}
|
|
@@ -1,19 +1,20 @@
|
|
|
1
|
+
import { AddressPointer, EventPointer } from "applesauce-core/helpers";
|
|
1
2
|
import { NostrEvent } from "applesauce-core/helpers/event";
|
|
2
|
-
import { Action } from "../action-
|
|
3
|
+
import { Action } from "../action-runner.js";
|
|
3
4
|
/**
|
|
4
5
|
* An action that adds a note or article to the bookmark list or a bookmark set
|
|
5
6
|
* @param event the event to bookmark
|
|
6
7
|
* @param identifier the "d" tag of the bookmark set or `undefined` for the default bookmark list
|
|
7
8
|
* @param hidden set to true to add to hidden bookmarks
|
|
8
9
|
*/
|
|
9
|
-
export declare function BookmarkEvent(event: NostrEvent, identifier?: string | NostrEvent, hidden?: boolean): Action;
|
|
10
|
+
export declare function BookmarkEvent(event: NostrEvent | EventPointer | AddressPointer, identifier?: string | NostrEvent, hidden?: boolean): Action;
|
|
10
11
|
/**
|
|
11
12
|
* An action that removes a note or article from the bookmark list or bookmark set
|
|
12
13
|
* @param event the event to remove from bookmarks
|
|
13
14
|
* @param identifier the "d" tag of the bookmark set or `undefined` for the default bookmark list
|
|
14
15
|
* @param hidden set to true to remove from hidden bookmarks
|
|
15
16
|
*/
|
|
16
|
-
export declare function UnbookmarkEvent(event: NostrEvent, identifier?: string | NostrEvent, hidden?: boolean): Action;
|
|
17
|
+
export declare function UnbookmarkEvent(event: NostrEvent | EventPointer | AddressPointer, identifier?: string | NostrEvent, hidden?: boolean): Action;
|
|
17
18
|
/** An action that creates a new bookmark list for a user */
|
|
18
19
|
export declare function CreateBookmarkList(bookmarks?: NostrEvent[]): Action;
|
|
19
20
|
/** An action that creates a new bookmark set for a user */
|
|
@@ -1,40 +1,55 @@
|
|
|
1
1
|
import * as List from "applesauce-common/operations/list";
|
|
2
2
|
import { addEventBookmarkTag, removeEventBookmarkTag } from "applesauce-common/operations/tag/bookmarks";
|
|
3
|
-
import { kinds } from "applesauce-core/helpers/event";
|
|
3
|
+
import { getReplaceableIdentifier, kinds } from "applesauce-core/helpers/event";
|
|
4
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
|
+
};
|
|
20
|
+
}
|
|
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
|
+
};
|
|
35
|
+
}
|
|
5
36
|
/**
|
|
6
37
|
* An action that adds a note or article to the bookmark list or a bookmark set
|
|
7
38
|
* @param event the event to bookmark
|
|
8
39
|
* @param identifier the "d" tag of the bookmark set or `undefined` for the default bookmark list
|
|
9
40
|
* @param hidden set to true to add to hidden bookmarks
|
|
10
41
|
*/
|
|
11
|
-
export function BookmarkEvent(event, identifier, hidden
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
: await factory.build({ kind: kinds.Bookmarksets }, hidden ? modifyHiddenTags(operation) : modifyPublicTags(operation));
|
|
23
|
-
}
|
|
24
|
-
else if (identifier === undefined || identifier?.kind === kinds.BookmarkList) {
|
|
25
|
-
const list = identifier ? identifier : events.getReplaceable(kinds.BookmarkList, self);
|
|
26
|
-
if (list && list.kind !== kinds.BookmarkList)
|
|
27
|
-
throw new Error("Event is not a bookmark list");
|
|
28
|
-
// Modify or build new event bookmark list
|
|
29
|
-
draft = list
|
|
30
|
-
? await factory.modifyTags(list, hidden ? { hidden: operation } : operation)
|
|
31
|
-
: await factory.build({ kind: kinds.BookmarkList }, hidden ? modifyHiddenTags(operation) : modifyPublicTags(operation));
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
throw new Error(`Event kind ${identifier.kind} is not a bookmark list or bookmark set`);
|
|
35
|
-
}
|
|
36
|
-
yield await factory.sign(draft);
|
|
37
|
-
};
|
|
42
|
+
export function BookmarkEvent(event, identifier, hidden) {
|
|
43
|
+
const operation = addEventBookmarkTag(event);
|
|
44
|
+
if (typeof identifier === "string" || identifier?.kind === kinds.Bookmarksets) {
|
|
45
|
+
return ModifyBookmarkSetEvent([operation], identifier, hidden);
|
|
46
|
+
}
|
|
47
|
+
else if (identifier === undefined || identifier?.kind === kinds.BookmarkList) {
|
|
48
|
+
return ModifyBookmarkListEvent([operation], hidden);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
throw new Error(`Event kind ${identifier.kind} is not a bookmark list or bookmark set`);
|
|
52
|
+
}
|
|
38
53
|
}
|
|
39
54
|
/**
|
|
40
55
|
* An action that removes a note or article from the bookmark list or bookmark set
|
|
@@ -42,42 +57,36 @@ export function BookmarkEvent(event, identifier, hidden = false) {
|
|
|
42
57
|
* @param identifier the "d" tag of the bookmark set or `undefined` for the default bookmark list
|
|
43
58
|
* @param hidden set to true to remove from hidden bookmarks
|
|
44
59
|
*/
|
|
45
|
-
export function UnbookmarkEvent(event, identifier, hidden
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
else {
|
|
58
|
-
throw new Error(`Event kind ${identifier.kind} is not a bookmark list or bookmark set`);
|
|
59
|
-
}
|
|
60
|
-
// If no list is found, return
|
|
61
|
-
if (!list)
|
|
62
|
-
return;
|
|
63
|
-
const draft = await factory.modifyTags(list, hidden ? { hidden: operation } : operation);
|
|
64
|
-
yield await factory.sign(draft);
|
|
65
|
-
};
|
|
60
|
+
export function UnbookmarkEvent(event, identifier, hidden) {
|
|
61
|
+
const operation = removeEventBookmarkTag(event);
|
|
62
|
+
if (typeof identifier === "string" || identifier?.kind === kinds.Bookmarksets) {
|
|
63
|
+
return ModifyBookmarkSetEvent([operation], identifier, hidden);
|
|
64
|
+
}
|
|
65
|
+
else if (identifier === undefined || identifier?.kind === kinds.BookmarkList) {
|
|
66
|
+
return ModifyBookmarkListEvent([operation], hidden);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
throw new Error(`Event kind ${identifier.kind} is not a bookmark list or bookmark set`);
|
|
70
|
+
}
|
|
66
71
|
}
|
|
67
72
|
/** An action that creates a new bookmark list for a user */
|
|
68
73
|
export function CreateBookmarkList(bookmarks) {
|
|
69
|
-
return async
|
|
74
|
+
return async ({ events, factory, self, user, publish, sign }) => {
|
|
70
75
|
const existing = events.getReplaceable(kinds.BookmarkList, self);
|
|
71
76
|
if (existing)
|
|
72
77
|
throw new Error("Bookmark list already exists");
|
|
73
|
-
const
|
|
74
|
-
|
|
78
|
+
const signed = await factory
|
|
79
|
+
.build({ kind: kinds.BookmarkList }, bookmarks ? modifyPublicTags(...bookmarks.map(addEventBookmarkTag)) : undefined)
|
|
80
|
+
.then(sign);
|
|
81
|
+
await publish(signed, await user.outboxes$.$first(1000, undefined));
|
|
75
82
|
};
|
|
76
83
|
}
|
|
77
84
|
/** An action that creates a new bookmark set for a user */
|
|
78
85
|
export function CreateBookmarkSet(title, description, additional) {
|
|
79
|
-
return async
|
|
80
|
-
const
|
|
81
|
-
|
|
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);
|
|
90
|
+
await publish(signed, await user.outboxes$.$first(1000, undefined));
|
|
82
91
|
};
|
|
83
92
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { AddressPointer } from "applesauce-core/helpers";
|
|
1
2
|
import { NostrEvent } from "applesauce-core/helpers/event";
|
|
2
|
-
import { Action } from "../action-
|
|
3
|
+
import { Action } from "../action-runner.js";
|
|
3
4
|
/** Adds a calendar event to a calendar */
|
|
4
|
-
export declare function AddEventToCalendar(calendar: NostrEvent, event: NostrEvent): Action;
|
|
5
|
+
export declare function AddEventToCalendar(calendar: NostrEvent | AddressPointer, event: NostrEvent | AddressPointer): Action;
|
|
5
6
|
/** Removes a calendar event from a calendar */
|
|
6
|
-
export declare function RemoveEventFromCalendar(calendar: NostrEvent, event: NostrEvent): Action;
|
|
7
|
+
export declare function RemoveEventFromCalendar(calendar: NostrEvent | AddressPointer, event: NostrEvent | AddressPointer): Action;
|
|
8
|
+
/** Creates a new calendar event with title and events */
|
|
9
|
+
export declare function CreateCalendar(title: string, events?: (NostrEvent | AddressPointer)[]): Action;
|
package/dist/actions/calendar.js
CHANGED
|
@@ -1,25 +1,39 @@
|
|
|
1
1
|
import { DATE_BASED_CALENDAR_EVENT_KIND, TIME_BASED_CALENDAR_EVENT_KIND, } from "applesauce-common/helpers/calendar-event";
|
|
2
|
-
import { kinds } from "applesauce-core/helpers/event";
|
|
3
2
|
import * as Calendar from "applesauce-common/operations/calendar";
|
|
3
|
+
import { isEvent, kinds } from "applesauce-core/helpers/event";
|
|
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
|
+
};
|
|
18
|
+
}
|
|
4
19
|
/** Adds a calendar event to a calendar */
|
|
5
20
|
export function AddEventToCalendar(calendar, event) {
|
|
6
|
-
if (calendar.kind !== kinds.Calendar)
|
|
7
|
-
throw new Error("Calendar is not a calendar event");
|
|
8
21
|
if (event.kind !== DATE_BASED_CALENDAR_EVENT_KIND && event.kind !== TIME_BASED_CALENDAR_EVENT_KIND)
|
|
9
22
|
throw new Error("Event is not a calendar event");
|
|
10
|
-
return
|
|
11
|
-
const draft = await factory.modify(calendar, Calendar.addEvent(event));
|
|
12
|
-
return await factory.sign(draft);
|
|
13
|
-
};
|
|
23
|
+
return ModifyCalendarEvent(calendar, [Calendar.addEvent(event)]);
|
|
14
24
|
}
|
|
15
25
|
/** Removes a calendar event from a calendar */
|
|
16
26
|
export function RemoveEventFromCalendar(calendar, event) {
|
|
17
|
-
if (calendar.kind !== kinds.Calendar)
|
|
18
|
-
throw new Error("Calendar is not a calendar event");
|
|
19
27
|
if (event.kind !== DATE_BASED_CALENDAR_EVENT_KIND && event.kind !== TIME_BASED_CALENDAR_EVENT_KIND)
|
|
20
28
|
throw new Error("Event is not a calendar event");
|
|
21
|
-
return
|
|
22
|
-
|
|
23
|
-
|
|
29
|
+
return ModifyCalendarEvent(calendar, [Calendar.removeEvent(event)]);
|
|
30
|
+
}
|
|
31
|
+
/** Creates a new calendar event with title and events */
|
|
32
|
+
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));
|
|
24
38
|
};
|
|
25
39
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { CommentBlueprintOptions } from "applesauce-common/blueprints";
|
|
2
|
+
import { CommentPointer } from "applesauce-common/helpers/comment";
|
|
3
|
+
import { NostrEvent } from "applesauce-core/helpers/event";
|
|
4
|
+
import { Action } from "../action-runner.js";
|
|
5
|
+
/**
|
|
6
|
+
* Creates a comment on an event or CommentPointer and publishes it to:
|
|
7
|
+
* - The parent event's author's inboxes (if the author exists and pubkey is available)
|
|
8
|
+
* - The current user's outboxes
|
|
9
|
+
*/
|
|
10
|
+
export declare function CreateComment(parent: NostrEvent | CommentPointer, content: string, options?: CommentBlueprintOptions): Action;
|