applesauce-core 5.1.0 → 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.
Files changed (80) hide show
  1. package/dist/casts/cast.d.ts +31 -0
  2. package/dist/casts/cast.js +67 -0
  3. package/dist/casts/index.d.ts +3 -0
  4. package/dist/casts/index.js +3 -0
  5. package/dist/casts/pubkey.d.ts +27 -0
  6. package/dist/casts/pubkey.js +49 -0
  7. package/dist/casts/user.d.ts +19 -0
  8. package/dist/casts/user.js +25 -0
  9. package/dist/factories/delete.d.ts +18 -0
  10. package/dist/factories/delete.js +23 -0
  11. package/dist/factories/event.d.ts +61 -0
  12. package/dist/factories/event.js +164 -0
  13. package/dist/factories/index.d.ts +5 -0
  14. package/dist/factories/index.js +5 -0
  15. package/dist/factories/mailboxes.d.ts +33 -0
  16. package/dist/factories/mailboxes.js +57 -0
  17. package/dist/factories/profile.d.ts +46 -0
  18. package/dist/factories/profile.js +80 -0
  19. package/dist/factories/types.d.ts +56 -0
  20. package/dist/helpers/event.d.ts +11 -2
  21. package/dist/helpers/event.js +2 -1
  22. package/dist/helpers/mailboxes.d.ts +5 -1
  23. package/dist/helpers/mailboxes.js +5 -0
  24. package/dist/helpers/pipeline.d.ts +14 -1
  25. package/dist/helpers/pipeline.js +17 -2
  26. package/dist/helpers/pointers.d.ts +25 -21
  27. package/dist/helpers/pointers.js +33 -18
  28. package/dist/helpers/profile.d.ts +2 -2
  29. package/dist/helpers/regexp.d.ts +2 -0
  30. package/dist/helpers/regexp.js +8 -2
  31. package/dist/helpers/relays.d.ts +3 -1
  32. package/dist/helpers/relays.js +8 -10
  33. package/dist/helpers/url.d.ts +1 -4
  34. package/dist/helpers/url.js +1 -4
  35. package/dist/index.d.ts +3 -1
  36. package/dist/index.js +4 -1
  37. package/dist/observable/catch-error-inline.d.ts +3 -0
  38. package/dist/observable/catch-error-inline.js +5 -0
  39. package/dist/observable/chainable.d.ts +36 -0
  40. package/dist/observable/chainable.js +72 -0
  41. package/dist/observable/combine-latest-by-index.d.ts +10 -0
  42. package/dist/observable/combine-latest-by-index.js +121 -0
  43. package/dist/observable/combine-latest-by-key.d.ts +10 -0
  44. package/dist/observable/combine-latest-by-key.js +136 -0
  45. package/dist/observable/combine-latest-by-value.d.ts +10 -0
  46. package/dist/observable/combine-latest-by-value.js +117 -0
  47. package/dist/observable/combine-latest-by.d.ts +16 -0
  48. package/dist/observable/combine-latest-by.js +12 -0
  49. package/dist/observable/index.d.ts +10 -4
  50. package/dist/observable/index.js +10 -4
  51. package/dist/observable/timeout-with-ignore.d.ts +24 -0
  52. package/dist/observable/timeout-with-ignore.js +33 -0
  53. package/dist/operations/client.d.ts +1 -1
  54. package/dist/operations/client.js +2 -2
  55. package/dist/operations/content.d.ts +5 -2
  56. package/dist/operations/content.js +13 -9
  57. package/dist/operations/delete.d.ts +1 -1
  58. package/dist/operations/encrypted-content.d.ts +9 -3
  59. package/dist/operations/encrypted-content.js +9 -3
  60. package/dist/operations/event.d.ts +6 -4
  61. package/dist/operations/event.js +20 -12
  62. package/dist/operations/hidden-content.d.ts +8 -3
  63. package/dist/operations/hidden-content.js +11 -6
  64. package/dist/operations/mailboxes.d.ts +5 -1
  65. package/dist/operations/mailboxes.js +76 -0
  66. package/dist/operations/profile.d.ts +1 -1
  67. package/dist/operations/tag/common.d.ts +22 -7
  68. package/dist/operations/tag/common.js +33 -18
  69. package/dist/operations/tag/relay.d.ts +1 -1
  70. package/dist/operations/tags.d.ts +10 -4
  71. package/dist/operations/tags.js +19 -13
  72. package/package.json +20 -5
  73. package/dist/event-factory/event-factory.d.ts +0 -57
  74. package/dist/event-factory/event-factory.js +0 -94
  75. package/dist/event-factory/index.d.ts +0 -3
  76. package/dist/event-factory/index.js +0 -3
  77. package/dist/event-factory/methods.d.ts +0 -17
  78. package/dist/event-factory/methods.js +0 -44
  79. package/dist/event-factory/types.d.ts +0 -76
  80. /package/dist/{event-factory → factories}/types.js +0 -0
@@ -0,0 +1,24 @@
1
+ import { type ObservableInput, type ObservedValueOf, type OperatorFunction, type TimeoutConfig } from "rxjs";
2
+ /**
3
+ * Like RxJS `timeout`, but only for emissions that are not ignored.
4
+ *
5
+ * Values that match `config.ignore` are forwarded immediately and do not affect
6
+ * timeout state (`first`/`each`). Timeout timing only observes non-ignored values.
7
+ *
8
+ * Example usage:
9
+ *
10
+ * source$.pipe(
11
+ * timeoutWithIgnore({
12
+ * first: 1500,
13
+ * each: 1000,
14
+ * with: () => of(null),
15
+ * ignore: value => value === undefined,
16
+ * })
17
+ * )
18
+ *
19
+ * @param config RxJS timeout config with an additional `ignore` matcher
20
+ * (`(value) => boolean` or array of values) used to bypass timeout checks.
21
+ */
22
+ export declare function timeoutWithIgnore<T, O extends ObservableInput<unknown> = ObservableInput<T>, M = unknown>(config: TimeoutConfig<T, O, M> & {
23
+ ignore: readonly T[] | ((value: T) => boolean);
24
+ }): OperatorFunction<T, T | ObservedValueOf<O>>;
@@ -0,0 +1,33 @@
1
+ import { endWith, filter, ignoreElements, merge, share, takeUntil, timeout, } from "rxjs";
2
+ /**
3
+ * Like RxJS `timeout`, but only for emissions that are not ignored.
4
+ *
5
+ * Values that match `config.ignore` are forwarded immediately and do not affect
6
+ * timeout state (`first`/`each`). Timeout timing only observes non-ignored values.
7
+ *
8
+ * Example usage:
9
+ *
10
+ * source$.pipe(
11
+ * timeoutWithIgnore({
12
+ * first: 1500,
13
+ * each: 1000,
14
+ * with: () => of(null),
15
+ * ignore: value => value === undefined,
16
+ * })
17
+ * )
18
+ *
19
+ * @param config RxJS timeout config with an additional `ignore` matcher
20
+ * (`(value) => boolean` or array of values) used to bypass timeout checks.
21
+ */
22
+ export function timeoutWithIgnore(config) {
23
+ return (source) => {
24
+ const { ignore, ...timeoutConfig } = config;
25
+ const isIgnored = (value) => (typeof ignore === "function" ? ignore(value) : ignore.includes(value));
26
+ const shared$ = source.pipe(share());
27
+ const watched$ = shared$.pipe(filter((value) => !isIgnored(value)));
28
+ const ignored$ = shared$.pipe(filter(isIgnored));
29
+ const timed$ = watched$.pipe(timeout(timeoutConfig), share());
30
+ // Stop forwarding ignored values as soon as the timed branch completes/errors.
31
+ return merge(timed$, ignored$).pipe(takeUntil(timed$.pipe(ignoreElements(), endWith(true))));
32
+ };
33
+ }
@@ -1,4 +1,4 @@
1
- import { EventOperation } from "../event-factory/types.js";
1
+ import type { EventOperation } from "../factories/types.js";
2
2
  import { AddressPointer } from "../helpers/pointers.js";
3
3
  /** Includes a NIP-89 client tag in an event*/
4
4
  export declare function setClient(name: string, pointer?: Omit<AddressPointer, "kind" | "relays">, replace?: boolean): EventOperation;
@@ -6,7 +6,7 @@ import { includeSingletonTag } from "./tags.js";
6
6
  const NEVER_ATTACH_CLIENT_TAG = [kinds.EncryptedDirectMessage, kinds.GiftWrap, kinds.Seal, kinds.PrivateDirectMessage];
7
7
  /** Includes a NIP-89 client tag in an event*/
8
8
  export function setClient(name, pointer, replace = true) {
9
- return (draft, ctx) => {
9
+ return (draft) => {
10
10
  if (NEVER_ATTACH_CLIENT_TAG.includes(draft.kind))
11
11
  return draft;
12
12
  else {
@@ -17,7 +17,7 @@ export function setClient(name, pointer, replace = true) {
17
17
  kind: kinds.Handlerinformation,
18
18
  })
19
19
  : undefined;
20
- return includeSingletonTag(fillAndTrimTag(["client", name, coordinate]), replace)(draft, ctx);
20
+ return includeSingletonTag(fillAndTrimTag(["client", name, coordinate]), replace)(draft);
21
21
  }
22
22
  };
23
23
  }
@@ -1,4 +1,4 @@
1
- import { Emoji, EventOperation } from "../event-factory/types.js";
1
+ import type { EventOperation, Emoji } from "../factories/types.js";
2
2
  /** Override the event content */
3
3
  export declare function setContent(content: string): EventOperation;
4
4
  /** Replaces any `@npub` or bare npub mentions with nostr: prefix */
@@ -11,7 +11,10 @@ export declare function setContentWarning(warning: boolean | string): EventOpera
11
11
  export declare function includeQuoteTags(): EventOperation;
12
12
  /** Adds "t" tags for every #hashtag in the content */
13
13
  export declare function includeContentHashtags(): EventOperation;
14
- /** Adds "emoji" tags for NIP-30 emojis used in the content */
14
+ /**
15
+ * Adds "emoji" tags for NIP-30 emojis used in the content
16
+ * @param emojis - Array of custom emojis to check for in content
17
+ */
15
18
  export declare function includeEmojis(emojis?: Emoji[]): EventOperation;
16
19
  export type TextContentOptions = {
17
20
  emojis?: Emoji[];
@@ -1,7 +1,7 @@
1
1
  import { EncryptedContentSymbol } from "../helpers/encrypted-content.js";
2
2
  import { ensureProfilePointerTag, ensureQuoteEventPointerTag } from "../helpers/factory.js";
3
3
  import { eventPipe, skip } from "../helpers/pipeline.js";
4
- import { getContentPointers, getPubkeyFromDecodeResult } from "../helpers/pointers.js";
4
+ import { getContentPointers, getPubkeyFromDecodeResult, getReplaceableAddressFromPointer, } from "../helpers/pointers.js";
5
5
  import { Expressions } from "../helpers/regexp.js";
6
6
  import { ensureNamedValueTag } from "../helpers/tags.js";
7
7
  /** Override the event content */
@@ -16,7 +16,7 @@ export function setContent(content) {
16
16
  export function repairNostrLinks() {
17
17
  return (draft) => ({
18
18
  ...draft,
19
- content: draft.content.replaceAll(/(?<=^|\s)(?:@)?((?:npub|note|nprofile|nevent|naddr)1[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{58})/gi, "nostr:$1"),
19
+ content: draft.content.replaceAll(/(?<=^|\s)(?:@)?((?:npub|note|nprofile|nevent|naddr)1[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{58,})/gi, "nostr:$1"),
20
20
  });
21
21
  }
22
22
  /** "p" tag any pubkey mentioned in the content using nostr: links */
@@ -76,17 +76,21 @@ export function includeContentHashtags() {
76
76
  return { ...draft, tags };
77
77
  };
78
78
  }
79
- /** Adds "emoji" tags for NIP-30 emojis used in the content */
80
- export function includeEmojis(emojis) {
81
- return (draft, ctx) => {
82
- const all = [...(ctx.emojis ?? []), ...(emojis ?? [])];
79
+ /**
80
+ * Adds "emoji" tags for NIP-30 emojis used in the content
81
+ * @param emojis - Array of custom emojis to check for in content
82
+ */
83
+ export function includeEmojis(emojis = []) {
84
+ return (draft) => {
83
85
  const tags = Array.from(draft.tags);
84
- // create tags for all occurrences of #hashtag
86
+ // create tags for all occurrences of :emoji:
85
87
  const matches = draft.content.matchAll(Expressions.emoji);
86
88
  for (const [_, name] of matches) {
87
- const emoji = all.find((e) => e.shortcode === name);
89
+ const emoji = emojis.find((e) => e.shortcode === name);
88
90
  if (emoji?.url) {
89
- tags.push(["emoji", emoji.shortcode, emoji.url]);
91
+ tags.push(emoji.address
92
+ ? ["emoji", emoji.shortcode, emoji.url, getReplaceableAddressFromPointer(emoji.address)]
93
+ : ["emoji", emoji.shortcode, emoji.url]);
90
94
  }
91
95
  }
92
96
  return { ...draft, tags };
@@ -1,4 +1,4 @@
1
- import { EventOperation } from "../event-factory/types.js";
1
+ import type { EventOperation } from "../factories/types.js";
2
2
  import { NostrEvent } from "../helpers/event.js";
3
3
  /** Sets the necessary tags for a NIP-09 delete event to point to a the events being deleted */
4
4
  export declare function setDeleteEvents(events: (string | NostrEvent)[]): EventOperation;
@@ -1,4 +1,10 @@
1
- import { EventOperation } from "../event-factory/types.js";
1
+ import type { EventOperation } from "../factories/types.js";
2
2
  import { EncryptionMethod } from "../helpers/encrypted-content.js";
3
- /** Sets the content to be encrypted to the pubkey with optional override method */
4
- export declare function setEncryptedContent(pubkey: string, content: string, override?: EncryptionMethod): EventOperation;
3
+ /**
4
+ * Sets the content to be encrypted to the pubkey with optional override method
5
+ * @param pubkey - Pubkey to encrypt the content for
6
+ * @param content - Plaintext content to encrypt
7
+ * @param signer - EventSigner for encryption
8
+ * @param override - Optional encryption method override
9
+ */
10
+ export declare function setEncryptedContent(pubkey: string, content: string, signer?: import("../factories/types.js").EventSigner, override?: EncryptionMethod): EventOperation;
@@ -1,7 +1,13 @@
1
1
  import { EncryptedContentSymbol, getEncryptedContentEncryptionMethods, } from "../helpers/encrypted-content.js";
2
- /** Sets the content to be encrypted to the pubkey with optional override method */
3
- export function setEncryptedContent(pubkey, content, override) {
4
- return async (draft, { signer }) => {
2
+ /**
3
+ * Sets the content to be encrypted to the pubkey with optional override method
4
+ * @param pubkey - Pubkey to encrypt the content for
5
+ * @param content - Plaintext content to encrypt
6
+ * @param signer - EventSigner for encryption
7
+ * @param override - Optional encryption method override
8
+ */
9
+ export function setEncryptedContent(pubkey, content, signer, override) {
10
+ return async (draft) => {
5
11
  if (!signer)
6
12
  throw new Error("Signer required for encrypted content");
7
13
  // Set method based on kind if not provided
@@ -1,5 +1,5 @@
1
- import { EventOperation } from "../event-factory/types.js";
2
- import { EventTemplate, NostrEvent, UnsignedEvent } from "../helpers/event.js";
1
+ import type { EventOperation } from "../factories/types.js";
2
+ import { EventTemplate, KnownEvent, KnownEventTemplate, KnownUnsignedEvent, NostrEvent, UnsignedEvent } from "../helpers/event.js";
3
3
  /** An operation that removes the signature from the event template */
4
4
  export declare function stripSignature<Input extends NostrEvent | UnsignedEvent | EventTemplate>(): EventOperation<Input, Omit<Input, "sig">>;
5
5
  /** An operation that removes the id and pubkey from the event template */
@@ -29,11 +29,13 @@ export type MetaTagOptions = {
29
29
  export declare function setMetaTags(options?: MetaTagOptions): EventOperation;
30
30
  /**
31
31
  * An operation that adds the signers pubkey to the event
32
+ * @param signer - Optional EventSigner (throws if not provided)
32
33
  * @throws {Error} if no signer is provided
33
34
  */
34
- export declare function stamp(): EventOperation<EventTemplate, UnsignedEvent>;
35
+ export declare function stamp<K extends number = number>(signer?: import("../factories/types.js").EventSigner): EventOperation<KnownEventTemplate<K>, KnownUnsignedEvent<K>>;
35
36
  /**
36
37
  * An operation that signs the event
38
+ * @param signer - Optional EventSigner (throws if not provided)
37
39
  * @throws {Error} if no signer is provided
38
40
  */
39
- export declare function sign(): EventOperation<EventTemplate | UnsignedEvent, NostrEvent>;
41
+ export declare function sign<K extends number = number, T extends KnownEventTemplate<K> = KnownEventTemplate<K>>(signer?: import("../factories/types.js").EventSigner): EventOperation<T, KnownEvent<K>>;
@@ -1,12 +1,12 @@
1
1
  import { nanoid } from "nanoid";
2
- import { getTagValue } from "../helpers/event.js";
3
- import { isAddressableKind } from "../helpers/event.js";
2
+ import { isKind } from "nostr-tools/kinds";
3
+ import { EncryptedContentSymbol } from "../helpers/encrypted-content.js";
4
+ import { getTagValue, isAddressableKind, } from "../helpers/event.js";
4
5
  import { eventPipe, skip } from "../helpers/pipeline.js";
5
6
  import { ensureSingletonTag } from "../helpers/tags.js";
6
7
  import { unixNow } from "../helpers/time.js";
7
8
  import { removeSingletonTag, setSingletonTag } from "./tag/common.js";
8
9
  import { includeSingletonTag, modifyPublicTags } from "./tags.js";
9
- import { EncryptedContentSymbol } from "../helpers/encrypted-content.js";
10
10
  /** An operation that removes the signature from the event template */
11
11
  export function stripSignature() {
12
12
  return (draft) => {
@@ -72,16 +72,17 @@ export function setMetaTags(options) {
72
72
  }
73
73
  /**
74
74
  * An operation that adds the signers pubkey to the event
75
+ * @param signer - Optional EventSigner (throws if not provided)
75
76
  * @throws {Error} if no signer is provided
76
77
  */
77
- export function stamp() {
78
- return async (draft, ctx) => {
79
- if (!ctx.signer)
78
+ export function stamp(signer) {
79
+ return async (draft) => {
80
+ if (!signer)
80
81
  throw new Error("Missing signer");
81
82
  // Remove old fields from signed nostr event
82
83
  Reflect.deleteProperty(draft, "id");
83
84
  Reflect.deleteProperty(draft, "sig");
84
- const pubkey = await ctx.signer.getPublicKey();
85
+ const pubkey = await signer.getPublicKey();
85
86
  const newDraft = { ...draft, pubkey };
86
87
  // copy the plaintext hidden content if its on the draft
87
88
  if (Reflect.has(draft, EncryptedContentSymbol))
@@ -91,14 +92,21 @@ export function stamp() {
91
92
  }
92
93
  /**
93
94
  * An operation that signs the event
95
+ * @param signer - Optional EventSigner (throws if not provided)
94
96
  * @throws {Error} if no signer is provided
95
97
  */
96
- export function sign() {
97
- return async (draft, ctx) => {
98
- if (!ctx.signer)
98
+ export function sign(signer) {
99
+ return async (draft) => {
100
+ if (!signer)
99
101
  throw new Error("Missing signer");
100
- draft = await stamp()(draft, ctx);
101
- const signed = await ctx.signer.signEvent(draft);
102
+ const unsigned = await stamp(signer)(draft);
103
+ const signed = await signer.signEvent(unsigned);
104
+ // Verify the pubkey has not changed
105
+ if (Reflect.has(draft, "pubkey") && Reflect.get(draft, "pubkey") !== signed.pubkey)
106
+ throw new Error("Signer modified pubkey");
107
+ // If its the same kind, return the signed event
108
+ if (!isKind(signed, draft.kind))
109
+ throw new Error("Signer modified event kind");
102
110
  // copy the plaintext hidden content if its on the draft
103
111
  if (Reflect.has(draft, EncryptedContentSymbol))
104
112
  Reflect.set(signed, EncryptedContentSymbol, Reflect.get(draft, EncryptedContentSymbol));
@@ -1,4 +1,9 @@
1
- import { EventOperation } from "../event-factory/types.js";
1
+ import type { EventOperation } from "../factories/types.js";
2
2
  import { EncryptionMethod } from "../helpers/encrypted-content.js";
3
- /** Sets the hidden content on an event */
4
- export declare function setHiddenContent(content: string, override?: EncryptionMethod): EventOperation;
3
+ /**
4
+ * Sets the hidden content on an event
5
+ * @param content - Plaintext content to encrypt
6
+ * @param signer - EventSigner for encryption
7
+ * @param override - Optional encryption method override
8
+ */
9
+ export declare function setHiddenContent(content: string, signer?: import("../factories/types.js").EventSigner, override?: EncryptionMethod): EventOperation;
@@ -1,10 +1,15 @@
1
1
  import { setEncryptedContent } from "./encrypted-content.js";
2
- /** Sets the hidden content on an event */
3
- export function setHiddenContent(content, override) {
4
- return async (draft, ctx) => {
5
- if (!ctx.signer)
2
+ /**
3
+ * Sets the hidden content on an event
4
+ * @param content - Plaintext content to encrypt
5
+ * @param signer - EventSigner for encryption
6
+ * @param override - Optional encryption method override
7
+ */
8
+ export function setHiddenContent(content, signer, override) {
9
+ return async (draft) => {
10
+ if (!signer)
6
11
  throw new Error("Signer required for encrypted content");
7
- const pubkey = await ctx.signer.getPublicKey();
8
- return setEncryptedContent(pubkey, content, override)(draft, ctx);
12
+ const pubkey = await signer.getPublicKey();
13
+ return setEncryptedContent(pubkey, content, signer, override)(draft);
9
14
  };
10
15
  }
@@ -1,4 +1,4 @@
1
- import { EventOperation } from "../event-factory/types.js";
1
+ import type { EventOperation } from "../factories/types.js";
2
2
  /** Add an outbox relay in NIP-65 mailboxes */
3
3
  export declare function addOutboxRelay(url: string | URL): EventOperation;
4
4
  /** Remove an outbox relay in NIP-65 mailboxes */
@@ -11,3 +11,7 @@ export declare function removeInboxRelay(url: string | URL): EventOperation;
11
11
  export declare function addMailboxRelay(url: string | URL): EventOperation;
12
12
  /** Completely removes a mailbox relay from NIP-65 */
13
13
  export declare function removeMailboxRelay(url: string | URL): EventOperation;
14
+ /** Sets all inbox relays, replacing existing ones while preserving outbox dimension */
15
+ export declare function setInboxRelays(urls: (string | URL)[]): EventOperation;
16
+ /** Sets all outbox relays, replacing existing ones while preserving inbox dimension */
17
+ export declare function setOutboxRelays(urls: (string | URL)[]): EventOperation;
@@ -78,3 +78,79 @@ export function addMailboxRelay(url) {
78
78
  export function removeMailboxRelay(url) {
79
79
  return modifyPublicTags(removeRelayTag(url, "r"));
80
80
  }
81
+ /** Sets all inbox relays, replacing existing ones while preserving outbox dimension */
82
+ export function setInboxRelays(urls) {
83
+ const normalizedUrls = urls.map((url) => normalizeURL(url).toString());
84
+ return modifyPublicTags((tags) => {
85
+ // Step 1: Remove all "read" markers from existing relays
86
+ const withoutInboxes = tags
87
+ .map((tag) => {
88
+ if (!isRTag(tag))
89
+ return tag;
90
+ // Remove inbox-only relays (read marker)
91
+ if (tag[2] === "read")
92
+ return null;
93
+ // Convert both (no marker) to outbox-only (write marker)
94
+ if (tag[2] === undefined)
95
+ return ["r", tag[1], "write"];
96
+ // Keep outbox-only relays (write marker) as is
97
+ return tag;
98
+ })
99
+ .filter((t) => t !== null);
100
+ // Step 2: Add "read" markers to the specified URLs
101
+ const result = [...withoutInboxes];
102
+ for (const url of normalizedUrls) {
103
+ const existingIndex = result.findIndex((t) => isRTag(t) && isSameURL(t[1], url));
104
+ if (existingIndex >= 0) {
105
+ const existing = result[existingIndex];
106
+ // Convert outbox-only (write) to both (no marker)
107
+ if (existing[2] === "write") {
108
+ result[existingIndex] = ["r", url];
109
+ }
110
+ }
111
+ else {
112
+ // Add as inbox-only (read marker)
113
+ result.push(["r", url, "read"]);
114
+ }
115
+ }
116
+ return result;
117
+ });
118
+ }
119
+ /** Sets all outbox relays, replacing existing ones while preserving inbox dimension */
120
+ export function setOutboxRelays(urls) {
121
+ const normalizedUrls = urls.map((url) => normalizeURL(url).toString());
122
+ return modifyPublicTags((tags) => {
123
+ // Step 1: Remove all "write" markers from existing relays
124
+ const withoutOutboxes = tags
125
+ .map((tag) => {
126
+ if (!isRTag(tag))
127
+ return tag;
128
+ // Remove outbox-only relays (write marker)
129
+ if (tag[2] === "write")
130
+ return null;
131
+ // Convert both (no marker) to inbox-only (read marker)
132
+ if (tag[2] === undefined)
133
+ return ["r", tag[1], "read"];
134
+ // Keep inbox-only relays (read marker) as is
135
+ return tag;
136
+ })
137
+ .filter((t) => t !== null);
138
+ // Step 2: Add "write" markers to the specified URLs
139
+ const result = [...withoutOutboxes];
140
+ for (const url of normalizedUrls) {
141
+ const existingIndex = result.findIndex((t) => isRTag(t) && isSameURL(t[1], url));
142
+ if (existingIndex >= 0) {
143
+ const existing = result[existingIndex];
144
+ // Convert inbox-only (read) to both (no marker)
145
+ if (existing[2] === "read") {
146
+ result[existingIndex] = ["r", url];
147
+ }
148
+ }
149
+ else {
150
+ // Add as outbox-only (write marker)
151
+ result.push(["r", url, "write"]);
152
+ }
153
+ }
154
+ return result;
155
+ });
156
+ }
@@ -1,4 +1,4 @@
1
- import { EventOperation } from "../event-factory/types.js";
1
+ import type { EventOperation } from "../factories/types.js";
2
2
  import { ProfileContent } from "../helpers/index.js";
3
3
  /** Sets the content of a kind 0 metadata event */
4
4
  export declare function setProfile(content: ProfileContent): EventOperation;
@@ -1,16 +1,31 @@
1
1
  import { NostrEvent } from "nostr-tools";
2
- import { TagOperation } from "../../event-factory/types.js";
2
+ import type { TagOperation } from "../../factories/types.js";
3
3
  import { AddressPointer, EventPointer, ProfilePointer } from "../../helpers/pointers.js";
4
- /** Adds a single "p" tag for a ProfilePointer */
5
- export declare function addProfilePointerTag(pubkey: string | ProfilePointer, replace?: boolean): TagOperation;
4
+ /**
5
+ * Adds a single "p" tag for a ProfilePointer
6
+ * @param pubkey - Pubkey string or ProfilePointer object
7
+ * @param relayHint - Optional relay hint (string) or function to get relay hint
8
+ * @param replace - If true, removes existing "p" tags for this pubkey
9
+ */
10
+ export declare function addProfilePointerTag(pubkey: string | ProfilePointer, relayHint?: string | ((pubkey: string) => Promise<string | undefined>), replace?: boolean): TagOperation;
6
11
  /** Removes all "p" tags matching a pubkey */
7
12
  export declare function removeProfilePointerTag(pubkey: string | ProfilePointer): TagOperation;
8
- /** Adds a single "e" tag for an EventPointer */
9
- export declare function addEventPointerTag(id: string | EventPointer | NostrEvent, replace?: boolean): TagOperation;
13
+ /**
14
+ * Adds a single "e" tag for an EventPointer
15
+ * @param id - Event ID string, EventPointer object, or NostrEvent
16
+ * @param relayHint - Optional relay hint (string) or function to get relay hint
17
+ * @param replace - If true, removes existing "e" tags for this event ID
18
+ */
19
+ export declare function addEventPointerTag(id: string | EventPointer | NostrEvent, relayHint?: string | ((eventId: string) => Promise<string | undefined>), replace?: boolean): TagOperation;
10
20
  /** Removes all "e" tags matching EventPointer or id */
11
21
  export declare function removeEventPointerTag(id: string | EventPointer): TagOperation;
12
- /** Adds a single "a" tag based on an AddressPointer */
13
- export declare function addAddressPointerTag(address: string | AddressPointer | NostrEvent, replace?: boolean): TagOperation;
22
+ /**
23
+ * Adds a single "a" tag based on an AddressPointer
24
+ * @param address - Address string, AddressPointer object, or NostrEvent
25
+ * @param relayHint - Optional relay hint (string) or function to get relay hint
26
+ * @param replace - If true, removes existing "a" tags for this address
27
+ */
28
+ export declare function addAddressPointerTag(address: string | AddressPointer | NostrEvent, relayHint?: string | ((pubkey: string) => Promise<string | undefined>), replace?: boolean): TagOperation;
14
29
  /** Removes all "a" tags for address pointer */
15
30
  export declare function removeAddressPointerTag(address: string | AddressPointer | NostrEvent): TagOperation;
16
31
  /** Adds a name / value tag */
@@ -2,13 +2,18 @@ import { createATagFromAddressPointer, createETagFromEventPointer, createPTagFro
2
2
  import { getAddressPointerForEvent, getEventPointerForEvent, getReplaceableAddressFromPointer, parseReplaceableAddress, } from "../../helpers/pointers.js";
3
3
  import { ensureNamedValueTag, ensureSingletonTag } from "../../helpers/tags.js";
4
4
  import { getReplaceableAddress, isEvent, skip } from "../../helpers/index.js";
5
- /** Adds a single "p" tag for a ProfilePointer */
6
- export function addProfilePointerTag(pubkey, replace = true) {
7
- return async (tags, { getPubkeyRelayHint }) => {
5
+ /**
6
+ * Adds a single "p" tag for a ProfilePointer
7
+ * @param pubkey - Pubkey string or ProfilePointer object
8
+ * @param relayHint - Optional relay hint (string) or function to get relay hint
9
+ * @param replace - If true, removes existing "p" tags for this pubkey
10
+ */
11
+ export function addProfilePointerTag(pubkey, relayHint, replace = true) {
12
+ return async (tags) => {
8
13
  const pointer = typeof pubkey === "string" ? { pubkey: pubkey } : { ...pubkey };
9
- // add relay hint
10
- if (getPubkeyRelayHint && pointer.relays?.[0] === undefined) {
11
- const hint = await getPubkeyRelayHint(pointer.pubkey);
14
+ // add relay hint (hybrid: string or function)
15
+ if (!pointer.relays?.[0] && relayHint) {
16
+ const hint = typeof relayHint === "string" ? relayHint : await relayHint(pointer.pubkey);
12
17
  if (hint)
13
18
  pointer.relays = [hint];
14
19
  }
@@ -24,13 +29,18 @@ export function removeProfilePointerTag(pubkey) {
24
29
  pubkey = typeof pubkey !== "string" ? pubkey.pubkey : pubkey;
25
30
  return (tags) => tags.filter((t) => !(t[0] === "p" && t[1] === pubkey));
26
31
  }
27
- /** Adds a single "e" tag for an EventPointer */
28
- export function addEventPointerTag(id, replace = true) {
29
- return async (tags, { getEventRelayHint }) => {
32
+ /**
33
+ * Adds a single "e" tag for an EventPointer
34
+ * @param id - Event ID string, EventPointer object, or NostrEvent
35
+ * @param relayHint - Optional relay hint (string) or function to get relay hint
36
+ * @param replace - If true, removes existing "e" tags for this event ID
37
+ */
38
+ export function addEventPointerTag(id, relayHint, replace = true) {
39
+ return async (tags) => {
30
40
  const pointer = typeof id === "string" ? { id } : isEvent(id) ? getEventPointerForEvent(id) : id;
31
- // add relay hint
32
- if (getEventRelayHint && pointer.relays?.[0] === undefined) {
33
- const hint = await getEventRelayHint(pointer.id);
41
+ // add relay hint (hybrid: string or function)
42
+ if (!pointer.relays?.[0] && relayHint) {
43
+ const hint = typeof relayHint === "string" ? relayHint : await relayHint(pointer.id);
34
44
  if (hint)
35
45
  pointer.relays = [hint];
36
46
  }
@@ -46,8 +56,13 @@ export function removeEventPointerTag(id) {
46
56
  id = typeof id === "string" ? id : id.id;
47
57
  return (tags) => tags.filter((t) => !(t[0] === "e" && t[1] === id));
48
58
  }
49
- /** Adds a single "a" tag based on an AddressPointer */
50
- export function addAddressPointerTag(address, replace = true) {
59
+ /**
60
+ * Adds a single "a" tag based on an AddressPointer
61
+ * @param address - Address string, AddressPointer object, or NostrEvent
62
+ * @param relayHint - Optional relay hint (string) or function to get relay hint
63
+ * @param replace - If true, removes existing "a" tags for this address
64
+ */
65
+ export function addAddressPointerTag(address, relayHint, replace = true) {
51
66
  // convert the string into an address pointer object
52
67
  const pointer = typeof address === "string"
53
68
  ? parseReplaceableAddress(address)
@@ -56,11 +71,11 @@ export function addAddressPointerTag(address, replace = true) {
56
71
  : address;
57
72
  if (!pointer)
58
73
  throw new Error("Unable to resolve address pointer");
59
- return async (tags, { getPubkeyRelayHint }) => {
74
+ return async (tags) => {
60
75
  const replaceableAddress = typeof address === "string" ? address : getReplaceableAddressFromPointer(pointer);
61
- // add relay hint if there isn't one
62
- if (getPubkeyRelayHint && pointer.relays?.[0] === undefined) {
63
- const hint = await getPubkeyRelayHint(pointer.pubkey);
76
+ // add relay hint if there isn't one (hybrid: string or function)
77
+ if (!pointer.relays?.[0] && relayHint) {
78
+ const hint = typeof relayHint === "string" ? relayHint : await relayHint(pointer.pubkey);
64
79
  if (hint)
65
80
  pointer.relays = [hint];
66
81
  }
@@ -1,4 +1,4 @@
1
- import { TagOperation } from "../../event-factory/types.js";
1
+ import type { TagOperation } from "../../factories/types.js";
2
2
  /** Adds a relay tag */
3
3
  export declare function addRelayTag(url: string | URL, tagName?: string, replace?: boolean): TagOperation;
4
4
  /** Removes all relay tags matching the relay */
@@ -1,4 +1,4 @@
1
- import { EventOperation, TagOperation } from "../event-factory/types.js";
1
+ import type { EventOperation, TagOperation } from "../factories/types.js";
2
2
  import { EventTemplate, NostrEvent, UnsignedEvent } from "../helpers/event.js";
3
3
  /** Includes only a single instance of tag in an events public tags */
4
4
  export declare function includeSingletonTag(tag: [string, ...string[]], replace?: boolean): EventOperation;
@@ -8,13 +8,19 @@ export declare function includeNameValueTag(tag: [string, string, ...string[]],
8
8
  export declare function modifyPublicTags<E extends EventTemplate | UnsignedEvent | NostrEvent>(...operations: (TagOperation | undefined)[]): EventOperation<E, E>;
9
9
  /**
10
10
  * Creates an event operation that modifies the hidden tags on an event with {@link TagOperation}s
11
+ * @param signer - EventSigner for encrypting/decrypting hidden tags
12
+ * @param operations - Tag operations to apply to hidden tags
11
13
  * @throws {Error} if no signer is provided
12
14
  * @throws {Error} if the event kind does not support hidden tags
13
15
  */
14
- export declare function modifyHiddenTags<E extends EventTemplate | UnsignedEvent | NostrEvent>(...operations: (TagOperation | undefined)[]): EventOperation<E, E>;
16
+ export declare function modifyHiddenTags<E extends EventTemplate | UnsignedEvent | NostrEvent>(signer: import("../factories/types.js").EventSigner | undefined, ...operations: (TagOperation | undefined)[]): EventOperation<E, E>;
15
17
  export type ModifyTagsOptions = TagOperation | TagOperation[] | {
16
18
  public?: TagOperation | TagOperation[];
17
19
  hidden?: TagOperation | TagOperation[];
18
20
  };
19
- /** A flexible method for creating an event operation that modifies the tags */
20
- export declare function modifyTags(tagOperations?: ModifyTagsOptions): EventOperation;
21
+ /**
22
+ * A flexible method for creating an event operation that modifies the tags
23
+ * @param tagOperations - Tag operations for public and/or hidden tags
24
+ * @param signer - Optional signer (required if modifying hidden tags)
25
+ */
26
+ export declare function modifyTags(tagOperations?: ModifyTagsOptions, signer?: import("../factories/types.js").EventSigner): EventOperation;