salt-agent-sdk 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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook.d.ts","sourceRoot":"","sources":["../src/webhook.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,470 @@
1
+ "use strict";
2
+ // The webhook server: receives salt-api's callbacks, decides WHETHER and to
3
+ // WHOM a reply is owed (dedup, GACM silence, mediator observe-gating,
4
+ // agent-to-agent loop capping, delegation-reply short-circuiting, identity
5
+ // resolution by trial-decryption), and hands off a clean, already-decrypted
6
+ // context to the consumer's callback for the one decision that's actually
7
+ // theirs: WHAT to say. Everything about the Salt protocol mechanics stays
8
+ // here; nothing about any particular model/agent-loop does.
9
+ //
10
+ // Extracted from salt-claude-agent/src/index.js, which mixed both concerns
11
+ // together. Prompt-string construction (hand-off mode notes, mediator
12
+ // coaching prefixes, card-interaction/invoice-paid instructions) is
13
+ // deliberately NOT here -- that's reference-implementation territory built
14
+ // on top of this module, since it's specific to how one particular model
15
+ // wants a situation framed.
16
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ var desc = Object.getOwnPropertyDescriptor(m, k);
19
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
20
+ desc = { enumerable: true, get: function() { return m[k]; } };
21
+ }
22
+ Object.defineProperty(o, k2, desc);
23
+ }) : (function(o, m, k, k2) {
24
+ if (k2 === undefined) k2 = k;
25
+ o[k2] = m[k];
26
+ }));
27
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
28
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
29
+ }) : function(o, v) {
30
+ o["default"] = v;
31
+ });
32
+ var __importStar = (this && this.__importStar) || (function () {
33
+ var ownKeys = function(o) {
34
+ ownKeys = Object.getOwnPropertyNames || function (o) {
35
+ var ar = [];
36
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
37
+ return ar;
38
+ };
39
+ return ownKeys(o);
40
+ };
41
+ return function (mod) {
42
+ if (mod && mod.__esModule) return mod;
43
+ var result = {};
44
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
45
+ __setModuleDefault(result, mod);
46
+ return result;
47
+ };
48
+ })();
49
+ var __importDefault = (this && this.__importDefault) || function (mod) {
50
+ return (mod && mod.__esModule) ? mod : { "default": mod };
51
+ };
52
+ Object.defineProperty(exports, "__esModule", { value: true });
53
+ exports.HANDOFF_BRIEFING_MARKER = void 0;
54
+ exports.createWebhookServer = createWebhookServer;
55
+ const express_1 = __importDefault(require("express"));
56
+ const pgp = __importStar(require("./crypto"));
57
+ const delegations = __importStar(require("./delegations"));
58
+ const PGP_MESSAGE_RE = /^-----BEGIN PGP MESSAGE/;
59
+ /** The exact marker a hand-off briefing must start with, so the incoming
60
+ * agent's polling loop (below) can detect it arrived. Consumers building
61
+ * the outgoing briefing prompt must instruct their model to emit this
62
+ * exact line first. */
63
+ exports.HANDOFF_BRIEFING_MARKER = "[[SALT-HANDOFF-BRIEFING]]";
64
+ const consoleLogger = {
65
+ info: (msg) => console.log(msg),
66
+ error: (msg) => console.error(msg),
67
+ };
68
+ /**
69
+ * Creates the Express app for a Salt agent's webhook endpoint. Mount it
70
+ * yourself (e.g. `createWebhookServer(opts).listen(port)`, or grab `.app`
71
+ * to compose it into a bigger server).
72
+ */
73
+ function createWebhookServer(options) {
74
+ const { client, identities, pgpPassphrase, webhookSharedSecret, mediatorAgentId } = options;
75
+ const logger = options.logger ?? consoleLogger;
76
+ const app = (0, express_1.default)();
77
+ app.use(express_1.default.json());
78
+ // Salt fires one webhook per chat member with a callback URL
79
+ // (Message#send_webhook in salt-api). When two or more identities THIS
80
+ // process hosts share a chat -- which delegation makes possible -- that's
81
+ // multiple deliveries of the SAME message to this SAME endpoint. Only one
82
+ // delivery can ever actually decrypt (the recipient's key), so without
83
+ // this guard that single message gets fully reprocessed once per
84
+ // redundant delivery, including racing past the delegations registry.
85
+ const MAX_SEEN_MESSAGE_IDS = 2000;
86
+ const seenMessageIds = new Set();
87
+ function alreadyProcessed(messageId) {
88
+ if (messageId == null)
89
+ return false;
90
+ if (seenMessageIds.has(messageId))
91
+ return true;
92
+ seenMessageIds.add(messageId);
93
+ if (seenMessageIds.size > MAX_SEEN_MESSAGE_IDS) {
94
+ const oldest = seenMessageIds.values().next().value;
95
+ if (oldest !== undefined)
96
+ seenMessageIds.delete(oldest);
97
+ }
98
+ return false;
99
+ }
100
+ // A second, independent safety net beyond delegations.ts's depth limit --
101
+ // that only bounds explicit delegate-call recursion, not two hosted
102
+ // agents just organically replying to each other's plain messages once a
103
+ // conversation starts. Cap it hard: once a chat between two identities
104
+ // THIS process hosts crosses this many auto-replies, the receiving
105
+ // identity just stops answering the other one there, until a human sends
106
+ // something new (which resets the count).
107
+ const MAX_AGENT_TO_AGENT_REPLIES_PER_CHAT = 2;
108
+ const agentToAgentReplyCounts = new Map();
109
+ app.get("/health", (_req, res) => {
110
+ res.json({
111
+ status: "ok",
112
+ identities: identities.all().map((i) => ({ salt_app_id: i.saltAppId, username: i.username })),
113
+ ...(options.healthExtra ? options.healthExtra() : {}),
114
+ });
115
+ });
116
+ // Every identity this process hosts shares this one endpoint, so the
117
+ // first step is figuring out *which* identity a given message is
118
+ // addressed to. Salt encrypts the message to every chat member's public
119
+ // key as a single multi-recipient PGP blob -- it only decrypts with a
120
+ // private key that was actually a member of that chat, so trying each
121
+ // known identity in turn and keeping whichever one succeeds is both
122
+ // correct and cheap for the small number of identities a process hosts.
123
+ async function resolveIdentity(ciphertext) {
124
+ for (const candidate of identities.all()) {
125
+ try {
126
+ const plaintext = await pgp.decrypt(ciphertext, candidate.privateKey, pgpPassphrase);
127
+ return { identity: candidate, plaintext };
128
+ }
129
+ catch {
130
+ // Not addressed to this identity -- try the next one.
131
+ }
132
+ }
133
+ return null;
134
+ }
135
+ // Fetches + decrypts a chat's recent messages with `identity`'s own key.
136
+ // Correct for any genuine member (including a silent observer): every
137
+ // message posted since joining was multi-recipient-encrypted to include
138
+ // that key. Messages from before joining simply fail to decrypt and are
139
+ // skipped -- the same degrade-gracefully convention Salt's own clients use.
140
+ async function buildSharedChatContext(identity, sharedChatId) {
141
+ let messages;
142
+ try {
143
+ messages = await client.getChatMessages(identity.apiKey, sharedChatId);
144
+ }
145
+ catch (err) {
146
+ logger.error(`[shared-context] fetching chat ${sharedChatId} failed: ${err.message}`);
147
+ return "(couldn't load the conversation)";
148
+ }
149
+ const lines = [];
150
+ for (const raw of messages) {
151
+ const m = raw;
152
+ if (m.event_type || typeof m.message !== "string" || !PGP_MESSAGE_RE.test(m.message))
153
+ continue;
154
+ try {
155
+ const text = await pgp.decrypt(m.message, identity.privateKey, pgpPassphrase);
156
+ lines.push(`${m.user?.display_name || "someone"}: ${text}`);
157
+ }
158
+ catch {
159
+ // Predates this identity joining the chat -- skip silently.
160
+ }
161
+ }
162
+ return lines.length ? lines.join("\n") : "(no messages yet)";
163
+ }
164
+ // Decrypts an attachment's PGP metadata blob (key/iv/filename/content_type),
165
+ // downloads the ciphertext, and AES-GCM-decrypts it. Only images are
166
+ // returned with actual bytes -- the SDK doesn't know how any given model
167
+ // wants other file types represented, so those get a text note instead.
168
+ async function decryptAttachmentIfPresent(identity, message) {
169
+ if (!message.resource?.encrypted_key)
170
+ return undefined;
171
+ try {
172
+ const metaJson = await pgp.decrypt(message.resource.encrypted_key, identity.privateKey, pgpPassphrase);
173
+ const meta = JSON.parse(metaJson);
174
+ if (!meta.content_type?.startsWith("image/")) {
175
+ return {
176
+ filename: meta.filename,
177
+ contentType: meta.content_type || "unknown",
178
+ size: meta.size,
179
+ unsupportedNote: `attached file: ${meta.filename}, ${meta.content_type || "unknown type"}, ${meta.size} bytes -- not viewable, only images are.`,
180
+ };
181
+ }
182
+ const ciphertextBytes = await client.getAttachment(identity.apiKey, message.message_id);
183
+ const plaintext = pgp.decryptAttachment(ciphertextBytes, meta.key, meta.iv);
184
+ return { filename: meta.filename, contentType: meta.content_type, size: meta.size, data: plaintext };
185
+ }
186
+ catch (err) {
187
+ logger.error(`[attachment] failed to decrypt: ${err.message}`);
188
+ return undefined;
189
+ }
190
+ }
191
+ // Pings the typing indicator for the duration of `fn` -- callers wrap the
192
+ // WHOLE "decide what to say, then say it" arc with this (not just the
193
+ // final post), since that first part (asking a model) is almost always
194
+ // the slow one and is exactly when a human benefits from seeing
195
+ // "X is typing...". Rides the existing ephemeral typing channel
196
+ // (content-free, receivers self-expire after ~4s) on the same 2.5s
197
+ // cadence the human composer uses.
198
+ async function withTypingHeartbeat(identity, chatId, fn) {
199
+ void client.signalTyping(identity.apiKey, chatId);
200
+ const timer = setInterval(() => void client.signalTyping(identity.apiKey, chatId), 2500);
201
+ try {
202
+ return await fn();
203
+ }
204
+ finally {
205
+ clearInterval(timer);
206
+ }
207
+ }
208
+ // Builds the reply() closure shared by every context type:
209
+ // encrypt-for-every-recipient + post + drain this reply's delegation
210
+ // trail onto it + fire-and-forget metrics. Does NOT itself manage the
211
+ // typing indicator -- see withTypingHeartbeat, which wraps the whole
212
+ // callback (including whatever happens before reply() is even called).
213
+ function makeReply(identity, chatId) {
214
+ return async (text) => {
215
+ const startedAt = Date.now();
216
+ let recipientKeys;
217
+ try {
218
+ const members = await client.getChatMembers(identity.apiKey, chatId);
219
+ recipientKeys = members
220
+ .filter((u) => parseInt(String(u.id), 10) !== identity.saltAppId && u.public_key)
221
+ .map((u) => u.public_key);
222
+ }
223
+ catch (err) {
224
+ logger.error(`[chat ${chatId}] fetching members failed: ${err.message}`);
225
+ return;
226
+ }
227
+ if (recipientKeys.length === 0) {
228
+ logger.error(`[chat ${chatId}] no recipient public keys; not sending.`);
229
+ return;
230
+ }
231
+ let encryptedMessage, senderMessage;
232
+ try {
233
+ encryptedMessage = await pgp.encryptFor(text, recipientKeys);
234
+ senderMessage = await pgp.encryptFor(text, [identity.publicKey]);
235
+ }
236
+ catch (err) {
237
+ logger.error(`[chat ${chatId}] encryption failed: ${err.message}`);
238
+ return;
239
+ }
240
+ const trail = delegations.drainTrail(identity.saltAppId, chatId);
241
+ try {
242
+ await client.postMessage(identity.apiKey, chatId, encryptedMessage, senderMessage, trail);
243
+ }
244
+ catch (err) {
245
+ logger.error(`[chat ${chatId}] posting reply failed: ${err.message}`);
246
+ return;
247
+ }
248
+ client.trackEvent(identity.apiKey, "agent_reply_sent", {
249
+ chat_id: chatId,
250
+ latency_ms: Date.now() - startedAt,
251
+ delegation_count: (trail || []).length,
252
+ });
253
+ };
254
+ }
255
+ async function handleMessage(body) {
256
+ const message = body.message;
257
+ const chatId = message.chat_id;
258
+ const chatMeta = body.chat;
259
+ if (alreadyProcessed(message.message_id))
260
+ return;
261
+ if (message.event_type)
262
+ return; // system events aren't prompts
263
+ const ciphertext = message.message;
264
+ if (typeof ciphertext !== "string" || !PGP_MESSAGE_RE.test(ciphertext))
265
+ return;
266
+ const resolved = await resolveIdentity(ciphertext);
267
+ if (!resolved) {
268
+ logger.error(`[chat ${chatId}] no known identity could decrypt this message; ignoring.`);
269
+ return;
270
+ }
271
+ let { identity, plaintext: caption } = resolved;
272
+ // GACM routing fix: salt-api sends one webhook delivery PER agent
273
+ // member, but they all land on this shared server and message-id dedup
274
+ // collapses them into a single pass -- whose decrypt-resolved identity
275
+ // is arbitrary (any member key opens a multi-recipient blob). When the
276
+ // chat declares an active agent that's hosted here, hand this pass to
277
+ // THAT identity; the plaintext is identical under any key, only "who
278
+ // replies" changes.
279
+ if (chatMeta?.active_agent_id) {
280
+ const active = identities.get(parseInt(String(chatMeta.active_agent_id), 10));
281
+ if (active)
282
+ identity = active;
283
+ }
284
+ const senderRaw = message.user;
285
+ const senderId = senderRaw ? parseInt(String(senderRaw.id), 10) : NaN;
286
+ // Reply to a pending delegation call? Hand it to that waiting promise
287
+ // instead of starting a fresh reply cycle -- see delegations.ts.
288
+ if (delegations.resolveIfPending(chatId, senderId, caption))
289
+ return;
290
+ // Never reply to our own messages (the reply we post is itself
291
+ // delivered back to us as a webhook) -- this is what prevents an
292
+ // infinite loop.
293
+ if (senderId === identity.saltAppId)
294
+ return;
295
+ // Mediated Chat: this identity is the configured Mediator, and this
296
+ // message is in the SHARED chat it silently observes -- present for
297
+ // context, but it only actually speaks in each human's own private
298
+ // coaching chat (coaching_for_chat_id pointing back at this one).
299
+ const isMediator = !!mediatorAgentId && identity.saltAppId === mediatorAgentId;
300
+ if (isMediator && chatMeta?.mediator_agent_id && !chatMeta.coaching_for_chat_id)
301
+ return;
302
+ // Global Agent Chat Mode: when the chat declares an active agent and
303
+ // it isn't this identity, stay silent. Lets retired/handed-off-from
304
+ // agents remain in the room without ever double-replying.
305
+ if (chatMeta?.active_agent_id && String(chatMeta.active_agent_id) !== String(identity.saltAppId))
306
+ return;
307
+ // A human sender always resets the count -- only agent-to-agent
308
+ // volleys are capped, never a real conversation with a person.
309
+ const senderIsAgent = !!identities.get(senderId) || senderRaw?.account_type === "Agent";
310
+ if (senderIsAgent) {
311
+ const count = (agentToAgentReplyCounts.get(chatId) || 0) + 1;
312
+ agentToAgentReplyCounts.set(chatId, count);
313
+ if (count > MAX_AGENT_TO_AGENT_REPLIES_PER_CHAT) {
314
+ logger.error(`[chat ${chatId}] agent-to-agent reply cap reached; not auto-replying to ${senderId} again.`);
315
+ return;
316
+ }
317
+ }
318
+ else {
319
+ agentToAgentReplyCounts.delete(chatId);
320
+ }
321
+ const { depth, text: strippedCaption } = delegations.parseIncoming(caption);
322
+ let mediatorSharedContext;
323
+ let attachment;
324
+ if (isMediator && chatMeta?.coaching_for_chat_id) {
325
+ mediatorSharedContext = await buildSharedChatContext(identity, chatMeta.coaching_for_chat_id);
326
+ }
327
+ else if (message.resource_type === "Attachment") {
328
+ attachment = await decryptAttachmentIfPresent(identity, message);
329
+ }
330
+ if (!options.onMessage)
331
+ return;
332
+ const ctx = {
333
+ identity,
334
+ chatId,
335
+ senderId,
336
+ sender: senderRaw,
337
+ text: strippedCaption,
338
+ delegationDepth: depth,
339
+ chatMeta,
340
+ mediatorSharedContext,
341
+ attachment,
342
+ reply: makeReply(identity, chatId),
343
+ };
344
+ try {
345
+ await withTypingHeartbeat(identity, chatId, () => Promise.resolve(options.onMessage(ctx)));
346
+ }
347
+ catch (err) {
348
+ logger.error(`[chat ${chatId}] onMessage failed: ${err.message}`);
349
+ // Discard any trail entries a partial run recorded -- there's no
350
+ // reply for them to ride on, and they must not leak onto the next one.
351
+ delegations.drainTrail(identity.saltAppId, chatId);
352
+ }
353
+ }
354
+ async function handleCardInteraction(body) {
355
+ const identity = identities.get(parseInt(String(body.owner_id), 10));
356
+ if (!identity || !options.onCardInteraction)
357
+ return;
358
+ try {
359
+ await options.onCardInteraction({
360
+ identity,
361
+ chatId: body.chat_id,
362
+ cardId: body.card_id,
363
+ actionId: body.action_id,
364
+ user: body.user,
365
+ blocks: body.state?.blocks,
366
+ });
367
+ }
368
+ catch (err) {
369
+ logger.error(`[chat ${body.chat_id}] onCardInteraction failed: ${err.message}`);
370
+ }
371
+ }
372
+ async function handleInvoicePaid(body) {
373
+ const identity = identities.get(parseInt(String(body.seller_id), 10));
374
+ if (!identity || !body.chat_id || !options.onInvoicePaid)
375
+ return;
376
+ const chatId = body.chat_id;
377
+ const ctx = {
378
+ identity,
379
+ chatId,
380
+ buyer: body.buyer,
381
+ lineItems: body.line_items || [],
382
+ amount: body.amount,
383
+ isTopUp: !!body.billing_account_id,
384
+ transferRequestId: body.transfer_request_id,
385
+ reply: makeReply(identity, chatId),
386
+ };
387
+ try {
388
+ await withTypingHeartbeat(identity, chatId, () => Promise.resolve(options.onInvoicePaid(ctx)));
389
+ }
390
+ catch (err) {
391
+ logger.error(`[chat ${chatId}] onInvoicePaid failed: ${err.message}`);
392
+ }
393
+ }
394
+ async function handleHandoffConfirmed(body) {
395
+ const identity = identities.get(parseInt(String(body.from_agent_id), 10));
396
+ if (!identity || !options.onHandoffConfirmed)
397
+ return;
398
+ const chatId = body.chat_id;
399
+ const ctx = { identity, chatId, reason: body.reason, reply: makeReply(identity, chatId) };
400
+ try {
401
+ await withTypingHeartbeat(identity, chatId, () => Promise.resolve(options.onHandoffConfirmed(ctx)));
402
+ }
403
+ catch (err) {
404
+ logger.error(`[chat ${chatId}] onHandoffConfirmed failed: ${err.message}`);
405
+ }
406
+ }
407
+ async function handleHandoffReceived(body) {
408
+ const identity = identities.get(parseInt(String(body.to_agent_id), 10));
409
+ if (!identity || !options.onHandoffReceived)
410
+ return;
411
+ const chatId = body.chat_id;
412
+ // handoff_confirmed and handoff_received fire at the same moment, but
413
+ // the outgoing agent still has to COMPOSE its briefing -- introduce too
414
+ // fast and there's nothing to ground it in yet. Poll until the
415
+ // HANDOFF_BRIEFING_MARKER shows up (or ~20s passes, e.g. the outgoing
416
+ // agent isn't hosted anywhere reachable / errored).
417
+ let context = "";
418
+ for (let attempt = 0; attempt < 10; attempt++) {
419
+ context = await buildSharedChatContext(identity, chatId);
420
+ if (context.includes(exports.HANDOFF_BRIEFING_MARKER))
421
+ break;
422
+ await new Promise((r) => setTimeout(r, 2000));
423
+ }
424
+ const ctx = { identity, chatId, reason: body.reason, context, reply: makeReply(identity, chatId) };
425
+ try {
426
+ await withTypingHeartbeat(identity, chatId, () => Promise.resolve(options.onHandoffReceived(ctx)));
427
+ }
428
+ catch (err) {
429
+ logger.error(`[chat ${chatId}] onHandoffReceived failed: ${err.message}`);
430
+ }
431
+ }
432
+ async function dispatch(body) {
433
+ if (body?.type === "card_interaction")
434
+ return handleCardInteraction(body);
435
+ if (body?.type === "invoice_paid")
436
+ return handleInvoicePaid(body);
437
+ if (body?.type === "handoff_confirmed")
438
+ return handleHandoffConfirmed(body);
439
+ if (body?.type === "handoff_received")
440
+ return handleHandoffReceived(body);
441
+ if (body?.message)
442
+ return handleMessage(body);
443
+ }
444
+ // salt-api's WebhookJob POSTs here with { chat, message } (or a typed
445
+ // event body for card/invoice/handoff). Ack immediately (200) and process
446
+ // in the background so a slow agent-loop call can't make Salt's webhook
447
+ // delivery time out.
448
+ //
449
+ // WEBHOOK_SHARED_SECRET: when this server is publicly reachable, anyone
450
+ // can POST here. Encrypted-message webhooks fail safe (forged ciphertext
451
+ // never decrypts), but card_interaction/invoice_paid payloads are
452
+ // PLAINTEXT and would be acted on -- so when the secret is configured
453
+ // (production), every POST must carry the matching header salt-api's
454
+ // jobs send. Unset (local dev), the check is skipped entirely.
455
+ app.post("/", (req, res) => {
456
+ if (webhookSharedSecret && req.get("X-Salt-Webhook-Secret") !== webhookSharedSecret) {
457
+ res.status(401).json({ error: "invalid webhook secret" });
458
+ return;
459
+ }
460
+ res.status(200).json({ status: "accepted" });
461
+ dispatch(req.body).catch((err) => logger.error(`[webhook] unhandled error: ${err.message}`));
462
+ });
463
+ return {
464
+ app,
465
+ listen(port) {
466
+ app.listen(port, () => logger.info(`salt-agent-sdk webhook server listening on :${port}`));
467
+ },
468
+ };
469
+ }
470
+ //# sourceMappingURL=webhook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook.js","sourceRoot":"","sources":["../src/webhook.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "salt-agent-sdk",
3
+ "version": "0.1.0",
4
+ "description": "Plumbing for building Salt (saltfor.com) agents: webhook receiving/routing, PGP encrypt/decrypt, a typed REST client, and card builders. Bring your own agent logic -- this handles everything Salt-protocol-specific.",
5
+ "license": "MIT",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "engines": {
12
+ "node": ">=18"
13
+ },
14
+ "scripts": {
15
+ "build": "tsc -p tsconfig.json",
16
+ "dev": "tsc -p tsconfig.json --watch",
17
+ "prepublishOnly": "npm run build"
18
+ },
19
+ "dependencies": {
20
+ "ethers": "^6.13.0",
21
+ "express": "^4.19.0",
22
+ "openpgp": "^5.11.0"
23
+ },
24
+ "devDependencies": {
25
+ "@types/express": "^4.17.21",
26
+ "@types/node": "^20.14.0",
27
+ "typescript": "^5.5.0"
28
+ }
29
+ }