@cotal-ai/auth 0.0.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/dist/callout.d.ts +108 -0
- package/dist/callout.d.ts.map +1 -0
- package/dist/callout.js +219 -0
- package/dist/callout.js.map +1 -0
- package/dist/commands.d.ts +2 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +359 -0
- package/dist/commands.js.map +1 -0
- package/dist/derive.d.ts +15 -0
- package/dist/derive.d.ts.map +1 -0
- package/dist/derive.js +72 -0
- package/dist/derive.js.map +1 -0
- package/dist/idp.d.ts +63 -0
- package/dist/idp.d.ts.map +1 -0
- package/dist/idp.js +125 -0
- package/dist/idp.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/issuer.d.ts +78 -0
- package/dist/issuer.d.ts.map +1 -0
- package/dist/issuer.js +137 -0
- package/dist/issuer.js.map +1 -0
- package/dist/ledger.d.ts +108 -0
- package/dist/ledger.d.ts.map +1 -0
- package/dist/ledger.js +399 -0
- package/dist/ledger.js.map +1 -0
- package/dist/login.d.ts +69 -0
- package/dist/login.d.ts.map +1 -0
- package/dist/login.js +338 -0
- package/dist/login.js.map +1 -0
- package/dist/permissions.d.ts +28 -0
- package/dist/permissions.d.ts.map +1 -0
- package/dist/permissions.js +50 -0
- package/dist/permissions.js.map +1 -0
- package/dist/provider.d.ts +18 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +213 -0
- package/dist/provider.js.map +1 -0
- package/dist/service.d.ts +10 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +288 -0
- package/dist/service.js.map +1 -0
- package/dist/store.d.ts +82 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +208 -0
- package/dist/store.js.map +1 -0
- package/dist/token.d.ts +68 -0
- package/dist/token.d.ts.map +1 -0
- package/dist/token.js +128 -0
- package/dist/token.js.map +1 -0
- package/package.json +35 -5
- package/README.md +0 -4
package/dist/commands.js
ADDED
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Self-registering `login` / `logout` commands (the delivery-daemon pattern): importing
|
|
3
|
+
* `@cotal-ai/auth` registers them into the core `Registry`, and the `cotal` binary pulls the
|
|
4
|
+
* package in at its composition root. Session state lives under the workspace's `homeCotalDir()`
|
|
5
|
+
* (`~/.cotal`, `COTAL_HOME`-overridable) — per human, per machine, NOT per checkout: you are
|
|
6
|
+
* logged in as YOU across every repo on this box.
|
|
7
|
+
*/
|
|
8
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
9
|
+
import { CotalEndpoint, mintCreds, newIdentity, registry } from "@cotal-ai/core";
|
|
10
|
+
import { authDir, CLI_USER_ACTOR, findCotalRoot, homeCotalDir, loadMeshes, loadSpaceAuth, resolveSpace, userAuthStateDir } from "@cotal-ai/workspace";
|
|
11
|
+
import { deleteIdpSession, establishIdpSession, loadIdpSession, normalizeIdpUrl, revokeIdpSession, } from "./login.js";
|
|
12
|
+
import { deriveOwnerForIdpSubject } from "./derive.js";
|
|
13
|
+
import { findManagedActor, grantActor, loadActorLedger, revokeActor } from "./ledger.js";
|
|
14
|
+
import { runAuthService } from "./service.js";
|
|
15
|
+
import { loadAuthServiceInfo, loadOwnerSecret, loadPinnedIdp } from "./store.js";
|
|
16
|
+
const DEFAULT_CLIENT_ID = "cotal-cli";
|
|
17
|
+
/** Every operational failure in these commands is a deliberately-legible thrown sentence
|
|
18
|
+
* (a refused client id, a revoked session, a malformed IdP response …) — the CLI's generic
|
|
19
|
+
* catch would re-throw it into a raw stack trace. Print the sentence, exit 1. */
|
|
20
|
+
async function legibly(fn) {
|
|
21
|
+
try {
|
|
22
|
+
await fn();
|
|
23
|
+
}
|
|
24
|
+
catch (e) {
|
|
25
|
+
console.error(e instanceof Error ? e.message : String(e));
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
async function runLogin(args) {
|
|
30
|
+
const values = args.values;
|
|
31
|
+
if (!values.idp) {
|
|
32
|
+
console.error("usage: cotal login --idp <auth base URL> [--client-id <id>] (Better Auth: <origin>/api/auth)");
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
const idpArg = values.idp;
|
|
36
|
+
await legibly(async () => {
|
|
37
|
+
const idp = normalizeIdpUrl(idpArg);
|
|
38
|
+
// establishIdpSession proves the session mints user JWTs BEFORE persisting it — a failed
|
|
39
|
+
// proof leaves no cache entry to fool requireIdpSession later.
|
|
40
|
+
const { session, sub, label } = await establishIdpSession({
|
|
41
|
+
dir: homeCotalDir(),
|
|
42
|
+
idpUrl: idp,
|
|
43
|
+
clientId: values["client-id"] ?? DEFAULT_CLIENT_ID,
|
|
44
|
+
onPrompt: (p) => {
|
|
45
|
+
console.log(`\nTo approve this sign-in, open:\n\n ${p.verificationUriComplete}\n`);
|
|
46
|
+
console.log(`(or go to ${p.verificationUri} and enter the code ${p.userCode})\n`);
|
|
47
|
+
console.log(`Waiting for approval - the code expires in ${Math.ceil(p.expiresInSec / 60)} min. Ctrl-C to abort.`);
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
// WHO signed in must be human-readable (per-user auth exists for operator-visible identity):
|
|
51
|
+
// prefer the IdP's email/name claim; the raw `sub` stays as the stable id (dim when secondary).
|
|
52
|
+
const who = label ? `${label} (${sub})` : sub;
|
|
53
|
+
console.log(`\nLogged in to ${idp} as ${who}. Session cached in ${homeCotalDir()} until ${new Date(session.expiresAt * 1000).toISOString()}.`);
|
|
54
|
+
// Signing in proves WHO you are; each mesh separately lets you in. Hand the human the exact
|
|
55
|
+
// next step — their sub is the one thing the operator needs from them.
|
|
56
|
+
console.log(`Not yet on a mesh? Its operator lets you in with: cotal actor grant ${CLI_USER_ACTOR} --sub ${sub} (that's the full grant - all channels, may spawn; narrow with --allow-subscribe/--allow-publish/--scope)`);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
async function runLogout(args) {
|
|
60
|
+
const values = args.values;
|
|
61
|
+
if (!values.idp) {
|
|
62
|
+
console.error("usage: cotal logout --idp <auth base URL>");
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
const idpArg = values.idp;
|
|
66
|
+
await legibly(async () => {
|
|
67
|
+
const idp = normalizeIdpUrl(idpArg);
|
|
68
|
+
const dir = homeCotalDir();
|
|
69
|
+
const session = loadIdpSession(dir, idp);
|
|
70
|
+
if (!session) {
|
|
71
|
+
console.log(`not logged in to ${idp} - nothing to clear`);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
await revokeIdpSession(idp, session.token);
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
// KEEP the local session on a failed revoke: the cached token is the only handle that can
|
|
79
|
+
// retry the revoke from the CLI, and a still-live server-side session that can no longer be
|
|
80
|
+
// revoked is worse than a lingering local cache. Fail loud with the recourse; the operator
|
|
81
|
+
// re-runs `cotal logout`.
|
|
82
|
+
throw new Error(`could not revoke the server-side session at ${idp} (${e instanceof Error ? e.message : String(e)}). ` +
|
|
83
|
+
`Your local login is kept so you can retry \`cotal logout --idp ${idp}\`; if it keeps failing, revoke the session from the IdP directly.`);
|
|
84
|
+
}
|
|
85
|
+
deleteIdpSession(dir, idp);
|
|
86
|
+
console.log(`Logged out of ${idp} - server-side session revoked, local cache cleared.`);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
/** The space-scoped provider state dir the `actor` commands operate on (`userAuthStateDir` — the
|
|
90
|
+
* multi-space-ready layout; nothing user-auth lives flat in `.cotal/auth/`). */
|
|
91
|
+
function actorStateDir(space) {
|
|
92
|
+
const s = space ?? resolveSpace(process.cwd());
|
|
93
|
+
return { dir: userAuthStateDir(findCotalRoot(), s), space: s };
|
|
94
|
+
}
|
|
95
|
+
/** Resolve the operator's target (owner) for `actor grant`/`revoke`: an explicit derived `--owner`
|
|
96
|
+
* token, or `--sub` (the IdP subject `cotal login` prints) derived through the SAME frozen encoding
|
|
97
|
+
* the bridge exchange uses. BOTH require the space's owner secret + IdP pin under `dir` — i.e. this
|
|
98
|
+
* IS the machine that ran `cotal up --user-auth`, where the authoritative ledger lives. Without
|
|
99
|
+
* them a grant would write an INERT LOCAL row and print a misleading success while the mesh's real
|
|
100
|
+
* ledger is untouched (an off-machine `--owner` cannot mutate authority), so we refuse instead. */
|
|
101
|
+
function resolveGrantOwner(dir, values) {
|
|
102
|
+
if (values.owner && values.sub)
|
|
103
|
+
throw new Error("pass --owner OR --sub, not both");
|
|
104
|
+
if (!values.owner && !values.sub)
|
|
105
|
+
throw new Error("say who: --sub <IdP subject> (shown by `cotal login`) or --owner <u_…>");
|
|
106
|
+
const secret = loadOwnerSecret(dir);
|
|
107
|
+
const idp = loadPinnedIdp(dir);
|
|
108
|
+
if (!secret || !idp)
|
|
109
|
+
throw new Error(`user auth is not enabled for this space here (no owner secret/IdP pin under ${dir}). The actor ledger lives on the machine that ran \`cotal up --user-auth --idp <url>\`; run the \`actor\` commands there`);
|
|
110
|
+
if (values.owner)
|
|
111
|
+
return values.owner;
|
|
112
|
+
return deriveOwnerForIdpSubject(secret, idp.issuer, values.sub);
|
|
113
|
+
}
|
|
114
|
+
const csv = (s, dflt) => s === undefined ? dflt : s.split(",").map((x) => x.trim()).filter(Boolean);
|
|
115
|
+
/** Close a revoked principal's LIVE window (D5 acceptance gate: removal stops live delivery
|
|
116
|
+
* IMMEDIATELY, not at bearer expiry): mint an ephemeral supervisor cred from the local signer and
|
|
117
|
+
* request the delivery daemon's `evictPrincipal` (privileged delivery-admin rail — scan→KICK→
|
|
118
|
+
* verify). BEST-EFFORT with honest copy: deny-new is already committed by the ledger revoke
|
|
119
|
+
* before this runs, so a missing daemon/signer/registry only widens the end back to the bearer's
|
|
120
|
+
* own expiry — reported, never silent, and never a reason to fail the revoke. */
|
|
121
|
+
async function evictRevokedPrincipal(space, principal) {
|
|
122
|
+
const fallback = (why) => `live-connection eviction skipped (${why}) - deny-new is committed and the revoke cannot be re-run; the already-open connection ends at its current bearer's expiry. To evict live connections at revoke time, run \`cotal actor revoke\` from the mesh root (local signer + registry).`;
|
|
123
|
+
const root = findCotalRoot();
|
|
124
|
+
const auth = loadSpaceAuth(authDir(root));
|
|
125
|
+
if (!auth)
|
|
126
|
+
return fallback("no local signer here");
|
|
127
|
+
const mesh = loadMeshes().find((m) => m.space === space);
|
|
128
|
+
if (!mesh)
|
|
129
|
+
return fallback("mesh not in the local registry");
|
|
130
|
+
const id = newIdentity();
|
|
131
|
+
const ep = new CotalEndpoint({
|
|
132
|
+
space,
|
|
133
|
+
servers: mesh.server,
|
|
134
|
+
creds: await mintCreds(auth, id, "supervisor"),
|
|
135
|
+
card: { id: id.id, name: "revoke-evict", kind: "endpoint" },
|
|
136
|
+
channels: [],
|
|
137
|
+
consume: false,
|
|
138
|
+
watchChannels: false,
|
|
139
|
+
watchPresence: false,
|
|
140
|
+
registerPresence: false,
|
|
141
|
+
});
|
|
142
|
+
ep.on("error", () => { });
|
|
143
|
+
try {
|
|
144
|
+
await ep.start();
|
|
145
|
+
const r = await ep.requestDeliveryAdmin("evictPrincipal", { principal }, 15_000);
|
|
146
|
+
if (!r.ok)
|
|
147
|
+
return `live-connection eviction refused: ${r.error}`;
|
|
148
|
+
const d = (r.data ?? {});
|
|
149
|
+
return d.verifiedGone
|
|
150
|
+
? `live connections closed now (${d.kicked ?? 0} kicked, verified gone)`
|
|
151
|
+
: `live-connection eviction INCOMPLETE (${d.kicked ?? 0} kicked, ${d.remaining ?? "?"} still live) - run \`cotal doctor auth\``;
|
|
152
|
+
}
|
|
153
|
+
catch (e) {
|
|
154
|
+
return fallback(e instanceof Error ? e.message : String(e));
|
|
155
|
+
}
|
|
156
|
+
finally {
|
|
157
|
+
await ep.stop().catch(() => { });
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
async function runActor(args) {
|
|
161
|
+
const [sub, actor] = args.positionals;
|
|
162
|
+
const values = args.values;
|
|
163
|
+
const { dir, space } = actorStateDir(values.space);
|
|
164
|
+
await legibly(async () => {
|
|
165
|
+
if (sub === "list") {
|
|
166
|
+
const rows = loadActorLedger(dir);
|
|
167
|
+
if (!rows.length) {
|
|
168
|
+
console.log("no actors granted - grant one with: cotal actor grant <actor> --sub <IdP subject>");
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
for (const r of rows.sort((a, b) => (a.owner + a.actor).localeCompare(b.owner + b.actor)))
|
|
172
|
+
console.log(`${r.owner}.${r.actor}${r.label ? ` (${r.label})` : ""} kind=${r.kind} role=${r.role ?? "-"} scope=[${r.scope.join(",")}] read=[${r.allowSubscribe.join(",")}] post=[${r.allowPublish.join(",")}]`);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
if (sub === "grant") {
|
|
176
|
+
if (!actor)
|
|
177
|
+
throw new Error("usage: cotal actor grant <actor> --sub <IdP subject> [--scope a,b] [--allow-subscribe a,b] [--allow-publish a,b] [--role r] [--label l]");
|
|
178
|
+
const owner = resolveGrantOwner(dir, values);
|
|
179
|
+
// Default = the FULL grant (all channels, spawn + the stock role): `actor grant` is an
|
|
180
|
+
// operator act of letting a user in, so omitting flags means "fully", and narrowing is the
|
|
181
|
+
// explicit choice (`--allow-subscribe general --scope ''`). The user's agents are still
|
|
182
|
+
// attenuated from whatever this row says (the envelope rule).
|
|
183
|
+
const row = grantActor(dir, {
|
|
184
|
+
owner,
|
|
185
|
+
actor,
|
|
186
|
+
scope: csv(values.scope, ["spawn", "role:default"]),
|
|
187
|
+
allowSubscribe: csv(values["allow-subscribe"], [">"]),
|
|
188
|
+
allowPublish: csv(values["allow-publish"], [">"]),
|
|
189
|
+
...(values.role ? { role: values.role } : {}),
|
|
190
|
+
...(values.label ? { label: values.label } : {}),
|
|
191
|
+
...(values.parent ? { parent: values.parent } : {}),
|
|
192
|
+
});
|
|
193
|
+
console.log(`✓ granted ${row.owner}.${row.actor} - read [${row.allowSubscribe.join(", ")}], post [${row.allowPublish.join(", ")}]${row.scope.length ? `, scope [${row.scope.join(", ")}]` : ""}`);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
if (sub === "revoke") {
|
|
197
|
+
if (!actor)
|
|
198
|
+
throw new Error("usage: cotal actor revoke <actor> --sub <IdP subject>|--owner <u_…>");
|
|
199
|
+
const owner = resolveGrantOwner(dir, values);
|
|
200
|
+
if (!revokeActor(dir, owner, actor)) {
|
|
201
|
+
if (findManagedActor(dir, owner, actor))
|
|
202
|
+
throw new Error(`${owner}.${actor} is a managed agent - its grant lives with its process: stop it if manager-owned (\`cotal stop --name ${actor}\`), or if it was a killed foreground spawn, respawn the same name (\`cotal spawn\`) to rotate the grant`);
|
|
203
|
+
console.log(`no grant for ${owner}.${actor} - nothing to revoke`);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
// Deny-new is immediate at both boundaries (exchange + connect). The LIVE window no longer
|
|
207
|
+
// rides the bearer's expiry by default: the flip wires revoke → the delivery daemon's
|
|
208
|
+
// evictPrincipal (scan→KICK→verify on the privileged rail), best-effort with honest copy —
|
|
209
|
+
// a human bearer can otherwise carry up to the IdP session cap, far beyond the agents' TTL.
|
|
210
|
+
console.log(`✓ revoked ${owner}.${actor} - new exchanges and new connects are denied now`);
|
|
211
|
+
console.log(` ${await evictRevokedPrincipal(space, `${owner}.${actor}`)}`);
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
throw new Error("usage: cotal actor <grant <actor> | revoke <actor> | list>");
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
/** `cotal agent-bearer` — the ONE thing a spawned user-mode agent execs to refresh its auth: read
|
|
218
|
+
* its spawn-time secret from the 0600 token file, exchange it at the space's auth service (agent
|
|
219
|
+
* grant type), print the fresh bearer to STDOUT, exit. Machine-facing: stdout carries the bearer
|
|
220
|
+
* and NOTHING else; every failure is a stderr sentence + exit 1 (the endpoint surfaces it as a
|
|
221
|
+
* loud "error" event and retries). The secret rides a file, never argv (ps-visible) or env. */
|
|
222
|
+
async function runAgentBearer(args) {
|
|
223
|
+
const v = args.values;
|
|
224
|
+
const { dir, space, owner, actor } = v;
|
|
225
|
+
const tokenFile = v["token-file"];
|
|
226
|
+
if (!dir || !space || !owner || !actor || !tokenFile)
|
|
227
|
+
throw new Error("usage: cotal agent-bearer --dir <state-dir> --space <s> --owner <u_…> --actor <a> --token-file <path> [--health-file <path>]");
|
|
228
|
+
// Every attempt's outcome lands in the manager-composed health file (core's AgentAuthHealth) —
|
|
229
|
+
// the `ps` window into a detached agent's bearer life. Best-effort: health reporting must never
|
|
230
|
+
// turn a successful exchange into a failure.
|
|
231
|
+
const health = (state, reason) => {
|
|
232
|
+
const path = v["health-file"];
|
|
233
|
+
if (!path)
|
|
234
|
+
return;
|
|
235
|
+
try {
|
|
236
|
+
writeFileSync(path, JSON.stringify({ state, at: new Date().toISOString(), ...(reason ? { reason } : {}) }));
|
|
237
|
+
}
|
|
238
|
+
catch { /* the exchange outcome still stands */ }
|
|
239
|
+
};
|
|
240
|
+
try {
|
|
241
|
+
let actorToken;
|
|
242
|
+
try {
|
|
243
|
+
actorToken = readFileSync(tokenFile, "utf8").trim();
|
|
244
|
+
}
|
|
245
|
+
catch (e) {
|
|
246
|
+
throw new Error(`agent-bearer: can't read the actor token file at ${tokenFile} (${e instanceof Error ? e.message : String(e)}) - respawn this agent to re-provision it`);
|
|
247
|
+
}
|
|
248
|
+
const info = loadAuthServiceInfo(dir);
|
|
249
|
+
const alive = (pid) => { try {
|
|
250
|
+
process.kill(pid, 0);
|
|
251
|
+
return true;
|
|
252
|
+
}
|
|
253
|
+
catch {
|
|
254
|
+
return false;
|
|
255
|
+
} };
|
|
256
|
+
if (!info || !alive(info.pid))
|
|
257
|
+
throw new Error(`agent-bearer: the user-auth service for space "${space}" is not running - restart it with \`cotal up\``);
|
|
258
|
+
let res;
|
|
259
|
+
try {
|
|
260
|
+
res = await fetch(`${info.url}/exchange`, {
|
|
261
|
+
method: "POST",
|
|
262
|
+
headers: { "content-type": "application/json", authorization: `Bearer ${info.cap}` },
|
|
263
|
+
body: JSON.stringify({ owner, actor, actorToken }),
|
|
264
|
+
signal: AbortSignal.timeout(15_000),
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
catch (e) {
|
|
268
|
+
throw new Error(`agent-bearer: the user-auth service did not answer at ${info.url} (${e instanceof Error ? e.message : String(e)}) - restart it with \`cotal up\``);
|
|
269
|
+
}
|
|
270
|
+
if (!res.ok) {
|
|
271
|
+
const body = (await res.json().catch(() => ({})));
|
|
272
|
+
throw new Error(`agent-bearer: exchange refused: ${body.error ?? `HTTP ${res.status}`}`);
|
|
273
|
+
}
|
|
274
|
+
const out = (await res.json().catch(() => ({})));
|
|
275
|
+
if (typeof out.token !== "string" || !out.token)
|
|
276
|
+
throw new Error("agent-bearer: the auth service's exchange returned no token - its build may be stale; restart it with `cotal up`");
|
|
277
|
+
health("ok");
|
|
278
|
+
process.stdout.write(`${out.token}\n`);
|
|
279
|
+
}
|
|
280
|
+
catch (e) {
|
|
281
|
+
health("failed", e instanceof Error ? e.message : String(e));
|
|
282
|
+
throw e;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
const authCommands = [
|
|
286
|
+
{
|
|
287
|
+
kind: "command",
|
|
288
|
+
name: "auth-service",
|
|
289
|
+
group: "Manager",
|
|
290
|
+
summary: "run the user-auth service daemon - NATS auth callout + token exchange/JWKS --space <s> --server <url> [--port <n>]",
|
|
291
|
+
flags: [
|
|
292
|
+
{ name: "space", type: "string", value: "<s>", description: "space to serve (required)" },
|
|
293
|
+
{ name: "server", type: "string", value: "<url>", description: "broker URL the callout serves (required)" },
|
|
294
|
+
{ name: "port", type: "string", value: "<n>", description: "loopback HTTP port for /exchange + /jwks (default: ephemeral)" },
|
|
295
|
+
],
|
|
296
|
+
run: (args) => legibly(() => runAuthService(args)),
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
kind: "command",
|
|
300
|
+
name: "actor",
|
|
301
|
+
group: "Identity",
|
|
302
|
+
summary: "manage the space's actor ledger - grant/revoke which (user, actor) pairs may run agents",
|
|
303
|
+
usage: "actor <grant <actor> | revoke <actor> | list> [--sub <IdP subject>|--owner <u_…>] [--space <s>] [--scope a,b] [--allow-subscribe a,b] [--allow-publish a,b] [--role r] [--label l]",
|
|
304
|
+
positionals: "<grant <actor> | revoke <actor> | list>",
|
|
305
|
+
flags: [
|
|
306
|
+
{ name: "space", type: "string", value: "<s>", description: "space whose ledger to manage (default: the folder's)" },
|
|
307
|
+
{ name: "sub", type: "string", value: "<subject>", description: "the IdP subject (shown by `cotal login`) the actor belongs to" },
|
|
308
|
+
{ name: "owner", type: "string", value: "<u_…>", description: "the derived owner token (alternative to --sub)" },
|
|
309
|
+
{ name: "scope", type: "string", value: "<a,b>", description: "capability scope for the bearer (default: spawn,role:default; '' = none; spawn = may run agents, role:<r> = may delegate role r)" },
|
|
310
|
+
{ name: "allow-subscribe", type: "string", value: "<a,b>", description: "channel read ACL (default: > = all channels) - the user's envelope: their agents can never read beyond it" },
|
|
311
|
+
{ name: "allow-publish", type: "string", value: "<a,b>", description: "channel post ACL (default: > = all channels) - also the envelope for their agents' posting" },
|
|
312
|
+
{ name: "role", type: "string", value: "<r>", description: "role (scopes the task-queue consumer)" },
|
|
313
|
+
{ name: "label", type: "string", value: "<l>", description: "display label for `actor list` (never the IdP subject)" },
|
|
314
|
+
{ name: "parent", type: "string", value: "<owner.actor>", description: "spawning principal audit link (operator grants are authority - this does not attenuate)" },
|
|
315
|
+
],
|
|
316
|
+
run: runActor,
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
kind: "command",
|
|
320
|
+
name: "agent-bearer",
|
|
321
|
+
group: "Manager",
|
|
322
|
+
summary: "print one fresh agent bearer for a spawned user-mode agent (machine-facing; exec'd by agent endpoints)",
|
|
323
|
+
usage: "agent-bearer --dir <state-dir> --space <s> --owner <u_…> --actor <a> --token-file <path>",
|
|
324
|
+
flags: [
|
|
325
|
+
{ name: "dir", type: "string", value: "<state-dir>", description: "the space's user-auth state dir" },
|
|
326
|
+
{ name: "space", type: "string", value: "<s>", description: "the space the bearer is scoped to" },
|
|
327
|
+
{ name: "owner", type: "string", value: "<u_…>", description: "the agent's owner token" },
|
|
328
|
+
{ name: "actor", type: "string", value: "<a>", description: "the agent's actor token" },
|
|
329
|
+
{ name: "token-file", type: "string", value: "<path>", description: "0600 file holding the spawn-time agent secret" },
|
|
330
|
+
{ name: "health-file", type: "string", value: "<path>", description: "write each attempt's outcome here (read by the manager's ps)" },
|
|
331
|
+
],
|
|
332
|
+
run: (args) => legibly(() => runAgentBearer(args)),
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
kind: "command",
|
|
336
|
+
name: "login",
|
|
337
|
+
group: "Identity",
|
|
338
|
+
summary: "sign in to a space's IdP (device code) and cache the session --idp <auth base URL> [--client-id <id>]",
|
|
339
|
+
usage: "login --idp <auth base URL> [--client-id <id>]",
|
|
340
|
+
flags: [
|
|
341
|
+
{ name: "idp", type: "string", value: "<auth base URL>", description: "Auth base URL, e.g. <origin>/api/auth" },
|
|
342
|
+
{ name: "client-id", type: "string", value: "<id>", description: "OAuth device-flow client id" },
|
|
343
|
+
],
|
|
344
|
+
run: runLogin,
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
kind: "command",
|
|
348
|
+
name: "logout",
|
|
349
|
+
group: "Identity",
|
|
350
|
+
summary: "revoke the IdP session and clear the cached login --idp <auth base URL>",
|
|
351
|
+
usage: "logout --idp <auth base URL>",
|
|
352
|
+
flags: [
|
|
353
|
+
{ name: "idp", type: "string", value: "<auth base URL>", description: "Auth base URL, e.g. <origin>/api/auth" },
|
|
354
|
+
],
|
|
355
|
+
run: runLogout,
|
|
356
|
+
},
|
|
357
|
+
];
|
|
358
|
+
registry.register(...authCommands);
|
|
359
|
+
//# sourceMappingURL=commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"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"}
|
package/dist/derive.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Derive the opaque per-space owner token for an authenticated IdP subject.
|
|
2
|
+
*
|
|
3
|
+
* `spaceSecret` is the space's owner-derivation secret (≥32 bytes, operator-held, never on the
|
|
4
|
+
* wire); `externalSubject` is the IdP-authenticated stable subject (e.g. Better Auth `sub`) —
|
|
5
|
+
* ALREADY VERIFIED by the caller (this function derives, it does not authenticate). Truncation
|
|
6
|
+
* to 128 bits keeps the token subject-sized while leaving collision odds negligible for any
|
|
7
|
+
* realistic owner population (birthday bound 2^64). Fails loud on weak/empty inputs. */
|
|
8
|
+
export declare function deriveOwnerToken(spaceSecret: string | Uint8Array, externalSubject: string): string;
|
|
9
|
+
/** Derive the owner for an IdP-authenticated subject — the ONE encoding of (idp issuer, sub) into
|
|
10
|
+
* the derivation input, shared by the bridge exchange and the operator grant command so the two can
|
|
11
|
+
* never drift. JSON-array encoding, NOT `${issuer}|${sub}`: a bare-delimiter concat is non-injective
|
|
12
|
+
* (("a","b|c") and ("a|b","c") would collide). FROZEN once real owners exist — changing it (or the
|
|
13
|
+
* IdP issuer string) re-keys every owner in the space. */
|
|
14
|
+
export declare function deriveOwnerForIdpSubject(spaceSecret: string | Uint8Array, idpIssuer: string, sub: string): string;
|
|
15
|
+
//# sourceMappingURL=derive.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"derive.d.ts","sourceRoot":"","sources":["../src/derive.ts"],"names":[],"mappings":"AA8CA;;;;;;yFAMyF;AACzF,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,UAAU,EAAE,eAAe,EAAE,MAAM,GAAG,MAAM,CAUlG;AAED;;;;2DAI2D;AAC3D,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,MAAM,GAAG,UAAU,EAChC,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,GACV,MAAM,CAIR"}
|
package/dist/derive.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Owner-token derivation — the server-side step that turns an authenticated IdP subject into the
|
|
3
|
+
* opaque, per-space `owner` the wire grammar carries (see `assertDerivedOwnerToken` in core for
|
|
4
|
+
* the format contract this emits).
|
|
5
|
+
*
|
|
6
|
+
* Properties, by construction:
|
|
7
|
+
* - **Opaque / non-PII**: a keyed HMAC of the IdP subject — the token reveals nothing about the
|
|
8
|
+
* subject (email, name, global id) without the per-space secret, so it is safe in subjects,
|
|
9
|
+
* JetStream metadata, logs, and history filters.
|
|
10
|
+
* - **Per-space**: the secret is per-space, so the same human gets unlinkable owners across
|
|
11
|
+
* spaces.
|
|
12
|
+
* - **Deterministic**: same (secret, subject) → same owner, so re-login re-lands in the same
|
|
13
|
+
* lanes with no mapping table.
|
|
14
|
+
* - **nkey-disjoint**: the emitted format (`u_` + lowercase base32) can never be an nkey — the
|
|
15
|
+
* flip's acceptance criterion 2, asserted on every return value.
|
|
16
|
+
*/
|
|
17
|
+
import { createHmac } from "node:crypto";
|
|
18
|
+
import { assertDerivedOwnerToken, DERIVED_OWNER_PREFIX } from "@cotal-ai/core";
|
|
19
|
+
/** Domain-separation context — versioned so a future derivation change cannot silently collide
|
|
20
|
+
* with v1 tokens. Changing this re-keys every owner in the space; treat it as a migration. */
|
|
21
|
+
const DERIVATION_CONTEXT = "cotal-owner-v1";
|
|
22
|
+
/** Minimum secret size. 32 bytes = the HMAC-SHA256 block-security sweet spot; anything shorter
|
|
23
|
+
* is a config mistake (a guessable secret makes owners linkable/reversible offline). */
|
|
24
|
+
const MIN_SECRET_BYTES = 32;
|
|
25
|
+
const BASE32_LOWER = "abcdefghijklmnopqrstuvwxyz234567";
|
|
26
|
+
/** RFC 4648 base32 (lowercased, unpadded) — 16 bytes → 26 chars, matching the format contract. */
|
|
27
|
+
function base32LowerNoPad(bytes) {
|
|
28
|
+
let out = "";
|
|
29
|
+
let bits = 0;
|
|
30
|
+
let acc = 0;
|
|
31
|
+
for (const b of bytes) {
|
|
32
|
+
acc = (acc << 8) | b;
|
|
33
|
+
bits += 8;
|
|
34
|
+
while (bits >= 5) {
|
|
35
|
+
out += BASE32_LOWER[(acc >>> (bits - 5)) & 31];
|
|
36
|
+
bits -= 5;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (bits > 0)
|
|
40
|
+
out += BASE32_LOWER[(acc << (5 - bits)) & 31];
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
43
|
+
/** Derive the opaque per-space owner token for an authenticated IdP subject.
|
|
44
|
+
*
|
|
45
|
+
* `spaceSecret` is the space's owner-derivation secret (≥32 bytes, operator-held, never on the
|
|
46
|
+
* wire); `externalSubject` is the IdP-authenticated stable subject (e.g. Better Auth `sub`) —
|
|
47
|
+
* ALREADY VERIFIED by the caller (this function derives, it does not authenticate). Truncation
|
|
48
|
+
* to 128 bits keeps the token subject-sized while leaving collision odds negligible for any
|
|
49
|
+
* realistic owner population (birthday bound 2^64). Fails loud on weak/empty inputs. */
|
|
50
|
+
export function deriveOwnerToken(spaceSecret, externalSubject) {
|
|
51
|
+
const secret = typeof spaceSecret === "string" ? new TextEncoder().encode(spaceSecret) : spaceSecret;
|
|
52
|
+
if (secret.byteLength < MIN_SECRET_BYTES)
|
|
53
|
+
throw new Error(`deriveOwnerToken: spaceSecret must be at least ${MIN_SECRET_BYTES} bytes (got ${secret.byteLength}) - ` +
|
|
54
|
+
`a short secret makes owner tokens offline-reversible/linkable`);
|
|
55
|
+
if (!externalSubject)
|
|
56
|
+
throw new Error("deriveOwnerToken: externalSubject must be a non-empty IdP subject");
|
|
57
|
+
const mac = createHmac("sha256", secret).update(`${DERIVATION_CONTEXT}:${externalSubject}`).digest();
|
|
58
|
+
return assertDerivedOwnerToken(DERIVED_OWNER_PREFIX + base32LowerNoPad(mac.subarray(0, 16)));
|
|
59
|
+
}
|
|
60
|
+
/** Derive the owner for an IdP-authenticated subject — the ONE encoding of (idp issuer, sub) into
|
|
61
|
+
* the derivation input, shared by the bridge exchange and the operator grant command so the two can
|
|
62
|
+
* never drift. JSON-array encoding, NOT `${issuer}|${sub}`: a bare-delimiter concat is non-injective
|
|
63
|
+
* (("a","b|c") and ("a|b","c") would collide). FROZEN once real owners exist — changing it (or the
|
|
64
|
+
* IdP issuer string) re-keys every owner in the space. */
|
|
65
|
+
export function deriveOwnerForIdpSubject(spaceSecret, idpIssuer, sub) {
|
|
66
|
+
if (!idpIssuer)
|
|
67
|
+
throw new Error("deriveOwnerForIdpSubject: idpIssuer must be a non-empty string");
|
|
68
|
+
if (!sub)
|
|
69
|
+
throw new Error("deriveOwnerForIdpSubject: sub must be a non-empty string");
|
|
70
|
+
return deriveOwnerToken(spaceSecret, JSON.stringify([idpIssuer, sub]));
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=derive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"derive.js","sourceRoot":"","sources":["../src/derive.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAE/E;+FAC+F;AAC/F,MAAM,kBAAkB,GAAG,gBAAgB,CAAC;AAE5C;yFACyF;AACzF,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAE5B,MAAM,YAAY,GAAG,kCAAkC,CAAC;AAExD,kGAAkG;AAClG,SAAS,gBAAgB,CAAC,KAAiB;IACzC,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QACrB,IAAI,IAAI,CAAC,CAAC;QACV,OAAO,IAAI,IAAI,CAAC,EAAE,CAAC;YACjB,GAAG,IAAI,YAAY,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;YAC/C,IAAI,IAAI,CAAC,CAAC;QACZ,CAAC;IACH,CAAC;IACD,IAAI,IAAI,GAAG,CAAC;QAAE,GAAG,IAAI,YAAY,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IAC5D,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;yFAMyF;AACzF,MAAM,UAAU,gBAAgB,CAAC,WAAgC,EAAE,eAAuB;IACxF,MAAM,MAAM,GAAG,OAAO,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;IACrG,IAAI,MAAM,CAAC,UAAU,GAAG,gBAAgB;QACtC,MAAM,IAAI,KAAK,CACb,kDAAkD,gBAAgB,eAAe,MAAM,CAAC,UAAU,MAAM;YACtG,+DAA+D,CAClE,CAAC;IACJ,IAAI,CAAC,eAAe;QAAE,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAC;IAC3G,MAAM,GAAG,GAAG,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,kBAAkB,IAAI,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;IACrG,OAAO,uBAAuB,CAAC,oBAAoB,GAAG,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;AAC/F,CAAC;AAED;;;;2DAI2D;AAC3D,MAAM,UAAU,wBAAwB,CACtC,WAAgC,EAChC,SAAiB,EACjB,GAAW;IAEX,IAAI,CAAC,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;IAClG,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;IACtF,OAAO,gBAAgB,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;AACzE,CAAC"}
|
package/dist/idp.d.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { CryptoKey, JWTVerifyGetKey } from "jose";
|
|
2
|
+
import type { UserTokenIssuer } from "./issuer.js";
|
|
3
|
+
import { type UserTokenView } from "./token.js";
|
|
4
|
+
/** The pinned identity of ONE external IdP. All fields are operator config — nothing in here is
|
|
5
|
+
* ever read from a presented token. */
|
|
6
|
+
export interface IdpConfig {
|
|
7
|
+
/** Exact `iss` the IdP mints (Better Auth default: its base-URL origin). */
|
|
8
|
+
issuer: string;
|
|
9
|
+
/** Exact `aud` the IdP mints (Better Auth default: its base-URL origin). */
|
|
10
|
+
audience: string;
|
|
11
|
+
/** The pinned verification key path over the IdP's JWKS — a {@link pinnedJwksResolver} on the
|
|
12
|
+
* IdP's JWKS URL, or a local public key. The token never influences key resolution. */
|
|
13
|
+
key: JWTVerifyGetKey | CryptoKey;
|
|
14
|
+
/** Clock skew tolerance in seconds (default 5). */
|
|
15
|
+
clockToleranceSec?: number;
|
|
16
|
+
}
|
|
17
|
+
/** What the operator's ledger grants a (owner, actor) pair — the ONLY source of `scope`/`parent`
|
|
18
|
+
* in the minted bearer. Returned by {@link CreateIdpBridgeOpts.authorizeActor}; the hook throws
|
|
19
|
+
* to deny. */
|
|
20
|
+
export interface ActorGrant {
|
|
21
|
+
scope?: string[];
|
|
22
|
+
/** The spawning principal (`<owner>.<actor>` dot-form), when the ledger records one. */
|
|
23
|
+
parent?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface CreateIdpBridgeOpts {
|
|
26
|
+
/** The one IdP this bridge trusts. */
|
|
27
|
+
idp: IdpConfig;
|
|
28
|
+
/** The space every minted bearer is scoped to (`aud`). One bridge per space. */
|
|
29
|
+
space: string;
|
|
30
|
+
/** The space's owner-derivation secret (≥32 bytes, operator-held). */
|
|
31
|
+
spaceSecret: string | Uint8Array;
|
|
32
|
+
/** The Plane-1 issuer that mints the Cotal bearer. */
|
|
33
|
+
issuer: UserTokenIssuer;
|
|
34
|
+
/** The ledger authority: is `actor` a live, ledger-authorized instance of `owner`, and what does
|
|
35
|
+
* it get? MUST return an {@link ActorGrant} object to allow; throw to deny. There is no
|
|
36
|
+
* allow-by-default — a hook that returns anything else fails the exchange. */
|
|
37
|
+
authorizeActor: (owner: string, actor: string) => ActorGrant | Promise<ActorGrant>;
|
|
38
|
+
}
|
|
39
|
+
/** A successful exchange: the minted bearer plus what a caller needs to cache/refresh it. */
|
|
40
|
+
export interface ExchangeResult {
|
|
41
|
+
/** The Cotal user bearer (compact JWS) the agent presents in `auth_token`. */
|
|
42
|
+
token: string;
|
|
43
|
+
/** The derived opaque owner the bearer is bound to. */
|
|
44
|
+
owner: string;
|
|
45
|
+
/** Bearer expiry (unix seconds) — schedule re-mint before this. */
|
|
46
|
+
exp: number;
|
|
47
|
+
}
|
|
48
|
+
export interface IdpBridge {
|
|
49
|
+
/** Exchange a verified IdP token for a Cotal user bearer bound to (derived owner, actor).
|
|
50
|
+
* `view` requests an elevated per-connection profile ({@link USER_TOKEN_VIEWS}); it is
|
|
51
|
+
* authorized HERE against the fresh ledger grant — scope must contain `admin` — and minted as
|
|
52
|
+
* the server-authored `act.view` claim. Human exchanges only; the managed (agent-secret)
|
|
53
|
+
* exchange path rejects views before it ever reaches a bridge. */
|
|
54
|
+
exchange(idpToken: string, req: {
|
|
55
|
+
actor: string;
|
|
56
|
+
ttlSec?: number;
|
|
57
|
+
view?: UserTokenView;
|
|
58
|
+
}): Promise<ExchangeResult>;
|
|
59
|
+
}
|
|
60
|
+
/** Build an {@link IdpBridge}. Misconfig fails HERE, at construction — an empty pin would
|
|
61
|
+
* otherwise fail closed on every exchange with a far worse operator signal. */
|
|
62
|
+
export declare function createIdpBridge(opts: CreateIdpBridgeOpts): IdpBridge;
|
|
63
|
+
//# sourceMappingURL=idp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idp.d.ts","sourceRoot":"","sources":["../src/idp.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,MAAM,CAAC;AAGvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAA4D,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAE1G;wCACwC;AACxC,MAAM,WAAW,SAAS;IACxB,4EAA4E;IAC5E,MAAM,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,QAAQ,EAAE,MAAM,CAAC;IACjB;4FACwF;IACxF,GAAG,EAAE,eAAe,GAAG,SAAS,CAAC;IACjC,mDAAmD;IACnD,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;eAEe;AACf,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,wFAAwF;IACxF,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,sCAAsC;IACtC,GAAG,EAAE,SAAS,CAAC;IACf,gFAAgF;IAChF,KAAK,EAAE,MAAM,CAAC;IACd,sEAAsE;IACtE,WAAW,EAAE,MAAM,GAAG,UAAU,CAAC;IACjC,sDAAsD;IACtD,MAAM,EAAE,eAAe,CAAC;IACxB;;mFAE+E;IAC/E,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CACpF;AAED,6FAA6F;AAC7F,MAAM,WAAW,cAAc;IAC7B,8EAA8E;IAC9E,KAAK,EAAE,MAAM,CAAC;IACd,uDAAuD;IACvD,KAAK,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,SAAS;IACxB;;;;uEAImE;IACnE,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,aAAa,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CACpH;AAkCD;gFACgF;AAChF,wBAAgB,eAAe,CAAC,IAAI,EAAE,mBAAmB,GAAG,SAAS,CAyDpE"}
|