Rework core integration: validated capability layer, docs, and session state

This commit is contained in:
Fisto
2026-09-11 14:09:04 +02:00
parent 2a15f057df
commit e62d3007d8
33 changed files with 1897 additions and 612 deletions
+83
View File
@@ -0,0 +1,83 @@
/*
* Vesktop ⇄ Veskslop daemon protocol.
*
* This is the only surface the external daemon can reach. Every action is
* validated by the core before anything touches Discord, and every failure is
* returned as a structured error instead of throwing.
*/
export const enum PuppetAction {
Ping = "ping",
EventsSubscribe = "events.subscribe",
StateGet = "state.get",
MessageSend = "message.send",
MessageRead = "message.read",
DmSend = "dm.send"
}
export const PuppetActions: readonly PuppetAction[] = [
PuppetAction.Ping,
PuppetAction.EventsSubscribe,
PuppetAction.StateGet,
PuppetAction.MessageSend,
PuppetAction.MessageRead,
PuppetAction.DmSend
];
export const enum PuppetErrorCode {
InvalidRequest = "INVALID_REQUEST",
PayloadTooLarge = "PAYLOAD_TOO_LARGE",
UnknownAction = "UNKNOWN_ACTION",
CoreUnavailable = "CORE_UNAVAILABLE",
NotLoggedIn = "NOT_LOGGED_IN",
InvalidSnowflake = "INVALID_SNOWFLAKE",
InvalidParam = "INVALID_PARAM",
ContentEmpty = "CONTENT_EMPTY",
ContentTooLong = "CONTENT_TOO_LONG",
ChannelNotFound = "CHANNEL_NOT_FOUND",
NotSendable = "NOT_SENDABLE",
SendFailed = "SEND_FAILED",
DmUnavailable = "DM_UNAVAILABLE",
RateLimited = "RATE_LIMITED",
Internal = "INTERNAL"
}
export interface PuppetError {
code: PuppetErrorCode | string;
message: string;
}
export interface PuppetRequest {
id?: string | number;
action: string;
params?: Record<string, unknown>;
}
export type PuppetResult =
| { ok: true; result?: unknown }
| { ok: false; error: PuppetError };
export type PuppetResponse =
| { id?: string | number; ok: true; result?: unknown }
| { id?: string | number; ok: false; error: PuppetError };
export interface PuppetEvent {
type: string;
[key: string]: unknown;
}
/** Hard safety limits applied core-side, regardless of what the daemon asks for. */
export const PUPPET_LIMITS = {
maxContentLength: 2000,
maxReadLimit: 100,
minActionIntervalMs: 500,
maxActionsPerMinute: 30,
maxRequestBytes: 64 * 1024,
maxChannelsPerGuild: 1000
};
const SNOWFLAKE_RE = /^\d{17,20}$/;
export function isSnowflake(value: unknown): value is string {
return typeof value === "string" && SNOWFLAKE_RE.test(value);
}