applesauce-core 0.0.0-next-20250407103800 → 0.0.0-next-20250414120207
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/dist/event-store/__tests__/event-store.test.js +52 -1
- package/dist/event-store/event-store.js +11 -4
- package/dist/helpers/__tests__/comment.test.js +14 -0
- package/dist/helpers/comment.d.ts +7 -3
- package/dist/helpers/comment.js +6 -1
- package/dist/helpers/pointers.js +3 -3
- package/package.json +1 -1
|
@@ -31,7 +31,7 @@ describe("add", () => {
|
|
|
31
31
|
expect(eventStore.getEvent(profile.id)).toBeDefined();
|
|
32
32
|
expect([...getSeenRelays(eventStore.getEvent(profile.id))]).toEqual(expect.arrayContaining(["wss://relay.a.com", "wss://relay.b.com"]));
|
|
33
33
|
});
|
|
34
|
-
it("should ignore deleted events", () => {
|
|
34
|
+
it("should ignore old deleted events but not newer ones", () => {
|
|
35
35
|
const deleteEvent = {
|
|
36
36
|
id: "delete event id",
|
|
37
37
|
kind: kinds.EventDeletion,
|
|
@@ -45,7 +45,58 @@ describe("add", () => {
|
|
|
45
45
|
eventStore.add(deleteEvent);
|
|
46
46
|
// now event should be ignored
|
|
47
47
|
eventStore.add(profile);
|
|
48
|
+
const newProfile = user.profile({ name: "new name" }, { created_at: profile.created_at + 1000 });
|
|
49
|
+
eventStore.add(newProfile);
|
|
48
50
|
expect(eventStore.getEvent(profile.id)).toBeUndefined();
|
|
51
|
+
expect(eventStore.getEvent(newProfile.id)).toBeDefined();
|
|
52
|
+
});
|
|
53
|
+
it("should remove profile events when delete event is added", () => {
|
|
54
|
+
// Add initial replaceable event
|
|
55
|
+
eventStore.add(profile);
|
|
56
|
+
expect(eventStore.getEvent(profile.id)).toBeDefined();
|
|
57
|
+
const newProfile = user.profile({ name: "new name" }, { created_at: profile.created_at + 1000 });
|
|
58
|
+
eventStore.add(newProfile);
|
|
59
|
+
const deleteEvent = {
|
|
60
|
+
id: "delete event id",
|
|
61
|
+
kind: kinds.EventDeletion,
|
|
62
|
+
created_at: profile.created_at + 100,
|
|
63
|
+
pubkey: user.pubkey,
|
|
64
|
+
tags: [["a", `${profile.kind}:${profile.pubkey}`]],
|
|
65
|
+
sig: "this should be ignored for the test",
|
|
66
|
+
content: "test",
|
|
67
|
+
};
|
|
68
|
+
// Add delete event with coordinate
|
|
69
|
+
eventStore.add(deleteEvent);
|
|
70
|
+
// Profile should be removed since delete event is newer
|
|
71
|
+
expect(eventStore.getEvent(profile.id)).toBeUndefined();
|
|
72
|
+
expect(eventStore.getEvent(newProfile.id)).toBeDefined();
|
|
73
|
+
expect(eventStore.getReplaceable(profile.kind, profile.pubkey)).toBe(newProfile);
|
|
74
|
+
});
|
|
75
|
+
it("should remove addressable replaceable events when delete event is added", () => {
|
|
76
|
+
// Add initial replaceable event
|
|
77
|
+
const event = user.event({ content: "test", kind: 30000, tags: [["d", "test"]] });
|
|
78
|
+
eventStore.add(event);
|
|
79
|
+
expect(eventStore.getEvent(event.id)).toBeDefined();
|
|
80
|
+
const newEvent = user.event({
|
|
81
|
+
...event,
|
|
82
|
+
created_at: event.created_at + 500,
|
|
83
|
+
});
|
|
84
|
+
eventStore.add(newEvent);
|
|
85
|
+
const deleteEvent = {
|
|
86
|
+
id: "delete event id",
|
|
87
|
+
kind: kinds.EventDeletion,
|
|
88
|
+
created_at: event.created_at + 100,
|
|
89
|
+
pubkey: user.pubkey,
|
|
90
|
+
tags: [["a", `${event.kind}:${event.pubkey}:test`]],
|
|
91
|
+
sig: "this should be ignored for the test",
|
|
92
|
+
content: "test",
|
|
93
|
+
};
|
|
94
|
+
// Add delete event with coordinate
|
|
95
|
+
eventStore.add(deleteEvent);
|
|
96
|
+
// Profile should be removed since delete event is newer
|
|
97
|
+
expect(eventStore.getEvent(event.id)).toBeUndefined();
|
|
98
|
+
expect(eventStore.getEvent(newEvent.id)).toBeDefined();
|
|
99
|
+
expect(eventStore.getReplaceable(event.kind, event.pubkey, "test")).toBe(newEvent);
|
|
49
100
|
});
|
|
50
101
|
});
|
|
51
102
|
describe("inserts", () => {
|
|
@@ -9,6 +9,7 @@ import { addSeenRelay, getSeenRelays } from "../helpers/relays.js";
|
|
|
9
9
|
import { getDeleteCoordinates, getDeleteIds } from "../helpers/delete.js";
|
|
10
10
|
import { claimEvents } from "../observable/claim-events.js";
|
|
11
11
|
import { claimLatest } from "../observable/claim-latest.js";
|
|
12
|
+
import { parseCoordinate } from "../helpers/pointers.js";
|
|
12
13
|
export const EventStoreSymbol = Symbol.for("event-store");
|
|
13
14
|
function sortDesc(a, b) {
|
|
14
15
|
return b.created_at - a.created_at;
|
|
@@ -74,10 +75,16 @@ export class EventStore {
|
|
|
74
75
|
const coords = getDeleteCoordinates(deleteEvent);
|
|
75
76
|
for (const coord of coords) {
|
|
76
77
|
this.deletedCoords.set(coord, Math.max(this.deletedCoords.get(coord) ?? 0, deleteEvent.created_at));
|
|
77
|
-
//
|
|
78
|
-
const
|
|
79
|
-
if (
|
|
80
|
-
|
|
78
|
+
// Parse the nostr address coordinate
|
|
79
|
+
const parsed = parseCoordinate(coord);
|
|
80
|
+
if (!parsed)
|
|
81
|
+
continue;
|
|
82
|
+
// Remove older versions of replaceable events
|
|
83
|
+
const events = this.database.getReplaceable(parsed.kind, parsed.pubkey, parsed.identifier) ?? [];
|
|
84
|
+
for (const event of events) {
|
|
85
|
+
if (event.created_at < deleteEvent.created_at)
|
|
86
|
+
this.database.removeEvent(event);
|
|
87
|
+
}
|
|
81
88
|
}
|
|
82
89
|
}
|
|
83
90
|
/** Copies important metadata from and identical event to another */
|
|
@@ -27,6 +27,7 @@ describe("getCommentEventPointer", () => {
|
|
|
27
27
|
["e", "86c0b95589b016ffb703bfc080d49e54106e74e2d683295119c3453e494dbe6f"],
|
|
28
28
|
];
|
|
29
29
|
expect(getCommentEventPointer(tags, true)).toEqual({
|
|
30
|
+
type: "event",
|
|
30
31
|
id: "86c0b95589b016ffb703bfc080d49e54106e74e2d683295119c3453e494dbe6f",
|
|
31
32
|
kind: 1621,
|
|
32
33
|
pubkey: "e4336cd525df79fa4d3af364fd9600d4b10dce4215aa4c33ed77ea0842344b10",
|
|
@@ -45,6 +46,7 @@ describe("getCommentEventPointer", () => {
|
|
|
45
46
|
["P", "bad-pubkey"],
|
|
46
47
|
];
|
|
47
48
|
expect(getCommentEventPointer(tags, true)).toEqual({
|
|
49
|
+
type: "event",
|
|
48
50
|
id: "86c0b95589b016ffb703bfc080d49e54106e74e2d683295119c3453e494dbe6f",
|
|
49
51
|
kind: 1621,
|
|
50
52
|
pubkey: "e4336cd525df79fa4d3af364fd9600d4b10dce4215aa4c33ed77ea0842344b10",
|
|
@@ -62,6 +64,7 @@ describe("getCommentEventPointer", () => {
|
|
|
62
64
|
["K", "1621"],
|
|
63
65
|
];
|
|
64
66
|
expect(getCommentEventPointer(tags, true)).toEqual({
|
|
67
|
+
type: "event",
|
|
65
68
|
id: "86c0b95589b016ffb703bfc080d49e54106e74e2d683295119c3453e494dbe6f",
|
|
66
69
|
kind: 1621,
|
|
67
70
|
pubkey: "e4336cd525df79fa4d3af364fd9600d4b10dce4215aa4c33ed77ea0842344b10",
|
|
@@ -75,6 +78,7 @@ describe("getCommentEventPointer", () => {
|
|
|
75
78
|
["P", "e4336cd525df79fa4d3af364fd9600d4b10dce4215aa4c33ed77ea0842344b10"],
|
|
76
79
|
];
|
|
77
80
|
expect(getCommentEventPointer(tags, true)).toEqual({
|
|
81
|
+
type: "event",
|
|
78
82
|
id: "86c0b95589b016ffb703bfc080d49e54106e74e2d683295119c3453e494dbe6f",
|
|
79
83
|
kind: 1621,
|
|
80
84
|
pubkey: "e4336cd525df79fa4d3af364fd9600d4b10dce4215aa4c33ed77ea0842344b10",
|
|
@@ -107,6 +111,7 @@ describe("getCommentAddressPointer", () => {
|
|
|
107
111
|
["E", "86c0b95589b016ffb703bfc080d49e54106e74e2d683295119c3453e494dbe6f"],
|
|
108
112
|
["K", "30000"],
|
|
109
113
|
], true)).toEqual({
|
|
114
|
+
type: "address",
|
|
110
115
|
id: "86c0b95589b016ffb703bfc080d49e54106e74e2d683295119c3453e494dbe6f",
|
|
111
116
|
kind: 30000,
|
|
112
117
|
pubkey: "e4336cd525df79fa4d3af364fd9600d4b10dce4215aa4c33ed77ea0842344b10",
|
|
@@ -118,6 +123,7 @@ describe("getCommentAddressPointer", () => {
|
|
|
118
123
|
["e", "86c0b95589b016ffb703bfc080d49e54106e74e2d683295119c3453e494dbe6f"],
|
|
119
124
|
["k", "30000"],
|
|
120
125
|
])).toEqual({
|
|
126
|
+
type: "address",
|
|
121
127
|
id: "86c0b95589b016ffb703bfc080d49e54106e74e2d683295119c3453e494dbe6f",
|
|
122
128
|
kind: 30000,
|
|
123
129
|
pubkey: "e4336cd525df79fa4d3af364fd9600d4b10dce4215aa4c33ed77ea0842344b10",
|
|
@@ -130,6 +136,7 @@ describe("getCommentAddressPointer", () => {
|
|
|
130
136
|
["A", "30000:e4336cd525df79fa4d3af364fd9600d4b10dce4215aa4c33ed77ea0842344b10:list", "wss://relay.io/"],
|
|
131
137
|
["K", "30000"],
|
|
132
138
|
], true)).toEqual({
|
|
139
|
+
type: "address",
|
|
133
140
|
kind: 30000,
|
|
134
141
|
pubkey: "e4336cd525df79fa4d3af364fd9600d4b10dce4215aa4c33ed77ea0842344b10",
|
|
135
142
|
identifier: "list",
|
|
@@ -140,6 +147,7 @@ describe("getCommentAddressPointer", () => {
|
|
|
140
147
|
["a", "30000:e4336cd525df79fa4d3af364fd9600d4b10dce4215aa4c33ed77ea0842344b10:list", "wss://relay.io/"],
|
|
141
148
|
["k", "30000"],
|
|
142
149
|
])).toEqual({
|
|
150
|
+
type: "address",
|
|
143
151
|
kind: 30000,
|
|
144
152
|
pubkey: "e4336cd525df79fa4d3af364fd9600d4b10dce4215aa4c33ed77ea0842344b10",
|
|
145
153
|
identifier: "list",
|
|
@@ -153,6 +161,7 @@ describe("getCommentAddressPointer", () => {
|
|
|
153
161
|
["E", "86c0b95589b016ffb703bfc080d49e54106e74e2d683295119c3453e494dbe6f", "wss://relay.io/"],
|
|
154
162
|
["K", "30000"],
|
|
155
163
|
], true)).toEqual({
|
|
164
|
+
type: "address",
|
|
156
165
|
id: "86c0b95589b016ffb703bfc080d49e54106e74e2d683295119c3453e494dbe6f",
|
|
157
166
|
kind: 30000,
|
|
158
167
|
pubkey: "e4336cd525df79fa4d3af364fd9600d4b10dce4215aa4c33ed77ea0842344b10",
|
|
@@ -165,6 +174,7 @@ describe("getCommentAddressPointer", () => {
|
|
|
165
174
|
["e", "86c0b95589b016ffb703bfc080d49e54106e74e2d683295119c3453e494dbe6f", "wss://relay.io/"],
|
|
166
175
|
["k", "30000"],
|
|
167
176
|
])).toEqual({
|
|
177
|
+
type: "address",
|
|
168
178
|
id: "86c0b95589b016ffb703bfc080d49e54106e74e2d683295119c3453e494dbe6f",
|
|
169
179
|
kind: 30000,
|
|
170
180
|
pubkey: "e4336cd525df79fa4d3af364fd9600d4b10dce4215aa4c33ed77ea0842344b10",
|
|
@@ -178,6 +188,7 @@ describe("getCommentAddressPointer", () => {
|
|
|
178
188
|
["A", "30010:e4336cd525df79fa4d3af364fd9600d4b10dce4215aa4c33ed77ea0842344b10:list"],
|
|
179
189
|
["K", "30000"],
|
|
180
190
|
], true)).toEqual({
|
|
191
|
+
type: "address",
|
|
181
192
|
kind: 30010,
|
|
182
193
|
pubkey: "e4336cd525df79fa4d3af364fd9600d4b10dce4215aa4c33ed77ea0842344b10",
|
|
183
194
|
identifier: "list",
|
|
@@ -187,6 +198,7 @@ describe("getCommentAddressPointer", () => {
|
|
|
187
198
|
["a", "30010:e4336cd525df79fa4d3af364fd9600d4b10dce4215aa4c33ed77ea0842344b10:list"],
|
|
188
199
|
["k", "30000"],
|
|
189
200
|
])).toEqual({
|
|
201
|
+
type: "address",
|
|
190
202
|
kind: 30010,
|
|
191
203
|
pubkey: "e4336cd525df79fa4d3af364fd9600d4b10dce4215aa4c33ed77ea0842344b10",
|
|
192
204
|
identifier: "list",
|
|
@@ -214,6 +226,7 @@ describe("getCommentExternalPointer", () => {
|
|
|
214
226
|
["I", "podcast:item:guid:d98d189b-dc7b-45b1-8720-d4b98690f31f"],
|
|
215
227
|
["K", "podcast:item:guid"],
|
|
216
228
|
], true)).toEqual({
|
|
229
|
+
type: "external",
|
|
217
230
|
identifier: "podcast:item:guid:d98d189b-dc7b-45b1-8720-d4b98690f31f",
|
|
218
231
|
kind: "podcast:item:guid",
|
|
219
232
|
});
|
|
@@ -222,6 +235,7 @@ describe("getCommentExternalPointer", () => {
|
|
|
222
235
|
["i", "podcast:item:guid:d98d189b-dc7b-45b1-8720-d4b98690f31f"],
|
|
223
236
|
["k", "podcast:item:guid"],
|
|
224
237
|
])).toEqual({
|
|
238
|
+
type: "external",
|
|
225
239
|
identifier: "podcast:item:guid:d98d189b-dc7b-45b1-8720-d4b98690f31f",
|
|
226
240
|
kind: "podcast:item:guid",
|
|
227
241
|
});
|
|
@@ -2,20 +2,24 @@ import { NostrEvent } from "nostr-tools";
|
|
|
2
2
|
import { ExternalPointer, ExternalIdentifiers } from "./external-id.js";
|
|
3
3
|
export declare const COMMENT_KIND = 1111;
|
|
4
4
|
export type CommentEventPointer = {
|
|
5
|
+
type: "event";
|
|
5
6
|
id: string;
|
|
6
7
|
kind: number;
|
|
7
8
|
pubkey?: string;
|
|
8
9
|
relay?: string;
|
|
9
10
|
};
|
|
10
11
|
export type CommentAddressPointer = {
|
|
12
|
+
type: "address";
|
|
11
13
|
id?: string;
|
|
12
14
|
kind: number;
|
|
13
15
|
pubkey: string;
|
|
14
16
|
identifier: string;
|
|
15
17
|
relay?: string;
|
|
16
18
|
};
|
|
17
|
-
export type CommentExternalPointer = ExternalPointer<
|
|
18
|
-
|
|
19
|
+
export type CommentExternalPointer<T extends keyof ExternalIdentifiers> = ExternalPointer<T> & {
|
|
20
|
+
type: "external";
|
|
21
|
+
};
|
|
22
|
+
export type CommentPointer = CommentEventPointer | CommentAddressPointer | CommentExternalPointer<keyof ExternalIdentifiers>;
|
|
19
23
|
export declare const CommentRootPointerSymbol: unique symbol;
|
|
20
24
|
export declare const CommentReplyPointerSymbol: unique symbol;
|
|
21
25
|
/**
|
|
@@ -32,7 +36,7 @@ export declare function getCommentAddressPointer(tags: string[][], root?: boolea
|
|
|
32
36
|
* Gets the ExternalPointer from an array of tags
|
|
33
37
|
* @throws
|
|
34
38
|
*/
|
|
35
|
-
export declare function getCommentExternalPointer(tags: string[][], root?: boolean): CommentExternalPointer | null;
|
|
39
|
+
export declare function getCommentExternalPointer(tags: string[][], root?: boolean): CommentExternalPointer<keyof ExternalIdentifiers> | null;
|
|
36
40
|
/**
|
|
37
41
|
* Returns the root pointer for a comment
|
|
38
42
|
* @throws
|
package/dist/helpers/comment.js
CHANGED
|
@@ -18,6 +18,7 @@ export function getCommentEventPointer(tags, root = false) {
|
|
|
18
18
|
// only the root pubkey can be gotten from the tags, since due to quotes and mentions there will be many "p" tags for replies
|
|
19
19
|
const rootPubkey = root ? tags.find((t) => t[0] === "P")?.[1] : undefined;
|
|
20
20
|
const pointer = {
|
|
21
|
+
type: "event",
|
|
21
22
|
id: eTag[1],
|
|
22
23
|
kind: parseInt(kind),
|
|
23
24
|
pubkey: eTag[3] || rootPubkey || undefined,
|
|
@@ -40,6 +41,7 @@ export function getCommentAddressPointer(tags, root = false) {
|
|
|
40
41
|
throw new Error("Missing kind tag");
|
|
41
42
|
const addressPointer = getAddressPointerFromATag(aTag);
|
|
42
43
|
const pointer = {
|
|
44
|
+
type: "address",
|
|
43
45
|
id: eTag?.[1],
|
|
44
46
|
pubkey: addressPointer.pubkey,
|
|
45
47
|
identifier: addressPointer.identifier,
|
|
@@ -60,7 +62,10 @@ export function getCommentExternalPointer(tags, root = false) {
|
|
|
60
62
|
if (iTag) {
|
|
61
63
|
if (!kind)
|
|
62
64
|
throw new Error("Missing kind tag");
|
|
63
|
-
return
|
|
65
|
+
return {
|
|
66
|
+
type: "external",
|
|
67
|
+
...getExternalPointerFromTag(iTag),
|
|
68
|
+
};
|
|
64
69
|
}
|
|
65
70
|
return null;
|
|
66
71
|
}
|
package/dist/helpers/pointers.js
CHANGED
|
@@ -5,16 +5,16 @@ import { isParameterizedReplaceableKind } from "nostr-tools/kinds";
|
|
|
5
5
|
import { isSafeRelayURL } from "./relays.js";
|
|
6
6
|
export function parseCoordinate(a, requireD = false, silent = true) {
|
|
7
7
|
const parts = a.split(":");
|
|
8
|
-
const kind = parts[0]
|
|
8
|
+
const kind = parts[0] ? parseInt(parts[0]) : undefined;
|
|
9
9
|
const pubkey = parts[1];
|
|
10
10
|
const d = parts[2];
|
|
11
|
-
if (
|
|
11
|
+
if (kind === undefined) {
|
|
12
12
|
if (silent)
|
|
13
13
|
return null;
|
|
14
14
|
else
|
|
15
15
|
throw new Error("Missing kind");
|
|
16
16
|
}
|
|
17
|
-
if (
|
|
17
|
+
if (pubkey === undefined || pubkey === "") {
|
|
18
18
|
if (silent)
|
|
19
19
|
return null;
|
|
20
20
|
else
|