1
0

feat: add private profile media and realtime contracts

This commit is contained in:
2026-08-11 19:21:49 -07:00
parent a2a52bfdae
commit 1c37ef8f3e
22 changed files with 2321 additions and 8 deletions
+150
View File
@@ -0,0 +1,150 @@
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import {
authorizeMediaSurface,
createMediaSurfaceLifecycle,
isMediaSurface,
parseMediaSurface,
parseMediaViewerContext,
transitionMediaSurface,
type MediaSurface,
type MediaSurfaceSource,
} from "../media/index.ts";
import type { VideoTexture } from "three";
const PRIVATE_SOURCE: MediaSurfaceSource = {
kind: "live-stream",
locator: "opaque:private-stream-token",
privacy: "private",
hasAudio: true,
autoplay: false,
muted: true,
};
function surface(over: Partial<MediaSurface> = {}): MediaSurface {
return {
screenId: "screen-1",
officeId: "office-1",
levelId: "level-1",
roomId: "room-1",
acl: {
audience: "office-members",
viewerIds: [],
presenterIds: ["presenter-1"],
moderatorIds: ["moderator-1"],
},
source: PRIVATE_SOURCE,
state: { status: "presenting", presenterId: "presenter-1", revision: 1 },
...over,
};
}
describe("media surface validation", () => {
it("accepts a strict JSON round trip and rejects extra/non-JSON fields", () => {
const parsed = parseMediaSurface(JSON.parse(JSON.stringify(surface())));
assert.deepEqual(parsed, surface());
assert.equal(isMediaSurface({ ...surface(), surprise: true }), false);
assert.equal(isMediaSurface({ ...surface(), screenId: "bad id" }), false);
assert.equal(isMediaSurface(Object.assign(Object.create(null), surface())), false);
});
it("enforces state/source consistency and safe playback literals", () => {
assert.throws(() => parseMediaSurface({ ...surface(), source: null }), /require a source/);
assert.throws(() => parseMediaSurface({
...surface(),
source: { ...PRIVATE_SOURCE, autoplay: true },
}), /autoplay/);
assert.throws(() => parseMediaSurface({
...surface(),
source: { ...PRIVATE_SOURCE, muted: false },
}), /muted/);
assert.throws(() => parseMediaSurface({
...surface(),
acl: { ...surface().acl, audience: "public" },
}), /private source/);
});
it("strictly validates the server-created viewer context", () => {
assert.deepEqual(parseMediaViewerContext({
viewerId: "viewer-1", officeIds: ["office-1"], optedIn: true,
}), { viewerId: "viewer-1", officeIds: ["office-1"], optedIn: true });
assert.throws(() => parseMediaViewerContext({
viewerId: null, officeIds: [], optedIn: true, clientClaimsAdmin: true,
}), /exactly/);
});
});
describe("server-enforceable authorization", () => {
it("never returns a private source to an anonymous public viewer", () => {
const decision = authorizeMediaSurface(surface(), { viewerId: null, officeIds: [], optedIn: true });
assert.equal(decision.authorized, false);
assert.equal(decision.canView, false);
assert.equal(decision.reason, "authentication_required");
assert.equal(decision.surface.source, null);
assert.ok(!JSON.stringify(decision).includes(PRIVATE_SOURCE.locator));
});
it("requires both trusted membership and explicit opt-in before releasing source", () => {
const context = { viewerId: "viewer-1", officeIds: ["office-1"], optedIn: false };
const waiting = authorizeMediaSurface(surface(), context);
assert.equal(waiting.authorized, true);
assert.equal(waiting.reason, "opt_in_required");
assert.equal(waiting.surface.source, null);
const ready = authorizeMediaSurface(surface(), { ...context, optedIn: true });
assert.equal(ready.canView, true);
assert.equal(ready.surface.source?.locator, PRIVATE_SOURCE.locator);
assert.deepEqual(ready.surface.playback, { autoplay: false, muted: true });
});
});
describe("presenter lifecycle", () => {
it("stops and revokes by clearing the sensitive source", () => {
const stopped = transitionMediaSurface(surface(), { type: "stop", presenterId: "presenter-1" });
assert.equal(stopped.state.status, "stopped");
assert.equal(stopped.source, null);
assert.equal(stopped.state.revision, 2);
const revoked = transitionMediaSurface(surface(), { type: "revoke", actorId: "moderator-1" });
assert.equal(revoked.state.status, "revoked");
assert.equal(revoked.source, null);
assert.throws(() => transitionMediaSurface(surface(), { type: "revoke", actorId: "stranger" }));
});
it("retains authorization through a deterministic disconnect/reconnect", () => {
const reconnecting = transitionMediaSurface(surface(), { type: "disconnect", presenterId: "presenter-1" });
assert.equal(reconnecting.state.status, "reconnecting");
const resumed = transitionMediaSurface(reconnecting, { type: "reconnect", presenterId: "presenter-1" });
assert.equal(resumed.state.status, "presenting");
assert.equal(resumed.state.revision, 3);
assert.throws(() => transitionMediaSurface(reconnecting, { type: "reconnect", presenterId: "other" }));
});
});
describe("caller-owned video/texture lifecycle", () => {
it("never plays, stops a track, or disposes a texture and releases references", () => {
let pauses = 0;
let stops = 0;
let disposals = 0;
const video = {
autoplay: true,
muted: false,
pause: () => { pauses += 1; },
} as unknown as HTMLVideoElement;
const texture = { dispose: () => { disposals += 1; } } as unknown as VideoTexture;
const track = { stop: () => { stops += 1; } } as unknown as MediaStreamTrack;
const lifecycle = createMediaSurfaceLifecycle();
lifecycle.bind({ video, texture, track });
assert.equal(video.autoplay, false);
assert.equal(video.muted, true);
assert.equal(lifecycle.texture(), null);
lifecycle.apply(authorizeMediaSurface(surface(), {
viewerId: "viewer-1", officeIds: ["office-1"], optedIn: true,
}));
assert.equal(lifecycle.texture(), texture);
lifecycle.dispose();
lifecycle.dispose();
assert.equal(lifecycle.texture(), null);
assert.ok(pauses >= 2);
assert.equal(stops, 0);
assert.equal(disposals, 0);
});
});
+184
View File
@@ -0,0 +1,184 @@
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import {
actorKindForPresence,
clearLocalProfile,
createDefaultLocalProfile,
createWebcamFaceConsent,
decodeLocalProfile,
encodeLocalProfile,
initialWebcamFaceConsent,
loadLocalProfile,
resolveHumanoidAppearance,
saveLocalProfile,
transitionWebcamFaceConsent,
type LocalProfileV1,
type ProfileStorageAdapter,
} from "../profile/index.ts";
class MemoryStorage implements ProfileStorageAdapter {
readonly values = new Map<string, string>();
getItem(key: string): string | null { return this.values.get(key) ?? null; }
setItem(key: string, value: string): void { this.values.set(key, value); }
removeItem(key: string): void { this.values.delete(key); }
}
describe("local member profile", () => {
it("makes stable, useful defaults from identity without retaining or leaking the id", () => {
const identityId = "auth0|private-user-82914";
const first = createDefaultLocalProfile(identityId, " Avery ");
const second = createDefaultLocalProfile(identityId, "Avery");
assert.deepEqual(first, second);
assert.equal(first.displayName, "Avery");
const encoded = encodeLocalProfile(first);
assert.equal(encoded.includes(identityId), false);
assert.deepEqual(Object.keys(first).sort(), ["appearance", "displayName", "version"]);
assert.doesNotThrow(() => JSON.stringify(first));
const resolved = resolveHumanoidAppearance(first.appearance);
assert.match(resolved.skinTone, /^#[0-9a-f]{6}$/i);
assert.match(resolved.outfitColor, /^#[0-9a-f]{6}$/i);
assert.equal(resolved.bodyShape, first.appearance.bodyShape);
});
it("strictly rejects unknown, malformed and future profile data", () => {
const profile = createDefaultLocalProfile("member", "Member");
assert.equal(decodeLocalProfile({ ...profile, identityId: "leak" }).ok, false);
assert.equal(decodeLocalProfile({ ...profile, faceImageUrl: "camera://stream" }).ok, false);
assert.equal(decodeLocalProfile({ ...profile, appearance: { ...profile.appearance, outfit: "rainbow" } }).ok, false);
assert.deepEqual(decodeLocalProfile({ version: 99 }), { ok: false, error: "profile: unsupported version" });
assert.deepEqual(decodeLocalProfile("{"), { ok: false, error: "profile: data is not valid JSON" });
assert.throws(() => createDefaultLocalProfile("", "Member"), RangeError);
});
it("migrates the one exact V1 shape into an isolated V2 appearance", () => {
const legacy: LocalProfileV1 = {
version: 1,
displayName: "River",
skinTone: "umber",
outfit: "navy",
accent: "amber",
hair: "auburn",
bodyShape: "slim",
};
const decoded = decodeLocalProfile(JSON.stringify(legacy));
assert.equal(decoded.ok, true);
if (!decoded.ok) return;
assert.equal(decoded.migrated, true);
assert.deepEqual(decoded.profile, {
version: 2,
displayName: "River",
appearance: {
skinTone: "umber",
outfit: "navy",
accent: "amber",
hair: "auburn",
bodyShape: "slim",
},
});
assert.equal(decodeLocalProfile({ ...legacy, extra: true }).ok, false);
});
it("maps signed-in and anonymous roles by environment", () => {
assert.equal(actorKindForPresence(true, "outdoors"), "humanoid");
assert.equal(actorKindForPresence(true, "office"), "humanoid");
assert.equal(actorKindForPresence(false, "outdoors"), "crow");
assert.equal(actorKindForPresence(false, "office"), "dog");
});
});
describe("profile persistence boundary", () => {
it("round-trips, reports migration without an implicit rewrite, and clears", () => {
const storage = new MemoryStorage();
const profile = createDefaultLocalProfile("signed-in-1", "Morgan");
assert.deepEqual(saveLocalProfile(storage, "tera.profile", profile), { ok: true });
assert.deepEqual(loadLocalProfile(storage, "tera.profile"), {
status: "loaded",
profile,
migrated: false,
});
const legacy: LocalProfileV1 = {
version: 1,
displayName: "Morgan",
skinTone: "sand",
outfit: "sage",
accent: "aqua",
hair: "black",
bodyShape: "average",
};
storage.values.set("legacy", JSON.stringify(legacy));
const before = storage.values.get("legacy");
const loaded = loadLocalProfile(storage, "legacy");
assert.equal(loaded.status, "loaded");
if (loaded.status === "loaded") assert.equal(loaded.migrated, true);
assert.equal(storage.values.get("legacy"), before, "load never silently rewrites data");
assert.deepEqual(clearLocalProfile(storage, "tera.profile"), { ok: true });
assert.deepEqual(loadLocalProfile(storage, "tera.profile"), { status: "missing" });
});
it("contains adapter and encoder exceptions", () => {
const unavailable: ProfileStorageAdapter = {
getItem: () => { throw new Error("blocked"); },
setItem: () => { throw new Error("quota"); },
removeItem: () => { throw new Error("blocked"); },
};
const profile = createDefaultLocalProfile("signed-in-2", "Taylor");
assert.equal(loadLocalProfile(unavailable, "tera.profile").status, "unavailable");
assert.equal(saveLocalProfile(unavailable, "tera.profile", profile).ok, false);
assert.equal(clearLocalProfile(unavailable, "tera.profile").ok, false);
assert.equal(loadLocalProfile(unavailable, " ").status, "invalid");
const invalid = { ...profile, displayName: "" };
assert.equal(saveLocalProfile(new MemoryStorage(), "x", invalid).ok, false);
});
});
describe("ephemeral webcam face consent", () => {
it("starts off with explicit privacy invariants and cannot auto-start", () => {
const state = initialWebcamFaceConsent();
assert.deepEqual(state, {
status: "off",
consentGranted: false,
ephemeral: true,
persistence: "none",
autoFetch: false,
revision: 0,
});
const rejected = transitionWebcamFaceConsent(state, { type: "start", explicitConsent: true });
assert.equal(rejected.accepted, false);
if (!rejected.accepted) assert.equal(rejected.reason, "consent-required");
});
it("requires request then explicit start, and clears consent on stop", () => {
const consent = createWebcamFaceConsent();
assert.equal(consent.requestStart().accepted, true);
assert.equal(consent.state().status, "awaiting-consent");
assert.equal(consent.start(true).accepted, true);
assert.deepEqual(consent.state(), {
status: "active",
consentGranted: true,
ephemeral: true,
persistence: "none",
autoFetch: false,
revision: 2,
});
assert.equal(consent.stop().accepted, true);
assert.equal(consent.state().status, "stopped");
assert.equal(consent.state().consentGranted, false);
assert.equal(consent.start(true).accepted, false, "a stopped session needs a new request");
});
it("revokes from any live state and requires a fresh user request before reuse", () => {
const consent = createWebcamFaceConsent();
consent.requestStart();
consent.start(true);
assert.equal(consent.revoke().accepted, true);
assert.equal(consent.state().status, "revoked");
assert.equal(consent.state().consentGranted, false);
assert.equal(consent.start(true).accepted, false);
assert.equal(consent.requestStart().accepted, true);
assert.equal(consent.state().status, "awaiting-consent");
const leaked = consent.state();
leaked.status = "active";
assert.equal(consent.state().status, "awaiting-consent");
});
});
+262
View File
@@ -0,0 +1,262 @@
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import {
PoseInterpolationBuffer,
isEntityPoseSnapshot,
isInterestCell,
isRealtimeSequence,
isRealtimeTimestamp,
validateClientRealtimeMessage,
validateMotion,
validateServerRealtimeMessage,
type ActorPoseSnapshot,
type InterestCell,
type VehiclePoseSnapshot,
} from "../realtime/index.ts";
const localActor = (
sequence: number,
timestampMs: number,
xM: number,
headingDeg = 0,
): ActorPoseSnapshot => ({
entity: "actor",
actorId: "actor-karti",
kind: "humanoid",
sequence,
timestampMs,
pose: {
space: "local",
cell: { kind: "floor", officeId: "lumbridge-hq", floorId: "level-1" },
xM,
yM: 0,
zM: 2,
headingDeg,
pitchDeg: 0,
},
velocity: { xMps: 10, yMps: 0, zMps: 0, yawDegPerSec: 10 },
});
const geographicVehicle = (
sequence: number,
timestampMs: number,
lat: number,
): VehiclePoseSnapshot => ({
entity: "vehicle",
vehicleId: "model-x-hero",
kind: "model-x",
driverActorId: "actor-karti",
sequence,
timestampMs,
pose: {
space: "geographic",
lat,
lng: -120,
altitudeM: 100,
headingDeg: 0,
pitchDeg: 0,
},
velocity: { xMps: 0, yMps: 0, zMps: 30, yawDegPerSec: 0 },
steering: 0,
wheelRadians: 2,
});
describe("realtime spatial protocol", () => {
it("validates all hierarchical interest cell kinds", () => {
const cells: InterestCell[] = [
{ kind: "california-tile", x: -4, y: 18, level: 6 },
{ kind: "city", cityId: "bay-area" },
{ kind: "office", officeId: "lumbridge-hq" },
{ kind: "floor", officeId: "lumbridge-hq", floorId: "level-1" },
{
kind: "room",
officeId: "lumbridge-hq",
floorId: "level-1",
roomId: "commons",
},
];
assert.ok(cells.every(isInterestCell));
assert.equal(isInterestCell({ kind: "city", cityId: "new-york" }), false);
assert.equal(isInterestCell({ kind: "california-tile", x: 0.5, y: 2, level: 4 }), false);
});
it("bounds sequence and timestamps before accepting an envelope", () => {
assert.equal(isRealtimeSequence(0), true);
assert.equal(isRealtimeSequence(4_294_967_295), true);
assert.equal(isRealtimeSequence(4_294_967_296), false);
assert.equal(isRealtimeTimestamp(1_765_000_000_000), true);
assert.equal(isRealtimeTimestamp(Number.MAX_SAFE_INTEGER), false);
});
it("accepts strict join/resume grants and membership revocation", () => {
const joinRequest = {
type: "join-request",
protocolVersion: 1,
requestId: "request-1",
actorId: "actor-karti",
resumeToken: null,
lastReceivedSequence: null,
interests: [{ kind: "city", cityId: "bay-area" }],
};
assert.equal(validateClientRealtimeMessage(joinRequest).ok, true);
const grant = {
type: "join-grant",
protocolVersion: 1,
requestId: "request-1",
sessionId: "session-1",
actorId: "actor-karti",
role: "member",
serverEpoch: "epoch-a",
serverTimeMs: 1_765_000_000_000,
nextSequence: 4,
resumeToken: "rotating-secret",
interests: joinRequest.interests,
initial: [localActor(3, 1_765_000_000_000, 0)],
};
assert.equal(validateServerRealtimeMessage(grant).ok, true);
assert.equal(validateClientRealtimeMessage({
type: "resume-request",
protocolVersion: 1,
requestId: "request-2",
sessionId: "session-1",
resumeToken: "rotating-secret",
serverEpoch: "epoch-a",
lastReceivedSequence: 3,
interests: joinRequest.interests,
}).ok, true);
assert.equal(validateServerRealtimeMessage({
type: "membership-revoked",
protocolVersion: 1,
serverEpoch: "epoch-a",
sequence: 5,
timestampMs: 1_765_000_000_010,
sessionId: "session-1",
actorId: "actor-karti",
reason: "membership-revoked",
reconnectAllowed: false,
}).ok, true);
});
it("rejects malformed, oversized, and non-finite server input", () => {
const actor = localActor(1, 1000, 0);
assert.equal(isEntityPoseSnapshot(actor), true);
assert.equal(isEntityPoseSnapshot({ ...actor, pose: { ...actor.pose, xM: Number.NaN } }), false);
assert.equal(validateServerRealtimeMessage({
type: "pose-delta",
protocolVersion: 1,
serverEpoch: "epoch-a",
sequence: 2,
timestampMs: 1000,
updates: [actor],
removedEntityIds: Array.from({ length: 2_049 }, (_, index) => `actor-${index}`),
}).ok, false);
assert.equal(validateServerRealtimeMessage({ type: "pose-delta", protocolVersion: 2 }).ok, false);
});
});
describe("authoritative motion validation", () => {
const limits = {
maximumHorizontalSpeedMps: 15,
maximumVerticalSpeedMps: 8,
maximumTurnRateDegPerSec: 180,
positionSlackM: 0.25,
};
it("accepts plausible actor movement and reports measured rates", () => {
const result = validateMotion(localActor(1, 1_000, 0), localActor(2, 2_000, 10), limits);
assert.equal(result.ok, true);
if (result.ok) {
assert.equal(result.horizontalSpeedMps, 9.75);
assert.equal(result.verticalSpeedMps, 0);
assert.equal(result.turnRateDegPerSec, 0);
}
});
it("rejects speed hacks, stale sequences, identity and interest-cell jumps", () => {
assert.deepEqual(validateMotion(localActor(1, 1_000, 0), localActor(2, 1_100, 50), limits), {
ok: false,
reason: "speed-exceeded",
});
assert.deepEqual(validateMotion(localActor(2, 2_000, 0), localActor(2, 3_000, 1), limits), {
ok: false,
reason: "time-invalid",
});
const another = { ...localActor(2, 2_000, 1), actorId: "actor-other" };
assert.deepEqual(validateMotion(localActor(1, 1_000, 0), another, limits), {
ok: false,
reason: "identity-mismatch",
});
const anotherFloor = localActor(2, 2_000, 1);
if (anotherFloor.pose.space === "local" && anotherFloor.pose.cell.kind === "floor") {
anotherFloor.pose.cell.floorId = "level-2";
}
assert.deepEqual(validateMotion(localActor(1, 1_000, 0), anotherFloor, limits), {
ok: false,
reason: "space-mismatch",
});
});
it("uses real geographic distance for statewide vehicle checks", () => {
const start = geographicVehicle(10, 10_000, 34);
const plausible = geographicVehicle(11, 11_000, 34.0002);
const result = validateMotion(start, plausible, {
maximumHorizontalSpeedMps: 40,
maximumVerticalSpeedMps: 5,
maximumTurnRateDegPerSec: 90,
positionSlackM: 1,
});
assert.equal(result.ok, true);
});
});
describe("pose interpolation buffer", () => {
it("interpolates deterministically at delayed server time", () => {
const a = new PoseInterpolationBuffer({ interpolationDelayMs: 100 });
const b = new PoseInterpolationBuffer({ interpolationDelayMs: 100 });
for (const buffer of [a, b]) {
assert.equal(buffer.push(localActor(1, 1_000, 0, 350)), true);
assert.equal(buffer.push(localActor(2, 1_200, 2, 10)), true);
}
const first = a.sample(1_200);
const second = b.sample(1_200);
assert.deepEqual(first, second);
assert.equal(first?.mode, "interpolated");
assert.equal(first?.timestampMs, 1_100);
assert.ok(first?.pose.space === "local");
if (first?.pose.space === "local") {
assert.equal(first.pose.xM, 1);
assert.equal(first.pose.headingDeg, 360, "heading follows the short arc through north");
}
});
it("caps extrapolation and then holds the capped predicted pose", () => {
const buffer = new PoseInterpolationBuffer({
interpolationDelayMs: 0,
maximumExtrapolationMs: 150,
});
buffer.push(localActor(1, 1_000, 0));
const predicted = buffer.sample(1_100);
assert.equal(predicted?.mode, "extrapolated");
assert.ok(predicted?.pose.space === "local");
if (predicted?.pose.space === "local") assert.equal(predicted.pose.xM, 1);
const capped = buffer.sample(10_000);
assert.equal(capped?.mode, "held");
assert.equal(capped?.timestampMs, 1_150);
assert.ok(capped?.pose.space === "local");
if (capped?.pose.space === "local") assert.equal(capped.pose.xM, 1.5);
});
it("rejects stale, duplicate, or mixed-entity input and caps capacity", () => {
const buffer = new PoseInterpolationBuffer({ capacity: 2 });
assert.equal(buffer.push(localActor(1, 1_000, 0)), true);
assert.equal(buffer.push(localActor(1, 1_100, 1)), false);
assert.equal(buffer.push(localActor(2, 1_200, 2)), true);
assert.equal(buffer.push(localActor(3, 1_300, 3)), true);
assert.equal(buffer.size(), 2);
assert.equal(buffer.push({ ...localActor(4, 1_400, 4), actorId: "other" }), false);
buffer.clear();
assert.equal(buffer.size(), 0);
assert.equal(buffer.sample(1_500), null);
});
});
+14
View File
@@ -74,6 +74,20 @@ describe("playable city scene actor", () => {
actor.dispose();
});
it("can exaggerate presentation scale without changing metre-space motion", () => {
const actor = createSceneActor(options({
sceneUnitsPerMetre: 0.001,
visualSceneUnitsPerMetre: 0.025,
active: true,
}));
assert.equal(actor.root.scale.x, 0.025);
actor.setActions({ forward: 1 });
actor.tick(0.2);
assert.ok(actor.state().z < 3);
assert.ok(Math.abs(actor.root.position.z - actor.state().z * 0.001) < 1e-12);
actor.dispose();
});
it("keeps its stable root and identity while replacing procedural rigs", () => {
const actor = createSceneActor(options({ active: true }));
const root = actor.root;
+9
View File
@@ -69,6 +69,15 @@ describe("walker input and clock", () => {
leaked.position.x = Number.NaN;
assert.deepEqual(controller.state().position, { x: 2, z: 2 });
});
it("uses and restores a normalized authored arrival facing", () => {
const controller = walker(planWith(), { facing: { x: 3, z: 4 } });
assert.deepEqual(controller.state().facing, { x: 0.6, z: 0.8 });
controller.tick(0.1, { x: -1, z: 0 });
assert.deepEqual(controller.state().facing, { x: -1, z: 0 });
controller.reset();
assert.deepEqual(controller.state().facing, { x: 0.6, z: 0.8 });
});
});
describe("walker collision", () => {