@solarpunkltd/swarm-chat-js 7.3.0 → 8.1.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.
- package/README.md +118 -20
- package/dist/chat.d.ts +14 -2
- package/dist/events.d.ts +9 -5
- package/dist/index.cjs +1 -1
- package/dist/index.js +102 -99
- package/dist/message/binding.d.ts +48 -0
- package/dist/message/canonicalSignature.d.ts +6 -0
- package/dist/message/entry.d.ts +25 -6
- package/dist/message/index.d.ts +2 -0
- package/dist/message/message.d.ts +60 -14
- package/dist/message/ownFeed.d.ts +9 -0
- package/dist/message-Bmwh3SCs.cjs +3 -0
- package/dist/message-Dbh8qrpg.js +455 -0
- package/dist/message.cjs +1 -1
- package/dist/message.js +2 -308
- package/dist/sender.d.ts +16 -4
- package/package.json +13 -10
package/dist/message.js
CHANGED
|
@@ -1,308 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
//#region src/message/message.ts
|
|
4
|
-
var s = 7, c = 2048, l = 128, u = 500, d = 20, f = {
|
|
5
|
-
TEXT: "text",
|
|
6
|
-
THREAD: "thread",
|
|
7
|
-
REACTION: "reaction"
|
|
8
|
-
};
|
|
9
|
-
function p(e) {
|
|
10
|
-
let t = 0;
|
|
11
|
-
for (let n of e) t++;
|
|
12
|
-
return t;
|
|
13
|
-
}
|
|
14
|
-
function m(e) {
|
|
15
|
-
return o.string().regex(RegExp(`^[0-9a-f]{${e}}$`), `expected ${e} lowercase hex characters`);
|
|
16
|
-
}
|
|
17
|
-
function h(e, t) {
|
|
18
|
-
return o.string().refine((n) => {
|
|
19
|
-
let r = p(n);
|
|
20
|
-
return r >= e && r <= t;
|
|
21
|
-
}, `expected ${e} to ${t} characters`);
|
|
22
|
-
}
|
|
23
|
-
var g = m(32), _ = o.strictObject({
|
|
24
|
-
v: o.literal(7),
|
|
25
|
-
topic: h(1, 128),
|
|
26
|
-
id: g,
|
|
27
|
-
type: o.enum([
|
|
28
|
-
f.TEXT,
|
|
29
|
-
f.THREAD,
|
|
30
|
-
f.REACTION
|
|
31
|
-
]),
|
|
32
|
-
target: o.union([o.literal(""), g]),
|
|
33
|
-
text: h(1, 500),
|
|
34
|
-
name: h(1, 20),
|
|
35
|
-
addr: m(40),
|
|
36
|
-
ts: o.number().int().nonnegative().max(2 ** 53 - 1),
|
|
37
|
-
sig: m(130)
|
|
38
|
-
}).refine((e) => e.type === f.TEXT == (e.target === ""), {
|
|
39
|
-
message: "a text message has no target, a thread reply or a reaction names one",
|
|
40
|
-
path: ["target"]
|
|
41
|
-
}), v = class extends Error {
|
|
42
|
-
constructor(e, t) {
|
|
43
|
-
super(`chat message refused (${e}): ${t}`), this.reason = e, this.name = "ChatMessageError";
|
|
44
|
-
}
|
|
45
|
-
}, y = new TextEncoder(), b = new TextDecoder("utf-8", { fatal: !0 });
|
|
46
|
-
function x(e) {
|
|
47
|
-
return y.encode(JSON.stringify([
|
|
48
|
-
e.v,
|
|
49
|
-
e.topic,
|
|
50
|
-
e.id,
|
|
51
|
-
e.type,
|
|
52
|
-
e.target,
|
|
53
|
-
e.text,
|
|
54
|
-
e.name,
|
|
55
|
-
e.addr,
|
|
56
|
-
e.ts
|
|
57
|
-
]));
|
|
58
|
-
}
|
|
59
|
-
function S(e) {
|
|
60
|
-
let t = {
|
|
61
|
-
v: e.v,
|
|
62
|
-
topic: e.topic,
|
|
63
|
-
id: e.id,
|
|
64
|
-
type: e.type,
|
|
65
|
-
target: e.target,
|
|
66
|
-
text: e.text,
|
|
67
|
-
name: e.name,
|
|
68
|
-
addr: e.addr,
|
|
69
|
-
ts: e.ts,
|
|
70
|
-
sig: e.sig
|
|
71
|
-
};
|
|
72
|
-
return y.encode(JSON.stringify(t));
|
|
73
|
-
}
|
|
74
|
-
function C() {
|
|
75
|
-
let e = crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(16));
|
|
76
|
-
return Array.from(e, (e) => e.toString(16).padStart(2, "0")).join("");
|
|
77
|
-
}
|
|
78
|
-
function w(e) {
|
|
79
|
-
return e.issues.map((e) => `${e.path.join(".") || "message"}: ${e.message}`).join(", ");
|
|
80
|
-
}
|
|
81
|
-
function T(e, t) {
|
|
82
|
-
let n = e instanceof r ? e : new r(e), i = {
|
|
83
|
-
v: 7,
|
|
84
|
-
topic: t.topic,
|
|
85
|
-
id: t.id ?? C(),
|
|
86
|
-
type: t.type,
|
|
87
|
-
target: t.target ?? "",
|
|
88
|
-
text: t.text,
|
|
89
|
-
name: t.name,
|
|
90
|
-
addr: n.publicKey().address().toHex(),
|
|
91
|
-
ts: t.ts ?? Date.now()
|
|
92
|
-
}, a = {
|
|
93
|
-
...i,
|
|
94
|
-
sig: "0".repeat(130)
|
|
95
|
-
}, o = _.safeParse(a);
|
|
96
|
-
if (!o.success) throw new v("shape", w(o.error));
|
|
97
|
-
let s = S(a).byteLength;
|
|
98
|
-
if (s > 2048) throw new v("too-large", `${s} bytes, the cap is ${c}`);
|
|
99
|
-
let l = {
|
|
100
|
-
...i,
|
|
101
|
-
sig: n.sign(x(i)).toHex()
|
|
102
|
-
};
|
|
103
|
-
return {
|
|
104
|
-
message: l,
|
|
105
|
-
bytes: S(l)
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
function E(e) {
|
|
109
|
-
try {
|
|
110
|
-
return new a(e.sig).recoverPublicKey(x(e)).address().toHex() === e.addr;
|
|
111
|
-
} catch {
|
|
112
|
-
return !1;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
function D(e) {
|
|
116
|
-
let t = _.safeParse(e);
|
|
117
|
-
return t.success ? E(t.data) ? {
|
|
118
|
-
ok: !0,
|
|
119
|
-
message: t.data
|
|
120
|
-
} : {
|
|
121
|
-
ok: !1,
|
|
122
|
-
reason: "signature",
|
|
123
|
-
detail: "the signature was not made by addr over these fields"
|
|
124
|
-
} : {
|
|
125
|
-
ok: !1,
|
|
126
|
-
reason: "shape",
|
|
127
|
-
detail: w(t.error)
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
function O(e) {
|
|
131
|
-
if (e.byteLength > 2048) return {
|
|
132
|
-
ok: !1,
|
|
133
|
-
reason: "too-large",
|
|
134
|
-
detail: `${e.byteLength} bytes, the cap is ${c}`
|
|
135
|
-
};
|
|
136
|
-
let t;
|
|
137
|
-
try {
|
|
138
|
-
t = b.decode(e);
|
|
139
|
-
} catch {
|
|
140
|
-
return {
|
|
141
|
-
ok: !1,
|
|
142
|
-
reason: "not-utf8",
|
|
143
|
-
detail: "the payload is not valid UTF-8"
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
let n;
|
|
147
|
-
try {
|
|
148
|
-
n = JSON.parse(t);
|
|
149
|
-
} catch {
|
|
150
|
-
return {
|
|
151
|
-
ok: !1,
|
|
152
|
-
reason: "not-json",
|
|
153
|
-
detail: "the payload is not JSON"
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
return D(n);
|
|
157
|
-
}
|
|
158
|
-
//#endregion
|
|
159
|
-
//#region src/message/entry.ts
|
|
160
|
-
var k = 4096, A = o.string().regex(/^[0-9a-f]{64}([0-9a-f]{64})?$/, "expected a 64 or 128 hex character reference"), j = o.number().int().nonnegative().max(2 ** 53 - 1), M = o.strictObject({
|
|
161
|
-
ref: A,
|
|
162
|
-
toSeq: j
|
|
163
|
-
}), N = o.strictObject({
|
|
164
|
-
v: o.literal(7),
|
|
165
|
-
seq: j,
|
|
166
|
-
at: j,
|
|
167
|
-
msg: _,
|
|
168
|
-
history: M.nullable()
|
|
169
|
-
}), P = o.strictObject({
|
|
170
|
-
seq: j,
|
|
171
|
-
at: j,
|
|
172
|
-
msg: _
|
|
173
|
-
}), F = o.strictObject({
|
|
174
|
-
v: o.literal(7),
|
|
175
|
-
topic: o.string().min(1),
|
|
176
|
-
fromSeq: j,
|
|
177
|
-
toSeq: j,
|
|
178
|
-
messages: o.array(o.unknown()),
|
|
179
|
-
prev: M.nullable()
|
|
180
|
-
}).refine((e) => e.fromSeq <= e.toSeq, {
|
|
181
|
-
message: "fromSeq is after toSeq",
|
|
182
|
-
path: ["fromSeq"]
|
|
183
|
-
}), I = new TextDecoder("utf-8", { fatal: !0 });
|
|
184
|
-
function L(e) {
|
|
185
|
-
let t;
|
|
186
|
-
try {
|
|
187
|
-
t = I.decode(e);
|
|
188
|
-
} catch {
|
|
189
|
-
return {
|
|
190
|
-
ok: !1,
|
|
191
|
-
reason: "not-utf8",
|
|
192
|
-
detail: "the payload is not valid UTF-8"
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
try {
|
|
196
|
-
return {
|
|
197
|
-
ok: !0,
|
|
198
|
-
value: JSON.parse(t)
|
|
199
|
-
};
|
|
200
|
-
} catch {
|
|
201
|
-
return {
|
|
202
|
-
ok: !1,
|
|
203
|
-
reason: "not-json",
|
|
204
|
-
detail: "the payload is not JSON"
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
function R(e) {
|
|
209
|
-
return e.issues.map((e) => `${e.path.join(".") || "value"}: ${e.message}`).join(", ");
|
|
210
|
-
}
|
|
211
|
-
function z(e, t, n) {
|
|
212
|
-
let r = L(e);
|
|
213
|
-
if (!r.ok) return r;
|
|
214
|
-
let i = N.safeParse(r.value);
|
|
215
|
-
return i.success ? i.data.seq === t ? i.data.msg.topic === n ? {
|
|
216
|
-
ok: !0,
|
|
217
|
-
value: i.data
|
|
218
|
-
} : {
|
|
219
|
-
ok: !1,
|
|
220
|
-
reason: "mismatch",
|
|
221
|
-
detail: "the message belongs to another chat"
|
|
222
|
-
} : {
|
|
223
|
-
ok: !1,
|
|
224
|
-
reason: "mismatch",
|
|
225
|
-
detail: `seq ${i.data.seq} at index ${t}`
|
|
226
|
-
} : {
|
|
227
|
-
ok: !1,
|
|
228
|
-
reason: "shape",
|
|
229
|
-
detail: R(i.error)
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
function B(e, t, n) {
|
|
233
|
-
let r = L(e);
|
|
234
|
-
if (!r.ok) return r;
|
|
235
|
-
let i = F.safeParse(r.value);
|
|
236
|
-
if (!i.success) return {
|
|
237
|
-
ok: !1,
|
|
238
|
-
reason: "shape",
|
|
239
|
-
detail: R(i.error)
|
|
240
|
-
};
|
|
241
|
-
if (i.data.topic !== t || i.data.toSeq !== n.toSeq) return {
|
|
242
|
-
ok: !1,
|
|
243
|
-
reason: "mismatch",
|
|
244
|
-
detail: "the file is not the one its link names"
|
|
245
|
-
};
|
|
246
|
-
let { fromSeq: a, toSeq: o, prev: s } = i.data, c = [], l = 0;
|
|
247
|
-
for (let e of i.data.messages) {
|
|
248
|
-
let n = P.safeParse(e);
|
|
249
|
-
n.success && n.data.seq >= a && n.data.seq <= o && n.data.msg.topic === t ? c.push(n.data) : l++;
|
|
250
|
-
}
|
|
251
|
-
return {
|
|
252
|
-
ok: !0,
|
|
253
|
-
value: {
|
|
254
|
-
topic: t,
|
|
255
|
-
fromSeq: a,
|
|
256
|
-
toSeq: o,
|
|
257
|
-
rows: c,
|
|
258
|
-
prev: s,
|
|
259
|
-
skipped: l
|
|
260
|
-
}
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
//#endregion
|
|
264
|
-
//#region src/message/note.ts
|
|
265
|
-
var V = 1, H = 2e3, U = 3e4, W = 256, G = o.strictObject({
|
|
266
|
-
v: o.literal(1),
|
|
267
|
-
newest: o.number().int().min(-1).max(2 ** 53 - 1),
|
|
268
|
-
writtenAt: o.number().int().nonnegative().max(2 ** 53 - 1)
|
|
269
|
-
});
|
|
270
|
-
function K(e) {
|
|
271
|
-
if (!Number.isInteger(e) || e <= 0) throw RangeError(`a note slot is a positive whole number of milliseconds, not ${e}`);
|
|
272
|
-
}
|
|
273
|
-
function q(e, t) {
|
|
274
|
-
return K(t), Math.floor(e / t);
|
|
275
|
-
}
|
|
276
|
-
function J(e, t) {
|
|
277
|
-
return K(t), (e + 1) * t;
|
|
278
|
-
}
|
|
279
|
-
function Y(e, t, n) {
|
|
280
|
-
return `${e}/note/${t}/${n}`;
|
|
281
|
-
}
|
|
282
|
-
function X(e, t, r) {
|
|
283
|
-
return n.fromString(Y(e, t, r));
|
|
284
|
-
}
|
|
285
|
-
function Z(n, r, a, o) {
|
|
286
|
-
let s = X(n, r, a);
|
|
287
|
-
return new i(e.keccak256(e.concat(s.toUint8Array(), new t(o).toUint8Array())));
|
|
288
|
-
}
|
|
289
|
-
var Q = new TextEncoder(), $ = new TextDecoder("utf-8", { fatal: !0 });
|
|
290
|
-
function ee(e) {
|
|
291
|
-
let t = {
|
|
292
|
-
v: 1,
|
|
293
|
-
newest: e.newest,
|
|
294
|
-
writtenAt: e.writtenAt
|
|
295
|
-
};
|
|
296
|
-
return Q.encode(JSON.stringify(t));
|
|
297
|
-
}
|
|
298
|
-
function te(e) {
|
|
299
|
-
if (e.length > 256) return null;
|
|
300
|
-
try {
|
|
301
|
-
let t = G.safeParse(JSON.parse($.decode(e)));
|
|
302
|
-
return t.success ? t.data : null;
|
|
303
|
-
} catch {
|
|
304
|
-
return null;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
//#endregion
|
|
308
|
-
export { v as ChatMessageError, U as DEFAULT_NOTE_HEARTBEAT_MS, H as DEFAULT_NOTE_SLOT_MS, k as MAX_ENTRY_BYTES, c as MAX_MESSAGE_BYTES, d as MAX_NAME_CHARACTERS, W as MAX_NOTE_BYTES, u as MAX_TEXT_CHARACTERS, l as MAX_TOPIC_CHARACTERS, s as MESSAGE_VERSION, f as MessageType, V as NOTE_VERSION, _ as chatMessageSchema, D as checkChatMessage, p as countCharacters, T as createChatMessage, S as encodeChatMessage, ee as encodeSlotNote, N as feedEntrySchema, E as hasValidSignature, F as historyFileSchema, M as historyLinkSchema, P as historyRowSchema, C as newMessageId, Z as noteAddress, X as noteIdentifier, Y as noteIdentifierText, J as noteSlotEnd, q as noteSlotOf, O as parseChatMessage, z as parseFeedEntry, B as parseHistoryFile, te as parseSlotNote, x as signedBytes, G as slotNoteSchema };
|
|
1
|
+
import { A as e, B as t, C as n, D as r, E as i, F as a, H as o, I as s, L as c, M as l, N as u, O as d, P as f, R as p, S as m, T as h, V as g, _, a as v, b as y, c as b, d as x, f as S, g as C, h as w, i as T, j as E, k as D, l as O, m as k, n as A, o as j, p as M, r as N, s as P, t as F, u as I, v as L, w as R, x as z, y as B, z as V } from "./message-Dbh8qrpg.js";
|
|
2
|
+
export { V as CHAT_BINDING_TITLE, m as ChatMessageError, F as DEFAULT_NOTE_HEARTBEAT_MS, A as DEFAULT_NOTE_SLOT_MS, t as MAX_BINDING_CHARACTERS, M as MAX_ENTRY_BYTES, n as MAX_MESSAGE_BYTES, R as MAX_NAME_CHARACTERS, N as MAX_NOTE_BYTES, h as MAX_TEXT_CHARACTERS, i as MAX_TOPIC_CHARACTERS, r as MESSAGE_VERSION, d as MessageType, D as MessageVia, T as NOTE_VERSION, y as OWN_FEED_TOPIC_PREFIX, g as chatBindingSchema, e as chatMessageSchema, o as checkChatBinding, E as countCharacters, l as createChatMessage, u as encodeChatMessage, v as encodeSlotNote, k as feedEntrySchema, f as hasValidSignature, w as historyFileSchema, C as historyLinkSchema, _ as historyRowSchema, a as newMessageId, j as noteAddress, P as noteIdentifier, b as noteIdentifierText, O as noteSlotEnd, I as noteSlotOf, z as ownFeedTopic, s as parseChatMessage, L as parseFeedEntry, B as parseHistoryFile, x as parseSlotNote, c as signedBytes, S as slotNoteSchema, p as verifyChatMessage };
|
package/dist/sender.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { PrivateKey } from '@ethersphere/bee-js';
|
|
2
|
-
import { type ChatMessage, type ChatMessageDraft } from './message/index.js';
|
|
2
|
+
import { type ChatBinding, type ChatMessage, type ChatMessageDraft, type MessageVia } from './message/index.js';
|
|
3
3
|
/** Writes one payload to the chat's GSOC address. Rejects when the write did not reach the node. */
|
|
4
4
|
export type GsocWrite = (payload: Uint8Array) => Promise<void>;
|
|
5
5
|
export interface SenderSettings {
|
|
@@ -26,21 +26,33 @@ export interface SenderEvents {
|
|
|
26
26
|
/** Read back from the chat feed. */
|
|
27
27
|
confirmed(message: ChatMessage): void;
|
|
28
28
|
}
|
|
29
|
-
export type SendDraft = Omit<ChatMessageDraft, 'name' | 'ts' | 'id'>;
|
|
29
|
+
export type SendDraft = Omit<ChatMessageDraft, 'name' | 'ts' | 'id' | 'via' | 'own' | 'idb'>;
|
|
30
|
+
/** What every message this sender signs says about who sent it and how. */
|
|
31
|
+
export interface SenderProfile {
|
|
32
|
+
name: string;
|
|
33
|
+
via: MessageVia;
|
|
34
|
+
/** The sender's Swarm ID chat binding, for a signed-in sender only. */
|
|
35
|
+
idb?: ChatBinding;
|
|
36
|
+
/**
|
|
37
|
+
* Whether the sender keeps a copy of every message in its own feed, false when left out. The library writes no copy:
|
|
38
|
+
* the `GsocWrite` that keeps one stores it from the payload it is handed, before or after the inbox write.
|
|
39
|
+
*/
|
|
40
|
+
own?: boolean;
|
|
41
|
+
}
|
|
30
42
|
/**
|
|
31
43
|
* Sends signed messages as GSOC writes and keeps each one pending until the chat feed shows it. A pending message is
|
|
32
44
|
* written again with the identical bytes, so the server can tell a resend from a new message by its id.
|
|
33
45
|
*/
|
|
34
46
|
export declare class Sender {
|
|
35
47
|
private readonly key;
|
|
36
|
-
private readonly
|
|
48
|
+
private readonly profile;
|
|
37
49
|
private readonly write;
|
|
38
50
|
private readonly events;
|
|
39
51
|
private readonly settings;
|
|
40
52
|
private readonly outgoing;
|
|
41
53
|
private readonly reactions;
|
|
42
54
|
private stopped;
|
|
43
|
-
constructor(key: PrivateKey,
|
|
55
|
+
constructor(key: PrivateKey, profile: SenderProfile, write: GsocWrite, events: SenderEvents, settings?: SenderSettings);
|
|
44
56
|
get address(): string;
|
|
45
57
|
/** Builds, signs and writes a message. Throws a ChatMessageError, and writes nothing, for one the server would refuse. */
|
|
46
58
|
send(draft: SendDraft): ChatMessage;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solarpunkltd/swarm-chat-js",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.1.0",
|
|
4
4
|
"description": "JS library for chatting on Swarm",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"chat",
|
|
@@ -36,7 +36,17 @@
|
|
|
36
36
|
"require": "./dist/message.cjs"
|
|
37
37
|
}
|
|
38
38
|
},
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "vite build && tsc -p tsconfig.build.json",
|
|
41
|
+
"prepack": "npm run build",
|
|
42
|
+
"lint": "oxlint --type-aware .",
|
|
43
|
+
"format": "oxfmt .",
|
|
44
|
+
"format:check": "oxfmt --check .",
|
|
45
|
+
"typecheck": "tsc --noEmit",
|
|
46
|
+
"test": "vitest run"
|
|
47
|
+
},
|
|
39
48
|
"dependencies": {
|
|
49
|
+
"@ethersphere/core-sdk": "0.1.1",
|
|
40
50
|
"zod": "4.6.5"
|
|
41
51
|
},
|
|
42
52
|
"devDependencies": {
|
|
@@ -55,12 +65,5 @@
|
|
|
55
65
|
"engines": {
|
|
56
66
|
"node": ">=24"
|
|
57
67
|
},
|
|
58
|
-
"
|
|
59
|
-
|
|
60
|
-
"lint": "oxlint --type-aware .",
|
|
61
|
-
"format": "oxfmt .",
|
|
62
|
-
"format:check": "oxfmt --check .",
|
|
63
|
-
"typecheck": "tsc --noEmit",
|
|
64
|
-
"test": "vitest run"
|
|
65
|
-
}
|
|
66
|
-
}
|
|
68
|
+
"packageManager": "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c"
|
|
69
|
+
}
|