@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.
- package/dist/index.cjs +985 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +558 -0
- package/dist/index.d.ts +558 -0
- package/dist/index.js +380 -0
- package/dist/index.js.map +1 -0
- package/dist/server-3KHS3VCE.js +426 -0
- package/dist/server-3KHS3VCE.js.map +1 -0
- package/dist/stdio-TAQIWN3E.js +120 -0
- package/dist/stdio-TAQIWN3E.js.map +1 -0
- package/package.json +66 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,985 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var express = require('express');
|
|
4
|
+
var fs2 = require('fs/promises');
|
|
5
|
+
var path2 = require('path');
|
|
6
|
+
var index_js = require('@modelcontextprotocol/sdk/server/index.js');
|
|
7
|
+
var stdio_js = require('@modelcontextprotocol/sdk/server/stdio.js');
|
|
8
|
+
var types_js = require('@modelcontextprotocol/sdk/types.js');
|
|
9
|
+
var zodToJsonSchema = require('zod-to-json-schema');
|
|
10
|
+
var fsSync = require('fs');
|
|
11
|
+
|
|
12
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
13
|
+
|
|
14
|
+
function _interopNamespace(e) {
|
|
15
|
+
if (e && e.__esModule) return e;
|
|
16
|
+
var n = Object.create(null);
|
|
17
|
+
if (e) {
|
|
18
|
+
Object.keys(e).forEach(function (k) {
|
|
19
|
+
if (k !== 'default') {
|
|
20
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
21
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
get: function () { return e[k]; }
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
n.default = e;
|
|
29
|
+
return Object.freeze(n);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
var express__default = /*#__PURE__*/_interopDefault(express);
|
|
33
|
+
var fs2__namespace = /*#__PURE__*/_interopNamespace(fs2);
|
|
34
|
+
var path2__namespace = /*#__PURE__*/_interopNamespace(path2);
|
|
35
|
+
var fsSync__namespace = /*#__PURE__*/_interopNamespace(fsSync);
|
|
36
|
+
|
|
37
|
+
var __defProp = Object.defineProperty;
|
|
38
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
39
|
+
var __esm = (fn, res) => function __init() {
|
|
40
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
41
|
+
};
|
|
42
|
+
var __export = (target, all) => {
|
|
43
|
+
for (var name in all)
|
|
44
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// src/server/mcp.ts
|
|
48
|
+
function visibilityToAudience(visibility) {
|
|
49
|
+
switch (visibility) {
|
|
50
|
+
case "model":
|
|
51
|
+
return ["assistant"];
|
|
52
|
+
case "app":
|
|
53
|
+
return ["user"];
|
|
54
|
+
case "both":
|
|
55
|
+
default:
|
|
56
|
+
return ["assistant", "user"];
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function createMcpHandler(config) {
|
|
60
|
+
return async (req, res) => {
|
|
61
|
+
const request = req.body;
|
|
62
|
+
if (request.jsonrpc !== "2.0") {
|
|
63
|
+
res.status(400).json({
|
|
64
|
+
jsonrpc: "2.0",
|
|
65
|
+
id: request.id ?? null,
|
|
66
|
+
error: { code: -32600, message: "Invalid Request: Not JSON-RPC 2.0" }
|
|
67
|
+
});
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
const result = await handleMethod(config, request.method, request.params ?? {});
|
|
72
|
+
const response = {
|
|
73
|
+
jsonrpc: "2.0",
|
|
74
|
+
id: request.id,
|
|
75
|
+
result
|
|
76
|
+
};
|
|
77
|
+
res.json(response);
|
|
78
|
+
} catch (error) {
|
|
79
|
+
const response = {
|
|
80
|
+
jsonrpc: "2.0",
|
|
81
|
+
id: request.id,
|
|
82
|
+
error: {
|
|
83
|
+
code: -32603,
|
|
84
|
+
message: error instanceof Error ? error.message : "Internal error",
|
|
85
|
+
data: error instanceof Error ? { stack: error.stack } : void 0
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
res.json(response);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
async function handleMethod(config, method, params) {
|
|
93
|
+
switch (method) {
|
|
94
|
+
case "initialize":
|
|
95
|
+
return {
|
|
96
|
+
protocolVersion: "2024-11-05",
|
|
97
|
+
capabilities: {
|
|
98
|
+
tools: {},
|
|
99
|
+
resources: {}
|
|
100
|
+
},
|
|
101
|
+
serverInfo: {
|
|
102
|
+
name: config.name,
|
|
103
|
+
version: config.version
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
case "tools/list":
|
|
107
|
+
return {
|
|
108
|
+
tools: Array.from(config.tools.values()).filter((tool) => tool.visibility !== "app").map((tool) => ({
|
|
109
|
+
name: tool.name,
|
|
110
|
+
description: tool.description,
|
|
111
|
+
inputSchema: tool.inputSchema,
|
|
112
|
+
annotations: {
|
|
113
|
+
audience: visibilityToAudience(tool.visibility)
|
|
114
|
+
},
|
|
115
|
+
_meta: tool.ui ? {
|
|
116
|
+
ui: {
|
|
117
|
+
visibility: visibilityToAudience(tool.visibility),
|
|
118
|
+
resourceUri: getUIResourceUri(tool.name, tool.category)
|
|
119
|
+
}
|
|
120
|
+
} : void 0
|
|
121
|
+
}))
|
|
122
|
+
};
|
|
123
|
+
case "tools/call": {
|
|
124
|
+
const toolName = params["name"];
|
|
125
|
+
const args = params["arguments"] ?? {};
|
|
126
|
+
const result = await config.executeTool(toolName, args);
|
|
127
|
+
return {
|
|
128
|
+
content: [
|
|
129
|
+
{
|
|
130
|
+
type: "text",
|
|
131
|
+
text: JSON.stringify(result)
|
|
132
|
+
}
|
|
133
|
+
],
|
|
134
|
+
structuredContent: result
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
case "resources/list":
|
|
138
|
+
return {
|
|
139
|
+
resources: Array.from(config.uiResources.values()).map((resource) => ({
|
|
140
|
+
uri: resource.uri,
|
|
141
|
+
name: resource.name,
|
|
142
|
+
mimeType: "text/html;profile=mcp-app",
|
|
143
|
+
_meta: {
|
|
144
|
+
ui: {
|
|
145
|
+
prefersBorder: resource.definition.prefersBorder,
|
|
146
|
+
autoResize: resource.definition.autoResize,
|
|
147
|
+
csp: resource.definition.csp
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}))
|
|
151
|
+
};
|
|
152
|
+
case "resources/read": {
|
|
153
|
+
const uri = params["uri"];
|
|
154
|
+
const resource = config.uiResources.get(uri);
|
|
155
|
+
if (!resource) {
|
|
156
|
+
throw new Error(`Resource not found: ${uri}`);
|
|
157
|
+
}
|
|
158
|
+
let htmlContent;
|
|
159
|
+
const htmlPath = resource.definition.html;
|
|
160
|
+
if (htmlPath.trim().startsWith("<")) {
|
|
161
|
+
htmlContent = htmlPath;
|
|
162
|
+
} else {
|
|
163
|
+
const fsPromises = await import('fs/promises');
|
|
164
|
+
const pathModule = await import('path');
|
|
165
|
+
const fullPath = pathModule.resolve(process.cwd(), htmlPath);
|
|
166
|
+
htmlContent = await fsPromises.readFile(fullPath, "utf-8");
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
contents: [
|
|
170
|
+
{
|
|
171
|
+
uri,
|
|
172
|
+
mimeType: "text/html",
|
|
173
|
+
text: htmlContent
|
|
174
|
+
}
|
|
175
|
+
]
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
case "notifications/initialized":
|
|
179
|
+
case "ping":
|
|
180
|
+
return {};
|
|
181
|
+
default:
|
|
182
|
+
throw new Error(`Unknown method: ${method}`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
function getUIResourceUri(toolName, category) {
|
|
186
|
+
const name = toolName.replace(/^(view|action|data|tool):/, "");
|
|
187
|
+
return `pancake://ui/${category}/${name}`;
|
|
188
|
+
}
|
|
189
|
+
var init_mcp = __esm({
|
|
190
|
+
"src/server/mcp.ts"() {
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// src/server/dev-proxy.ts
|
|
195
|
+
function isDevelopment() {
|
|
196
|
+
return process.env["NODE_ENV"] !== "production";
|
|
197
|
+
}
|
|
198
|
+
function createViteProxy(config) {
|
|
199
|
+
const vitePort = config.vitePort ?? 5173;
|
|
200
|
+
const viteUrl = `http://localhost:${vitePort}`;
|
|
201
|
+
const vitePaths = [
|
|
202
|
+
"/@vite/",
|
|
203
|
+
"/@react-refresh",
|
|
204
|
+
"/assets/",
|
|
205
|
+
"/src/",
|
|
206
|
+
"/__vite_ping",
|
|
207
|
+
"/@fs/",
|
|
208
|
+
"/node_modules/.vite/"
|
|
209
|
+
];
|
|
210
|
+
return async (req, res, next) => {
|
|
211
|
+
const shouldProxy = vitePaths.some((p) => req.path.startsWith(p));
|
|
212
|
+
if (!shouldProxy) {
|
|
213
|
+
next();
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
try {
|
|
217
|
+
const targetUrl = `${viteUrl}${req.url}`;
|
|
218
|
+
const response = await fetch(targetUrl, {
|
|
219
|
+
method: req.method,
|
|
220
|
+
headers: {
|
|
221
|
+
...Object.fromEntries(
|
|
222
|
+
Object.entries(req.headers).filter(
|
|
223
|
+
([key]) => !["host", "connection"].includes(key.toLowerCase())
|
|
224
|
+
)
|
|
225
|
+
)
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
response.headers.forEach((value, key) => {
|
|
229
|
+
res.setHeader(key, value);
|
|
230
|
+
});
|
|
231
|
+
res.status(response.status);
|
|
232
|
+
if (response.body) {
|
|
233
|
+
const reader = response.body.getReader();
|
|
234
|
+
const pump = async () => {
|
|
235
|
+
const { done, value } = await reader.read();
|
|
236
|
+
if (done) {
|
|
237
|
+
res.end();
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
res.write(Buffer.from(value));
|
|
241
|
+
return pump();
|
|
242
|
+
};
|
|
243
|
+
await pump();
|
|
244
|
+
} else {
|
|
245
|
+
res.end();
|
|
246
|
+
}
|
|
247
|
+
} catch (error) {
|
|
248
|
+
if (isDevelopment()) {
|
|
249
|
+
console.warn(`[Pancake] Vite proxy failed for ${req.path}:`, error);
|
|
250
|
+
}
|
|
251
|
+
next();
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
function generateHMRTemplate(serverUrl, viewName) {
|
|
256
|
+
return `<!DOCTYPE html>
|
|
257
|
+
<html lang="en">
|
|
258
|
+
<head>
|
|
259
|
+
<meta charset="UTF-8" />
|
|
260
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
261
|
+
<title>${viewName}</title>
|
|
262
|
+
<base href="${serverUrl}/" />
|
|
263
|
+
<script type="module">
|
|
264
|
+
import { injectIntoGlobalHook } from "${serverUrl}/@react-refresh";
|
|
265
|
+
injectIntoGlobalHook(window);
|
|
266
|
+
window.$RefreshReg$ = () => {};
|
|
267
|
+
window.$RefreshSig$ = () => (type) => type;
|
|
268
|
+
window.__vite_plugin_react_preamble_installed__ = true;
|
|
269
|
+
</script>
|
|
270
|
+
<script type="module" src="${serverUrl}/@vite/client"></script>
|
|
271
|
+
</head>
|
|
272
|
+
<body>
|
|
273
|
+
<div id="root"></div>
|
|
274
|
+
<script type="module">
|
|
275
|
+
// Initialize Pancake client before loading the view
|
|
276
|
+
import('${serverUrl}/src/pancake-init.ts')
|
|
277
|
+
.then(async (mod) => {
|
|
278
|
+
if (mod.init) await mod.init();
|
|
279
|
+
})
|
|
280
|
+
.catch(() => {
|
|
281
|
+
// pancake-init.ts might not exist, that's ok
|
|
282
|
+
})
|
|
283
|
+
.finally(() => {
|
|
284
|
+
import('${serverUrl}/src/views/${viewName}/index.tsx')
|
|
285
|
+
.catch(() => import('${serverUrl}/src/views/${viewName}.tsx'))
|
|
286
|
+
.catch(() => import('${serverUrl}/src/views/${viewName}/index.ts'))
|
|
287
|
+
.catch(() => import('${serverUrl}/src/views/${viewName}.ts'))
|
|
288
|
+
.catch((err) => {
|
|
289
|
+
console.error('Failed to load view:', err);
|
|
290
|
+
document.body.innerHTML = '<pre style="color: red;">Failed to load view: ' + err.message + '</pre>';
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
</script>
|
|
294
|
+
</body>
|
|
295
|
+
</html>`;
|
|
296
|
+
}
|
|
297
|
+
var init_dev_proxy = __esm({
|
|
298
|
+
"src/server/dev-proxy.ts"() {
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
function createUIRoutes(uiResources, devServerConfig) {
|
|
302
|
+
const router = express.Router();
|
|
303
|
+
router.get("/:category/:name", async (req, res) => {
|
|
304
|
+
const { category, name } = req.params;
|
|
305
|
+
const uri = `pancake://ui/${category}/${name}`;
|
|
306
|
+
const resource = uiResources.get(uri);
|
|
307
|
+
if (!resource) {
|
|
308
|
+
res.status(404).json({ error: `UI not found: ${category}/${name}` });
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
try {
|
|
312
|
+
const html = await getUIHtml(resource.definition, name, devServerConfig);
|
|
313
|
+
res.type("html").send(html);
|
|
314
|
+
} catch (error) {
|
|
315
|
+
res.status(500).json({
|
|
316
|
+
error: "Failed to load UI",
|
|
317
|
+
details: error instanceof Error ? error.message : String(error)
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
router.get("/:name", async (req, res) => {
|
|
322
|
+
const { name } = req.params;
|
|
323
|
+
for (const category of ["view", "action", "tool"]) {
|
|
324
|
+
const uri = `pancake://ui/${category}/${name}`;
|
|
325
|
+
const resource = uiResources.get(uri);
|
|
326
|
+
if (resource) {
|
|
327
|
+
try {
|
|
328
|
+
const html = await getUIHtml(resource.definition, name, devServerConfig);
|
|
329
|
+
res.type("html").send(html);
|
|
330
|
+
return;
|
|
331
|
+
} catch (error) {
|
|
332
|
+
res.status(500).json({
|
|
333
|
+
error: "Failed to load UI",
|
|
334
|
+
details: error instanceof Error ? error.message : String(error)
|
|
335
|
+
});
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
res.status(404).json({ error: `UI not found: ${name}` });
|
|
341
|
+
});
|
|
342
|
+
return router;
|
|
343
|
+
}
|
|
344
|
+
async function getUIHtml(ui, viewName, devServerConfig) {
|
|
345
|
+
if (isDevelopment() && devServerConfig) {
|
|
346
|
+
const vitePort = devServerConfig.vitePort ?? 5173;
|
|
347
|
+
return generateHMRTemplate(`http://localhost:${vitePort}`, viewName);
|
|
348
|
+
}
|
|
349
|
+
if (ui.html.trim().startsWith("<")) {
|
|
350
|
+
return ui.html;
|
|
351
|
+
}
|
|
352
|
+
const htmlPath = path2__namespace.resolve(process.cwd(), ui.html);
|
|
353
|
+
const content = await fs2__namespace.readFile(htmlPath, "utf-8");
|
|
354
|
+
return content;
|
|
355
|
+
}
|
|
356
|
+
var init_routes = __esm({
|
|
357
|
+
"src/server/routes.ts"() {
|
|
358
|
+
init_dev_proxy();
|
|
359
|
+
}
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
// src/server/stdio.ts
|
|
363
|
+
var stdio_exports = {};
|
|
364
|
+
__export(stdio_exports, {
|
|
365
|
+
startStdioServer: () => startStdioServer
|
|
366
|
+
});
|
|
367
|
+
function visibilityToAudience2(visibility) {
|
|
368
|
+
switch (visibility) {
|
|
369
|
+
case "model":
|
|
370
|
+
return ["assistant"];
|
|
371
|
+
case "app":
|
|
372
|
+
return ["user"];
|
|
373
|
+
case "both":
|
|
374
|
+
default:
|
|
375
|
+
return ["assistant", "user"];
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
async function startStdioServer(config) {
|
|
379
|
+
const server = new index_js.Server(
|
|
380
|
+
{
|
|
381
|
+
name: config.name,
|
|
382
|
+
version: config.version
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
capabilities: {
|
|
386
|
+
tools: {},
|
|
387
|
+
resources: {}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
);
|
|
391
|
+
server.setRequestHandler(
|
|
392
|
+
types_js.ListToolsRequestSchema,
|
|
393
|
+
async () => {
|
|
394
|
+
return {
|
|
395
|
+
tools: Array.from(config.tools.values()).map((tool) => ({
|
|
396
|
+
name: tool.name,
|
|
397
|
+
description: tool.description,
|
|
398
|
+
inputSchema: tool.inputSchema,
|
|
399
|
+
annotations: {
|
|
400
|
+
audience: visibilityToAudience2(tool.visibility)
|
|
401
|
+
},
|
|
402
|
+
_meta: tool.ui ? {
|
|
403
|
+
ui: {
|
|
404
|
+
visibility: visibilityToAudience2(tool.visibility),
|
|
405
|
+
resourceUri: getUIResourceUri2(tool.name, tool.category)
|
|
406
|
+
}
|
|
407
|
+
} : void 0
|
|
408
|
+
}))
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
);
|
|
412
|
+
server.setRequestHandler(
|
|
413
|
+
types_js.CallToolRequestSchema,
|
|
414
|
+
async (request) => {
|
|
415
|
+
const { name, arguments: args = {} } = request.params;
|
|
416
|
+
const result = await config.executeTool(name, args);
|
|
417
|
+
return {
|
|
418
|
+
content: [
|
|
419
|
+
{
|
|
420
|
+
type: "text",
|
|
421
|
+
text: JSON.stringify(result)
|
|
422
|
+
}
|
|
423
|
+
],
|
|
424
|
+
structuredContent: result
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
);
|
|
428
|
+
server.setRequestHandler(
|
|
429
|
+
types_js.ListResourcesRequestSchema,
|
|
430
|
+
async () => {
|
|
431
|
+
return {
|
|
432
|
+
resources: Array.from(config.uiResources.values()).map((resource) => ({
|
|
433
|
+
uri: resource.uri,
|
|
434
|
+
name: resource.name,
|
|
435
|
+
mimeType: "text/html;profile=mcp-app",
|
|
436
|
+
_meta: {
|
|
437
|
+
ui: {
|
|
438
|
+
prefersBorder: resource.definition.prefersBorder,
|
|
439
|
+
autoResize: resource.definition.autoResize,
|
|
440
|
+
csp: resource.definition.csp
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}))
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
);
|
|
447
|
+
server.setRequestHandler(
|
|
448
|
+
types_js.ReadResourceRequestSchema,
|
|
449
|
+
async (request) => {
|
|
450
|
+
const { uri } = request.params;
|
|
451
|
+
const resource = config.uiResources.get(uri);
|
|
452
|
+
if (!resource) {
|
|
453
|
+
throw new Error(`Resource not found: ${uri}`);
|
|
454
|
+
}
|
|
455
|
+
return {
|
|
456
|
+
contents: [
|
|
457
|
+
{
|
|
458
|
+
uri,
|
|
459
|
+
mimeType: "text/html",
|
|
460
|
+
text: resource.definition.html
|
|
461
|
+
}
|
|
462
|
+
]
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
);
|
|
466
|
+
const transport = new stdio_js.StdioServerTransport();
|
|
467
|
+
await server.connect(transport);
|
|
468
|
+
return {
|
|
469
|
+
close: async () => {
|
|
470
|
+
await server.close();
|
|
471
|
+
}
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
function getUIResourceUri2(toolName, category) {
|
|
475
|
+
const name = toolName.replace(/^(view|action|data|tool):/, "");
|
|
476
|
+
return `pancake://ui/${category}/${name}`;
|
|
477
|
+
}
|
|
478
|
+
var init_stdio = __esm({
|
|
479
|
+
"src/server/stdio.ts"() {
|
|
480
|
+
}
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
// src/server/index.ts
|
|
484
|
+
var server_exports = {};
|
|
485
|
+
__export(server_exports, {
|
|
486
|
+
createServer: () => createServer
|
|
487
|
+
});
|
|
488
|
+
function generateRequestId() {
|
|
489
|
+
return `req_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 9)}`;
|
|
490
|
+
}
|
|
491
|
+
async function createServer(config) {
|
|
492
|
+
const app = express__default.default();
|
|
493
|
+
app.use(express__default.default.json());
|
|
494
|
+
if (config.config?.cors) {
|
|
495
|
+
const corsConfig = config.config.cors;
|
|
496
|
+
app.use((req, res, next) => {
|
|
497
|
+
const origin = corsConfig.origin;
|
|
498
|
+
if (origin === true) {
|
|
499
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
500
|
+
} else if (typeof origin === "string") {
|
|
501
|
+
res.setHeader("Access-Control-Allow-Origin", origin);
|
|
502
|
+
} else if (Array.isArray(origin)) {
|
|
503
|
+
const requestOrigin = req.headers.origin;
|
|
504
|
+
if (requestOrigin && origin.includes(requestOrigin)) {
|
|
505
|
+
res.setHeader("Access-Control-Allow-Origin", requestOrigin);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
if (corsConfig.credentials) {
|
|
509
|
+
res.setHeader("Access-Control-Allow-Credentials", "true");
|
|
510
|
+
}
|
|
511
|
+
if (corsConfig.methods) {
|
|
512
|
+
res.setHeader("Access-Control-Allow-Methods", corsConfig.methods.join(", "));
|
|
513
|
+
}
|
|
514
|
+
if (corsConfig.allowedHeaders) {
|
|
515
|
+
res.setHeader("Access-Control-Allow-Headers", corsConfig.allowedHeaders.join(", "));
|
|
516
|
+
}
|
|
517
|
+
if (req.method === "OPTIONS") {
|
|
518
|
+
res.status(204).end();
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
next();
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
if (isDevelopment() && config.config?.devServer) {
|
|
525
|
+
const viteProxy = createViteProxy(config.config.devServer);
|
|
526
|
+
app.use(viteProxy);
|
|
527
|
+
}
|
|
528
|
+
const uiRoutes = createUIRoutes(config.uiResources, config.config?.devServer);
|
|
529
|
+
app.use("/ui", uiRoutes);
|
|
530
|
+
const executeTool = async (toolName, input, metadata = {}) => {
|
|
531
|
+
const tool = config.tools.get(toolName);
|
|
532
|
+
if (!tool) {
|
|
533
|
+
throw new Error(`Unknown tool: ${toolName}`);
|
|
534
|
+
}
|
|
535
|
+
const ctx = {
|
|
536
|
+
requestId: generateRequestId(),
|
|
537
|
+
toolName,
|
|
538
|
+
metadata
|
|
539
|
+
};
|
|
540
|
+
const startTime = Date.now();
|
|
541
|
+
try {
|
|
542
|
+
const result = await config.middlewareChain.execute(
|
|
543
|
+
{ toolName, input, metadata },
|
|
544
|
+
() => tool.handler(input, ctx)
|
|
545
|
+
);
|
|
546
|
+
config.events.emit("tool:success", {
|
|
547
|
+
toolName,
|
|
548
|
+
result,
|
|
549
|
+
durationMs: Date.now() - startTime
|
|
550
|
+
});
|
|
551
|
+
return result;
|
|
552
|
+
} catch (error) {
|
|
553
|
+
config.events.emit("tool:error", {
|
|
554
|
+
toolName,
|
|
555
|
+
error,
|
|
556
|
+
durationMs: Date.now() - startTime
|
|
557
|
+
});
|
|
558
|
+
throw error;
|
|
559
|
+
}
|
|
560
|
+
};
|
|
561
|
+
const mcpRoute = config.config?.serverRoute ?? "/mcp";
|
|
562
|
+
const mcpHandler = createMcpHandler({
|
|
563
|
+
name: config.name,
|
|
564
|
+
version: config.version,
|
|
565
|
+
tools: config.tools,
|
|
566
|
+
uiResources: config.uiResources,
|
|
567
|
+
executeTool
|
|
568
|
+
});
|
|
569
|
+
app.post(mcpRoute, mcpHandler);
|
|
570
|
+
app.get("/health", (_req, res) => {
|
|
571
|
+
res.json({ status: "ok", name: config.name, version: config.version });
|
|
572
|
+
});
|
|
573
|
+
if (config.transport === "stdio") {
|
|
574
|
+
const { startStdioServer: startStdioServer2 } = await Promise.resolve().then(() => (init_stdio(), stdio_exports));
|
|
575
|
+
return startStdioServer2({
|
|
576
|
+
name: config.name,
|
|
577
|
+
version: config.version,
|
|
578
|
+
tools: config.tools,
|
|
579
|
+
uiResources: config.uiResources,
|
|
580
|
+
executeTool
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
return new Promise((resolve3) => {
|
|
584
|
+
const httpServer = app.listen(config.port, config.host, () => {
|
|
585
|
+
if (config.config?.debug) {
|
|
586
|
+
console.log(`Pancake server "${config.name}" running on http://${config.host}:${config.port}`);
|
|
587
|
+
console.log(` MCP endpoint: ${mcpRoute}`);
|
|
588
|
+
console.log(` UI endpoint: /ui/:viewName`);
|
|
589
|
+
console.log(` Tools registered: ${config.tools.size}`);
|
|
590
|
+
}
|
|
591
|
+
resolve3({
|
|
592
|
+
close: () => new Promise((resolveClose) => {
|
|
593
|
+
httpServer.close(() => resolveClose());
|
|
594
|
+
})
|
|
595
|
+
});
|
|
596
|
+
});
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
var init_server = __esm({
|
|
600
|
+
"src/server/index.ts"() {
|
|
601
|
+
init_mcp();
|
|
602
|
+
init_routes();
|
|
603
|
+
init_dev_proxy();
|
|
604
|
+
}
|
|
605
|
+
});
|
|
606
|
+
|
|
607
|
+
// src/view.ts
|
|
608
|
+
function isViewConfig(value) {
|
|
609
|
+
return typeof value === "object" && value !== null && "description" in value && "ui" in value;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// src/action.ts
|
|
613
|
+
function isActionConfig(value) {
|
|
614
|
+
return typeof value === "object" && value !== null && "description" in value && "input" in value && "output" in value && "handler" in value;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// src/data.ts
|
|
618
|
+
function isDataConfig(value) {
|
|
619
|
+
return typeof value === "object" && value !== null && "description" in value && "input" in value && "output" in value && "handler" in value && !("ui" in value);
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// src/tool.ts
|
|
623
|
+
function isToolConfig(value) {
|
|
624
|
+
return typeof value === "object" && value !== null && "name" in value && "description" in value && "input" in value && "output" in value && "handler" in value;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
// src/normalizers.ts
|
|
628
|
+
function toJsonSchema(schema) {
|
|
629
|
+
if (!schema) {
|
|
630
|
+
return { type: "object", properties: {} };
|
|
631
|
+
}
|
|
632
|
+
return zodToJsonSchema.zodToJsonSchema(schema);
|
|
633
|
+
}
|
|
634
|
+
function normalizeView(name, config) {
|
|
635
|
+
const toolName = `view:${name}`;
|
|
636
|
+
return {
|
|
637
|
+
name: toolName,
|
|
638
|
+
description: config.description,
|
|
639
|
+
inputSchema: toJsonSchema(config.input),
|
|
640
|
+
outputSchema: toJsonSchema(config.data),
|
|
641
|
+
handler: async (input, ctx) => {
|
|
642
|
+
if (config.handler) {
|
|
643
|
+
const validated = config.input ? config.input.parse(input) : input;
|
|
644
|
+
return config.handler(validated, {
|
|
645
|
+
...ctx,
|
|
646
|
+
viewName: name
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
return {};
|
|
650
|
+
},
|
|
651
|
+
ui: config.ui,
|
|
652
|
+
visibility: config.visibility ?? "both",
|
|
653
|
+
category: "view"
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
function normalizeAction(name, config) {
|
|
657
|
+
const toolName = `action:${name}`;
|
|
658
|
+
return {
|
|
659
|
+
name: toolName,
|
|
660
|
+
description: config.description,
|
|
661
|
+
inputSchema: toJsonSchema(config.input),
|
|
662
|
+
outputSchema: toJsonSchema(config.output),
|
|
663
|
+
handler: async (input, ctx) => {
|
|
664
|
+
const validated = config.input.parse(input);
|
|
665
|
+
return config.handler(validated, {
|
|
666
|
+
...ctx,
|
|
667
|
+
actionName: name
|
|
668
|
+
});
|
|
669
|
+
},
|
|
670
|
+
ui: config.ui,
|
|
671
|
+
visibility: config.visibility ?? "both",
|
|
672
|
+
category: "action"
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
function normalizeData(name, config) {
|
|
676
|
+
const toolName = `data:${name}`;
|
|
677
|
+
return {
|
|
678
|
+
name: toolName,
|
|
679
|
+
description: config.description,
|
|
680
|
+
inputSchema: toJsonSchema(config.input),
|
|
681
|
+
outputSchema: toJsonSchema(config.output),
|
|
682
|
+
handler: async (input, ctx) => {
|
|
683
|
+
const validated = config.input.parse(input);
|
|
684
|
+
return config.handler(validated, {
|
|
685
|
+
...ctx,
|
|
686
|
+
dataName: name
|
|
687
|
+
});
|
|
688
|
+
},
|
|
689
|
+
ui: void 0,
|
|
690
|
+
// Data fetchers don't have UI
|
|
691
|
+
visibility: config.visibility ?? "both",
|
|
692
|
+
category: "data"
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
function normalizeTool(name, config) {
|
|
696
|
+
return {
|
|
697
|
+
name: config.name || name,
|
|
698
|
+
description: config.description,
|
|
699
|
+
inputSchema: toJsonSchema(config.input),
|
|
700
|
+
outputSchema: toJsonSchema(config.output),
|
|
701
|
+
handler: async (input, ctx) => {
|
|
702
|
+
const validated = config.input.parse(input);
|
|
703
|
+
return config.handler(validated, ctx);
|
|
704
|
+
},
|
|
705
|
+
ui: config.ui,
|
|
706
|
+
visibility: config.visibility ?? "both",
|
|
707
|
+
category: "tool"
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
// src/app.ts
|
|
712
|
+
var TypedEventEmitter = class {
|
|
713
|
+
listeners = /* @__PURE__ */ new Map();
|
|
714
|
+
on(event, handler) {
|
|
715
|
+
const handlers = this.listeners.get(event) ?? /* @__PURE__ */ new Set();
|
|
716
|
+
handlers.add(handler);
|
|
717
|
+
this.listeners.set(event, handlers);
|
|
718
|
+
return () => handlers.delete(handler);
|
|
719
|
+
}
|
|
720
|
+
emit(event, payload) {
|
|
721
|
+
const handlers = this.listeners.get(event);
|
|
722
|
+
if (handlers) {
|
|
723
|
+
for (const handler of handlers) {
|
|
724
|
+
handler(payload);
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
};
|
|
729
|
+
var MiddlewareChain = class {
|
|
730
|
+
middlewares = [];
|
|
731
|
+
constructor(initial) {
|
|
732
|
+
if (initial) {
|
|
733
|
+
this.middlewares = [...initial];
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
add(middleware) {
|
|
737
|
+
this.middlewares.push(middleware);
|
|
738
|
+
}
|
|
739
|
+
async execute(ctx, handler) {
|
|
740
|
+
const state = /* @__PURE__ */ new Map();
|
|
741
|
+
const middlewareCtx = { ...ctx, state };
|
|
742
|
+
let index = 0;
|
|
743
|
+
let result;
|
|
744
|
+
const next = async () => {
|
|
745
|
+
if (index < this.middlewares.length) {
|
|
746
|
+
const mw = this.middlewares[index++];
|
|
747
|
+
await mw(middlewareCtx, next);
|
|
748
|
+
} else {
|
|
749
|
+
result = await handler();
|
|
750
|
+
}
|
|
751
|
+
};
|
|
752
|
+
await next();
|
|
753
|
+
return result;
|
|
754
|
+
}
|
|
755
|
+
};
|
|
756
|
+
var PluginManager = class {
|
|
757
|
+
constructor(plugins = []) {
|
|
758
|
+
this.plugins = plugins;
|
|
759
|
+
}
|
|
760
|
+
async runHook(hook, context) {
|
|
761
|
+
for (const plugin of this.plugins) {
|
|
762
|
+
const fn = plugin[hook];
|
|
763
|
+
if (typeof fn === "function") {
|
|
764
|
+
await fn.call(plugin, context);
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
};
|
|
769
|
+
function createApp(config) {
|
|
770
|
+
if (!config.name) {
|
|
771
|
+
throw new Error("App name is required");
|
|
772
|
+
}
|
|
773
|
+
if (!config.version) {
|
|
774
|
+
throw new Error("App version is required");
|
|
775
|
+
}
|
|
776
|
+
const events = new TypedEventEmitter();
|
|
777
|
+
const middlewareChain = new MiddlewareChain(config.middleware);
|
|
778
|
+
const pluginManager = new PluginManager(config.plugins);
|
|
779
|
+
const tools = /* @__PURE__ */ new Map();
|
|
780
|
+
const uiResources = /* @__PURE__ */ new Map();
|
|
781
|
+
for (const [name, viewConfig] of Object.entries(config.views ?? {})) {
|
|
782
|
+
const tool = normalizeView(name, viewConfig);
|
|
783
|
+
tools.set(tool.name, tool);
|
|
784
|
+
if (tool.ui) {
|
|
785
|
+
const uri = `pancake://ui/view/${name}`;
|
|
786
|
+
uiResources.set(uri, {
|
|
787
|
+
name,
|
|
788
|
+
uri,
|
|
789
|
+
definition: tool.ui
|
|
790
|
+
});
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
for (const [name, actionConfig] of Object.entries(config.actions ?? {})) {
|
|
794
|
+
const tool = normalizeAction(name, actionConfig);
|
|
795
|
+
tools.set(tool.name, tool);
|
|
796
|
+
if (tool.ui) {
|
|
797
|
+
const uri = `pancake://ui/action/${name}`;
|
|
798
|
+
uiResources.set(uri, {
|
|
799
|
+
name,
|
|
800
|
+
uri,
|
|
801
|
+
definition: tool.ui
|
|
802
|
+
});
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
for (const [name, dataConfig] of Object.entries(config.data ?? {})) {
|
|
806
|
+
const tool = normalizeData(name, dataConfig);
|
|
807
|
+
tools.set(tool.name, tool);
|
|
808
|
+
}
|
|
809
|
+
for (const [name, toolConfig] of Object.entries(config.tools ?? {})) {
|
|
810
|
+
const tool = normalizeTool(name, toolConfig);
|
|
811
|
+
tools.set(tool.name, tool);
|
|
812
|
+
if (tool.ui) {
|
|
813
|
+
const uri = `pancake://ui/tool/${name}`;
|
|
814
|
+
uiResources.set(uri, {
|
|
815
|
+
name,
|
|
816
|
+
uri,
|
|
817
|
+
definition: tool.ui
|
|
818
|
+
});
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
events.emit("app:init", { config });
|
|
822
|
+
let server = null;
|
|
823
|
+
const app = {
|
|
824
|
+
async start(options = {}) {
|
|
825
|
+
const port = options.port ?? 3e3;
|
|
826
|
+
const host = options.host ?? "0.0.0.0";
|
|
827
|
+
const transport = options.transport ?? "http";
|
|
828
|
+
for (const plugin of config.plugins ?? []) {
|
|
829
|
+
await pluginManager.runHook("onInit", { app: config, plugin });
|
|
830
|
+
}
|
|
831
|
+
const { createServer: createServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
|
|
832
|
+
const serverConfig = {
|
|
833
|
+
name: config.name,
|
|
834
|
+
version: config.version,
|
|
835
|
+
tools,
|
|
836
|
+
uiResources,
|
|
837
|
+
middlewareChain,
|
|
838
|
+
events,
|
|
839
|
+
port,
|
|
840
|
+
host,
|
|
841
|
+
transport
|
|
842
|
+
};
|
|
843
|
+
if (config.config) {
|
|
844
|
+
const cfg = {};
|
|
845
|
+
if (config.config.cors !== void 0) cfg.cors = config.config.cors;
|
|
846
|
+
if (config.config.debug !== void 0) cfg.debug = config.config.debug;
|
|
847
|
+
if (config.config.serverRoute !== void 0) cfg.serverRoute = config.config.serverRoute;
|
|
848
|
+
if (config.config.devServer !== void 0) cfg.devServer = config.config.devServer;
|
|
849
|
+
serverConfig.config = cfg;
|
|
850
|
+
}
|
|
851
|
+
server = await createServer2(serverConfig);
|
|
852
|
+
for (const plugin of config.plugins ?? []) {
|
|
853
|
+
await pluginManager.runHook("onStart", { app: config, plugin });
|
|
854
|
+
}
|
|
855
|
+
events.emit("app:start", { port, transport });
|
|
856
|
+
},
|
|
857
|
+
async stop() {
|
|
858
|
+
if (server) {
|
|
859
|
+
for (const plugin of config.plugins ?? []) {
|
|
860
|
+
await pluginManager.runHook("onShutdown", { app: config, plugin });
|
|
861
|
+
}
|
|
862
|
+
await server.close();
|
|
863
|
+
server = null;
|
|
864
|
+
events.emit("app:shutdown", { graceful: true });
|
|
865
|
+
}
|
|
866
|
+
},
|
|
867
|
+
handler() {
|
|
868
|
+
return async (_req, _res, next) => {
|
|
869
|
+
next();
|
|
870
|
+
};
|
|
871
|
+
},
|
|
872
|
+
async handleRequest(_req) {
|
|
873
|
+
return new Response("Not implemented", { status: 501 });
|
|
874
|
+
},
|
|
875
|
+
use(middleware) {
|
|
876
|
+
middlewareChain.add(middleware);
|
|
877
|
+
},
|
|
878
|
+
on(event, handler) {
|
|
879
|
+
return events.on(event, handler);
|
|
880
|
+
}
|
|
881
|
+
};
|
|
882
|
+
return app;
|
|
883
|
+
}
|
|
884
|
+
function discoverViews(dir) {
|
|
885
|
+
const views = {};
|
|
886
|
+
const absoluteDir = path2__namespace.resolve(process.cwd(), dir);
|
|
887
|
+
try {
|
|
888
|
+
const entries = fsSync__namespace.readdirSync(absoluteDir, { withFileTypes: true });
|
|
889
|
+
for (const entry of entries) {
|
|
890
|
+
if (entry.isDirectory()) {
|
|
891
|
+
const indexHtml = path2__namespace.join(absoluteDir, entry.name, "index.html");
|
|
892
|
+
const metadataJson = path2__namespace.join(absoluteDir, entry.name, "metadata.json");
|
|
893
|
+
if (fileExistsSync(indexHtml) && fileExistsSync(metadataJson)) {
|
|
894
|
+
const metadata = parseMetadataSync(metadataJson);
|
|
895
|
+
views[entry.name] = createViewFromDiscovery(entry.name, indexHtml, metadata);
|
|
896
|
+
}
|
|
897
|
+
} else if (entry.name.endsWith(".html")) {
|
|
898
|
+
const baseName = entry.name.replace(".html", "");
|
|
899
|
+
const metadataPath = path2__namespace.join(absoluteDir, `${baseName}.json`);
|
|
900
|
+
const htmlPath = path2__namespace.join(absoluteDir, entry.name);
|
|
901
|
+
if (fileExistsSync(metadataPath)) {
|
|
902
|
+
const metadata = parseMetadataSync(metadataPath);
|
|
903
|
+
views[baseName] = createViewFromDiscovery(baseName, htmlPath, metadata);
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
} catch (error) {
|
|
908
|
+
console.warn(`[Pancake] Could not discover views from ${dir}:`, error);
|
|
909
|
+
}
|
|
910
|
+
return views;
|
|
911
|
+
}
|
|
912
|
+
async function discoverViewsAsync(dir) {
|
|
913
|
+
const views = {};
|
|
914
|
+
const absoluteDir = path2__namespace.resolve(process.cwd(), dir);
|
|
915
|
+
try {
|
|
916
|
+
const entries = await fs2__namespace.readdir(absoluteDir, { withFileTypes: true });
|
|
917
|
+
for (const entry of entries) {
|
|
918
|
+
if (entry.isDirectory()) {
|
|
919
|
+
const indexHtml = path2__namespace.join(absoluteDir, entry.name, "index.html");
|
|
920
|
+
const metadataJson = path2__namespace.join(absoluteDir, entry.name, "metadata.json");
|
|
921
|
+
if (await fileExists(indexHtml) && await fileExists(metadataJson)) {
|
|
922
|
+
const metadata = await parseMetadata(metadataJson);
|
|
923
|
+
views[entry.name] = createViewFromDiscovery(entry.name, indexHtml, metadata);
|
|
924
|
+
}
|
|
925
|
+
} else if (entry.name.endsWith(".html")) {
|
|
926
|
+
const baseName = entry.name.replace(".html", "");
|
|
927
|
+
const metadataPath = path2__namespace.join(absoluteDir, `${baseName}.json`);
|
|
928
|
+
const htmlPath = path2__namespace.join(absoluteDir, entry.name);
|
|
929
|
+
if (await fileExists(metadataPath)) {
|
|
930
|
+
const metadata = await parseMetadata(metadataPath);
|
|
931
|
+
views[baseName] = createViewFromDiscovery(baseName, htmlPath, metadata);
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
} catch (error) {
|
|
936
|
+
console.warn(`[Pancake] Could not discover views from ${dir}:`, error);
|
|
937
|
+
}
|
|
938
|
+
return views;
|
|
939
|
+
}
|
|
940
|
+
async function fileExists(filePath) {
|
|
941
|
+
try {
|
|
942
|
+
await fs2__namespace.access(filePath);
|
|
943
|
+
return true;
|
|
944
|
+
} catch {
|
|
945
|
+
return false;
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
function fileExistsSync(filePath) {
|
|
949
|
+
try {
|
|
950
|
+
fsSync__namespace.accessSync(filePath);
|
|
951
|
+
return true;
|
|
952
|
+
} catch {
|
|
953
|
+
return false;
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
async function parseMetadata(filePath) {
|
|
957
|
+
const content = await fs2__namespace.readFile(filePath, "utf-8");
|
|
958
|
+
return JSON.parse(content);
|
|
959
|
+
}
|
|
960
|
+
function parseMetadataSync(filePath) {
|
|
961
|
+
const content = fsSync__namespace.readFileSync(filePath, "utf-8");
|
|
962
|
+
return JSON.parse(content);
|
|
963
|
+
}
|
|
964
|
+
function createViewFromDiscovery(name, htmlPath, metadata) {
|
|
965
|
+
return {
|
|
966
|
+
description: metadata.description,
|
|
967
|
+
// Note: input/data from JSON are JSON Schema, not Zod
|
|
968
|
+
// We'll need to handle this specially in the normalizer
|
|
969
|
+
visibility: metadata.visibility ?? "both",
|
|
970
|
+
ui: {
|
|
971
|
+
html: htmlPath,
|
|
972
|
+
name
|
|
973
|
+
}
|
|
974
|
+
};
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
exports.createApp = createApp;
|
|
978
|
+
exports.discoverViews = discoverViews;
|
|
979
|
+
exports.discoverViewsAsync = discoverViewsAsync;
|
|
980
|
+
exports.isActionConfig = isActionConfig;
|
|
981
|
+
exports.isDataConfig = isDataConfig;
|
|
982
|
+
exports.isToolConfig = isToolConfig;
|
|
983
|
+
exports.isViewConfig = isViewConfig;
|
|
984
|
+
//# sourceMappingURL=index.cjs.map
|
|
985
|
+
//# sourceMappingURL=index.cjs.map
|