@pancake-apps/server 0.0.1

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,558 @@
1
+ import { RequestHandler } from 'express';
2
+ import { z } from 'zod';
3
+
4
+ /**
5
+ * Content Security Policy configuration for UI resources
6
+ */
7
+ interface ContentSecurityPolicy {
8
+ /** Domains allowed for connect-src (fetch, WebSocket, etc.) */
9
+ connectDomains?: string[];
10
+ /** Domains allowed for loading resources (images, fonts, etc.) */
11
+ resourceDomains?: string[];
12
+ /** Domains allowed for script-src */
13
+ scriptDomains?: string[];
14
+ }
15
+ /**
16
+ * UI definition for views and tools
17
+ */
18
+ interface UIDefinition {
19
+ /** Path to HTML file or inline HTML (starts with "<") */
20
+ html: string;
21
+ /** Display name for the UI */
22
+ name?: string;
23
+ /** Whether the host should render a border around the UI */
24
+ prefersBorder?: boolean;
25
+ /** Whether the UI should auto-resize based on content */
26
+ autoResize?: boolean;
27
+ /** Content Security Policy for the UI iframe */
28
+ csp?: ContentSecurityPolicy;
29
+ /** Domain for cross-origin UIs */
30
+ domain?: string;
31
+ }
32
+ /**
33
+ * Visibility options for tools/views
34
+ * - 'model': Only visible to the AI model
35
+ * - 'app': Only visible to the UI/app
36
+ * - 'both': Visible to both model and app
37
+ */
38
+ type Visibility = 'model' | 'app' | 'both';
39
+ /**
40
+ * Protocol types for client detection
41
+ */
42
+ type Protocol = 'mcp' | 'openai' | 'mock';
43
+ /**
44
+ * Host context provided by MCP or OpenAI hosts
45
+ */
46
+ interface HostContext {
47
+ /** Current theme */
48
+ theme: 'light' | 'dark';
49
+ /** Current display mode */
50
+ displayMode: 'inline' | 'fullscreen' | 'pip';
51
+ /** Available display modes */
52
+ availableDisplayModes: string[];
53
+ /** Viewport dimensions */
54
+ viewport: {
55
+ width: number;
56
+ height: number;
57
+ };
58
+ /** User's locale (e.g., 'en-US') */
59
+ locale: string;
60
+ /** User's timezone */
61
+ timeZone: string;
62
+ /** Platform type */
63
+ platform: 'desktop' | 'mobile' | 'web';
64
+ /** Current view identifier (if applicable) */
65
+ view?: string;
66
+ /** Safe area insets for mobile */
67
+ safeAreaInsets?: {
68
+ top: number;
69
+ right: number;
70
+ bottom: number;
71
+ left: number;
72
+ };
73
+ }
74
+
75
+ /**
76
+ * Base context passed to all handlers
77
+ */
78
+ interface BaseContext {
79
+ /** Unique identifier for this request */
80
+ requestId: string;
81
+ /** Session identifier (if available) */
82
+ sessionId?: string;
83
+ /** Additional metadata from the protocol */
84
+ metadata: Record<string, unknown>;
85
+ }
86
+ /**
87
+ * Context passed to view handlers
88
+ */
89
+ interface ViewContext extends BaseContext {
90
+ /** Name of the view being rendered */
91
+ viewName: string;
92
+ }
93
+ /**
94
+ * Context passed to action handlers
95
+ */
96
+ interface ActionContext extends BaseContext {
97
+ /** Name of the action being executed */
98
+ actionName: string;
99
+ }
100
+ /**
101
+ * Context passed to data handlers
102
+ */
103
+ interface DataContext extends BaseContext {
104
+ /** Name of the data fetcher being called */
105
+ dataName: string;
106
+ }
107
+ /**
108
+ * Context passed to low-level tool handlers
109
+ */
110
+ interface ToolContext extends BaseContext {
111
+ /** Name of the tool being called */
112
+ toolName: string;
113
+ }
114
+
115
+ /**
116
+ * Configuration for defining a view
117
+ *
118
+ * Views are MCP tools + resources that display a UI.
119
+ * They can optionally fetch data to pass to the UI.
120
+ */
121
+ interface ViewConfig<TInput extends z.ZodType = z.ZodTypeAny, TData extends z.ZodType = z.ZodTypeAny> {
122
+ /** Description of what this view shows */
123
+ description: string;
124
+ /** Input schema for view parameters (optional) */
125
+ input?: TInput;
126
+ /** Schema for data returned to the UI (optional) */
127
+ data?: TData;
128
+ /**
129
+ * Handler that fetches data for the view.
130
+ * The returned data is passed to the UI via viewParams.data
131
+ */
132
+ handler?: (input: z.infer<TInput>, ctx: ViewContext) => Promise<z.infer<TData>>;
133
+ /** UI definition (required for views) */
134
+ ui: UIDefinition;
135
+ /** Visibility settings */
136
+ visibility?: Visibility;
137
+ }
138
+ /**
139
+ * Internal normalized view definition
140
+ */
141
+ interface ViewDefinition<TInput extends z.ZodType = z.ZodTypeAny, TData extends z.ZodType = z.ZodTypeAny> {
142
+ readonly _type: 'view';
143
+ readonly name: string;
144
+ readonly description: string;
145
+ readonly input: TInput | undefined;
146
+ readonly data: TData | undefined;
147
+ readonly handler: ((input: z.infer<TInput>, ctx: ViewContext) => Promise<z.infer<TData>>) | undefined;
148
+ readonly ui: UIDefinition;
149
+ readonly visibility: Visibility;
150
+ }
151
+ /**
152
+ * Metadata for discovered views (from JSON files)
153
+ */
154
+ interface ViewMetadata {
155
+ /** Description of the view */
156
+ description: string;
157
+ /** JSON Schema for input parameters */
158
+ input?: Record<string, unknown>;
159
+ /** JSON Schema for data output */
160
+ data?: Record<string, unknown>;
161
+ /** Visibility settings */
162
+ visibility?: Visibility;
163
+ }
164
+ /**
165
+ * Result of view discovery
166
+ */
167
+ interface DiscoveredView {
168
+ /** View name (derived from filename/folder) */
169
+ name: string;
170
+ /** Path to the HTML file */
171
+ htmlPath: string;
172
+ /** Parsed metadata */
173
+ metadata: ViewMetadata;
174
+ }
175
+
176
+ /**
177
+ * Configuration for defining an action
178
+ *
179
+ * Actions are MCP tools that perform write operations.
180
+ * They can be called from the UI via window.pancake.dispatch()
181
+ */
182
+ interface ActionConfig<TInput extends z.ZodType = z.ZodTypeAny, TOutput extends z.ZodType = z.ZodTypeAny> {
183
+ /** Description of what this action does */
184
+ description: string;
185
+ /** Input schema for action parameters */
186
+ input: TInput;
187
+ /** Output schema for action result */
188
+ output: TOutput;
189
+ /** Handler that executes the action */
190
+ handler: (input: z.infer<TInput>, ctx: ActionContext) => Promise<z.infer<TOutput>>;
191
+ /** Optional UI for action confirmation/result display */
192
+ ui?: UIDefinition;
193
+ /** Visibility settings (default: 'both') */
194
+ visibility?: Visibility;
195
+ }
196
+ /**
197
+ * Internal normalized action definition
198
+ */
199
+ interface ActionDefinition<TInput extends z.ZodType = z.ZodTypeAny, TOutput extends z.ZodType = z.ZodTypeAny> {
200
+ readonly _type: 'action';
201
+ readonly name: string;
202
+ readonly description: string;
203
+ readonly input: TInput;
204
+ readonly output: TOutput;
205
+ readonly handler: (input: z.infer<TInput>, ctx: ActionContext) => Promise<z.infer<TOutput>>;
206
+ readonly ui: UIDefinition | undefined;
207
+ readonly visibility: Visibility;
208
+ }
209
+
210
+ /**
211
+ * Configuration for defining a data fetcher
212
+ *
213
+ * Data fetchers are MCP tools that perform read operations.
214
+ * They can be called from the UI via window.pancake.getData()
215
+ */
216
+ interface DataConfig<TInput extends z.ZodType = z.ZodTypeAny, TOutput extends z.ZodType = z.ZodTypeAny> {
217
+ /** Description of what data this fetches */
218
+ description: string;
219
+ /** Input schema for query parameters */
220
+ input: TInput;
221
+ /** Output schema for returned data */
222
+ output: TOutput;
223
+ /** Handler that fetches the data */
224
+ handler: (input: z.infer<TInput>, ctx: DataContext) => Promise<z.infer<TOutput>>;
225
+ /** Visibility settings (default: 'both') */
226
+ visibility?: Visibility;
227
+ }
228
+ /**
229
+ * Internal normalized data definition
230
+ */
231
+ interface DataDefinition<TInput extends z.ZodType = z.ZodTypeAny, TOutput extends z.ZodType = z.ZodTypeAny> {
232
+ readonly _type: 'data';
233
+ readonly name: string;
234
+ readonly description: string;
235
+ readonly input: TInput;
236
+ readonly output: TOutput;
237
+ readonly handler: (input: z.infer<TInput>, ctx: DataContext) => Promise<z.infer<TOutput>>;
238
+ readonly visibility: Visibility;
239
+ }
240
+
241
+ /**
242
+ * Configuration for defining a low-level tool
243
+ *
244
+ * This is the base abstraction that Views, Actions, and Data
245
+ * are built upon. Use this for advanced use cases.
246
+ */
247
+ interface ToolConfig<TInput extends z.ZodType = z.ZodTypeAny, TOutput extends z.ZodType = z.ZodTypeAny> {
248
+ /** Tool name (must be unique) */
249
+ name: string;
250
+ /** Description of what this tool does */
251
+ description: string;
252
+ /** Input schema */
253
+ input: TInput;
254
+ /** Output schema */
255
+ output: TOutput;
256
+ /** Handler that executes the tool */
257
+ handler: (input: z.infer<TInput>, ctx: ToolContext) => Promise<z.infer<TOutput>>;
258
+ /** Optional UI to display with the tool */
259
+ ui?: UIDefinition;
260
+ /** Visibility settings */
261
+ visibility?: Visibility;
262
+ }
263
+ /**
264
+ * Internal normalized tool definition
265
+ */
266
+ interface ToolDefinition<TInput extends z.ZodType = z.ZodTypeAny, TOutput extends z.ZodType = z.ZodTypeAny> {
267
+ readonly _type: 'tool';
268
+ readonly name: string;
269
+ readonly description: string;
270
+ readonly input: TInput;
271
+ readonly output: TOutput;
272
+ readonly handler: (input: z.infer<TInput>, ctx: ToolContext) => Promise<z.infer<TOutput>>;
273
+ readonly ui: UIDefinition | undefined;
274
+ readonly visibility: Visibility;
275
+ }
276
+ /**
277
+ * Internal tool representation used by the server
278
+ * This is what Views, Actions, and Data are normalized to
279
+ */
280
+ interface InternalTool {
281
+ readonly name: string;
282
+ readonly description: string;
283
+ readonly inputSchema: Record<string, unknown>;
284
+ readonly outputSchema: Record<string, unknown>;
285
+ readonly handler: (input: unknown, ctx: ToolContext) => Promise<unknown>;
286
+ readonly ui: UIDefinition | undefined;
287
+ readonly visibility: Visibility;
288
+ readonly category: 'view' | 'action' | 'data' | 'tool';
289
+ }
290
+
291
+ /**
292
+ * CORS configuration
293
+ */
294
+ interface CorsConfig {
295
+ /** Allowed origins */
296
+ origin?: string | string[] | boolean;
297
+ /** Allowed methods */
298
+ methods?: string[];
299
+ /** Allowed headers */
300
+ allowedHeaders?: string[];
301
+ /** Exposed headers */
302
+ exposedHeaders?: string[];
303
+ /** Allow credentials */
304
+ credentials?: boolean;
305
+ /** Preflight cache duration */
306
+ maxAge?: number;
307
+ }
308
+ /**
309
+ * OAuth configuration for protected endpoints
310
+ */
311
+ interface OAuthConfig {
312
+ /** OAuth provider */
313
+ provider: string;
314
+ /** Client ID */
315
+ clientId: string;
316
+ /** Client secret */
317
+ clientSecret: string;
318
+ /** Authorization URL */
319
+ authorizationUrl: string;
320
+ /** Token URL */
321
+ tokenUrl: string;
322
+ /** Scopes to request */
323
+ scopes: string[];
324
+ }
325
+ /**
326
+ * Development server configuration
327
+ */
328
+ interface DevServerConfig {
329
+ /** Vite dev server port (default: 5173) */
330
+ vitePort?: number;
331
+ /** Path prefix for Vite proxy */
332
+ proxyPath?: string;
333
+ }
334
+ /**
335
+ * Application configuration
336
+ */
337
+ interface AppConfig {
338
+ /** Application name */
339
+ name: string;
340
+ /** Application version */
341
+ version: string;
342
+ /** View configurations */
343
+ views?: Record<string, ViewConfig>;
344
+ /** Action configurations */
345
+ actions?: Record<string, ActionConfig>;
346
+ /** Data fetcher configurations */
347
+ data?: Record<string, DataConfig>;
348
+ /** Low-level tool configurations (advanced) */
349
+ tools?: Record<string, ToolConfig>;
350
+ /** Middleware chain */
351
+ middleware?: Middleware[];
352
+ /** Plugins */
353
+ plugins?: Plugin[];
354
+ /** Additional configuration */
355
+ config?: {
356
+ /** CORS settings */
357
+ cors?: CorsConfig;
358
+ /** OAuth settings */
359
+ oauth?: OAuthConfig;
360
+ /** Enable debug mode */
361
+ debug?: boolean;
362
+ /** Custom MCP endpoint path (default: '/mcp') */
363
+ serverRoute?: string;
364
+ /** Development server settings */
365
+ devServer?: DevServerConfig;
366
+ };
367
+ }
368
+ /**
369
+ * Server start options
370
+ */
371
+ interface StartOptions {
372
+ /** Port to listen on (default: 3000) */
373
+ port?: number;
374
+ /** Host to bind to (default: '0.0.0.0') */
375
+ host?: string;
376
+ /** Transport type */
377
+ transport?: 'http' | 'stdio' | 'sse';
378
+ }
379
+ /**
380
+ * Application instance
381
+ */
382
+ interface App {
383
+ /** Start the server */
384
+ start(options?: StartOptions): Promise<void>;
385
+ /** Stop the server */
386
+ stop(): Promise<void>;
387
+ /** Get Express middleware for custom server integration */
388
+ handler(): RequestHandler;
389
+ /** Handle a fetch request (for serverless/edge) */
390
+ handleRequest(req: Request): Promise<Response>;
391
+ /** Add middleware */
392
+ use(middleware: Middleware): void;
393
+ /** Subscribe to events */
394
+ on<K extends keyof EventMap>(event: K, handler: (payload: EventMap[K]) => void): () => void;
395
+ }
396
+ /**
397
+ * Middleware context
398
+ */
399
+ interface MiddlewareContext {
400
+ readonly toolName: string;
401
+ readonly input: unknown;
402
+ readonly metadata: Record<string, unknown>;
403
+ readonly state: Map<string, unknown>;
404
+ }
405
+ /**
406
+ * Middleware function
407
+ */
408
+ type Middleware = (ctx: MiddlewareContext, next: () => Promise<void>) => Promise<void>;
409
+ /**
410
+ * Plugin context
411
+ */
412
+ interface PluginContext {
413
+ readonly app: AppConfig;
414
+ readonly plugin: Plugin;
415
+ }
416
+ /**
417
+ * Tool call context for plugins
418
+ */
419
+ interface ToolCallContext {
420
+ readonly toolName: string;
421
+ readonly input: unknown;
422
+ readonly metadata: Record<string, unknown>;
423
+ }
424
+ /**
425
+ * Tool error context for plugins
426
+ */
427
+ interface ToolErrorContext extends ToolCallContext {
428
+ readonly error: Error;
429
+ }
430
+ /**
431
+ * Plugin interface
432
+ */
433
+ interface Plugin {
434
+ /** Plugin name */
435
+ name: string;
436
+ /** Plugin version */
437
+ version?: string;
438
+ /** Called when app is initialized */
439
+ onInit?(ctx: PluginContext): Promise<void>;
440
+ /** Called when server starts */
441
+ onStart?(ctx: PluginContext): Promise<void>;
442
+ /** Called when server shuts down */
443
+ onShutdown?(ctx: PluginContext): Promise<void>;
444
+ /** Called before a tool is executed */
445
+ beforeToolCall?(ctx: ToolCallContext): Promise<void>;
446
+ /** Called after a tool is executed */
447
+ afterToolCall?(ctx: ToolCallContext): Promise<void>;
448
+ /** Called when a tool throws an error */
449
+ onToolError?(ctx: ToolErrorContext): Promise<void>;
450
+ }
451
+ /**
452
+ * Event map for typed event emitter
453
+ */
454
+ interface EventMap {
455
+ 'app:init': {
456
+ config: AppConfig;
457
+ };
458
+ 'app:start': {
459
+ port?: number;
460
+ transport: string;
461
+ };
462
+ 'app:shutdown': {
463
+ graceful: boolean;
464
+ };
465
+ 'tool:called': {
466
+ toolName: string;
467
+ input: unknown;
468
+ };
469
+ 'tool:success': {
470
+ toolName: string;
471
+ result: unknown;
472
+ durationMs: number;
473
+ };
474
+ 'tool:error': {
475
+ toolName: string;
476
+ error: Error;
477
+ durationMs: number;
478
+ };
479
+ }
480
+
481
+ /**
482
+ * Create a Pancake application.
483
+ *
484
+ * @example
485
+ * ```ts
486
+ * import { createApp, defineView, defineAction, defineData } from '@pancake-apps/server';
487
+ * import { z } from 'zod';
488
+ *
489
+ * const app = createApp({
490
+ * name: 'my-app',
491
+ * version: '1.0.0',
492
+ * views: {
493
+ * hello: defineView({
494
+ * description: 'Greeting view',
495
+ * input: z.object({ name: z.string() }),
496
+ * ui: { html: './views/hello.html' },
497
+ * }),
498
+ * },
499
+ * actions: {
500
+ * save: defineAction({
501
+ * description: 'Save data',
502
+ * input: z.object({ data: z.string() }),
503
+ * output: z.object({ success: z.boolean() }),
504
+ * handler: async ({ data }) => ({ success: true }),
505
+ * }),
506
+ * },
507
+ * });
508
+ *
509
+ * app.start({ port: 3000 });
510
+ * ```
511
+ */
512
+ declare function createApp(config: AppConfig): App;
513
+
514
+ /**
515
+ * Check if a value is a ViewConfig
516
+ */
517
+ declare function isViewConfig(value: unknown): value is ViewConfig;
518
+
519
+ /**
520
+ * Check if a value is an ActionConfig
521
+ */
522
+ declare function isActionConfig(value: unknown): value is ActionConfig;
523
+
524
+ /**
525
+ * Check if a value is a DataConfig
526
+ */
527
+ declare function isDataConfig(value: unknown): value is DataConfig;
528
+
529
+ /**
530
+ * Check if a value is a ToolConfig
531
+ */
532
+ declare function isToolConfig(value: unknown): value is ToolConfig;
533
+
534
+ /**
535
+ * Discover views from a directory.
536
+ *
537
+ * Supports two patterns:
538
+ * 1. Flat files: `views/hello.html` + `views/hello.json`
539
+ * 2. Folder-based: `views/hello/index.html` + `views/hello/metadata.json`
540
+ *
541
+ * @example
542
+ * ```ts
543
+ * const app = createApp({
544
+ * name: 'my-app',
545
+ * version: '1.0.0',
546
+ * views: {
547
+ * ...discoverViews('./src/views'),
548
+ * },
549
+ * });
550
+ * ```
551
+ */
552
+ declare function discoverViews(dir: string): Record<string, ViewConfig>;
553
+ /**
554
+ * Async version of discoverViews for dynamic usage
555
+ */
556
+ declare function discoverViewsAsync(dir: string): Promise<Record<string, ViewConfig>>;
557
+
558
+ export { type ActionConfig, type ActionContext, type ActionDefinition, type App, type AppConfig, type BaseContext, type ContentSecurityPolicy, type CorsConfig, type DataConfig, type DataContext, type DataDefinition, type DevServerConfig, type DiscoveredView, type EventMap, type HostContext, type InternalTool, type Middleware, type MiddlewareContext, type OAuthConfig, type Plugin, type PluginContext, type Protocol, type StartOptions, type ToolCallContext, type ToolConfig, type ToolContext, type ToolDefinition, type ToolErrorContext, type UIDefinition, type ViewConfig, type ViewContext, type ViewDefinition, type ViewMetadata, type Visibility, createApp, discoverViews, discoverViewsAsync, isActionConfig, isDataConfig, isToolConfig, isViewConfig };