@tinycloud/share-sdk 1.2.0-beta.3 → 1.2.0-beta.5
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/addressed-publish-BnSBJ-MX.d.ts +242 -0
- package/dist/addressed-publish-DtcLNG2m.d.cts +242 -0
- package/dist/artifact.cjs +88 -13
- package/dist/artifact.cjs.map +1 -1
- package/dist/artifact.d.cts +28 -8
- package/dist/artifact.d.ts +28 -8
- package/dist/artifact.js +84 -14
- package/dist/artifact.js.map +1 -1
- package/dist/history-CUWDK0lE.d.cts +180 -0
- package/dist/history-CyT6x8h4.d.ts +180 -0
- package/dist/index.cjs +128 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +93 -154
- package/dist/index.d.ts +93 -154
- package/dist/index.js +123 -4
- package/dist/index.js.map +1 -1
- package/dist/owner-policy-BqzRlkb6.d.cts +297 -0
- package/dist/owner-policy-BqzRlkb6.d.ts +297 -0
- package/dist/share-index.cjs +8714 -0
- package/dist/share-index.cjs.map +1 -0
- package/dist/share-index.d.cts +1063 -0
- package/dist/share-index.d.ts +1063 -0
- package/dist/share-index.js +8642 -0
- package/dist/share-index.js.map +1 -0
- package/dist/share-root.cjs +23 -1
- package/dist/share-root.cjs.map +1 -1
- package/dist/share-root.d.cts +2 -1
- package/dist/share-root.d.ts +2 -1
- package/dist/share-root.js +23 -1
- package/dist/share-root.js.map +1 -1
- package/package.json +8 -2
- package/dist/addressed-publish-CsUS7-SI.d.cts +0 -535
- package/dist/addressed-publish-CsUS7-SI.d.ts +0 -535
|
@@ -0,0 +1,1063 @@
|
|
|
1
|
+
import { a as SenderShareRecordStorage, S as SenderShareRecord } from './history-CUWDK0lE.cjs';
|
|
2
|
+
export { f as SenderShareRecordProofs } from './history-CUWDK0lE.cjs';
|
|
3
|
+
import { j as PublishedShareDeliveryMaterial, q as SignedDelegation, g as OwnerSharePolicyRegistration } from './owner-policy-BqzRlkb6.cjs';
|
|
4
|
+
import { ShareEnvelopeV3 } from '@tinycloud/share-envelope';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Identifiers and the key classifier for the shared share index
|
|
8
|
+
* (TC-1432 design C §1). All keys here are relative to the vault prefix
|
|
9
|
+
* `sender-history/v2/records/`.
|
|
10
|
+
*/
|
|
11
|
+
/** Vault key prefix of every share record and of the index documents. */
|
|
12
|
+
declare const SHARE_RECORDS_VAULT_PREFIX = "sender-history/v2/records/";
|
|
13
|
+
/** The main index document key. */
|
|
14
|
+
declare const INDEX_MAIN_KEY = "_index/main";
|
|
15
|
+
/** Length of a DID-derived agent id (132 bits of base64url). */
|
|
16
|
+
declare const AGENT_ID_LENGTH = 22;
|
|
17
|
+
/** `^[A-Za-z0-9_-]{1,512}$`, excluding the reserved first segments `_index` and `agents`. */
|
|
18
|
+
declare function isShareId(value: unknown): value is string;
|
|
19
|
+
declare function isAgentId(value: unknown): value is string;
|
|
20
|
+
/**
|
|
21
|
+
* The first 22 base64url characters of
|
|
22
|
+
* `sha256("xyz.tinycloud.share/agent-id/v1|" + agentDid)`. `agentDid` is the
|
|
23
|
+
* DID of the key that signs the agent's invocations and delegations, so a new
|
|
24
|
+
* key gets a new prefix.
|
|
25
|
+
*/
|
|
26
|
+
declare function agentIdFromDid(agentDid: string): string;
|
|
27
|
+
declare function agentRecordKey(agentId: string, shareId: string): string;
|
|
28
|
+
/** Explicit list prefix (with the trailing slash) of one agent's records, relative to `records/`. */
|
|
29
|
+
declare function agentRecordPrefix(agentId: string): string;
|
|
30
|
+
type ClassifiedRecordKey = {
|
|
31
|
+
readonly kind: "index";
|
|
32
|
+
readonly name: string;
|
|
33
|
+
} | {
|
|
34
|
+
readonly kind: "web";
|
|
35
|
+
readonly shareId: string;
|
|
36
|
+
} | {
|
|
37
|
+
readonly kind: "agent";
|
|
38
|
+
readonly agentId: string;
|
|
39
|
+
readonly shareId: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Never fetched, never rendered. `agentId`/`suffix` are set when the key
|
|
43
|
+
* lies inside an agent prefix (`agents/<valid id>/…`), so it is counted
|
|
44
|
+
* once against that agent; any other key can only be written by owner
|
|
45
|
+
* clients and is skipped without counting.
|
|
46
|
+
*/
|
|
47
|
+
| {
|
|
48
|
+
readonly kind: "rejected";
|
|
49
|
+
readonly agentId?: string;
|
|
50
|
+
readonly suffix?: string;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Classify one raw listed key (relative to `records/`), before any
|
|
54
|
+
* needs-attention logic. A key containing `%`, `\`, a `.`/`..` segment, an
|
|
55
|
+
* empty segment or a leading `/` is rejected first.
|
|
56
|
+
*/
|
|
57
|
+
declare function classifyRecordKey(key: string): ClassifiedRecordKey;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Share link validator (design C §5 check 6, §6 Open/Copy). A link is
|
|
61
|
+
* accepted only when it is https on a configured share origin and has one of
|
|
62
|
+
* the share link shapes:
|
|
63
|
+
* - `/s/<cid>#k=<key>`: registry envelope link;
|
|
64
|
+
* - `/s/inline#v=2&p=<payload>`: Node Policy/v3 sealed-inline link (what
|
|
65
|
+
* `publishAddressedShare` emits);
|
|
66
|
+
* - `/viewer#tc1=<token>`: native bearer link (`createNativeShare`).
|
|
67
|
+
*
|
|
68
|
+
* The result names the shape only; the link itself is never copied into it.
|
|
69
|
+
*/
|
|
70
|
+
type ShareLinkShape = "envelope" | "inline" | "native";
|
|
71
|
+
type ShareLinkCheck = {
|
|
72
|
+
readonly ok: true;
|
|
73
|
+
readonly shape: ShareLinkShape;
|
|
74
|
+
} | {
|
|
75
|
+
readonly ok: false;
|
|
76
|
+
};
|
|
77
|
+
declare function validateShareLink(link: unknown, shareOrigins: readonly string[]): ShareLinkCheck;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* The agent's key-encryption key (design C §3, V3-6). Security-sensitive:
|
|
81
|
+
* keep this module small and free of logging.
|
|
82
|
+
*
|
|
83
|
+
* KEK_a = HKDF-SHA256(ikm = private key bytes,
|
|
84
|
+
* salt = "xyz.tinycloud.share/agent-kek/v1",
|
|
85
|
+
* info = agentDid)
|
|
86
|
+
* kid = HKDF-SHA256(same ikm and salt, info = "kid")[0..8]
|
|
87
|
+
*
|
|
88
|
+
* The private key is the one the agent signs its invocations and delegations
|
|
89
|
+
* with (the session key when it has a private part, otherwise the profile
|
|
90
|
+
* key), and `agentDid` is that key's DID. KEK_a is imported non-extractable,
|
|
91
|
+
* for AES-GCM wrapping only.
|
|
92
|
+
*/
|
|
93
|
+
interface AgentKeyMaterial {
|
|
94
|
+
readonly agentDid: string;
|
|
95
|
+
/** base64url of the first 8 bytes of HKDF(…, info "kid"). */
|
|
96
|
+
readonly kid: string;
|
|
97
|
+
readonly kek: CryptoKey;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Derive KEK_a and kid. `privateKeyBytes` is read, never retained; the caller
|
|
101
|
+
* owns (and should zero) it.
|
|
102
|
+
*/
|
|
103
|
+
declare function deriveAgentKeyMaterial(privateKeyBytes: Uint8Array, agentDid: string): Promise<AgentKeyMaterial>;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Agent record codec: the double-wrapped data key (design C §3, R1, V3-3..6).
|
|
107
|
+
* Security-sensitive: keep this module small; nothing here logs, and no
|
|
108
|
+
* error carries key bytes.
|
|
109
|
+
*
|
|
110
|
+
* One stored value per record, `vault/…/records/agents/<agentId>/<shareId>`:
|
|
111
|
+
*
|
|
112
|
+
* { hdr: { v: 1, agentDid, kid, alg: "A256GCM", ownerNetworkId, recordV },
|
|
113
|
+
* ct: b64url(iv ‖ AES-256-GCM(encKey, record, aad = B)),
|
|
114
|
+
* commit: b64url(HMAC-SHA256(commitKey, B)),
|
|
115
|
+
* wrapAgent: b64url(iv ‖ AES-256-GCM(KEK_a, DEK, aad = B)) | null,
|
|
116
|
+
* wrapOwner: owner-network envelope of DEK with aad = B }
|
|
117
|
+
*
|
|
118
|
+
* B = "xyz.tinycloud.share/agent-record/v1|" + spaceId + "|" + vaultKey
|
|
119
|
+
* + "|" + agentDid + "|" + ownerNetworkId (EVM addresses lowercased)
|
|
120
|
+
* encKey = HKDF-SHA256(DEK, info "enc|" + B)
|
|
121
|
+
* commitKey = HKDF-SHA256(DEK, info "commit|" + B)
|
|
122
|
+
*
|
|
123
|
+
* Every seal takes a fresh random 32-byte DEK and fresh random 96-bit nonces.
|
|
124
|
+
* The DEK itself is never used as a key. Opening requires the unwrapped DEK
|
|
125
|
+
* to be exactly 32 bytes, checks `commit` in constant time, and zeroes the
|
|
126
|
+
* DEK on every path.
|
|
127
|
+
*/
|
|
128
|
+
declare const AGENT_RECORD_VERSION = 1;
|
|
129
|
+
/** Record schema versions this build understands. */
|
|
130
|
+
declare const SUPPORTED_AGENT_RECORD_V = 1;
|
|
131
|
+
/**
|
|
132
|
+
* Stored agent records larger than this are refused before any crypto.
|
|
133
|
+
* Design C proposed 16 KiB (open decision 1); a real CLI bearer record that
|
|
134
|
+
* carries its link and its full chain (C1: link UCAN + owner→session CACAO)
|
|
135
|
+
* measured 16,918 B on a local node, so the cap is 32 KiB.
|
|
136
|
+
*/
|
|
137
|
+
declare const MAX_AGENT_RECORD_BYTES: number;
|
|
138
|
+
type AgentRecordFailure = "size" | "shape" | "header" | "newer" | "decrypt" | "commit";
|
|
139
|
+
/** A refused agent record. The message is fixed per reason. */
|
|
140
|
+
declare class AgentRecordError extends Error {
|
|
141
|
+
readonly reason: AgentRecordFailure;
|
|
142
|
+
constructor(reason: AgentRecordFailure);
|
|
143
|
+
}
|
|
144
|
+
/** Thrown by an {@link OwnerNetworkUnwrap} when the decrypt service is unreachable (not a refusal). */
|
|
145
|
+
declare class OwnerUnwrapUnavailableError extends Error {
|
|
146
|
+
constructor();
|
|
147
|
+
}
|
|
148
|
+
interface AgentRecordHeader {
|
|
149
|
+
readonly v: 1;
|
|
150
|
+
readonly agentDid: string;
|
|
151
|
+
readonly kid: string | null;
|
|
152
|
+
readonly alg: "A256GCM";
|
|
153
|
+
readonly ownerNetworkId: string;
|
|
154
|
+
readonly recordV: number;
|
|
155
|
+
}
|
|
156
|
+
interface StoredAgentRecord {
|
|
157
|
+
readonly hdr: AgentRecordHeader;
|
|
158
|
+
readonly ct: string;
|
|
159
|
+
readonly commit: string;
|
|
160
|
+
readonly wrapAgent: string | null;
|
|
161
|
+
readonly wrapOwner: Readonly<Record<string, unknown>>;
|
|
162
|
+
}
|
|
163
|
+
/** Encrypts the DEK to the owner network (needs no capability). */
|
|
164
|
+
interface OwnerNetworkWrap {
|
|
165
|
+
wrap(dek: Uint8Array, aad: Uint8Array): Promise<Readonly<Record<string, unknown>>>;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Network-decrypts the owner wrap. Implementations must pass `aad` to the
|
|
169
|
+
* decrypt call so the envelope's declared AAD is compared before any POST.
|
|
170
|
+
*/
|
|
171
|
+
interface OwnerNetworkUnwrap {
|
|
172
|
+
unwrap(envelope: Readonly<Record<string, unknown>>, aad: Uint8Array): Promise<Uint8Array>;
|
|
173
|
+
}
|
|
174
|
+
interface AgentRecordBindingInput {
|
|
175
|
+
readonly spaceId: string;
|
|
176
|
+
/** Full vault key: `sender-history/v2/records/agents/<agentId>/<shareId>`. */
|
|
177
|
+
readonly vaultKey: string;
|
|
178
|
+
readonly agentDid: string;
|
|
179
|
+
readonly ownerNetworkId: string;
|
|
180
|
+
}
|
|
181
|
+
declare function agentRecordBinding(input: AgentRecordBindingInput): Uint8Array;
|
|
182
|
+
interface SealAgentRecordInput extends AgentRecordBindingInput {
|
|
183
|
+
/** UTF-8 JSON of the full `SenderShareRecord` (link and `proofs` included). */
|
|
184
|
+
readonly plaintext: Uint8Array;
|
|
185
|
+
/** Absent for a remote-signer-only profile: the record is then owner-readable only (`kid: null`). */
|
|
186
|
+
readonly agentKey?: AgentKeyMaterial;
|
|
187
|
+
readonly ownerWrap: OwnerNetworkWrap;
|
|
188
|
+
readonly recordV?: number;
|
|
189
|
+
}
|
|
190
|
+
/** Seal one agent record. Each call draws a fresh DEK and fresh nonces. */
|
|
191
|
+
declare function sealAgentRecord(input: SealAgentRecordInput): Promise<StoredAgentRecord>;
|
|
192
|
+
/**
|
|
193
|
+
* Parse the stored bytes and check the header against the path (§5 checks
|
|
194
|
+
* 2–3), before any crypto. `newer` means a higher `recordV` than this build
|
|
195
|
+
* knows: skip and re-check after an upgrade, do not reject.
|
|
196
|
+
*/
|
|
197
|
+
declare function parseStoredAgentRecord(bytes: Uint8Array, expected: {
|
|
198
|
+
readonly agentDid?: string;
|
|
199
|
+
readonly ownerNetworkId: string;
|
|
200
|
+
}): StoredAgentRecord;
|
|
201
|
+
/**
|
|
202
|
+
* Owner path (§3 steps 2–4): refuse locally, before any network call, an
|
|
203
|
+
* owner wrap whose declared AAD is not exactly B or whose network is not the
|
|
204
|
+
* owner's; then network-unwrap, and open.
|
|
205
|
+
*/
|
|
206
|
+
declare function openAgentRecordAsOwner(record: StoredAgentRecord, location: {
|
|
207
|
+
readonly spaceId: string;
|
|
208
|
+
readonly vaultKey: string;
|
|
209
|
+
}, unwrap: OwnerNetworkUnwrap): Promise<Uint8Array>;
|
|
210
|
+
/** Agent read-back: `wrapAgent` under KEK_a; no owner-network decrypt anywhere. */
|
|
211
|
+
declare function openAgentRecordAsAgent(record: StoredAgentRecord, location: {
|
|
212
|
+
readonly spaceId: string;
|
|
213
|
+
readonly vaultKey: string;
|
|
214
|
+
}, agentKey: AgentKeyMaterial): Promise<Uint8Array>;
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Storage port of the share index (design C §1, §4). Every key is relative to
|
|
218
|
+
* `sender-history/v2/records/`. The port is structural so share-sdk does not
|
|
219
|
+
* depend on the TinyCloud SDK packages; {@link createTinyCloudShareIndexBackend}
|
|
220
|
+
* adapts a TinyCloud client (node or web SDK) to it.
|
|
221
|
+
*/
|
|
222
|
+
type ShareDocumentRead = {
|
|
223
|
+
readonly status: "ok";
|
|
224
|
+
readonly value: unknown;
|
|
225
|
+
readonly etag: string;
|
|
226
|
+
} | {
|
|
227
|
+
readonly status: "not_found";
|
|
228
|
+
}
|
|
229
|
+
/** Deterministic corruption (bad envelope, AAD bound elsewhere, undecodable payload). */
|
|
230
|
+
| {
|
|
231
|
+
readonly status: "corrupt";
|
|
232
|
+
readonly etag?: string;
|
|
233
|
+
}
|
|
234
|
+
/** Outage or transient failure: never a reason to rebuild. */
|
|
235
|
+
| {
|
|
236
|
+
readonly status: "unavailable";
|
|
237
|
+
};
|
|
238
|
+
type ShareRawRead = {
|
|
239
|
+
readonly status: "ok";
|
|
240
|
+
readonly bytes: Uint8Array;
|
|
241
|
+
readonly etag: string;
|
|
242
|
+
} | {
|
|
243
|
+
readonly status: "not_found";
|
|
244
|
+
}
|
|
245
|
+
/** Larger than the `maxBytes` the caller passed: the node refused to send the body, or its length was over. */
|
|
246
|
+
| {
|
|
247
|
+
readonly status: "too_large";
|
|
248
|
+
} | {
|
|
249
|
+
readonly status: "unavailable";
|
|
250
|
+
};
|
|
251
|
+
type ShareWriteCondition = {
|
|
252
|
+
readonly ifMatch: string;
|
|
253
|
+
} | {
|
|
254
|
+
readonly ifNoneMatch: "*";
|
|
255
|
+
};
|
|
256
|
+
type ShareWriteResult = {
|
|
257
|
+
readonly ok: true;
|
|
258
|
+
} | {
|
|
259
|
+
readonly ok: false;
|
|
260
|
+
readonly code: "conflict" | "outcome_unknown" | "busy" | "unauthorized" | "failed";
|
|
261
|
+
}
|
|
262
|
+
/** The etag was refused as malformed (for example weakened to `W/"…"` in transit). Never retried; `message` is the SDK's own. */
|
|
263
|
+
| {
|
|
264
|
+
readonly ok: false;
|
|
265
|
+
readonly code: "invalid_etag";
|
|
266
|
+
readonly message: string;
|
|
267
|
+
};
|
|
268
|
+
type ShareListResult = {
|
|
269
|
+
readonly status: "ok";
|
|
270
|
+
readonly keys: readonly string[];
|
|
271
|
+
readonly cursor?: string;
|
|
272
|
+
} | {
|
|
273
|
+
readonly status: "unavailable";
|
|
274
|
+
};
|
|
275
|
+
interface ShareIndexBackend {
|
|
276
|
+
readonly spaceId: string;
|
|
277
|
+
readonly ownerNetworkId: string;
|
|
278
|
+
/** Owner-network vault read with the slice-1 AAD check, from the network (never a replica). */
|
|
279
|
+
readVault(key: string): Promise<ShareDocumentRead>;
|
|
280
|
+
/** Owner-network vault write: a fresh envelope each time; conditional when `condition` is set. */
|
|
281
|
+
writeVault(key: string, value: unknown, condition?: ShareWriteCondition): Promise<ShareWriteResult>;
|
|
282
|
+
/** Delete a record; an absent key counts as success. */
|
|
283
|
+
deleteRecord(key: string): Promise<ShareWriteResult>;
|
|
284
|
+
/** One page of keys under `prefix` (relative, with its trailing slash, or "" for all records). */
|
|
285
|
+
listKeys(prefix: string, cursor?: string): Promise<ShareListResult>;
|
|
286
|
+
/**
|
|
287
|
+
* Raw stored bytes and etag (agent records), from the network. With
|
|
288
|
+
* `maxBytes`, a larger value is reported `too_large` and its body is not
|
|
289
|
+
* downloaded (see {@link createTinyCloudShareIndexBackend}).
|
|
290
|
+
*/
|
|
291
|
+
readRaw(key: string, maxBytes?: number): Promise<ShareRawRead>;
|
|
292
|
+
writeRaw(key: string, value: Readonly<Record<string, unknown>>, condition: ShareWriteCondition): Promise<ShareWriteResult>;
|
|
293
|
+
readonly ownerWrap: OwnerNetworkWrap;
|
|
294
|
+
/** Owner-network decrypt; absent for Tier W agents, which have no decrypt grant. */
|
|
295
|
+
readonly ownerUnwrap?: OwnerNetworkUnwrap;
|
|
296
|
+
}
|
|
297
|
+
/** The vault's classified network read (`readNetworkEncrypted`), as this adapter consumes it. */
|
|
298
|
+
interface VaultNetworkRead {
|
|
299
|
+
readonly status: string;
|
|
300
|
+
readonly entry?: {
|
|
301
|
+
readonly value: unknown;
|
|
302
|
+
readonly etag?: string;
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
type SdkResult<T> = {
|
|
306
|
+
readonly ok: true;
|
|
307
|
+
readonly data: T;
|
|
308
|
+
} | {
|
|
309
|
+
readonly ok: false;
|
|
310
|
+
readonly error: {
|
|
311
|
+
readonly code: string;
|
|
312
|
+
readonly message?: string;
|
|
313
|
+
readonly meta?: Record<string, unknown>;
|
|
314
|
+
};
|
|
315
|
+
};
|
|
316
|
+
/** The subset of a TinyCloud client the adapter uses (node-sdk `TinyCloudNode` or the web SDK). */
|
|
317
|
+
interface TinyCloudShareIndexClient {
|
|
318
|
+
readonly vault: {
|
|
319
|
+
readNetworkEncrypted(key: string, options: {
|
|
320
|
+
readonly expectAad: true;
|
|
321
|
+
}): Promise<VaultNetworkRead>;
|
|
322
|
+
put(key: string, value: unknown, options?: {
|
|
323
|
+
readonly ifMatch?: string;
|
|
324
|
+
readonly ifNoneMatch?: "*";
|
|
325
|
+
}): Promise<SdkResult<unknown>>;
|
|
326
|
+
delete(key: string): Promise<SdkResult<unknown>>;
|
|
327
|
+
};
|
|
328
|
+
readonly kv: {
|
|
329
|
+
/** `maxResponseBytes`: the node refuses (413, `KV_RESPONSE_TOO_LARGE`) a larger value before sending its body. */
|
|
330
|
+
get(key: string, options: {
|
|
331
|
+
readonly prefix: "";
|
|
332
|
+
readonly raw: true;
|
|
333
|
+
readonly source: "network";
|
|
334
|
+
readonly maxResponseBytes?: number;
|
|
335
|
+
}): Promise<SdkResult<{
|
|
336
|
+
readonly data: unknown;
|
|
337
|
+
readonly headers: {
|
|
338
|
+
readonly etag?: string;
|
|
339
|
+
};
|
|
340
|
+
}>>;
|
|
341
|
+
put(key: string, value: unknown, options: {
|
|
342
|
+
readonly prefix: "";
|
|
343
|
+
readonly ifMatch?: string;
|
|
344
|
+
readonly ifNoneMatch?: "*";
|
|
345
|
+
}): Promise<SdkResult<unknown>>;
|
|
346
|
+
list(options: {
|
|
347
|
+
readonly prefix: string;
|
|
348
|
+
readonly removePrefix: true;
|
|
349
|
+
readonly limit: number;
|
|
350
|
+
readonly cursor?: string;
|
|
351
|
+
readonly source: "network";
|
|
352
|
+
}): Promise<SdkResult<{
|
|
353
|
+
readonly keys: readonly string[];
|
|
354
|
+
readonly nextCursor?: string;
|
|
355
|
+
readonly truncated?: boolean;
|
|
356
|
+
}>>;
|
|
357
|
+
};
|
|
358
|
+
readonly encryption: {
|
|
359
|
+
encryptToNetwork(networkId: string, plaintext: Uint8Array, options: {
|
|
360
|
+
readonly aad: Uint8Array;
|
|
361
|
+
}): Promise<SdkResult<object>>;
|
|
362
|
+
decryptEnvelope?(envelope: never, proof: {
|
|
363
|
+
readonly proofs: readonly string[];
|
|
364
|
+
}, options: {
|
|
365
|
+
readonly aad: Uint8Array;
|
|
366
|
+
}): Promise<SdkResult<Uint8Array>>;
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
/** Shown when the SDK reports `INVALID_ETAG` without a message of its own. */
|
|
370
|
+
declare const INVALID_ETAG_MESSAGE = "etag was weakened in transit; compare-and-swap unavailable through this path";
|
|
371
|
+
interface TinyCloudShareIndexBackendOptions {
|
|
372
|
+
readonly client: TinyCloudShareIndexClient;
|
|
373
|
+
readonly spaceId: string;
|
|
374
|
+
readonly ownerNetworkId: string;
|
|
375
|
+
/** The decrypt capability proof of the owner session (`{ proofs: [session.delegationCid] }`). Omit for Tier W agents. */
|
|
376
|
+
readonly decryptProof?: () => {
|
|
377
|
+
readonly proofs: readonly string[];
|
|
378
|
+
};
|
|
379
|
+
/**
|
|
380
|
+
* The KV prefix every key here sits under: `vault/sender-history/v2/records/`
|
|
381
|
+
* for a client whose KV service has no prefix of its own.
|
|
382
|
+
*/
|
|
383
|
+
readonly kvRecordsPrefix?: string;
|
|
384
|
+
}
|
|
385
|
+
/** Adapt a TinyCloud client (owner web, owner-key CLI, Tier 2 or Tier W agent) to {@link ShareIndexBackend}. */
|
|
386
|
+
declare function createTinyCloudShareIndexBackend(options: TinyCloudShareIndexBackendOptions): ShareIndexBackend;
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* The compare-and-swap loop policy shared by the index and the record stores
|
|
390
|
+
* (design C §4, plus the lead's rule for slice 2):
|
|
391
|
+
* - every attempt starts with a fresh network read and re-applies the change,
|
|
392
|
+
* so a lost race (`ETAG_MISMATCH`) and an unknown outcome (`OUTCOME_UNKNOWN`)
|
|
393
|
+
* are both decided from what the node now holds, never by a blind re-put;
|
|
394
|
+
* - `ETAG_MISMATCH` and `NODE_BUSY` back off 50 ms·2ⁿ with jitter, capped at
|
|
395
|
+
* 1 s, for at most 6 attempts;
|
|
396
|
+
* - `INVALID_ETAG` is never retried: the first one throws
|
|
397
|
+
* {@link ShareIndexCasError} with the SDK's own message (an ETag weakened
|
|
398
|
+
* in transit, for example by a CDN, cannot be used for compare-and-swap).
|
|
399
|
+
*/
|
|
400
|
+
interface CasPolicy {
|
|
401
|
+
readonly maxAttempts: number;
|
|
402
|
+
readonly backoffBaseMs: number;
|
|
403
|
+
readonly backoffCapMs: number;
|
|
404
|
+
readonly sleep: (ms: number) => Promise<void>;
|
|
405
|
+
readonly random: () => number;
|
|
406
|
+
}
|
|
407
|
+
declare const DEFAULT_CAS_POLICY: CasPolicy;
|
|
408
|
+
type ShareIndexCasErrorCode =
|
|
409
|
+
/** The etag was refused as malformed; compare-and-swap is unavailable through this path. Never retried. */
|
|
410
|
+
"INVALID_ETAG"
|
|
411
|
+
/** Every attempt lost a race or found the node busy. */
|
|
412
|
+
| "EXHAUSTED"
|
|
413
|
+
/** The write was refused (authorization, storage) or the read failed. */
|
|
414
|
+
| "FAILED";
|
|
415
|
+
declare class ShareIndexCasError extends Error {
|
|
416
|
+
readonly code: ShareIndexCasErrorCode;
|
|
417
|
+
readonly key: string;
|
|
418
|
+
readonly attempts: number;
|
|
419
|
+
constructor(code: ShareIndexCasErrorCode, message: string, key: string, attempts: number);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
declare class WebShareRecordStore implements SenderShareRecordStorage {
|
|
423
|
+
private readonly backend;
|
|
424
|
+
private readonly cas;
|
|
425
|
+
constructor(backend: ShareIndexBackend, cas?: CasPolicy);
|
|
426
|
+
put(record: SenderShareRecord): Promise<void>;
|
|
427
|
+
update(shareId: string, change: (record: SenderShareRecord) => SenderShareRecord | Promise<SenderShareRecord>): Promise<SenderShareRecord | undefined>;
|
|
428
|
+
get(shareId: string): Promise<SenderShareRecord | undefined>;
|
|
429
|
+
list(): Promise<readonly SenderShareRecord[]>;
|
|
430
|
+
delete(shareId: string): Promise<void>;
|
|
431
|
+
}
|
|
432
|
+
interface AgentShareRecordStoreOptions {
|
|
433
|
+
readonly backend: ShareIndexBackend;
|
|
434
|
+
/** DID of the key that signs the agent's invocations and delegations. */
|
|
435
|
+
readonly agentDid: string;
|
|
436
|
+
/** KEK_a from the same key; absent for a remote-signer-only profile (records are then owner-readable only). */
|
|
437
|
+
readonly agentKey?: AgentKeyMaterial;
|
|
438
|
+
readonly cas?: CasPolicy;
|
|
439
|
+
/**
|
|
440
|
+
* The share origin on which records read back get their Policy/v3
|
|
441
|
+
* `/s/inline` link rebuilt (the stored form keeps no link; see
|
|
442
|
+
* `delivery.ts`). Absent: records read back carry no v3 link.
|
|
443
|
+
*/
|
|
444
|
+
readonly shareOrigin?: string;
|
|
445
|
+
}
|
|
446
|
+
declare class AgentShareRecordStore implements SenderShareRecordStorage {
|
|
447
|
+
private readonly options;
|
|
448
|
+
readonly agentId: string;
|
|
449
|
+
private readonly cas;
|
|
450
|
+
constructor(options: AgentShareRecordStoreOptions);
|
|
451
|
+
/** Whether this profile can read its own records back (`kid` is set). */
|
|
452
|
+
get canReadBack(): boolean;
|
|
453
|
+
private location;
|
|
454
|
+
private seal;
|
|
455
|
+
private open;
|
|
456
|
+
/** Create or replace; each write is a fresh seal under CAS (If-None-Match `*` for a new key). */
|
|
457
|
+
put(record: SenderShareRecord): Promise<void>;
|
|
458
|
+
/** CAS update with the etag from the agent's own read (for example its own `revokedAt`). */
|
|
459
|
+
update(shareId: string, change: (record: SenderShareRecord) => SenderShareRecord | Promise<SenderShareRecord>): Promise<SenderShareRecord | undefined>;
|
|
460
|
+
get(shareId: string): Promise<SenderShareRecord | undefined>;
|
|
461
|
+
/** Lists the explicit `agents/<agentId>/` prefix (trailing slash: `list({})` would be refused). */
|
|
462
|
+
list(): Promise<readonly SenderShareRecord[]>;
|
|
463
|
+
/** Tier W has no delete grant on its prefix; the owner deletes agent records. */
|
|
464
|
+
delete(_shareId: string): Promise<void>;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* The stored form of a share record in the space (TC-1432 slice 2, cap
|
|
469
|
+
* ruling): each blob is stored once.
|
|
470
|
+
*
|
|
471
|
+
* A Policy/v3 record's `deliveryMaterial.envelope` is exactly what
|
|
472
|
+
* `sealedEnvelope` decrypts to under `envelopeKey` (`publishAddressedShare`
|
|
473
|
+
* seals `canonicalize(envelope)`), and its `/s/inline` link is
|
|
474
|
+
* `sealedEnvelope`, its CID and `envelopeKey` encoded again. Both are
|
|
475
|
+
* dropped before an agent record is sealed and rebuilt when needed:
|
|
476
|
+
* {@link openDeliveryEnvelope} for the verifier and a delivery retry,
|
|
477
|
+
* {@link shareLinkForRecord} at Open/Copy. `sealedEnvelope` stays (the node
|
|
478
|
+
* reopens that exact value and its nonce is random) and so does the session
|
|
479
|
+
* CACAO (it proves the chain). A bearer record keeps its `link`, which is
|
|
480
|
+
* not derivable.
|
|
481
|
+
*
|
|
482
|
+
* Security-sensitive: the sealed bytes are checked against `shareCid` before
|
|
483
|
+
* they are opened, and the plaintext must be the canonical JSON of the
|
|
484
|
+
* envelope, so a record cannot carry one envelope for display and another for
|
|
485
|
+
* the node.
|
|
486
|
+
*/
|
|
487
|
+
type StoredDeliveryMaterial = Omit<PublishedShareDeliveryMaterial, "envelope">;
|
|
488
|
+
/** A share record as stored at an agent (or migrated) key: {@link SenderShareRecord} without derivable blobs. */
|
|
489
|
+
type StoredShareRecord = Omit<SenderShareRecord, "deliveryMaterial"> & {
|
|
490
|
+
readonly deliveryMaterial?: StoredDeliveryMaterial;
|
|
491
|
+
};
|
|
492
|
+
/** Keys of a stored `deliveryMaterial`, exactly. */
|
|
493
|
+
declare const STORED_DELIVERY_MATERIAL_KEYS: readonly string[];
|
|
494
|
+
declare class DeliveryMaterialError extends Error {
|
|
495
|
+
constructor(message: string);
|
|
496
|
+
}
|
|
497
|
+
/** The signed envelope inside `sealedEnvelope`; throws {@link DeliveryMaterialError} unless it is exactly that. */
|
|
498
|
+
declare function openDeliveryEnvelope(material: StoredDeliveryMaterial): Promise<Record<string, unknown>>;
|
|
499
|
+
/**
|
|
500
|
+
* The link to show at Open/Copy: a bearer record's stored `link`, or a
|
|
501
|
+
* Policy/v3 record's `/s/inline` link rebuilt on `shareOrigin` (the
|
|
502
|
+
* viewer's configured share origin) from `sealedEnvelope` and `envelopeKey`.
|
|
503
|
+
*/
|
|
504
|
+
declare function shareLinkForRecord(record: Pick<StoredShareRecord, "link" | "deliveryMaterial">, shareOrigin: string): Promise<string | undefined>;
|
|
505
|
+
/**
|
|
506
|
+
* The stored form of `record`. For a Policy/v3 record (one with
|
|
507
|
+
* `deliveryMaterial`), drops `deliveryMaterial.envelope` and `link` after
|
|
508
|
+
* checking they are exactly what the sealed material rebuilds, so nothing is
|
|
509
|
+
* lost. Throws {@link DeliveryMaterialError} otherwise.
|
|
510
|
+
*/
|
|
511
|
+
declare function compactShareRecord(record: SenderShareRecord | StoredShareRecord): Promise<StoredShareRecord>;
|
|
512
|
+
/**
|
|
513
|
+
* The full record again (for a delivery retry or a caller that wants the
|
|
514
|
+
* {@link SenderShareRecord} shape): the envelope reopened from the sealed
|
|
515
|
+
* material and, when `shareOrigin` is given, the `/s/inline` link rebuilt.
|
|
516
|
+
*/
|
|
517
|
+
declare function expandShareRecord(record: StoredShareRecord, shareOrigin?: string): Promise<SenderShareRecord>;
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* Index document schema v1, rows, `project()`, and the versioned agent-record
|
|
521
|
+
* schema (design C §2, §5 check 5). The index holds display fields only:
|
|
522
|
+
* never `link`, `deliveryMaterial`, share keys, unmasked emails or `#k=`.
|
|
523
|
+
* Unknown fields on the header, on agent entries and on rows are kept.
|
|
524
|
+
*/
|
|
525
|
+
declare const INDEX_SCHEMA_VERSION = 1;
|
|
526
|
+
type ShareProofState = "proven" | "chained" | "unproven";
|
|
527
|
+
interface ShareIndexRow {
|
|
528
|
+
/** Display name: ≤120 characters, bidi and control characters stripped. */
|
|
529
|
+
readonly n: string;
|
|
530
|
+
readonly k: "file" | "folder";
|
|
531
|
+
/** Content kind: the lowercase file extension, when there is a short one. */
|
|
532
|
+
readonly ck?: string;
|
|
533
|
+
readonly ak: "bearer" | "recipientDid" | "exactEmail" | "emailDomain";
|
|
534
|
+
/** Masked audience label. */
|
|
535
|
+
readonly al: string;
|
|
536
|
+
readonly a: readonly string[];
|
|
537
|
+
/** Created (`registeredAt`) and expires, ISO 8601. */
|
|
538
|
+
readonly c: string;
|
|
539
|
+
readonly x: string;
|
|
540
|
+
/** Revocation; only `confirmed` (node-confirmed) is sticky. */
|
|
541
|
+
readonly r?: {
|
|
542
|
+
readonly at: string;
|
|
543
|
+
readonly confirmed: boolean;
|
|
544
|
+
};
|
|
545
|
+
/**
|
|
546
|
+
* Revoke kind. For agent rows the revoke action is decided at click time
|
|
547
|
+
* from the freshly verified record (§6). Observed on a local node (C5,
|
|
548
|
+
* TC-1432 slice 2):
|
|
549
|
+
* - per share: the owner wallet can revoke an agent's v3 root (`policyRoot`,
|
|
550
|
+
* `enforcementRoot` CIDs from the signed envelope) through the generic
|
|
551
|
+
* `/revoke` route: 200, and an open recipient session's next read gets 403
|
|
552
|
+
* `root-revoked`. Only the JSON root-revocation route answers 403
|
|
553
|
+
* `root-revocation-issuer-invalid` to the owner.
|
|
554
|
+
* - session-wide: revoking the agent's owner→session delegation kills its
|
|
555
|
+
* bearer links and fails new v3 claims at once, but an already-open v3
|
|
556
|
+
* recipient session keeps reading for its lifetime (3,598 s observed).
|
|
557
|
+
* The node liveness check (N3, test B-1) closes that.
|
|
558
|
+
*/
|
|
559
|
+
readonly rk: "policy-v3" | "delegation" | "none";
|
|
560
|
+
/** The share's revoke CID; unique across rows. */
|
|
561
|
+
readonly cid?: string;
|
|
562
|
+
/** Every CID this row claims (one row per CID, §5 check 7). */
|
|
563
|
+
readonly cc?: readonly string[];
|
|
564
|
+
/** Provenance, derived from the key path: `web` or `agent:<agentId>`. */
|
|
565
|
+
readonly src: string;
|
|
566
|
+
/** Agent and migrated rows: the proof state of the verified chain. */
|
|
567
|
+
readonly ps?: ShareProofState;
|
|
568
|
+
/** `migrated`: a one-time owner import (shown as "imported"); ranks by `ps`, never as a web row. */
|
|
569
|
+
readonly pv?: "migrated";
|
|
570
|
+
/** The verified chain has expired (shown as Expired, not rejected). */
|
|
571
|
+
readonly pe?: true;
|
|
572
|
+
/** Needs attention: unreadable record, or `shareId` ≠ key basename. */
|
|
573
|
+
readonly na?: true;
|
|
574
|
+
readonly [unknown: string]: unknown;
|
|
575
|
+
}
|
|
576
|
+
interface ShareIndexAgentEntry {
|
|
577
|
+
/** The agent DID, once a record with a valid header was seen. */
|
|
578
|
+
readonly did: string | null;
|
|
579
|
+
readonly rows: number;
|
|
580
|
+
readonly rejected: Readonly<Record<string, number>>;
|
|
581
|
+
/** Raw key suffixes (≤64 chars) refused on first sight: never refetched. At most 100. */
|
|
582
|
+
readonly rejectedKeys: readonly string[];
|
|
583
|
+
/** Keys whose `recordV` is newer than this build: skipped until an upgrade. At most 100. */
|
|
584
|
+
readonly newerKeys?: readonly string[];
|
|
585
|
+
readonly newerV?: number;
|
|
586
|
+
readonly paused: false | {
|
|
587
|
+
readonly reason: "rejections" | "row-cap" | "newer";
|
|
588
|
+
readonly at: string;
|
|
589
|
+
};
|
|
590
|
+
readonly firstSeen: string;
|
|
591
|
+
readonly [unknown: string]: unknown;
|
|
592
|
+
}
|
|
593
|
+
interface ShareIndexDocument {
|
|
594
|
+
readonly v: number;
|
|
595
|
+
readonly ownerDid: string;
|
|
596
|
+
readonly spaceId: string;
|
|
597
|
+
readonly updatedAt: string;
|
|
598
|
+
readonly updatedBy: string;
|
|
599
|
+
readonly archives: readonly {
|
|
600
|
+
readonly name: string;
|
|
601
|
+
readonly ids: readonly string[];
|
|
602
|
+
}[];
|
|
603
|
+
readonly tombstones: readonly {
|
|
604
|
+
readonly key: string;
|
|
605
|
+
readonly at: string;
|
|
606
|
+
}[];
|
|
607
|
+
readonly reconcile: {
|
|
608
|
+
readonly cursor?: string;
|
|
609
|
+
};
|
|
610
|
+
readonly agents: Readonly<Record<string, ShareIndexAgentEntry>>;
|
|
611
|
+
readonly rows: Readonly<Record<string, ShareIndexRow>>;
|
|
612
|
+
readonly [unknown: string]: unknown;
|
|
613
|
+
}
|
|
614
|
+
interface ShareIndexArchiveDocument {
|
|
615
|
+
readonly v: number;
|
|
616
|
+
readonly rows: Readonly<Record<string, ShareIndexRow>>;
|
|
617
|
+
readonly [unknown: string]: unknown;
|
|
618
|
+
}
|
|
619
|
+
type ParsedIndexDocument = {
|
|
620
|
+
readonly status: "ok";
|
|
621
|
+
readonly doc: ShareIndexDocument;
|
|
622
|
+
}
|
|
623
|
+
/** A higher `v`: render read-only, never write. */
|
|
624
|
+
| {
|
|
625
|
+
readonly status: "newer";
|
|
626
|
+
readonly v: number;
|
|
627
|
+
}
|
|
628
|
+
/** Decrypted, but not a valid document: deterministic corruption. */
|
|
629
|
+
| {
|
|
630
|
+
readonly status: "invalid";
|
|
631
|
+
};
|
|
632
|
+
declare function parseIndexDocument(value: unknown): ParsedIndexDocument;
|
|
633
|
+
/** Strip bidi/control/format characters and cap at 120 code points. */
|
|
634
|
+
declare function displayName(value: unknown, fallback: string): string;
|
|
635
|
+
/**
|
|
636
|
+
* The display-only projection of a record. `claims` overrides the CIDs the
|
|
637
|
+
* row may claim (agent rows claim only what their chain verified).
|
|
638
|
+
*/
|
|
639
|
+
declare function project(record: StoredShareRecord, input: {
|
|
640
|
+
readonly key: string;
|
|
641
|
+
readonly src: string;
|
|
642
|
+
readonly claims?: readonly string[];
|
|
643
|
+
readonly proof?: {
|
|
644
|
+
readonly state: ShareProofState;
|
|
645
|
+
readonly expired: boolean;
|
|
646
|
+
};
|
|
647
|
+
}): ShareIndexRow;
|
|
648
|
+
/**
|
|
649
|
+
* Whether `spaceId` (`tinycloud:pkh:eip155:<chain>:<address>:<name>`) is a
|
|
650
|
+
* space of the account `ownerDid` (`did:pkh:eip155:<chain>:<address>`),
|
|
651
|
+
* whatever its name: the CLI keeps share content in `default` while the
|
|
652
|
+
* records live in `applications`. Address spelling is ignored.
|
|
653
|
+
*/
|
|
654
|
+
declare function isSpaceOwnedBy(spaceId: string, ownerDid: string): boolean;
|
|
655
|
+
/** A record refused by the schema. `provenance`: an agent-subtree record claiming `migrated`. */
|
|
656
|
+
declare class ShareRecordSchemaError extends Error {
|
|
657
|
+
readonly reason: "schema" | "provenance";
|
|
658
|
+
constructor(reason: "schema" | "provenance");
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
declare function claimRank(row: Pick<ShareIndexRow, "src" | "ps" | "pv">): number;
|
|
662
|
+
type ClaimDecision = {
|
|
663
|
+
readonly admit: true;
|
|
664
|
+
readonly displaced: readonly string[];
|
|
665
|
+
} | {
|
|
666
|
+
readonly admit: false;
|
|
667
|
+
readonly heldBy: string;
|
|
668
|
+
};
|
|
669
|
+
/**
|
|
670
|
+
* Decide a new claim `row` at `key` against the rows already in `rows`.
|
|
671
|
+
* Collisions are rows (other than `key` itself) that claim any CID in common.
|
|
672
|
+
* Web rows never displace other web rows (both are owner-written).
|
|
673
|
+
*/
|
|
674
|
+
declare function decideClaim(rows: Readonly<Record<string, ShareIndexRow>>, key: string, row: ShareIndexRow): ClaimDecision;
|
|
675
|
+
|
|
676
|
+
/**
|
|
677
|
+
* Attenuation containment (design C4): every (resource, ability) of the child
|
|
678
|
+
* must be granted by the parent on the same resource or on a parent resource
|
|
679
|
+
* under the segment-prefix rule `child == parent || child.startsWith(parent
|
|
680
|
+
* + "/")` (a parent already ending in `/` is a prefix itself), as
|
|
681
|
+
* `unified.ts:1225-1233` applies it. EVM address spelling is ignored. A
|
|
682
|
+
* parent ability whose caveats are all empty objects is unrestricted;
|
|
683
|
+
* otherwise the child's caveats must be identical. Fail-closed.
|
|
684
|
+
*/
|
|
685
|
+
type Attenuation = Readonly<Record<string, Readonly<Record<string, readonly unknown[]>>>>;
|
|
686
|
+
declare function attenuationCovers(parent: Attenuation, child: Attenuation): boolean;
|
|
687
|
+
|
|
688
|
+
/**
|
|
689
|
+
* Owner→session SIWE CACAO checks (design C4). Security-sensitive.
|
|
690
|
+
*
|
|
691
|
+
* Signature, canonical DAG-CBOR, exact-bytes CID and the ReCap statement are
|
|
692
|
+
* verified by the injected parser: sdk-core `parseSignedSiweCacao`
|
|
693
|
+
* (`cacao.ts:205-276`; share-sdk cannot depend on sdk-core, which depends on
|
|
694
|
+
* share-sdk). That parser does not check validity times, so this module adds:
|
|
695
|
+
* `Not Before`/`Expiration Time` against `now`, issuer == the account owner,
|
|
696
|
+
* audience == the child's issuer, and child attenuation ⊆ the CACAO's. `Not
|
|
697
|
+
* Before` and `Issued At` are read from the verified bytes ({@link cacaoTimes}).
|
|
698
|
+
*/
|
|
699
|
+
interface ParsedSiweCacao {
|
|
700
|
+
readonly cid: string;
|
|
701
|
+
/** `did:pkh:eip155:<chain>:<address>`. */
|
|
702
|
+
readonly issuer: string;
|
|
703
|
+
/** SIWE `uri`: the delegate DID. */
|
|
704
|
+
readonly audience: string;
|
|
705
|
+
readonly attenuation: Attenuation;
|
|
706
|
+
readonly expiresAt?: string;
|
|
707
|
+
}
|
|
708
|
+
/** Verifies signature, encoding and the exact-bytes CID; throws otherwise. */
|
|
709
|
+
type SiweCacaoParser = (authorization: string, expectedCid: string) => Promise<ParsedSiweCacao>;
|
|
710
|
+
type DelegationTime = "current" | "expired";
|
|
711
|
+
interface OwnerSessionCheck {
|
|
712
|
+
readonly authorization: string;
|
|
713
|
+
readonly expectedCid: string;
|
|
714
|
+
readonly accountOwnerDid: string;
|
|
715
|
+
/** The issuer of the delegation this CACAO must authorize (the leaf or root issuer). */
|
|
716
|
+
readonly childIssuer: string;
|
|
717
|
+
readonly childAttenuation: Attenuation;
|
|
718
|
+
readonly now: Date;
|
|
719
|
+
readonly parse: SiweCacaoParser;
|
|
720
|
+
}
|
|
721
|
+
interface VerifiedOwnerSession {
|
|
722
|
+
readonly cid: string;
|
|
723
|
+
/** The session principal (audience without fragment). */
|
|
724
|
+
readonly sessionDid: string;
|
|
725
|
+
readonly time: DelegationTime;
|
|
726
|
+
/** The signed `Issued At` (epoch ms), when the parser reports it. */
|
|
727
|
+
readonly issuedAt?: number;
|
|
728
|
+
}
|
|
729
|
+
/** Throws when the CACAO does not prove the owner→session hop; reports expiry separately. */
|
|
730
|
+
declare function verifyOwnerSessionDelegation(input: OwnerSessionCheck): Promise<VerifiedOwnerSession>;
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* CID ownership by proof (design C §5 check 7, C1–C4). Everything is checked
|
|
734
|
+
* from the signed bytes the record carries; nothing is fetched.
|
|
735
|
+
*
|
|
736
|
+
* - `proven`: the full chain verifies to the account owner and the leaf
|
|
737
|
+
* issuer (the policy owner for Policy/v3) is `hdr.agentDid`.
|
|
738
|
+
* - `chained`: the full chain verifies to the account owner through another key.
|
|
739
|
+
* - `unproven`: the leaf verifies but the owner→session CACAO is absent.
|
|
740
|
+
* - `expired` is reported next to the state: a chain that verifies but has
|
|
741
|
+
* expired is admitted as Expired, not rejected.
|
|
742
|
+
* - anything else: `{ ok: false }` (reason `proof`).
|
|
743
|
+
*
|
|
744
|
+
* Supported chains: native bearer links (`proofs.link` + `proofs.session`),
|
|
745
|
+
* Policy/v3 addressed shares (the envelope opened from
|
|
746
|
+
* `deliveryMaterial.sealedEnvelope`, bound to `shareCid`, + `proofs.session`)
|
|
747
|
+
* and Policy/v2 owner-policy shares (`proofs.ownerPolicy`, `ownerDelegation`,
|
|
748
|
+
* `enforcementDelegation`, optional `registration`).
|
|
749
|
+
*
|
|
750
|
+
* What revocation achieves today (local node, C5): the owner wallet's generic
|
|
751
|
+
* `/revoke` of a verified v3 root CID ends that share at once, open recipient
|
|
752
|
+
* sessions included (403 `root-revoked`); only the JSON root-revocation route
|
|
753
|
+
* refuses the owner (403 `root-revocation-issuer-invalid`). Revoking the
|
|
754
|
+
* verified session CACAO kills the session's bearer links and new v3 claims
|
|
755
|
+
* at once, but an already-open v3 recipient session keeps reading for its
|
|
756
|
+
* lifetime (3,598 s observed) until the node liveness check (N3, test B-1).
|
|
757
|
+
* Migrated records are verified with no agent binding, so they are never
|
|
758
|
+
* `proven`.
|
|
759
|
+
*/
|
|
760
|
+
type ChainVerdict = {
|
|
761
|
+
readonly ok: true;
|
|
762
|
+
readonly state: ShareProofState;
|
|
763
|
+
readonly expired: boolean;
|
|
764
|
+
readonly claims: readonly string[];
|
|
765
|
+
/**
|
|
766
|
+
* Where `registeredAt` may lie, from signed times in the chain (epoch ms):
|
|
767
|
+
* a signed issuance time ± {@link REGISTERED_AT_SKEW_MS} when the chain
|
|
768
|
+
* has one (link `nbf`, the v3 binding's `issuedAt`, the node's v2
|
|
769
|
+
* `registeredAt`); otherwise the session's signed `Issued At` as the
|
|
770
|
+
* earliest and the leaf's expiry as the latest.
|
|
771
|
+
*/
|
|
772
|
+
readonly issued: {
|
|
773
|
+
readonly earliest?: number;
|
|
774
|
+
readonly latest?: number;
|
|
775
|
+
};
|
|
776
|
+
} | {
|
|
777
|
+
readonly ok: false;
|
|
778
|
+
readonly detail: string;
|
|
779
|
+
};
|
|
780
|
+
/** The node registration key for a node audience, from the share public config. */
|
|
781
|
+
interface ShareRegistrationKey {
|
|
782
|
+
readonly kid: string;
|
|
783
|
+
/** Raw 32-byte Ed25519 key, or its 34-byte did:key multicodec form. */
|
|
784
|
+
readonly publicKey: Uint8Array;
|
|
785
|
+
}
|
|
786
|
+
interface ChainContext {
|
|
787
|
+
readonly accountOwnerDid: string;
|
|
788
|
+
/** `hdr.agentDid`, already bound to the path by `derive(agentDid) == agentId`. */
|
|
789
|
+
readonly agentDid: string;
|
|
790
|
+
readonly now: Date;
|
|
791
|
+
readonly parseSiweCacao: SiweCacaoParser;
|
|
792
|
+
/** Registration key by `target.nodeAudience`; absent ⇒ `registrationCid` is not claimed. */
|
|
793
|
+
readonly registrationKey?: (nodeAudience: string) => ShareRegistrationKey | undefined;
|
|
794
|
+
}
|
|
795
|
+
/** Verify the chain behind every CID a stored agent (or migrated) record claims. Never throws. */
|
|
796
|
+
declare function verifyAgentRecordChain(record: StoredShareRecord, context: ChainContext): Promise<ChainVerdict>;
|
|
797
|
+
|
|
798
|
+
/**
|
|
799
|
+
* Signed UCAN verifier for issued delegations (native bearer link
|
|
800
|
+
* delegations and Policy/v3 owner roots). Security-sensitive.
|
|
801
|
+
*
|
|
802
|
+
* Same acceptance as sdk-core `parseSignedCompactUcanAttenuation`
|
|
803
|
+
* (`unified.ts:1281-1314`): EdDSA/JWT/ucv 0.10.0 header whose JWK binds the
|
|
804
|
+
* did:key issuer, strict Ed25519 signature, CID = CIDv1(raw, blake3) of the
|
|
805
|
+
* exact Authorization bytes. It additionally returns the verified `prf`,
|
|
806
|
+
* `nbf` and `exp` (design C4), and requires `exp`: an expiry-less delegation
|
|
807
|
+
* is refused. Payload JSON need not be JCS: WASM-issued link delegations are
|
|
808
|
+
* not.
|
|
809
|
+
*/
|
|
810
|
+
interface SignedUcanDelegation {
|
|
811
|
+
readonly cid: string;
|
|
812
|
+
/** Issuer principal without any `#fragment`. */
|
|
813
|
+
readonly issuer: string;
|
|
814
|
+
/** Audience principal without any `#fragment`. */
|
|
815
|
+
readonly audience: string;
|
|
816
|
+
readonly attenuation: Readonly<Record<string, Readonly<Record<string, readonly unknown[]>>>>;
|
|
817
|
+
readonly proofs: readonly string[];
|
|
818
|
+
readonly notBefore?: number;
|
|
819
|
+
readonly expiresAt: number;
|
|
820
|
+
readonly facts?: readonly unknown[];
|
|
821
|
+
}
|
|
822
|
+
declare function parseSignedUcan(authorization: string, expectedCid?: string): SignedUcanDelegation;
|
|
823
|
+
|
|
824
|
+
/**
|
|
825
|
+
* Verifier for a Policy/v2 enforcement delegation
|
|
826
|
+
* (`TinyCloudSharePolicyEnforcement`, signed by the share key;
|
|
827
|
+
* `createPolicyEnforcementDelegation`). No verifier existed before
|
|
828
|
+
* (design C §5 check 7, C4).
|
|
829
|
+
*
|
|
830
|
+
* Checks, all fail-closed:
|
|
831
|
+
* - the DAG-CBOR bytes are exactly the canonical encoding of
|
|
832
|
+
* `{ domain, unsigned: { type, version: 2, issuerDid, audienceDid, facts } }`
|
|
833
|
+
* built from the delegation's own fields (so every reported field is signed);
|
|
834
|
+
* - the Ed25519 signature over those bytes verifies against `issuerDid`
|
|
835
|
+
* (a did:key), strict RFC 8032;
|
|
836
|
+
* - the CID recomputed from the exact bytes equals `cid` (and `expectedCid`);
|
|
837
|
+
* - `facts.shareKeyDid` equals the issuer.
|
|
838
|
+
*/
|
|
839
|
+
declare function verifyPolicyEnforcementDelegation(delegation: SignedDelegation, expectedCid?: string): Promise<SignedDelegation>;
|
|
840
|
+
|
|
841
|
+
/**
|
|
842
|
+
* `SenderShareIndex`: the encrypted, display-only share index at
|
|
843
|
+
* `records/_index/main` (design C §2, §4, §5, §7). Records stay canonical;
|
|
844
|
+
* the index is a projection that is only ever written with compare-and-swap.
|
|
845
|
+
*/
|
|
846
|
+
interface ShareIndexLimits {
|
|
847
|
+
readonly listPagesPerPass: number;
|
|
848
|
+
readonly fetchesPerPass: number;
|
|
849
|
+
readonly newRowsPerAgentPerPass: number;
|
|
850
|
+
readonly liveRowsPerAgent: number;
|
|
851
|
+
readonly rejectionsBeforePause: number;
|
|
852
|
+
/** Agent rows together may use at most this share of `mainRowBytes`. */
|
|
853
|
+
readonly agentRowShare: number;
|
|
854
|
+
readonly mainRowBytes: number;
|
|
855
|
+
readonly headerBytes: number;
|
|
856
|
+
readonly maxAgentRecordBytes: number;
|
|
857
|
+
readonly tombstoneTtlMs: number;
|
|
858
|
+
readonly archiveAgeMs: number;
|
|
859
|
+
readonly statusChecksPerSync: number;
|
|
860
|
+
}
|
|
861
|
+
declare const DEFAULT_SHARE_INDEX_LIMITS: ShareIndexLimits;
|
|
862
|
+
/** Outbox ops carry rows and CIDs, never records. */
|
|
863
|
+
type ShareIndexOp = {
|
|
864
|
+
readonly id: string;
|
|
865
|
+
readonly type: "upsert";
|
|
866
|
+
readonly key: string;
|
|
867
|
+
readonly row: ShareIndexRow;
|
|
868
|
+
} | {
|
|
869
|
+
readonly id: string;
|
|
870
|
+
readonly type: "revoke";
|
|
871
|
+
readonly key: string;
|
|
872
|
+
readonly at: string;
|
|
873
|
+
readonly confirmed: boolean;
|
|
874
|
+
}
|
|
875
|
+
/** Only for revoked, expired or unreadable rows: tombstone first, then the caller deletes the record. */
|
|
876
|
+
| {
|
|
877
|
+
readonly id: string;
|
|
878
|
+
readonly type: "delete";
|
|
879
|
+
readonly key: string;
|
|
880
|
+
}
|
|
881
|
+
/** Owner agent controls: `resume` clears a pause; `recheck` also clears the agent's rejected lists. */
|
|
882
|
+
| {
|
|
883
|
+
readonly id: string;
|
|
884
|
+
readonly type: "agent";
|
|
885
|
+
readonly agentId: string;
|
|
886
|
+
readonly action: "resume" | "recheck";
|
|
887
|
+
};
|
|
888
|
+
/** Durable op queue: IndexedDB on the web, the profile cache for Tier 2. */
|
|
889
|
+
interface ShareIndexOutbox {
|
|
890
|
+
list(): Promise<readonly ShareIndexOp[]>;
|
|
891
|
+
put(op: ShareIndexOp): Promise<void>;
|
|
892
|
+
remove(ids: readonly string[]): Promise<void>;
|
|
893
|
+
}
|
|
894
|
+
declare class MemoryShareIndexOutbox implements ShareIndexOutbox {
|
|
895
|
+
private readonly ops;
|
|
896
|
+
list(): Promise<readonly ShareIndexOp[]>;
|
|
897
|
+
put(op: ShareIndexOp): Promise<void>;
|
|
898
|
+
remove(ids: readonly string[]): Promise<void>;
|
|
899
|
+
}
|
|
900
|
+
/** Node-side status of a row's share, for status sync. `unknown` (e.g. agent-issued CIDs, TC-1419) changes nothing. */
|
|
901
|
+
interface ShareStatusPort {
|
|
902
|
+
status(key: string, row: ShareIndexRow): Promise<"revoked" | "active" | "unknown">;
|
|
903
|
+
}
|
|
904
|
+
interface SenderShareIndexOptions {
|
|
905
|
+
readonly backend: ShareIndexBackend;
|
|
906
|
+
readonly outbox: ShareIndexOutbox;
|
|
907
|
+
/** The account owner (`did:pkh:…`). */
|
|
908
|
+
readonly ownerDid: string;
|
|
909
|
+
/** `updatedBy` label of this writer. */
|
|
910
|
+
readonly writer: string;
|
|
911
|
+
/** Configured share origins, for the link check. */
|
|
912
|
+
readonly shareOrigins: readonly string[];
|
|
913
|
+
/** sdk-core `parseSignedSiweCacao`. */
|
|
914
|
+
readonly parseSiweCacao: SiweCacaoParser;
|
|
915
|
+
/** Node registration keys by `nodeAudience`, from the share public config. */
|
|
916
|
+
readonly registrationKey?: (nodeAudience: string) => ShareRegistrationKey | undefined;
|
|
917
|
+
readonly limits?: Partial<ShareIndexLimits>;
|
|
918
|
+
readonly cas?: Partial<CasPolicy>;
|
|
919
|
+
readonly now?: () => Date;
|
|
920
|
+
}
|
|
921
|
+
type ShareIndexLoad = {
|
|
922
|
+
readonly status: "ok";
|
|
923
|
+
readonly doc: ShareIndexDocument;
|
|
924
|
+
}
|
|
925
|
+
/** A higher schema version: render read-only (option A path), never write. */
|
|
926
|
+
| {
|
|
927
|
+
readonly status: "read_only";
|
|
928
|
+
readonly v: number;
|
|
929
|
+
} | {
|
|
930
|
+
readonly status: "not_found";
|
|
931
|
+
}
|
|
932
|
+
/** Deterministic corruption: the next write rebuilds. */
|
|
933
|
+
| {
|
|
934
|
+
readonly status: "corrupt";
|
|
935
|
+
}
|
|
936
|
+
/** Outage: never a reason to rebuild. */
|
|
937
|
+
| {
|
|
938
|
+
readonly status: "unavailable";
|
|
939
|
+
};
|
|
940
|
+
type ShareIndexWriteStatus = "written" | "unchanged" | "read_only" | "unavailable";
|
|
941
|
+
interface ShareIndexWriteOutcome {
|
|
942
|
+
readonly status: ShareIndexWriteStatus;
|
|
943
|
+
/** The document as written, or as found when the change was already present. */
|
|
944
|
+
readonly doc?: ShareIndexDocument;
|
|
945
|
+
}
|
|
946
|
+
interface ShareIndexFlushResult {
|
|
947
|
+
readonly status: ShareIndexWriteStatus | "empty";
|
|
948
|
+
/** Op ids that can never apply (tombstoned upsert, delete of a live row, unknown row). They are dropped. */
|
|
949
|
+
readonly refused: readonly string[];
|
|
950
|
+
}
|
|
951
|
+
/**
|
|
952
|
+
* §5 rejection reasons; every check-4 failure (unwrap, DEK length, commit, GCM) is `decrypt`.
|
|
953
|
+
* `provenance`: an agent-subtree record claiming `migrated`, which only owner imports may carry.
|
|
954
|
+
*/
|
|
955
|
+
type AgentRejectReason = "size" | "shape" | "header" | "decrypt" | "schema" | "provenance" | "link" | "proof";
|
|
956
|
+
interface ShareIndexReconcileReport {
|
|
957
|
+
readonly status: ShareIndexWriteStatus;
|
|
958
|
+
readonly pages: number;
|
|
959
|
+
readonly fetches: number;
|
|
960
|
+
readonly admitted: number;
|
|
961
|
+
readonly rejected: Readonly<Record<string, number>>;
|
|
962
|
+
readonly deferred: number;
|
|
963
|
+
/** True when this pass reached the end of the key listing. */
|
|
964
|
+
readonly cycleComplete: boolean;
|
|
965
|
+
/** The header reached its cap: new agent header state (entries, rejections) was not added. Show an alert; no row was evicted. */
|
|
966
|
+
readonly headerFull: boolean;
|
|
967
|
+
}
|
|
968
|
+
/** Encoded size of everything except the rows. */
|
|
969
|
+
declare function headerBytes(doc: ShareIndexDocument): number;
|
|
970
|
+
declare class SenderShareIndex {
|
|
971
|
+
private readonly options;
|
|
972
|
+
private readonly backend;
|
|
973
|
+
private readonly limits;
|
|
974
|
+
private readonly cas;
|
|
975
|
+
private readonly now;
|
|
976
|
+
constructor(options: SenderShareIndexOptions);
|
|
977
|
+
/** Library open: one GET + one decrypt. */
|
|
978
|
+
load(): Promise<ShareIndexLoad>;
|
|
979
|
+
enqueue(op: ShareIndexOp): Promise<void>;
|
|
980
|
+
/** Rebuild base after deterministic corruption: an empty document plus the archives found under `_index/`. */
|
|
981
|
+
private rebuildBase;
|
|
982
|
+
private emptyDoc;
|
|
983
|
+
/**
|
|
984
|
+
* Read → mutate → If-Match write, per {@link runCas}. A no-op change is never
|
|
985
|
+
* written. The header cap is enforced by the reconciler on agent-derived
|
|
986
|
+
* state only (see {@link reconcile}); the owner's own writes are never blocked by it.
|
|
987
|
+
*/
|
|
988
|
+
private update;
|
|
989
|
+
/** When false (header at its cap), no new agent header state is added: no new entries, rejections or newer keys. */
|
|
990
|
+
private growHeader;
|
|
991
|
+
private ensureAgent;
|
|
992
|
+
/** Count a rejection once per key: a key already in `rejectedKeys` changes nothing. */
|
|
993
|
+
private recordRejection;
|
|
994
|
+
/** Remove a displaced row; a displaced agent claim counts as `proof` and is not refetched. */
|
|
995
|
+
private displace;
|
|
996
|
+
private isRetired;
|
|
997
|
+
private applyOp;
|
|
998
|
+
private displaceForDelete;
|
|
999
|
+
/**
|
|
1000
|
+
* Apply every pending outbox op in one CAS. Ops leave the outbox only after
|
|
1001
|
+
* the write is confirmed (or the change was already present). Any CAS error,
|
|
1002
|
+
* including `INVALID_ETAG`, propagates with the ops still pending.
|
|
1003
|
+
*/
|
|
1004
|
+
flush(): Promise<ShareIndexFlushResult>;
|
|
1005
|
+
private examineAgentRecord;
|
|
1006
|
+
/** §5 checks 5–7 for a decrypted record, shared by agent records and one-time owner imports. */
|
|
1007
|
+
private checkRecord;
|
|
1008
|
+
private peekRecordV;
|
|
1009
|
+
private archivedClaims;
|
|
1010
|
+
/**
|
|
1011
|
+
* One budgeted pass: list keys from `reconcile.cursor`, fetch and check what
|
|
1012
|
+
* the index does not know, then apply the findings in one CAS. Never
|
|
1013
|
+
* deletes rows; tombstoned, archived and rejected keys are never refetched.
|
|
1014
|
+
*/
|
|
1015
|
+
reconcile(): Promise<ShareIndexReconcileReport>;
|
|
1016
|
+
private applyFindings;
|
|
1017
|
+
syncStatus(port: ShareStatusPort): Promise<{
|
|
1018
|
+
readonly status: ShareIndexWriteStatus;
|
|
1019
|
+
readonly checked: number;
|
|
1020
|
+
}>;
|
|
1021
|
+
compact(): Promise<{
|
|
1022
|
+
readonly status: ShareIndexWriteStatus;
|
|
1023
|
+
readonly archived: number;
|
|
1024
|
+
}>;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
/**
|
|
1028
|
+
* Policy/v2 node registration receipt, with expiry reported apart from
|
|
1029
|
+
* invalidity (design C4). Security-sensitive.
|
|
1030
|
+
*
|
|
1031
|
+
* The package's `validateOwnerSharePolicyRegistration` refuses an expired
|
|
1032
|
+
* receipt before checking anything else, so an expired-but-genuine receipt
|
|
1033
|
+
* cannot be told from a forged one. This verifier makes the same checks
|
|
1034
|
+
* (exact shape; binding to the chain's CIDs; every field the original compares
|
|
1035
|
+
* against the canonical policy and the enforcement facts; canonical times;
|
|
1036
|
+
* the CID over the canonical core; the node's Ed25519 signature against the
|
|
1037
|
+
* registration key from the share public config) and then reports `expired`
|
|
1038
|
+
* separately. `registrationCid` is not inside the node-signed core, so the
|
|
1039
|
+
* CID-over-core check is what binds it.
|
|
1040
|
+
*/
|
|
1041
|
+
interface RegistrationKey {
|
|
1042
|
+
readonly kid: string;
|
|
1043
|
+
/** Raw 32-byte Ed25519 key, or its 34-byte did:key multicodec form. */
|
|
1044
|
+
readonly publicKey: Uint8Array;
|
|
1045
|
+
}
|
|
1046
|
+
interface CheckedRegistration {
|
|
1047
|
+
readonly status: "valid" | "expired";
|
|
1048
|
+
readonly registration: OwnerSharePolicyRegistration;
|
|
1049
|
+
}
|
|
1050
|
+
/** Throws when the receipt does not verify; reports a verified receipt past its `expiresAt` as `expired`. */
|
|
1051
|
+
declare function checkRegistrationReceipt(value: unknown, expected: {
|
|
1052
|
+
readonly policyCid: string;
|
|
1053
|
+
readonly ownerDelegationCid: string;
|
|
1054
|
+
readonly enforcementDelegationCid: string;
|
|
1055
|
+
/** The `policy` object of the canonical Policy/v2 envelope whose bytes hash to `policyCid`. */
|
|
1056
|
+
readonly policy: Readonly<Record<string, unknown>>;
|
|
1057
|
+
/** The verified enforcement delegation's facts. */
|
|
1058
|
+
readonly enforcementFacts: Readonly<Record<string, unknown>>;
|
|
1059
|
+
}, key: RegistrationKey, now: Date): CheckedRegistration;
|
|
1060
|
+
|
|
1061
|
+
declare function verifyEnvelopeV3At(envelope: ShareEnvelopeV3, expectedSignerDid: string, now: number): Promise<boolean>;
|
|
1062
|
+
|
|
1063
|
+
export { AGENT_ID_LENGTH, AGENT_RECORD_VERSION, type AgentKeyMaterial, AgentRecordError, type AgentRecordFailure, type AgentRecordHeader, type AgentRejectReason, AgentShareRecordStore, type AgentShareRecordStoreOptions, type Attenuation, type CasPolicy, type ChainContext, type ChainVerdict, type CheckedRegistration, type ClaimDecision, type ClassifiedRecordKey, DEFAULT_CAS_POLICY, DEFAULT_SHARE_INDEX_LIMITS, DeliveryMaterialError, INDEX_MAIN_KEY, INDEX_SCHEMA_VERSION, INVALID_ETAG_MESSAGE, MAX_AGENT_RECORD_BYTES, MemoryShareIndexOutbox, type OwnerNetworkUnwrap, type OwnerNetworkWrap, OwnerUnwrapUnavailableError, type ParsedSiweCacao, type RegistrationKey, SHARE_RECORDS_VAULT_PREFIX, STORED_DELIVERY_MATERIAL_KEYS, SUPPORTED_AGENT_RECORD_V, SenderShareIndex, type SenderShareIndexOptions, SenderShareRecord, type ShareDocumentRead, type ShareIndexAgentEntry, type ShareIndexArchiveDocument, type ShareIndexBackend, ShareIndexCasError, type ShareIndexCasErrorCode, type ShareIndexDocument, type ShareIndexFlushResult, type ShareIndexLimits, type ShareIndexLoad, type ShareIndexOp, type ShareIndexOutbox, type ShareIndexReconcileReport, type ShareIndexRow, type ShareIndexWriteOutcome, type ShareIndexWriteStatus, type ShareLinkCheck, type ShareLinkShape, type ShareListResult, type ShareProofState, type ShareRawRead, ShareRecordSchemaError, type ShareRegistrationKey, type ShareStatusPort, type ShareWriteCondition, type ShareWriteResult, type SignedUcanDelegation, type SiweCacaoParser, type StoredAgentRecord, type StoredDeliveryMaterial, type StoredShareRecord, type TinyCloudShareIndexBackendOptions, type TinyCloudShareIndexClient, type VaultNetworkRead, WebShareRecordStore, agentIdFromDid, agentRecordBinding, agentRecordKey, agentRecordPrefix, attenuationCovers, checkRegistrationReceipt, claimRank, classifyRecordKey, compactShareRecord, createTinyCloudShareIndexBackend, decideClaim, deriveAgentKeyMaterial, displayName, expandShareRecord, headerBytes, isAgentId, isShareId, isSpaceOwnedBy, openAgentRecordAsAgent, openAgentRecordAsOwner, openDeliveryEnvelope, parseIndexDocument, parseSignedUcan, parseStoredAgentRecord, project, sealAgentRecord, shareLinkForRecord, validateShareLink, verifyAgentRecordChain, verifyEnvelopeV3At, verifyOwnerSessionDelegation, verifyPolicyEnforcementDelegation };
|