@pancake-apps/server 0.0.3 → 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,172 @@
1
+ // src/utils/metadata.ts
2
+ function mapVisibilityToMcp(visibility) {
3
+ switch (visibility) {
4
+ case "model":
5
+ return ["model"];
6
+ case "app":
7
+ return ["app"];
8
+ case "both":
9
+ default:
10
+ return ["model", "app"];
11
+ }
12
+ }
13
+ function mapVisibilityToOpenAI(visibility) {
14
+ switch (visibility) {
15
+ case "model":
16
+ return { "openai/visibility": "public", "openai/widgetAccessible": false };
17
+ case "app":
18
+ return { "openai/visibility": "private", "openai/widgetAccessible": true };
19
+ case "both":
20
+ default:
21
+ return { "openai/visibility": "public", "openai/widgetAccessible": true };
22
+ }
23
+ }
24
+ function mapVisibilityToAudience(visibility) {
25
+ switch (visibility) {
26
+ case "model":
27
+ return ["assistant"];
28
+ case "app":
29
+ return ["user"];
30
+ case "both":
31
+ default:
32
+ return ["assistant", "user"];
33
+ }
34
+ }
35
+
36
+ // src/utils/csp.ts
37
+ function generateMcpCSPMetadata(csp) {
38
+ const result = {};
39
+ if (csp.connectDomains && csp.connectDomains.length > 0) {
40
+ result.connectDomains = csp.connectDomains;
41
+ }
42
+ if (csp.resourceDomains && csp.resourceDomains.length > 0) {
43
+ result.resourceDomains = csp.resourceDomains;
44
+ }
45
+ if (csp.scriptDomains && csp.scriptDomains.length > 0) {
46
+ result.scriptDomains = csp.scriptDomains;
47
+ }
48
+ return result;
49
+ }
50
+ function generateOpenAICSPMetadata(csp) {
51
+ const result = {};
52
+ if (csp.connectDomains && csp.connectDomains.length > 0) {
53
+ result.connect_domains = csp.connectDomains;
54
+ }
55
+ if (csp.resourceDomains && csp.resourceDomains.length > 0) {
56
+ result.resource_domains = csp.resourceDomains;
57
+ }
58
+ if (csp.scriptDomains && csp.scriptDomains.length > 0) {
59
+ result.script_domains = csp.scriptDomains;
60
+ }
61
+ return result;
62
+ }
63
+
64
+ // src/adapters/mcp.ts
65
+ var McpAdapter = class {
66
+ /**
67
+ * Build tool metadata for MCP protocol
68
+ */
69
+ buildToolMeta(tool, uiUri) {
70
+ const visibility = mapVisibilityToMcp(tool.visibility);
71
+ const uiMeta = {
72
+ visibility,
73
+ ...uiUri ? { resourceUri: uiUri } : {}
74
+ };
75
+ const annotations = {
76
+ audience: mapVisibilityToAudience(tool.visibility)
77
+ };
78
+ const meta = {
79
+ ui: uiMeta,
80
+ "ui/visibility": visibility,
81
+ ...uiUri ? { "ui/resourceUri": uiUri } : {}
82
+ };
83
+ return {
84
+ annotations,
85
+ _meta: meta
86
+ };
87
+ }
88
+ /**
89
+ * Build UI resource metadata for MCP protocol
90
+ */
91
+ buildUIResourceMeta(uiDef) {
92
+ const uiMeta = {};
93
+ if (uiDef.csp) {
94
+ const cspMetadata = generateMcpCSPMetadata(uiDef.csp);
95
+ if (Object.keys(cspMetadata).length > 0) {
96
+ uiMeta.csp = cspMetadata;
97
+ }
98
+ }
99
+ if (uiDef.prefersBorder !== void 0) {
100
+ uiMeta.prefersBorder = uiDef.prefersBorder;
101
+ }
102
+ if (uiDef.autoResize !== void 0) {
103
+ uiMeta.autoResize = uiDef.autoResize;
104
+ }
105
+ if (uiDef.domain) {
106
+ uiMeta.domain = uiDef.domain;
107
+ }
108
+ const result = {
109
+ mimeType: "text/html;profile=mcp-app"
110
+ };
111
+ if (Object.keys(uiMeta).length > 0) {
112
+ result._meta = { ui: uiMeta };
113
+ }
114
+ return result;
115
+ }
116
+ };
117
+
118
+ // src/adapters/openai.ts
119
+ var OpenAIAdapter = class {
120
+ /**
121
+ * Build tool metadata for OpenAI protocol
122
+ */
123
+ buildToolMeta(tool, uiUri) {
124
+ const meta = {};
125
+ const visibilitySettings = mapVisibilityToOpenAI(tool.visibility);
126
+ Object.assign(meta, visibilitySettings);
127
+ if (uiUri) {
128
+ meta["openai/outputTemplate"] = uiUri;
129
+ }
130
+ const annotations = {
131
+ audience: mapVisibilityToAudience(tool.visibility)
132
+ };
133
+ return {
134
+ annotations,
135
+ _meta: Object.keys(meta).length > 0 ? meta : void 0
136
+ };
137
+ }
138
+ /**
139
+ * Build UI resource metadata for OpenAI protocol
140
+ */
141
+ buildUIResourceMeta(uiDef) {
142
+ const meta = {};
143
+ if (uiDef.csp) {
144
+ const cspMetadata = generateOpenAICSPMetadata(uiDef.csp);
145
+ if (Object.keys(cspMetadata).length > 0) {
146
+ meta["openai/widgetCSP"] = cspMetadata;
147
+ }
148
+ }
149
+ if (uiDef.prefersBorder !== void 0) {
150
+ meta["openai/widgetPrefersBorder"] = uiDef.prefersBorder;
151
+ }
152
+ if (uiDef.domain) {
153
+ meta["openai/widgetDomain"] = uiDef.domain;
154
+ }
155
+ const result = {
156
+ mimeType: "text/html+skybridge"
157
+ };
158
+ if (Object.keys(meta).length > 0) {
159
+ result._meta = meta;
160
+ }
161
+ return result;
162
+ }
163
+ };
164
+
165
+ // src/adapters/index.ts
166
+ function createAdapter(protocol) {
167
+ return protocol === "openai" ? new OpenAIAdapter() : new McpAdapter();
168
+ }
169
+
170
+ export { createAdapter };
171
+ //# sourceMappingURL=chunk-CVG3DAN6.js.map
172
+ //# sourceMappingURL=chunk-CVG3DAN6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/metadata.ts","../src/utils/csp.ts","../src/adapters/mcp.ts","../src/adapters/openai.ts","../src/adapters/index.ts"],"names":[],"mappings":";AA2BO,SAAS,mBAAmB,UAAA,EAA6C;AAC9E,EAAA,QAAQ,UAAA;AAAY,IAClB,KAAK,OAAA;AACH,MAAA,OAAO,CAAC,OAAO,CAAA;AAAA,IACjB,KAAK,KAAA;AACH,MAAA,OAAO,CAAC,KAAK,CAAA;AAAA,IACf,KAAK,MAAA;AAAA,IACL;AACE,MAAA,OAAO,CAAC,SAAS,KAAK,CAAA;AAAA;AAE5B;AA0BO,SAAS,sBAAsB,UAAA,EAAmD;AACvF,EAAA,QAAQ,UAAA;AAAY,IAClB,KAAK,OAAA;AACH,MAAA,OAAO,EAAE,mBAAA,EAAqB,QAAA,EAAU,yBAAA,EAA2B,KAAA,EAAM;AAAA,IAC3E,KAAK,KAAA;AACH,MAAA,OAAO,EAAE,mBAAA,EAAqB,SAAA,EAAW,yBAAA,EAA2B,IAAA,EAAK;AAAA,IAC3E,KAAK,MAAA;AAAA,IACL;AACE,MAAA,OAAO,EAAE,mBAAA,EAAqB,QAAA,EAAU,yBAAA,EAA2B,IAAA,EAAK;AAAA;AAE9E;AAcO,SAAS,wBAAwB,UAAA,EAAmC;AACzE,EAAA,QAAQ,UAAA;AAAY,IAClB,KAAK,OAAA;AACH,MAAA,OAAO,CAAC,WAAW,CAAA;AAAA,IACrB,KAAK,KAAA;AACH,MAAA,OAAO,CAAC,MAAM,CAAA;AAAA,IAChB,KAAK,MAAA;AAAA,IACL;AACE,MAAA,OAAO,CAAC,aAAa,MAAM,CAAA;AAAA;AAEjC;;;ACtEO,SAAS,uBAAuB,GAAA,EAA4C;AACjF,EAAA,MAAM,SAAyB,EAAC;AAEhC,EAAA,IAAI,GAAA,CAAI,cAAA,IAAkB,GAAA,CAAI,cAAA,CAAe,SAAS,CAAA,EAAG;AACvD,IAAA,MAAA,CAAO,iBAAiB,GAAA,CAAI,cAAA;AAAA,EAC9B;AAEA,EAAA,IAAI,GAAA,CAAI,eAAA,IAAmB,GAAA,CAAI,eAAA,CAAgB,SAAS,CAAA,EAAG;AACzD,IAAA,MAAA,CAAO,kBAAkB,GAAA,CAAI,eAAA;AAAA,EAC/B;AAEA,EAAA,IAAI,GAAA,CAAI,aAAA,IAAiB,GAAA,CAAI,aAAA,CAAc,SAAS,CAAA,EAAG;AACrD,IAAA,MAAA,CAAO,gBAAgB,GAAA,CAAI,aAAA;AAAA,EAC7B;AAEA,EAAA,OAAO,MAAA;AACT;AAoBO,SAAS,0BAA0B,GAAA,EAA+C;AACvF,EAAA,MAAM,SAA4B,EAAC;AAEnC,EAAA,IAAI,GAAA,CAAI,cAAA,IAAkB,GAAA,CAAI,cAAA,CAAe,SAAS,CAAA,EAAG;AACvD,IAAA,MAAA,CAAO,kBAAkB,GAAA,CAAI,cAAA;AAAA,EAC/B;AAEA,EAAA,IAAI,GAAA,CAAI,eAAA,IAAmB,GAAA,CAAI,eAAA,CAAgB,SAAS,CAAA,EAAG;AACzD,IAAA,MAAA,CAAO,mBAAmB,GAAA,CAAI,eAAA;AAAA,EAChC;AAEA,EAAA,IAAI,GAAA,CAAI,aAAA,IAAiB,GAAA,CAAI,aAAA,CAAc,SAAS,CAAA,EAAG;AACrD,IAAA,MAAA,CAAO,iBAAiB,GAAA,CAAI,aAAA;AAAA,EAC9B;AAEA,EAAA,OAAO,MAAA;AACT;;;ACrDO,IAAM,aAAN,MAA4C;AAAA;AAAA;AAAA;AAAA,EAIjD,aAAA,CAAc,MAAoB,KAAA,EAAgC;AAChE,IAAA,MAAM,UAAA,GAAa,kBAAA,CAAmB,IAAA,CAAK,UAAU,CAAA;AACrD,IAAA,MAAM,MAAA,GAAkC;AAAA,MACtC,UAAA;AAAA,MACA,GAAI,KAAA,GAAQ,EAAE,WAAA,EAAa,KAAA,KAAU;AAAC,KACxC;AAGA,IAAA,MAAM,WAAA,GAAuC;AAAA,MAC3C,QAAA,EAAU,uBAAA,CAAwB,IAAA,CAAK,UAAU;AAAA,KACnD;AAKA,IAAA,MAAM,IAAA,GAAgC;AAAA,MACpC,EAAA,EAAI,MAAA;AAAA,MACJ,eAAA,EAAiB,UAAA;AAAA,MACjB,GAAI,KAAA,GAAQ,EAAE,gBAAA,EAAkB,KAAA,KAAU;AAAC,KAC7C;AAEA,IAAA,OAAO;AAAA,MACL,WAAA;AAAA,MACA,KAAA,EAAO;AAAA,KACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,oBAAoB,KAAA,EAA2C;AAC7D,IAAA,MAAM,SAAkC,EAAC;AAGzC,IAAA,IAAI,MAAM,GAAA,EAAK;AACb,MAAA,MAAM,WAAA,GAAc,sBAAA,CAAuB,KAAA,CAAM,GAAG,CAAA;AACpD,MAAA,IAAI,MAAA,CAAO,IAAA,CAAK,WAAW,CAAA,CAAE,SAAS,CAAA,EAAG;AACvC,QAAA,MAAA,CAAO,GAAA,GAAM,WAAA;AAAA,MACf;AAAA,IACF;AAGA,IAAA,IAAI,KAAA,CAAM,kBAAkB,MAAA,EAAW;AACrC,MAAA,MAAA,CAAO,gBAAgB,KAAA,CAAM,aAAA;AAAA,IAC/B;AAGA,IAAA,IAAI,KAAA,CAAM,eAAe,MAAA,EAAW;AAClC,MAAA,MAAA,CAAO,aAAa,KAAA,CAAM,UAAA;AAAA,IAC5B;AAGA,IAAA,IAAI,MAAM,MAAA,EAAQ;AAChB,MAAA,MAAA,CAAO,SAAS,KAAA,CAAM,MAAA;AAAA,IACxB;AAEA,IAAA,MAAM,MAAA,GAA+B;AAAA,MACnC,QAAA,EAAU;AAAA,KACZ;AAEA,IAAA,IAAI,MAAA,CAAO,IAAA,CAAK,MAAM,CAAA,CAAE,SAAS,CAAA,EAAG;AAClC,MAAA,MAAA,CAAO,KAAA,GAAQ,EAAE,EAAA,EAAI,MAAA,EAAO;AAAA,IAC9B;AAEA,IAAA,OAAO,MAAA;AAAA,EACT;AACF,CAAA;;;ACtEO,IAAM,gBAAN,MAA+C;AAAA;AAAA;AAAA;AAAA,EAIpD,aAAA,CAAc,MAAoB,KAAA,EAAgC;AAChE,IAAA,MAAM,OAAgC,EAAC;AAGvC,IAAA,MAAM,kBAAA,GAAqB,qBAAA,CAAsB,IAAA,CAAK,UAAU,CAAA;AAChE,IAAA,MAAA,CAAO,MAAA,CAAO,MAAM,kBAAkB,CAAA;AAGtC,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,IAAA,CAAK,uBAAuB,CAAA,GAAI,KAAA;AAAA,IAClC;AAGA,IAAA,MAAM,WAAA,GAAuC;AAAA,MAC3C,QAAA,EAAU,uBAAA,CAAwB,IAAA,CAAK,UAAU;AAAA,KACnD;AAEA,IAAA,OAAO;AAAA,MACL,WAAA;AAAA,MACA,OAAO,MAAA,CAAO,IAAA,CAAK,IAAI,CAAA,CAAE,MAAA,GAAS,IAAI,IAAA,GAAO;AAAA,KAC/C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,oBAAoB,KAAA,EAA2C;AAC7D,IAAA,MAAM,OAAgC,EAAC;AAGvC,IAAA,IAAI,MAAM,GAAA,EAAK;AACb,MAAA,MAAM,WAAA,GAAc,yBAAA,CAA0B,KAAA,CAAM,GAAG,CAAA;AACvD,MAAA,IAAI,MAAA,CAAO,IAAA,CAAK,WAAW,CAAA,CAAE,SAAS,CAAA,EAAG;AACvC,QAAA,IAAA,CAAK,kBAAkB,CAAA,GAAI,WAAA;AAAA,MAC7B;AAAA,IACF;AAGA,IAAA,IAAI,KAAA,CAAM,kBAAkB,MAAA,EAAW;AACrC,MAAA,IAAA,CAAK,4BAA4B,IAAI,KAAA,CAAM,aAAA;AAAA,IAC7C;AAGA,IAAA,IAAI,MAAM,MAAA,EAAQ;AAChB,MAAA,IAAA,CAAK,qBAAqB,IAAI,KAAA,CAAM,MAAA;AAAA,IACtC;AAEA,IAAA,MAAM,MAAA,GAA+B;AAAA,MACnC,QAAA,EAAU;AAAA,KACZ;AAEA,IAAA,IAAI,MAAA,CAAO,IAAA,CAAK,IAAI,CAAA,CAAE,SAAS,CAAA,EAAG;AAChC,MAAA,MAAA,CAAO,KAAA,GAAQ,IAAA;AAAA,IACjB;AAEA,IAAA,OAAO,MAAA;AAAA,EACT;AACF,CAAA;;;AC5DO,SAAS,cAAc,QAAA,EAAqC;AACjE,EAAA,OAAO,aAAa,QAAA,GAAW,IAAI,aAAA,EAAc,GAAI,IAAI,UAAA,EAAW;AACtE","file":"chunk-CVG3DAN6.js","sourcesContent":["/**\n * Protocol metadata utilities\n *\n * Provides utilities for mapping tool definitions to protocol-specific metadata\n * formats for MCP Apps and OpenAI/ChatGPT Apps.\n */\n\nimport type { Visibility } from '../types/protocol.js';\n\n// =============================================================================\n// MCP VISIBILITY MAPPING\n// =============================================================================\n\n/**\n * MCP visibility value\n * Array of who can invoke: \"model\", \"app\", or both\n */\nexport type McpVisibilityValue = ('model' | 'app')[];\n\n/**\n * Map visibility to MCP protocol format\n *\n * Visibility mappings:\n * - \"both\" (default): [\"model\", \"app\"] - Tool accessible to both model and UI\n * - \"model\": [\"model\"] - Tool only accessible to the model\n * - \"app\": [\"app\"] - Tool only accessible to the UI\n */\nexport function mapVisibilityToMcp(visibility?: Visibility): McpVisibilityValue {\n switch (visibility) {\n case 'model':\n return ['model'];\n case 'app':\n return ['app'];\n case 'both':\n default:\n return ['model', 'app'];\n }\n}\n\n// =============================================================================\n// OPENAI VISIBILITY MAPPING\n// =============================================================================\n\n/**\n * OpenAI visibility settings with proper openai/ prefixed keys\n *\n * Settings:\n * - openai/visibility: \"public\" | \"private\" - Controls model access\n * - openai/widgetAccessible: boolean - Controls UI access\n */\nexport interface OpenAIVisibilitySettings {\n 'openai/visibility': 'public' | 'private';\n 'openai/widgetAccessible': boolean;\n}\n\n/**\n * Map visibility to OpenAI/ChatGPT protocol settings\n *\n * Visibility mappings:\n * - \"both\" (default): visibility=\"public\", widgetAccessible=true\n * - \"model\": visibility=\"public\", widgetAccessible=false\n * - \"app\": visibility=\"private\", widgetAccessible=true\n */\nexport function mapVisibilityToOpenAI(visibility?: Visibility): OpenAIVisibilitySettings {\n switch (visibility) {\n case 'model':\n return { 'openai/visibility': 'public', 'openai/widgetAccessible': false };\n case 'app':\n return { 'openai/visibility': 'private', 'openai/widgetAccessible': true };\n case 'both':\n default:\n return { 'openai/visibility': 'public', 'openai/widgetAccessible': true };\n }\n}\n\n// =============================================================================\n// MCP AUDIENCE MAPPING (for annotations)\n// =============================================================================\n\n/**\n * Map visibility to MCP audience format for annotations\n *\n * Visibility mappings:\n * - \"both\" (default): [\"assistant\", \"user\"]\n * - \"model\": [\"assistant\"]\n * - \"app\": [\"user\"]\n */\nexport function mapVisibilityToAudience(visibility?: Visibility): string[] {\n switch (visibility) {\n case 'model':\n return ['assistant'];\n case 'app':\n return ['user'];\n case 'both':\n default:\n return ['assistant', 'user'];\n }\n}\n","/**\n * CSP (Content Security Policy) utilities\n *\n * Provides utilities for mapping CSP configuration to protocol-specific formats\n * for MCP Apps and OpenAI/ChatGPT Apps.\n */\n\nimport type { ContentSecurityPolicy } from '../types/protocol.js';\n\n// =============================================================================\n// MCP CSP METADATA\n// =============================================================================\n\n/**\n * MCP CSP metadata format (camelCase)\n */\nexport interface McpCSPMetadata {\n connectDomains?: string[];\n resourceDomains?: string[];\n scriptDomains?: string[];\n}\n\n/**\n * Generate CSP metadata for MCP Apps protocol\n *\n * MCP Apps use camelCase field names.\n */\nexport function generateMcpCSPMetadata(csp: ContentSecurityPolicy): McpCSPMetadata {\n const result: McpCSPMetadata = {};\n\n if (csp.connectDomains && csp.connectDomains.length > 0) {\n result.connectDomains = csp.connectDomains;\n }\n\n if (csp.resourceDomains && csp.resourceDomains.length > 0) {\n result.resourceDomains = csp.resourceDomains;\n }\n\n if (csp.scriptDomains && csp.scriptDomains.length > 0) {\n result.scriptDomains = csp.scriptDomains;\n }\n\n return result;\n}\n\n// =============================================================================\n// OPENAI CSP METADATA\n// =============================================================================\n\n/**\n * OpenAI CSP metadata format (snake_case)\n */\nexport interface OpenAICSPMetadata {\n connect_domains?: string[];\n resource_domains?: string[];\n script_domains?: string[];\n}\n\n/**\n * Generate CSP metadata for OpenAI/ChatGPT Apps protocol\n *\n * ChatGPT Apps use snake_case field names.\n */\nexport function generateOpenAICSPMetadata(csp: ContentSecurityPolicy): OpenAICSPMetadata {\n const result: OpenAICSPMetadata = {};\n\n if (csp.connectDomains && csp.connectDomains.length > 0) {\n result.connect_domains = csp.connectDomains;\n }\n\n if (csp.resourceDomains && csp.resourceDomains.length > 0) {\n result.resource_domains = csp.resourceDomains;\n }\n\n if (csp.scriptDomains && csp.scriptDomains.length > 0) {\n result.script_domains = csp.scriptDomains;\n }\n\n return result;\n}\n","/**\n * MCP Protocol Adapter\n *\n * Handles metadata generation for MCP Apps protocol.\n * Uses camelCase naming and _meta.ui.* namespace.\n */\n\nimport type { InternalTool } from '../types/tool.js';\nimport type { UIDefinition } from '../types/protocol.js';\nimport type { ProtocolAdapter, ToolMetaResult, UIResourceMetaResult } from './types.js';\nimport { mapVisibilityToMcp, mapVisibilityToAudience } from '../utils/metadata.js';\nimport { generateMcpCSPMetadata } from '../utils/csp.js';\n\n// =============================================================================\n// MCP ADAPTER\n// =============================================================================\n\n/**\n * MCP protocol adapter implementation\n *\n * Generates metadata in MCP Apps format:\n * - Visibility as array: [\"model\"], [\"app\"], or [\"model\", \"app\"]\n * - Metadata under _meta.ui.* namespace\n * - MIME type: text/html;profile=mcp-app\n * - CSP with camelCase keys (connectDomains, resourceDomains)\n */\nexport class McpAdapter implements ProtocolAdapter {\n /**\n * Build tool metadata for MCP protocol\n */\n buildToolMeta(tool: InternalTool, uiUri?: string): ToolMetaResult {\n const visibility = mapVisibilityToMcp(tool.visibility);\n const uiMeta: Record<string, unknown> = {\n visibility,\n ...(uiUri ? { resourceUri: uiUri } : {}),\n };\n\n // Build annotations with audience\n const annotations: Record<string, unknown> = {\n audience: mapVisibilityToAudience(tool.visibility),\n };\n\n // Provide both nested and flat shapes for compatibility:\n // - ext-apps / MCP Apps uses nested `_meta.ui.resourceUri`\n // - Some inspectors use flat `_meta[\"ui/resourceUri\"]` key\n const meta: Record<string, unknown> = {\n ui: uiMeta,\n 'ui/visibility': visibility,\n ...(uiUri ? { 'ui/resourceUri': uiUri } : {}),\n };\n\n return {\n annotations,\n _meta: meta,\n };\n }\n\n /**\n * Build UI resource metadata for MCP protocol\n */\n buildUIResourceMeta(uiDef: UIDefinition): UIResourceMetaResult {\n const uiMeta: Record<string, unknown> = {};\n\n // Add CSP metadata if specified\n if (uiDef.csp) {\n const cspMetadata = generateMcpCSPMetadata(uiDef.csp);\n if (Object.keys(cspMetadata).length > 0) {\n uiMeta.csp = cspMetadata;\n }\n }\n\n // Add prefersBorder if specified\n if (uiDef.prefersBorder !== undefined) {\n uiMeta.prefersBorder = uiDef.prefersBorder;\n }\n\n // Add autoResize if specified\n if (uiDef.autoResize !== undefined) {\n uiMeta.autoResize = uiDef.autoResize;\n }\n\n // Add domain if specified\n if (uiDef.domain) {\n uiMeta.domain = uiDef.domain;\n }\n\n const result: UIResourceMetaResult = {\n mimeType: 'text/html;profile=mcp-app',\n };\n\n if (Object.keys(uiMeta).length > 0) {\n result._meta = { ui: uiMeta };\n }\n\n return result;\n }\n}\n","/**\n * OpenAI Protocol Adapter\n *\n * Handles metadata generation for OpenAI/ChatGPT Apps protocol.\n * Uses snake_case naming and openai/* prefixed keys.\n */\n\nimport type { InternalTool } from '../types/tool.js';\nimport type { UIDefinition } from '../types/protocol.js';\nimport type { ProtocolAdapter, ToolMetaResult, UIResourceMetaResult } from './types.js';\nimport { mapVisibilityToOpenAI, mapVisibilityToAudience } from '../utils/metadata.js';\nimport { generateOpenAICSPMetadata } from '../utils/csp.js';\n\n// =============================================================================\n// OPENAI ADAPTER\n// =============================================================================\n\n/**\n * OpenAI protocol adapter implementation\n *\n * Generates metadata in OpenAI/ChatGPT Apps format:\n * - Visibility as openai/visibility (\"public\"/\"private\") + openai/widgetAccessible\n * - Metadata with openai/* prefixed keys\n * - MIME type: text/html+skybridge\n * - CSP with snake_case keys (connect_domains, resource_domains, etc.)\n */\nexport class OpenAIAdapter implements ProtocolAdapter {\n /**\n * Build tool metadata for OpenAI protocol\n */\n buildToolMeta(tool: InternalTool, uiUri?: string): ToolMetaResult {\n const meta: Record<string, unknown> = {};\n\n // Add visibility settings with openai/ prefixes\n const visibilitySettings = mapVisibilityToOpenAI(tool.visibility);\n Object.assign(meta, visibilitySettings);\n\n // Add UI binding with OpenAI prefix\n if (uiUri) {\n meta['openai/outputTemplate'] = uiUri;\n }\n\n // Build annotations with audience (same as MCP)\n const annotations: Record<string, unknown> = {\n audience: mapVisibilityToAudience(tool.visibility),\n };\n\n return {\n annotations,\n _meta: Object.keys(meta).length > 0 ? meta : undefined,\n };\n }\n\n /**\n * Build UI resource metadata for OpenAI protocol\n */\n buildUIResourceMeta(uiDef: UIDefinition): UIResourceMetaResult {\n const meta: Record<string, unknown> = {};\n\n // Add CSP metadata with openai/ prefix\n if (uiDef.csp) {\n const cspMetadata = generateOpenAICSPMetadata(uiDef.csp);\n if (Object.keys(cspMetadata).length > 0) {\n meta['openai/widgetCSP'] = cspMetadata;\n }\n }\n\n // Add prefersBorder with openai/ prefix\n if (uiDef.prefersBorder !== undefined) {\n meta['openai/widgetPrefersBorder'] = uiDef.prefersBorder;\n }\n\n // Add domain with openai/ prefix\n if (uiDef.domain) {\n meta['openai/widgetDomain'] = uiDef.domain;\n }\n\n const result: UIResourceMetaResult = {\n mimeType: 'text/html+skybridge',\n };\n\n if (Object.keys(meta).length > 0) {\n result._meta = meta;\n }\n\n return result;\n }\n}\n","/**\n * Protocol adapters module\n *\n * Provides adapter factory and exports for protocol-specific metadata generation.\n */\n\nimport type { Protocol } from '../types/protocol.js';\nimport type { ProtocolAdapter } from './types.js';\nimport { McpAdapter } from './mcp.js';\nimport { OpenAIAdapter } from './openai.js';\n\n// =============================================================================\n// ADAPTER FACTORY\n// =============================================================================\n\n/**\n * Create a protocol adapter for the specified protocol\n *\n * @param protocol - Target protocol (\"mcp\" | \"openai\")\n * @returns Protocol-specific adapter instance\n *\n * @example\n * ```typescript\n * const adapter = createAdapter(\"openai\");\n * const toolMeta = adapter.buildToolMeta(tool, uiUri);\n * ```\n */\nexport function createAdapter(protocol: Protocol): ProtocolAdapter {\n return protocol === 'openai' ? new OpenAIAdapter() : new McpAdapter();\n}\n\n// =============================================================================\n// EXPORTS\n// =============================================================================\n\nexport type { ProtocolAdapter, ToolMetaResult, UIResourceMetaResult } from './types.js';\nexport { McpAdapter } from './mcp.js';\nexport { OpenAIAdapter } from './openai.js';\n"]}