import { z } from 'zod' import { PAIRING_OFFER_VERSION, type PairingOffer } from './pairing' export const RuntimeAccessEndpointSchema = z.object({ id: z.string().min(1), kind: z.literal('websocket'), label: z.string().min(1), endpoint: z.string().min(1), deviceToken: z.string().min(1), publicKeyB64: z.string().min(1) }) export type RuntimeAccessEndpoint = z.infer export const PublicRuntimeAccessEndpointSchema = RuntimeAccessEndpointSchema.omit({ deviceToken: true, publicKeyB64: true }) export type PublicRuntimeAccessEndpoint = z.infer export const RuntimeEnvironmentSourceSchema = z.enum(['manual', 'ephemeral-vm']) export type RuntimeEnvironmentSource = z.infer export const KnownRuntimeEnvironmentSchema = z.object({ id: z.string().min(1), name: z.string().min(1), createdAt: z.number().finite(), updatedAt: z.number().finite(), lastUsedAt: z.number().finite().nullable(), runtimeId: z.string().min(1).nullable(), source: RuntimeEnvironmentSourceSchema.optional(), endpoints: z.array(RuntimeAccessEndpointSchema).min(1), preferredEndpointId: z.string().min(1) }) export type KnownRuntimeEnvironment = z.infer export type PublicKnownRuntimeEnvironment = Omit & { endpoints: PublicRuntimeAccessEndpoint[] } export function redactRuntimeEnvironment( environment: KnownRuntimeEnvironment ): PublicKnownRuntimeEnvironment { return { ...environment, endpoints: environment.endpoints.map( ({ deviceToken: _deviceToken, publicKeyB64: _key, ...rest }) => rest ) } } export const RuntimeEnvironmentStoreSchema = z.object({ version: z.literal(1), environments: z.array(KnownRuntimeEnvironmentSchema) }) export type RuntimeEnvironmentStore = z.infer export function createEnvironmentFromPairingOffer(args: { id: string name: string now: number offer: PairingOffer runtimeId?: string | null source?: RuntimeEnvironmentSource }): KnownRuntimeEnvironment { const endpointId = `ws-${args.id}` return KnownRuntimeEnvironmentSchema.parse({ id: args.id, name: args.name, createdAt: args.now, updatedAt: args.now, lastUsedAt: null, runtimeId: args.runtimeId ?? null, ...(args.source ? { source: args.source } : {}), endpoints: [ { id: endpointId, kind: 'websocket', label: 'WebSocket', endpoint: args.offer.endpoint, deviceToken: args.offer.deviceToken, publicKeyB64: args.offer.publicKeyB64 } ], preferredEndpointId: endpointId }) } export function isEphemeralVmRuntimeEnvironment( environment: Pick ): boolean { return environment.source === 'ephemeral-vm' } export function isUserManagedRuntimeEnvironment( environment: Pick ): boolean { return !isEphemeralVmRuntimeEnvironment(environment) } export function getPreferredPairingOffer(environment: KnownRuntimeEnvironment): PairingOffer { const endpoint = environment.endpoints.find((entry) => entry.id === environment.preferredEndpointId) ?? environment.endpoints[0] if (!endpoint) { throw new Error(`Environment ${environment.name} has no access endpoints`) } return { v: PAIRING_OFFER_VERSION, endpoint: endpoint.endpoint, deviceToken: endpoint.deviceToken, publicKeyB64: endpoint.publicKeyB64 } }