Files
VoCat/web/src/components/sms/smsApi.ts
T
MengMengCode 9fc3f1c5b8 feat: add Telegram API URL handling and version comparison utilities
- Implemented `telegramAPIURL` and `validateTelegramAPIURL` functions for constructing and validating Telegram API URLs.
- Added semantic versioning utilities in `version.go` to compare versions and validate semantic version formats.
- Created tests for version comparison logic in `version_test.go`.
- Introduced IMS call handling in `call_runtime.go`, including methods for dialing, answering, and hanging up calls.
- Added tests for incoming call handling and validation in `call_runtime_test.go`.
- Developed a new `PluginsCard` component for managing plugins via URL or file upload in the web interface.
- Implemented plugin management functions in `extensions.ts` and created an `ExtensionPage` for displaying plugin contributions.
2026-08-09 19:28:12 +08:00

90 lines
2.5 KiB
TypeScript

import { api } from "../../api";
import type { DeviceListItem, DevicesResponse, SMSContact, SMSMessage } from "../../types";
// Build a query string keeping snake_case keys (api() only snakeizes JSON bodies, not paths).
function qs(params: Record<string, string | number | undefined>): string {
const sp = new URLSearchParams();
for (const [key, value] of Object.entries(params)) {
if (value === undefined || value === "") continue;
sp.set(key, String(value));
}
const s = sp.toString();
return s ? `?${s}` : "";
}
export async function listSmsDevices(): Promise<DeviceListItem[]> {
const res = await api<DevicesResponse>("/devices");
return (res.devices || []).filter((d) => d.running);
}
export function listContacts(deviceId: string): Promise<SMSContact[]> {
return api<SMSContact[]>(
`/sms/contacts${qs({ limit: 200, device_id: deviceId && deviceId !== "all" ? deviceId : undefined })}`,
);
}
export interface ThreadQuery {
peer: string;
limit: number;
deviceId?: string;
modemImei?: string;
imsi?: string;
beforeTs?: string;
beforeId?: number;
}
export function getThread(q: ThreadQuery): Promise<SMSMessage[]> {
return api<SMSMessage[]>(
`/sms/thread${qs({
peer: q.peer,
limit: q.limit,
device_id: q.deviceId,
modem_imei: q.modemImei,
imsi: q.imsi,
before_ts: q.beforeTs,
before_id: q.beforeId,
})}`,
);
}
export interface SendSmsPayload {
deviceId?: string;
phone: string;
message: string;
}
export interface SmsSendResult {
id?: number;
messageId?: string;
partsTotal: number;
partsAttempted: number;
partsAccepted: number;
allPartsAccepted: boolean;
submissionAccepted: boolean;
deliveryConfirmed: boolean;
outcome: "delivered" | "accepted_unconfirmed" | "partial" | "failed";
submissionState?: string;
deliveryState?: string;
transport?: "ims" | "cellular_at";
warning?: string;
}
export function sendSms(payload: SendSmsPayload): Promise<SmsSendResult> {
return api<SmsSendResult>("/sms/send", { method: "POST", body: payload });
}
export function deleteMessage(id: number): Promise<{ threadEmpty?: boolean }> {
return api<{ threadEmpty?: boolean }>(`/sms/messages/${id}`, { method: "DELETE" });
}
export interface DeleteThreadQuery {
peer: string;
deviceId?: string;
modemImei?: string;
imsi?: string;
}
export function deleteThread(q: DeleteThreadQuery): Promise<unknown> {
return api(`/sms/thread${qs({ peer: q.peer, device_id: q.deviceId, modem_imei: q.modemImei, imsi: q.imsi })}`, { method: "DELETE" });
}