@tinycloud/courier 0.5.1-beta.1 → 0.5.1-beta.3

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/state.js ADDED
@@ -0,0 +1,516 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { cmd } from './program.js';
4
+ import { hasProfileFields, isAgentKey, loadGrant, loadKey, profileDir, readRegularFile, readSecure, saveKey, saveProfile, writeSecure } from './profile.js';
5
+ import { checkApprovalResultBinding, openRelayResult } from '@tinycloud/share-envelope/links';
6
+ import { APPROVAL_FILE, approvalPhase, clearPending, lacksOwner, readApprovalEntry, resultEnvelopeOf } from './approval-phase.js';
7
+ import { assertBoundToKey } from './grant.js';
8
+ import { bareDid, siweTimes } from './authority.js';
9
+ import { dropPendingDelegation, hasLivePending, liveRedeemedDelegations } from './pending.js';
10
+ import { REVOKE_URL } from './grant-refusal.js';
11
+ import { CourierError } from './errors.js';
12
+ import { base64url32, ed25519DidKey, ed25519PublicKey } from './did-key.js';
13
+ /**
14
+ * One derivation of where `init` stands, shared by every init mode.
15
+ *
16
+ * Inputs (all in the Courier home): profile.json (`status`, `spacePending`), grant.json, key.json, pending-grant.json (live records),
17
+ * approval-pending.json, rotation.json, and any stray key-bearing temp file (`rotation.json.<pid>.<hex>.tmp`, `key.json.<pid>.<hex>.tmp`).
18
+ *
19
+ * `readInputs` is the only place that touches the disk, so the way the inputs are read can be replaced in one spot.
20
+ * `classifyState` is pure. `deriveState` only reads: it never repairs, drops or rewrites a file. Recovery is the explicit
21
+ * `recoverInterrupted` step an init mode takes after reading.
22
+ *
23
+ * Key rotation is one journaled step over key.json, profile.json, grant.json and approval-pending.json:
24
+ * (1) rotation.json is written (temp file, fsync, rename, directory fsync). It holds the complete NEW key and profile and the
25
+ * non-secret facts about the approval being discarded, so nothing about the discard depends on the process staying alive;
26
+ * (2) key.json is replaced; (3) profile.json is replaced; (4) grant.json, and approval-pending.json when discarding, are removed;
27
+ * (5) the discard warning is printed, then rotation.json is removed (its only deletion point).
28
+ * Before the rename in (1) nothing but a stray temp file can differ from the old state. From then on every init mode rolls forward
29
+ * from the journal alone; every step is idempotent. A process killed while writing a temp file leaves it behind (0600, holding a
30
+ * key that may or may not have been installed, or an approval's relay key and result): `recoverInterrupted` zero-fills and removes it, unless
31
+ * the process that named it is still running.
32
+ */
33
+ const ROTATION_FILE = 'rotation.json';
34
+ const STRAY_TEMP = /^(?:rotation|key|approval-pending)\.json\.(\d+)\.[0-9a-f]{12}\.tmp$/;
35
+ /** The mode of a grant.json that is a regular file and not owner-only, else undefined. */
36
+ function looseGrantMode() {
37
+ try {
38
+ const stat = fs.lstatSync(path.join(profileDir(), 'grant.json'));
39
+ return stat.isFile() && (stat.mode & 0o077) !== 0 ? (stat.mode & 0o777).toString(8) : undefined;
40
+ }
41
+ catch {
42
+ return undefined;
43
+ }
44
+ }
45
+ /**
46
+ * A saved grant is a regular grant.json that parses and has the shape of a grant (the existing `loadGrant`). A truncated or corrupt file,
47
+ * or a path that is not a file, is not a saved grant: it is left as it is, counted as absent, and reported once. A grant.json that has the
48
+ * shape of a grant but a loose mode IS a saved grant (it is never counted absent); `DerivedState.grantMode` tells init to stop until
49
+ * its mode is fixed.
50
+ */
51
+ function savedGrant(notes) {
52
+ const file = path.join(profileDir(), 'grant.json');
53
+ if (!fs.existsSync(file))
54
+ return false;
55
+ if (looseGrantMode()) {
56
+ // Inspect the content before any mode advice: only a file that is a grant has a mode worth fixing.
57
+ try {
58
+ const grant = JSON.parse(readRegularFile(file) ?? 'null');
59
+ if (grant?.v === 1 && !!grant.delegationHeader?.Authorization && !!grant.delegationCid && !!grant.siwe)
60
+ return true;
61
+ }
62
+ catch { /* not JSON: reported below, without the parser's message */ }
63
+ notes.push('grant.json is not a usable saved grant, so it is treated as not saved and left as it is (it is corrupt or not a grant).');
64
+ return false;
65
+ }
66
+ try {
67
+ return loadGrant() !== undefined;
68
+ }
69
+ catch (error) {
70
+ notes.push(`grant.json is not a usable saved grant, so it is treated as not saved and left as it is (${error.message}).`);
71
+ return false;
72
+ }
73
+ }
74
+ export const heldApproval = (approval) => approval === 'held' || approval === 'committed';
75
+ const liveApproval = (approval) => approval === 'open' || approval === 'unreadable' || heldApproval(approval);
76
+ /**
77
+ * Whether `init --wait` goes on (collects a saved approval, or makes the request) rather than advising another command. It follows from the
78
+ * same inputs and action as everything else here: an approval the owner gave (retryable result reference, saved result or commit) is
79
+ * always collected, even beside a saved grant; an open request is collected while the space is being set up; otherwise `--wait` goes on
80
+ * only where the action is waiting, requesting or starting, and advises `--resume` for a grant saved and not installed.
81
+ */
82
+ function waitGoesOn(i, action) {
83
+ if (action === 'refuse' || action === 'finish-rotation' || action === 'fix-profile')
84
+ return false;
85
+ if (heldApproval(i.approval))
86
+ return true;
87
+ // As before: on a profile that has a grant (ready) or is setting up its space, `--wait` only collects a request that is saved.
88
+ if (i.profile === 'awaiting-space' || i.profile === 'ready')
89
+ return i.approval === 'open';
90
+ return action === 'wait' || action === 'request' || action === 'init';
91
+ }
92
+ export function classifyState(i) {
93
+ const is = (state, action) => ({ state, action, cleanTemp: i.rotationTemp, wait: waitGoesOn(i, action) });
94
+ if (i.rotation)
95
+ return is('rotation-interrupted', 'finish-rotation');
96
+ if (i.profile === 'unreadable')
97
+ return is('profile-unreadable', 'fix-profile');
98
+ // A saved approval without the profile or key it belongs to is never dropped here: the person decides.
99
+ if (liveApproval(i.approval) && lacksOwner({ profile: i.profile !== 'absent', key: i.key }))
100
+ return is('approval-orphaned', 'refuse');
101
+ if (i.profile === 'absent')
102
+ return i.key ? is('key-only', 'init') : is('new', 'init');
103
+ if (!i.key)
104
+ return is('key-missing', 'rotate-key');
105
+ if (i.profile === 'awaiting-grant') {
106
+ // A grant saved and not installed is installed first (`--resume`); a held approval beside it stays on disk for the next `--wait`.
107
+ if (i.pendingGrant)
108
+ return is('saved-delegation', 'resume');
109
+ if (i.grant)
110
+ return is('saved-grant', 'resume');
111
+ // With nothing saved to install, an approval the owner gave is collected, never discarded.
112
+ if (heldApproval(i.approval))
113
+ return is('approval-held', 'wait');
114
+ if (i.approval === 'open')
115
+ return is('approval-open', 'wait');
116
+ if (i.approval === 'unreadable')
117
+ return is('approval-unreadable', 'fix-approval');
118
+ return is('awaiting-grant', 'request');
119
+ }
120
+ if (i.profile === 'awaiting-space') {
121
+ if (!i.grant)
122
+ return heldApproval(i.approval) ? is('approval-held', 'wait') : is('grant-missing', 'request');
123
+ return i.spacePending ? is('space-pending', 'resume') : is('space-missing', 'resume');
124
+ }
125
+ // ready: a held renewal is collected by `--wait`; `--resume` stays refused on a ready profile, as before.
126
+ if (heldApproval(i.approval))
127
+ return is('ready-approval', 'wait');
128
+ if (i.approval === 'unreadable')
129
+ return is('approval-unreadable', 'fix-approval');
130
+ if (!i.grant)
131
+ return is('grant-missing', 'request');
132
+ if (i.approval === 'open')
133
+ return is('ready-approval', 'wait');
134
+ return is('ready', 'none');
135
+ }
136
+ /** The approval input of the state table, taken from the one classifier. */
137
+ function approvalState() {
138
+ const phase = approvalPhase(readApprovalEntry());
139
+ switch (phase.phase) {
140
+ case 'held': return phase.stage === 'committed' ? 'committed' : 'held';
141
+ case 'orphaned': return 'none';
142
+ default: return phase.phase;
143
+ }
144
+ }
145
+ const rotationPath = () => path.join(profileDir(), ROTATION_FILE);
146
+ /**
147
+ * The profile's status and spacePending, read without validating the rest (an outdated profile is the job of the mode that loads it).
148
+ * A profile.json that exists and cannot be read, or has no usable status, is `unreadable`: never the same as absent.
149
+ */
150
+ function readProfileFields() {
151
+ if (!fs.existsSync(path.join(profileDir(), 'profile.json')))
152
+ return { status: 'absent', spacePending: false };
153
+ try {
154
+ const profile = readSecure('profile.json', false);
155
+ const status = profile?.status;
156
+ if (status === 'awaiting-grant' || status === 'awaiting-space' || status === 'ready')
157
+ return { status, spacePending: profile?.spacePending === true };
158
+ }
159
+ catch { /* unreadable */ }
160
+ return { status: 'unreadable', spacePending: false };
161
+ }
162
+ /** `text` as one POSIX shell word. */
163
+ function shellQuote(text) {
164
+ return `'${text.replace(/'/g, `'\\''`)}'`;
165
+ }
166
+ /** Whether the process that named a temp file may still be writing it. This process is not: its writes are synchronous and finished. */
167
+ function writerAlive(pid) {
168
+ if (pid === process.pid)
169
+ return false;
170
+ try {
171
+ process.kill(pid, 0);
172
+ return true;
173
+ }
174
+ catch (error) {
175
+ return error.code === 'EPERM';
176
+ }
177
+ }
178
+ /**
179
+ * The stray temp files, classified from ONE directory listing with ONE liveness probe per file: `dead` (writer gone: the only ones
180
+ * `recoverInterrupted` removes) and `live` (writer may still be running: kept, because between its fsync and its rename the file is live).
181
+ * A caller acts on this one snapshot, so a process that dies or whose pid is reused between two probes cannot split the decision.
182
+ */
183
+ function classifyTemps() {
184
+ const dead = [];
185
+ const live = [];
186
+ let names = [];
187
+ try {
188
+ names = fs.readdirSync(profileDir()).sort();
189
+ }
190
+ catch { /* no home yet */ }
191
+ for (const name of names) {
192
+ const match = STRAY_TEMP.exec(name);
193
+ if (!match)
194
+ continue;
195
+ const pid = Number(match[1]);
196
+ if (writerAlive(pid))
197
+ live.push({ name, pid });
198
+ else
199
+ dead.push(name);
200
+ }
201
+ return { dead, live };
202
+ }
203
+ /** The one place the inputs are read. Reads only. `notes` are warnings the init mode prints once; nothing is repaired or removed. */
204
+ export function readInputs(notes = []) {
205
+ const dir = profileDir();
206
+ const { status, spacePending } = readProfileFields();
207
+ return {
208
+ profile: status,
209
+ spacePending,
210
+ grant: savedGrant(notes),
211
+ key: fs.existsSync(path.join(dir, 'key.json')),
212
+ pendingGrant: hasLivePending(),
213
+ approval: approvalState(),
214
+ rotation: fs.existsSync(rotationPath()),
215
+ rotationTemp: classifyTemps().dead.length > 0,
216
+ };
217
+ }
218
+ export function deriveState() {
219
+ const notes = [];
220
+ const inputs = readInputs(notes);
221
+ const grantMode = inputs.grant ? looseGrantMode() : undefined;
222
+ return { inputs, notes, ...(grantMode ? { grantMode } : {}), ...classifyState(inputs) };
223
+ }
224
+ /** Which mode to restore depends on what is loose: the profile directory is 0700, a private file inside it 0600. */
225
+ function permissionAdvice(name) {
226
+ return `If the directory is loose, run \`chmod 700 ${profileDir()}\`; if the file is loose, run \`chmod 600 ${path.join(profileDir(), name)}\`.`;
227
+ }
228
+ function orphanAdvice(approval) {
229
+ const file = path.join(profileDir(), APPROVAL_FILE);
230
+ const left = `A saved approval request (${file}) has no matching profile and agent key. It was left as it is and nothing was changed.`;
231
+ if (approval === 'unreadable')
232
+ return `${left} The request cannot be read. ${permissionAdvice(APPROVAL_FILE)} Then run the command again.`;
233
+ if (approval === 'open')
234
+ return `${left} Restore the missing file, or run \`${cmd('init --rotate-key')}\` to start over with a new agent key.`;
235
+ return `${left} Restore the missing file, or run \`${cmd('init --rotate-key')}\`, which discards that approval and starts over with a new agent key.`;
236
+ }
237
+ /** The next command for the person or agent running init. */
238
+ export function adviceFor(d) {
239
+ switch (d.state) {
240
+ case 'rotation-interrupted': return `A key rotation was interrupted. Any \`${cmd('init')}\` command finishes it first.`;
241
+ case 'profile-unreadable': return `${path.join(profileDir(), 'profile.json')} cannot be read, so nothing was changed. ${permissionAdvice('profile.json')} If its content is damaged, \`${cmd('init --rotate-key')}\` replaces the agent key and the profile with new ones.`;
242
+ case 'approval-orphaned': return orphanAdvice(d.inputs.approval);
243
+ case 'new':
244
+ case 'key-only': return `No Courier profile yet. Run \`${cmd('init --request')}\`, send the printed openkeyUrl to the owner, then run \`${cmd('init --wait')}\`.`;
245
+ case 'key-missing': return `The profile has no agent key. Run \`${cmd('init --rotate-key')}\` and approve a new grant.`;
246
+ case 'saved-delegation':
247
+ case 'saved-grant': return `An approved grant is saved and not installed: run \`${cmd('init --resume')}\`. No new approval is needed.`;
248
+ case 'approval-held': return `An approval from the owner is saved: run \`${cmd('init --wait')}\`. No new approval is needed.`;
249
+ case 'approval-open': return `An approval request is open: run \`${cmd('init --wait')}\` to collect it once the owner approves.`;
250
+ case 'approval-unreadable': return `The saved approval request cannot be read. ${permissionAdvice(APPROVAL_FILE)} Then run \`${cmd('init --wait')}\`.`;
251
+ case 'awaiting-grant': return `No grant yet. Run \`${cmd('init --request')}\`, send the printed openkeyUrl to the owner, then run \`${cmd('init --wait')}\`.`;
252
+ case 'grant-missing': return d.inputs.profile === 'ready'
253
+ ? `This profile already has a grant and no approval request is pending. To renew it, run \`${cmd('init --request')}\`, send the printed openkeyUrl to the owner, then run \`${cmd('init --wait')}\`.`
254
+ : `The grant is saved and the "agents" space is still being set up: run \`${cmd('init --resume')}\`. \`${cmd('init --wait')}\` collects an approval that \`${cmd('init --request')}\` asked for.`;
255
+ case 'space-pending':
256
+ case 'space-missing': return `The grant is saved and the agents space is still being set up: run \`${cmd('init --resume')}\`. \`${cmd('init --wait')}\` collects an approval that \`${cmd('init --request')}\` asked for.`;
257
+ case 'ready-approval': return `An approval request is saved: run \`${cmd('init --wait')}\` to collect or acknowledge it.`;
258
+ case 'ready': return `This profile already has a grant and no approval request is pending. To renew it, run \`${cmd('init --request')}\`, send the printed openkeyUrl to the owner, then run \`${cmd('init --wait')}\`.`;
259
+ }
260
+ }
261
+ // ---------- recovery ----------
262
+ /**
263
+ * Explicit recovery, run once at the start of an init mode: roll an interrupted rotation forward (only after the journal validated), then
264
+ * remove stray key-bearing temp files. A refusal in the first step happens before anything is changed.
265
+ */
266
+ export function recoverInterrupted() {
267
+ finishRotation();
268
+ const temps = classifyTemps();
269
+ for (const name of temps.dead)
270
+ scrub(path.join(profileDir(), name));
271
+ for (const { name, pid } of temps.live) {
272
+ const file = path.join(profileDir(), name);
273
+ // A running pid does not excuse a file that is not a plain single-link file of this user: that is refused, as for a dead writer.
274
+ let stat;
275
+ try {
276
+ stat = fs.lstatSync(file);
277
+ }
278
+ catch (error) {
279
+ // The writer finished and renamed it into place after the listing: it has moved, there is nothing to keep or refuse.
280
+ if (error.code === 'ENOENT')
281
+ continue;
282
+ throw error;
283
+ }
284
+ if (!isPlain(stat))
285
+ throw refuseStray(file);
286
+ console.error(`warning: ${name} was kept, not deleted, and may contain private-key material (an agent key, or an approval's relay key and result). Process ${pid}, which named it, is running: either a Courier process still writing it, or an unrelated process that was given the same pid after Courier died (pid reuse); Courier cannot tell which. Check with \`ps -p ${pid} -o pid=,args=\`; only if that is not a Courier process, remove the file with \`rm -- ${shellQuote(file)}\`.`);
287
+ }
288
+ }
289
+ /**
290
+ * A stray temp file may hold a private key. Only a plain file of this user with a single link is touched, and it is checked again on the
291
+ * open descriptor so a swap between the check and the open is caught: its bytes are overwritten with zeros (best effort: a copy-on-write or
292
+ * journaling filesystem may keep old blocks) and it is unlinked. Anything else is left as it is and reported.
293
+ */
294
+ const isPlain = (stat) => stat.isFile() && stat.uid === process.getuid?.() && stat.nlink === 1;
295
+ const refuseStray = (file) => new CourierError('stray-temp', `${file} is not a plain file of this user with one link, so it was left as it is. Remove it by hand, then run the command again.`);
296
+ function scrub(file) {
297
+ const before = fs.lstatSync(file);
298
+ if (!isPlain(before))
299
+ throw refuseStray(file);
300
+ const fd = fs.openSync(file, fs.constants.O_WRONLY | fs.constants.O_NOFOLLOW);
301
+ try {
302
+ const open = fs.fstatSync(fd);
303
+ if (!isPlain(open) || open.dev !== before.dev || open.ino !== before.ino)
304
+ throw refuseStray(file);
305
+ fs.writeSync(fd, Buffer.alloc(open.size));
306
+ fs.fsyncSync(fd);
307
+ }
308
+ finally {
309
+ fs.closeSync(fd);
310
+ }
311
+ fs.unlinkSync(file);
312
+ syncDir();
313
+ }
314
+ function syncDir() {
315
+ const dir = fs.openSync(profileDir(), 'r');
316
+ try {
317
+ fs.fsyncSync(dir);
318
+ }
319
+ finally {
320
+ fs.closeSync(dir);
321
+ }
322
+ }
323
+ const validGrantList = (list) => Array.isArray(list)
324
+ && list.every((g) => !!g && typeof g === 'object' && typeof g.delegationCid === 'string' && g.delegationCid !== '' && (g.expiresAt === undefined || typeof g.expiresAt === 'string'));
325
+ /**
326
+ * Whether a key is an Ed25519 agent key as `newAgentKey` makes one: a plain-object JWK with kty OKP, crv Ed25519, and `x` and `d` as
327
+ * unpadded base64url text of exactly 32 bytes, where `x` is the public key of `d`, and the `did:key` is the one derived from `x`
328
+ * (a `#fragment`, when present, names the same key).
329
+ */
330
+ function hasKeyProof(key) {
331
+ const jwk = key.jwk;
332
+ if (Array.isArray(jwk) || jwk.kty !== 'OKP' || jwk.crv !== 'Ed25519')
333
+ return false;
334
+ const x = base64url32(jwk.x);
335
+ const d = base64url32(jwk.d);
336
+ if (!x || !d || !x.equals(ed25519PublicKey(d)))
337
+ return false;
338
+ const did = ed25519DidKey(x);
339
+ const parts = key.did.split('#');
340
+ return parts.length <= 2 && parts[0] === did && (parts.length === 1 || parts[1] === did.slice('did:key:'.length));
341
+ }
342
+ /** What is wrong with a parsed journal, or undefined when it is a rotation this code may replay. Never includes any of its content. */
343
+ function journalProblem(journal) {
344
+ if (!journal || typeof journal !== 'object' || Array.isArray(journal))
345
+ return 'it is not an object';
346
+ const j = journal;
347
+ if (j.v !== 1)
348
+ return 'its version is not 1';
349
+ if (!isAgentKey(j.key) || !hasKeyProof(j.key))
350
+ return 'its key is not a valid agent key';
351
+ if (!hasProfileFields(j.profile ?? null))
352
+ return 'its profile is not a complete current profile';
353
+ if (j.profile?.status !== 'awaiting-grant')
354
+ return 'its profile is not awaiting-grant';
355
+ if (j.profile.courierDid !== bareDid(j.key.did))
356
+ return 'its profile does not belong to its key';
357
+ if (typeof j.discardApproval !== 'boolean' || typeof j.grantedResult !== 'boolean')
358
+ return 'its approval facts are not booleans';
359
+ if (j.delegationCid !== undefined && typeof j.delegationCid !== 'string')
360
+ return 'its delegation is not text';
361
+ if (j.grantExpiresAt !== undefined && typeof j.grantExpiresAt !== 'string')
362
+ return 'its grant expiry is not text';
363
+ if (j.discardedGrants !== undefined && !validGrantList(j.discardedGrants))
364
+ return 'its discarded grants are not a list of delegations';
365
+ if (j.unmatchedGrants !== undefined && !validGrantList(j.unmatchedGrants))
366
+ return 'its unmatched grants are not a list of delegations';
367
+ if (j.installedGrant !== undefined && !validGrantList([j.installedGrant]))
368
+ return 'its installed grant is not a delegation';
369
+ return undefined;
370
+ }
371
+ /** The non-secret facts about the saved approval, taken before the journal is written. */
372
+ async function approvalFacts() {
373
+ const entry = readApprovalEntry();
374
+ const phase = approvalPhase(entry);
375
+ if (phase.phase !== 'held' || entry.kind !== 'ok')
376
+ return { discardApproval: false, grantedResult: false };
377
+ const pending = entry.pending;
378
+ // A collected result or a commit means the owner approved and a grant may be live; a reference alone is not yet a result.
379
+ const grantedResult = phase.stage !== 'ref';
380
+ let delegationCid;
381
+ let grantExpiresAt;
382
+ if (grantedResult) {
383
+ try {
384
+ const opened = await openRelayResult(resultEnvelopeOf(pending), pending.requestId, pending.relayPrivateKey);
385
+ const claimed = opened.delegation?.delegationCid;
386
+ if (typeof claimed === 'string' && claimed !== '')
387
+ delegationCid = claimed;
388
+ grantExpiresAt = checkApprovalResultBinding(opened, { requestId: pending.requestId, bodyCid: pending.bodyCid, request: pending.request }).delegationExpiresAt;
389
+ }
390
+ catch { /* the notice is still given, with what could be read */ }
391
+ }
392
+ return { discardApproval: true, grantedResult, ...(delegationCid ? { delegationCid } : {}), ...(grantExpiresAt ? { grantExpiresAt } : {}) };
393
+ }
394
+ /** The non-secret facts (CID, expiry) of a saved delegation, or undefined when it names no CID. */
395
+ function grantFacts(cid, expiresAt) {
396
+ if (typeof cid !== 'string' || cid === '')
397
+ return undefined;
398
+ let until;
399
+ try {
400
+ until = expiresAt()?.toISOString();
401
+ }
402
+ catch { /* unknown */ }
403
+ return { delegationCid: cid, ...(until ? { expiresAt: until } : {}) };
404
+ }
405
+ /**
406
+ * Redeemed delegations saved for the OLD agent key: they would be useless after the rotation and may be live grants (`discarded`).
407
+ * When key.json cannot be read no delegation can be tied to a key: they are `unmatched`, kept as they are and reported, never dropped.
408
+ */
409
+ function oldKeyDelegations() {
410
+ let old;
411
+ try {
412
+ old = loadKey();
413
+ }
414
+ catch {
415
+ old = undefined;
416
+ }
417
+ const discarded = [];
418
+ const unmatched = [];
419
+ for (const delegation of liveRedeemedDelegations()) {
420
+ if (old) {
421
+ try {
422
+ assertBoundToKey(delegation, old);
423
+ }
424
+ catch {
425
+ continue;
426
+ }
427
+ }
428
+ const facts = grantFacts(delegation.delegationCid, () => siweTimes(delegation.siwe).expiresAt);
429
+ if (facts)
430
+ (old ? discarded : unmatched).push(facts);
431
+ }
432
+ return { discarded, unmatched };
433
+ }
434
+ /** The installed grant.json's CID and expiry, read before the rotation removes it. Reads it even at a loose mode; nothing secret is kept. */
435
+ function installedGrantFacts() {
436
+ try {
437
+ const grant = JSON.parse(readRegularFile(path.join(profileDir(), 'grant.json')) ?? 'null');
438
+ return grantFacts(grant?.delegationCid, () => {
439
+ if (typeof grant?.siwe === 'string')
440
+ return siweTimes(grant.siwe).expiresAt;
441
+ return typeof grant?.expiresAt === 'string' ? new Date(grant.expiresAt) : undefined;
442
+ });
443
+ }
444
+ catch {
445
+ return undefined;
446
+ }
447
+ }
448
+ /** Steps 1-5. `profile` is the complete new profile. */
449
+ export async function rotateKey(key, profile) {
450
+ const { discarded, unmatched } = oldKeyDelegations();
451
+ const installed = installedGrantFacts();
452
+ const journal = {
453
+ v: 1, key, profile, ...(await approvalFacts()), discardedGrants: discarded,
454
+ ...(unmatched.length > 0 ? { unmatchedGrants: unmatched } : {}), ...(installed ? { installedGrant: installed } : {}),
455
+ };
456
+ writeSecure(rotationPath(), journal);
457
+ applyRotation(journal);
458
+ }
459
+ function removeIfPresent(file) {
460
+ try {
461
+ fs.unlinkSync(file);
462
+ }
463
+ catch (error) {
464
+ if (error.code !== 'ENOENT')
465
+ throw error;
466
+ }
467
+ }
468
+ function applyRotation(journal) {
469
+ saveKey(journal.key);
470
+ saveProfile(journal.profile);
471
+ removeIfPresent(path.join(profileDir(), 'grant.json'));
472
+ if (journal.discardApproval)
473
+ clearPending();
474
+ for (const grant of journal.discardedGrants ?? [])
475
+ dropPendingDelegation(grant.delegationCid);
476
+ syncDir();
477
+ warnDiscarded(journal);
478
+ fs.unlinkSync(rotationPath());
479
+ syncDir();
480
+ }
481
+ const untilText = (expiresAt) => (expiresAt ? `, valid until ${expiresAt}` : '');
482
+ /** Printed from the journal, so any init mode that finishes the rotation, also after a crash, says the same thing. */
483
+ function warnDiscarded(journal) {
484
+ if (journal.discardApproval) {
485
+ console.error('The saved approval request already held an approval from the owner. It is bound to the old agent key, so this key rotation discards that approval: the owner must approve a new request.');
486
+ }
487
+ if (journal.discardApproval && journal.grantedResult) {
488
+ const named = journal.delegationCid ? ` (delegation ${journal.delegationCid})` : '';
489
+ console.error(`That request was already granted by the owner${named}, so a live grant may exist${untilText(journal.grantExpiresAt)}. This agent cannot revoke it; the owner can revoke it at ${REVOKE_URL}.`);
490
+ }
491
+ for (const grant of journal.discardedGrants ?? []) {
492
+ console.error(`A redeemed grant saved for the old agent key and not installed (delegation ${grant.delegationCid}) was discarded by this key rotation. A live grant may exist${untilText(grant.expiresAt)}. This agent cannot revoke it; the owner can revoke it at ${REVOKE_URL}.`);
493
+ }
494
+ for (const grant of journal.unmatchedGrants ?? []) {
495
+ console.error(`A redeemed grant saved in pending-grant.json (delegation ${grant.delegationCid}) could not be matched to the old agent key (key.json cannot be read), so it was kept as it is. A live grant may exist${untilText(grant.expiresAt)}. This agent cannot revoke it; the owner can revoke it at ${REVOKE_URL}.`);
496
+ }
497
+ // The grant installed for the old key was removed, not revoked: the invoking command and one that finishes the rotation both say so.
498
+ if (journal.installedGrant) {
499
+ const { delegationCid, expiresAt } = journal.installedGrant;
500
+ const until = expiresAt ? `until ${expiresAt}` : 'until it expires';
501
+ console.error(`The installed grant for the old agent key (delegation ${delegationCid}) was removed by this key rotation. It is not revoked: it may still be valid ${until}. This agent cannot revoke it; the owner can revoke it at ${REVOKE_URL}.`);
502
+ }
503
+ }
504
+ /** Roll an interrupted rotation forward. Returns whether one was found. Refuses, changing nothing, when the record is not a valid rotation. */
505
+ export function finishRotation() {
506
+ if (!fs.existsSync(rotationPath()))
507
+ return false;
508
+ const journal = readSecure(ROTATION_FILE, true);
509
+ const problem = journalProblem(journal);
510
+ if (problem) {
511
+ throw new CourierError('bad-profile', `${rotationPath()} is not a valid key rotation record (${problem}). Nothing was changed. Restore it from a backup, or move it aside and run \`${cmd('init --rotate-key')}\` to start over with a new agent key.`);
512
+ }
513
+ applyRotation(journal);
514
+ return true;
515
+ }
516
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,UAAU,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE5J,OAAO,EAAE,0BAA0B,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAC9F,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAClI,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAC9F,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAE5E;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,aAAa,GAAG,eAAe,CAAC;AACtC,MAAM,UAAU,GAAG,qEAAqE,CAAC;AAsCzF,0FAA0F;AAC1F,SAAS,cAAc;IACrB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,YAAY,CAAC,CAAC,CAAC;QACjE,OAAO,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAClG,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,SAAS,CAAC;IAAC,CAAC;AAC/B,CAAC;AAED;;;;;GAKG;AACH,SAAS,UAAU,CAAC,KAAe;IACjC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,YAAY,CAAC,CAAC;IACnD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACvC,IAAI,cAAc,EAAE,EAAE,CAAC;QACrB,mGAAmG;QACnG,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,MAAM,CAAoH,CAAC;YAC7K,IAAI,KAAK,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,gBAAgB,EAAE,aAAa,IAAI,CAAC,CAAC,KAAK,CAAC,aAAa,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI;gBAAE,OAAO,IAAI,CAAC;QACtH,CAAC;QAAC,MAAM,CAAC,CAAC,4DAA4D,CAAC,CAAC;QACxE,KAAK,CAAC,IAAI,CAAC,yHAAyH,CAAC,CAAC;QACtI,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,CAAC;QACH,OAAO,SAAS,EAAE,KAAK,SAAS,CAAC;IACnC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,4FAA6F,KAAe,CAAC,OAAO,IAAI,CAAC,CAAC;QACrI,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,QAAuB,EAAW,EAAE,CAAC,QAAQ,KAAK,MAAM,IAAI,QAAQ,KAAK,WAAW,CAAC;AAClH,MAAM,YAAY,GAAG,CAAC,QAAuB,EAAW,EAAE,CAAC,QAAQ,KAAK,MAAM,IAAI,QAAQ,KAAK,YAAY,IAAI,YAAY,CAAC,QAAQ,CAAC,CAAC;AAEtI;;;;;GAKG;AACH,SAAS,UAAU,CAAC,CAAc,EAAE,MAAmB;IACrD,IAAI,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,iBAAiB,IAAI,MAAM,KAAK,aAAa;QAAE,OAAO,KAAK,CAAC;IAClG,IAAI,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1C,+HAA+H;IAC/H,IAAI,CAAC,CAAC,OAAO,KAAK,gBAAgB,IAAI,CAAC,CAAC,OAAO,KAAK,OAAO;QAAE,OAAO,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC;IAC1F,OAAO,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,MAAM,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,CAAc;IAC1C,MAAM,EAAE,GAAG,CAAC,KAAgB,EAAE,MAAmB,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC,YAAY,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IAClI,IAAI,CAAC,CAAC,QAAQ;QAAE,OAAO,EAAE,CAAC,sBAAsB,EAAE,iBAAiB,CAAC,CAAC;IACrE,IAAI,CAAC,CAAC,OAAO,KAAK,YAAY;QAAE,OAAO,EAAE,CAAC,oBAAoB,EAAE,aAAa,CAAC,CAAC;IAC/E,uGAAuG;IACvG,IAAI,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,KAAK,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC;QAAE,OAAO,EAAE,CAAC,mBAAmB,EAAE,QAAQ,CAAC,CAAC;IACtI,IAAI,CAAC,CAAC,OAAO,KAAK,QAAQ;QAAE,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACtF,IAAI,CAAC,CAAC,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;IACnD,IAAI,CAAC,CAAC,OAAO,KAAK,gBAAgB,EAAE,CAAC;QACnC,kIAAkI;QAClI,IAAI,CAAC,CAAC,YAAY;YAAE,OAAO,EAAE,CAAC,kBAAkB,EAAE,QAAQ,CAAC,CAAC;QAC5D,IAAI,CAAC,CAAC,KAAK;YAAE,OAAO,EAAE,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;QAChD,2FAA2F;QAC3F,IAAI,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC;YAAE,OAAO,EAAE,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;QACjE,IAAI,CAAC,CAAC,QAAQ,KAAK,MAAM;YAAE,OAAO,EAAE,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;QAC9D,IAAI,CAAC,CAAC,QAAQ,KAAK,YAAY;YAAE,OAAO,EAAE,CAAC,qBAAqB,EAAE,cAAc,CAAC,CAAC;QAClF,OAAO,EAAE,CAAC,gBAAgB,EAAE,SAAS,CAAC,CAAC;IACzC,CAAC;IACD,IAAI,CAAC,CAAC,OAAO,KAAK,gBAAgB,EAAE,CAAC;QACnC,IAAI,CAAC,CAAC,CAAC,KAAK;YAAE,OAAO,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,eAAe,EAAE,SAAS,CAAC,CAAC;QAC7G,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;IACxF,CAAC;IACD,0GAA0G;IAC1G,IAAI,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC;IAClE,IAAI,CAAC,CAAC,QAAQ,KAAK,YAAY;QAAE,OAAO,EAAE,CAAC,qBAAqB,EAAE,cAAc,CAAC,CAAC;IAClF,IAAI,CAAC,CAAC,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC,eAAe,EAAE,SAAS,CAAC,CAAC;IACpD,IAAI,CAAC,CAAC,QAAQ,KAAK,MAAM;QAAE,OAAO,EAAE,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC;IAC/D,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AAC7B,CAAC;AAED,4EAA4E;AAC5E,SAAS,aAAa;IACpB,MAAM,KAAK,GAAG,aAAa,CAAC,iBAAiB,EAAE,CAAC,CAAC;IACjD,QAAQ,KAAK,CAAC,KAAK,EAAE,CAAC;QACpB,KAAK,MAAM,CAAC,CAAC,OAAO,KAAK,CAAC,KAAK,KAAK,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC;QACvE,KAAK,UAAU,CAAC,CAAC,OAAO,MAAM,CAAC;QAC/B,OAAO,CAAC,CAAC,OAAO,KAAK,CAAC,KAAK,CAAC;IAC9B,CAAC;AACH,CAAC;AAED,MAAM,YAAY,GAAG,GAAW,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,aAAa,CAAC,CAAC;AAE1E;;;GAGG;AACH,SAAS,iBAAiB;IACxB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,cAAc,CAAC,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;IAC9G,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,UAAU,CAA+C,cAAc,EAAE,KAAK,CAAC,CAAC;QAChG,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC;QAC/B,IAAI,MAAM,KAAK,gBAAgB,IAAI,MAAM,KAAK,gBAAgB,IAAI,MAAM,KAAK,OAAO;YAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,KAAK,IAAI,EAAE,CAAC;IACxJ,CAAC;IAAC,MAAM,CAAC,CAAC,gBAAgB,CAAC,CAAC;IAC5B,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;AACvD,CAAC;AAED,sCAAsC;AACtC,SAAS,UAAU,CAAC,IAAY;IAC9B,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC;AAC5C,CAAC;AAED,wIAAwI;AACxI,SAAS,WAAW,CAAC,GAAW;IAC9B,IAAI,GAAG,KAAK,OAAO,CAAC,GAAG;QAAE,OAAO,KAAK,CAAC;IACtC,IAAI,CAAC;QAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAAC,OAAO,IAAI,CAAC;IAAC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAAC,OAAQ,KAA+B,CAAC,IAAI,KAAK,OAAO,CAAC;IAAC,CAAC;AACxH,CAAC;AAED;;;;GAIG;AACH,SAAS,aAAa;IACpB,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,MAAM,IAAI,GAAoC,EAAE,CAAC;IACjD,IAAI,KAAK,GAAa,EAAE,CAAC;IACzB,IAAI,CAAC;QAAC,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,UAAU,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;IAChF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,CAAC,KAAK;YAAE,SAAS;QACrB,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7B,IAAI,WAAW,CAAC,GAAG,CAAC;YAAE,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;;YAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvE,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AACxB,CAAC;AAED,qIAAqI;AACrI,MAAM,UAAU,UAAU,CAAC,QAAkB,EAAE;IAC7C,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;IACzB,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,iBAAiB,EAAE,CAAC;IACrD,OAAO;QACL,OAAO,EAAE,MAAM;QACf,YAAY;QACZ,KAAK,EAAE,UAAU,CAAC,KAAK,CAAC;QACxB,GAAG,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;QAC9C,YAAY,EAAE,cAAc,EAAE;QAC9B,QAAQ,EAAE,aAAa,EAAE;QACzB,QAAQ,EAAE,EAAE,CAAC,UAAU,CAAC,YAAY,EAAE,CAAC;QACvC,YAAY,EAAE,aAAa,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC;KAC9C,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IACjC,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAC9D,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;AAC1F,CAAC;AAED,oHAAoH;AACpH,SAAS,gBAAgB,CAAC,IAAY;IACpC,OAAO,8CAA8C,UAAU,EAAE,6CAA6C,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC;AACnJ,CAAC;AAED,SAAS,YAAY,CAAC,QAAuB;IAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,aAAa,CAAC,CAAC;IACpD,MAAM,IAAI,GAAG,6BAA6B,IAAI,wFAAwF,CAAC;IACvI,IAAI,QAAQ,KAAK,YAAY;QAAE,OAAO,GAAG,IAAI,gCAAgC,gBAAgB,CAAC,aAAa,CAAC,8BAA8B,CAAC;IAC3I,IAAI,QAAQ,KAAK,MAAM;QAAE,OAAO,GAAG,IAAI,uCAAuC,GAAG,CAAC,mBAAmB,CAAC,wCAAwC,CAAC;IAC/I,OAAO,GAAG,IAAI,uCAAuC,GAAG,CAAC,mBAAmB,CAAC,wEAAwE,CAAC;AACxJ,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,SAAS,CAAC,CAAyC;IACjE,QAAQ,CAAC,CAAC,KAAK,EAAE,CAAC;QAChB,KAAK,sBAAsB,CAAC,CAAC,OAAO,yCAAyC,GAAG,CAAC,MAAM,CAAC,+BAA+B,CAAC;QACxH,KAAK,oBAAoB,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,cAAc,CAAC,4CAA4C,gBAAgB,CAAC,cAAc,CAAC,iCAAiC,GAAG,CAAC,mBAAmB,CAAC,0DAA0D,CAAC;QAC5Q,KAAK,mBAAmB,CAAC,CAAC,OAAO,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACjE,KAAK,KAAK,CAAC;QACX,KAAK,UAAU,CAAC,CAAC,OAAO,iCAAiC,GAAG,CAAC,gBAAgB,CAAC,4DAA4D,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC;QAClK,KAAK,aAAa,CAAC,CAAC,OAAO,uCAAuC,GAAG,CAAC,mBAAmB,CAAC,6BAA6B,CAAC;QACxH,KAAK,kBAAkB,CAAC;QACxB,KAAK,aAAa,CAAC,CAAC,OAAO,uDAAuD,GAAG,CAAC,eAAe,CAAC,gCAAgC,CAAC;QACvI,KAAK,eAAe,CAAC,CAAC,OAAO,8CAA8C,GAAG,CAAC,aAAa,CAAC,gCAAgC,CAAC;QAC9H,KAAK,eAAe,CAAC,CAAC,OAAO,sCAAsC,GAAG,CAAC,aAAa,CAAC,2CAA2C,CAAC;QACjI,KAAK,qBAAqB,CAAC,CAAC,OAAO,8CAA8C,gBAAgB,CAAC,aAAa,CAAC,eAAe,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC;QACvJ,KAAK,gBAAgB,CAAC,CAAC,OAAO,uBAAuB,GAAG,CAAC,gBAAgB,CAAC,4DAA4D,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC;QAC9J,KAAK,eAAe,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,OAAO,KAAK,OAAO;YACvD,CAAC,CAAC,2FAA2F,GAAG,CAAC,gBAAgB,CAAC,4DAA4D,GAAG,CAAC,aAAa,CAAC,KAAK;YACrM,CAAC,CAAC,0EAA0E,GAAG,CAAC,eAAe,CAAC,SAAS,GAAG,CAAC,aAAa,CAAC,kCAAkC,GAAG,CAAC,gBAAgB,CAAC,eAAe,CAAC;QACpM,KAAK,eAAe,CAAC;QACrB,KAAK,eAAe,CAAC,CAAC,OAAO,wEAAwE,GAAG,CAAC,eAAe,CAAC,SAAS,GAAG,CAAC,aAAa,CAAC,kCAAkC,GAAG,CAAC,gBAAgB,CAAC,eAAe,CAAC;QAC3N,KAAK,gBAAgB,CAAC,CAAC,OAAO,uCAAuC,GAAG,CAAC,aAAa,CAAC,kCAAkC,CAAC;QAC1H,KAAK,OAAO,CAAC,CAAC,OAAO,2FAA2F,GAAG,CAAC,gBAAgB,CAAC,4DAA4D,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC;IAC3N,CAAC;AACH,CAAC;AAED,iCAAiC;AAEjC;;;GAGG;AACH,MAAM,UAAU,kBAAkB;IAChC,cAAc,EAAE,CAAC;IACjB,MAAM,KAAK,GAAG,aAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;IACpE,KAAK,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,IAAI,CAAC,CAAC;QAC3C,iIAAiI;QACjI,IAAI,IAAc,CAAC;QACnB,IAAI,CAAC;YAAC,IAAI,GAAG,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAAC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChD,qHAAqH;YACrH,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;gBAAE,SAAS;YACjE,MAAM,KAAK,CAAC;QACd,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;YAAE,MAAM,WAAW,CAAC,IAAI,CAAC,CAAC;QAC5C,OAAO,CAAC,KAAK,CAAC,YAAY,IAAI,+HAA+H,GAAG,8MAA8M,GAAG,yFAAyF,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACne,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,OAAO,GAAG,CAAC,IAAc,EAAW,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC,GAAG,KAAK,OAAO,CAAC,MAAM,EAAE,EAAE,IAAI,IAAI,CAAC,KAAK,KAAK,CAAC,CAAC;AAClH,MAAM,WAAW,GAAG,CAAC,IAAY,EAAgB,EAAE,CAAC,IAAI,YAAY,CAAC,YAAY,EAAE,GAAG,IAAI,0HAA0H,CAAC,CAAC;AAEtN,SAAS,KAAK,CAAC,IAAY;IACzB,MAAM,MAAM,GAAG,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAClC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,MAAM,WAAW,CAAC,IAAI,CAAC,CAAC;IAC9C,MAAM,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,GAAG,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAC9E,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QAC9B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG,KAAK,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,KAAK,MAAM,CAAC,GAAG;YAAE,MAAM,WAAW,CAAC,IAAI,CAAC,CAAC;QAClG,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAC1C,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IACnB,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IACnB,CAAC;IACD,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IACpB,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,OAAO;IACd,MAAM,GAAG,GAAG,EAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,EAAE,GAAG,CAAC,CAAC;IAC3C,IAAI,CAAC;QAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAAC,CAAC;YAAS,CAAC;QAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAAC,CAAC;AAC3D,CAAC;AA6BD,MAAM,cAAc,GAAG,CAAC,IAAa,EAAW,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;OACjE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,aAAa,KAAK,QAAQ,IAAI,CAAC,CAAC,aAAa,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,SAAS,KAAK,SAAS,IAAI,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC;AAExL;;;;GAIG;AACH,SAAS,WAAW,CAAC,GAAa;IAChC,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IACpB,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,GAAG,KAAK,KAAK,IAAI,GAAG,CAAC,GAAG,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACnF,MAAM,CAAC,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC7B,MAAM,CAAC,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC7B,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IAC7D,MAAM,GAAG,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;IAC7B,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACjC,OAAO,KAAK,CAAC,MAAM,IAAI,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;AACpH,CAAC;AAED,uIAAuI;AACvI,SAAS,cAAc,CAAC,OAAgB;IACtC,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,OAAO,qBAAqB,CAAC;IACpG,MAAM,CAAC,GAAG,OAAmC,CAAC;IAC9C,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;QAAE,OAAO,sBAAsB,CAAC;IAC7C,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC;QAAE,OAAO,kCAAkC,CAAC;IACzF,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,OAAO,IAAI,IAAI,CAAC;QAAE,OAAO,+CAA+C,CAAC;IACjG,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,gBAAgB;QAAE,OAAO,mCAAmC,CAAC;IACvF,IAAI,CAAC,CAAC,OAAO,CAAC,UAAU,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;QAAE,OAAO,wCAAwC,CAAC;IACjG,IAAI,OAAO,CAAC,CAAC,eAAe,KAAK,SAAS,IAAI,OAAO,CAAC,CAAC,aAAa,KAAK,SAAS;QAAE,OAAO,qCAAqC,CAAC;IACjI,IAAI,CAAC,CAAC,aAAa,KAAK,SAAS,IAAI,OAAO,CAAC,CAAC,aAAa,KAAK,QAAQ;QAAE,OAAO,4BAA4B,CAAC;IAC9G,IAAI,CAAC,CAAC,cAAc,KAAK,SAAS,IAAI,OAAO,CAAC,CAAC,cAAc,KAAK,QAAQ;QAAE,OAAO,8BAA8B,CAAC;IAClH,IAAI,CAAC,CAAC,eAAe,KAAK,SAAS,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,eAAe,CAAC;QAAE,OAAO,oDAAoD,CAAC;IACvI,IAAI,CAAC,CAAC,eAAe,KAAK,SAAS,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,eAAe,CAAC;QAAE,OAAO,oDAAoD,CAAC;IACvI,IAAI,CAAC,CAAC,cAAc,KAAK,SAAS,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC;QAAE,OAAO,yCAAyC,CAAC;IAC5H,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,0FAA0F;AAC1F,KAAK,UAAU,aAAa;IAC1B,MAAM,KAAK,GAAG,iBAAiB,EAAE,CAAC;IAClC,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IACnC,IAAI,KAAK,CAAC,KAAK,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI;QAAE,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;IAC3G,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC9B,0HAA0H;IAC1H,MAAM,aAAa,GAAG,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC;IAC5C,IAAI,aAAiC,CAAC;IACtC,IAAI,cAAkC,CAAC;IACvC,IAAI,aAAa,EAAE,CAAC;QAClB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;YAC5G,MAAM,OAAO,GAAI,MAAM,CAAC,UAA6D,EAAE,aAAa,CAAC;YACrG,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,EAAE;gBAAE,aAAa,GAAG,OAAO,CAAC;YAC3E,cAAc,GAAG,0BAA0B,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,mBAAmB,CAAC;QAChK,CAAC;QAAC,MAAM,CAAC,CAAC,wDAAwD,CAAC,CAAC;IACtE,CAAC;IACD,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,aAAa,EAAE,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AAC9I,CAAC;AAED,mGAAmG;AACnG,SAAS,UAAU,CAAC,GAAY,EAAE,SAAiC;IACjE,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IAC5D,IAAI,KAAyB,CAAC;IAC9B,IAAI,CAAC;QAAC,KAAK,GAAG,SAAS,EAAE,EAAE,WAAW,EAAE,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC;IACnE,OAAO,EAAE,aAAa,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AACxE,CAAC;AAED;;;GAGG;AACH,SAAS,iBAAiB;IACxB,IAAI,GAAyB,CAAC;IAC9B,IAAI,CAAC;QAAC,GAAG,GAAG,OAAO,EAAE,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,GAAG,GAAG,SAAS,CAAC;IAAC,CAAC;IACnD,MAAM,SAAS,GAAqB,EAAE,CAAC;IACvC,MAAM,SAAS,GAAqB,EAAE,CAAC;IACvC,KAAK,MAAM,UAAU,IAAI,uBAAuB,EAAE,EAAE,CAAC;QACnD,IAAI,GAAG,EAAE,CAAC;YACR,IAAI,CAAC;gBAAC,gBAAgB,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC;gBAAC,SAAS;YAAC,CAAC;QAChE,CAAC;QACD,MAAM,KAAK,GAAG,UAAU,CAAC,UAAU,CAAC,aAAa,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC;QAC/F,IAAI,KAAK;YAAE,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;AAClC,CAAC;AAED,6IAA6I;AAC7I,SAAS,mBAAmB;IAC1B,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,YAAY,CAAC,CAAC,IAAI,MAAM,CAA4E,CAAC;QACtK,OAAO,UAAU,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE;YAC3C,IAAI,OAAO,KAAK,EAAE,IAAI,KAAK,QAAQ;gBAAE,OAAO,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC;YAC5E,OAAO,OAAO,KAAK,EAAE,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACtF,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,SAAS,CAAC;IAAC,CAAC;AAC/B,CAAC;AAED,wDAAwD;AACxD,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,GAAa,EAAE,OAAgB;IAC7D,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,iBAAiB,EAAE,CAAC;IACrD,MAAM,SAAS,GAAG,mBAAmB,EAAE,CAAC;IACxC,MAAM,OAAO,GAAoB;QAC/B,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,aAAa,EAAE,CAAC,EAAE,eAAe,EAAE,SAAS;QAC1E,GAAG,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACrH,CAAC;IACF,WAAW,CAAC,YAAY,EAAE,EAAE,OAAO,CAAC,CAAC;IACrC,aAAa,CAAC,OAAO,CAAC,CAAC;AACzB,CAAC;AAED,SAAS,eAAe,CAAC,IAAY;IACnC,IAAI,CAAC;QAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IAAC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAC1C,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;YAAE,MAAM,KAAK,CAAC;IACtE,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,OAAwB;IAC7C,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACrB,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7B,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,YAAY,CAAC,CAAC,CAAC;IACvD,IAAI,OAAO,CAAC,eAAe;QAAE,YAAY,EAAE,CAAC;IAC5C,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,eAAe,IAAI,EAAE;QAAE,qBAAqB,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IAC9F,OAAO,EAAE,CAAC;IACV,aAAa,CAAC,OAAO,CAAC,CAAC;IACvB,EAAE,CAAC,UAAU,CAAC,YAAY,EAAE,CAAC,CAAC;IAC9B,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,SAAS,GAAG,CAAC,SAA6B,EAAU,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAE7G,sHAAsH;AACtH,SAAS,aAAa,CAAC,OAAwB;IAC7C,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;QAC5B,OAAO,CAAC,KAAK,CAAC,0LAA0L,CAAC,CAAC;IAC5M,CAAC;IACD,IAAI,OAAO,CAAC,eAAe,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;QACrD,MAAM,KAAK,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,gBAAgB,OAAO,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACpF,OAAO,CAAC,KAAK,CAAC,gDAAgD,KAAK,8BAA8B,SAAS,CAAC,OAAO,CAAC,cAAc,CAAC,6DAA6D,UAAU,GAAG,CAAC,CAAC;IAChN,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,eAAe,IAAI,EAAE,EAAE,CAAC;QAClD,OAAO,CAAC,KAAK,CAAC,8EAA8E,KAAK,CAAC,aAAa,+DAA+D,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,6DAA6D,UAAU,GAAG,CAAC,CAAC;IACtR,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,eAAe,IAAI,EAAE,EAAE,CAAC;QAClD,OAAO,CAAC,KAAK,CAAC,4DAA4D,KAAK,CAAC,aAAa,yHAAyH,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,6DAA6D,UAAU,GAAG,CAAC,CAAC;IAC9T,CAAC;IACD,qIAAqI;IACrI,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;QAC3B,MAAM,EAAE,aAAa,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,cAAc,CAAC;QAC5D,MAAM,KAAK,GAAG,SAAS,CAAC,CAAC,CAAC,SAAS,SAAS,EAAE,CAAC,CAAC,CAAC,kBAAkB,CAAC;QACpE,OAAO,CAAC,KAAK,CAAC,yDAAyD,aAAa,gFAAgF,KAAK,6DAA6D,UAAU,GAAG,CAAC,CAAC;IACvP,CAAC;AACH,CAAC;AAED,+IAA+I;AAC/I,MAAM,UAAU,cAAc;IAC5B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,EAAE,CAAC;QAAE,OAAO,KAAK,CAAC;IACjD,MAAM,OAAO,GAAG,UAAU,CAAU,aAAa,EAAE,IAAI,CAAC,CAAC;IACzD,MAAM,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IACxC,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,IAAI,YAAY,CAAC,aAAa,EAAE,GAAG,YAAY,EAAE,wCAAwC,OAAO,gFAAgF,GAAG,CAAC,mBAAmB,CAAC,wCAAwC,CAAC,CAAC;IAC1P,CAAC;IACD,aAAa,CAAC,OAA0B,CAAC,CAAC;IAC1C,OAAO,IAAI,CAAC;AACd,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tinycloud/courier",
3
- "version": "0.5.1-beta.1",
3
+ "version": "0.5.1-beta.3",
4
4
  "description": "Courier: agent-to-agent threads over TinyCloud (CLI, library and agent skill)",
5
5
  "author": "TinyCloud, Inc.",
6
6
  "type": "module",
@@ -30,8 +30,8 @@
30
30
  "test:live": "tsc -p tsconfig.json && node scripts/happy-path.mjs"
31
31
  },
32
32
  "dependencies": {
33
- "@tinycloud/node-sdk": "3.11.0-beta.1",
34
- "@tinycloud/sdk-core": "3.11.0-beta.1",
33
+ "@tinycloud/node-sdk": "3.11.0-beta.2",
34
+ "@tinycloud/sdk-core": "3.11.0-beta.2",
35
35
  "@tinycloud/share-envelope": "1.5.0",
36
36
  "ulid": "^3.0.2"
37
37
  },