@ravi-hq/ravi 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.
Files changed (85) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +271 -0
  3. package/dist/channels/email.d.ts +221 -0
  4. package/dist/channels/email.d.ts.map +1 -0
  5. package/dist/channels/email.js +143 -0
  6. package/dist/channels/email.js.map +1 -0
  7. package/dist/channels/sms.d.ts +223 -0
  8. package/dist/channels/sms.d.ts.map +1 -0
  9. package/dist/channels/sms.js +141 -0
  10. package/dist/channels/sms.js.map +1 -0
  11. package/dist/cli.d.ts +24 -0
  12. package/dist/cli.d.ts.map +1 -0
  13. package/dist/cli.js +390 -0
  14. package/dist/cli.js.map +1 -0
  15. package/dist/client.d.ts +174 -0
  16. package/dist/client.d.ts.map +1 -0
  17. package/dist/client.js +289 -0
  18. package/dist/client.js.map +1 -0
  19. package/dist/config.d.ts +9 -0
  20. package/dist/config.d.ts.map +1 -0
  21. package/dist/config.js +9 -0
  22. package/dist/config.js.map +1 -0
  23. package/dist/crypto.d.ts +143 -0
  24. package/dist/crypto.d.ts.map +1 -0
  25. package/dist/crypto.js +310 -0
  26. package/dist/crypto.js.map +1 -0
  27. package/dist/index.d.ts +79 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +143 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/service.d.ts +98 -0
  32. package/dist/service.d.ts.map +1 -0
  33. package/dist/service.js +130 -0
  34. package/dist/service.js.map +1 -0
  35. package/dist/sse.d.ts +110 -0
  36. package/dist/sse.d.ts.map +1 -0
  37. package/dist/sse.js +269 -0
  38. package/dist/sse.js.map +1 -0
  39. package/dist/tools/email-send.d.ts +13 -0
  40. package/dist/tools/email-send.d.ts.map +1 -0
  41. package/dist/tools/email-send.js +60 -0
  42. package/dist/tools/email-send.js.map +1 -0
  43. package/dist/tools/feedback.d.ts +13 -0
  44. package/dist/tools/feedback.d.ts.map +1 -0
  45. package/dist/tools/feedback.js +43 -0
  46. package/dist/tools/feedback.js.map +1 -0
  47. package/dist/tools/identity.d.ts +43 -0
  48. package/dist/tools/identity.d.ts.map +1 -0
  49. package/dist/tools/identity.js +59 -0
  50. package/dist/tools/identity.js.map +1 -0
  51. package/dist/tools/inbox.d.ts +22 -0
  52. package/dist/tools/inbox.d.ts.map +1 -0
  53. package/dist/tools/inbox.js +166 -0
  54. package/dist/tools/inbox.js.map +1 -0
  55. package/dist/tools/passwords.d.ts +19 -0
  56. package/dist/tools/passwords.d.ts.map +1 -0
  57. package/dist/tools/passwords.js +165 -0
  58. package/dist/tools/passwords.js.map +1 -0
  59. package/dist/tools/sms-send.d.ts +11 -0
  60. package/dist/tools/sms-send.d.ts.map +1 -0
  61. package/dist/tools/sms-send.js +32 -0
  62. package/dist/tools/sms-send.js.map +1 -0
  63. package/dist/tools/vault.d.ts +15 -0
  64. package/dist/tools/vault.d.ts.map +1 -0
  65. package/dist/tools/vault.js +97 -0
  66. package/dist/tools/vault.js.map +1 -0
  67. package/dist/types.d.ts +137 -0
  68. package/dist/types.d.ts.map +1 -0
  69. package/dist/types.js +7 -0
  70. package/dist/types.js.map +1 -0
  71. package/dist/utils.d.ts +11 -0
  72. package/dist/utils.d.ts.map +1 -0
  73. package/dist/utils.js +18 -0
  74. package/dist/utils.js.map +1 -0
  75. package/openclaw.plugin.json +33 -0
  76. package/package.json +70 -0
  77. package/skills/CLAUDE.md +36 -0
  78. package/skills/ravi/SKILL.md +46 -0
  79. package/skills/ravi-email-send/SKILL.md +44 -0
  80. package/skills/ravi-feedback/SKILL.md +37 -0
  81. package/skills/ravi-identity/SKILL.md +50 -0
  82. package/skills/ravi-inbox/SKILL.md +58 -0
  83. package/skills/ravi-login/SKILL.md +42 -0
  84. package/skills/ravi-passwords/SKILL.md +48 -0
  85. package/skills/ravi-vault/SKILL.md +54 -0
package/dist/cli.js ADDED
@@ -0,0 +1,390 @@
1
+ import { execFile } from "node:child_process";
2
+ import { createInterface } from "node:readline";
3
+ import { mkdirSync, writeFileSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ import { homedir, platform } from "node:os";
6
+ import { RAVI_API_URL } from "./config.js";
7
+ import { RaviClient, RaviApiError } from "./client.js";
8
+ /** Try to open a URL in the user's default browser. Non-fatal on failure. */
9
+ function openBrowser(url) {
10
+ const cmd = platform() === "darwin" ? "open" :
11
+ platform() === "win32" ? "cmd" :
12
+ "xdg-open";
13
+ const args = platform() === "win32" ? ["/c", "start", url] : [url];
14
+ execFile(cmd, args, () => {
15
+ // Silently ignore errors — user can open the URL manually
16
+ });
17
+ }
18
+ /**
19
+ * Prompt the user for a 6-digit PIN via stdin (hidden input).
20
+ * Matches the CLI's interactive PIN prompt behavior.
21
+ */
22
+ async function promptPIN(prompt) {
23
+ return new Promise((resolve, reject) => {
24
+ const rl = createInterface({ input: process.stdin, output: process.stderr });
25
+ // Mute output to hide PIN typing (write prompt to stderr like the CLI)
26
+ process.stderr.write(prompt);
27
+ const stdin = process.stdin;
28
+ const wasRaw = stdin.isRaw;
29
+ if (stdin.isTTY && stdin.setRawMode) {
30
+ stdin.setRawMode(true);
31
+ }
32
+ let pin = "";
33
+ const onData = (key) => {
34
+ const ch = key.toString();
35
+ if (ch === "\r" || ch === "\n") {
36
+ // Done
37
+ if (stdin.isTTY && stdin.setRawMode)
38
+ stdin.setRawMode(wasRaw ?? false);
39
+ stdin.removeListener("data", onData);
40
+ process.stderr.write("\n");
41
+ rl.close();
42
+ resolve(pin);
43
+ }
44
+ else if (ch === "\x03") {
45
+ // Ctrl+C
46
+ if (stdin.isTTY && stdin.setRawMode)
47
+ stdin.setRawMode(wasRaw ?? false);
48
+ stdin.removeListener("data", onData);
49
+ rl.close();
50
+ reject(new Error("Cancelled"));
51
+ }
52
+ else if (ch === "\x7f" || ch === "\b") {
53
+ // Backspace
54
+ pin = pin.slice(0, -1);
55
+ }
56
+ else if (ch.length === 1 && ch >= " ") {
57
+ pin += ch;
58
+ }
59
+ };
60
+ stdin.on("data", onData);
61
+ });
62
+ }
63
+ /**
64
+ * Prompt for PIN with choose + confirm (first-time setup),
65
+ * or just enter PIN (returning user). Validates 6-digit format.
66
+ */
67
+ async function promptAndConfirmPIN() {
68
+ const pin = await promptPIN("Choose a 6-digit encryption PIN: ");
69
+ if (!/^\d{6}$/.test(pin)) {
70
+ throw new Error("PIN must be exactly 6 digits.");
71
+ }
72
+ const confirm = await promptPIN("Confirm PIN: ");
73
+ if (pin !== confirm) {
74
+ throw new Error("PINs do not match.");
75
+ }
76
+ return pin;
77
+ }
78
+ async function promptExistingPIN() {
79
+ const pin = await promptPIN("Enter your 6-digit encryption PIN: ");
80
+ if (!/^\d{6}$/.test(pin)) {
81
+ throw new Error("PIN must be exactly 6 digits.");
82
+ }
83
+ return pin;
84
+ }
85
+ /**
86
+ * Save recovery key to ~/.ravi/recovery-key.txt (same location as CLI).
87
+ * Creates ~/.ravi/ directory if needed. File permissions: 0600.
88
+ */
89
+ function saveRecoveryKey(recoveryKey) {
90
+ const raviDir = join(homedir(), ".ravi");
91
+ mkdirSync(raviDir, { recursive: true, mode: 0o700 });
92
+ const filePath = join(raviDir, "recovery-key.txt");
93
+ writeFileSync(filePath, recoveryKey + "\n", { mode: 0o600 });
94
+ return filePath;
95
+ }
96
+ // ─── Command Definitions ────────────────────────────────────────────────────
97
+ /**
98
+ * All CLI commands exposed by the Ravi plugin.
99
+ *
100
+ * OpenClaw registers these so the user can run `openclaw ravi login`,
101
+ * `openclaw ravi status`, etc.
102
+ */
103
+ export const cliCommands = [
104
+ // ── login ───────────────────────────────────────────────────────────────
105
+ {
106
+ name: "login",
107
+ description: "Authenticate with Ravi using device code flow. Opens a browser for login.",
108
+ handler: async (_args, config) => {
109
+ const apiUrl = RAVI_API_URL;
110
+ // Step 1: Initiate device code flow
111
+ const response = await fetch(`${apiUrl}/api/auth/device/`, {
112
+ method: "POST",
113
+ headers: { "Content-Type": "application/json" },
114
+ });
115
+ if (!response.ok) {
116
+ const detail = await response.text().catch(() => "");
117
+ throw new Error(`Failed to initiate device code flow (HTTP ${response.status}): ${detail}`);
118
+ }
119
+ const data = (await response.json());
120
+ // Step 2: Open browser and display user code
121
+ // Pass user_code as query param so the verify page auto-fills it
122
+ const verifyUrl = `${data.verification_uri}?user_code=${data.user_code}`;
123
+ openBrowser(verifyUrl);
124
+ let output = `\nTo authenticate, visit: ${verifyUrl}\n`;
125
+ output += `Code: ${data.user_code}\n`;
126
+ output += `(Attempting to open browser automatically)\n\n`;
127
+ output += `Waiting for authorization...\n`;
128
+ // Step 3: Poll for token until authorized or expired
129
+ const intervalMs = (data.interval || 5) * 1000;
130
+ const deadline = Date.now() + data.expires_in * 1000;
131
+ let consecutiveNetworkErrors = 0;
132
+ while (Date.now() < deadline) {
133
+ await new Promise((resolve) => setTimeout(resolve, intervalMs));
134
+ let tokenResponse;
135
+ try {
136
+ tokenResponse = await fetch(`${apiUrl}/api/auth/device/token/`, {
137
+ method: "POST",
138
+ headers: { "Content-Type": "application/json" },
139
+ body: JSON.stringify({ device_code: data.device_code }),
140
+ });
141
+ }
142
+ catch {
143
+ consecutiveNetworkErrors++;
144
+ if (consecutiveNetworkErrors >= 3) {
145
+ throw new Error(`Network error during login — failed ${consecutiveNetworkErrors} consecutive times. ` +
146
+ `Check your network connection and that ${apiUrl} is reachable.`);
147
+ }
148
+ continue;
149
+ }
150
+ consecutiveNetworkErrors = 0;
151
+ if (tokenResponse.ok) {
152
+ const tokenData = (await tokenResponse.json());
153
+ // Step 4: Check encryption status and handle PIN setup/verification
154
+ const client = new RaviClient({ apiUrl, token: tokenData.access });
155
+ output += `\nAuthenticated as ${tokenData.user.email}\n\n`;
156
+ // Track PIN resolved during this session (from config or prompted)
157
+ let resolvedPin = config.pin;
158
+ // Check encryption status
159
+ // Backend uses get_or_create — always returns 200 with empty public_key for new users
160
+ let meta = null;
161
+ try {
162
+ meta = await client.getEncryptionMeta();
163
+ }
164
+ catch (err) {
165
+ const msg = err instanceof Error ? err.message : String(err);
166
+ output += `WARNING: Could not check encryption status: ${msg}\n`;
167
+ output += `Encryption features may not work correctly.\n\n`;
168
+ }
169
+ if (meta && !meta.public_key) {
170
+ // First-time setup — prompt for PIN if not in config
171
+ if (!resolvedPin) {
172
+ try {
173
+ resolvedPin = await promptAndConfirmPIN();
174
+ }
175
+ catch (err) {
176
+ const msg = err instanceof Error ? err.message : String(err);
177
+ output += `PIN setup cancelled: ${msg}\n`;
178
+ output += `Run 'openclaw ravi login' again to set up encryption.\n\n`;
179
+ }
180
+ }
181
+ if (resolvedPin) {
182
+ try {
183
+ const { setupEncryption } = await import("./crypto.js");
184
+ const setup = await setupEncryption(resolvedPin);
185
+ // Save recovery key to ~/.ravi/recovery-key.txt (same as CLI)
186
+ const recoveryPath = saveRecoveryKey(setup.recoveryKey);
187
+ // Register with server
188
+ await client.updateEncryptionMeta({
189
+ salt: setup.salt,
190
+ public_key: setup.publicKey,
191
+ verifier: setup.verifier,
192
+ });
193
+ output += `E2E encryption set up successfully!\n`;
194
+ output += `Recovery key saved to ${recoveryPath} — back this up!\n\n`;
195
+ }
196
+ catch (err) {
197
+ const msg = err instanceof Error ? err.message : String(err);
198
+ output += `Failed to set up encryption: ${msg}\n`;
199
+ output += `You can try again by running 'openclaw ravi login'.\n\n`;
200
+ }
201
+ }
202
+ }
203
+ else if (meta && meta.public_key) {
204
+ // Existing encryption — verify PIN (prompt if not in config)
205
+ if (!resolvedPin) {
206
+ try {
207
+ resolvedPin = await promptExistingPIN();
208
+ }
209
+ catch (err) {
210
+ const msg = err instanceof Error ? err.message : String(err);
211
+ output += `PIN entry cancelled: ${msg}\n\n`;
212
+ }
213
+ }
214
+ if (resolvedPin) {
215
+ try {
216
+ const { deriveKeyPair, verify } = await import("./crypto.js");
217
+ const kp = await deriveKeyPair(resolvedPin, meta.salt);
218
+ const valid = await verify(kp, meta.verifier);
219
+ if (valid) {
220
+ output += `PIN verified — E2E encryption is ready.\n\n`;
221
+ }
222
+ else {
223
+ output += `WARNING: PIN does not match! Check your PIN.\n\n`;
224
+ }
225
+ }
226
+ catch (err) {
227
+ const msg = err instanceof Error ? err.message : String(err);
228
+ output += `PIN verification failed: ${msg}\n\n`;
229
+ }
230
+ }
231
+ }
232
+ // Fetch identities to auto-include identityUuid
233
+ let identityUuidLine = "";
234
+ try {
235
+ const identities = await client.listIdentities();
236
+ if (identities.length === 1) {
237
+ identityUuidLine = ` "identityUuid": "${identities[0].uuid}",\n`;
238
+ output += `Auto-selected identity: ${identities[0].name} (${identities[0].uuid})\n\n`;
239
+ }
240
+ else if (identities.length > 1) {
241
+ output += `Multiple identities found. Add one to your config as "identityUuid":\n`;
242
+ for (const identity of identities) {
243
+ output += ` - ${identity.name}: ${identity.uuid}\n`;
244
+ }
245
+ output += `\n`;
246
+ }
247
+ else {
248
+ output += `No identities found. Create one first, then add its UUID to config as "identityUuid".\n\n`;
249
+ }
250
+ }
251
+ catch {
252
+ // Can't list identities — skip auto-include
253
+ }
254
+ // Output config snippet
255
+ output += `Plugin config:\n\n`;
256
+ output += `{\n`;
257
+ output += ` "plugins": {\n`;
258
+ output += ` "entries": {\n`;
259
+ output += ` "ravi": {\n`;
260
+ output += ` "enabled": true,\n`;
261
+ output += ` "config": {\n`;
262
+ // apiUrl is baked in at build time — not part of user config
263
+ output += ` "token": "${tokenData.access}",\n`;
264
+ output += ` "refreshToken": "${tokenData.refresh}",\n`;
265
+ output += identityUuidLine;
266
+ output += ` "pin": "${resolvedPin ?? "YOUR_6_DIGIT_PIN"}"\n`;
267
+ output += ` }\n`;
268
+ output += ` }\n`;
269
+ output += ` }\n`;
270
+ output += ` }\n`;
271
+ output += `}\n\n`;
272
+ output += `Run 'openclaw ravi setup' to configure channels.\n`;
273
+ return output;
274
+ }
275
+ // Check whether the error is "still waiting" or a terminal failure
276
+ const error = (await tokenResponse.json().catch(() => ({})));
277
+ if (error.error !== "authorization_pending") {
278
+ throw new Error(`Device code flow failed: ${error.error ?? `HTTP ${tokenResponse.status}`}`);
279
+ }
280
+ }
281
+ throw new Error("Device code expired. Please try again.");
282
+ },
283
+ },
284
+ // ── status ──────────────────────────────────────────────────────────────
285
+ {
286
+ name: "status",
287
+ description: "Show authentication status and available identities.",
288
+ handler: async (_args, config) => {
289
+ if (!config.token) {
290
+ return `Not configured. Run 'openclaw ravi login' to authenticate.`;
291
+ }
292
+ const apiUrl = RAVI_API_URL;
293
+ const client = new RaviClient({ apiUrl, token: config.token });
294
+ try {
295
+ const identities = await client.listIdentities();
296
+ let output = `Authenticated to ${apiUrl}\n`;
297
+ output += `PIN configured: ${config.pin ? "Yes" : "No"}\n`;
298
+ output += `\nIdentities (${identities.length}):\n`;
299
+ for (const identity of identities) {
300
+ output += ` - ${identity.name} (${identity.uuid})\n`;
301
+ if (identity.email)
302
+ output += ` Email: ${identity.email}\n`;
303
+ if (identity.phone)
304
+ output += ` Phone: ${identity.phone}\n`;
305
+ }
306
+ if (!config.pin) {
307
+ output += `\nWARNING: No PIN configured — encrypted data (passwords, vault) will not be readable.\n`;
308
+ output += `Add your PIN to the plugin config to enable E2E decryption.\n`;
309
+ }
310
+ return output;
311
+ }
312
+ catch (err) {
313
+ if (err instanceof RaviApiError && (err.status === 401 || err.status === 403)) {
314
+ return `Token expired or invalid. Run 'openclaw ravi login' to re-authenticate.`;
315
+ }
316
+ if (err instanceof RaviApiError && err.status === 402) {
317
+ return `Billing issue (HTTP 402). Please check your Ravi subscription.`;
318
+ }
319
+ const message = err instanceof Error ? err.message : String(err);
320
+ return `Failed to fetch status: ${message}\n\nIf this persists, check your network connection and API URL.`;
321
+ }
322
+ },
323
+ },
324
+ // ── setup ───────────────────────────────────────────────────────────────
325
+ {
326
+ name: "setup",
327
+ description: "Interactive setup for email and SMS channels.",
328
+ handler: async (_args, config) => {
329
+ const apiUrl = RAVI_API_URL;
330
+ const client = new RaviClient({ apiUrl, token: config.token });
331
+ const identities = await client.listIdentities();
332
+ if (identities.length === 0) {
333
+ return "No identities found. Create one first with the 'ravi_identity_create' tool.";
334
+ }
335
+ let output = "Channel Configuration\n";
336
+ output += "=====================\n\n";
337
+ // Suggest identityUuid for plugin config
338
+ if (identities.length === 1) {
339
+ output += `Tip: Add this to your plugin config to scope all tools to this identity:\n`;
340
+ output += ` "identityUuid": "${identities[0].uuid}"\n\n`;
341
+ }
342
+ else {
343
+ output += `Tip: Add "identityUuid" to your plugin config to scope all tools to one identity:\n`;
344
+ for (const identity of identities) {
345
+ output += ` - ${identity.name}: "${identity.uuid}"\n`;
346
+ }
347
+ output += `\n`;
348
+ }
349
+ output += "Add this to your OpenClaw config under the 'channels' key.\n\n";
350
+ output += `"channels": {\n`;
351
+ // Email accounts
352
+ const emailIdentities = identities.filter(i => i.email);
353
+ if (emailIdentities.length > 0) {
354
+ output += ` "ravi-email": {\n`;
355
+ output += ` "accounts": {\n`;
356
+ for (const [idx, identity] of emailIdentities.entries()) {
357
+ output += ` "${identity.uuid}": {\n`;
358
+ output += ` "identityUuid": "${identity.uuid}",\n`;
359
+ output += ` "identityName": "${identity.name}",\n`;
360
+ output += ` "email": "${identity.email}"\n`;
361
+ output += ` }${idx < emailIdentities.length - 1 ? "," : ""}\n`;
362
+ }
363
+ output += ` }\n`;
364
+ output += ` },\n`;
365
+ }
366
+ // SMS accounts
367
+ const phoneIdentities = identities.filter(i => i.phone);
368
+ if (phoneIdentities.length > 0) {
369
+ output += ` "ravi-sms": {\n`;
370
+ output += ` "accounts": {\n`;
371
+ for (const [idx, identity] of phoneIdentities.entries()) {
372
+ output += ` "${identity.uuid}": {\n`;
373
+ output += ` "identityUuid": "${identity.uuid}",\n`;
374
+ output += ` "identityName": "${identity.name}",\n`;
375
+ output += ` "phone": "${identity.phone}"\n`;
376
+ output += ` }${idx < phoneIdentities.length - 1 ? "," : ""}\n`;
377
+ }
378
+ output += ` }\n`;
379
+ output += ` }\n`;
380
+ }
381
+ output += `}\n\n`;
382
+ output += `NOTE: Messages from your personal email (owner) and other Ravi identities (self)\n`;
383
+ output += `give the agent full access. Messages from unknown senders (external) are delivered\n`;
384
+ output += `as read-only context — the agent can see them but cannot respond or use write tools.\n`;
385
+ output += `To allow someone full access, add them as a personal email on the Ravi dashboard.\n`;
386
+ return output;
387
+ },
388
+ },
389
+ ];
390
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGvD,6EAA6E;AAC7E,SAAS,WAAW,CAAC,GAAW;IAC9B,MAAM,GAAG,GACP,QAAQ,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAClC,QAAQ,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YAChC,UAAU,CAAC;IACb,MAAM,IAAI,GAAG,QAAQ,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACnE,QAAQ,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE;QACvB,0DAA0D;IAC5D,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,SAAS,CAAC,MAAc;IACrC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QAC7E,uEAAuE;QACvE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC7B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC5B,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC;QAC3B,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;YACpC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;QAED,IAAI,GAAG,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,GAAG,CAAC,GAAW,EAAE,EAAE;YAC7B,MAAM,EAAE,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;YAC1B,IAAI,EAAE,KAAK,IAAI,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;gBAC/B,OAAO;gBACP,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,UAAU;oBAAE,KAAK,CAAC,UAAU,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC;gBACvE,KAAK,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;gBACrC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC3B,EAAE,CAAC,KAAK,EAAE,CAAC;gBACX,OAAO,CAAC,GAAG,CAAC,CAAC;YACf,CAAC;iBAAM,IAAI,EAAE,KAAK,MAAM,EAAE,CAAC;gBACzB,SAAS;gBACT,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,UAAU;oBAAE,KAAK,CAAC,UAAU,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC;gBACvE,KAAK,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;gBACrC,EAAE,CAAC,KAAK,EAAE,CAAC;gBACX,MAAM,CAAC,IAAI,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;YACjC,CAAC;iBAAM,IAAI,EAAE,KAAK,MAAM,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;gBACxC,YAAY;gBACZ,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACzB,CAAC;iBAAM,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,IAAI,EAAE,IAAI,GAAG,EAAE,CAAC;gBACxC,GAAG,IAAI,EAAE,CAAC;YACZ,CAAC;QACH,CAAC,CAAC;QACF,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,mBAAmB;IAChC,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,mCAAmC,CAAC,CAAC;IACjE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACnD,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,eAAe,CAAC,CAAC;IACjD,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,KAAK,UAAU,iBAAiB;IAC9B,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,qCAAqC,CAAC,CAAC;IACnE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;GAGG;AACH,SAAS,eAAe,CAAC,WAAmB;IAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;IACzC,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACrD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;IACnD,aAAa,CAAC,QAAQ,EAAE,WAAW,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC7D,OAAO,QAAQ,CAAC;AAClB,CAAC;AAoBD,+EAA+E;AAE/E;;;;;GAKG;AACH,MAAM,CAAC,MAAM,WAAW,GAAiB;IACvC,2EAA2E;IAC3E;QACE,IAAI,EAAE,OAAO;QACb,WAAW,EACT,2EAA2E;QAC7E,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;YAC/B,MAAM,MAAM,GAAG,YAAY,CAAC;YAE5B,oCAAoC;YACpC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,mBAAmB,EAAE;gBACzD,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;aAChD,CAAC,CAAC;YAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;gBACrD,MAAM,IAAI,KAAK,CACb,6CAA6C,QAAQ,CAAC,MAAM,MAAM,MAAM,EAAE,CAC3E,CAAC;YACJ,CAAC;YAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAMlC,CAAC;YAEF,6CAA6C;YAC7C,iEAAiE;YACjE,MAAM,SAAS,GAAG,GAAG,IAAI,CAAC,gBAAgB,cAAc,IAAI,CAAC,SAAS,EAAE,CAAC;YACzE,WAAW,CAAC,SAAS,CAAC,CAAC;YAEvB,IAAI,MAAM,GAAG,6BAA6B,SAAS,IAAI,CAAC;YACxD,MAAM,IAAI,SAAS,IAAI,CAAC,SAAS,IAAI,CAAC;YACtC,MAAM,IAAI,gDAAgD,CAAC;YAC3D,MAAM,IAAI,gCAAgC,CAAC;YAE3C,qDAAqD;YACrD,MAAM,UAAU,GAAG,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC;YAC/C,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;YACrD,IAAI,wBAAwB,GAAG,CAAC,CAAC;YAEjC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;gBAC7B,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC;gBAEhE,IAAI,aAAuB,CAAC;gBAC5B,IAAI,CAAC;oBACH,aAAa,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,yBAAyB,EAAE;wBAC9D,MAAM,EAAE,MAAM;wBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;wBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC;qBACxD,CAAC,CAAC;gBACL,CAAC;gBAAC,MAAM,CAAC;oBACP,wBAAwB,EAAE,CAAC;oBAC3B,IAAI,wBAAwB,IAAI,CAAC,EAAE,CAAC;wBAClC,MAAM,IAAI,KAAK,CACb,uCAAuC,wBAAwB,sBAAsB;4BACrF,0CAA0C,MAAM,gBAAgB,CACjE,CAAC;oBACJ,CAAC;oBACD,SAAS;gBACX,CAAC;gBAED,wBAAwB,GAAG,CAAC,CAAC;gBAE7B,IAAI,aAAa,CAAC,EAAE,EAAE,CAAC;oBACrB,MAAM,SAAS,GAAG,CAAC,MAAM,aAAa,CAAC,IAAI,EAAE,CAI5C,CAAC;oBAEF,oEAAoE;oBACpE,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;oBAEnE,MAAM,IAAI,sBAAsB,SAAS,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC;oBAE3D,mEAAmE;oBACnE,IAAI,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC;oBAE7B,0BAA0B;oBAC1B,sFAAsF;oBACtF,IAAI,IAAI,GAAkE,IAAI,CAAC;oBAC/E,IAAI,CAAC;wBACH,IAAI,GAAG,MAAM,MAAM,CAAC,iBAAiB,EAAE,CAAC;oBAC1C,CAAC;oBAAC,OAAO,GAAG,EAAE,CAAC;wBACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;wBAC7D,MAAM,IAAI,+CAA+C,GAAG,IAAI,CAAC;wBACjE,MAAM,IAAI,iDAAiD,CAAC;oBAC9D,CAAC;oBAED,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;wBAC7B,qDAAqD;wBACrD,IAAI,CAAC,WAAW,EAAE,CAAC;4BACjB,IAAI,CAAC;gCACH,WAAW,GAAG,MAAM,mBAAmB,EAAE,CAAC;4BAC5C,CAAC;4BAAC,OAAO,GAAG,EAAE,CAAC;gCACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gCAC7D,MAAM,IAAI,wBAAwB,GAAG,IAAI,CAAC;gCAC1C,MAAM,IAAI,2DAA2D,CAAC;4BACxE,CAAC;wBACH,CAAC;wBAED,IAAI,WAAW,EAAE,CAAC;4BAChB,IAAI,CAAC;gCACH,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;gCACxD,MAAM,KAAK,GAAG,MAAM,eAAe,CAAC,WAAW,CAAC,CAAC;gCAEjD,8DAA8D;gCAC9D,MAAM,YAAY,GAAG,eAAe,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;gCAExD,uBAAuB;gCACvB,MAAM,MAAM,CAAC,oBAAoB,CAAC;oCAChC,IAAI,EAAE,KAAK,CAAC,IAAI;oCAChB,UAAU,EAAE,KAAK,CAAC,SAAS;oCAC3B,QAAQ,EAAE,KAAK,CAAC,QAAQ;iCACzB,CAAC,CAAC;gCAEH,MAAM,IAAI,uCAAuC,CAAC;gCAClD,MAAM,IAAI,yBAAyB,YAAY,sBAAsB,CAAC;4BACxE,CAAC;4BAAC,OAAO,GAAG,EAAE,CAAC;gCACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gCAC7D,MAAM,IAAI,gCAAgC,GAAG,IAAI,CAAC;gCAClD,MAAM,IAAI,yDAAyD,CAAC;4BACtE,CAAC;wBACH,CAAC;oBACH,CAAC;yBAAM,IAAI,IAAI,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;wBACnC,6DAA6D;wBAC7D,IAAI,CAAC,WAAW,EAAE,CAAC;4BACjB,IAAI,CAAC;gCACH,WAAW,GAAG,MAAM,iBAAiB,EAAE,CAAC;4BAC1C,CAAC;4BAAC,OAAO,GAAG,EAAE,CAAC;gCACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gCAC7D,MAAM,IAAI,wBAAwB,GAAG,MAAM,CAAC;4BAC9C,CAAC;wBACH,CAAC;wBAED,IAAI,WAAW,EAAE,CAAC;4BAChB,IAAI,CAAC;gCACH,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;gCAC9D,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;gCACvD,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;gCAE9C,IAAI,KAAK,EAAE,CAAC;oCACV,MAAM,IAAI,6CAA6C,CAAC;gCAC1D,CAAC;qCAAM,CAAC;oCACN,MAAM,IAAI,kDAAkD,CAAC;gCAC/D,CAAC;4BACH,CAAC;4BAAC,OAAO,GAAG,EAAE,CAAC;gCACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gCAC7D,MAAM,IAAI,4BAA4B,GAAG,MAAM,CAAC;4BAClD,CAAC;wBACH,CAAC;oBACH,CAAC;oBAED,gDAAgD;oBAChD,IAAI,gBAAgB,GAAG,EAAE,CAAC;oBAC1B,IAAI,CAAC;wBACH,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,cAAc,EAAE,CAAC;wBACjD,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;4BAC5B,gBAAgB,GAAG,8BAA8B,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC;4BAC1E,MAAM,IAAI,2BAA2B,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC;wBACxF,CAAC;6BAAM,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;4BACjC,MAAM,IAAI,wEAAwE,CAAC;4BACnF,KAAK,MAAM,QAAQ,IAAI,UAAU,EAAE,CAAC;gCAClC,MAAM,IAAI,OAAO,QAAQ,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,IAAI,CAAC;4BACvD,CAAC;4BACD,MAAM,IAAI,IAAI,CAAC;wBACjB,CAAC;6BAAM,CAAC;4BACN,MAAM,IAAI,2FAA2F,CAAC;wBACxG,CAAC;oBACH,CAAC;oBAAC,MAAM,CAAC;wBACP,4CAA4C;oBAC9C,CAAC;oBAED,wBAAwB;oBACxB,MAAM,IAAI,oBAAoB,CAAC;oBAC/B,MAAM,IAAI,KAAK,CAAC;oBAChB,MAAM,IAAI,kBAAkB,CAAC;oBAC7B,MAAM,IAAI,oBAAoB,CAAC;oBAC/B,MAAM,IAAI,mBAAmB,CAAC;oBAC9B,MAAM,IAAI,4BAA4B,CAAC;oBACvC,MAAM,IAAI,uBAAuB,CAAC;oBAClC,6DAA6D;oBAC7D,MAAM,IAAI,uBAAuB,SAAS,CAAC,MAAM,MAAM,CAAC;oBACxD,MAAM,IAAI,8BAA8B,SAAS,CAAC,OAAO,MAAM,CAAC;oBAChE,MAAM,IAAI,gBAAgB,CAAC;oBAC3B,MAAM,IAAI,qBAAqB,WAAW,IAAI,kBAAkB,KAAK,CAAC;oBACtE,MAAM,IAAI,aAAa,CAAC;oBACxB,MAAM,IAAI,WAAW,CAAC;oBACtB,MAAM,IAAI,SAAS,CAAC;oBACpB,MAAM,IAAI,OAAO,CAAC;oBAClB,MAAM,IAAI,OAAO,CAAC;oBAClB,MAAM,IAAI,oDAAoD,CAAC;oBAC/D,OAAO,MAAM,CAAC;gBAChB,CAAC;gBAED,mEAAmE;gBACnE,MAAM,KAAK,GAAG,CAAC,MAAM,aAAa,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAE1D,CAAC;gBACF,IAAI,KAAK,CAAC,KAAK,KAAK,uBAAuB,EAAE,CAAC;oBAC5C,MAAM,IAAI,KAAK,CACb,4BAA4B,KAAK,CAAC,KAAK,IAAI,QAAQ,aAAa,CAAC,MAAM,EAAE,EAAE,CAC5E,CAAC;gBACJ,CAAC;YACH,CAAC;YAED,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAC5D,CAAC;KACF;IAED,2EAA2E;IAC3E;QACE,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,sDAAsD;QACnE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;YAC/B,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;gBAClB,OAAO,4DAA4D,CAAC;YACtE,CAAC;YAED,MAAM,MAAM,GAAG,YAAY,CAAC;YAC5B,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;YAE/D,IAAI,CAAC;gBACH,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,cAAc,EAAE,CAAC;gBAEjD,IAAI,MAAM,GAAG,oBAAoB,MAAM,IAAI,CAAC;gBAC5C,MAAM,IAAI,mBAAmB,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;gBAC3D,MAAM,IAAI,iBAAiB,UAAU,CAAC,MAAM,MAAM,CAAC;gBAEnD,KAAK,MAAM,QAAQ,IAAI,UAAU,EAAE,CAAC;oBAClC,MAAM,IAAI,OAAO,QAAQ,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,KAAK,CAAC;oBACtD,IAAI,QAAQ,CAAC,KAAK;wBAAE,MAAM,IAAI,cAAc,QAAQ,CAAC,KAAK,IAAI,CAAC;oBAC/D,IAAI,QAAQ,CAAC,KAAK;wBAAE,MAAM,IAAI,cAAc,QAAQ,CAAC,KAAK,IAAI,CAAC;gBACjE,CAAC;gBAED,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;oBAChB,MAAM,IAAI,0FAA0F,CAAC;oBACrG,MAAM,IAAI,+DAA+D,CAAC;gBAC5E,CAAC;gBAED,OAAO,MAAM,CAAC;YAChB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,GAAG,YAAY,YAAY,IAAI,CAAC,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,EAAE,CAAC;oBAC9E,OAAO,yEAAyE,CAAC;gBACnF,CAAC;gBACD,IAAI,GAAG,YAAY,YAAY,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;oBACtD,OAAO,gEAAgE,CAAC;gBAC1E,CAAC;gBACD,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACjE,OAAO,2BAA2B,OAAO,kEAAkE,CAAC;YAC9G,CAAC;QACH,CAAC;KACF;IAED,2EAA2E;IAC3E;QACE,IAAI,EAAE,OAAO;QACb,WAAW,EAAE,+CAA+C;QAC5D,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;YAC/B,MAAM,MAAM,GAAG,YAAY,CAAC;YAC5B,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;YAE/D,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,cAAc,EAAE,CAAC;YAEjD,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC5B,OAAO,6EAA6E,CAAC;YACvF,CAAC;YAED,IAAI,MAAM,GAAG,yBAAyB,CAAC;YACvC,MAAM,IAAI,2BAA2B,CAAC;YAEtC,yCAAyC;YACzC,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC5B,MAAM,IAAI,4EAA4E,CAAC;gBACvF,MAAM,IAAI,sBAAsB,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC;YAC5D,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,qFAAqF,CAAC;gBAChG,KAAK,MAAM,QAAQ,IAAI,UAAU,EAAE,CAAC;oBAClC,MAAM,IAAI,OAAO,QAAQ,CAAC,IAAI,MAAM,QAAQ,CAAC,IAAI,KAAK,CAAC;gBACzD,CAAC;gBACD,MAAM,IAAI,IAAI,CAAC;YACjB,CAAC;YAED,MAAM,IAAI,gEAAgE,CAAC;YAE3E,MAAM,IAAI,iBAAiB,CAAC;YAE5B,iBAAiB;YACjB,MAAM,eAAe,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YACxD,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC/B,MAAM,IAAI,qBAAqB,CAAC;gBAChC,MAAM,IAAI,qBAAqB,CAAC;gBAChC,KAAK,MAAM,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,eAAe,CAAC,OAAO,EAAE,EAAE,CAAC;oBACxD,MAAM,IAAI,UAAU,QAAQ,CAAC,IAAI,QAAQ,CAAC;oBAC1C,MAAM,IAAI,4BAA4B,QAAQ,CAAC,IAAI,MAAM,CAAC;oBAC1D,MAAM,IAAI,4BAA4B,QAAQ,CAAC,IAAI,MAAM,CAAC;oBAC1D,MAAM,IAAI,qBAAqB,QAAQ,CAAC,KAAK,KAAK,CAAC;oBACnD,MAAM,IAAI,UAAU,GAAG,GAAG,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;gBACtE,CAAC;gBACD,MAAM,IAAI,SAAS,CAAC;gBACpB,MAAM,IAAI,QAAQ,CAAC;YACrB,CAAC;YAED,eAAe;YACf,MAAM,eAAe,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YACxD,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC/B,MAAM,IAAI,mBAAmB,CAAC;gBAC9B,MAAM,IAAI,qBAAqB,CAAC;gBAChC,KAAK,MAAM,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,eAAe,CAAC,OAAO,EAAE,EAAE,CAAC;oBACxD,MAAM,IAAI,UAAU,QAAQ,CAAC,IAAI,QAAQ,CAAC;oBAC1C,MAAM,IAAI,4BAA4B,QAAQ,CAAC,IAAI,MAAM,CAAC;oBAC1D,MAAM,IAAI,4BAA4B,QAAQ,CAAC,IAAI,MAAM,CAAC;oBAC1D,MAAM,IAAI,qBAAqB,QAAQ,CAAC,KAAK,KAAK,CAAC;oBACnD,MAAM,IAAI,UAAU,GAAG,GAAG,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;gBACtE,CAAC;gBACD,MAAM,IAAI,SAAS,CAAC;gBACpB,MAAM,IAAI,OAAO,CAAC;YACpB,CAAC;YAED,MAAM,IAAI,OAAO,CAAC;YAElB,MAAM,IAAI,oFAAoF,CAAC;YAC/F,MAAM,IAAI,sFAAsF,CAAC;YACjG,MAAM,IAAI,wFAAwF,CAAC;YACnG,MAAM,IAAI,qFAAqF,CAAC;YAEhG,OAAO,MAAM,CAAC;QAChB,CAAC;KACF;CACF,CAAC"}
@@ -0,0 +1,174 @@
1
+ import type { Identity, EmailThread, EmailMessage, SmsConversation, SmsMessage, PasswordEntry, SecretEntry, EncryptionMeta } from "./types.js";
2
+ /** Options for constructing a {@link RaviClient}. */
3
+ export interface RaviClientConfig {
4
+ /** Base URL of the Ravi API (e.g. "https://api.ravi.dev"). */
5
+ apiUrl: string;
6
+ /** JWT bearer token for authentication. */
7
+ token: string;
8
+ /** Optional refresh token for automatic access token renewal on 401. */
9
+ refreshToken?: string;
10
+ /** Optional identity UUID — sets the `X-Ravi-Identity` header on scoped requests. */
11
+ identityUuid?: string;
12
+ }
13
+ /**
14
+ * Error thrown when the Ravi API returns a non-OK response.
15
+ *
16
+ * Includes the HTTP status code and response body for programmatic handling
17
+ * (e.g. distinguishing 402 billing errors from 404s).
18
+ */
19
+ export declare class RaviApiError extends Error {
20
+ readonly method: string;
21
+ readonly path: string;
22
+ readonly status: number;
23
+ readonly body: string;
24
+ constructor(method: string, path: string, status: number, body: string);
25
+ }
26
+ /**
27
+ * Typed HTTP client for the Ravi REST API.
28
+ *
29
+ * Handles authentication, identity scoping via `X-Ravi-Identity`, and
30
+ * provides methods for every Ravi API endpoint. All methods return typed
31
+ * promises and throw {@link RaviApiError} on non-OK responses.
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * const client = new RaviClient({ apiUrl: "https://api.ravi.dev", token: "ey..." });
36
+ * const identities = await client.listIdentities();
37
+ * client.setIdentity(identities[0].uuid);
38
+ * const threads = await client.listEmailThreads();
39
+ * ```
40
+ */
41
+ export declare class RaviClient {
42
+ private apiUrl;
43
+ private token;
44
+ private refreshToken?;
45
+ private identityUuid?;
46
+ private isRefreshing;
47
+ constructor(config: RaviClientConfig);
48
+ /**
49
+ * Set the identity UUID used for scoped requests.
50
+ *
51
+ * Once set, all subsequent requests include the `X-Ravi-Identity` header
52
+ * so the server knows which identity the request is scoped to.
53
+ */
54
+ setIdentity(uuid: string): void;
55
+ /**
56
+ * Internal helper that executes an authenticated HTTP request against the
57
+ * Ravi API and returns the parsed JSON response.
58
+ *
59
+ * On a 401 response, if a refresh token is available, automatically
60
+ * attempts to refresh the access token and retries the request once.
61
+ *
62
+ * @throws {RaviApiError} When the server returns a non-2xx status code.
63
+ */
64
+ private request;
65
+ /** List all identities belonging to the authenticated user. */
66
+ listIdentities(): Promise<Identity[]>;
67
+ /** Create a new identity with the given name. */
68
+ createIdentity(name: string): Promise<Identity>;
69
+ /** Get the email address for the current identity. Returns empty string if none. */
70
+ getEmail(): Promise<string>;
71
+ /** Get the phone number for the current identity. Returns empty string if none. */
72
+ getPhone(): Promise<string>;
73
+ /**
74
+ * List email threads for the current identity.
75
+ *
76
+ * @param unread - When `true`, only return threads with unread messages.
77
+ */
78
+ listEmailThreads(unread?: boolean): Promise<EmailThread[]>;
79
+ /**
80
+ * Get all messages in an email thread.
81
+ *
82
+ * @param threadId - The thread identifier.
83
+ */
84
+ getEmailThread(threadId: string): Promise<EmailMessage[]>;
85
+ /**
86
+ * List SMS conversations for the current identity.
87
+ *
88
+ * @param unread - When `true`, only return conversations with unread messages.
89
+ */
90
+ listSmsConversations(unread?: boolean): Promise<SmsConversation[]>;
91
+ /**
92
+ * Get all messages in an SMS conversation.
93
+ *
94
+ * @param conversationId - The conversation identifier.
95
+ */
96
+ listSmsMessages(conversationId: string): Promise<SmsMessage[]>;
97
+ /**
98
+ * Compose and send a new email from the current identity's inbox.
99
+ *
100
+ * Automatically discovers the identity's inbox ID before sending.
101
+ *
102
+ * @param to - Recipient email address.
103
+ * @param subject - Email subject line.
104
+ * @param body - HTML body content.
105
+ * @throws {Error} When the identity has no email inbox provisioned.
106
+ */
107
+ composeEmail(to: string, subject: string, body: string): Promise<EmailMessage>;
108
+ /**
109
+ * Reply to an existing email message.
110
+ *
111
+ * @param messageId - The numeric ID of the message to reply to.
112
+ * @param body - HTML body content for the reply.
113
+ * @param replyAll - When `true`, reply to all recipients (default: `false`).
114
+ */
115
+ replyToEmail(messageId: number, body: string, replyAll?: boolean): Promise<EmailMessage>;
116
+ /**
117
+ * Send an SMS message from the current identity's phone number.
118
+ *
119
+ * @param toNumber - Recipient phone number in E.164 format.
120
+ * @param body - Message text.
121
+ */
122
+ sendSms(toNumber: string, body: string): Promise<SmsMessage>;
123
+ /** List all password entries for the current identity. Fields may be E2E encrypted. */
124
+ listPasswords(): Promise<PasswordEntry[]>;
125
+ /** Get a single password entry by UUID. */
126
+ getPassword(uuid: string): Promise<PasswordEntry>;
127
+ /**
128
+ * Create a new password entry.
129
+ *
130
+ * @param data - Password fields. `domain` is required; other fields are optional.
131
+ */
132
+ createPassword(data: {
133
+ domain: string;
134
+ username?: string;
135
+ password?: string;
136
+ notes?: string;
137
+ }): Promise<PasswordEntry>;
138
+ /** Delete a password entry by UUID. */
139
+ deletePassword(uuid: string): Promise<void>;
140
+ /** List all vault secrets for the current identity. */
141
+ listSecrets(): Promise<SecretEntry[]>;
142
+ /**
143
+ * Get a single vault secret by key.
144
+ *
145
+ * Uses the `?key=` filter on the list endpoint (backend lookup_field is uuid,
146
+ * not key). Returns the first match or throws 404-like error.
147
+ *
148
+ * @param key - The secret's key name.
149
+ */
150
+ getSecret(key: string): Promise<SecretEntry>;
151
+ /**
152
+ * Create or update a vault secret.
153
+ *
154
+ * @param key - The secret's key name.
155
+ * @param value - The secret value (will be E2E encrypted by the crypto layer).
156
+ */
157
+ setSecret(key: string, value: string): Promise<SecretEntry>;
158
+ /** Delete a vault secret by UUID. */
159
+ deleteSecret(uuid: string): Promise<void>;
160
+ /**
161
+ * Get the encryption metadata for the current identity.
162
+ *
163
+ * Returns the salt, verifier, and public key needed to derive the
164
+ * E2E encryption key from the user's PIN.
165
+ */
166
+ getEncryptionMeta(): Promise<EncryptionMeta>;
167
+ /** Update (or initialize) the user's encryption metadata. */
168
+ updateEncryptionMeta(data: {
169
+ salt?: string;
170
+ public_key?: string;
171
+ verifier?: string;
172
+ }): Promise<EncryptionMeta>;
173
+ }
174
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}