@stage-labs/metro 0.1.0-beta.170 → 0.1.0-beta.172

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 (42) hide show
  1. package/dist/cli.js +7 -10
  2. package/dist/route.js +16 -8
  3. package/dist/serve.js +1 -1
  4. package/dist/service.js +1 -1
  5. package/package.json +1 -1
  6. package/runtime/marketplace/.claude-plugin/marketplace.json +1 -1
  7. package/runtime/marketplace/plugin/.claude-plugin/plugin.json +2 -3
  8. package/runtime/node_modules/@metro-labs/core/src/stations/account-store.ts +1 -1
  9. package/runtime/node_modules/@metro-labs/daemon/src/channels/inbound.ts +14 -7
  10. package/runtime/node_modules/@metro-labs/daemon/src/channels/pending.ts +3 -0
  11. package/runtime/node_modules/@metro-labs/daemon/src/claude/login.ts +41 -3
  12. package/runtime/node_modules/@metro-labs/daemon/src/claude/settings.ts +11 -2
  13. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay.ts +30 -6
  14. package/runtime/node_modules/@metro-labs/daemon/src/connectors/store.ts +12 -8
  15. package/runtime/node_modules/@metro-labs/daemon/src/gateway/bedrock.ts +4 -4
  16. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex.ts +18 -7
  17. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gateway.ts +6 -8
  18. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-stream.ts +5 -2
  19. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini.ts +18 -7
  20. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-signin.ts +4 -6
  21. package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-relay.ts +1 -1
  22. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-inline.ts +29 -1
  23. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-resolve.ts +4 -9
  24. package/runtime/node_modules/@metro-labs/discord-bot/src/actions.ts +1 -144
  25. package/runtime/node_modules/@metro-labs/discord-bot/src/format.ts +14 -5
  26. package/runtime/node_modules/@metro-labs/telegram/src/format.ts +19 -0
  27. package/runtime/node_modules/@metro-labs/telegram/src/inbound.ts +2 -1
  28. package/runtime/node_modules/@metro-labs/telegram-bot/src/actions.ts +1 -45
  29. package/runtime/node_modules/@metro-labs/telegram-bot/src/format.ts +13 -5
  30. package/runtime/node_modules/@metro-labs/telegram-bot/src/media-actions.ts +1 -73
  31. package/runtime/node_modules/@metro-labs/xmtp/package.json +0 -1
  32. package/runtime/node_modules/@metro-labs/xmtp/src/actions-conv.ts +2 -173
  33. package/runtime/node_modules/@metro-labs/xmtp/src/actions-meta.ts +2 -41
  34. package/runtime/node_modules/@metro-labs/xmtp/src/actions.ts +1 -129
  35. package/runtime/node_modules/@metro-labs/xmtp/src/emit-core.ts +13 -5
  36. package/runtime/node_modules/@metro-labs/xmtp/src/emit.ts +1 -10
  37. package/runtime/node_modules/@metro-labs/xmtp/src/index.ts +3 -4
  38. package/runtime/node_modules/@metro-labs/xmtp/src/labels.ts +1 -19
  39. package/runtime/runtime.json +1 -1
  40. package/runtime/stations.json +0 -1
  41. package/runtime/node_modules/@metro-labs/xmtp/src/actions-push.ts +0 -87
  42. package/runtime/node_modules/@metro-labs/xmtp/src/push.ts +0 -349
@@ -5,10 +5,10 @@ import { isRecord } from '@metro-labs/core/is-record';
5
5
  import { errMsg, log } from '@metro-labs/core/log';
6
6
  import { beginLogin, finishLogin, readCodexCliAuth, type CodexTokens } from './codex-auth.js';
7
7
  import { beginDeviceLogin, pollDeviceLogin } from './codex-device.js';
8
- import { codexModels, currentTokens, freshCodexState } from './codex.js';
8
+ import { codexModels, currentTokens, sharedCodexState } from './codex.js';
9
9
  import { beginLogin as beginGeminiLogin, exchangeCode as exchangeGeminiCode, userEmail, type GeminiTokens } from './gemini-auth.js';
10
10
  import { onboard, parseGeminiProject } from './gemini-setup.js';
11
- import { currentGeminiTokens, freshGeminiState, listGeminiModels, type GeminiDeps } from './gemini.js';
11
+ import { currentGeminiTokens, listGeminiModels, sharedGeminiState, type GeminiDeps } from './gemini.js';
12
12
  import { openrouterCredits } from './openrouter.js';
13
13
  import { lastServed } from './served.js';
14
14
  import { geminiUsage, noteUsage, openrouterUsage, usageOf } from './usage.js';
@@ -23,8 +23,6 @@ import {
23
23
  } from './model-config.js';
24
24
  import { asApiError, askedConnection, BODY_MAX, connectionFor, CREDITS_TTL_MS, settingsBody, type ModelApiDeps, type Route, type Store } from './model-store.js';
25
25
 
26
- const codexState = freshCodexState();
27
- const geminiState = freshGeminiState();
28
26
 
29
27
  function connectionToFill(store: Store, req: IncomingMessage, provider: Provider): { cfg: ModelConfig; id: string } {
30
28
  const asked = askedConnection(req);
@@ -100,7 +98,7 @@ export const CODEX_ROUTES: Record<string, Route> = {
100
98
  const conn = connectionFor(store.read(), req, 'codex');
101
99
  if (conn.codex === null) throw new ApiError('this connection is not signed in yet', 400);
102
100
  const codexDeps = codexDepsFor(deps, store, conn.id);
103
- const auth = await currentTokens(conn, codexDeps, codexState).catch(asApiError);
101
+ const auth = await currentTokens(conn, codexDeps, sharedCodexState).catch(asApiError);
104
102
  return { models: await codexModels(auth, codexDeps).catch(asApiError) };
105
103
  },
106
104
  },
@@ -117,7 +115,7 @@ export const geminiDeps = (deps: ModelApiDeps, store: Store): GeminiDeps => ({
117
115
 
118
116
  async function geminiModelsOf(conn: Connection, deps: ModelApiDeps, store: Store): Promise<Awaited<ReturnType<typeof listGeminiModels>>> {
119
117
  if (conn.gemini === null) throw new ApiError('this connection is not signed in yet', 400);
120
- const tokens = await currentGeminiTokens(conn, geminiDeps(deps, store), geminiState);
118
+ const tokens = await currentGeminiTokens(conn, geminiDeps(deps, store), sharedGeminiState);
121
119
  return listGeminiModels(tokens, geminiDeps(deps, store));
122
120
  }
123
121
 
@@ -55,7 +55,7 @@ export function registerPermissionRelay(deps: PermissionRelayDeps): void {
55
55
  );
56
56
  return;
57
57
  }
58
- relay.registerPermission(params.request_id);
58
+ relay.registerPermission(params.request_id, line);
59
59
  try {
60
60
  await metroSend(line, promptBody(params));
61
61
  } catch (e) {
@@ -1,4 +1,5 @@
1
- import { mkdtemp, rm, writeFile } from 'node:fs/promises';
1
+ import { mkdtemp, open, rm, writeFile } from 'node:fs/promises';
2
+ import { assertAttachmentSize } from '@metro-labs/core/stations/attachments';
2
3
  import { tmpdir } from 'node:os';
3
4
  import { join } from 'node:path';
4
5
 
@@ -98,3 +99,30 @@ export async function writeInlineTemp(
98
99
 
99
100
  export const removeInlineTemp = (dir: string): Promise<void> =>
100
101
  rm(dir, { recursive: true, force: true });
102
+
103
+ export async function streamToTemp(
104
+ body: ReadableStream<Uint8Array>,
105
+ name: string | undefined,
106
+ ): Promise<InlineTemp & { bytes: number }> {
107
+ const dir = await mkdtemp(join(tmpdir(), INLINE_TEMP_PREFIX));
108
+ const path = join(dir, safeFileName(name));
109
+ const handle = await open(path, 'wx', 0o600);
110
+ const reader = body.getReader();
111
+ let bytes = 0;
112
+ try {
113
+ for (;;) {
114
+ const { done, value } = await reader.read();
115
+ if (done) break;
116
+ bytes += value.length;
117
+ assertAttachmentSize(bytes);
118
+ await handle.write(value);
119
+ }
120
+ } catch (err) {
121
+ await reader.cancel().catch(() => undefined);
122
+ await handle.close();
123
+ await removeInlineTemp(dir);
124
+ throw err;
125
+ }
126
+ await handle.close();
127
+ return { dir, path, bytes };
128
+ }
@@ -2,13 +2,13 @@ import {
2
2
  assertAttachmentSize,
3
3
  assertContentLength,
4
4
  guessMime,
5
- saveBufferToCache,
6
5
  } from '@metro-labs/core/stations/attachments';
7
6
  import {
8
7
  assertInlineTotal,
9
8
  decodeInline,
10
9
  removeInlineTemp,
11
10
  splitInlineData,
11
+ streamToTemp,
12
12
  writeInlineTemp,
13
13
  } from './attach-inline.js';
14
14
  import { realpathSync } from 'node:fs';
@@ -39,8 +39,6 @@ const basenameOf = (src: string): string =>
39
39
 
40
40
  const isHttpUrl = (src: string): boolean => /^https?:\/\//i.test(src);
41
41
 
42
- const mintId = (): string => Math.random().toString(36).slice(2, 12);
43
-
44
42
  const HIDDEN_SEGMENT = /(^|\/)\.[^/]/;
45
43
 
46
44
  function assertReadablePath(path: string): void {
@@ -93,15 +91,12 @@ async function fromUrl(
93
91
  if (!res.ok)
94
92
  throw new Error(`attachment fetch failed ${res.status} for '${url}'`);
95
93
  assertContentLength(res.headers.get('content-length'));
96
- const data = new Uint8Array(await res.arrayBuffer());
97
94
  const mime =
98
95
  a.mime ?? res.headers.get('content-type')?.split(';')[0] ?? guessMime(url);
99
96
  const name = a.name ?? basenameOf(url) ?? 'attachment';
100
- const saved = await saveBufferToCache(data, `out${mintId()}`, 0, {
101
- mime,
102
- name,
103
- });
104
- return { path: saved.path, mime, name, bytes: data.length };
97
+ if (res.body === null) throw new Error(`attachment fetch returned no body for '${url}'`);
98
+ const { dir, path, bytes } = await streamToTemp(res.body, name);
99
+ return { path, mime, name, bytes, temp: dir };
105
100
  }
106
101
 
107
102
  async function fromData(
@@ -1,20 +1,13 @@
1
+ import type { Message } from 'discord.js';
1
2
  import {
2
- ActivityType,
3
- type Message,
4
- type PresenceStatusData,
5
- } from 'discord.js';
6
- import {
7
- accountFor,
8
3
  accounts,
9
4
  encodeEmoji,
10
- lineOf,
11
5
  rest,
12
6
  routeOf,
13
7
  } from './accounts.js';
14
8
  import { emitOutbound, emitOutboundEdit, emitOutboundReact } from './format.js';
15
9
  import { respond } from './wire.js';
16
10
  import { normalizeDiscord } from '@metro-labs/core/stations/messaging-normalize';
17
- import { assertContentLength } from '@metro-labs/core/stations/attachments';
18
11
  import {
19
12
  appendFiles,
20
13
  outgoingFiles,
@@ -111,38 +104,6 @@ async function send(id: string, args: Record<string, unknown>): Promise<void> {
111
104
  });
112
105
  }
113
106
 
114
- function presence(id: string, args: Record<string, unknown>): void {
115
- const {
116
- text,
117
- status = 'online',
118
- account,
119
- } = args as {
120
- text?: string;
121
- status?: PresenceStatusData;
122
- account?: string;
123
- };
124
- const accountId = accountFor({ account });
125
- const acct = accounts.get(accountId);
126
- if (!acct) {
127
- respond(id, { error: `unknown account '${accountId}'` });
128
- return;
129
- }
130
- const client = acct.client;
131
- if (!client.user) {
132
- respond(id, { error: `gateway not ready for account '${accountId}'` });
133
- return;
134
- }
135
- client.user.setPresence({
136
- status,
137
- activities: text
138
- ? [{ name: 'Custom Status', type: ActivityType.Custom, state: text }]
139
- : [],
140
- });
141
- respond(id, {
142
- result: { ok: true, text: text ?? null, status, account: accountId },
143
- });
144
- }
145
-
146
107
  const profileUrl = (userId?: string): string | null =>
147
108
  userId === undefined ? null : `https://discord.com/users/${userId}`;
148
109
 
@@ -245,104 +206,6 @@ async function fetchMessages(
245
206
  respond(id, { result: { messages: msgs, account: accountId } });
246
207
  }
247
208
 
248
- async function download(
249
- id: string,
250
- args: Record<string, unknown>,
251
- ): Promise<void> {
252
- const {
253
- line,
254
- messageId,
255
- outDir = '/tmp',
256
- account,
257
- } = args as {
258
- line: string;
259
- messageId: string;
260
- outDir?: string;
261
- account?: string;
262
- };
263
- const { accountId, channelId } = routeOf(line, account);
264
- const msg = await rest<{
265
- attachments: { url: string; content_type?: string; filename: string }[];
266
- }>(accountId, 'GET', `/channels/${channelId}/messages/${messageId}`);
267
- const files: { path: string; mediaType: string }[] = [];
268
- for (const att of msg.attachments) {
269
- const res = await fetch(att.url, { signal: AbortSignal.timeout(60_000) });
270
- if (!res.ok)
271
- throw new Error(`discord-bot download ${res.status} for ${att.url}`);
272
- assertContentLength(res.headers.get('content-length'));
273
- const buf = await res.arrayBuffer();
274
- const path = `${outDir}/${messageId}-${att.filename}`;
275
- await Bun.write(path, buf);
276
- files.push({
277
- path,
278
- mediaType: att.content_type ?? 'application/octet-stream',
279
- });
280
- }
281
- respond(id, { result: { files, account: accountId } });
282
- }
283
-
284
- async function threadCreate(
285
- id: string,
286
- args: Record<string, unknown>,
287
- ): Promise<void> {
288
- const {
289
- line,
290
- messageId,
291
- name,
292
- autoArchiveDuration = 1440,
293
- account,
294
- } = args as {
295
- line: string;
296
- messageId?: string;
297
- name: string;
298
- autoArchiveDuration?: number;
299
- account?: string;
300
- };
301
- const { accountId, channelId } = routeOf(line, account);
302
- const path = messageId
303
- ? `/channels/${channelId}/messages/${messageId}/threads`
304
- : `/channels/${channelId}/threads`;
305
- const res = await rest<{ id: string }>(accountId, 'POST', path, {
306
- name,
307
- auto_archive_duration: autoArchiveDuration,
308
- });
309
- respond(id, {
310
- result: {
311
- threadId: res.id,
312
- line: lineOf(accountId, res.id),
313
- account: accountId,
314
- },
315
- });
316
- }
317
-
318
- async function pin(id: string, args: Record<string, unknown>): Promise<void> {
319
- const { line, messageId, account } = args as {
320
- line: string;
321
- messageId: string;
322
- account?: string;
323
- };
324
- const { accountId, channelId } = routeOf(line, account);
325
- await rest(accountId, 'PUT', `/channels/${channelId}/pins/${messageId}`);
326
- respond(id, { result: { ok: true, account: accountId } });
327
- }
328
-
329
- async function typing(id: string, args: Record<string, unknown>): Promise<void> {
330
- const { line, account } = args as { line: string; account?: string };
331
- const { accountId, channelId } = routeOf(line, account);
332
- await rest(accountId, 'POST', `/channels/${channelId}/typing`);
333
- respond(id, { result: { ok: true, account: accountId } });
334
- }
335
-
336
- async function channel(
337
- id: string,
338
- args: Record<string, unknown>,
339
- ): Promise<void> {
340
- const { line, account } = args as { line: string; account?: string };
341
- const { accountId, channelId } = routeOf(line, account);
342
- const res = await rest(accountId, 'GET', `/channels/${channelId}`);
343
- respond(id, { result: res });
344
- }
345
-
346
209
  async function listMembers(
347
210
  id: string,
348
211
  args: Record<string, unknown>,
@@ -369,13 +232,7 @@ const HANDLERS: Record<string, StationHandler> = {
369
232
  edit,
370
233
  delete: remove,
371
234
  fetch: fetchMessages,
372
- download,
373
- thread_create: threadCreate,
374
- pin,
375
- typing,
376
- channel,
377
235
  listMembers,
378
- set_presence: presence,
379
236
  set_profile: setProfile,
380
237
  profile: readProfile,
381
238
  joinVoice,
@@ -44,11 +44,20 @@ function emitAttachmentSaved(
44
44
  },
45
45
  });
46
46
  })
47
- .catch((err: unknown) =>
48
- process.stderr.write(
49
- `discord-bot attachment save failed: ${err instanceof Error ? err.message : String(err)}\n`,
50
- ),
51
- );
47
+ .catch((err: unknown) => {
48
+ const reason = err instanceof Error ? err.message : String(err);
49
+ process.stderr.write(`discord-bot attachment save failed: ${reason}\n`);
50
+ emitInbound(accountId, {
51
+ kind: 'inbound',
52
+ id: mintId(),
53
+ ts: new Date().toISOString(),
54
+ station: 'discord-bot',
55
+ line,
56
+ from: SELF_URI,
57
+ text: `📎 not fetched: ${reason}`,
58
+ payload: { contentType: 'attachmentFailed', attachmentFor: sourceMsgId, index, name: ref.name ?? undefined, mime: ref.contentType ?? undefined, reason },
59
+ });
60
+ });
52
61
  }
53
62
 
54
63
  const AV_TAG: Record<string, string> = { audio: 'audio', video: 'video' };
@@ -123,6 +123,25 @@ export function attachmentSavedEnvelope(
123
123
  };
124
124
  }
125
125
 
126
+ export function attachmentFailedEnvelope(
127
+ accountId: string,
128
+ line: string,
129
+ sourceEnvId: string,
130
+ reason: string,
131
+ index = 0,
132
+ ): Record<string, unknown> {
133
+ return {
134
+ kind: 'inbound',
135
+ id: mintId(),
136
+ ts: new Date().toISOString(),
137
+ station: 'telegram',
138
+ line,
139
+ from: `metro://telegram/${accountId}/self`,
140
+ text: `📎 not fetched: ${reason}`,
141
+ payload: { account: accountId, contentType: 'attachmentFailed', attachmentFor: sourceEnvId, index, reason },
142
+ };
143
+ }
144
+
126
145
  export interface ReactionInput {
127
146
  accountId: string;
128
147
  chatId: number;
@@ -1,7 +1,7 @@
1
1
  import type { Message } from '@mtcute/bun';
2
2
  import { errMsg, log } from '@metro-labs/core/log';
3
3
  import { emit } from './wire.js';
4
- import { envelope, isOwnEcho, attachmentSavedEnvelope } from './format.js';
4
+ import { envelope, isOwnEcho, attachmentFailedEnvelope, attachmentSavedEnvelope } from './format.js';
5
5
  import { downloadMedia, isDownloadable } from './attachments.js';
6
6
  import { subscribeReactions } from './reactions.js';
7
7
  import type { UserClient } from './client.js';
@@ -28,6 +28,7 @@ async function saveMediaAndEmit(
28
28
  process.stderr.write(
29
29
  `telegram[${accountId}] media save failed: ${errMsg(e)}\n`,
30
30
  );
31
+ emit(attachmentFailedEnvelope(accountId, env.line as string, env.id as string, errMsg(e)));
31
32
  }
32
33
  }
33
34
 
@@ -1,4 +1,4 @@
1
- import { accountFor, accounts, tg, targetOf } from './accounts.js';
1
+ import { accounts, tg, targetOf } from './accounts.js';
2
2
  import { respond } from './wire.js';
3
3
  import { errMsg } from '@metro-labs/core/log';
4
4
  import { normalizeTelegram } from '@metro-labs/core/stations/messaging-normalize';
@@ -13,21 +13,14 @@ import {
13
13
  type StationHandler,
14
14
  } from '@metro-labs/core/stations/station-runtime';
15
15
  import { mediaKindOf } from './attachments.js';
16
- import { assertContentLength } from '@metro-labs/core/stations/attachments';
17
16
  import {
18
17
  emitOutbound,
19
18
  finishSend,
20
- media,
21
19
  MEDIA_METHOD_FIELD,
22
- sendDice,
23
- sendLocation,
24
20
  sendMedia,
25
21
  } from './media-actions.js';
26
22
  import { readProfile, setProfile } from './profile.js';
27
23
 
28
-
29
-
30
-
31
24
  export type { CallMsg };
32
25
 
33
26
  const meCache = new Map<string, { id: number; username: string | null }>();
@@ -211,34 +204,6 @@ async function remove(id: string, args: Record<string, unknown>): Promise<void>
211
204
  respond(id, { result: { ok: true, account: accountId } });
212
205
  }
213
206
 
214
-
215
-
216
- async function download(id: string, args: Record<string, unknown>): Promise<void> {
217
- const {
218
- fileId,
219
- outDir = '/tmp',
220
- account,
221
- } = args as { fileId: string; outDir?: string; account?: string };
222
- const accountId = accountFor({ account });
223
- const acct = accounts.get(accountId);
224
- if (!acct) throw new Error(`unknown account '${accountId}'`);
225
- const meta = await tg<{ file_path: string }>(accountId, 'getFile', {
226
- file_id: fileId,
227
- });
228
- const res = await fetch(`${acct.fileApi}/${meta.file_path}`, {
229
- signal: AbortSignal.timeout(60_000),
230
- });
231
- if (!res.ok) throw new Error(`telegram-bot download ${res.status}`);
232
- assertContentLength(res.headers.get('content-length'));
233
- const data = await res.arrayBuffer();
234
- const filename = meta.file_path.split('/').pop() ?? `${fileId}.bin`;
235
- const path = `${outDir}/${Date.now()}-${filename}`;
236
- await Bun.write(path, data);
237
- respond(id, {
238
- result: { path, fileSize: data.byteLength, account: accountId },
239
- });
240
- }
241
-
242
207
  async function listMembers(
243
208
  id: string,
244
209
  args: Record<string, unknown>,
@@ -274,15 +239,6 @@ const HANDLERS: Record<string, StationHandler> = {
274
239
  listMembers,
275
240
  set_profile: setProfile,
276
241
  profile: readProfile,
277
- send_photo: (id, args) =>
278
- media(id, 'sendPhoto', 'photo', ((args.caption as string) ?? '') + ' [image]', args),
279
- send_document: (id, args) =>
280
- media(id, 'sendDocument', 'document', ((args.caption as string) ?? '') + ' [file]', args),
281
- send_voice: (id, args) => media(id, 'sendVoice', 'voice', '[voice]', args),
282
- send_sticker: (id, args) => media(id, 'sendSticker', 'sticker', '[sticker]', args),
283
- send_dice: sendDice,
284
- send_location: sendLocation,
285
- download,
286
242
  };
287
243
 
288
244
  export const handleCall = makeStation({
@@ -198,9 +198,17 @@ export function saveMediaAndEmit(
198
198
  },
199
199
  });
200
200
  })
201
- .catch((err: unknown) =>
202
- process.stderr.write(
203
- `telegram-bot media save failed: ${errMsg(err)}\n`,
204
- ),
205
- );
201
+ .catch((err: unknown) => {
202
+ process.stderr.write(`telegram-bot media save failed: ${errMsg(err)}\n`);
203
+ emitInbound(emit, accountId, {
204
+ kind: 'inbound',
205
+ id: mintId(),
206
+ ts: new Date().toISOString(),
207
+ station: 'telegram-bot',
208
+ line,
209
+ from: SELF_URI || `metro://telegram-bot/${accountId}/self`,
210
+ text: `📎 not fetched: ${errMsg(err)}`,
211
+ payload: { contentType: 'attachmentFailed', attachmentFor: sourceEnvId, index: 0, reason: errMsg(err) },
212
+ });
213
+ });
206
214
  }
@@ -1,4 +1,4 @@
1
- import { tg, tgForm, targetOf } from './accounts.js';
1
+ import { tgForm, targetOf } from './accounts.js';
2
2
  import { emit, mintId, respond, SELF_URI } from './wire.js';
3
3
  import { appendFile } from '@metro-labs/core/stations/attachments';
4
4
 
@@ -82,25 +82,6 @@ export async function sendMedia(
82
82
  return { accountId, message_id: r.message_id };
83
83
  }
84
84
 
85
- export async function media(
86
- id: string,
87
- method: string,
88
- field: string,
89
- label: string,
90
- args: Record<string, unknown>,
91
- ): Promise<void> {
92
- const { accountId, message_id } = await sendMedia(method, field, args);
93
- const line = (args as { line: string }).line;
94
- finishSend(
95
- id,
96
- accountId,
97
- line,
98
- String(message_id),
99
- label,
100
- args.replyTo as string | undefined,
101
- );
102
- }
103
-
104
85
  export const MEDIA_METHOD_FIELD: Record<
105
86
  string,
106
87
  { method: string; field: string }
@@ -111,56 +92,3 @@ export const MEDIA_METHOD_FIELD: Record<
111
92
  video: { method: 'sendVideo', field: 'video' },
112
93
  document: { method: 'sendDocument', field: 'document' },
113
94
  };
114
-
115
- export async function sendDice(
116
- id: string,
117
- args: Record<string, unknown>,
118
- ): Promise<void> {
119
- const {
120
- line,
121
- emoji = '\U0001F3B2',
122
- account,
123
- } = args as { line: string; emoji?: string; account?: string };
124
- const { accountId, chatId, topicId } = targetOf(line, account);
125
- const body: Record<string, unknown> = { chat_id: chatId, emoji };
126
- if (topicId !== undefined) body.message_thread_id = topicId;
127
- const r = await tg<{ message_id: number; dice?: { value: number } }>(
128
- accountId,
129
- 'sendDice',
130
- body,
131
- );
132
- finishSend(
133
- id,
134
- accountId,
135
- line,
136
- String(r.message_id),
137
- `[dice ${emoji} = ${r.dice?.value ?? '?'}]`,
138
- undefined,
139
- { value: r.dice?.value },
140
- );
141
- }
142
-
143
- export async function sendLocation(
144
- id: string,
145
- args: Record<string, unknown>,
146
- ): Promise<void> {
147
- const { line, latitude, longitude, account } = args as {
148
- line: string;
149
- latitude: number;
150
- longitude: number;
151
- account?: string;
152
- };
153
- const { accountId, chatId } = targetOf(line, account);
154
- const r = await tg<{ message_id: number }>(accountId, 'sendLocation', {
155
- chat_id: chatId,
156
- latitude,
157
- longitude,
158
- });
159
- finishSend(
160
- id,
161
- accountId,
162
- line,
163
- String(r.message_id),
164
- `[location: ${latitude}, ${longitude}]`,
165
- );
166
- }
@@ -18,7 +18,6 @@
18
18
  "@xmtp/content-type-reaction": "^2.0.2",
19
19
  "@xmtp/content-type-remote-attachment": "^2.0.4",
20
20
  "@xmtp/content-type-reply": "^2.0.3",
21
- "@xmtp/content-type-wallet-send-calls": "^2.0.0",
22
21
  "@xmtp/node-bindings": "1.9.1",
23
22
  "@xmtp/node-sdk": "^6.0.0",
24
23
  "@zerodev/ecdsa-validator": "5.4.9",