dev/2026-04-08 #1

Merged
hzhang merged 8 commits from dev/2026-04-08 into main 2026-04-13 09:33:41 +00:00
3 changed files with 185 additions and 1 deletions
Showing only changes of commit de9c41fc88 - Show all commits

View File

@@ -7,7 +7,8 @@ It is referenced as a git submodule by both `Yonexus.Server` and `Yonexus.Client
## Contents
- `PROTOCOL.md` — full protocol specification
- TypeScript type definitions (planned: `src/types.ts`)
- `src/types.ts` — shared builtin envelope / payload TypeScript definitions
- `src/index.ts` — package export surface
- Canonical JSON shape references
## Purpose

1
src/index.ts Normal file
View File

@@ -0,0 +1 @@
export * from "./types.js";

182
src/types.ts Normal file
View File

@@ -0,0 +1,182 @@
export const YONEXUS_PROTOCOL_VERSION = "1" as const;
export const builtinMessageTypes = [
"hello",
"hello_ack",
"pair_request",
"pair_confirm",
"pair_success",
"pair_failed",
"auth_request",
"auth_success",
"auth_failed",
"re_pair_required",
"heartbeat",
"heartbeat_ack",
"status_update",
"disconnect_notice",
"error"
] as const;
export type BuiltinMessageType = (typeof builtinMessageTypes)[number];
export interface BuiltinEnvelope<
TType extends BuiltinMessageType = BuiltinMessageType,
TPayload extends Record<string, unknown> = Record<string, unknown>
> {
type: TType;
requestId?: string;
timestamp?: number;
payload?: TPayload;
}
export interface HelloPayload {
identifier: string;
hasSecret: boolean;
hasKeyPair: boolean;
publicKey?: string;
protocolVersion: string;
}
export type HelloAckNextAction =
| "pair_required"
| "auth_required"
| "rejected"
| "waiting_pair_confirm";
export interface HelloAckPayload {
identifier: string;
nextAction: HelloAckNextAction;
}
export type AdminNotificationStatus = "sent" | "failed";
export interface PairRequestPayload {
identifier: string;
expiresAt: number;
ttlSeconds: number;
adminNotification: AdminNotificationStatus;
codeDelivery: "out_of_band";
}
export interface PairConfirmPayload {
identifier: string;
pairingCode: string;
}
export interface PairSuccessPayload {
identifier: string;
secret: string;
pairedAt: number;
}
export type PairFailedReason =
| "expired"
| "invalid_code"
| "identifier_not_allowed"
| "admin_notification_failed"
| "internal_error";
export interface PairFailedPayload {
identifier: string;
reason: PairFailedReason;
}
export interface AuthRequestPayload {
identifier: string;
nonce: string;
proofTimestamp: number;
signature: string;
publicKey?: string;
}
export interface AuthSuccessPayload {
identifier: string;
authenticatedAt: number;
status: "online";
}
export type AuthFailedReason =
| "unknown_identifier"
| "not_paired"
| "invalid_signature"
| "invalid_secret"
| "stale_timestamp"
| "future_timestamp"
| "nonce_collision"
| "rate_limited"
| "re_pair_required";
export interface AuthFailedPayload {
identifier: string;
reason: AuthFailedReason;
}
export interface RePairRequiredPayload {
identifier: string;
reason: "nonce_collision" | "rate_limited" | "trust_revoked";
}
export interface HeartbeatPayload {
identifier: string;
status: "alive";
}
export interface HeartbeatAckPayload {
identifier: string;
status: "online" | "unstable" | "offline";
}
export interface StatusUpdatePayload {
identifier: string;
status: "online" | "unstable" | "offline";
reason: string;
}
export interface DisconnectNoticePayload {
identifier: string;
reason: string;
}
export type ProtocolErrorCode =
| "MALFORMED_MESSAGE"
| "UNSUPPORTED_PROTOCOL_VERSION"
| "IDENTIFIER_NOT_ALLOWED"
| "PAIRING_REQUIRED"
| "PAIRING_EXPIRED"
| "ADMIN_NOTIFICATION_FAILED"
| "AUTH_FAILED"
| "NONCE_COLLISION"
| "RATE_LIMITED"
| "RE_PAIR_REQUIRED"
| "CLIENT_OFFLINE"
| "INTERNAL_ERROR";
export interface ErrorPayload {
code: ProtocolErrorCode;
message?: string;
details?: Record<string, unknown>;
}
export type BuiltinPayloadMap = {
hello: HelloPayload;
hello_ack: HelloAckPayload;
pair_request: PairRequestPayload;
pair_confirm: PairConfirmPayload;
pair_success: PairSuccessPayload;
pair_failed: PairFailedPayload;
auth_request: AuthRequestPayload;
auth_success: AuthSuccessPayload;
auth_failed: AuthFailedPayload;
re_pair_required: RePairRequiredPayload;
heartbeat: HeartbeatPayload;
heartbeat_ack: HeartbeatAckPayload;
status_update: StatusUpdatePayload;
disconnect_notice: DisconnectNoticePayload;
error: ErrorPayload;
};
export type TypedBuiltinEnvelope<TType extends keyof BuiltinPayloadMap> = BuiltinEnvelope<
TType,
BuiltinPayloadMap[TType]
>;