@estiva-app/protocol 0.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.
@@ -0,0 +1,432 @@
1
+ /** A Nostr tag: an array of strings whose first element is the tag name. */
2
+ export type NostrTag = string[];
3
+ /** An event before signing. `pubkey` is 64-char lowercase hex. */
4
+ export interface UnsignedEvent {
5
+ pubkey: string;
6
+ created_at: number;
7
+ kind: number;
8
+ tags: NostrTag[];
9
+ content: string;
10
+ }
11
+ /** A signed event, ready to submit to the relay. */
12
+ export interface SignedEvent extends UnsignedEvent {
13
+ id: string;
14
+ sig: string;
15
+ }
16
+ /**
17
+ * Buzz kind numbers used across the suite (crates/buzz-core/src/kind.rs).
18
+ *
19
+ * The union of what Peek and Ship each declared before SHA-3. A kind number is
20
+ * a fact about the relay, not about an app, so there is no reason for two apps
21
+ * to hold different subsets of it — and a subset is how an app ends up unable to
22
+ * *read* a kind its neighbour writes.
23
+ */
24
+ export declare const KIND: {
25
+ readonly PROFILE: 0;
26
+ readonly DELETION: 5;
27
+ readonly REACTION: 7;
28
+ readonly STREAM_MESSAGE: 9;
29
+ readonly NIP29_PUT_USER: 9000;
30
+ readonly NIP29_EDIT_METADATA: 9002;
31
+ readonly NIP29_CREATE_GROUP: 9007;
32
+ readonly NIP29_DELETE_GROUP: 9008;
33
+ /**
34
+ * Estiva assertion — a statement *about* something in the channel, rather
35
+ * than a message in it (PEEK-128). `resolution` is the first and, for now,
36
+ * only subtype; the `t` tag names it so later subtypes can join without a
37
+ * new kind.
38
+ *
39
+ * The number sits in the **regular** range (1000–9999), which is what makes
40
+ * it stored and append-only. A replaceable kind would overwrite the previous
41
+ * assertion and destroy exactly the history this exists to keep. It clears
42
+ * NIP-29's 9000–9030 block on purpose.
43
+ */
44
+ readonly ASSERTION: 9101;
45
+ /**
46
+ * NIP-22 comment (REW-10). Ship's comments are posted into the project's
47
+ * Folder — which *is* a Peek topic's channel — so they arrive in a channel as
48
+ * ordinary messages and must be read alongside `STREAM_MESSAGE`.
49
+ *
50
+ * Both kinds, permanently: a `kind:9` is not replaceable, so every comment
51
+ * written before Ship flipped stays `kind:9` forever and this pair can never
52
+ * shrink to one.
53
+ */
54
+ readonly COMMENT: 1111;
55
+ /** NIP-84 highlight. */
56
+ readonly HIGHLIGHT: 9802;
57
+ /** NIP-FC File — see docs/buzz-compat/nips/NIP-FC.md in the Peek repo. */
58
+ readonly FILE: 30840;
59
+ /** NIP-FC Component. */
60
+ readonly COMPONENT: 30841;
61
+ /**
62
+ * NIP-42 relay auth — the challenge response that turns a connected socket
63
+ * into an authenticated one (`Kind::Authentication`, PEE-5).
64
+ *
65
+ * Unlike every other kind here, this one is **never published**: Buzz builds
66
+ * it into `buzz-auth/src/nip42.rs`, never stores it, and never logs it —
67
+ * "AUTH events are never stored or logged (may contain bearer tokens)" is a
68
+ * comment in that file. It goes over the socket and is gone.
69
+ */
70
+ readonly RELAY_AUTH: 22242;
71
+ readonly HTTP_AUTH: 27235;
72
+ };
73
+ /** `build_reaction` (builders.rs:463) caps the emoji at 64 chars. */
74
+ export declare const MAX_EMOJI_CHARS = 64;
75
+ /** kind:9 content cap — `check_content(content, 64 * 1024)` in build_message. */
76
+ export declare const MAX_MESSAGE_BYTES: number;
77
+ /** `mention_tags` in builders.rs rejects more than this many mentions. */
78
+ export declare const MAX_MENTIONS = 50;
79
+ /**
80
+ * NIP-01 event id: sha256 over the canonical serialization
81
+ * `[0, pubkey, created_at, kind, tags, content]`.
82
+ *
83
+ * `JSON.stringify` produces exactly the escaping NIP-01 requires (`\n`, `\"`,
84
+ * `\\`, `\r`, `\t`, `\b`, `\f`, `\uXXXX` for other control chars) with no
85
+ * insignificant whitespace, so no custom serializer is needed.
86
+ *
87
+ * Cross-checked against `nostr-tools/pure`'s `getEventHash` over 103 events
88
+ * recorded from production: all 103 ids agree. See `test/oracle.test.ts` — the
89
+ * third-party implementation is a devDependency of this package and a dependency
90
+ * of nothing, so the check costs consumers no bytes.
91
+ */
92
+ export declare function computeEventId(e: UnsignedEvent): string;
93
+ /** Apps store ms; Nostr `created_at` is seconds. */
94
+ export declare function toNostrSeconds(ms: number): number;
95
+ /**
96
+ * Buzz's `canonical_channel_name` (crates/buzz-core/src/channel.rs:15):
97
+ * strip leading '#' and whitespace, then trim the end. Applied by
98
+ * `build_create_channel` before the name reaches the tag, so we must match it or
99
+ * our ids diverge for any title with a leading '#' or space.
100
+ */
101
+ export declare function canonicalChannelName(name: string): string;
102
+ /** NIP-01 addressable reference: `<kind>:<pubkey>:<d-tag>`. */
103
+ export declare function addr(kind: number, pubkey: string, dTag: string): string;
104
+ /**
105
+ * kind:0 profile — mirrors `build_profile` (builders.rs:537).
106
+ *
107
+ * Buzz builds the content with `serde_json::Map`, which is a `BTreeMap` unless
108
+ * the `preserve_order` feature is enabled. It is not enabled in Buzz's
109
+ * workspace, so **keys serialize in alphabetical order**: about, display_name,
110
+ * name, nip05, picture. We sort to match; getting this wrong changes the content
111
+ * string and therefore the event id.
112
+ *
113
+ * An app must not call this: the identity service is the sole publisher of
114
+ * `kind:0` and refuses it for every app before consulting any allowlist
115
+ * (SPEC §4.2). It is here because the *identity service* and the seed scripts
116
+ * need it, and because a second copy of this key ordering is the kind of thing
117
+ * that drifts.
118
+ */
119
+ export declare function buildProfile(pubkey: string, createdAtMs: number, fields: {
120
+ display_name?: string;
121
+ name?: string;
122
+ picture?: string;
123
+ about?: string;
124
+ nip05?: string;
125
+ }): UnsignedEvent;
126
+ /** Who a pubkey belongs to, as far as the relay knows. */
127
+ export interface Profile {
128
+ /** kind:0 `display_name` or `name`. Absent when nobody has published one. */
129
+ displayName?: string;
130
+ /** kind:0 `picture` — an avatar URL chosen by whichever app published it. */
131
+ picture?: string;
132
+ }
133
+ /**
134
+ * The inverse of `buildProfile`: a kind:0 event to the fields an app shows.
135
+ *
136
+ * Both name keys are read because both are written: Peek publishes
137
+ * `display_name`, Ship publishes `name`, and a person who has used both apps
138
+ * should resolve either way rather than on a coin flip. Anything that will not
139
+ * parse costs a name, never the read that asked for it.
140
+ *
141
+ * One parser is what keeps a person from having two names depending on which
142
+ * app they appear in — which is the whole reason this is not left to each
143
+ * consumer.
144
+ */
145
+ export declare function parseProfile(event: {
146
+ content: string;
147
+ } | undefined): Profile;
148
+ export type ChannelVisibility = 'open' | 'private';
149
+ export type ChannelKind = 'stream' | 'forum' | 'dm';
150
+ /**
151
+ * kind:9007 create channel — mirrors `build_create_channel` (builders.rs:674).
152
+ * Tag order is fixed: h, name, [visibility], [channel_type], [about], [ttl].
153
+ */
154
+ export declare function buildCreateChannel(pubkey: string, createdAtMs: number, args: {
155
+ channelUuid: string;
156
+ name: string;
157
+ visibility?: ChannelVisibility;
158
+ channelType?: ChannelKind;
159
+ about?: string;
160
+ ttlSeconds?: number;
161
+ }): UnsignedEvent;
162
+ /**
163
+ * kind:9008 NIP-29 delete-group — what makes a deleted container actually gone.
164
+ *
165
+ * Deleting a topic in Peek used to remove it and its messages from Convex and
166
+ * publish nothing at all. Create propagated as a 9007; delete propagated
167
+ * nowhere. So a conversation somebody deleted, believing it gone, stayed
168
+ * readable to every admitted member indefinitely — measured on production at 145
169
+ * messages across 37 channels with zero deletion requests against any of them
170
+ * (PEEK-170).
171
+ *
172
+ * **9008 rather than a kind:5 per message**, and the difference is capability
173
+ * rather than efficiency. Buzz rejects a multi-target kind:5 outright, and
174
+ * NIP-09 is honoured only for the key that signed the original — so
175
+ * per-message deletion could never reach anybody else's messages in the
176
+ * container. Delete-group soft-deletes the channel, and Buzz's read guards
177
+ * (`c.deleted_at IS NULL` in both `get_accessible_channels` and `is_member`)
178
+ * then hide the whole container regardless of who wrote what is in it.
179
+ *
180
+ * Requires the channel's **owner** — Buzz enforces "only owner can delete
181
+ * group" in `validate_admin_event`, and a container's creator becomes its owner
182
+ * at create. Anybody else is refused, which the caller reports rather than hides.
183
+ */
184
+ export declare function buildDeleteChannel(pubkey: string, createdAtMs: number, args: {
185
+ channelUuid: string;
186
+ }): UnsignedEvent;
187
+ /**
188
+ * kind:9002 edit metadata — renaming a channel (PEE-2).
189
+ *
190
+ * Buzz applies each recognised tag it finds (`name`, `about`, `archived`,
191
+ * `topic`, `purpose`, `visibility`, `ttl`) and refuses an event carrying none
192
+ * of them, so this builds exactly the fields asked for and nothing else.
193
+ *
194
+ * The name goes through `canonicalChannelName` for the same reason
195
+ * `buildCreateChannel` does: Buzz canonicalises before storing, so sending the
196
+ * raw string means the app and the relay disagree about what the container is
197
+ * called. A name that canonicalises away to nothing is not a rename, and
198
+ * throwing here is better than a round trip to be told so.
199
+ *
200
+ * Requires the channel's owner or admin — the relay refuses anyone else.
201
+ */
202
+ export declare function buildEditChannelMetadata(pubkey: string, createdAtMs: number, args: {
203
+ channelUuid: string;
204
+ name?: string;
205
+ about?: string;
206
+ }): UnsignedEvent;
207
+ export type MemberRole = 'owner' | 'admin' | 'member';
208
+ /**
209
+ * kind:9000 add member — mirrors `build_add_member` (builders.rs:565).
210
+ * Tag order: h, p, [role]. The target pubkey is lowercased by Buzz.
211
+ */
212
+ export declare function buildAddMember(pubkey: string, createdAtMs: number, args: {
213
+ channelUuid: string;
214
+ targetPubkey: string;
215
+ role?: MemberRole;
216
+ }): UnsignedEvent;
217
+ /**
218
+ * kind:7 reaction — mirrors `build_reaction` (builders.rs:463).
219
+ *
220
+ * Note there is **no `h` tag**: Buzz derives the channel from the *target's*
221
+ * `#e` tag and explicitly ignores a client-supplied `#h` (`NOSTR.md`). Adding one
222
+ * would change the event id for no benefit.
223
+ */
224
+ export declare function buildReaction(pubkey: string, createdAtMs: number, args: {
225
+ targetEventId: string;
226
+ emoji: string;
227
+ }): UnsignedEvent;
228
+ /**
229
+ * kind:5 deletion — mirrors `build_remove_reaction` (builders.rs:495).
230
+ *
231
+ * Buzz accepts self-authored deletions (and an owner deleting their agent's).
232
+ * NIP-09 is a *request*, author-scoped, and it removes the record rather than
233
+ * the work — so an app must hide the control from non-authors rather than offer
234
+ * one that silently fails (SPEC §6.5).
235
+ */
236
+ export declare function buildDeletion(pubkey: string, createdAtMs: number, args: {
237
+ targetEventId: string;
238
+ }): UnsignedEvent;
239
+ /**
240
+ * NIP-10 reply context.
241
+ *
242
+ * Mirrors Buzz's `ThreadRef` + `thread_tags` (builders.rs:173), which has a
243
+ * detail that is easy to get wrong: for a **direct** reply (parent is the root)
244
+ * Buzz emits a SINGLE tag marked `"reply"` — not a `"root"` tag. Only a nested
245
+ * reply emits both. Getting this wrong changes the event id and, worse, produces
246
+ * threads Buzz's clients read differently.
247
+ */
248
+ export interface ThreadRef {
249
+ /** Thread root event id (64-hex). */
250
+ rootId: string;
251
+ /** Direct parent event id. Equal to `rootId` for a direct reply. */
252
+ parentId: string;
253
+ }
254
+ /** Exactly Buzz's `thread_tags` (builders.rs:173). */
255
+ export declare function threadTags(ref: ThreadRef): NostrTag[];
256
+ /**
257
+ * kind:9 stream message — mirrors `build_message` (builders.rs:219).
258
+ * Tag order: h, [thread tags], [a about], [p mentions], [broadcast], [imeta].
259
+ *
260
+ * **This is the shape verified byte-identical against Buzz's SDK** — see Peek's
261
+ * docs/buzz-compat/INTEROP_PROOF.md §4.
262
+ *
263
+ * **`about` is where the two copies had drifted.** Peek grew it so a pasted
264
+ * NIP-19 pointer could carry its address as an `a` tag and Ship could route the
265
+ * conversation to the issue directly; Ship's copy never received it and could
266
+ * not emit one at all. Peek's shape is what ships. Omitting `about` produces
267
+ * byte-identical output to Ship's old builder — pinned by
268
+ * `test/wire-vectors.test.ts`, because "the change is a no-op for Ship" is
269
+ * exactly the kind of claim that deserves a fixture rather than a sentence.
270
+ */
271
+ export declare function buildMessage(pubkey: string, createdAtMs: number, args: {
272
+ channelUuid: string;
273
+ content: string;
274
+ threadRef?: ThreadRef;
275
+ /** Addressable objects this conversation concerns (for cross-app routing). */
276
+ about?: string[];
277
+ /** Mentioned pubkeys (64-hex). Deduplicated, lowercased, capped at 50. */
278
+ mentions?: string[];
279
+ broadcast?: boolean;
280
+ /** Raw `imeta` tag vectors for media attachments. */
281
+ mediaTags?: NostrTag[];
282
+ }): UnsignedEvent;
283
+ /** Assertion subtypes. Only `resolution` exists today (PEEK-128). */
284
+ export declare const ASSERTION_SUBTYPE: {
285
+ readonly RESOLUTION: "resolution";
286
+ };
287
+ /** What a resolution assertion says happened. */
288
+ export type ResolutionAction = 'resolved' | 'reopened';
289
+ /** Rationale cap — the same 64 KiB ceiling a message content carries. */
290
+ export declare const MAX_RATIONALE_BYTES: number;
291
+ /**
292
+ * kind:9101 resolution assertion — "this thread is resolved", said on the wire
293
+ * so any Estiva app reading the channel can see it (PEEK-128).
294
+ *
295
+ * **Append-only.** A reopen is another assertion, never a deletion of the
296
+ * resolve that preceded it; current state is folded from the ordered run, not
297
+ * read off a single canonical event. That is why this is a regular kind rather
298
+ * than a replaceable one — see `KIND.ASSERTION`.
299
+ *
300
+ * The event carries the claim and who made it. It does **not** carry authority:
301
+ * there is no "proposed" or "endorsed" mode here, because how much weight a
302
+ * given actor's assertion deserves is a policy question that belongs to the app
303
+ * reading it, not to the protocol. That is also why the *fold* of these
304
+ * assertions is not in this package — see the README on the line this package
305
+ * does not cross.
306
+ *
307
+ * Tag order is fixed so the event id is reproducible: h, e(target), t, action,
308
+ * [e(support)].
309
+ */
310
+ export declare function buildResolution(pubkey: string, createdAtMs: number, args: {
311
+ channelUuid: string;
312
+ /** Event id of the message whose resolution state this asserts. */
313
+ targetEventId: string;
314
+ action: ResolutionAction;
315
+ /** Optional reply that carried the resolution, for readers that want it. */
316
+ supportingEventId?: string;
317
+ /** Optional free text. */
318
+ rationale?: string;
319
+ }): UnsignedEvent;
320
+ /** NIP-32 self-label: a namespace and a value, both indexable. */
321
+ export interface Label {
322
+ /** Namespace, e.g. "nfb.highlight". */
323
+ namespace: string;
324
+ /** Value within that namespace, e.g. "insight". */
325
+ value: string;
326
+ }
327
+ /**
328
+ * kind:30840 File — NIP-FC.
329
+ *
330
+ * `componentDTags` are listed **in document order**; order lives on the File so
331
+ * reordering is a single edit in one place.
332
+ */
333
+ export declare function buildFile(pubkey: string, createdAtMs: number, args: {
334
+ /** Stable File id. MUST NOT encode the relay or org — Files are portable. */
335
+ fileId: string;
336
+ title: string;
337
+ componentDTags: string[];
338
+ /** Channel scope. A File in a private channel inherits its access rules. */
339
+ channelUuid?: string;
340
+ /** File-level metadata; shape is the app's business. */
341
+ metadata?: Record<string, unknown>;
342
+ }): UnsignedEvent;
343
+ /**
344
+ * kind:30841 Component — NIP-FC.
345
+ *
346
+ * `type` must be namespaced `<namespace>/<name>`. The protocol defines the
347
+ * container; the payload shape belongs to the type.
348
+ */
349
+ export declare function buildComponent(pubkey: string, createdAtMs: number, args: {
350
+ componentId: string;
351
+ /** Parent File's `d` tag. */
352
+ fileId: string;
353
+ /** Namespaced, e.g. `nfb/todo`. */
354
+ type: string;
355
+ payload: Record<string, unknown>;
356
+ channelUuid?: string;
357
+ labels?: Label[];
358
+ }): UnsignedEvent;
359
+ /**
360
+ * kind:9802 highlight — NIP-84.
361
+ *
362
+ * `.content` is the excerpt itself. `e`/`a` tags point at a source event, `r` at
363
+ * a URL; `p` attributes the original author.
364
+ *
365
+ * Optional NIP-32 `L`/`l` self-labels categorise the highlight. NIP-32 §52
366
+ * allows those tags on non-1985 events for exactly this ("self-reporting"), so
367
+ * a highlight can say *what kind* of highlight it is without a bespoke kind.
368
+ */
369
+ export declare function buildHighlight(pubkey: string, createdAtMs: number, args: {
370
+ /** The excerpt. */
371
+ content: string;
372
+ /** Channel to post into (Buzz scopes by `h`). */
373
+ channelUuid?: string;
374
+ /** Source event being highlighted. */
375
+ sourceEventId?: string;
376
+ /** Source URL, when the highlight came from outside Nostr. */
377
+ sourceUrl?: string;
378
+ /** Original author(s) of the highlighted material. */
379
+ attribution?: string[];
380
+ labels?: Label[];
381
+ }): UnsignedEvent;
382
+ /**
383
+ * The relay's clock tolerance for a NIP-42 AUTH event, in seconds.
384
+ *
385
+ * `TIMESTAMP_TOLERANCE_SECS` in `crates/buzz-auth/src/nip42.rs` — the same ±60s
386
+ * NIP-98 uses, checked against the *relay's* clock. It is the one failure here
387
+ * a correct client can still hit: a browser whose clock is more than a minute
388
+ * out signs a perfectly valid event that is refused every time, and the socket
389
+ * is left open and permanently unauthenticated rather than closed.
390
+ */
391
+ export declare const RELAY_AUTH_TOLERANCE_SECS = 60;
392
+ /**
393
+ * The relay URL a NIP-42 `relay` tag must carry, as Buzz computes it.
394
+ *
395
+ * `nip42_expected_relay_url` (`buzz-relay/src/api/bridge.rs:225`) is literally
396
+ * `format!("{scheme}://{}", tenant.host())` — scheme from the deployment, host
397
+ * from **the tenant the connection arrived on**, never the deployment-wide
398
+ * `config.relay_url`. Buzz has a test asserting exactly that
399
+ * (`nip42_expected_relay_url_uses_tenant_host_not_config_host`), because it
400
+ * regressed once.
401
+ *
402
+ * So: an origin, with no path and no trailing slash, derived from the URL we
403
+ * actually connected to. `normalize_relay_url` on the relay side would forgive
404
+ * a trailing slash, but it would not forgive a path or a different host.
405
+ */
406
+ export declare function relayAuthUrl(connectUrl: string): string;
407
+ /**
408
+ * An unsigned kind:22242 answering a relay's AUTH challenge.
409
+ *
410
+ * Built here rather than at a call site because the tag layout is part of the
411
+ * event id preimage, and a second copy would be a silent divergence the relay
412
+ * notices and we do not.
413
+ *
414
+ * **Tag order is not load-bearing for this one kind**, unusually for this file.
415
+ * Buzz looks both tags up by name — `tags.find(TagKind::Challenge)` and
416
+ * `tags.find(TagKind::Relay)` in `verify_nip42_event` — and the two reference
417
+ * clients disagree anyway: rust-nostr's `EventBuilder::auth` emits challenge
418
+ * first, nostr-tools' `makeAuthEvent` emits relay first. NIP-42's own example
419
+ * uses relay-then-challenge, which is what this follows. Nothing downstream
420
+ * compares this event's id to anything, because nothing ever stores it.
421
+ */
422
+ export declare function buildUnsignedRelayAuthEvent(args: {
423
+ /** Left empty for `/sign`, which overwrites it with the token's subject. */
424
+ pubkey: string;
425
+ /** The URL the socket connected to. Reduced to an origin — see above. */
426
+ relayUrl: string;
427
+ /** The challenge exactly as the relay sent it. Compared byte for byte. */
428
+ challenge: string;
429
+ /** Override for tests; defaults to now. `Date.now` is in `lib.es2022`. */
430
+ nowMs?: number;
431
+ }): UnsignedEvent;
432
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"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"}