agentmb 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/INSTALL.md +154 -0
- package/README.md +228 -0
- package/dist/audit/logger.d.ts +25 -0
- package/dist/audit/logger.d.ts.map +1 -0
- package/dist/audit/logger.js +56 -0
- package/dist/audit/logger.js.map +1 -0
- package/dist/browser/actions.d.ts +111 -0
- package/dist/browser/actions.d.ts.map +1 -0
- package/dist/browser/actions.js +291 -0
- package/dist/browser/actions.js.map +1 -0
- package/dist/browser/manager.d.ts +51 -0
- package/dist/browser/manager.d.ts.map +1 -0
- package/dist/browser/manager.js +233 -0
- package/dist/browser/manager.js.map +1 -0
- package/dist/cli/client.d.ts +13 -0
- package/dist/cli/client.d.ts.map +1 -0
- package/dist/cli/client.js +109 -0
- package/dist/cli/client.js.map +1 -0
- package/dist/cli/commands/actions.d.ts +3 -0
- package/dist/cli/commands/actions.d.ts.map +1 -0
- package/dist/cli/commands/actions.js +349 -0
- package/dist/cli/commands/actions.js.map +1 -0
- package/dist/cli/commands/pages.d.ts +3 -0
- package/dist/cli/commands/pages.d.ts.map +1 -0
- package/dist/cli/commands/pages.js +107 -0
- package/dist/cli/commands/pages.js.map +1 -0
- package/dist/cli/commands/route.d.ts +3 -0
- package/dist/cli/commands/route.d.ts.map +1 -0
- package/dist/cli/commands/route.js +72 -0
- package/dist/cli/commands/route.js.map +1 -0
- package/dist/cli/commands/session.d.ts +3 -0
- package/dist/cli/commands/session.d.ts.map +1 -0
- package/dist/cli/commands/session.js +57 -0
- package/dist/cli/commands/session.js.map +1 -0
- package/dist/cli/commands/start.d.ts +8 -0
- package/dist/cli/commands/start.d.ts.map +1 -0
- package/dist/cli/commands/start.js +66 -0
- package/dist/cli/commands/start.js.map +1 -0
- package/dist/cli/commands/status.d.ts +6 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +25 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/stop.d.ts +6 -0
- package/dist/cli/commands/stop.d.ts.map +1 -0
- package/dist/cli/commands/stop.js +53 -0
- package/dist/cli/commands/stop.js.map +1 -0
- package/dist/cli/commands/trace.d.ts +3 -0
- package/dist/cli/commands/trace.d.ts.map +1 -0
- package/dist/cli/commands/trace.js +43 -0
- package/dist/cli/commands/trace.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +44 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/daemon/config.d.ts +25 -0
- package/dist/daemon/config.d.ts.map +1 -0
- package/dist/daemon/config.js +35 -0
- package/dist/daemon/config.js.map +1 -0
- package/dist/daemon/index.d.ts +7 -0
- package/dist/daemon/index.d.ts.map +1 -0
- package/dist/daemon/index.js +84 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/daemon/routes/actions.d.ts +5 -0
- package/dist/daemon/routes/actions.d.ts.map +1 -0
- package/dist/daemon/routes/actions.js +425 -0
- package/dist/daemon/routes/actions.js.map +1 -0
- package/dist/daemon/routes/sessions.d.ts +5 -0
- package/dist/daemon/routes/sessions.d.ts.map +1 -0
- package/dist/daemon/routes/sessions.js +507 -0
- package/dist/daemon/routes/sessions.js.map +1 -0
- package/dist/daemon/server.d.ts +6 -0
- package/dist/daemon/server.d.ts.map +1 -0
- package/dist/daemon/server.js +66 -0
- package/dist/daemon/server.js.map +1 -0
- package/dist/daemon/session.d.ts +52 -0
- package/dist/daemon/session.d.ts.map +1 -0
- package/dist/daemon/session.js +191 -0
- package/dist/daemon/session.js.map +1 -0
- package/dist/daemon/types.d.ts +17 -0
- package/dist/daemon/types.d.ts.map +1 -0
- package/dist/daemon/types.js +3 -0
- package/dist/daemon/types.js.map +1 -0
- package/dist/policy/engine.d.ts +43 -0
- package/dist/policy/engine.d.ts.map +1 -0
- package/dist/policy/engine.js +234 -0
- package/dist/policy/engine.js.map +1 -0
- package/dist/policy/types.d.ts +40 -0
- package/dist/policy/types.d.ts.map +1 -0
- package/dist/policy/types.js +53 -0
- package/dist/policy/types.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { BrowserContext, Page } from 'playwright-core';
|
|
2
|
+
/** Resolve raw env-var string to a 32-byte Buffer, or throw on bad length. */
|
|
3
|
+
export declare function resolveEncryptionKey(raw: string): Buffer;
|
|
4
|
+
export interface SessionInfo {
|
|
5
|
+
id: string;
|
|
6
|
+
profile: string;
|
|
7
|
+
headless: boolean;
|
|
8
|
+
createdAt: string;
|
|
9
|
+
agentId?: string;
|
|
10
|
+
/** 'live' = browser running; 'zombie' = metadata only (browser not started) */
|
|
11
|
+
state: 'live' | 'zombie';
|
|
12
|
+
}
|
|
13
|
+
export interface LiveSession extends SessionInfo {
|
|
14
|
+
context: BrowserContext | null;
|
|
15
|
+
page: Page | null;
|
|
16
|
+
}
|
|
17
|
+
export declare class SessionRegistry {
|
|
18
|
+
private sessions;
|
|
19
|
+
private stateFile;
|
|
20
|
+
private encryptionKey?;
|
|
21
|
+
constructor(dataDir: string, encryptionKeyStr?: string);
|
|
22
|
+
/** Load persisted session metadata from previous daemon run. */
|
|
23
|
+
loadPersistedSessions(): void;
|
|
24
|
+
private persist;
|
|
25
|
+
create(opts: {
|
|
26
|
+
profile?: string;
|
|
27
|
+
headless?: boolean;
|
|
28
|
+
agentId?: string;
|
|
29
|
+
}): string;
|
|
30
|
+
attach(id: string, context: BrowserContext, page: Page): void;
|
|
31
|
+
get(id: string): LiveSession | undefined;
|
|
32
|
+
getOrThrow(id: string): LiveSession;
|
|
33
|
+
/** Get a live (browser-running) session or return an error discriminant. */
|
|
34
|
+
getLive(id: string): (LiveSession & {
|
|
35
|
+
context: BrowserContext;
|
|
36
|
+
page: Page;
|
|
37
|
+
}) | {
|
|
38
|
+
notFound: true;
|
|
39
|
+
} | {
|
|
40
|
+
zombie: true;
|
|
41
|
+
info: SessionInfo;
|
|
42
|
+
};
|
|
43
|
+
list(): SessionInfo[];
|
|
44
|
+
count(): number;
|
|
45
|
+
/** Update the headless flag in memory and persist to disk (called after mode switch). */
|
|
46
|
+
updateHeadless(id: string, headless: boolean): void;
|
|
47
|
+
close(id: string): Promise<void>;
|
|
48
|
+
/** On daemon shutdown: persist zombie metadata to disk, then close all contexts. */
|
|
49
|
+
shutdownAll(): Promise<void>;
|
|
50
|
+
closeAll(): Promise<void>;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/daemon/session.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AActD,8EAA8E;AAC9E,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CASxD;AAgCD,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,OAAO,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,+EAA+E;IAC/E,KAAK,EAAE,MAAM,GAAG,QAAQ,CAAA;CACzB;AAED,MAAM,WAAW,WAAY,SAAQ,WAAW;IAC9C,OAAO,EAAE,cAAc,GAAG,IAAI,CAAA;IAC9B,IAAI,EAAE,IAAI,GAAG,IAAI,CAAA;CAClB;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,aAAa,CAAC,CAAQ;gBAElB,OAAO,EAAE,MAAM,EAAE,gBAAgB,CAAC,EAAE,MAAM;IAQtD,gEAAgE;IAChE,qBAAqB,IAAI,IAAI;IAgC7B,OAAO,CAAC,OAAO;IAcf,MAAM,CAAC,IAAI,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM;IAehF,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI;IAO7D,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAIxC,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW;IAMnC,4EAA4E;IAC5E,OAAO,CAAC,EAAE,EAAE,MAAM,GACd,CAAC,WAAW,GAAG;QAAE,OAAO,EAAE,cAAc,CAAC;QAAC,IAAI,EAAE,IAAI,CAAA;KAAE,CAAC,GACvD;QAAE,QAAQ,EAAE,IAAI,CAAA;KAAE,GAClB;QAAE,MAAM,EAAE,IAAI,CAAC;QAAC,IAAI,EAAE,WAAW,CAAA;KAAE;IAOvC,IAAI,IAAI,WAAW,EAAE;IAIrB,KAAK,IAAI,MAAM;IAIf,yFAAyF;IACzF,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,IAAI;IAO7C,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUtC,oFAAoF;IAC9E,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAiB5B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAGhC"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.SessionRegistry = void 0;
|
|
7
|
+
exports.resolveEncryptionKey = resolveEncryptionKey;
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
11
|
+
/** Resolve raw env-var string to a 32-byte Buffer, or throw on bad length. */
|
|
12
|
+
function resolveEncryptionKey(raw) {
|
|
13
|
+
// Prefer base64 (44 chars for 32 bytes); fall back to hex (64 chars)
|
|
14
|
+
const b64 = Buffer.from(raw, 'base64');
|
|
15
|
+
if (b64.length === 32)
|
|
16
|
+
return b64;
|
|
17
|
+
const hex = Buffer.from(raw, 'hex');
|
|
18
|
+
if (hex.length === 32)
|
|
19
|
+
return hex;
|
|
20
|
+
throw new Error('AGENTMB_ENCRYPTION_KEY must be exactly 32 bytes — provide as base64 (44 chars) or hex (64 chars)');
|
|
21
|
+
}
|
|
22
|
+
function encryptSessions(data, key) {
|
|
23
|
+
const iv = crypto_1.default.randomBytes(12);
|
|
24
|
+
const cipher = crypto_1.default.createCipheriv('aes-256-gcm', key, iv);
|
|
25
|
+
const plaintext = JSON.stringify(data);
|
|
26
|
+
const ct = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);
|
|
27
|
+
const envelope = {
|
|
28
|
+
v: 1,
|
|
29
|
+
alg: 'aes-256-gcm',
|
|
30
|
+
iv: iv.toString('hex'),
|
|
31
|
+
tag: cipher.getAuthTag().toString('hex'),
|
|
32
|
+
ct: ct.toString('hex'),
|
|
33
|
+
};
|
|
34
|
+
return JSON.stringify(envelope);
|
|
35
|
+
}
|
|
36
|
+
function decryptSessions(raw, key) {
|
|
37
|
+
const env = JSON.parse(raw);
|
|
38
|
+
const decipher = crypto_1.default.createDecipheriv('aes-256-gcm', key, Buffer.from(env.iv, 'hex'));
|
|
39
|
+
decipher.setAuthTag(Buffer.from(env.tag, 'hex'));
|
|
40
|
+
const pt = Buffer.concat([
|
|
41
|
+
decipher.update(Buffer.from(env.ct, 'hex')),
|
|
42
|
+
decipher.final(),
|
|
43
|
+
]).toString('utf8');
|
|
44
|
+
return JSON.parse(pt);
|
|
45
|
+
}
|
|
46
|
+
class SessionRegistry {
|
|
47
|
+
sessions = new Map();
|
|
48
|
+
stateFile;
|
|
49
|
+
encryptionKey;
|
|
50
|
+
constructor(dataDir, encryptionKeyStr) {
|
|
51
|
+
this.stateFile = path_1.default.join(dataDir, 'sessions.json');
|
|
52
|
+
fs_1.default.mkdirSync(dataDir, { recursive: true });
|
|
53
|
+
if (encryptionKeyStr) {
|
|
54
|
+
this.encryptionKey = resolveEncryptionKey(encryptionKeyStr);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/** Load persisted session metadata from previous daemon run. */
|
|
58
|
+
loadPersistedSessions() {
|
|
59
|
+
if (!fs_1.default.existsSync(this.stateFile))
|
|
60
|
+
return;
|
|
61
|
+
try {
|
|
62
|
+
const raw = fs_1.default.readFileSync(this.stateFile, 'utf8');
|
|
63
|
+
let data;
|
|
64
|
+
const parsed = JSON.parse(raw);
|
|
65
|
+
if (Array.isArray(parsed)) {
|
|
66
|
+
// Plain JSON (no encryption configured, or pre-encryption file)
|
|
67
|
+
data = parsed;
|
|
68
|
+
}
|
|
69
|
+
else if (parsed.v === 1 && parsed.ct) {
|
|
70
|
+
// Encrypted envelope
|
|
71
|
+
if (!this.encryptionKey) {
|
|
72
|
+
process.stderr.write('[agentmb] sessions.json is encrypted but AGENTMB_ENCRYPTION_KEY is not set — skipping session load\n');
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
data = decryptSessions(raw, this.encryptionKey);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
return; // unknown format, start fresh
|
|
79
|
+
}
|
|
80
|
+
for (const info of data) {
|
|
81
|
+
// Register as zombie — profile is on disk, browser not running
|
|
82
|
+
this.sessions.set(info.id, { ...info, state: 'zombie', context: null, page: null });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// Corrupt or tampered state file — ignore, start fresh
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
persist() {
|
|
90
|
+
const infos = Array.from(this.sessions.values()).map(({ context: _c, page: _p, ...info }) => info);
|
|
91
|
+
try {
|
|
92
|
+
const content = this.encryptionKey
|
|
93
|
+
? encryptSessions(infos, this.encryptionKey)
|
|
94
|
+
: JSON.stringify(infos, null, 2);
|
|
95
|
+
fs_1.default.writeFileSync(this.stateFile, content);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// non-critical
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
create(opts) {
|
|
102
|
+
const id = 'sess_' + crypto_1.default.randomBytes(6).toString('hex');
|
|
103
|
+
const info = {
|
|
104
|
+
id,
|
|
105
|
+
profile: opts.profile ?? 'default',
|
|
106
|
+
headless: opts.headless ?? true,
|
|
107
|
+
createdAt: new Date().toISOString(),
|
|
108
|
+
agentId: opts.agentId,
|
|
109
|
+
state: 'zombie', // becomes 'live' after attach()
|
|
110
|
+
};
|
|
111
|
+
this.sessions.set(id, { ...info, context: null, page: null });
|
|
112
|
+
this.persist();
|
|
113
|
+
return id;
|
|
114
|
+
}
|
|
115
|
+
attach(id, context, page) {
|
|
116
|
+
const existing = this.sessions.get(id);
|
|
117
|
+
if (!existing)
|
|
118
|
+
throw new Error(`Session ${id} not found`);
|
|
119
|
+
this.sessions.set(id, { ...existing, state: 'live', context, page });
|
|
120
|
+
this.persist();
|
|
121
|
+
}
|
|
122
|
+
get(id) {
|
|
123
|
+
return this.sessions.get(id);
|
|
124
|
+
}
|
|
125
|
+
getOrThrow(id) {
|
|
126
|
+
const s = this.sessions.get(id);
|
|
127
|
+
if (!s)
|
|
128
|
+
throw new Error(`Session not found: ${id}`);
|
|
129
|
+
return s;
|
|
130
|
+
}
|
|
131
|
+
/** Get a live (browser-running) session or return an error discriminant. */
|
|
132
|
+
getLive(id) {
|
|
133
|
+
const s = this.sessions.get(id);
|
|
134
|
+
if (!s)
|
|
135
|
+
return { notFound: true };
|
|
136
|
+
if (s.state !== 'live' || !s.page || !s.context)
|
|
137
|
+
return { zombie: true, info: s };
|
|
138
|
+
return s;
|
|
139
|
+
}
|
|
140
|
+
list() {
|
|
141
|
+
return Array.from(this.sessions.values()).map(({ context: _c, page: _p, ...info }) => info);
|
|
142
|
+
}
|
|
143
|
+
count() {
|
|
144
|
+
return Array.from(this.sessions.values()).filter((s) => s.state === 'live').length;
|
|
145
|
+
}
|
|
146
|
+
/** Update the headless flag in memory and persist to disk (called after mode switch). */
|
|
147
|
+
updateHeadless(id, headless) {
|
|
148
|
+
const s = this.sessions.get(id);
|
|
149
|
+
if (!s)
|
|
150
|
+
return;
|
|
151
|
+
s.headless = headless;
|
|
152
|
+
this.persist();
|
|
153
|
+
}
|
|
154
|
+
async close(id) {
|
|
155
|
+
const s = this.sessions.get(id);
|
|
156
|
+
if (!s)
|
|
157
|
+
return;
|
|
158
|
+
if (s.context) {
|
|
159
|
+
try {
|
|
160
|
+
await s.context.close();
|
|
161
|
+
}
|
|
162
|
+
catch { /* ignore */ }
|
|
163
|
+
}
|
|
164
|
+
this.sessions.delete(id);
|
|
165
|
+
this.persist();
|
|
166
|
+
}
|
|
167
|
+
/** On daemon shutdown: persist zombie metadata to disk, then close all contexts. */
|
|
168
|
+
async shutdownAll() {
|
|
169
|
+
// 1. Mark all live sessions as zombie and persist to disk (so they survive restart)
|
|
170
|
+
for (const [, s] of this.sessions) {
|
|
171
|
+
if (s.state === 'live')
|
|
172
|
+
s.state = 'zombie';
|
|
173
|
+
}
|
|
174
|
+
this.persist();
|
|
175
|
+
// 2. Close all browser contexts
|
|
176
|
+
await Promise.all(Array.from(this.sessions.values()).map(async (s) => {
|
|
177
|
+
if (s.context) {
|
|
178
|
+
try {
|
|
179
|
+
await s.context.close();
|
|
180
|
+
}
|
|
181
|
+
catch { /* ignore */ }
|
|
182
|
+
}
|
|
183
|
+
}));
|
|
184
|
+
this.sessions.clear();
|
|
185
|
+
}
|
|
186
|
+
async closeAll() {
|
|
187
|
+
await Promise.all(Array.from(this.sessions.keys()).map((id) => this.close(id)));
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
exports.SessionRegistry = SessionRegistry;
|
|
191
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/daemon/session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fastify instance type augmentation (T11: auditLogger type safety)
|
|
3
|
+
*
|
|
4
|
+
* Adds typed `auditLogger` and `browserManager` properties to FastifyInstance
|
|
5
|
+
* so route handlers can access them without `(server as any)` casts.
|
|
6
|
+
*/
|
|
7
|
+
import type { AuditLogger } from '../audit/logger';
|
|
8
|
+
import type { BrowserManager } from '../browser/manager';
|
|
9
|
+
import type { PolicyEngine } from '../policy/engine';
|
|
10
|
+
declare module 'fastify' {
|
|
11
|
+
interface FastifyInstance {
|
|
12
|
+
auditLogger: AuditLogger | undefined;
|
|
13
|
+
browserManager: BrowserManager | undefined;
|
|
14
|
+
policyEngine: PolicyEngine | undefined;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/daemon/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAEpD,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAU,eAAe;QACvB,WAAW,EAAE,WAAW,GAAG,SAAS,CAAA;QACpC,cAAc,EAAE,cAAc,GAAG,SAAS,CAAA;QAC1C,YAAY,EAAE,YAAY,GAAG,SAAS,CAAA;KACvC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/daemon/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { AuditLogger } from '../audit/logger';
|
|
2
|
+
import { PolicyConfig, PolicyProfileName, PolicyCheckResult } from './types';
|
|
3
|
+
export declare function extractDomain(url: string): string;
|
|
4
|
+
export declare class PolicyEngine {
|
|
5
|
+
/** Base policy config (from daemon startup profile) */
|
|
6
|
+
private baseConfig;
|
|
7
|
+
/** Per-session policy overrides (set by POST /sessions/:id/policy) */
|
|
8
|
+
private sessionOverrides;
|
|
9
|
+
/** Timestamp of last completed action per domain-session */
|
|
10
|
+
private lastActionTs;
|
|
11
|
+
/** Rolling window of action timestamps (60s) per domain-session */
|
|
12
|
+
private actionWindow;
|
|
13
|
+
/** Retry count per domain-session */
|
|
14
|
+
private retryCount;
|
|
15
|
+
/** Cooldown-ends-at timestamp per domain-session */
|
|
16
|
+
private cooldownUntil;
|
|
17
|
+
/** TTL for idle domain state entries (30 minutes) */
|
|
18
|
+
private static readonly DOMAIN_TTL_MS;
|
|
19
|
+
/** Minimum interval between cleanup passes (5 minutes) */
|
|
20
|
+
private static readonly CLEANUP_INTERVAL_MS;
|
|
21
|
+
/** Timestamp of last domain-state cleanup pass */
|
|
22
|
+
private lastCleanupTs;
|
|
23
|
+
constructor(profileName?: PolicyProfileName);
|
|
24
|
+
/**
|
|
25
|
+
* Lazily prune per-domain state entries that have been idle longer than
|
|
26
|
+
* DOMAIN_TTL_MS. Called from checkAndWait() at most once per
|
|
27
|
+
* CLEANUP_INTERVAL_MS to avoid O(n) work on every action.
|
|
28
|
+
*/
|
|
29
|
+
private maybeCleanupStaleDomains;
|
|
30
|
+
setSessionPolicy(sessionId: string, profileName: PolicyProfileName, overrides?: Partial<PolicyConfig>): void;
|
|
31
|
+
getSessionPolicy(sessionId: string): PolicyConfig;
|
|
32
|
+
clearSession(sessionId: string): void;
|
|
33
|
+
checkAndWait(params: {
|
|
34
|
+
sessionId: string;
|
|
35
|
+
domain: string;
|
|
36
|
+
action: string;
|
|
37
|
+
sensitive?: boolean;
|
|
38
|
+
retry?: boolean;
|
|
39
|
+
auditLogger?: AuditLogger;
|
|
40
|
+
}): Promise<PolicyCheckResult>;
|
|
41
|
+
recordError(sessionId: string, domain: string, auditLogger?: AuditLogger): void;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/policy/engine.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,EACL,YAAY,EACZ,iBAAiB,EAEjB,iBAAiB,EAElB,MAAM,SAAS,CAAA;AAahB,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAOjD;AAED,qBAAa,YAAY;IACvB,uDAAuD;IACvD,OAAO,CAAC,UAAU,CAAc;IAEhC,sEAAsE;IACtE,OAAO,CAAC,gBAAgB,CAAkC;IAI1D,4DAA4D;IAC5D,OAAO,CAAC,YAAY,CAA+B;IAEnD,mEAAmE;IACnE,OAAO,CAAC,YAAY,CAAiC;IAErD,qCAAqC;IACrC,OAAO,CAAC,UAAU,CAA+B;IAEjD,oDAAoD;IACpD,OAAO,CAAC,aAAa,CAA+B;IAEpD,qDAAqD;IACrD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAc;IAEnD,0DAA0D;IAC1D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAa;IAExD,kDAAkD;IAClD,OAAO,CAAC,aAAa,CAAI;gBAEb,WAAW,GAAE,iBAA0B;IAInD;;;;OAIG;IACH,OAAO,CAAC,wBAAwB;IAkBhC,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,iBAAiB,EAAE,SAAS,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,IAAI;IAK5G,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY;IAIjD,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAgB/B,YAAY,CAAC,MAAM,EAAE;QACzB,SAAS,EAAE,MAAM,CAAA;QACjB,MAAM,EAAE,MAAM,CAAA;QACd,MAAM,EAAE,MAAM,CAAA;QACd,SAAS,CAAC,EAAE,OAAO,CAAA;QACnB,KAAK,CAAC,EAAE,OAAO,CAAA;QACf,WAAW,CAAC,EAAE,WAAW,CAAA;KAC1B,GAAG,OAAO,CAAC,iBAAiB,CAAC;IA0I9B,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,WAAW,GAAG,IAAI;CAehF"}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.PolicyEngine = void 0;
|
|
7
|
+
exports.extractDomain = extractDomain;
|
|
8
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
9
|
+
const types_1 = require("./types");
|
|
10
|
+
function sleep(ms) {
|
|
11
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
12
|
+
}
|
|
13
|
+
function actionId() {
|
|
14
|
+
return 'act_' + crypto_1.default.randomBytes(6).toString('hex');
|
|
15
|
+
}
|
|
16
|
+
function extractDomain(url) {
|
|
17
|
+
try {
|
|
18
|
+
return new URL(url).hostname || url;
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
// data: URIs or relative paths — use as-is, truncated
|
|
22
|
+
return url.slice(0, 64);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
class PolicyEngine {
|
|
26
|
+
/** Base policy config (from daemon startup profile) */
|
|
27
|
+
baseConfig;
|
|
28
|
+
/** Per-session policy overrides (set by POST /sessions/:id/policy) */
|
|
29
|
+
sessionOverrides = new Map();
|
|
30
|
+
// -- Per-domain, per-session tracking --
|
|
31
|
+
/** Timestamp of last completed action per domain-session */
|
|
32
|
+
lastActionTs = new Map();
|
|
33
|
+
/** Rolling window of action timestamps (60s) per domain-session */
|
|
34
|
+
actionWindow = new Map();
|
|
35
|
+
/** Retry count per domain-session */
|
|
36
|
+
retryCount = new Map();
|
|
37
|
+
/** Cooldown-ends-at timestamp per domain-session */
|
|
38
|
+
cooldownUntil = new Map();
|
|
39
|
+
/** TTL for idle domain state entries (30 minutes) */
|
|
40
|
+
static DOMAIN_TTL_MS = 30 * 60_000;
|
|
41
|
+
/** Minimum interval between cleanup passes (5 minutes) */
|
|
42
|
+
static CLEANUP_INTERVAL_MS = 5 * 60_000;
|
|
43
|
+
/** Timestamp of last domain-state cleanup pass */
|
|
44
|
+
lastCleanupTs = 0;
|
|
45
|
+
constructor(profileName = 'safe') {
|
|
46
|
+
this.baseConfig = types_1.POLICY_PROFILES[profileName] ?? types_1.POLICY_PROFILES.safe;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Lazily prune per-domain state entries that have been idle longer than
|
|
50
|
+
* DOMAIN_TTL_MS. Called from checkAndWait() at most once per
|
|
51
|
+
* CLEANUP_INTERVAL_MS to avoid O(n) work on every action.
|
|
52
|
+
*/
|
|
53
|
+
maybeCleanupStaleDomains() {
|
|
54
|
+
const now = Date.now();
|
|
55
|
+
if (now - this.lastCleanupTs < PolicyEngine.CLEANUP_INTERVAL_MS)
|
|
56
|
+
return;
|
|
57
|
+
this.lastCleanupTs = now;
|
|
58
|
+
for (const [key, ts] of this.lastActionTs) {
|
|
59
|
+
if (now - ts > PolicyEngine.DOMAIN_TTL_MS) {
|
|
60
|
+
this.lastActionTs.delete(key);
|
|
61
|
+
this.actionWindow.delete(key);
|
|
62
|
+
this.retryCount.delete(key);
|
|
63
|
+
this.cooldownUntil.delete(key);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
// Per-session policy management
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
setSessionPolicy(sessionId, profileName, overrides) {
|
|
71
|
+
const base = types_1.POLICY_PROFILES[profileName] ?? types_1.POLICY_PROFILES.safe;
|
|
72
|
+
this.sessionOverrides.set(sessionId, { ...base, ...overrides });
|
|
73
|
+
}
|
|
74
|
+
getSessionPolicy(sessionId) {
|
|
75
|
+
return this.sessionOverrides.get(sessionId) ?? this.baseConfig;
|
|
76
|
+
}
|
|
77
|
+
clearSession(sessionId) {
|
|
78
|
+
this.sessionOverrides.delete(sessionId);
|
|
79
|
+
for (const key of [...this.lastActionTs.keys()]) {
|
|
80
|
+
if (key.startsWith(`${sessionId}|`)) {
|
|
81
|
+
this.lastActionTs.delete(key);
|
|
82
|
+
this.actionWindow.delete(key);
|
|
83
|
+
this.retryCount.delete(key);
|
|
84
|
+
this.cooldownUntil.delete(key);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
// Core check: throttle + cooldown + bulk rate-limit + jitter + guardrails
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
91
|
+
async checkAndWait(params) {
|
|
92
|
+
const { sessionId, domain, action, sensitive = false, retry = false, auditLogger } = params;
|
|
93
|
+
const cfg = this.getSessionPolicy(sessionId);
|
|
94
|
+
const key = `${sessionId}|${domain}`;
|
|
95
|
+
let waitedMs = 0;
|
|
96
|
+
// Profile 'disabled' — fast path, no checks
|
|
97
|
+
if (cfg.profile === 'disabled') {
|
|
98
|
+
return { allowed: true, waitedMs: 0 };
|
|
99
|
+
}
|
|
100
|
+
// Lazy domain-state TTL cleanup (runs at most every 5 min)
|
|
101
|
+
this.maybeCleanupStaleDomains();
|
|
102
|
+
const aId = actionId();
|
|
103
|
+
// -- Sensitive action guardrail --
|
|
104
|
+
if (sensitive && !cfg.allowSensitiveActions) {
|
|
105
|
+
auditLogger?.write({
|
|
106
|
+
session_id: sessionId,
|
|
107
|
+
action_id: aId,
|
|
108
|
+
type: 'policy',
|
|
109
|
+
action: 'deny',
|
|
110
|
+
params: { domain, action, reason: 'sensitive_action_blocked' },
|
|
111
|
+
result: { policy_event: 'deny', profile: cfg.profile },
|
|
112
|
+
});
|
|
113
|
+
return {
|
|
114
|
+
allowed: false,
|
|
115
|
+
reason: `Sensitive action blocked by '${cfg.profile}' policy. Enable via POST /api/v1/sessions/:id/policy with {"allow_sensitive_actions":true}.`,
|
|
116
|
+
policyEvent: 'deny',
|
|
117
|
+
waitedMs: 0,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
// -- Retry budget check --
|
|
121
|
+
if (retry) {
|
|
122
|
+
const used = this.retryCount.get(key) ?? 0;
|
|
123
|
+
if (used >= cfg.maxRetriesPerDomain) {
|
|
124
|
+
auditLogger?.write({
|
|
125
|
+
session_id: sessionId,
|
|
126
|
+
action_id: aId,
|
|
127
|
+
type: 'policy',
|
|
128
|
+
action: 'deny',
|
|
129
|
+
params: { domain, action, reason: 'retry_budget_exhausted', used, max: cfg.maxRetriesPerDomain },
|
|
130
|
+
result: { policy_event: 'deny', profile: cfg.profile },
|
|
131
|
+
});
|
|
132
|
+
return {
|
|
133
|
+
allowed: false,
|
|
134
|
+
reason: `Retry budget exhausted for domain '${domain}' (${used}/${cfg.maxRetriesPerDomain} retries used).`,
|
|
135
|
+
policyEvent: 'deny',
|
|
136
|
+
waitedMs: 0,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
this.retryCount.set(key, used + 1);
|
|
140
|
+
auditLogger?.write({
|
|
141
|
+
session_id: sessionId,
|
|
142
|
+
action_id: aId,
|
|
143
|
+
type: 'policy',
|
|
144
|
+
action: 'retry',
|
|
145
|
+
params: { domain, action, retry_count: used + 1, max: cfg.maxRetriesPerDomain },
|
|
146
|
+
result: { policy_event: 'retry', profile: cfg.profile },
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
// -- Cooldown check --
|
|
150
|
+
const cooldownEnd = this.cooldownUntil.get(key) ?? 0;
|
|
151
|
+
const now = Date.now();
|
|
152
|
+
if (now < cooldownEnd) {
|
|
153
|
+
const waitMs = cooldownEnd - now;
|
|
154
|
+
auditLogger?.write({
|
|
155
|
+
session_id: sessionId,
|
|
156
|
+
action_id: aId,
|
|
157
|
+
type: 'policy',
|
|
158
|
+
action: 'cooldown',
|
|
159
|
+
params: { domain, action, wait_ms: waitMs },
|
|
160
|
+
result: { policy_event: 'cooldown', profile: cfg.profile },
|
|
161
|
+
});
|
|
162
|
+
await sleep(waitMs);
|
|
163
|
+
waitedMs += waitMs;
|
|
164
|
+
}
|
|
165
|
+
// -- Bulk rate-limit (rolling 60s window) --
|
|
166
|
+
const now2 = Date.now();
|
|
167
|
+
const recent = (this.actionWindow.get(key) ?? []).filter((t) => now2 - t < 60_000);
|
|
168
|
+
if (recent.length >= cfg.maxActionsPerMinute) {
|
|
169
|
+
const oldestInWindow = recent[0];
|
|
170
|
+
const waitMs = 60_000 - (now2 - oldestInWindow) + 100;
|
|
171
|
+
auditLogger?.write({
|
|
172
|
+
session_id: sessionId,
|
|
173
|
+
action_id: aId,
|
|
174
|
+
type: 'policy',
|
|
175
|
+
action: 'throttle',
|
|
176
|
+
params: { domain, action, reason: 'bulk_rate_limit', wait_ms: waitMs, actions_in_window: recent.length },
|
|
177
|
+
result: { policy_event: 'throttle', profile: cfg.profile },
|
|
178
|
+
});
|
|
179
|
+
await sleep(waitMs);
|
|
180
|
+
waitedMs += waitMs;
|
|
181
|
+
}
|
|
182
|
+
// -- Domain min-interval throttle --
|
|
183
|
+
const now3 = Date.now();
|
|
184
|
+
const lastT = this.lastActionTs.get(key) ?? 0;
|
|
185
|
+
const elapsed = now3 - lastT;
|
|
186
|
+
if (elapsed < cfg.domainMinIntervalMs) {
|
|
187
|
+
const waitMs = cfg.domainMinIntervalMs - elapsed;
|
|
188
|
+
auditLogger?.write({
|
|
189
|
+
session_id: sessionId,
|
|
190
|
+
action_id: aId,
|
|
191
|
+
type: 'policy',
|
|
192
|
+
action: 'throttle',
|
|
193
|
+
params: { domain, action, reason: 'min_interval', wait_ms: waitMs, elapsed_ms: elapsed },
|
|
194
|
+
result: { policy_event: 'throttle', profile: cfg.profile },
|
|
195
|
+
});
|
|
196
|
+
await sleep(waitMs);
|
|
197
|
+
waitedMs += waitMs;
|
|
198
|
+
}
|
|
199
|
+
// -- Jitter --
|
|
200
|
+
const [jMin, jMax] = cfg.jitterMs;
|
|
201
|
+
const jitter = jMax > jMin ? Math.round(jMin + Math.random() * (jMax - jMin)) : jMin;
|
|
202
|
+
if (jitter > 0) {
|
|
203
|
+
await sleep(jitter);
|
|
204
|
+
waitedMs += jitter;
|
|
205
|
+
}
|
|
206
|
+
// -- Update tracking state --
|
|
207
|
+
const now4 = Date.now();
|
|
208
|
+
this.lastActionTs.set(key, now4);
|
|
209
|
+
const updatedWindow = [...recent.filter((t) => now4 - t < 60_000), now4];
|
|
210
|
+
this.actionWindow.set(key, updatedWindow);
|
|
211
|
+
return { allowed: true, waitedMs, policyEvent: waitedMs > 0 ? 'throttle' : undefined };
|
|
212
|
+
}
|
|
213
|
+
// ---------------------------------------------------------------------------
|
|
214
|
+
// Error / cooldown recording (call after an action receives a rate-limit error)
|
|
215
|
+
// ---------------------------------------------------------------------------
|
|
216
|
+
recordError(sessionId, domain, auditLogger) {
|
|
217
|
+
const cfg = this.getSessionPolicy(sessionId);
|
|
218
|
+
if (cfg.cooldownAfterErrorMs <= 0)
|
|
219
|
+
return;
|
|
220
|
+
const key = `${sessionId}|${domain}`;
|
|
221
|
+
const until = Date.now() + cfg.cooldownAfterErrorMs;
|
|
222
|
+
this.cooldownUntil.set(key, until);
|
|
223
|
+
auditLogger?.write({
|
|
224
|
+
session_id: sessionId,
|
|
225
|
+
action_id: actionId(),
|
|
226
|
+
type: 'policy',
|
|
227
|
+
action: 'cooldown',
|
|
228
|
+
params: { domain, reason: 'error_recorded', cooldown_until: new Date(until).toISOString() },
|
|
229
|
+
result: { policy_event: 'cooldown', profile: cfg.profile },
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
exports.PolicyEngine = PolicyEngine;
|
|
234
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/policy/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agentmb — social-media safety execution policy (r06-c02)
|
|
3
|
+
*
|
|
4
|
+
* Provides domain-level throttling, random jitter, cooldown windows, retry
|
|
5
|
+
* budgets, and sensitive-action guardrails to reduce platform risk-control
|
|
6
|
+
* triggering during automated browser workflows.
|
|
7
|
+
*/
|
|
8
|
+
export type PolicyProfileName = 'safe' | 'permissive' | 'disabled';
|
|
9
|
+
export interface PolicyConfig {
|
|
10
|
+
/** Profile name used for identification and audit logs. */
|
|
11
|
+
profile: PolicyProfileName;
|
|
12
|
+
/** Minimum milliseconds between two successive actions on the same domain. */
|
|
13
|
+
domainMinIntervalMs: number;
|
|
14
|
+
/** [min, max] random jitter added before every action (ms). */
|
|
15
|
+
jitterMs: [number, number];
|
|
16
|
+
/** Milliseconds to wait after a rate-limit/error response before next action. */
|
|
17
|
+
cooldownAfterErrorMs: number;
|
|
18
|
+
/** Maximum number of retry attempts allowed per domain per session. */
|
|
19
|
+
maxRetriesPerDomain: number;
|
|
20
|
+
/** Maximum total actions per domain within a rolling 60-second window. */
|
|
21
|
+
maxActionsPerMinute: number;
|
|
22
|
+
/**
|
|
23
|
+
* When false (default in 'safe'), requests with sensitive=true are denied
|
|
24
|
+
* unless the session has explicitly enabled sensitive actions.
|
|
25
|
+
*/
|
|
26
|
+
allowSensitiveActions: boolean;
|
|
27
|
+
}
|
|
28
|
+
/** Built-in policy profiles. */
|
|
29
|
+
export declare const POLICY_PROFILES: Record<PolicyProfileName, PolicyConfig>;
|
|
30
|
+
export type PolicyEvent = 'throttle' | 'cooldown' | 'deny' | 'retry' | 'jitter';
|
|
31
|
+
export interface PolicyCheckResult {
|
|
32
|
+
allowed: boolean;
|
|
33
|
+
/** Present when allowed=false */
|
|
34
|
+
reason?: string;
|
|
35
|
+
/** Type of policy event that triggered a wait or denial */
|
|
36
|
+
policyEvent?: PolicyEvent;
|
|
37
|
+
/** Total milliseconds waited due to policy (jitter + throttle + cooldown) */
|
|
38
|
+
waitedMs: number;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/policy/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,YAAY,GAAG,UAAU,CAAA;AAElE,MAAM,WAAW,YAAY;IAC3B,2DAA2D;IAC3D,OAAO,EAAE,iBAAiB,CAAA;IAK1B,8EAA8E;IAC9E,mBAAmB,EAAE,MAAM,CAAA;IAE3B,+DAA+D;IAC/D,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAK1B,iFAAiF;IACjF,oBAAoB,EAAE,MAAM,CAAA;IAK5B,uEAAuE;IACvE,mBAAmB,EAAE,MAAM,CAAA;IAK3B,0EAA0E;IAC1E,mBAAmB,EAAE,MAAM,CAAA;IAK3B;;;OAGG;IACH,qBAAqB,EAAE,OAAO,CAAA;CAC/B;AAED,gCAAgC;AAChC,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,iBAAiB,EAAE,YAAY,CA0CnE,CAAA;AAED,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,UAAU,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAA;AAE/E,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAA;IAChB,iCAAiC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,2DAA2D;IAC3D,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,CAAA;CACjB"}
|