@vibevibes/sdk 0.1.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,622 @@
1
+ import React from 'react';
2
+ import { z } from 'zod';
3
+
4
+ /**
5
+ * Experience SDK Types - Simplified state sync
6
+ */
7
+
8
+ type ToolRisk = "low" | "medium" | "high";
9
+ /**
10
+ * Netcode mode declaration — experiences declare their sync strategy.
11
+ * The runtime picks the right optimizations automatically.
12
+ */
13
+ type NetcodeMode = "default" | "tick" | "p2p-ephemeral";
14
+ /**
15
+ * JSON Patch operation (RFC 6902 subset).
16
+ */
17
+ type JsonPatchOp = {
18
+ op: "add" | "remove" | "replace";
19
+ path: string;
20
+ value?: any;
21
+ };
22
+ type ExperienceImport = {
23
+ experienceId: string;
24
+ tools: string[] | '*';
25
+ prefix?: string;
26
+ };
27
+ /**
28
+ * Event emitted after a tool executes (used by typed event subscriptions).
29
+ */
30
+ type ToolEvent = {
31
+ id: string;
32
+ ts: number;
33
+ actorId: string;
34
+ owner?: string;
35
+ tool: string;
36
+ input: any;
37
+ output?: any;
38
+ error?: string;
39
+ };
40
+ /**
41
+ * Agent slot definition for multi-agent rooms.
42
+ * Experience authors define named agent roles with system prompts and tool restrictions.
43
+ */
44
+ type AgentSlot = {
45
+ role: string;
46
+ systemPrompt: string;
47
+ allowedTools?: string[];
48
+ autoSpawn?: boolean;
49
+ maxInstances?: number;
50
+ };
51
+ type ExperienceManifest = {
52
+ id: string;
53
+ version: string;
54
+ title: string;
55
+ description: string;
56
+ requested_capabilities: string[];
57
+ imports?: ExperienceImport[];
58
+ agentSlots?: AgentSlot[];
59
+ category?: string;
60
+ tags?: string[];
61
+ /** Sync strategy: 'default' | 'tick' | 'p2p-ephemeral'. Default: 'default'. */
62
+ netcode?: NetcodeMode;
63
+ /** For 'tick' netcode: server tick interval in ms (e.g. 50 = 20Hz). */
64
+ tickRateMs?: number;
65
+ /** State keys routed through fast ephemeral channel (no tool gate). */
66
+ hotKeys?: string[];
67
+ };
68
+ /**
69
+ * Simplified Tool Context (no yjs, no events array)
70
+ *
71
+ * Use the generic parameter for typed state:
72
+ * handler: async (ctx: ToolCtx<{ count: number }>, input) => {
73
+ * const current = ctx.state.count; // typed
74
+ * }
75
+ */
76
+ type ToolCtx<TState extends Record<string, any> = Record<string, any>> = {
77
+ roomId: string;
78
+ actorId: string;
79
+ owner?: string;
80
+ state: TState;
81
+ setState: (newState: TState) => void;
82
+ timestamp: number;
83
+ memory: Record<string, any>;
84
+ setMemory: (updates: Record<string, any>) => void;
85
+ /**
86
+ * Spawn a child room with a specified experience.
87
+ * Only available when manifest declares "room.spawn" in requested_capabilities.
88
+ * Rate limited to 5 spawns per room per 5 minutes.
89
+ */
90
+ spawnRoom?: (opts: SpawnRoomOpts) => Promise<SpawnRoomResult>;
91
+ };
92
+ type ToolDef<TInput = any, TOutput = any> = {
93
+ name: string;
94
+ description: string;
95
+ input_schema: z.ZodTypeAny;
96
+ risk: ToolRisk;
97
+ capabilities_required: string[];
98
+ handler: (ctx: ToolCtx, input: TInput) => Promise<TOutput>;
99
+ emits?: string[];
100
+ on?: Record<string, (ctx: ToolCtx, event: ToolEvent) => Promise<void>>;
101
+ /**
102
+ * If false, skip persisting state + event to DB after execution.
103
+ * State is still broadcast to clients. Use for high-frequency tools
104
+ * like cursor moves, animations, etc. Default: true.
105
+ */
106
+ persist?: boolean;
107
+ };
108
+ /**
109
+ * Simplified Canvas Props - Hybrid State Model
110
+ *
111
+ * Use the generic parameter for typed sharedState:
112
+ * const Canvas: React.FC<CanvasProps<{ count: number }>> = ({ sharedState }) => {
113
+ * const count = sharedState.count; // fully typed
114
+ * };
115
+ */
116
+ type CanvasProps<TState extends Record<string, any> = Record<string, any>> = {
117
+ roomId: string;
118
+ actorId: string;
119
+ sharedState: TState;
120
+ callTool: (name: string, input: any, predictFn?: (state: TState) => TState) => Promise<any>;
121
+ /** Batch multiple tool calls in a single round-trip. */
122
+ callTools?: (calls: Array<{
123
+ name: string;
124
+ input: any;
125
+ }>) => Promise<any[]>;
126
+ ephemeralState: Record<string, Record<string, any>>;
127
+ setEphemeral: (data: Record<string, any>) => void;
128
+ /** Fire a client-authoritative action via Broadcast (no tool gate, no persistence). */
129
+ dispatchEphemeralAction?: (name: string, input: any) => void;
130
+ /** Subscribe to ephemeral actions from other participants. */
131
+ onEphemeralAction?: (handler: (action: {
132
+ name: string;
133
+ input: any;
134
+ actorId: string;
135
+ ts: number;
136
+ }) => void) => () => void;
137
+ participants: string[];
138
+ };
139
+ /**
140
+ * Assertion chain returned by `expect()` in test helpers.
141
+ */
142
+ type ExpectChain<T> = {
143
+ toBe: (expected: T) => void;
144
+ toEqual: (expected: any) => void;
145
+ toBeTruthy: () => void;
146
+ toBeFalsy: () => void;
147
+ toContain: (item: any) => void;
148
+ toHaveProperty: (key: string, value?: any) => void;
149
+ not: ExpectChain<T>;
150
+ };
151
+ /**
152
+ * Helpers injected into each test's `run` function.
153
+ *
154
+ * - `tool(name)` looks up a tool from the experience's tools array
155
+ * - `ctx(opts?)` creates a mock ToolCtx; call `getState()` after mutations
156
+ * - `expect(actual)` returns an assertion chain for type-safe assertions
157
+ * - `snapshot(label, value)` stores/compares values within a test session
158
+ *
159
+ * Tests signal failure by throwing. If `run` resolves, the test passed.
160
+ */
161
+ type TestHelpers = {
162
+ tool: (name: string) => ToolDef;
163
+ ctx: (opts?: {
164
+ state?: Record<string, any>;
165
+ actorId?: string;
166
+ roomId?: string;
167
+ owner?: string;
168
+ }) => ToolCtx & {
169
+ getState: () => Record<string, any>;
170
+ };
171
+ expect: <T>(actual: T) => ExpectChain<T>;
172
+ snapshot: (label: string, value: any) => void;
173
+ };
174
+ /**
175
+ * Inline test for experience tool handlers.
176
+ * Throw to fail; resolve to pass.
177
+ */
178
+ type TestDef = {
179
+ name: string;
180
+ run: (helpers: TestHelpers) => Promise<void>;
181
+ };
182
+ /**
183
+ * Declarative hint for agents about when to act.
184
+ * Experience authors include these to guide agent behavior.
185
+ */
186
+ type AgentHint = {
187
+ trigger: string;
188
+ condition?: string;
189
+ suggestedTools: string[];
190
+ priority?: 'low' | 'medium' | 'high';
191
+ cooldownMs?: number;
192
+ /** Cross-room agent coordination: follow linked rooms and react to activity there. */
193
+ crossRoom?: {
194
+ linkTypes?: string[];
195
+ watchFor?: string[];
196
+ };
197
+ };
198
+ /**
199
+ * Client-authoritative action that bypasses the tool gate entirely.
200
+ * Goes through Supabase Broadcast directly — no persistence, no server validation.
201
+ * Use for cursor positions, hover states, drag previews, etc.
202
+ */
203
+ type EphemeralActionDef = {
204
+ name: string;
205
+ description: string;
206
+ input_schema: z.ZodTypeAny;
207
+ };
208
+ /**
209
+ * Performance metrics exposed by the room sync system.
210
+ */
211
+ type PerfMetrics = {
212
+ toolCallRtts: number[];
213
+ broadcastLatencies: number[];
214
+ stateSize: number;
215
+ rendersPerSecond: number;
216
+ pendingOptimistic: number;
217
+ };
218
+ /**
219
+ * Follow protocol: allows participants to "follow" another user's viewport/actions.
220
+ * Stored in ephemeral state under the `_follow` key.
221
+ */
222
+ type FollowState = {
223
+ targetActorId: string;
224
+ mode: 'viewport' | 'actions' | 'both';
225
+ since: number;
226
+ };
227
+ /**
228
+ * Multi-agent message for negotiation protocol.
229
+ * Agents communicate through shared state under the `_agentMessages` key.
230
+ */
231
+ type AgentMessage = {
232
+ id: string;
233
+ from: string;
234
+ to: string | '*';
235
+ type: 'proposal' | 'vote' | 'delegate' | 'inform' | 'request';
236
+ content: string;
237
+ data?: Record<string, any>;
238
+ ts: number;
239
+ ttl?: number;
240
+ };
241
+ /**
242
+ * State migration function for experience versioning.
243
+ * Called when a room's experience version changes.
244
+ */
245
+ type StateMigration = {
246
+ from: string;
247
+ to: string;
248
+ migrate: (oldState: Record<string, any>) => Record<string, any>;
249
+ };
250
+ /**
251
+ * Webhook event types that can be filtered.
252
+ */
253
+ type WebhookEventType = 'tool.executed' | 'tool.error' | 'participant.joined' | 'participant.left' | 'state.changed' | 'room.created' | 'room.reset';
254
+ /**
255
+ * Options for spawning a child room from a tool handler.
256
+ * Requires "room.spawn" in manifest.requested_capabilities.
257
+ */
258
+ type SpawnRoomOpts = {
259
+ experienceId: string;
260
+ name?: string;
261
+ initialState?: Record<string, any>;
262
+ /** If true, store parent roomId in child state as _parentRoom */
263
+ linkBack?: boolean;
264
+ };
265
+ type SpawnRoomResult = {
266
+ roomId: string;
267
+ url: string;
268
+ };
269
+ /**
270
+ * A link between two rooms (parent/child relationship).
271
+ */
272
+ type RoomLink = {
273
+ parentRoomId: string;
274
+ childRoomId: string;
275
+ linkType: 'spawned' | 'referenced' | 'forked';
276
+ metadata?: Record<string, any>;
277
+ createdAt: string;
278
+ };
279
+ type ExperienceModule = {
280
+ manifest: ExperienceManifest;
281
+ Canvas: React.FC<CanvasProps>;
282
+ tools: ToolDef[];
283
+ tests?: TestDef[];
284
+ agentHints?: AgentHint[];
285
+ /** Client-authoritative actions that bypass the tool gate. */
286
+ ephemeralActions?: EphemeralActionDef[];
287
+ /** State migrations for version upgrades. */
288
+ migrations?: StateMigration[];
289
+ };
290
+
291
+ declare function defineTool<TInput, TOutput>(config: {
292
+ name: string;
293
+ description: string;
294
+ input_schema: z.ZodType<TInput>;
295
+ risk?: ToolRisk;
296
+ capabilities_required?: string[];
297
+ handler: ToolDef<TInput, TOutput>["handler"];
298
+ }): ToolDef<TInput, TOutput>;
299
+ declare function defineTest(config: {
300
+ name: string;
301
+ run: TestDef["run"];
302
+ }): TestDef;
303
+ declare function defineEphemeralAction(config: {
304
+ name: string;
305
+ description: string;
306
+ input_schema: z.ZodTypeAny;
307
+ }): EphemeralActionDef;
308
+ /**
309
+ * Reduced-boilerplate tool definition.
310
+ * Auto-derives defaults: risk="low", capabilities=["state.write"],
311
+ * and spreads input into state if no handler is provided.
312
+ *
313
+ * Usage:
314
+ * quickTool("counter.increment", "Add 1 to count", z.object({}), async (ctx) => {
315
+ * ctx.setState({ ...ctx.state, count: (ctx.state.count ?? 0) + 1 });
316
+ * })
317
+ */
318
+ declare function quickTool<TInput>(name: string, description: string, input_schema: z.ZodType<TInput>, handler: ToolDef<TInput, any>["handler"]): ToolDef<TInput, any>;
319
+ declare function defineExperience(module: ExperienceModule): ExperienceModule;
320
+ declare function validateExperience(module: ExperienceModule): {
321
+ valid: boolean;
322
+ errors: string[];
323
+ };
324
+
325
+ /**
326
+ * React hooks for experience authors.
327
+ *
328
+ * These hooks simplify common patterns in experience Canvas components:
329
+ * - useToolCall: wraps callTool with loading/error state
330
+ * - useSharedState: typed accessor for a specific state key
331
+ * - useOptimisticTool: optimistic updates with rollback on error
332
+ * - useParticipants: parsed participant list with structured data
333
+ *
334
+ * Hooks rely on React being available as a global (provided by the bundler runtime).
335
+ */
336
+ type CallToolFn = (name: string, input: any) => Promise<any>;
337
+ type UseToolCallReturn = {
338
+ call: (name: string, input: any) => Promise<any>;
339
+ loading: boolean;
340
+ error: string | null;
341
+ };
342
+ /**
343
+ * Wraps callTool with loading and error tracking.
344
+ *
345
+ * Usage:
346
+ * const { call, loading, error } = useToolCall(callTool);
347
+ * <button onClick={() => call('counter.increment', {})} disabled={loading}>
348
+ */
349
+ declare function useToolCall(callTool: CallToolFn): UseToolCallReturn;
350
+ /**
351
+ * Typed accessor for a specific key in shared state.
352
+ *
353
+ * Usage:
354
+ * const count = useSharedState<number>(sharedState, 'count', 0);
355
+ */
356
+ declare function useSharedState<T>(sharedState: Record<string, any>, key: string, defaultValue?: T): T;
357
+ type UseOptimisticToolReturn = {
358
+ call: (name: string, input: any, optimisticState: Record<string, any>) => Promise<any>;
359
+ state: Record<string, any>;
360
+ pending: boolean;
361
+ };
362
+ /**
363
+ * Applies an optimistic state update immediately, then reverts on error.
364
+ *
365
+ * Usage:
366
+ * const { call, state, pending } = useOptimisticTool(callTool, sharedState);
367
+ * call('counter.increment', {}, { count: sharedState.count + 1 });
368
+ */
369
+ declare function useOptimisticTool(callTool: CallToolFn, sharedState: Record<string, any>): UseOptimisticToolReturn;
370
+ /**
371
+ * Decouples render frequency from state sync frequency.
372
+ * State updates are buffered and applied at most once per animation frame.
373
+ * Optional interpolation function smooths transitions between states.
374
+ *
375
+ * Usage:
376
+ * const displayState = useAnimationFrame(sharedState);
377
+ * // OR with interpolation:
378
+ * const displayState = useAnimationFrame(sharedState, (prev, next, t) => ({
379
+ * ...next,
380
+ * x: prev.x + (next.x - prev.x) * t,
381
+ * }));
382
+ */
383
+ declare function useAnimationFrame(sharedState: Record<string, any>, interpolate?: (prev: Record<string, any>, next: Record<string, any>, t: number) => Record<string, any>): Record<string, any>;
384
+ type ParsedParticipant = {
385
+ id: string;
386
+ username: string;
387
+ type: 'human' | 'ai' | 'unknown';
388
+ index: number;
389
+ };
390
+ /**
391
+ * Parses the participant ID list into structured objects.
392
+ *
393
+ * Participant IDs follow the format: {username}-{type}-{N}
394
+ * e.g., "alice-human-1", "claude-ai-2"
395
+ */
396
+ declare function useParticipants(participants: string[]): ParsedParticipant[];
397
+ type FollowMode = 'viewport' | 'actions' | 'both';
398
+ type FollowData = {
399
+ targetActorId: string;
400
+ mode: FollowMode;
401
+ since: number;
402
+ };
403
+ type EphemeralAction = {
404
+ name: string;
405
+ input: any;
406
+ actorId: string;
407
+ ts: number;
408
+ };
409
+ type DispatchEphemeralActionFn = (name: string, input: any) => void;
410
+ type OnEphemeralActionFn = (handler: (action: EphemeralAction) => void) => () => void;
411
+ type SetEphemeralFn = (data: Record<string, any>) => void;
412
+ type UseFollowReturn = {
413
+ /** Start following a target participant. */
414
+ follow: (targetActorId: string, mode: FollowMode) => void;
415
+ /** Stop following. */
416
+ unfollow: () => void;
417
+ /** Who you are currently following, or null. */
418
+ following: FollowData | null;
419
+ /** List of actor IDs that are following you. */
420
+ followers: Array<{
421
+ actorId: string;
422
+ mode: FollowMode;
423
+ since: number;
424
+ }>;
425
+ };
426
+ /**
427
+ * Manages follow-mode state via ephemeral presence.
428
+ *
429
+ * Stores follow intent in ephemeral state under `_follow` key and dispatches
430
+ * `follow.started` / `follow.stopped` ephemeral actions to notify participants.
431
+ *
432
+ * Usage:
433
+ * const { follow, unfollow, following, followers } = useFollow(
434
+ * actorId, participants, ephemeralState, setEphemeral,
435
+ * onEphemeralAction, dispatchEphemeralAction
436
+ * );
437
+ * follow('alice-human-1', 'viewport');
438
+ */
439
+ declare function useFollow(actorId: string, participants: string[], ephemeralState: Record<string, Record<string, any>>, setEphemeral: SetEphemeralFn, _onEphemeralAction?: OnEphemeralActionFn, dispatchEphemeralAction?: DispatchEphemeralActionFn): UseFollowReturn;
440
+ /**
441
+ * Manages typing/activity indicators via ephemeral state.
442
+ *
443
+ * Usage:
444
+ * const { setTyping, typingUsers } = useTypingIndicator(actorId, ephemeralState, setEphemeral);
445
+ *
446
+ * // Call setTyping(true) when the user starts typing
447
+ * // Call setTyping(false) when they stop (auto-clears after 3s)
448
+ * // typingUsers is an array of actor IDs currently typing
449
+ */
450
+ declare function useTypingIndicator(actorId: string, ephemeralState: Record<string, Record<string, any>>, setEphemeral: (data: Record<string, any>) => void, timeoutMs?: number): {
451
+ setTyping: (isTyping: boolean) => void;
452
+ typingUsers: string[];
453
+ };
454
+
455
+ /**
456
+ * Pre-built UI components for experiences.
457
+ *
458
+ * These components use inline styles (no Tailwind dependency) so they work
459
+ * reliably inside bundled experience canvases. They provide sensible defaults
460
+ * and can be overridden via the `style` prop.
461
+ *
462
+ * Usage in experiences:
463
+ * import { Button, Card, Input, Badge, Stack, Grid } from "@vibevibes/experience-sdk";
464
+ */
465
+ type ButtonProps = {
466
+ children?: any;
467
+ onClick?: () => void;
468
+ disabled?: boolean;
469
+ variant?: 'primary' | 'secondary' | 'danger' | 'ghost';
470
+ size?: 'sm' | 'md' | 'lg';
471
+ style?: Record<string, any>;
472
+ };
473
+ declare function Button({ children, onClick, disabled, variant, size, style }: ButtonProps): any;
474
+ type CardProps = {
475
+ children?: any;
476
+ title?: string;
477
+ style?: Record<string, any>;
478
+ };
479
+ declare function Card({ children, title, style }: CardProps): any;
480
+ type InputProps = {
481
+ value?: string;
482
+ onChange?: (value: string) => void;
483
+ placeholder?: string;
484
+ type?: string;
485
+ disabled?: boolean;
486
+ style?: Record<string, any>;
487
+ };
488
+ declare function Input({ value, onChange, placeholder, type, disabled, style }: InputProps): any;
489
+ type BadgeProps = {
490
+ children?: any;
491
+ color?: 'gray' | 'blue' | 'green' | 'red' | 'yellow' | 'purple';
492
+ style?: Record<string, any>;
493
+ };
494
+ declare function Badge({ children, color, style }: BadgeProps): any;
495
+ type StackProps = {
496
+ children?: any;
497
+ direction?: 'row' | 'column';
498
+ gap?: string | number;
499
+ align?: string;
500
+ justify?: string;
501
+ style?: Record<string, any>;
502
+ };
503
+ declare function Stack({ children, direction, gap, align, justify, style }: StackProps): any;
504
+ type GridProps = {
505
+ children?: any;
506
+ columns?: number | string;
507
+ gap?: string | number;
508
+ style?: Record<string, any>;
509
+ };
510
+ declare function Grid({ children, columns, gap, style }: GridProps): any;
511
+
512
+ /**
513
+ * Multi-agent negotiation protocol.
514
+ * Provides pre-built tools for agent-to-agent communication.
515
+ */
516
+
517
+ declare function createAgentProtocolTools(namespace: string, z: any): ToolDef[];
518
+
519
+ /**
520
+ * Pre-built agent hints for the negotiation protocol.
521
+ */
522
+
523
+ declare function createAgentProtocolHints(namespace: string): AgentHint[];
524
+
525
+ /**
526
+ * State migration runner for experience versioning.
527
+ *
528
+ * Pure functions (no side effects, no async) so they can run in Edge Functions,
529
+ * Node.js, or the browser.
530
+ */
531
+
532
+ interface MigrationResult {
533
+ migrated: boolean;
534
+ fromVersion: string;
535
+ toVersion: string;
536
+ state: Record<string, any>;
537
+ }
538
+ /**
539
+ * Get the state version from a state object.
540
+ * Stored in state._version, defaults to "0.0.0" if absent.
541
+ */
542
+ declare function getStateVersion(state: Record<string, any>): string;
543
+ /**
544
+ * Compare two semver strings.
545
+ * Returns -1 if a < b, 0 if equal, 1 if a > b.
546
+ *
547
+ * Handles standard major.minor.patch format. Missing segments default to 0.
548
+ */
549
+ declare function compareSemver(a: string, b: string): number;
550
+ /**
551
+ * Run all applicable migrations on a state object.
552
+ *
553
+ * - Reads state._version (default "0.0.0") as the starting version
554
+ * - Sorts migrations by their to version (ascending semver)
555
+ * - Applies each migration where migration.to > stateVersion and migration.to <= currentVersion
556
+ * - Sets state._version = currentVersion after all migrations
557
+ * - Returns a MigrationResult indicating whether any migrations were applied
558
+ *
559
+ * The migration runner is pure: it does not mutate the input state object.
560
+ * It returns a new state object with migrations applied.
561
+ */
562
+ declare function migrateState(state: Record<string, any>, migrations: StateMigration[], currentVersion: string): MigrationResult;
563
+
564
+ /**
565
+ * Storage adapter interface for vibe vibes
566
+ * Allows multiple storage backends: in-memory, Supabase, GitHub, etc.
567
+ */
568
+ interface ExperienceListing {
569
+ id: string;
570
+ title: string;
571
+ description: string;
572
+ version: string;
573
+ source: 'builtin' | 'github' | 'supabase';
574
+ github_repo?: string;
575
+ github_url?: string;
576
+ }
577
+ interface RoomState {
578
+ roomId: string;
579
+ experienceId: string;
580
+ sharedState: Record<string, any>;
581
+ updatedAt: number;
582
+ }
583
+ interface StorageToolEvent {
584
+ id: string;
585
+ ts: number;
586
+ actor_id: string;
587
+ tool: string;
588
+ input: unknown;
589
+ output: unknown;
590
+ }
591
+ /**
592
+ * Storage adapter interface
593
+ * All methods are async to support both local and remote storage
594
+ */
595
+ interface StorageAdapter {
596
+ saveRoomState(roomId: string, state: RoomState): Promise<void>;
597
+ loadRoomState(roomId: string): Promise<RoomState | null>;
598
+ appendEvent(roomId: string, event: StorageToolEvent): Promise<void>;
599
+ loadEvents(roomId: string, limit?: number): Promise<StorageToolEvent[]>;
600
+ listExperiences(userId?: string): Promise<ExperienceListing[]>;
601
+ saveUserProfile?(userId: string, profile: any): Promise<void>;
602
+ loadUserProfile?(userId: string): Promise<any | null>;
603
+ }
604
+ /**
605
+ * In-memory storage adapter
606
+ * No persistence - data lost on restart
607
+ * Perfect for local development and demos
608
+ */
609
+ declare class InMemoryAdapter implements StorageAdapter {
610
+ private roomStates;
611
+ private events;
612
+ private profiles;
613
+ saveRoomState(roomId: string, state: RoomState): Promise<void>;
614
+ loadRoomState(roomId: string): Promise<RoomState | null>;
615
+ appendEvent(roomId: string, event: StorageToolEvent): Promise<void>;
616
+ loadEvents(roomId: string, limit?: number): Promise<StorageToolEvent[]>;
617
+ listExperiences(_userId?: string): Promise<ExperienceListing[]>;
618
+ saveUserProfile(userId: string, profile: any): Promise<void>;
619
+ loadUserProfile(userId: string): Promise<any | null>;
620
+ }
621
+
622
+ export { type AgentHint, type AgentMessage, type AgentSlot, Badge, Button, type CanvasProps, Card, type EphemeralActionDef, type ExpectChain, type ExperienceImport, type ExperienceListing, type ExperienceManifest, type ExperienceModule, type FollowState, Grid, InMemoryAdapter, Input, type JsonPatchOp, type MigrationResult, type NetcodeMode, type ParsedParticipant, type PerfMetrics, type RoomLink, type RoomState, type SpawnRoomOpts, type SpawnRoomResult, Stack, type StateMigration, type StorageAdapter, type StorageToolEvent, type TestDef, type TestHelpers, type ToolCtx, type ToolDef, type ToolEvent, type ToolRisk, type UseFollowReturn, type UseOptimisticToolReturn, type UseToolCallReturn, type WebhookEventType, compareSemver, createAgentProtocolHints, createAgentProtocolTools, defineEphemeralAction, defineExperience, defineTest, defineTool, getStateVersion, migrateState, quickTool, useAnimationFrame, useFollow, useOptimisticTool, useParticipants, useSharedState, useToolCall, useTypingIndicator, validateExperience };