@forgesworn/fold-kit 0.10.0 → 0.13.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/dist/index.d.ts CHANGED
@@ -7,7 +7,7 @@ export type { DeviceCredential, AccessTier, AgentRule, RoomPolicy, KindredProof
7
7
  export type { RelayTransport } from './transport.js';
8
8
  export { createDeviceCredential, verifyDeviceCredential, PERSON_CREDENTIAL_MAX_SECONDS, RestampedCredentialExpiryError, } from './credential.js';
9
9
  export type { CreateCredentialOptions, VerifyResult } from './credential.js';
10
- export { SEAL_TAG, isSealPubkey, generateSealKey, credentialSeal, sealTarget, sealTo, openSealed, newerCredential, } from './seal.js';
10
+ export { SEAL_TAG, SENDER_TAG, sealSender, isSealPubkey, generateSealKey, credentialSeal, sealTarget, sealTo, openSealed, newerCredential, } from './seal.js';
11
11
  export type { SealKey } from './seal.js';
12
12
  export { deriveScoped, SCOPED_LABEL_PATTERN } from './scoped.js';
13
13
  export type { ScopedKeys } from './scoped.js';
@@ -18,8 +18,10 @@ export { MAX_RELAY_HINTS, MAX_ICE_HINTS, MAX_NETWORK_HINT_LENGTH, isSafeRelayUrl
18
18
  export { sanitiseDisplayName, MAX_DISPLAY_NAME_LENGTH } from './display-name.js';
19
19
  export { issueKindredProof, evaluateAccess, ACCESS_LABELS, } from './access.js';
20
20
  export type { IssueKindredProofOptions } from './access.js';
21
- export { INVITATION_DELEGATION_TTL_SECONDS, MAX_INVITATION_DELEGATION_DEPTH, createRoomInvitation, roomInvitation, deriveInvitationId, encodeInvitationRequest, decodeInvitationRequest, verifyInvitationDelegation, encodeInvitationGrant, decodeRoomAdmissionGrant, decodeInvitationGrant, ROOM_ENDED_MESSAGE, encodeInvitationRetirement, decodeInvitationRetirement, decodeInvitationRetirementNotice, retirementError, hostRoomInvitation, requestRoomAdmissionCapability, requestRoomAdmission, INVITATION_LABELS, } from './invitation.js';
22
- export type { RoomInvitation, RoomInvitationHost, InvitationDelegation, RoomInvitationDelegate, RoomAdmission, EncodeInvitationRequestOptions, InvitationRequest, DecodeInvitationRequestOptions, EncodeInvitationGrantOptions, DecodeInvitationGrantOptions, HostRoomInvitationOptions, EncodeInvitationRetirementOptions, RequestRoomAdmissionOptions, } from './invitation.js';
21
+ export { INVITATION_DELEGATION_TTL_SECONDS, MAX_INVITATION_DELEGATION_DEPTH, createRoomInvitation, roomInvitation, deriveInvitationId, encodeInvitationAccountProof, encodeInvitationRequest, decodeInvitationRequest, verifyInvitationDelegation, encodeInvitationGrant, decodeRoomAdmissionGrant, decodeInvitationGrant, ROOM_ENDED_MESSAGE, encodeInvitationRetirement, decodeInvitationRetirement, decodeInvitationRetirementNotice, retirementError, hostRoomInvitation, requestRoomAdmissionCapability, requestRoomAdmission, INVITATION_LABELS, } from './invitation.js';
22
+ export type { RoomInvitation, RoomInvitationHost, InvitationDelegation, RoomInvitationDelegate, RoomAdmission, EncodeInvitationAccountProofOptions, EncodeInvitationRequestOptions, InvitationRequest, DecodeInvitationRequestOptions, EncodeInvitationGrantOptions, DecodeInvitationGrantOptions, HostRoomInvitationOptions, EncodeInvitationRetirementOptions, RequestRoomAdmissionOptions, } from './invitation.js';
23
+ export { encodeInvitationDecline, decodeInvitationDecline, InvitationDeclinedError } from './invitation-decline.js';
24
+ export type { EncodeInvitationDeclineOptions, InvitationDecline } from './invitation-decline.js';
23
25
  export { encodePersistentInvitation, decodePersistentInvitation, requestPersistentRoomAdmission, PERSISTENT_INVITATION_LABELS, } from './persistent-invitation.js';
24
26
  export type { PersistentRoomAdmission } from './persistent-invitation.js';
25
27
  export { withExpiration, isRoomEnds, requireRoomEnds, MAX_ROOM_ENDS_SECONDS } from './expiration.js';
@@ -28,6 +30,8 @@ export { MAX_ROOM_LINK_FRAGMENT_LENGTH, parseRoomLink, encodeRoomLink, } from '.
28
30
  export type { RoomLink } from './link.js';
29
31
  export { EPOCH_ID_INFO, EPOCH_KEY_INFO, MAX_EPOCH, EPOCH_REQUEST_KEY_INFO, generateEpochSecret, deriveEpoch, encodeRekeyEvent, peekRekeyEvent, readMemberList, REPORT_UNKNOWN_EVERY_SECONDS, decodeRekeyEvent, HISTORY_WINDOW_SECONDS, MAX_HISTORY_EPOCHS, epochsInWindow, deriveEpochRequestKey, epochRequestAdmission, encodeEpochRequest, decodeEpochRequest, encodeEpochGrant, decodeEpochGrant, hostRoomEpoch, sealCredential, EpochRefusedError, requestRoomEpoch, canonicalAdmins, CHANNEL_NAME, RESERVED_CHANNELS, canonicalChannels, signChannels, verifyChannels, signAdmins, verifyAdmins, EPOCH_LABELS, } from './epoch.js';
30
32
  export type { RoomEpoch, EpochKeys, EncodeRekeyOptions, RekeyRecipient, RekeyNotice, PeekRekeyOptions, DecodeRekeyOptions, LeftEpoch, EpochRequestAdmissionOptions, EncodeEpochRequestOptions, DecodeEpochRequestOptions, EpochRequest, EpochRefusal, EncodeEpochGrantOptions, DecodeEpochGrantOptions, EpochGrant, HostRoomEpochOptions, RequestRoomEpochOptions, SignAdminsOptions, SignChannelsOptions, VerifyChannelsOptions, VerifyAdminsOptions, } from './epoch.js';
33
+ export { DEFAULT_REPLY_DELAY_MS, REFUSE_AGAIN_AFTER_SECONDS, MAX_REFUSALS_PER_MINUTE, REFUSAL_LIMITER_CAPACITY, RefusalLimiter, replyDelay, } from './quiet-reply.js';
34
+ export type { ReplyDelayRange, ReplySchedule, RefusalLimiterOptions } from './quiet-reply.js';
31
35
  export { EPOCH_COMMIT_PREFIX, epochCommitment, EPOCH_COMMIT_LABELS } from './epoch-commit.js';
32
36
  export { MEMBER_EPOCH_KINDS, MEMBER_EPOCH_REQUEST_KEY_INFO, MAX_MEMBER_EPOCH_CHAIN, deriveMemberEpochRequestKey, readRekeyEvidence, encodeMemberEpochRequest, decodeMemberEpochRequest, encodeMemberEpochGrant, decodeMemberEpochGrant, hostMemberEpochDesk, memberEpochSource, requestMemberEpoch, MEMBER_EPOCH_LABELS, } from './member-epoch.js';
33
37
  export type { RekeyEvidence, EncodeMemberEpochRequestOptions, DecodeMemberEpochRequestOptions, MemberEpochRequest, EncodeMemberEpochGrantOptions, DecodeMemberEpochGrantOptions, MemberEpochGrant, HostMemberEpochDeskOptions, MemberEpochRequestOptions, MemberEpochSource, } from './member-epoch.js';
package/dist/index.js CHANGED
@@ -5,19 +5,21 @@ export { verifyEventUncached, boundedEventVerifier } from './verify.js';
5
5
  export { localIdentity } from './identity.js';
6
6
  export { KINDS } from './kinds.js';
7
7
  export { createDeviceCredential, verifyDeviceCredential, PERSON_CREDENTIAL_MAX_SECONDS, RestampedCredentialExpiryError, } from './credential.js';
8
- export { SEAL_TAG, isSealPubkey, generateSealKey, credentialSeal, sealTarget, sealTo, openSealed, newerCredential, } from './seal.js';
8
+ export { SEAL_TAG, SENDER_TAG, sealSender, isSealPubkey, generateSealKey, credentialSeal, sealTarget, sealTo, openSealed, newerCredential, } from './seal.js';
9
9
  export { deriveScoped, SCOPED_LABEL_PATTERN } from './scoped.js';
10
10
  export { createSubKeyCertificate, verifySubKeyCertificate, SUB_KEY_CERTIFICATE_SCOPE, } from './sub-cert.js';
11
11
  export { generateRoomSecret, deriveRoom, encodeJoinUrl, decodeJoinUrl, parseRoomPolicy, ROOM_LABELS, } from './room.js';
12
12
  export { MAX_RELAY_HINTS, MAX_ICE_HINTS, MAX_NETWORK_HINT_LENGTH, isSafeRelayUrl, safeRelayUrls, isSafeIceUrl, safeIceUrls, assertNetworkHintBounds, } from './network-hints.js';
13
13
  export { sanitiseDisplayName, MAX_DISPLAY_NAME_LENGTH } from './display-name.js';
14
14
  export { issueKindredProof, evaluateAccess, ACCESS_LABELS, } from './access.js';
15
- export { INVITATION_DELEGATION_TTL_SECONDS, MAX_INVITATION_DELEGATION_DEPTH, createRoomInvitation, roomInvitation, deriveInvitationId, encodeInvitationRequest, decodeInvitationRequest, verifyInvitationDelegation, encodeInvitationGrant, decodeRoomAdmissionGrant, decodeInvitationGrant, ROOM_ENDED_MESSAGE, encodeInvitationRetirement, decodeInvitationRetirement, decodeInvitationRetirementNotice, retirementError, hostRoomInvitation, requestRoomAdmissionCapability, requestRoomAdmission, INVITATION_LABELS, } from './invitation.js';
15
+ export { INVITATION_DELEGATION_TTL_SECONDS, MAX_INVITATION_DELEGATION_DEPTH, createRoomInvitation, roomInvitation, deriveInvitationId, encodeInvitationAccountProof, encodeInvitationRequest, decodeInvitationRequest, verifyInvitationDelegation, encodeInvitationGrant, decodeRoomAdmissionGrant, decodeInvitationGrant, ROOM_ENDED_MESSAGE, encodeInvitationRetirement, decodeInvitationRetirement, decodeInvitationRetirementNotice, retirementError, hostRoomInvitation, requestRoomAdmissionCapability, requestRoomAdmission, INVITATION_LABELS, } from './invitation.js';
16
+ export { encodeInvitationDecline, decodeInvitationDecline, InvitationDeclinedError } from './invitation-decline.js';
16
17
  export { encodePersistentInvitation, decodePersistentInvitation, requestPersistentRoomAdmission, PERSISTENT_INVITATION_LABELS, } from './persistent-invitation.js';
17
18
  export { withExpiration, isRoomEnds, requireRoomEnds, MAX_ROOM_ENDS_SECONDS } from './expiration.js';
18
19
  export { isInvitationRelays, requireInvitationRelays, MAX_INVITATION_RELAYS } from './invitation-relays.js';
19
20
  export { MAX_ROOM_LINK_FRAGMENT_LENGTH, parseRoomLink, encodeRoomLink, } from './link.js';
20
21
  export { EPOCH_ID_INFO, EPOCH_KEY_INFO, MAX_EPOCH, EPOCH_REQUEST_KEY_INFO, generateEpochSecret, deriveEpoch, encodeRekeyEvent, peekRekeyEvent, readMemberList, REPORT_UNKNOWN_EVERY_SECONDS, decodeRekeyEvent, HISTORY_WINDOW_SECONDS, MAX_HISTORY_EPOCHS, epochsInWindow, deriveEpochRequestKey, epochRequestAdmission, encodeEpochRequest, decodeEpochRequest, encodeEpochGrant, decodeEpochGrant, hostRoomEpoch, sealCredential, EpochRefusedError, requestRoomEpoch, canonicalAdmins, CHANNEL_NAME, RESERVED_CHANNELS, canonicalChannels, signChannels, verifyChannels, signAdmins, verifyAdmins, EPOCH_LABELS, } from './epoch.js';
22
+ export { DEFAULT_REPLY_DELAY_MS, REFUSE_AGAIN_AFTER_SECONDS, MAX_REFUSALS_PER_MINUTE, REFUSAL_LIMITER_CAPACITY, RefusalLimiter, replyDelay, } from './quiet-reply.js';
21
23
  export { EPOCH_COMMIT_PREFIX, epochCommitment, EPOCH_COMMIT_LABELS } from './epoch-commit.js';
22
24
  export { MEMBER_EPOCH_KINDS, MEMBER_EPOCH_REQUEST_KEY_INFO, MAX_MEMBER_EPOCH_CHAIN, deriveMemberEpochRequestKey, readRekeyEvidence, encodeMemberEpochRequest, decodeMemberEpochRequest, encodeMemberEpochGrant, decodeMemberEpochGrant, hostMemberEpochDesk, memberEpochSource, requestMemberEpoch, MEMBER_EPOCH_LABELS, } from './member-epoch.js';
23
25
  export { deriveChannel, CHANNEL_ID_INFO, CHANNEL_KEY_INFO, MAX_CHANNEL_NAME_LENGTH, CHANNEL_LABELS } from './channel.js';
@@ -0,0 +1,26 @@
1
+ import { type Event } from 'nostr-tools/pure';
2
+ import type { DecodeInvitationGrantOptions, InvitationDelegation, RoomInvitation } from './invitation.js';
3
+ export interface EncodeInvitationDeclineOptions {
4
+ invitation: RoomInvitation;
5
+ inviterSk: Uint8Array;
6
+ requester: string;
7
+ request: string;
8
+ now: number;
9
+ /** Root-to-responder chain; empty only for the pinned root inviter. */
10
+ delegation?: InvitationDelegation[];
11
+ }
12
+ export interface InvitationDecline {
13
+ request: string;
14
+ responder: string;
15
+ }
16
+ export declare class InvitationDeclinedError extends Error {
17
+ constructor();
18
+ }
19
+ /** A private refusal, carrying no room secret or new responder delegation.
20
+ * Version 3 distinguishes it from version-2 grants on the same reply kind.
21
+ * Older readers ignore it and continue their existing bounded wait. */
22
+ export declare function encodeInvitationDecline(opts: EncodeInvitationDeclineOptions): Event;
23
+ /** Only a fresh, request-bound refusal from the pinned root or a currently
24
+ * delegated responder can stop this guest's wait. A bearer holder has no
25
+ * authority to refuse someone else. No room capability is returned. */
26
+ export declare function decodeInvitationDecline(event: Event, opts: DecodeInvitationGrantOptions): InvitationDecline | null;
@@ -0,0 +1,74 @@
1
+ import { nip44 } from 'nostr-tools';
2
+ import { finalizeEvent, getPublicKey } from 'nostr-tools/pure';
3
+ import { hexEquals, normaliseHex } from './hex.js';
4
+ import { KINDS } from './kinds.js';
5
+ import { deriveInvitationId, verifyInvitationDelegation } from './invitation.js';
6
+ import { verifyEventUncached } from './verify.js';
7
+ export class InvitationDeclinedError extends Error {
8
+ constructor() {
9
+ super('Someone in the room declined your request to join.');
10
+ this.name = 'InvitationDeclinedError';
11
+ }
12
+ }
13
+ /** A private refusal, carrying no room secret or new responder delegation.
14
+ * Version 3 distinguishes it from version-2 grants on the same reply kind.
15
+ * Older readers ignore it and continue their existing bounded wait. */
16
+ export function encodeInvitationDecline(opts) {
17
+ if (opts.inviterSk.length !== 32)
18
+ throw new Error('inviter secret key must be 32 bytes');
19
+ if (!Number.isSafeInteger(opts.now) || opts.now < 0)
20
+ throw new Error('invalid invitation decline time');
21
+ if (!/^[0-9a-f]{64}$/i.test(opts.requester) || !/^[0-9a-f]{64}$/i.test(opts.request)) {
22
+ throw new Error('request and requester must be 32-byte hex');
23
+ }
24
+ const responder = getPublicKey(opts.inviterSk);
25
+ const delegation = opts.delegation ?? [];
26
+ const authority = verifyInvitationDelegation(opts.invitation, delegation, opts.now);
27
+ if (authority === null || !hexEquals(authority, responder)) {
28
+ throw new Error('responder is not delegated for invitation');
29
+ }
30
+ const requester = normaliseHex(opts.requester);
31
+ return finalizeEvent({
32
+ kind: KINDS.INVITATION_GRANT,
33
+ created_at: opts.now,
34
+ tags: [['d', deriveInvitationId(opts.invitation)], ['p', requester]],
35
+ content: nip44.v2.encrypt(JSON.stringify({
36
+ v: 3, decision: 'declined', request: normaliseHex(opts.request), delegation,
37
+ }), nip44.v2.utils.getConversationKey(opts.inviterSk, requester)),
38
+ }, opts.inviterSk);
39
+ }
40
+ /** Only a fresh, request-bound refusal from the pinned root or a currently
41
+ * delegated responder can stop this guest's wait. A bearer holder has no
42
+ * authority to refuse someone else. No room capability is returned. */
43
+ export function decodeInvitationDecline(event, opts) {
44
+ try {
45
+ const age = opts.maxAgeSeconds ?? 90;
46
+ if (!Number.isSafeInteger(opts.now) || opts.now < 0 || !Number.isSafeInteger(age) || age < 0)
47
+ return null;
48
+ if (event.kind !== KINDS.INVITATION_GRANT || !verifyEventUncached(event))
49
+ return null;
50
+ if (!Number.isSafeInteger(event.created_at) || event.created_at < 0 || Math.abs(opts.now - event.created_at) > age)
51
+ return null;
52
+ const rendezvous = event.tags.filter(t => t[0] === 'd');
53
+ const addressed = event.tags.filter(t => t[0] === 'p');
54
+ if (rendezvous.length !== 1 || rendezvous[0]?.[1] !== deriveInvitationId(opts.invitation))
55
+ return null;
56
+ const requester = getPublicKey(opts.requesterSk);
57
+ if (addressed.length !== 1 || !hexEquals(addressed[0]?.[1] ?? '', requester))
58
+ return null;
59
+ const body = JSON.parse(nip44.v2.decrypt(event.content, nip44.v2.utils.getConversationKey(opts.requesterSk, event.pubkey)));
60
+ if (!body || body.v !== 3 || body.decision !== 'declined')
61
+ return null;
62
+ if (typeof body.request !== 'string' || !/^[0-9a-f]{64}$/i.test(body.request) || !hexEquals(body.request, opts.request))
63
+ return null;
64
+ if ('secret' in body || !Array.isArray(body.delegation))
65
+ return null;
66
+ const authority = verifyInvitationDelegation(opts.invitation, body.delegation, opts.now);
67
+ if (authority === null || !hexEquals(authority, event.pubkey))
68
+ return null;
69
+ return { request: normaliseHex(body.request), responder: normaliseHex(event.pubkey) };
70
+ }
71
+ catch {
72
+ return null;
73
+ }
74
+ }
@@ -1,5 +1,7 @@
1
1
  import { type Event } from 'nostr-tools/pure';
2
2
  import type { RelayTransport } from './transport.js';
3
+ import type { ParticipantIdentity } from './identity.js';
4
+ import { type ReplyDelayRange, type ReplySchedule } from './quiet-reply.js';
3
5
  /** A delegated responder cannot silently make its authority permanent. */
4
6
  export declare const INVITATION_DELEGATION_TTL_SECONDS: number;
5
7
  /** Bounds both verification work and the size of a grant from a hostile peer. */
@@ -73,13 +75,31 @@ export interface EncodeInvitationRequestOptions {
73
75
  now: number;
74
76
  name?: string;
75
77
  participant?: string;
78
+ /** Account-signed proof bound to this invitation, request device and time.
79
+ * The proof stays inside the bearer-encrypted request, never a public relay
80
+ * event. Without it, `participant` remains an unverified claim. */
81
+ accountProof?: Event;
76
82
  }
83
+ export interface EncodeInvitationAccountProofOptions {
84
+ invitation: RoomInvitation;
85
+ device: string;
86
+ identity: ParticipantIdentity;
87
+ now: number;
88
+ }
89
+ /** Prove control of an account for one ephemeral admission device. This is
90
+ * deliberately separate from a room device credential: a guest does not yet
91
+ * know the room or its traffic key, and this proof grants neither. */
92
+ export declare function encodeInvitationAccountProof(opts: EncodeInvitationAccountProofOptions): Promise<Event>;
77
93
  /** Who is asking, as decoded from a request. */
78
94
  export interface InvitationRequest {
79
95
  device: string;
80
96
  request: string;
81
97
  name?: string;
82
98
  participant?: string;
99
+ /** Present only after fresh signature verification of an account proof
100
+ * bound to this exact invitation, request-signing device and timestamp.
101
+ * Never authorise automatic admission from `participant` alone. */
102
+ verifiedParticipant?: string;
83
103
  }
84
104
  /** Prove possession of the bearer without putting it, or a traffic key, on a relay. */
85
105
  export declare function encodeInvitationRequest(opts: EncodeInvitationRequestOptions): Event;
@@ -144,7 +164,8 @@ export interface HostRoomInvitationOptions {
144
164
  onAdmitted?: (device: string) => void;
145
165
  /** The same publication acknowledgement, correlated to the request. */
146
166
  onGrantPublished?: (request: InvitationRequest) => void;
147
- /** Publication rejected or threw. No admission callback is made. */
167
+ /** A publication attempt failed, or approval came after request expiry.
168
+ * A valid retry may recover; no admission callback follows a failed send. */
148
169
  onGrantFailed?: (request: InvitationRequest, error: unknown) => void;
149
170
  /** Called when the creator's durable retirement tombstone is heard. */
150
171
  onRetired?: () => void;
@@ -152,7 +173,7 @@ export interface HostRoomInvitationOptions {
152
173
  * moves. Omit to say nothing, which a joiner treats as unknown. */
153
174
  epoch?: () => number;
154
175
  /**
155
- * Asked before every grant, when present. Return true to let the
176
+ * Asked once per fresh signed request, when present. Return true to let the
156
177
  * request in, false to leave it unanswered: there is no refusal on the
157
178
  * wire, so a declined person sees the room not answer, which is the same
158
179
  * as nobody being home. A request is asked about once, whatever its
@@ -161,6 +182,30 @@ export interface HostRoomInvitationOptions {
161
182
  * room's link has always meant.
162
183
  */
163
184
  admit?: (request: InvitationRequest) => boolean | Promise<boolean>;
185
+ /**
186
+ * Wait a random time in this range, in milliseconds, before publishing
187
+ * each grant, after `admit` when there is one. Absent, a grant goes out
188
+ * as soon as it is decided, as it always has (or after
189
+ * `DEFAULT_REPLY_DELAY_MS` when `coordinate` is set). For a device that
190
+ * answers automatically: an instant answer under the same key tells
191
+ * whoever holds the link when that device is online.
192
+ */
193
+ grantDelayMs?: ReplyDelayRange;
194
+ /**
195
+ * Several of the room's devices answer the same link: wait first, and
196
+ * stand down if another responder's grant to the same requester appears
197
+ * during the wait, so normally one device answers. Waits
198
+ * `grantDelayMs`, default `[500, 2000]`. A grant is seen by its public
199
+ * tags only, so anyone holding the link could post a false one; this
200
+ * responder stands down at most once per request, and answers the
201
+ * requester's next retry. Absent or false, nothing changes and no extra
202
+ * subscription is opened.
203
+ */
204
+ coordinate?: boolean;
205
+ /** For tests: a source of numbers in [0, 1). Default `Math.random`. */
206
+ random?: () => number;
207
+ /** For tests: how the wait is timed. Default `setTimeout`. */
208
+ schedule?: ReplySchedule;
164
209
  }
165
210
  export interface EncodeInvitationRetirementOptions {
166
211
  invitation: RoomInvitation;
@@ -219,10 +264,15 @@ export interface RequestRoomAdmissionOptions {
219
264
  /** Carried in the request for a host who asks before letting people in. */
220
265
  name?: string;
221
266
  participant?: string;
267
+ /** Optional proof of the claimed account, made by this matching identity.
268
+ * A signer error is a failed request, never a switch to another account. */
269
+ identity?: ParticipantIdentity;
270
+ signal?: AbortSignal;
222
271
  }
223
- /** Resolve the room and a bounded responder delegation, with no account or
224
- * prompt. Retaining the delegation is what removes the creator as an
225
- * availability dependency for the next arrival. */
272
+ /** Resolve the room and a bounded responder delegation. Anonymous requests
273
+ * need no account. Supplying an identity signs a proof for this request; its
274
+ * signer may ask the person to approve. Retaining the delegation removes the
275
+ * creator as an availability dependency for the next arrival. */
226
276
  export declare function requestRoomAdmissionCapability(opts: RequestRoomAdmissionOptions): Promise<RoomAdmission>;
227
277
  /** Compatibility wrapper for non-interactive consumers. It joins correctly,
228
278
  * but discards the ability to keep the link available for somebody else. */
@@ -231,4 +281,4 @@ export declare function requestRoomAdmission(opts: RequestRoomAdmissionOptions):
231
281
  * `src/labels.test.ts`, which checks each module against its own exported
232
282
  * list rather than scanning file text for matching comments. Pure data -
233
283
  * adding this export changes no runtime behaviour. */
234
- export declare const INVITATION_LABELS: readonly ["kithmoot/v2/invitation-delegation:", "kithmoot/v2/invitation-id", "kithmoot/v2/invitation-request-key"];
284
+ export declare const INVITATION_LABELS: readonly ["kithmoot/v2/invitation-account-proof", "kithmoot/v2/invitation-delegation:", "kithmoot/v2/invitation-id", "kithmoot/v2/invitation-request-key"];