feat: add private profile media and realtime contracts
This commit is contained in:
@@ -0,0 +1,219 @@
|
||||
/** JSON-safe contracts for an eventual server-authoritative Tera session. */
|
||||
|
||||
export type RealtimeActorKind = "humanoid" | "dog" | "crow";
|
||||
export type RealtimeVehicleKind = "model-x";
|
||||
export type RealtimeMemberRole = "visitor" | "member" | "admin";
|
||||
export type RealtimeRevocationReason =
|
||||
| "signed-out"
|
||||
| "membership-revoked"
|
||||
| "session-replaced"
|
||||
| "protocol-violation"
|
||||
| "server-shutdown";
|
||||
|
||||
export interface CaliforniaTileInterest {
|
||||
kind: "california-tile";
|
||||
/** Discrete authored world grid, not web-map tiles. */
|
||||
x: number;
|
||||
y: number;
|
||||
level: number;
|
||||
}
|
||||
|
||||
export interface CityInterest {
|
||||
kind: "city";
|
||||
cityId: "bay-area" | "socal";
|
||||
}
|
||||
|
||||
export interface OfficeInterest {
|
||||
kind: "office";
|
||||
officeId: string;
|
||||
}
|
||||
|
||||
export interface FloorInterest {
|
||||
kind: "floor";
|
||||
officeId: string;
|
||||
floorId: string;
|
||||
}
|
||||
|
||||
export interface RoomInterest {
|
||||
kind: "room";
|
||||
officeId: string;
|
||||
floorId: string;
|
||||
roomId: string;
|
||||
}
|
||||
|
||||
export type InterestCell =
|
||||
| CaliforniaTileInterest
|
||||
| CityInterest
|
||||
| OfficeInterest
|
||||
| FloorInterest
|
||||
| RoomInterest;
|
||||
|
||||
/** Monotonic within one server epoch and bounded to an unsigned 32-bit integer. */
|
||||
export type RealtimeSequence = number;
|
||||
/** Unix epoch milliseconds, serialized as a safe integer. */
|
||||
export type RealtimeTimestamp = number;
|
||||
|
||||
export interface GeographicPose {
|
||||
space: "geographic";
|
||||
lat: number;
|
||||
lng: number;
|
||||
altitudeM: number;
|
||||
headingDeg: number;
|
||||
pitchDeg: number;
|
||||
}
|
||||
|
||||
export interface LocalPose {
|
||||
space: "local";
|
||||
/** The smallest spatial cell whose coordinates define this pose. */
|
||||
cell: CityInterest | OfficeInterest | FloorInterest | RoomInterest;
|
||||
xM: number;
|
||||
yM: number;
|
||||
zM: number;
|
||||
headingDeg: number;
|
||||
pitchDeg: number;
|
||||
}
|
||||
|
||||
export type SpatialPose = GeographicPose | LocalPose;
|
||||
|
||||
export interface PoseVelocity {
|
||||
xMps: number;
|
||||
yMps: number;
|
||||
zMps: number;
|
||||
yawDegPerSec: number;
|
||||
}
|
||||
|
||||
interface EntityPoseSnapshotBase {
|
||||
sequence: RealtimeSequence;
|
||||
timestampMs: RealtimeTimestamp;
|
||||
pose: SpatialPose;
|
||||
velocity: PoseVelocity;
|
||||
}
|
||||
|
||||
export interface ActorPoseSnapshot extends EntityPoseSnapshotBase {
|
||||
entity: "actor";
|
||||
actorId: string;
|
||||
kind: RealtimeActorKind;
|
||||
}
|
||||
|
||||
export interface VehiclePoseSnapshot extends EntityPoseSnapshotBase {
|
||||
entity: "vehicle";
|
||||
vehicleId: string;
|
||||
kind: RealtimeVehicleKind;
|
||||
driverActorId: string | null;
|
||||
steering: number;
|
||||
wheelRadians: number;
|
||||
}
|
||||
|
||||
export type EntityPoseSnapshot = ActorPoseSnapshot | VehiclePoseSnapshot;
|
||||
|
||||
export interface JoinRequest {
|
||||
type: "join-request";
|
||||
protocolVersion: 1;
|
||||
requestId: string;
|
||||
actorId: string;
|
||||
resumeToken: string | null;
|
||||
lastReceivedSequence: RealtimeSequence | null;
|
||||
interests: readonly InterestCell[];
|
||||
}
|
||||
|
||||
export interface JoinGrant {
|
||||
type: "join-grant";
|
||||
protocolVersion: 1;
|
||||
requestId: string;
|
||||
sessionId: string;
|
||||
actorId: string;
|
||||
role: RealtimeMemberRole;
|
||||
serverEpoch: string;
|
||||
serverTimeMs: RealtimeTimestamp;
|
||||
nextSequence: RealtimeSequence;
|
||||
resumeToken: string;
|
||||
interests: readonly InterestCell[];
|
||||
initial: readonly EntityPoseSnapshot[];
|
||||
}
|
||||
|
||||
export interface ResumeRequest {
|
||||
type: "resume-request";
|
||||
protocolVersion: 1;
|
||||
requestId: string;
|
||||
sessionId: string;
|
||||
resumeToken: string;
|
||||
serverEpoch: string;
|
||||
lastReceivedSequence: RealtimeSequence;
|
||||
interests: readonly InterestCell[];
|
||||
}
|
||||
|
||||
export interface ResumeGrant {
|
||||
type: "resume-grant";
|
||||
protocolVersion: 1;
|
||||
requestId: string;
|
||||
sessionId: string;
|
||||
serverEpoch: string;
|
||||
serverTimeMs: RealtimeTimestamp;
|
||||
nextSequence: RealtimeSequence;
|
||||
resumeToken: string;
|
||||
/** True means queued deltas bridge the requested sequence without a gap. */
|
||||
continuous: boolean;
|
||||
snapshot: readonly EntityPoseSnapshot[];
|
||||
}
|
||||
|
||||
export interface PoseDelta {
|
||||
type: "pose-delta";
|
||||
protocolVersion: 1;
|
||||
serverEpoch: string;
|
||||
sequence: RealtimeSequence;
|
||||
timestampMs: RealtimeTimestamp;
|
||||
updates: readonly EntityPoseSnapshot[];
|
||||
removedEntityIds: readonly string[];
|
||||
}
|
||||
|
||||
export interface MembershipRevoked {
|
||||
type: "membership-revoked";
|
||||
protocolVersion: 1;
|
||||
serverEpoch: string;
|
||||
sequence: RealtimeSequence;
|
||||
timestampMs: RealtimeTimestamp;
|
||||
sessionId: string;
|
||||
actorId: string;
|
||||
reason: RealtimeRevocationReason;
|
||||
reconnectAllowed: boolean;
|
||||
}
|
||||
|
||||
export type ClientRealtimeMessage = JoinRequest | ResumeRequest;
|
||||
export type ServerRealtimeMessage = JoinGrant | ResumeGrant | PoseDelta | MembershipRevoked;
|
||||
|
||||
export type RealtimeValidationResult<T> =
|
||||
| { ok: true; value: T }
|
||||
| { ok: false; error: string };
|
||||
|
||||
export interface MotionLimits {
|
||||
maximumHorizontalSpeedMps: number;
|
||||
maximumVerticalSpeedMps: number;
|
||||
maximumTurnRateDegPerSec: number;
|
||||
/** Allows quantization and packet jitter without permitting teleportation. */
|
||||
positionSlackM: number;
|
||||
minimumDeltaSeconds?: number;
|
||||
maximumDeltaSeconds?: number;
|
||||
}
|
||||
|
||||
export type MotionValidationResult =
|
||||
| { ok: true; horizontalSpeedMps: number; verticalSpeedMps: number; turnRateDegPerSec: number }
|
||||
| {
|
||||
ok: false;
|
||||
reason: "identity-mismatch" | "space-mismatch" | "time-invalid" | "speed-exceeded";
|
||||
};
|
||||
|
||||
export interface InterpolationOptions {
|
||||
interpolationDelayMs?: number;
|
||||
maximumExtrapolationMs?: number;
|
||||
capacity?: number;
|
||||
}
|
||||
|
||||
export type BufferedSampleMode = "exact" | "interpolated" | "extrapolated" | "held";
|
||||
|
||||
export interface BufferedPoseSample {
|
||||
mode: BufferedSampleMode;
|
||||
pose: SpatialPose;
|
||||
velocity: PoseVelocity;
|
||||
timestampMs: RealtimeTimestamp;
|
||||
sourceSequence: RealtimeSequence;
|
||||
}
|
||||
Reference in New Issue
Block a user