@ziprack/sdk 0.2.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store-BHnO2KB3.js","sources":["../src/core/protocol.ts","../src/core/mock/MockRack.ts","../src/core/mock/MockTransport.ts","../src/core/mock/store.ts"],"sourcesContent":["export const PROTOCOL_NAMESPACE = 'ziprack' as const;\nexport const PROTOCOL_VERSION = 1 as const;\nexport const FORMAT = 'ziprack/1' as const;\n\nexport interface Envelope<T = unknown> {\n ns: typeof PROTOCOL_NAMESPACE;\n v: typeof PROTOCOL_VERSION;\n type: string;\n requestId?: string;\n payload?: T;\n}\n\nlet requestCounter = 0;\n\nexport function newRequestId(): string {\n const cryptoRef = typeof globalThis.crypto !== 'undefined' ? globalThis.crypto : undefined;\n if (cryptoRef && typeof cryptoRef.randomUUID === 'function') {\n return cryptoRef.randomUUID();\n }\n requestCounter += 1;\n\n return `req-${Date.now().toString(36)}-${requestCounter.toString(36)}`;\n}\n\nexport function createEnvelope<T>(type: string, payload?: T, requestId?: string): Envelope<T> {\n const envelope: Envelope<T> = { ns: PROTOCOL_NAMESPACE, v: PROTOCOL_VERSION, type, payload };\n if (requestId !== undefined) {\n envelope.requestId = requestId;\n }\n\n return envelope;\n}\n\nexport function isEnvelope(data: unknown): data is Envelope {\n if (typeof data !== 'object' || data === null) {\n return false;\n }\n const candidate = data as Partial<Envelope>;\n\n return candidate.ns === PROTOCOL_NAMESPACE && candidate.v === PROTOCOL_VERSION && typeof candidate.type === 'string';\n}\n\n/** Capability id from a message type (\"db:create\" -> \"db\"). */\nexport function capabilityOf(type: string): string {\n const index = type.indexOf(':');\n\n return index === -1 ? type : type.slice(0, index);\n}\n","import { capabilityOf } from '../protocol';\nimport type { AckResult, JsonObject, LaunchData, RackEvent, RoomMember, RoomRole } from '../types';\nimport type { RecordRow, WhereClause } from '../../db';\nimport type { StoredFile } from '../../storage';\nimport type { Store } from './store';\n\nexport interface MockManifest {\n schema?: string;\n slug: string;\n name: string;\n version: string;\n requires?: { capabilities?: string[]; profile?: string[] };\n media?: Array<{ id: string; provider: string; key: string }>;\n activities?: Array<{ id: string; type: string; label: string; scale?: unknown; segment?: string | null; sequence?: number }>;\n collections?: Array<{ name: string; scope: string; schema?: JsonObject }>;\n uploads?: Array<{ name: string; scope: string; mime?: string[]; max_bytes?: number }>;\n prompts?: Array<{ id: string; mode: 'analysis' | 'chat'; output_schema?: JsonObject; knowledge?: Array<{ slot: string }> }>;\n knowledge?: Array<{ id: string; label?: string }>;\n broadcast?: { facilitator_events?: string[]; channels?: string[]; mock_mode?: 'first_in' | 'opt_in' };\n roles?: Array<{ name: string; label?: string; description?: string; grant?: 'everyone' | 'members' | 'guests' | 'assigned' }>;\n [key: string]: unknown;\n}\n\nexport type AiMockHandler = (vars: JsonObject, mode: 'analysis' | 'chat', message?: string) => unknown | Promise<unknown>;\n\nexport interface MockRackOptions {\n /** Whether undeclared capabilities are refused, as a real Rack would. Default true when a manifest is present. */\n strict?: boolean;\n log?: (type: string, payload: unknown) => void;\n participantId?: number;\n participantName?: string;\n /** Force the mock room role instead of deriving it from the assignment mode. */\n role?: RoomRole;\n /** Launch as a guest: `guest` instead of `member`, and the guest grants. */\n guest?: boolean;\n /** Roles to hold on top of the grants, as if the Rack had assigned them (any name, built-in ones included). */\n roles?: string[];\n}\n\nexport type MockOutcome = AckResult | { stream: AsyncIterable<JsonObject>; final: () => JsonObject };\n\n/**\n * An in-memory Rack that services every capability so an applet can be built\n * and QA'd standalone. Shared by the browser mock transport (localStorage) and\n * the testing FakeHost (memory).\n */\nexport class MockRack {\n public readonly participantId: number;\n\n public readonly participantName: string;\n\n public readonly statements: Array<JsonObject & { id: string }> = [];\n\n public readonly events: RackEvent[] = [];\n\n private readonly aiHandlers = new Map<string, AiMockHandler>();\n\n private readonly chatHistory = new Map<string, Array<{ role: string; content: string }>>();\n\n private readonly blobs = new Map<string, string>();\n\n private readonly eventListeners = new Set<(event: RackEvent) => void>();\n\n private readonly roomMembers = new Map<number, RoomMember & { lastSeen: number; joinedAt?: number }>();\n\n private roomState: Record<string, { value: unknown; version: number }> = {};\n\n private role: RoomRole = 'participant';\n\n private readonly joinedAt = Date.now() + Math.random();\n\n private channel: BroadcastChannel | null = null;\n\n private heartbeat: ReturnType<typeof setInterval> | null = null;\n\n public constructor(\n public readonly manifest: MockManifest | null,\n private readonly store: Store,\n private readonly options: MockRackOptions = {},\n ) {\n this.participantId = options.participantId ?? Math.floor(Math.random() * 1_000_000) + 1;\n this.participantName = options.participantName ?? 'Dev User';\n }\n\n public get slug(): string {\n return this.manifest?.slug ?? 'applet';\n }\n\n private key(...parts: string[]): string {\n return `ziprack-mock:${this.slug}:${parts.join(':')}`;\n }\n\n public declares(capability: string): boolean {\n if (!this.manifest) {\n return true;\n }\n\n return (this.manifest.requires?.capabilities ?? []).some((ref) => ref.split('@')[0] === capability);\n }\n\n public onEvent(listener: (event: RackEvent) => void): () => void {\n this.eventListeners.add(listener);\n\n return () => {\n this.eventListeners.delete(listener);\n };\n }\n\n public pushEvent(event: RackEvent): void {\n this.events.push(event);\n this.eventListeners.forEach((l) => l(event));\n }\n\n public launchData(nameHint?: string): LaunchData {\n const m = this.manifest;\n const launch: LaunchData = {\n schema: 'ziprack/1',\n actor: { id: this.participantId, name: this.participantName },\n applet: { slug: this.slug, name: `${m?.name ?? nameHint ?? 'Applet'} (mock)`, version: m?.version ?? 'dev' },\n capabilities: m?.requires?.capabilities ?? [],\n media: Object.fromEntries((m?.media ?? []).map((item) => [item.id, {\n provider: item.provider,\n embedUrl: item.provider === 'vimeo' ? `https://player.vimeo.com/video/${item.key}?dnt=1` : `https://www.youtube-nocookie.com/embed/${item.key}?rel=0`,\n meta: null,\n }])),\n roles: this.roles(),\n };\n\n if (this.declares('auth')) {\n const user: LaunchData['auth'] = { user: { id: this.participantId, display_name: this.participantName } };\n for (const attribute of m?.requires?.profile ?? []) {\n user.user[attribute] = user.user[attribute] ?? `mock-${attribute}`;\n }\n launch.auth = user;\n }\n if (this.declares('attempt')) {\n launch.attempt = this.attempt();\n }\n if (this.declares('activity')) {\n launch.activity = { activities: [...(m?.activities ?? [])].sort((a, b) => (a.sequence ?? 0) - (b.sequence ?? 0)) };\n }\n if (this.declares('db')) {\n launch.db = { collections: (m?.collections ?? []).map((c) => ({ name: c.name, scope: c.scope })) };\n }\n if (this.declares('storage')) {\n launch.storage = { uploads: (m?.uploads ?? []).map((u) => ({ name: u.name, scope: u.scope, mime: u.mime ?? [], max_bytes: u.max_bytes ?? 10 * 1024 * 1024 })) };\n }\n if (this.declares('ai')) {\n launch.ai = {\n prompts: (m?.prompts ?? []).map((p) => (p.knowledge?.length ? { id: p.id, mode: p.mode, knowledge: p.knowledge.map((b) => b.slot) } : { id: p.id, mode: p.mode })),\n ...(m?.knowledge?.length ? { knowledge: m.knowledge.map((k) => ({ id: k.id, label: k.label ?? null })) } : {}),\n };\n }\n if (this.declares('broadcast')) {\n this.joinRoom();\n launch.broadcast = {\n room: { id: 1, code: 'MOCK01', name: `${this.slug} room`, status: 'open', mode: m?.broadcast?.mock_mode ?? 'first_in' },\n role: this.role,\n members: this.members(),\n state: this.stateSnapshot(),\n channels: m?.broadcast?.channels ?? ['main'],\n };\n }\n\n return launch;\n }\n\n /**\n * What a Rack would resolve: member or guest, the manifest's grants, and\n * any roles the options say were assigned.\n */\n public roles(): string[] {\n const guest = this.options.guest ?? false;\n const granted = (this.manifest?.roles ?? [])\n .filter((role) => role.grant === 'everyone' || (role.grant === 'members' && !guest) || (role.grant === 'guests' && guest))\n .map((role) => role.name);\n\n return [...new Set([guest ? 'guest' : 'member', ...granted, ...(this.options.roles ?? [])])];\n }\n\n public mockAi(promptId: string, handler: AiMockHandler): void {\n this.aiHandlers.set(promptId, handler);\n }\n\n public dispose(): void {\n if (this.heartbeat) {\n clearInterval(this.heartbeat);\n }\n if (this.channel) {\n this.send({ t: 'bye', from: this.member() });\n this.channel.close();\n }\n }\n\n // ---------------------------------------------------------------- dispatch\n\n public async handle(type: string, payload: JsonObject): Promise<MockOutcome> {\n this.options.log?.(type, payload);\n\n if (type === 'rack:eject') {\n return { ok: true };\n }\n\n const capability = capabilityOf(type);\n if ((this.options.strict ?? this.manifest !== null) && !this.declares(capability)) {\n return { ok: false, error: 'undeclared_capability', message: `The manifest does not declare the [${capability}] capability.` };\n }\n\n switch (type) {\n case 'attempt:state': return this.attemptState(payload);\n case 'attempt:segment': return this.attemptSegment(payload);\n case 'attempt:complete': return this.attemptComplete(payload);\n case 'activity:statement': return this.statement(payload);\n case 'db:create': return this.dbCreate(payload);\n case 'db:get': return this.dbGet(payload);\n case 'db:update': return this.dbUpdate(payload);\n case 'db:delete': return this.dbDelete(payload);\n case 'db:list': return this.dbList(payload);\n case 'db:count': return this.dbCount(payload);\n case 'storage:put': return this.storagePut(payload);\n case 'storage:url': return this.storageUrl(payload);\n case 'storage:list': return this.storageList(payload);\n case 'storage:delete': return this.storageDelete(payload);\n case 'ai:ask': return this.aiAsk(payload);\n case 'ai:chat': return this.aiChat(payload);\n case 'ai:chat.reset': this.chatHistory.delete(String(payload.prompt)); return { ok: true };\n case 'broadcast:join': return { ok: true, data: { members: this.members(), state: this.stateSnapshot() } };\n case 'broadcast:leave': return { ok: true };\n case 'broadcast:publish': return this.publish(payload);\n case 'broadcast:state.get': return { ok: true, data: { state: this.stateSnapshot(Array.isArray(payload.keys) ? (payload.keys as string[]) : undefined) } };\n case 'broadcast:state.set': return this.stateSet(payload);\n case 'broadcast:presence': return { ok: true, data: { members: this.members() } };\n case 'broadcast:invite': return this.invite();\n case 'broadcast:claim': return this.claim();\n case 'broadcast:transfer': return this.transfer(payload);\n default:\n return { ok: false, error: 'unknown_type', message: `Unknown message type [${type}].` };\n }\n }\n\n // ---------------------------------------------------------------- attempt\n\n public attempt(): NonNullable<LaunchData['attempt']> {\n return this.store.get(this.key('attempt')) ?? { id: 1, status: 'in_progress', state: null, segment: null };\n }\n\n private saveAttempt(attempt: NonNullable<LaunchData['attempt']>): void {\n this.store.set(this.key('attempt'), attempt);\n }\n\n private attemptState(payload: JsonObject): AckResult {\n const attempt = this.attempt();\n if (attempt.status === 'completed') {\n return { ok: false, error: 'completed', message: 'This attempt is already completed.' };\n }\n const size = JSON.stringify(payload.state ?? {}).length;\n if (size > 65536) {\n return { ok: false, error: 'validation', message: `State is ${size} bytes; the limit is 65536.` };\n }\n this.saveAttempt({ ...attempt, state: (payload.state as JsonObject) ?? null });\n\n return { ok: true };\n }\n\n private attemptSegment(payload: JsonObject): AckResult {\n const attempt = this.attempt();\n if (attempt.status === 'completed') {\n return { ok: false, error: 'completed' };\n }\n this.saveAttempt({ ...attempt, segment: (payload.segment as Record<string, string>) ?? null });\n\n return { ok: true };\n }\n\n private attemptComplete(payload: JsonObject): AckResult {\n const attempt = this.attempt();\n const completedAt = new Date().toISOString();\n if (attempt.status !== 'completed') {\n this.saveAttempt({ ...attempt, status: 'completed' });\n if (this.declares('activity')) {\n this.statement({ verb: 'completed', activity: { id: 'attempt', type: 'attempt' }, result: payload.summary ?? null, occurred_at: completedAt });\n }\n }\n\n return { ok: true, data: { status: 'completed', completed_at: completedAt } };\n }\n\n /** Clear a completed mock attempt so the experience can be run again. */\n public resetAttempt(): void {\n this.store.remove(this.key('attempt'));\n }\n\n // ---------------------------------------------------------------- activity\n\n private statement(payload: JsonObject): AckResult<{ id: string }> {\n const verb = String(payload.verb ?? '');\n if (!/^[a-z][a-z0-9_.:-]*$/.test(verb) || verb.length > 100) {\n return { ok: false, error: 'validation', message: `Invalid verb [${verb}].` };\n }\n const activity = payload.activity as { id?: string } | undefined;\n if (!activity?.id) {\n return { ok: false, error: 'validation', message: 'activity.id is required.' };\n }\n const id = `mock-${Date.now().toString(36)}-${this.statements.length + 1}`;\n this.statements.push({ id, ...payload });\n\n return { ok: true, data: { id } };\n }\n\n // ---------------------------------------------------------------- db\n\n private collectionKey(name: string): string {\n return this.key('db', name);\n }\n\n public records(collection: string): RecordRow[] {\n return this.store.get<RecordRow[]>(this.collectionKey(collection)) ?? [];\n }\n\n private saveRecords(collection: string, records: RecordRow[]): void {\n this.store.set(this.collectionKey(collection), records);\n }\n\n private collectionDeclared(name: string): AckResult | null {\n if (this.manifest && !(this.manifest.collections ?? []).some((c) => c.name === name)) {\n return { ok: false, error: 'not_found', message: `Collection [${name}] is not declared in the manifest.` };\n }\n const scope = (this.manifest?.collections ?? []).find((c) => c.name === name)?.scope;\n if (scope === 'attempt' && this.attempt().status === 'completed') {\n return { ok: false, error: 'completed', message: 'Attempt-scoped records are frozen after completion.' };\n }\n\n return null;\n }\n\n private dbCreate(payload: JsonObject): AckResult {\n const name = String(payload.collection);\n const declared = this.collectionDeclared(name);\n if (declared) {\n return declared;\n }\n const now = new Date().toISOString();\n const record: RecordRow = {\n id: `rec-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`,\n data: (payload.data as JsonObject) ?? {},\n owner_id: this.participantId,\n created_at: now,\n updated_at: now,\n };\n this.saveRecords(name, [...this.records(name), record]);\n\n return { ok: true, data: { record } };\n }\n\n private dbGet(payload: JsonObject): AckResult {\n const record = this.records(String(payload.collection)).find((r) => r.id === payload.id);\n\n return record ? { ok: true, data: { record } } : { ok: false, error: 'not_found' };\n }\n\n private dbUpdate(payload: JsonObject): AckResult {\n const name = String(payload.collection);\n const frozen = this.collectionDeclared(name);\n if (frozen && frozen.error === 'completed') {\n return frozen;\n }\n const records = this.records(name);\n const index = records.findIndex((r) => r.id === payload.id);\n if (index === -1) {\n return { ok: false, error: 'not_found' };\n }\n const merge = payload.merge !== false;\n const data = (payload.data as JsonObject) ?? {};\n records[index] = { ...records[index], data: merge ? { ...records[index].data, ...data } : data, updated_at: new Date().toISOString() };\n this.saveRecords(name, records);\n\n return { ok: true, data: { record: records[index] } };\n }\n\n private dbDelete(payload: JsonObject): AckResult {\n const name = String(payload.collection);\n const records = this.records(name);\n if (!records.some((r) => r.id === payload.id)) {\n return { ok: false, error: 'not_found' };\n }\n this.saveRecords(name, records.filter((r) => r.id !== payload.id));\n\n return { ok: true, data: { id: payload.id } };\n }\n\n private filter(records: RecordRow[], where: WhereClause[] | undefined): RecordRow[] {\n if (!where) {\n return records;\n }\n\n return records.filter((record) => where.every(([path, op, value]) => {\n const actual = path.split('.').reduce<unknown>((acc, part) => (acc as JsonObject | undefined)?.[part], record.data);\n switch (op) {\n case '=': return actual === value;\n case '!=': return actual !== value;\n case '<': return (actual as number) < (value as number);\n case '<=': return (actual as number) <= (value as number);\n case '>': return (actual as number) > (value as number);\n case '>=': return (actual as number) >= (value as number);\n case 'in': return Array.isArray(value) && value.includes(actual);\n default: return false;\n }\n }));\n }\n\n private dbList(payload: JsonObject): AckResult {\n const name = String(payload.collection);\n if (this.manifest && !(this.manifest.collections ?? []).some((c) => c.name === name)) {\n return { ok: false, error: 'not_found', message: `Collection [${name}] is not declared in the manifest.` };\n }\n let records = this.filter(this.records(name), payload.where as WhereClause[] | undefined);\n if (typeof payload.orderBy === 'string') {\n const path = payload.orderBy;\n const dir = payload.direction === 'desc' ? -1 : 1;\n records = [...records].sort((a, b) => {\n const av = path.split('.').reduce<unknown>((acc, p) => (acc as JsonObject | undefined)?.[p], a.data) as number | string;\n const bv = path.split('.').reduce<unknown>((acc, p) => (acc as JsonObject | undefined)?.[p], b.data) as number | string;\n\n return av < bv ? -dir : av > bv ? dir : 0;\n });\n }\n const limit = Math.min(Number(payload.limit ?? 50), 100);\n const offset = payload.cursor ? Number(payload.cursor) : 0;\n const page = records.slice(offset, offset + limit);\n const nextCursor = offset + limit < records.length ? String(offset + limit) : null;\n\n return { ok: true, data: { records: page, nextCursor } };\n }\n\n private dbCount(payload: JsonObject): AckResult {\n return { ok: true, data: { count: this.filter(this.records(String(payload.collection)), payload.where as WhereClause[] | undefined).length } };\n }\n\n // ---------------------------------------------------------------- storage\n\n public files(): StoredFile[] {\n return this.store.get<StoredFile[]>(this.key('files')) ?? [];\n }\n\n private storagePut(payload: JsonObject): AckResult {\n const upload = String(payload.upload);\n const slot = (this.manifest?.uploads ?? []).find((u) => u.name === upload);\n if (this.manifest && !slot) {\n return { ok: false, error: 'not_found', message: `Upload [${upload}] is not declared in the manifest.` };\n }\n const mime = String(payload.mime ?? '');\n if (slot?.mime && slot.mime.length > 0 && !slot.mime.some((m) => m === mime || (m.endsWith('/*') && mime.startsWith(m.slice(0, -1))))) {\n return { ok: false, error: 'validation', message: `MIME type [${mime}] is not allowed for upload [${upload}].` };\n }\n const bytes = Number(payload.bytes ?? 0);\n if (slot?.max_bytes && bytes > slot.max_bytes) {\n return { ok: false, error: 'quota_exceeded', message: `File is ${bytes} bytes; the limit is ${slot.max_bytes}.` };\n }\n const file: StoredFile = {\n id: `file-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`,\n upload,\n name: String(payload.name ?? 'blob'),\n mime,\n bytes,\n status: 'clean',\n created_at: new Date().toISOString(),\n };\n const blob = payload.file;\n if (typeof URL !== 'undefined' && typeof URL.createObjectURL === 'function' && blob instanceof Blob) {\n this.blobs.set(file.id, URL.createObjectURL(blob));\n }\n this.store.set(this.key('files'), [...this.files(), file]);\n\n return { ok: true, data: { file } };\n }\n\n private storageUrl(payload: JsonObject): AckResult {\n const file = this.files().find((f) => f.id === payload.id);\n if (!file) {\n return { ok: false, error: 'not_found' };\n }\n\n return { ok: true, data: { url: this.blobs.get(file.id) ?? `mock://files/${file.id}`, expires_at: new Date(Date.now() + 600_000).toISOString() } };\n }\n\n private storageList(payload: JsonObject): AckResult {\n const files = this.files().filter((f) => !payload.upload || f.upload === payload.upload);\n\n return { ok: true, data: { files } };\n }\n\n private storageDelete(payload: JsonObject): AckResult {\n this.store.set(this.key('files'), this.files().filter((f) => f.id !== payload.id));\n\n return { ok: true, data: { id: payload.id } };\n }\n\n // ---------------------------------------------------------------- ai\n\n private prompt(id: string): { id: string; mode: 'analysis' | 'chat'; output_schema?: JsonObject; knowledge?: Array<{ slot: string }> } | null {\n return (this.manifest?.prompts ?? []).find((p) => p.id === id) ?? (this.manifest ? null : { id, mode: 'analysis' });\n }\n\n private async aiAsk(payload: JsonObject): Promise<AckResult> {\n const prompt = this.prompt(String(payload.prompt));\n if (!prompt) {\n return { ok: false, error: 'not_found', message: `Prompt [${payload.prompt}] is not declared in the manifest.` };\n }\n const handler = this.aiHandlers.get(prompt.id);\n const vars = (payload.vars as JsonObject) ?? {};\n const output = handler ? await handler(vars, 'analysis') : stubFromSchema(prompt.output_schema, vars);\n\n // The mock has no knowledge base: a grounded prompt answers with no citations.\n const citations = prompt.knowledge?.length ? { citations: [] } : {};\n\n return { ok: true, data: { output, usage: { input_tokens: 42, output_tokens: 17 }, ...citations } };\n }\n\n private async aiChat(payload: JsonObject): Promise<MockOutcome> {\n const prompt = this.prompt(String(payload.prompt));\n if (!prompt) {\n return { ok: false, error: 'not_found', message: `Prompt [${payload.prompt}] is not declared in the manifest.` };\n }\n const message = String(payload.message ?? '');\n const history = this.chatHistory.get(prompt.id) ?? [];\n history.push({ role: 'user', content: message });\n const handler = this.aiHandlers.get(prompt.id);\n const reply = handler ? String(await handler({ ...((payload.vars as JsonObject) ?? {}), history }, 'chat', message)) : `[mock ${prompt.id}] You said: ${message}`;\n history.push({ role: 'assistant', content: reply });\n this.chatHistory.set(prompt.id, history);\n\n const words = reply.split(' ');\n const messageId = `msg-${Date.now().toString(36)}`;\n\n return {\n stream: (async function* () {\n for (let i = 0; i < words.length; i++) {\n yield { delta: (i === 0 ? '' : ' ') + words[i] };\n }\n })(),\n final: () => ({ message_id: messageId, text: reply, usage: { input_tokens: message.length, output_tokens: reply.length }, ...(prompt.knowledge?.length ? { citations: [] } : {}) }),\n };\n }\n\n // ---------------------------------------------------------------- broadcast (BroadcastChannel across tabs)\n\n private member(): RoomMember & { joinedAt: number } {\n return { id: this.participantId, name: this.participantName, role: this.role, present: true, joinedAt: this.joinedAt };\n }\n\n public members(): RoomMember[] {\n const now = Date.now();\n const others = [...this.roomMembers.values()].filter((m) => now - m.lastSeen < 15_000).map(({ lastSeen: _l, joinedAt: _j, ...m }) => m);\n const { joinedAt: _joined, ...self } = this.member();\n\n return [self, ...others].sort((a, b) => a.id - b.id);\n }\n\n private stateSnapshot(keys?: string[]): JsonObject {\n const snapshot: JsonObject = {};\n for (const [key, entry] of Object.entries(this.roomState)) {\n if (!keys || keys.includes(key)) {\n snapshot[key] = entry.value;\n }\n }\n\n return snapshot;\n }\n\n private send(message: JsonObject): void {\n this.channel?.postMessage({ ...message, sender: this.participantId });\n }\n\n private joinRoom(): void {\n if (this.channel) {\n return;\n }\n const mode = this.manifest?.broadcast?.mock_mode ?? 'first_in';\n // Optimistic first_in: this tab takes the role until an earlier facilitator answers.\n this.role = this.options.role ?? (mode === 'first_in' ? 'facilitator' : 'participant');\n\n if (typeof BroadcastChannel === 'undefined') {\n return;\n }\n this.channel = new BroadcastChannel(this.key('room'));\n this.channel.onmessage = (event: MessageEvent<JsonObject>) => this.onRoomMessage(event.data);\n this.send({ t: 'hello', from: this.member() });\n this.heartbeat = setInterval(() => this.send({ t: 'here', from: this.member() }), 5000);\n }\n\n /** An earlier facilitator wins; a later optimistic one steps down. */\n private reconcileFacilitator(from: RoomMember & { joinedAt?: number }): void {\n if (from.role === 'facilitator' && this.role === 'facilitator' && (from.joinedAt ?? 0) < this.joinedAt) {\n this.role = 'participant';\n this.pushEvent({ channel: '$room', event: 'role', payload: { role: 'participant', participant_id: this.participantId } });\n }\n }\n\n private onRoomMessage(data: JsonObject): void {\n const from = data.from as (RoomMember & { joinedAt?: number }) | undefined;\n if (data.sender === this.participantId) {\n return;\n }\n switch (data.t) {\n case 'hello':\n if (from) {\n this.roomMembers.set(from.id, { ...from, lastSeen: Date.now() });\n this.reconcileFacilitator(from);\n this.send({ t: 'here', from: this.member() });\n this.send({ t: 'state-sync', state: this.roomState });\n this.pushEvent({ channel: '$room', event: 'presence', payload: { members: this.members() } });\n }\n break;\n case 'here':\n if (from) {\n const known = this.roomMembers.has(from.id);\n this.roomMembers.set(from.id, { ...from, lastSeen: Date.now() });\n this.reconcileFacilitator(from);\n if (!known) {\n this.pushEvent({ channel: '$room', event: 'presence', payload: { members: this.members() } });\n }\n }\n break;\n case 'bye':\n if (from) {\n this.roomMembers.delete(from.id);\n this.pushEvent({ channel: '$room', event: 'presence', payload: { members: this.members() } });\n }\n break;\n case 'event':\n this.pushEvent({ channel: String(data.channel), event: String(data.event), payload: data.payload, from: { participant_id: Number(data.sender), role: (from?.role ?? 'participant') as RoomRole } });\n break;\n case 'state': {\n const key = String(data.key);\n const version = Number(data.version);\n if ((this.roomState[key]?.version ?? 0) <= version) {\n this.roomState[key] = { value: data.value, version };\n this.pushEvent({ channel: '$room', event: 'state', payload: { key, value: data.value, version } });\n }\n break;\n }\n case 'state-sync':\n for (const [key, entry] of Object.entries(data.state as Record<string, { value: unknown; version: number }>)) {\n if ((this.roomState[key]?.version ?? 0) < entry.version) {\n this.roomState[key] = entry;\n }\n }\n break;\n case 'role':\n if (from) {\n this.roomMembers.set(from.id, { ...from, lastSeen: Date.now() });\n if (from.role === 'facilitator' && this.role === 'facilitator') {\n this.role = 'participant';\n this.pushEvent({ channel: '$room', event: 'role', payload: { role: 'participant', participant_id: this.participantId } });\n }\n this.pushEvent({ channel: '$room', event: 'role', payload: { role: from.role, participant_id: from.id } });\n this.pushEvent({ channel: '$room', event: 'presence', payload: { members: this.members() } });\n }\n break;\n default:\n break;\n }\n }\n\n /**\n * A mock room is two tabs of the dev server, so the invite is this page:\n * scan it and the second tab joins over BroadcastChannel, exactly as the\n * real join URL would.\n */\n private invite(): AckResult {\n const url = typeof location === 'undefined' ? 'https://rack.test/r/MOCK01' : location.origin + location.pathname;\n\n return { ok: true, data: { code: 'MOCK01', url } };\n }\n\n private setRole(role: RoomRole): void {\n this.role = role;\n this.send({ t: 'role', from: this.member() });\n this.pushEvent({ channel: '$room', event: 'role', payload: { role, participant_id: this.participantId } });\n }\n\n private publish(payload: JsonObject): AckResult {\n const event = String(payload.event);\n const facilitatorOnly = this.manifest?.broadcast?.facilitator_events ?? [];\n if (facilitatorOnly.includes(event) && this.role !== 'facilitator') {\n return { ok: false, error: 'forbidden', message: `Event [${event}] may only be sent by the facilitator.` };\n }\n const from = { participant_id: this.participantId, role: this.role };\n this.send({ t: 'event', channel: payload.channel, event, payload: payload.payload, from: this.member() });\n this.pushEvent({ channel: String(payload.channel ?? 'main'), event, payload: payload.payload, from });\n\n return { ok: true };\n }\n\n private stateSet(payload: JsonObject): AckResult {\n const key = String(payload.key);\n const version = (this.roomState[key]?.version ?? 0) + 1;\n this.roomState[key] = { value: payload.value, version };\n this.send({ t: 'state', key, value: payload.value, version });\n this.pushEvent({ channel: '$room', event: 'state', payload: { key, value: payload.value, version } });\n\n return { ok: true, data: { version } };\n }\n\n private claim(): AckResult {\n this.setRole('facilitator');\n\n return { ok: true, data: { role: 'facilitator' } };\n }\n\n private transfer(payload: JsonObject): AckResult {\n if (this.role !== 'facilitator') {\n return { ok: false, error: 'forbidden', message: 'Only the facilitator can transfer the role.' };\n }\n const target = this.roomMembers.get(Number(payload.to));\n if (!target) {\n return { ok: false, error: 'not_found' };\n }\n this.role = 'participant';\n target.role = 'facilitator';\n this.send({ t: 'role', from: { ...target } });\n this.pushEvent({ channel: '$room', event: 'role', payload: { role: 'participant', participant_id: this.participantId } });\n this.pushEvent({ channel: '$room', event: 'role', payload: { role: 'facilitator', participant_id: target.id } });\n\n return { ok: true };\n }\n}\n\n/** A plausible object for an analysis prompt's output_schema, so UIs render in mock mode. */\nexport function stubFromSchema(schema: JsonObject | undefined, vars: JsonObject): unknown {\n if (!schema) {\n return { summary: `Mock analysis of ${JSON.stringify(vars).slice(0, 60)}` };\n }\n const type = schema.type;\n if (type === 'object') {\n const out: JsonObject = {};\n for (const [key, prop] of Object.entries((schema.properties as Record<string, JsonObject>) ?? {})) {\n out[key] = stubFromSchema(prop, vars);\n }\n\n return out;\n }\n if (type === 'array') {\n return [stubFromSchema(schema.items as JsonObject, vars)];\n }\n if (type === 'number' || type === 'integer') {\n return typeof schema.minimum === 'number' ? schema.minimum : 3;\n }\n if (type === 'boolean') {\n return true;\n }\n if (Array.isArray(schema.enum)) {\n return schema.enum[0];\n }\n\n return 'mock';\n}\n","import type { AckResult, JsonObject, RackEvent, SendOptions, Transport } from '../types';\nimport type { MockRack } from './MockRack';\n\n/**\n * Transport that fulfils every message locally through a MockRack.\n */\nexport class MockTransport implements Transport {\n public readonly kind = 'mock' as const;\n\n public constructor(public readonly rack: MockRack) {}\n\n public async send<T = JsonObject>(type: string, payload: unknown, options: SendOptions = {}): Promise<AckResult<T>> {\n const outcome = await this.rack.handle(type, (payload as JsonObject) ?? {});\n\n if ('stream' in outcome) {\n for await (const chunk of outcome.stream) {\n options.onPartial?.(chunk);\n }\n\n return { ok: true, data: outcome.final() as T };\n }\n\n return outcome as AckResult<T>;\n }\n\n public fire(type: string, payload: unknown = {}): void {\n void this.rack.handle(type, (payload as JsonObject) ?? {});\n }\n\n public onEvent(listener: (event: RackEvent) => void): () => void {\n return this.rack.onEvent(listener);\n }\n\n public dispose(): void {\n this.rack.dispose();\n }\n}\n","/**\n * Key/value persistence for the mock Rack. localStorage in the browser so a\n * standalone session survives a refresh; memory in tests.\n */\nexport interface Store {\n get<T>(key: string): T | null;\n set(key: string, value: unknown): void;\n remove(key: string): void;\n keys(prefix: string): string[];\n}\n\nexport class MemoryStore implements Store {\n private readonly data = new Map<string, string>();\n\n public get<T>(key: string): T | null {\n const raw = this.data.get(key);\n\n return raw === undefined ? null : (JSON.parse(raw) as T);\n }\n\n public set(key: string, value: unknown): void {\n this.data.set(key, JSON.stringify(value));\n }\n\n public remove(key: string): void {\n this.data.delete(key);\n }\n\n public keys(prefix: string): string[] {\n return [...this.data.keys()].filter((k) => k.startsWith(prefix));\n }\n}\n\nexport class LocalStore implements Store {\n public get<T>(key: string): T | null {\n try {\n const raw = window.localStorage.getItem(key);\n\n return raw === null ? null : (JSON.parse(raw) as T);\n } catch {\n return null;\n }\n }\n\n public set(key: string, value: unknown): void {\n try {\n window.localStorage.setItem(key, JSON.stringify(value));\n } catch {\n // Storage may be unavailable; mock mode tolerates that silently.\n }\n }\n\n public remove(key: string): void {\n try {\n window.localStorage.removeItem(key);\n } catch {\n // ignore\n }\n }\n\n public keys(prefix: string): string[] {\n try {\n const keys: string[] = [];\n for (let i = 0; i < window.localStorage.length; i++) {\n const key = window.localStorage.key(i);\n if (key && key.startsWith(prefix)) {\n keys.push(key);\n }\n }\n\n return keys;\n } catch {\n return [];\n }\n }\n}\n"],"names":["PROTOCOL_NAMESPACE","PROTOCOL_VERSION","FORMAT","requestCounter","newRequestId","cryptoRef","createEnvelope","type","payload","requestId","envelope","isEnvelope","data","candidate","capabilityOf","index","MockRack","manifest","store","options","parts","capability","ref","listener","event","l","nameHint","m","launch","item","user","attribute","a","b","c","u","p","k","guest","granted","role","promptId","handler","attempt","size","completedAt","verb","id","name","collection","records","declared","now","record","r","frozen","merge","where","path","op","value","actual","acc","part","dir","av","bv","limit","offset","page","nextCursor","upload","slot","mime","bytes","file","blob","f","prompt","vars","output","stubFromSchema","citations","message","history","reply","words","messageId","i","others","_l","_j","_joined","self","keys","snapshot","key","entry","mode","from","known","version","target","schema","out","prop","MockTransport","rack","outcome","chunk","MemoryStore","raw","prefix","LocalStore"],"mappings":"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"}
package/dist/testing.js CHANGED
@@ -1,4 +1,4 @@
1
- import { b as s, e, M as a } from "./store-BXGon4iJ.js";
1
+ import { b as s, e, M as a } from "./store-BHnO2KB3.js";
2
2
  class i {
3
3
  constructor(t = null, r = {}) {
4
4
  this.rack = new s(t, new e(), { participantId: 1, participantName: "Test User", ...r });
@@ -1,2 +1,2 @@
1
- var ZipRackSdk=(function(u){"use strict";class R{constructor(t){this.link=t}activities(){return this.link.launch()?.activity?.activities??[]}activity(t){return this.activities().find(e=>e.id===t)??null}statement(t){return this.link.send("activity:statement",{...t,occurred_at:t.occurred_at??new Date().toISOString()})}answer(t,e,s={}){return this.statement({verb:"answered",activity:{id:t,type:s.type??this.activity(t)?.type},result:{response:e},context:s.context})}progress(t,e){return this.statement({verb:"progressed",activity:{id:t,type:"step"},context:e})}}class E{constructor(t,e){this.link=t,this.promptId=e}async send(t,e){let s="";const r=await this.link.send("ai:chat",{prompt:this.promptId,message:t},{timeoutMs:6e4,onPartial:i=>{const a=typeof i.delta=="string"?i.delta:"";s+=a,e?.(a,s)}});return r.ok?{ok:!0,data:{message_id:String(r.data?.message_id??""),text:r.data?.text??s,usage:r.data?.usage??{input_tokens:0,output_tokens:0}}}:r}reset(){return this.link.send("ai:chat.reset",{prompt:this.promptId})}}class I{constructor(t){this.link=t}prompts(){return this.link.launch()?.ai?.prompts??[]}ask(t,e={}){return this.link.send("ai:ask",{prompt:t,vars:e},{timeoutMs:6e4})}chat(t){return new E(this.link,t)}}class L{constructor(t){this.link=t,this.local={}}current(){const t=this.link.launch()?.attempt;return t?{...t,...this.local}:null}get status(){return this.current()?.status??null}get id(){return this.current()?.id??null}state(){return this.current()?.state??null}segment(){return this.current()?.segment??null}setState(t){return this.local.state=t,this.link.send("attempt:state",{state:t})}setSegment(t){return this.local.segment=t,this.link.send("attempt:segment",{segment:t})}async complete(t){const e=await this.link.send("attempt:complete",{summary:t??null});return e.ok&&(this.local.status="completed"),e}}class O{constructor(t){this.link=t}user(){return this.link.launch()?.auth?.user??null}attribute(t,e=null){const s=this.user();return!s||!(t in s)?e:s[t]}}const j="$room";class T{constructor(t,e){this.link=t,this.name=e,this.listeners=new Map,this.unsubscribe=null}attach(){this.unsubscribe??=this.link.onEvent(t=>{t.channel===this.name&&(this.listeners.get(t.event)?.forEach(e=>e(t.payload,t.from)),this.listeners.get("*")?.forEach(e=>e({event:t.event,payload:t.payload},t.from)))})}listen(t,e){const s=this.listeners.get(t)??new Set;return s.add(e),this.listeners.set(t,s),()=>{s.delete(e)}}publish(t,e={}){return this.link.send("broadcast:publish",{channel:this.name,event:t,payload:e})}async leave(){return this.unsubscribe?.(),this.unsubscribe=null,this.listeners.clear(),this.link.send("broadcast:leave",{channel:this.name})}}class C{constructor(t){this.link=t,this.channels=new Map,this.roomListeners=new Map,this.localRole=null,this.localMembers=null,this.localState=null,this.detach=null,this.state={get:async e=>{const s=await this.link.send("broadcast:state.get",e?{keys:e}:{});return s.ok&&s.data&&(this.localState={...this.localState??{},...s.data.state}),s},set:(e,s)=>(this.localState={...this.localState??this.launch()?.state??{},[e]:s},this.link.send("broadcast:state.set",{key:e,value:s})),snapshot:()=>this.localState??this.launch()?.state??{}}}get room(){return this.launch()?.room??null}get role(){return this.localRole??this.launch()?.role??null}get isFacilitator(){return this.role==="facilitator"}members(){return this.localMembers??this.launch()?.members??[]}async join(t="main"){this.ensureRoomListener();let e=this.channels.get(t);return e||(e=new T(this.link,t),this.channels.set(t,e)),e.attach(),await this.link.send("broadcast:join",{channel:t}),e}async presence(){const t=await this.link.send("broadcast:presence",{});return t.ok&&t.data&&(this.localMembers=t.data.members),t}invite(){return this.link.send("broadcast:invite",{})}claim(){return this.link.send("broadcast:claim",{})}transfer(t){return this.link.send("broadcast:transfer",{to:t})}on(t,e){this.ensureRoomListener();const s=this.roomListeners.get(t)??new Set;return s.add(e),this.roomListeners.set(t,s),()=>{s.delete(e)}}launch(){return this.link.launch()?.broadcast??null}ensureRoomListener(){this.detach??=this.link.onEvent(t=>{if(t.channel!==j)return;const e=t.payload;t.event==="presence"&&Array.isArray(e.members)&&(this.localMembers=e.members),t.event==="state"&&typeof e.key=="string"&&(this.localState={...this.localState??this.launch()?.state??{},[e.key]:e.value}),t.event==="role"&&e.participant_id===this.link.launch()?.actor.id&&(this.localRole=e.role),this.roomListeners.get(t.event)?.forEach(s=>s(e))})}}function w(n){return{ok:!1,error:"undeclared_capability",message:`The manifest does not declare the [${n}] capability.`}}class q{constructor(t,e){this.link=t,this.name=e}create(t){return this.send("db:create",{data:t})}get(t){return this.send("db:get",{id:t})}update(t,e,s={}){return this.send("db:update",{id:t,data:e,merge:s.merge??!0})}delete(t){return this.send("db:delete",{id:t})}list(t={}){return this.send("db:list",t)}count(t={}){return this.send("db:count",t)}send(t,e){return this.link.launch()&&!this.link.declares("db")?Promise.resolve(w("db")):this.link.send(t,{collection:this.name,...e})}}class U{constructor(t){this.link=t}collection(t){return new q(this.link,t)}collections(){return this.link.launch()?.db?.collections??[]}}class P{constructor(t){this.link=t}get(t){return this.link.launch()?.media?.[t]??null}embedUrl(t){return this.get(t)?.embedUrl??null}all(){return this.link.launch()?.media??{}}}class N{constructor(t){this.link=t}uploads(){return this.link.launch()?.storage?.uploads??[]}put(t,e,s={}){const r=e instanceof File?e.name:"blob";return this.link.send("storage:put",{upload:t,file:e,name:r,mime:e.type,bytes:e.size,meta:s},{timeoutMs:12e4})}url(t){return this.link.send("storage:url",{id:t})}list(t){return this.link.send("storage:list",t?{upload:t}:{})}delete(t){return this.link.send("storage:delete",{id:t})}}const y="ziprack",S=1;let _=0;function x(){const n=typeof globalThis.crypto<"u"?globalThis.crypto:void 0;return n&&typeof n.randomUUID=="function"?n.randomUUID():(_+=1,`req-${Date.now().toString(36)}-${_.toString(36)}`)}function M(n,t,e){const s={ns:y,v:S,type:n,payload:t};return e!==void 0&&(s.requestId=e),s}function z(n){if(typeof n!="object"||n===null)return!1;const t=n;return t.ns===y&&t.v===S&&typeof t.type=="string"}function p(n){const t=n.indexOf(":");return t===-1?n:n.slice(0,t)}class H{constructor(t){this.options=t,this.kind="host",this.pending=new Map,this.eventListeners=new Set,this.launchResolvers=[],this.launchData=null,this.listener=e=>this.onMessage(e),this.target=t.target??window.parent,this.isHost=t.isHost??(e=>e===window.parent),this.listenOn=t.listenOn??window,this.listenOn.addEventListener("message",this.listener)}announceReady(){this.fire("rack:ready",{})}waitForLaunch(t){return this.launchData?Promise.resolve(this.launchData):new Promise(e=>{const s=setTimeout(()=>{this.launchResolvers=this.launchResolvers.filter(i=>i!==r),e(null)},t),r=i=>{clearTimeout(s),e(i)};this.launchResolvers.push(r)})}send(t,e,s={}){const r=x(),i=s.timeoutMs??this.options.ackTimeoutMs;return new Promise(a=>{const o={resolve:a,timer:setTimeout(()=>this.expire(r),i),timeoutMs:i,onPartial:s.onPartial};this.pending.set(r,o),this.post(M(t,e,r))})}fire(t,e={}){this.post(M(t,e))}onEvent(t){return this.eventListeners.add(t),()=>{this.eventListeners.delete(t)}}dispose(){this.listenOn.removeEventListener("message",this.listener);for(const[t,e]of this.pending)clearTimeout(e.timer),e.resolve({ok:!1,error:"disposed"}),this.pending.delete(t)}expire(t){const e=this.pending.get(t);e&&(this.pending.delete(t),e.resolve({ok:!1,error:"timeout"}))}post(t){this.target.postMessage(t,"*")}onMessage(t){if(!this.isHost(t.source)||!z(t.data))return;const e=t.data;if(e.type==="rack:launch"){this.launchData=e.payload;const s=this.launchResolvers;this.launchResolvers=[],s.forEach(r=>r(this.launchData));return}if(e.type==="rack:event"){const s=e.payload;this.eventListeners.forEach(r=>r(s));return}e.type==="rack:ack"&&this.onAck(e.payload)}onAck(t){const e=this.pending.get(t.requestId);if(!e)return;if(!t.done&&t.data?.stream===!0){clearTimeout(e.timer),e.timer=setTimeout(()=>this.expire(t.requestId),e.timeoutMs);return}if(t.partial&&!t.done){const{requestId:b,ok:v,partial:m,...h}=t;e.onPartial?.(h),clearTimeout(e.timer),e.timer=setTimeout(()=>this.expire(t.requestId),e.timeoutMs);return}clearTimeout(e.timer),this.pending.delete(t.requestId);const{requestId:s,ok:r,data:i,error:a,message:o,details:c,partial:l,done:D,...d}=t;e.resolve({ok:r,data:i??(Object.keys(d).length?d:void 0),error:a,message:o,details:c})}}class F{constructor(t,e,s={}){this.manifest=t,this.store=e,this.options=s,this.statements=[],this.events=[],this.aiHandlers=new Map,this.chatHistory=new Map,this.blobs=new Map,this.eventListeners=new Set,this.roomMembers=new Map,this.roomState={},this.role="participant",this.joinedAt=Date.now()+Math.random(),this.channel=null,this.heartbeat=null,this.participantId=s.participantId??Math.floor(Math.random()*1e6)+1,this.participantName=s.participantName??"Dev User"}get slug(){return this.manifest?.slug??"applet"}key(...t){return`ziprack-mock:${this.slug}:${t.join(":")}`}declares(t){return this.manifest?(this.manifest.requires?.capabilities??[]).some(e=>e.split("@")[0]===t):!0}onEvent(t){return this.eventListeners.add(t),()=>{this.eventListeners.delete(t)}}pushEvent(t){this.events.push(t),this.eventListeners.forEach(e=>e(t))}launchData(t){const e=this.manifest,s={schema:"ziprack/1",actor:{id:this.participantId,name:this.participantName},applet:{slug:this.slug,name:`${e?.name??t??"Applet"} (mock)`,version:e?.version??"dev"},capabilities:e?.requires?.capabilities??[],media:Object.fromEntries((e?.media??[]).map(r=>[r.id,{provider:r.provider,embedUrl:r.provider==="vimeo"?`https://player.vimeo.com/video/${r.key}?dnt=1`:`https://www.youtube-nocookie.com/embed/${r.key}?rel=0`,meta:null}]))};if(this.declares("auth")){const r={user:{id:this.participantId,display_name:this.participantName}};for(const i of e?.requires?.profile??[])r.user[i]=r.user[i]??`mock-${i}`;s.auth=r}return this.declares("attempt")&&(s.attempt=this.attempt()),this.declares("activity")&&(s.activity={activities:[...e?.activities??[]].sort((r,i)=>(r.sequence??0)-(i.sequence??0))}),this.declares("db")&&(s.db={collections:(e?.collections??[]).map(r=>({name:r.name,scope:r.scope}))}),this.declares("storage")&&(s.storage={uploads:(e?.uploads??[]).map(r=>({name:r.name,scope:r.scope,mime:r.mime??[],max_bytes:r.max_bytes??10485760}))}),this.declares("ai")&&(s.ai={prompts:(e?.prompts??[]).map(r=>({id:r.id,mode:r.mode}))}),this.declares("broadcast")&&(this.joinRoom(),s.broadcast={room:{id:1,code:"MOCK01",name:`${this.slug} room`,status:"open",mode:e?.broadcast?.mock_mode??"first_in"},role:this.role,members:this.members(),state:this.stateSnapshot(),channels:e?.broadcast?.channels??["main"]}),s}mockAi(t,e){this.aiHandlers.set(t,e)}dispose(){this.heartbeat&&clearInterval(this.heartbeat),this.channel&&(this.send({t:"bye",from:this.member()}),this.channel.close())}async handle(t,e){if(this.options.log?.(t,e),t==="rack:eject")return{ok:!0};const s=p(t);if((this.options.strict??this.manifest!==null)&&!this.declares(s))return{ok:!1,error:"undeclared_capability",message:`The manifest does not declare the [${s}] capability.`};switch(t){case"attempt:state":return this.attemptState(e);case"attempt:segment":return this.attemptSegment(e);case"attempt:complete":return this.attemptComplete(e);case"activity:statement":return this.statement(e);case"db:create":return this.dbCreate(e);case"db:get":return this.dbGet(e);case"db:update":return this.dbUpdate(e);case"db:delete":return this.dbDelete(e);case"db:list":return this.dbList(e);case"db:count":return this.dbCount(e);case"storage:put":return this.storagePut(e);case"storage:url":return this.storageUrl(e);case"storage:list":return this.storageList(e);case"storage:delete":return this.storageDelete(e);case"ai:ask":return this.aiAsk(e);case"ai:chat":return this.aiChat(e);case"ai:chat.reset":return this.chatHistory.delete(String(e.prompt)),{ok:!0};case"broadcast:join":return{ok:!0,data:{members:this.members(),state:this.stateSnapshot()}};case"broadcast:leave":return{ok:!0};case"broadcast:publish":return this.publish(e);case"broadcast:state.get":return{ok:!0,data:{state:this.stateSnapshot(Array.isArray(e.keys)?e.keys:void 0)}};case"broadcast:state.set":return this.stateSet(e);case"broadcast:presence":return{ok:!0,data:{members:this.members()}};case"broadcast:invite":return this.invite();case"broadcast:claim":return this.claim();case"broadcast:transfer":return this.transfer(e);default:return{ok:!1,error:"unknown_type",message:`Unknown message type [${t}].`}}}attempt(){return this.store.get(this.key("attempt"))??{id:1,status:"in_progress",state:null,segment:null}}saveAttempt(t){this.store.set(this.key("attempt"),t)}attemptState(t){const e=this.attempt();if(e.status==="completed")return{ok:!1,error:"completed",message:"This attempt is already completed."};const s=JSON.stringify(t.state??{}).length;return s>65536?{ok:!1,error:"validation",message:`State is ${s} bytes; the limit is 65536.`}:(this.saveAttempt({...e,state:t.state??null}),{ok:!0})}attemptSegment(t){const e=this.attempt();return e.status==="completed"?{ok:!1,error:"completed"}:(this.saveAttempt({...e,segment:t.segment??null}),{ok:!0})}attemptComplete(t){const e=this.attempt(),s=new Date().toISOString();return e.status!=="completed"&&(this.saveAttempt({...e,status:"completed"}),this.declares("activity")&&this.statement({verb:"completed",activity:{id:"attempt",type:"attempt"},result:t.summary??null,occurred_at:s})),{ok:!0,data:{status:"completed",completed_at:s}}}resetAttempt(){this.store.remove(this.key("attempt"))}statement(t){const e=String(t.verb??"");if(!/^[a-z][a-z0-9_.:-]*$/.test(e)||e.length>100)return{ok:!1,error:"validation",message:`Invalid verb [${e}].`};if(!t.activity?.id)return{ok:!1,error:"validation",message:"activity.id is required."};const r=`mock-${Date.now().toString(36)}-${this.statements.length+1}`;return this.statements.push({id:r,...t}),{ok:!0,data:{id:r}}}collectionKey(t){return this.key("db",t)}records(t){return this.store.get(this.collectionKey(t))??[]}saveRecords(t,e){this.store.set(this.collectionKey(t),e)}collectionDeclared(t){return this.manifest&&!(this.manifest.collections??[]).some(s=>s.name===t)?{ok:!1,error:"not_found",message:`Collection [${t}] is not declared in the manifest.`}:(this.manifest?.collections??[]).find(s=>s.name===t)?.scope==="attempt"&&this.attempt().status==="completed"?{ok:!1,error:"completed",message:"Attempt-scoped records are frozen after completion."}:null}dbCreate(t){const e=String(t.collection),s=this.collectionDeclared(e);if(s)return s;const r=new Date().toISOString(),i={id:`rec-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,7)}`,data:t.data??{},owner_id:this.participantId,created_at:r,updated_at:r};return this.saveRecords(e,[...this.records(e),i]),{ok:!0,data:{record:i}}}dbGet(t){const e=this.records(String(t.collection)).find(s=>s.id===t.id);return e?{ok:!0,data:{record:e}}:{ok:!1,error:"not_found"}}dbUpdate(t){const e=String(t.collection),s=this.collectionDeclared(e);if(s&&s.error==="completed")return s;const r=this.records(e),i=r.findIndex(c=>c.id===t.id);if(i===-1)return{ok:!1,error:"not_found"};const a=t.merge!==!1,o=t.data??{};return r[i]={...r[i],data:a?{...r[i].data,...o}:o,updated_at:new Date().toISOString()},this.saveRecords(e,r),{ok:!0,data:{record:r[i]}}}dbDelete(t){const e=String(t.collection),s=this.records(e);return s.some(r=>r.id===t.id)?(this.saveRecords(e,s.filter(r=>r.id!==t.id)),{ok:!0,data:{id:t.id}}):{ok:!1,error:"not_found"}}filter(t,e){return e?t.filter(s=>e.every(([r,i,a])=>{const o=r.split(".").reduce((c,l)=>c?.[l],s.data);switch(i){case"=":return o===a;case"!=":return o!==a;case"<":return o<a;case"<=":return o<=a;case">":return o>a;case">=":return o>=a;case"in":return Array.isArray(a)&&a.includes(o);default:return!1}})):t}dbList(t){const e=String(t.collection);if(this.manifest&&!(this.manifest.collections??[]).some(c=>c.name===e))return{ok:!1,error:"not_found",message:`Collection [${e}] is not declared in the manifest.`};let s=this.filter(this.records(e),t.where);if(typeof t.orderBy=="string"){const c=t.orderBy,l=t.direction==="desc"?-1:1;s=[...s].sort((D,d)=>{const b=c.split(".").reduce((m,h)=>m?.[h],D.data),v=c.split(".").reduce((m,h)=>m?.[h],d.data);return b<v?-l:b>v?l:0})}const r=Math.min(Number(t.limit??50),100),i=t.cursor?Number(t.cursor):0,a=s.slice(i,i+r),o=i+r<s.length?String(i+r):null;return{ok:!0,data:{records:a,nextCursor:o}}}dbCount(t){return{ok:!0,data:{count:this.filter(this.records(String(t.collection)),t.where).length}}}files(){return this.store.get(this.key("files"))??[]}storagePut(t){const e=String(t.upload),s=(this.manifest?.uploads??[]).find(c=>c.name===e);if(this.manifest&&!s)return{ok:!1,error:"not_found",message:`Upload [${e}] is not declared in the manifest.`};const r=String(t.mime??"");if(s?.mime&&s.mime.length>0&&!s.mime.some(c=>c===r||c.endsWith("/*")&&r.startsWith(c.slice(0,-1))))return{ok:!1,error:"validation",message:`MIME type [${r}] is not allowed for upload [${e}].`};const i=Number(t.bytes??0);if(s?.max_bytes&&i>s.max_bytes)return{ok:!1,error:"quota_exceeded",message:`File is ${i} bytes; the limit is ${s.max_bytes}.`};const a={id:`file-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,7)}`,upload:e,name:String(t.name??"blob"),mime:r,bytes:i,status:"clean",created_at:new Date().toISOString()},o=t.file;return typeof URL<"u"&&typeof URL.createObjectURL=="function"&&o instanceof Blob&&this.blobs.set(a.id,URL.createObjectURL(o)),this.store.set(this.key("files"),[...this.files(),a]),{ok:!0,data:{file:a}}}storageUrl(t){const e=this.files().find(s=>s.id===t.id);return e?{ok:!0,data:{url:this.blobs.get(e.id)??`mock://files/${e.id}`,expires_at:new Date(Date.now()+6e5).toISOString()}}:{ok:!1,error:"not_found"}}storageList(t){return{ok:!0,data:{files:this.files().filter(s=>!t.upload||s.upload===t.upload)}}}storageDelete(t){return this.store.set(this.key("files"),this.files().filter(e=>e.id!==t.id)),{ok:!0,data:{id:t.id}}}prompt(t){return(this.manifest?.prompts??[]).find(e=>e.id===t)??(this.manifest?null:{id:t,mode:"analysis"})}async aiAsk(t){const e=this.prompt(String(t.prompt));if(!e)return{ok:!1,error:"not_found",message:`Prompt [${t.prompt}] is not declared in the manifest.`};const s=this.aiHandlers.get(e.id),r=t.vars??{};return{ok:!0,data:{output:s?await s(r,"analysis"):f(e.output_schema,r),usage:{input_tokens:42,output_tokens:17}}}}async aiChat(t){const e=this.prompt(String(t.prompt));if(!e)return{ok:!1,error:"not_found",message:`Prompt [${t.prompt}] is not declared in the manifest.`};const s=String(t.message??""),r=this.chatHistory.get(e.id)??[];r.push({role:"user",content:s});const i=this.aiHandlers.get(e.id),a=i?String(await i({history:r},"chat",s)):`[mock ${e.id}] You said: ${s}`;r.push({role:"assistant",content:a}),this.chatHistory.set(e.id,r);const o=a.split(" "),c=`msg-${Date.now().toString(36)}`;return{stream:(async function*(){for(let l=0;l<o.length;l++)yield{delta:(l===0?"":" ")+o[l]}})(),final:()=>({message_id:c,text:a,usage:{input_tokens:s.length,output_tokens:a.length}})}}member(){return{id:this.participantId,name:this.participantName,role:this.role,present:!0,joinedAt:this.joinedAt}}members(){const t=Date.now(),e=[...this.roomMembers.values()].filter(i=>t-i.lastSeen<15e3).map(({lastSeen:i,joinedAt:a,...o})=>o),{joinedAt:s,...r}=this.member();return[r,...e].sort((i,a)=>i.id-a.id)}stateSnapshot(t){const e={};for(const[s,r]of Object.entries(this.roomState))(!t||t.includes(s))&&(e[s]=r.value);return e}send(t){this.channel?.postMessage({...t,sender:this.participantId})}joinRoom(){if(this.channel)return;const t=this.manifest?.broadcast?.mock_mode??"first_in";this.role=this.options.role??(t==="first_in"?"facilitator":"participant"),!(typeof BroadcastChannel>"u")&&(this.channel=new BroadcastChannel(this.key("room")),this.channel.onmessage=e=>this.onRoomMessage(e.data),this.send({t:"hello",from:this.member()}),this.heartbeat=setInterval(()=>this.send({t:"here",from:this.member()}),5e3))}reconcileFacilitator(t){t.role==="facilitator"&&this.role==="facilitator"&&(t.joinedAt??0)<this.joinedAt&&(this.role="participant",this.pushEvent({channel:"$room",event:"role",payload:{role:"participant",participant_id:this.participantId}}))}onRoomMessage(t){const e=t.from;if(t.sender!==this.participantId)switch(t.t){case"hello":e&&(this.roomMembers.set(e.id,{...e,lastSeen:Date.now()}),this.reconcileFacilitator(e),this.send({t:"here",from:this.member()}),this.send({t:"state-sync",state:this.roomState}),this.pushEvent({channel:"$room",event:"presence",payload:{members:this.members()}}));break;case"here":if(e){const s=this.roomMembers.has(e.id);this.roomMembers.set(e.id,{...e,lastSeen:Date.now()}),this.reconcileFacilitator(e),s||this.pushEvent({channel:"$room",event:"presence",payload:{members:this.members()}})}break;case"bye":e&&(this.roomMembers.delete(e.id),this.pushEvent({channel:"$room",event:"presence",payload:{members:this.members()}}));break;case"event":this.pushEvent({channel:String(t.channel),event:String(t.event),payload:t.payload,from:{participant_id:Number(t.sender),role:e?.role??"participant"}});break;case"state":{const s=String(t.key),r=Number(t.version);(this.roomState[s]?.version??0)<=r&&(this.roomState[s]={value:t.value,version:r},this.pushEvent({channel:"$room",event:"state",payload:{key:s,value:t.value,version:r}}));break}case"state-sync":for(const[s,r]of Object.entries(t.state))(this.roomState[s]?.version??0)<r.version&&(this.roomState[s]=r);break;case"role":e&&(this.roomMembers.set(e.id,{...e,lastSeen:Date.now()}),e.role==="facilitator"&&this.role==="facilitator"&&(this.role="participant",this.pushEvent({channel:"$room",event:"role",payload:{role:"participant",participant_id:this.participantId}})),this.pushEvent({channel:"$room",event:"role",payload:{role:e.role,participant_id:e.id}}),this.pushEvent({channel:"$room",event:"presence",payload:{members:this.members()}}));break}}invite(){return{ok:!0,data:{code:"MOCK01",url:typeof location>"u"?"https://rack.test/r/MOCK01":location.origin+location.pathname}}}setRole(t){this.role=t,this.send({t:"role",from:this.member()}),this.pushEvent({channel:"$room",event:"role",payload:{role:t,participant_id:this.participantId}})}publish(t){const e=String(t.event);if((this.manifest?.broadcast?.facilitator_events??[]).includes(e)&&this.role!=="facilitator")return{ok:!1,error:"forbidden",message:`Event [${e}] may only be sent by the facilitator.`};const r={participant_id:this.participantId,role:this.role};return this.send({t:"event",channel:t.channel,event:e,payload:t.payload,from:this.member()}),this.pushEvent({channel:String(t.channel??"main"),event:e,payload:t.payload,from:r}),{ok:!0}}stateSet(t){const e=String(t.key),s=(this.roomState[e]?.version??0)+1;return this.roomState[e]={value:t.value,version:s},this.send({t:"state",key:e,value:t.value,version:s}),this.pushEvent({channel:"$room",event:"state",payload:{key:e,value:t.value,version:s}}),{ok:!0,data:{version:s}}}claim(){return this.setRole("facilitator"),{ok:!0,data:{role:"facilitator"}}}transfer(t){if(this.role!=="facilitator")return{ok:!1,error:"forbidden",message:"Only the facilitator can transfer the role."};const e=this.roomMembers.get(Number(t.to));return e?(this.role="participant",e.role="facilitator",this.send({t:"role",from:{...e}}),this.pushEvent({channel:"$room",event:"role",payload:{role:"participant",participant_id:this.participantId}}),this.pushEvent({channel:"$room",event:"role",payload:{role:"facilitator",participant_id:e.id}}),{ok:!0}):{ok:!1,error:"not_found"}}}function f(n,t){if(!n)return{summary:`Mock analysis of ${JSON.stringify(t).slice(0,60)}`};const e=n.type;if(e==="object"){const s={};for(const[r,i]of Object.entries(n.properties??{}))s[r]=f(i,t);return s}return e==="array"?[f(n.items,t)]:e==="number"||e==="integer"?typeof n.minimum=="number"?n.minimum:3:e==="boolean"?!0:Array.isArray(n.enum)?n.enum[0]:"mock"}class k{constructor(t){this.rack=t,this.kind="mock"}async send(t,e,s={}){const r=await this.rack.handle(t,e??{});if("stream"in r){for await(const i of r.stream)s.onPartial?.(i);return{ok:!0,data:r.final()}}return r}fire(t,e={}){this.rack.handle(t,e??{})}onEvent(t){return this.rack.onEvent(t)}dispose(){this.rack.dispose()}}class B{get(t){try{const e=window.localStorage.getItem(t);return e===null?null:JSON.parse(e)}catch{return null}}set(t,e){try{window.localStorage.setItem(t,JSON.stringify(e))}catch{}}remove(t){try{window.localStorage.removeItem(t)}catch{}}keys(t){try{const e=[];for(let s=0;s<window.localStorage.length;s++){const r=window.localStorage.key(s);r&&r.startsWith(t)&&e.push(r)}return e}catch{return[]}}}const K=3e3,J=5e3;class A{constructor(){this.transport=null,this.initPromise=null,this.launchData=null,this.queue=[],this.launchListeners=new Set,this.eventListeners=new Set,this.pendingAiMocks=[];const t={send:(e,s,r)=>this.send(e,s,r),fire:(e,s)=>this.fire(e,s),launch:()=>this.launchData,declares:e=>this.declares(e),onEvent:e=>this.on("event",e),mode:()=>this.mode};this.auth=new O(t),this.attempt=new L(t),this.activity=new R(t),this.db=new U(t),this.storage=new N(t),this.ai=new I(t),this.broadcast=new C(t),this.media=new P(t),this.mock={ai:(e,s)=>{const r=this.mockRack();r?r.mockAi(e,s):this.pendingAiMocks.push([e,s])},resetAttempt:()=>this.mockRack()?.resetAttempt(),rack:()=>this.mockRack()}}init(t={}){return this.initPromise??=this.performInit(t),this.initPromise}get launched(){return this.launchData!==null}get mode(){return this.transport?.kind??"pending"}getLaunchData(){return this.launchData}declares(t){return(this.launchData?.capabilities??[]).some(e=>e.split("@")[0]===t)}on(t,e){if(t==="launch"){const r=e;return this.launchListeners.add(r),this.launchData&&r(this.launchData),()=>{this.launchListeners.delete(r)}}const s=e;return this.eventListeners.add(s),()=>{this.eventListeners.delete(s)}}eject(){this.fire("rack:eject",{}),this.transport?.kind==="mock"&&console.info("[ziprack mock] eject: the Rack would navigate away now.")}send(t,e,s){return this.launchData&&!t.startsWith("rack:")&&!this.declares(p(t))?Promise.resolve(w(p(t))):this.transport?this.transport.send(t,e,s):new Promise(r=>{this.queue.push({type:t,payload:e,options:s,resolve:r})})}fire(t,e={}){if(this.transport){this.transport.fire(t,e);return}this.send(t,e)}dispose(){this.transport?.dispose(),this.transport=null,this.initPromise=null,this.launchData=null}async performInit(t){const e=t.ackTimeoutMs??J,s=t.launchTimeoutMs??K;if(t.transport){const o=t.launch??(t.transport instanceof k?t.transport.rack.launchData():null);if(!o)throw new Error("init({ transport }) needs `launch` data unless the transport is a MockTransport.");return this.activate(t.transport,o)}if(!(typeof window<"u"&&window.parent!==window))return this.activateMock(t,"not embedded in a Rack");const i=new H({ackTimeoutMs:e});i.announceReady();const a=await i.waitForLaunch(s);return a?this.activate(i,a):(i.dispose(),this.activateMock(t,`no rack:launch within ${s}ms`))}async activateMock(t,e){console.info(`[ziprack] running in mock mode (${e})`);const s=await W(t.manifestUrl??"./manifest.json",t.slug),r=new F(s,new B,{log:(i,a)=>console.info(`[ziprack mock] ${i}`,a)});for(const[i,a]of this.pendingAiMocks)r.mockAi(i,a);return this.pendingAiMocks=[],this.activate(new k(r),r.launchData(t.slug))}activate(t,e){return this.transport=t,this.launchData=e,t.onEvent(s=>this.eventListeners.forEach(r=>r(s))),this.launchListeners.forEach(s=>s(e)),this.flushQueue(),e}flushQueue(){if(this.transport)for(;this.queue.length>0;){const e=this.queue.shift();this.send(e.type,e.payload,e.options).then(e.resolve)}}mockRack(){return this.transport instanceof k?this.transport.rack:null}}async function W(n,t){if(typeof fetch!="function")return null;try{const e=await fetch(n,{cache:"no-store"});if(!e.ok)throw new Error(String(e.status));const s=await e.json();return t&&s.slug!==t&&console.warn(`[ziprack mock] manifest slug [${s.slug}] does not match init({ slug: '${t}' }).`),s}catch(e){return console.warn(`[ziprack mock] could not load ${n}; mock mode will accept every capability.`,e),null}}const g=new A;function $(){return new A}return window.Rack=g,window.ZipRack={Rack:g,createRack:$},u.Rack=g,u.createRack=$,Object.defineProperty(u,Symbol.toStringTag,{value:"Module"}),u})({});
1
+ var ZipRackSdk=(function(u){"use strict";class D{constructor(t){this.link=t}activities(){return this.link.launch()?.activity?.activities??[]}activity(t){return this.activities().find(e=>e.id===t)??null}statement(t){return this.link.send("activity:statement",{...t,occurred_at:t.occurred_at??new Date().toISOString()})}answer(t,e,s={}){return this.statement({verb:"answered",activity:{id:t,type:s.type??this.activity(t)?.type},result:{response:e},context:s.context})}progress(t,e){return this.statement({verb:"progressed",activity:{id:t,type:"step"},context:e})}}class E{constructor(t,e,s={}){this.link=t,this.promptId=e,this.vars=s}async send(t,e){let s="";const r=Object.keys(this.vars).length>0?{prompt:this.promptId,message:t,vars:this.vars}:{prompt:this.promptId,message:t},i=await this.link.send("ai:chat",r,{timeoutMs:6e4,onPartial:a=>{const o=typeof a.delta=="string"?a.delta:"";s+=o,e?.(o,s)}});return i.ok?{ok:!0,data:{message_id:String(i.data?.message_id??""),text:i.data?.text??s,usage:i.data?.usage??{input_tokens:0,output_tokens:0},...i.data?.citations?{citations:i.data.citations}:{}}}:i}reset(){return this.link.send("ai:chat.reset",{prompt:this.promptId})}}class I{constructor(t){this.link=t}prompts(){return this.link.launch()?.ai?.prompts??[]}knowledge(){return this.link.launch()?.ai?.knowledge??[]}ask(t,e={}){return this.link.send("ai:ask",{prompt:t,vars:e},{timeoutMs:6e4})}chat(t,e={}){return new E(this.link,t,e)}}class L{constructor(t){this.link=t,this.local={}}current(){const t=this.link.launch()?.attempt;return t?{...t,...this.local}:null}get status(){return this.current()?.status??null}get id(){return this.current()?.id??null}state(){return this.current()?.state??null}segment(){return this.current()?.segment??null}setState(t){return this.local.state=t,this.link.send("attempt:state",{state:t})}setSegment(t){return this.local.segment=t,this.link.send("attempt:segment",{segment:t})}async complete(t){const e=await this.link.send("attempt:complete",{summary:t??null});return e.ok&&(this.local.status="completed"),e}}class O{constructor(t){this.link=t}user(){return this.link.launch()?.auth?.user??null}attribute(t,e=null){const s=this.user();return!s||!(t in s)?e:s[t]}roles(){return this.link.launch()?.roles??[]}hasRole(t){return this.roles().includes(t)}isGuest(){return this.hasRole("guest")}}const j="$room";class T{constructor(t,e){this.link=t,this.name=e,this.listeners=new Map,this.unsubscribe=null}attach(){this.unsubscribe??=this.link.onEvent(t=>{t.channel===this.name&&(this.listeners.get(t.event)?.forEach(e=>e(t.payload,t.from)),this.listeners.get("*")?.forEach(e=>e({event:t.event,payload:t.payload},t.from)))})}listen(t,e){const s=this.listeners.get(t)??new Set;return s.add(e),this.listeners.set(t,s),()=>{s.delete(e)}}publish(t,e={}){return this.link.send("broadcast:publish",{channel:this.name,event:t,payload:e})}async leave(){return this.unsubscribe?.(),this.unsubscribe=null,this.listeners.clear(),this.link.send("broadcast:leave",{channel:this.name})}}class C{constructor(t){this.link=t,this.channels=new Map,this.roomListeners=new Map,this.localRole=null,this.localMembers=null,this.localState=null,this.detach=null,this.state={get:async e=>{const s=await this.link.send("broadcast:state.get",e?{keys:e}:{});return s.ok&&s.data&&(this.localState={...this.localState??{},...s.data.state}),s},set:(e,s)=>(this.localState={...this.localState??this.launch()?.state??{},[e]:s},this.link.send("broadcast:state.set",{key:e,value:s})),snapshot:()=>this.localState??this.launch()?.state??{}}}get room(){return this.launch()?.room??null}get role(){return this.localRole??this.launch()?.role??null}get isFacilitator(){return this.role==="facilitator"}members(){return this.localMembers??this.launch()?.members??[]}async join(t="main"){this.ensureRoomListener();let e=this.channels.get(t);return e||(e=new T(this.link,t),this.channels.set(t,e)),e.attach(),await this.link.send("broadcast:join",{channel:t}),e}async presence(){const t=await this.link.send("broadcast:presence",{});return t.ok&&t.data&&(this.localMembers=t.data.members),t}invite(){return this.link.send("broadcast:invite",{})}claim(){return this.link.send("broadcast:claim",{})}transfer(t){return this.link.send("broadcast:transfer",{to:t})}on(t,e){this.ensureRoomListener();const s=this.roomListeners.get(t)??new Set;return s.add(e),this.roomListeners.set(t,s),()=>{s.delete(e)}}launch(){return this.link.launch()?.broadcast??null}ensureRoomListener(){this.detach??=this.link.onEvent(t=>{if(t.channel!==j)return;const e=t.payload;t.event==="presence"&&Array.isArray(e.members)&&(this.localMembers=e.members),t.event==="state"&&typeof e.key=="string"&&(this.localState={...this.localState??this.launch()?.state??{},[e.key]:e.value}),t.event==="role"&&e.participant_id===this.link.launch()?.actor.id&&(this.localRole=e.role),this.roomListeners.get(t.event)?.forEach(s=>s(e))})}}function w(n){return{ok:!1,error:"undeclared_capability",message:`The manifest does not declare the [${n}] capability.`}}class U{constructor(t,e){this.link=t,this.name=e}create(t){return this.send("db:create",{data:t})}get(t){return this.send("db:get",{id:t})}update(t,e,s={}){return this.send("db:update",{id:t,data:e,merge:s.merge??!0})}delete(t){return this.send("db:delete",{id:t})}list(t={}){return this.send("db:list",t)}count(t={}){return this.send("db:count",t)}send(t,e){return this.link.launch()&&!this.link.declares("db")?Promise.resolve(w("db")):this.link.send(t,{collection:this.name,...e})}}class q{constructor(t){this.link=t}collection(t){return new U(this.link,t)}collections(){return this.link.launch()?.db?.collections??[]}}class P{constructor(t){this.link=t}get(t){return this.link.launch()?.media?.[t]??null}embedUrl(t){return this.get(t)?.embedUrl??null}all(){return this.link.launch()?.media??{}}}class N{constructor(t){this.link=t}uploads(){return this.link.launch()?.storage?.uploads??[]}put(t,e,s={}){const r=e instanceof File?e.name:"blob";return this.link.send("storage:put",{upload:t,file:e,name:r,mime:e.type,bytes:e.size,meta:s},{timeoutMs:12e4})}url(t){return this.link.send("storage:url",{id:t})}list(t){return this.link.send("storage:list",t?{upload:t}:{})}delete(t){return this.link.send("storage:delete",{id:t})}}const y="ziprack",S=1;let _=0;function x(){const n=typeof globalThis.crypto<"u"?globalThis.crypto:void 0;return n&&typeof n.randomUUID=="function"?n.randomUUID():(_+=1,`req-${Date.now().toString(36)}-${_.toString(36)}`)}function M(n,t,e){const s={ns:y,v:S,type:n,payload:t};return e!==void 0&&(s.requestId=e),s}function z(n){if(typeof n!="object"||n===null)return!1;const t=n;return t.ns===y&&t.v===S&&typeof t.type=="string"}function p(n){const t=n.indexOf(":");return t===-1?n:n.slice(0,t)}class H{constructor(t){this.options=t,this.kind="host",this.pending=new Map,this.eventListeners=new Set,this.launchResolvers=[],this.launchData=null,this.listener=e=>this.onMessage(e),this.target=t.target??window.parent,this.isHost=t.isHost??(e=>e===window.parent),this.listenOn=t.listenOn??window,this.listenOn.addEventListener("message",this.listener)}announceReady(){this.fire("rack:ready",{})}waitForLaunch(t){return this.launchData?Promise.resolve(this.launchData):new Promise(e=>{const s=setTimeout(()=>{this.launchResolvers=this.launchResolvers.filter(i=>i!==r),e(null)},t),r=i=>{clearTimeout(s),e(i)};this.launchResolvers.push(r)})}send(t,e,s={}){const r=x(),i=s.timeoutMs??this.options.ackTimeoutMs;return new Promise(a=>{const o={resolve:a,timer:setTimeout(()=>this.expire(r),i),timeoutMs:i,onPartial:s.onPartial};this.pending.set(r,o),this.post(M(t,e,r))})}fire(t,e={}){this.post(M(t,e))}onEvent(t){return this.eventListeners.add(t),()=>{this.eventListeners.delete(t)}}dispose(){this.listenOn.removeEventListener("message",this.listener);for(const[t,e]of this.pending)clearTimeout(e.timer),e.resolve({ok:!1,error:"disposed"}),this.pending.delete(t)}expire(t){const e=this.pending.get(t);e&&(this.pending.delete(t),e.resolve({ok:!1,error:"timeout"}))}post(t){this.target.postMessage(t,"*")}onMessage(t){if(!this.isHost(t.source)||!z(t.data))return;const e=t.data;if(e.type==="rack:launch"){this.launchData=e.payload;const s=this.launchResolvers;this.launchResolvers=[],s.forEach(r=>r(this.launchData));return}if(e.type==="rack:event"){const s=e.payload;this.eventListeners.forEach(r=>r(s));return}e.type==="rack:ack"&&this.onAck(e.payload)}onAck(t){const e=this.pending.get(t.requestId);if(!e)return;if(!t.done&&t.data?.stream===!0){clearTimeout(e.timer),e.timer=setTimeout(()=>this.expire(t.requestId),e.timeoutMs);return}if(t.partial&&!t.done){const{requestId:b,ok:v,partial:m,...h}=t;e.onPartial?.(h),clearTimeout(e.timer),e.timer=setTimeout(()=>this.expire(t.requestId),e.timeoutMs);return}clearTimeout(e.timer),this.pending.delete(t.requestId);const{requestId:s,ok:r,data:i,error:a,message:o,details:c,partial:l,done:R,...d}=t;e.resolve({ok:r,data:i??(Object.keys(d).length?d:void 0),error:a,message:o,details:c})}}class F{constructor(t,e,s={}){this.manifest=t,this.store=e,this.options=s,this.statements=[],this.events=[],this.aiHandlers=new Map,this.chatHistory=new Map,this.blobs=new Map,this.eventListeners=new Set,this.roomMembers=new Map,this.roomState={},this.role="participant",this.joinedAt=Date.now()+Math.random(),this.channel=null,this.heartbeat=null,this.participantId=s.participantId??Math.floor(Math.random()*1e6)+1,this.participantName=s.participantName??"Dev User"}get slug(){return this.manifest?.slug??"applet"}key(...t){return`ziprack-mock:${this.slug}:${t.join(":")}`}declares(t){return this.manifest?(this.manifest.requires?.capabilities??[]).some(e=>e.split("@")[0]===t):!0}onEvent(t){return this.eventListeners.add(t),()=>{this.eventListeners.delete(t)}}pushEvent(t){this.events.push(t),this.eventListeners.forEach(e=>e(t))}launchData(t){const e=this.manifest,s={schema:"ziprack/1",actor:{id:this.participantId,name:this.participantName},applet:{slug:this.slug,name:`${e?.name??t??"Applet"} (mock)`,version:e?.version??"dev"},capabilities:e?.requires?.capabilities??[],media:Object.fromEntries((e?.media??[]).map(r=>[r.id,{provider:r.provider,embedUrl:r.provider==="vimeo"?`https://player.vimeo.com/video/${r.key}?dnt=1`:`https://www.youtube-nocookie.com/embed/${r.key}?rel=0`,meta:null}])),roles:this.roles()};if(this.declares("auth")){const r={user:{id:this.participantId,display_name:this.participantName}};for(const i of e?.requires?.profile??[])r.user[i]=r.user[i]??`mock-${i}`;s.auth=r}return this.declares("attempt")&&(s.attempt=this.attempt()),this.declares("activity")&&(s.activity={activities:[...e?.activities??[]].sort((r,i)=>(r.sequence??0)-(i.sequence??0))}),this.declares("db")&&(s.db={collections:(e?.collections??[]).map(r=>({name:r.name,scope:r.scope}))}),this.declares("storage")&&(s.storage={uploads:(e?.uploads??[]).map(r=>({name:r.name,scope:r.scope,mime:r.mime??[],max_bytes:r.max_bytes??10485760}))}),this.declares("ai")&&(s.ai={prompts:(e?.prompts??[]).map(r=>r.knowledge?.length?{id:r.id,mode:r.mode,knowledge:r.knowledge.map(i=>i.slot)}:{id:r.id,mode:r.mode}),...e?.knowledge?.length?{knowledge:e.knowledge.map(r=>({id:r.id,label:r.label??null}))}:{}}),this.declares("broadcast")&&(this.joinRoom(),s.broadcast={room:{id:1,code:"MOCK01",name:`${this.slug} room`,status:"open",mode:e?.broadcast?.mock_mode??"first_in"},role:this.role,members:this.members(),state:this.stateSnapshot(),channels:e?.broadcast?.channels??["main"]}),s}roles(){const t=this.options.guest??!1,e=(this.manifest?.roles??[]).filter(s=>s.grant==="everyone"||s.grant==="members"&&!t||s.grant==="guests"&&t).map(s=>s.name);return[...new Set([t?"guest":"member",...e,...this.options.roles??[]])]}mockAi(t,e){this.aiHandlers.set(t,e)}dispose(){this.heartbeat&&clearInterval(this.heartbeat),this.channel&&(this.send({t:"bye",from:this.member()}),this.channel.close())}async handle(t,e){if(this.options.log?.(t,e),t==="rack:eject")return{ok:!0};const s=p(t);if((this.options.strict??this.manifest!==null)&&!this.declares(s))return{ok:!1,error:"undeclared_capability",message:`The manifest does not declare the [${s}] capability.`};switch(t){case"attempt:state":return this.attemptState(e);case"attempt:segment":return this.attemptSegment(e);case"attempt:complete":return this.attemptComplete(e);case"activity:statement":return this.statement(e);case"db:create":return this.dbCreate(e);case"db:get":return this.dbGet(e);case"db:update":return this.dbUpdate(e);case"db:delete":return this.dbDelete(e);case"db:list":return this.dbList(e);case"db:count":return this.dbCount(e);case"storage:put":return this.storagePut(e);case"storage:url":return this.storageUrl(e);case"storage:list":return this.storageList(e);case"storage:delete":return this.storageDelete(e);case"ai:ask":return this.aiAsk(e);case"ai:chat":return this.aiChat(e);case"ai:chat.reset":return this.chatHistory.delete(String(e.prompt)),{ok:!0};case"broadcast:join":return{ok:!0,data:{members:this.members(),state:this.stateSnapshot()}};case"broadcast:leave":return{ok:!0};case"broadcast:publish":return this.publish(e);case"broadcast:state.get":return{ok:!0,data:{state:this.stateSnapshot(Array.isArray(e.keys)?e.keys:void 0)}};case"broadcast:state.set":return this.stateSet(e);case"broadcast:presence":return{ok:!0,data:{members:this.members()}};case"broadcast:invite":return this.invite();case"broadcast:claim":return this.claim();case"broadcast:transfer":return this.transfer(e);default:return{ok:!1,error:"unknown_type",message:`Unknown message type [${t}].`}}}attempt(){return this.store.get(this.key("attempt"))??{id:1,status:"in_progress",state:null,segment:null}}saveAttempt(t){this.store.set(this.key("attempt"),t)}attemptState(t){const e=this.attempt();if(e.status==="completed")return{ok:!1,error:"completed",message:"This attempt is already completed."};const s=JSON.stringify(t.state??{}).length;return s>65536?{ok:!1,error:"validation",message:`State is ${s} bytes; the limit is 65536.`}:(this.saveAttempt({...e,state:t.state??null}),{ok:!0})}attemptSegment(t){const e=this.attempt();return e.status==="completed"?{ok:!1,error:"completed"}:(this.saveAttempt({...e,segment:t.segment??null}),{ok:!0})}attemptComplete(t){const e=this.attempt(),s=new Date().toISOString();return e.status!=="completed"&&(this.saveAttempt({...e,status:"completed"}),this.declares("activity")&&this.statement({verb:"completed",activity:{id:"attempt",type:"attempt"},result:t.summary??null,occurred_at:s})),{ok:!0,data:{status:"completed",completed_at:s}}}resetAttempt(){this.store.remove(this.key("attempt"))}statement(t){const e=String(t.verb??"");if(!/^[a-z][a-z0-9_.:-]*$/.test(e)||e.length>100)return{ok:!1,error:"validation",message:`Invalid verb [${e}].`};if(!t.activity?.id)return{ok:!1,error:"validation",message:"activity.id is required."};const r=`mock-${Date.now().toString(36)}-${this.statements.length+1}`;return this.statements.push({id:r,...t}),{ok:!0,data:{id:r}}}collectionKey(t){return this.key("db",t)}records(t){return this.store.get(this.collectionKey(t))??[]}saveRecords(t,e){this.store.set(this.collectionKey(t),e)}collectionDeclared(t){return this.manifest&&!(this.manifest.collections??[]).some(s=>s.name===t)?{ok:!1,error:"not_found",message:`Collection [${t}] is not declared in the manifest.`}:(this.manifest?.collections??[]).find(s=>s.name===t)?.scope==="attempt"&&this.attempt().status==="completed"?{ok:!1,error:"completed",message:"Attempt-scoped records are frozen after completion."}:null}dbCreate(t){const e=String(t.collection),s=this.collectionDeclared(e);if(s)return s;const r=new Date().toISOString(),i={id:`rec-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,7)}`,data:t.data??{},owner_id:this.participantId,created_at:r,updated_at:r};return this.saveRecords(e,[...this.records(e),i]),{ok:!0,data:{record:i}}}dbGet(t){const e=this.records(String(t.collection)).find(s=>s.id===t.id);return e?{ok:!0,data:{record:e}}:{ok:!1,error:"not_found"}}dbUpdate(t){const e=String(t.collection),s=this.collectionDeclared(e);if(s&&s.error==="completed")return s;const r=this.records(e),i=r.findIndex(c=>c.id===t.id);if(i===-1)return{ok:!1,error:"not_found"};const a=t.merge!==!1,o=t.data??{};return r[i]={...r[i],data:a?{...r[i].data,...o}:o,updated_at:new Date().toISOString()},this.saveRecords(e,r),{ok:!0,data:{record:r[i]}}}dbDelete(t){const e=String(t.collection),s=this.records(e);return s.some(r=>r.id===t.id)?(this.saveRecords(e,s.filter(r=>r.id!==t.id)),{ok:!0,data:{id:t.id}}):{ok:!1,error:"not_found"}}filter(t,e){return e?t.filter(s=>e.every(([r,i,a])=>{const o=r.split(".").reduce((c,l)=>c?.[l],s.data);switch(i){case"=":return o===a;case"!=":return o!==a;case"<":return o<a;case"<=":return o<=a;case">":return o>a;case">=":return o>=a;case"in":return Array.isArray(a)&&a.includes(o);default:return!1}})):t}dbList(t){const e=String(t.collection);if(this.manifest&&!(this.manifest.collections??[]).some(c=>c.name===e))return{ok:!1,error:"not_found",message:`Collection [${e}] is not declared in the manifest.`};let s=this.filter(this.records(e),t.where);if(typeof t.orderBy=="string"){const c=t.orderBy,l=t.direction==="desc"?-1:1;s=[...s].sort((R,d)=>{const b=c.split(".").reduce((m,h)=>m?.[h],R.data),v=c.split(".").reduce((m,h)=>m?.[h],d.data);return b<v?-l:b>v?l:0})}const r=Math.min(Number(t.limit??50),100),i=t.cursor?Number(t.cursor):0,a=s.slice(i,i+r),o=i+r<s.length?String(i+r):null;return{ok:!0,data:{records:a,nextCursor:o}}}dbCount(t){return{ok:!0,data:{count:this.filter(this.records(String(t.collection)),t.where).length}}}files(){return this.store.get(this.key("files"))??[]}storagePut(t){const e=String(t.upload),s=(this.manifest?.uploads??[]).find(c=>c.name===e);if(this.manifest&&!s)return{ok:!1,error:"not_found",message:`Upload [${e}] is not declared in the manifest.`};const r=String(t.mime??"");if(s?.mime&&s.mime.length>0&&!s.mime.some(c=>c===r||c.endsWith("/*")&&r.startsWith(c.slice(0,-1))))return{ok:!1,error:"validation",message:`MIME type [${r}] is not allowed for upload [${e}].`};const i=Number(t.bytes??0);if(s?.max_bytes&&i>s.max_bytes)return{ok:!1,error:"quota_exceeded",message:`File is ${i} bytes; the limit is ${s.max_bytes}.`};const a={id:`file-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,7)}`,upload:e,name:String(t.name??"blob"),mime:r,bytes:i,status:"clean",created_at:new Date().toISOString()},o=t.file;return typeof URL<"u"&&typeof URL.createObjectURL=="function"&&o instanceof Blob&&this.blobs.set(a.id,URL.createObjectURL(o)),this.store.set(this.key("files"),[...this.files(),a]),{ok:!0,data:{file:a}}}storageUrl(t){const e=this.files().find(s=>s.id===t.id);return e?{ok:!0,data:{url:this.blobs.get(e.id)??`mock://files/${e.id}`,expires_at:new Date(Date.now()+6e5).toISOString()}}:{ok:!1,error:"not_found"}}storageList(t){return{ok:!0,data:{files:this.files().filter(s=>!t.upload||s.upload===t.upload)}}}storageDelete(t){return this.store.set(this.key("files"),this.files().filter(e=>e.id!==t.id)),{ok:!0,data:{id:t.id}}}prompt(t){return(this.manifest?.prompts??[]).find(e=>e.id===t)??(this.manifest?null:{id:t,mode:"analysis"})}async aiAsk(t){const e=this.prompt(String(t.prompt));if(!e)return{ok:!1,error:"not_found",message:`Prompt [${t.prompt}] is not declared in the manifest.`};const s=this.aiHandlers.get(e.id),r=t.vars??{},i=s?await s(r,"analysis"):f(e.output_schema,r),a=e.knowledge?.length?{citations:[]}:{};return{ok:!0,data:{output:i,usage:{input_tokens:42,output_tokens:17},...a}}}async aiChat(t){const e=this.prompt(String(t.prompt));if(!e)return{ok:!1,error:"not_found",message:`Prompt [${t.prompt}] is not declared in the manifest.`};const s=String(t.message??""),r=this.chatHistory.get(e.id)??[];r.push({role:"user",content:s});const i=this.aiHandlers.get(e.id),a=i?String(await i({...t.vars??{},history:r},"chat",s)):`[mock ${e.id}] You said: ${s}`;r.push({role:"assistant",content:a}),this.chatHistory.set(e.id,r);const o=a.split(" "),c=`msg-${Date.now().toString(36)}`;return{stream:(async function*(){for(let l=0;l<o.length;l++)yield{delta:(l===0?"":" ")+o[l]}})(),final:()=>({message_id:c,text:a,usage:{input_tokens:s.length,output_tokens:a.length},...e.knowledge?.length?{citations:[]}:{}})}}member(){return{id:this.participantId,name:this.participantName,role:this.role,present:!0,joinedAt:this.joinedAt}}members(){const t=Date.now(),e=[...this.roomMembers.values()].filter(i=>t-i.lastSeen<15e3).map(({lastSeen:i,joinedAt:a,...o})=>o),{joinedAt:s,...r}=this.member();return[r,...e].sort((i,a)=>i.id-a.id)}stateSnapshot(t){const e={};for(const[s,r]of Object.entries(this.roomState))(!t||t.includes(s))&&(e[s]=r.value);return e}send(t){this.channel?.postMessage({...t,sender:this.participantId})}joinRoom(){if(this.channel)return;const t=this.manifest?.broadcast?.mock_mode??"first_in";this.role=this.options.role??(t==="first_in"?"facilitator":"participant"),!(typeof BroadcastChannel>"u")&&(this.channel=new BroadcastChannel(this.key("room")),this.channel.onmessage=e=>this.onRoomMessage(e.data),this.send({t:"hello",from:this.member()}),this.heartbeat=setInterval(()=>this.send({t:"here",from:this.member()}),5e3))}reconcileFacilitator(t){t.role==="facilitator"&&this.role==="facilitator"&&(t.joinedAt??0)<this.joinedAt&&(this.role="participant",this.pushEvent({channel:"$room",event:"role",payload:{role:"participant",participant_id:this.participantId}}))}onRoomMessage(t){const e=t.from;if(t.sender!==this.participantId)switch(t.t){case"hello":e&&(this.roomMembers.set(e.id,{...e,lastSeen:Date.now()}),this.reconcileFacilitator(e),this.send({t:"here",from:this.member()}),this.send({t:"state-sync",state:this.roomState}),this.pushEvent({channel:"$room",event:"presence",payload:{members:this.members()}}));break;case"here":if(e){const s=this.roomMembers.has(e.id);this.roomMembers.set(e.id,{...e,lastSeen:Date.now()}),this.reconcileFacilitator(e),s||this.pushEvent({channel:"$room",event:"presence",payload:{members:this.members()}})}break;case"bye":e&&(this.roomMembers.delete(e.id),this.pushEvent({channel:"$room",event:"presence",payload:{members:this.members()}}));break;case"event":this.pushEvent({channel:String(t.channel),event:String(t.event),payload:t.payload,from:{participant_id:Number(t.sender),role:e?.role??"participant"}});break;case"state":{const s=String(t.key),r=Number(t.version);(this.roomState[s]?.version??0)<=r&&(this.roomState[s]={value:t.value,version:r},this.pushEvent({channel:"$room",event:"state",payload:{key:s,value:t.value,version:r}}));break}case"state-sync":for(const[s,r]of Object.entries(t.state))(this.roomState[s]?.version??0)<r.version&&(this.roomState[s]=r);break;case"role":e&&(this.roomMembers.set(e.id,{...e,lastSeen:Date.now()}),e.role==="facilitator"&&this.role==="facilitator"&&(this.role="participant",this.pushEvent({channel:"$room",event:"role",payload:{role:"participant",participant_id:this.participantId}})),this.pushEvent({channel:"$room",event:"role",payload:{role:e.role,participant_id:e.id}}),this.pushEvent({channel:"$room",event:"presence",payload:{members:this.members()}}));break}}invite(){return{ok:!0,data:{code:"MOCK01",url:typeof location>"u"?"https://rack.test/r/MOCK01":location.origin+location.pathname}}}setRole(t){this.role=t,this.send({t:"role",from:this.member()}),this.pushEvent({channel:"$room",event:"role",payload:{role:t,participant_id:this.participantId}})}publish(t){const e=String(t.event);if((this.manifest?.broadcast?.facilitator_events??[]).includes(e)&&this.role!=="facilitator")return{ok:!1,error:"forbidden",message:`Event [${e}] may only be sent by the facilitator.`};const r={participant_id:this.participantId,role:this.role};return this.send({t:"event",channel:t.channel,event:e,payload:t.payload,from:this.member()}),this.pushEvent({channel:String(t.channel??"main"),event:e,payload:t.payload,from:r}),{ok:!0}}stateSet(t){const e=String(t.key),s=(this.roomState[e]?.version??0)+1;return this.roomState[e]={value:t.value,version:s},this.send({t:"state",key:e,value:t.value,version:s}),this.pushEvent({channel:"$room",event:"state",payload:{key:e,value:t.value,version:s}}),{ok:!0,data:{version:s}}}claim(){return this.setRole("facilitator"),{ok:!0,data:{role:"facilitator"}}}transfer(t){if(this.role!=="facilitator")return{ok:!1,error:"forbidden",message:"Only the facilitator can transfer the role."};const e=this.roomMembers.get(Number(t.to));return e?(this.role="participant",e.role="facilitator",this.send({t:"role",from:{...e}}),this.pushEvent({channel:"$room",event:"role",payload:{role:"participant",participant_id:this.participantId}}),this.pushEvent({channel:"$room",event:"role",payload:{role:"facilitator",participant_id:e.id}}),{ok:!0}):{ok:!1,error:"not_found"}}}function f(n,t){if(!n)return{summary:`Mock analysis of ${JSON.stringify(t).slice(0,60)}`};const e=n.type;if(e==="object"){const s={};for(const[r,i]of Object.entries(n.properties??{}))s[r]=f(i,t);return s}return e==="array"?[f(n.items,t)]:e==="number"||e==="integer"?typeof n.minimum=="number"?n.minimum:3:e==="boolean"?!0:Array.isArray(n.enum)?n.enum[0]:"mock"}class k{constructor(t){this.rack=t,this.kind="mock"}async send(t,e,s={}){const r=await this.rack.handle(t,e??{});if("stream"in r){for await(const i of r.stream)s.onPartial?.(i);return{ok:!0,data:r.final()}}return r}fire(t,e={}){this.rack.handle(t,e??{})}onEvent(t){return this.rack.onEvent(t)}dispose(){this.rack.dispose()}}class B{get(t){try{const e=window.localStorage.getItem(t);return e===null?null:JSON.parse(e)}catch{return null}}set(t,e){try{window.localStorage.setItem(t,JSON.stringify(e))}catch{}}remove(t){try{window.localStorage.removeItem(t)}catch{}}keys(t){try{const e=[];for(let s=0;s<window.localStorage.length;s++){const r=window.localStorage.key(s);r&&r.startsWith(t)&&e.push(r)}return e}catch{return[]}}}const K=3e3,J=5e3;class A{constructor(){this.transport=null,this.initPromise=null,this.launchData=null,this.queue=[],this.launchListeners=new Set,this.eventListeners=new Set,this.pendingAiMocks=[];const t={send:(e,s,r)=>this.send(e,s,r),fire:(e,s)=>this.fire(e,s),launch:()=>this.launchData,declares:e=>this.declares(e),onEvent:e=>this.on("event",e),mode:()=>this.mode};this.auth=new O(t),this.attempt=new L(t),this.activity=new D(t),this.db=new q(t),this.storage=new N(t),this.ai=new I(t),this.broadcast=new C(t),this.media=new P(t),this.mock={ai:(e,s)=>{const r=this.mockRack();r?r.mockAi(e,s):this.pendingAiMocks.push([e,s])},resetAttempt:()=>this.mockRack()?.resetAttempt(),rack:()=>this.mockRack()}}init(t={}){return this.initPromise??=this.performInit(t),this.initPromise}get launched(){return this.launchData!==null}get mode(){return this.transport?.kind??"pending"}getLaunchData(){return this.launchData}declares(t){return(this.launchData?.capabilities??[]).some(e=>e.split("@")[0]===t)}on(t,e){if(t==="launch"){const r=e;return this.launchListeners.add(r),this.launchData&&r(this.launchData),()=>{this.launchListeners.delete(r)}}const s=e;return this.eventListeners.add(s),()=>{this.eventListeners.delete(s)}}eject(){this.fire("rack:eject",{}),this.transport?.kind==="mock"&&console.info("[ziprack mock] eject: the Rack would navigate away now.")}send(t,e,s){return this.launchData&&!t.startsWith("rack:")&&!this.declares(p(t))?Promise.resolve(w(p(t))):this.transport?this.transport.send(t,e,s):new Promise(r=>{this.queue.push({type:t,payload:e,options:s,resolve:r})})}fire(t,e={}){if(this.transport){this.transport.fire(t,e);return}this.send(t,e)}dispose(){this.transport?.dispose(),this.transport=null,this.initPromise=null,this.launchData=null}async performInit(t){const e=t.ackTimeoutMs??J,s=t.launchTimeoutMs??K;if(t.transport){const o=t.launch??(t.transport instanceof k?t.transport.rack.launchData():null);if(!o)throw new Error("init({ transport }) needs `launch` data unless the transport is a MockTransport.");return this.activate(t.transport,o)}if(!(typeof window<"u"&&window.parent!==window))return this.activateMock(t,"not embedded in a Rack");const i=new H({ackTimeoutMs:e});i.announceReady();const a=await i.waitForLaunch(s);return a?this.activate(i,a):(i.dispose(),this.activateMock(t,`no rack:launch within ${s}ms`))}async activateMock(t,e){console.info(`[ziprack] running in mock mode (${e})`);const s=await W(t.manifestUrl??"./manifest.json",t.slug),r=new F(s,new B,{log:(i,a)=>console.info(`[ziprack mock] ${i}`,a),...G()});for(const[i,a]of this.pendingAiMocks)r.mockAi(i,a);return this.pendingAiMocks=[],this.activate(new k(r),r.launchData(t.slug))}activate(t,e){return this.transport=t,this.launchData=e,t.onEvent(s=>this.eventListeners.forEach(r=>r(s))),this.launchListeners.forEach(s=>s(e)),this.flushQueue(),e}flushQueue(){if(this.transport)for(;this.queue.length>0;){const e=this.queue.shift();this.send(e.type,e.payload,e.options).then(e.resolve)}}mockRack(){return this.transport instanceof k?this.transport.rack:null}}async function W(n,t){if(typeof fetch!="function")return null;try{const e=await fetch(n,{cache:"no-store"});if(!e.ok)throw new Error(String(e.status));const s=await e.json();return t&&s.slug!==t&&console.warn(`[ziprack mock] manifest slug [${s.slug}] does not match init({ slug: '${t}' }).`),s}catch(e){return console.warn(`[ziprack mock] could not load ${n}; mock mode will accept every capability.`,e),null}}function G(n=typeof location>"u"?"":location.search){const t=new URLSearchParams(n),e=(t.get("ziprack-roles")??"").split(",").map(s=>s.trim()).filter(s=>s!=="");return{...e.length>0?{roles:e}:{},...t.has("ziprack-guest")?{guest:t.get("ziprack-guest")!=="0"}:{}}}const g=new A;function $(){return new A}return window.Rack=g,window.ZipRack={Rack:g,createRack:$},u.Rack=g,u.createRack=$,Object.defineProperty(u,Symbol.toStringTag,{value:"Module"}),u})({});
2
2
  //# sourceMappingURL=ziprack-sdk.iife.js.map