nitrostack 1.0.55 → 1.0.57

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.
Files changed (222) hide show
  1. package/dist/cli/commands/init.d.ts.map +1 -1
  2. package/dist/cli/commands/init.js +14 -9
  3. package/dist/cli/commands/init.js.map +1 -1
  4. package/dist/widgets/hooks/index.d.ts +7 -0
  5. package/dist/widgets/hooks/index.d.ts.map +1 -0
  6. package/dist/widgets/hooks/index.js +7 -0
  7. package/dist/widgets/hooks/index.js.map +1 -0
  8. package/dist/widgets/hooks/use-display-mode.d.ts +11 -0
  9. package/dist/widgets/hooks/use-display-mode.d.ts.map +1 -0
  10. package/dist/widgets/hooks/use-display-mode.js +13 -0
  11. package/dist/widgets/hooks/use-display-mode.js.map +1 -0
  12. package/dist/widgets/hooks/use-max-height.d.ts +10 -0
  13. package/dist/widgets/hooks/use-max-height.d.ts.map +1 -0
  14. package/dist/widgets/hooks/use-max-height.js +13 -0
  15. package/dist/widgets/hooks/use-max-height.js.map +1 -0
  16. package/dist/widgets/hooks/use-openai-global.d.ts +12 -0
  17. package/dist/widgets/hooks/use-openai-global.d.ts.map +1 -0
  18. package/dist/widgets/hooks/use-openai-global.js +32 -0
  19. package/dist/widgets/hooks/use-openai-global.js.map +1 -0
  20. package/dist/widgets/hooks/use-theme.d.ts +10 -0
  21. package/dist/widgets/hooks/use-theme.d.ts.map +1 -0
  22. package/dist/widgets/hooks/use-theme.js +12 -0
  23. package/dist/widgets/hooks/use-theme.js.map +1 -0
  24. package/dist/widgets/hooks/use-widget-state.d.ts +18 -0
  25. package/dist/widgets/hooks/use-widget-state.d.ts.map +1 -0
  26. package/dist/widgets/hooks/use-widget-state.js +27 -0
  27. package/dist/widgets/hooks/use-widget-state.js.map +1 -0
  28. package/dist/widgets/hooks/useWidgetSDK.d.ts +47 -0
  29. package/dist/widgets/hooks/useWidgetSDK.d.ts.map +1 -0
  30. package/dist/widgets/hooks/useWidgetSDK.js +67 -0
  31. package/dist/widgets/hooks/useWidgetSDK.js.map +1 -0
  32. package/dist/widgets/index.d.ts +7 -1
  33. package/dist/widgets/index.d.ts.map +1 -1
  34. package/dist/widgets/index.js +11 -1
  35. package/dist/widgets/index.js.map +1 -1
  36. package/dist/widgets/runtime/WidgetLayout.d.ts +32 -0
  37. package/dist/widgets/runtime/WidgetLayout.d.ts.map +1 -0
  38. package/dist/widgets/runtime/WidgetLayout.js +143 -0
  39. package/dist/widgets/runtime/WidgetLayout.js.map +1 -0
  40. package/dist/widgets/runtime/widget-polyfill.d.ts +1 -0
  41. package/dist/widgets/runtime/widget-polyfill.d.ts.map +1 -0
  42. package/dist/widgets/runtime/widget-polyfill.js +28 -0
  43. package/dist/widgets/runtime/widget-polyfill.js.map +1 -0
  44. package/dist/widgets/sdk.d.ts +109 -0
  45. package/dist/widgets/sdk.d.ts.map +1 -0
  46. package/dist/widgets/sdk.js +221 -0
  47. package/dist/widgets/sdk.js.map +1 -0
  48. package/dist/widgets/types.d.ts +89 -0
  49. package/dist/widgets/types.d.ts.map +1 -0
  50. package/dist/widgets/types.js +8 -0
  51. package/dist/widgets/types.js.map +1 -0
  52. package/dist/widgets/utils/media-queries.d.ts +34 -0
  53. package/dist/widgets/utils/media-queries.d.ts.map +1 -0
  54. package/dist/widgets/utils/media-queries.js +42 -0
  55. package/dist/widgets/utils/media-queries.js.map +1 -0
  56. package/package.json +2 -2
  57. package/src/studio/app/chat/page.tsx +274 -137
  58. package/src/studio/app/globals.css +140 -64
  59. package/src/studio/branding.md +807 -0
  60. package/src/studio/components/WidgetRenderer.tsx +222 -16
  61. package/src/studio/lib/llm-service.ts +39 -39
  62. package/templates/typescript-oauth/{env.example → .env.example} +4 -10
  63. package/templates/typescript-oauth/README.md +226 -306
  64. package/templates/typescript-oauth/package-lock.json +4253 -0
  65. package/templates/typescript-oauth/package.json +10 -5
  66. package/templates/typescript-oauth/src/app.module.ts +39 -36
  67. package/templates/typescript-oauth/src/guards/oauth.guard.ts +0 -1
  68. package/templates/typescript-oauth/src/index.ts +22 -30
  69. package/templates/typescript-oauth/src/modules/flights/booking.tools.ts +323 -0
  70. package/templates/typescript-oauth/src/modules/flights/flights.module.ts +14 -0
  71. package/templates/typescript-oauth/src/modules/flights/flights.prompts.ts +231 -0
  72. package/templates/typescript-oauth/src/modules/flights/flights.resources.ts +215 -0
  73. package/templates/typescript-oauth/src/modules/flights/flights.tools.ts +457 -0
  74. package/templates/typescript-oauth/src/services/duffel.service.ts +285 -0
  75. package/templates/typescript-oauth/src/widgets/app/airport-search/page.tsx +270 -0
  76. package/templates/typescript-oauth/src/widgets/app/flight-details/page.tsx +261 -0
  77. package/templates/typescript-oauth/src/widgets/app/flight-search-results/page.tsx +378 -0
  78. package/templates/typescript-oauth/src/widgets/app/globals.css +167 -0
  79. package/templates/typescript-oauth/src/widgets/app/layout.tsx +6 -2
  80. package/templates/typescript-oauth/src/widgets/app/order-cancellation/page.tsx +207 -0
  81. package/templates/typescript-oauth/src/widgets/app/order-summary/page.tsx +245 -0
  82. package/templates/typescript-oauth/src/widgets/app/payment-confirmation/page.tsx +152 -0
  83. package/templates/typescript-oauth/src/widgets/app/seat-selection/page.tsx +486 -0
  84. package/templates/typescript-oauth/src/widgets/next-env.d.ts +5 -0
  85. package/templates/typescript-oauth/src/widgets/package-lock.json +155 -126
  86. package/templates/typescript-oauth/src/widgets/widget-manifest.json +374 -27
  87. package/templates/typescript-pizzaz/IMPLEMENTATION.md +98 -0
  88. package/templates/typescript-pizzaz/README.md +233 -0
  89. package/templates/typescript-pizzaz/package.json +31 -0
  90. package/templates/typescript-pizzaz/src/app.module.ts +28 -0
  91. package/templates/typescript-pizzaz/src/index.ts +30 -0
  92. package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.data.ts +106 -0
  93. package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.module.ts +11 -0
  94. package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.service.ts +60 -0
  95. package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.tools.ts +197 -0
  96. package/templates/typescript-pizzaz/src/widgets/app/layout.tsx +18 -0
  97. package/templates/typescript-pizzaz/src/widgets/app/pizza-list/page.tsx +272 -0
  98. package/templates/typescript-pizzaz/src/widgets/app/pizza-map/page.tsx +216 -0
  99. package/templates/typescript-pizzaz/src/widgets/app/pizza-shop/page.tsx +374 -0
  100. package/templates/typescript-pizzaz/src/widgets/components/CompactShopCard.tsx +144 -0
  101. package/templates/typescript-pizzaz/src/widgets/components/PizzaCard.tsx +191 -0
  102. package/templates/typescript-pizzaz/src/widgets/package.json +30 -0
  103. package/templates/typescript-pizzaz/src/widgets/widget-manifest.json +253 -0
  104. package/templates/typescript-pizzaz/tsconfig.json +30 -0
  105. package/templates/typescript-starter/src/modules/calculator/calculator.resources.ts +0 -1
  106. package/templates/typescript-starter/src/widgets/app/calculator-result/page.tsx +102 -56
  107. package/templates/typescript-starter/src/widgets/app/layout.tsx +6 -2
  108. package/templates/typescript-auth/AI_AGENT_CLI_REFERENCE.md +0 -702
  109. package/templates/typescript-auth/AI_AGENT_SDK_REFERENCE.md +0 -1260
  110. package/templates/typescript-auth/README.md +0 -402
  111. package/templates/typescript-auth/env.example +0 -25
  112. package/templates/typescript-auth/package.json +0 -36
  113. package/templates/typescript-auth/src/app.module.ts +0 -103
  114. package/templates/typescript-auth/src/db/database.ts +0 -160
  115. package/templates/typescript-auth/src/db/seed.ts +0 -374
  116. package/templates/typescript-auth/src/db/setup.ts +0 -87
  117. package/templates/typescript-auth/src/events/analytics.service.ts +0 -52
  118. package/templates/typescript-auth/src/events/notification.service.ts +0 -40
  119. package/templates/typescript-auth/src/filters/global-exception.filter.ts +0 -28
  120. package/templates/typescript-auth/src/guards/README.md +0 -75
  121. package/templates/typescript-auth/src/guards/jwt.guard.ts +0 -105
  122. package/templates/typescript-auth/src/health/database.health.ts +0 -41
  123. package/templates/typescript-auth/src/index.ts +0 -29
  124. package/templates/typescript-auth/src/interceptors/transform.interceptor.ts +0 -24
  125. package/templates/typescript-auth/src/middleware/logging.middleware.ts +0 -42
  126. package/templates/typescript-auth/src/modules/addresses/addresses.module.ts +0 -16
  127. package/templates/typescript-auth/src/modules/addresses/addresses.prompts.ts +0 -114
  128. package/templates/typescript-auth/src/modules/addresses/addresses.resources.ts +0 -40
  129. package/templates/typescript-auth/src/modules/addresses/addresses.tools.ts +0 -284
  130. package/templates/typescript-auth/src/modules/auth/auth.module.ts +0 -16
  131. package/templates/typescript-auth/src/modules/auth/auth.prompts.ts +0 -147
  132. package/templates/typescript-auth/src/modules/auth/auth.resources.ts +0 -84
  133. package/templates/typescript-auth/src/modules/auth/auth.tools.ts +0 -139
  134. package/templates/typescript-auth/src/modules/cart/cart.module.ts +0 -16
  135. package/templates/typescript-auth/src/modules/cart/cart.prompts.ts +0 -95
  136. package/templates/typescript-auth/src/modules/cart/cart.resources.ts +0 -44
  137. package/templates/typescript-auth/src/modules/cart/cart.tools.ts +0 -277
  138. package/templates/typescript-auth/src/modules/orders/orders.module.ts +0 -16
  139. package/templates/typescript-auth/src/modules/orders/orders.prompts.ts +0 -88
  140. package/templates/typescript-auth/src/modules/orders/orders.resources.ts +0 -48
  141. package/templates/typescript-auth/src/modules/orders/orders.tools.ts +0 -303
  142. package/templates/typescript-auth/src/modules/products/products.module.ts +0 -16
  143. package/templates/typescript-auth/src/modules/products/products.prompts.ts +0 -146
  144. package/templates/typescript-auth/src/modules/products/products.resources.ts +0 -98
  145. package/templates/typescript-auth/src/modules/products/products.tools.ts +0 -266
  146. package/templates/typescript-auth/src/pipes/validation.pipe.ts +0 -42
  147. package/templates/typescript-auth/src/services/database.service.ts +0 -90
  148. package/templates/typescript-auth/src/widgets/app/add-to-cart/page.tsx +0 -122
  149. package/templates/typescript-auth/src/widgets/app/address-added/page.tsx +0 -116
  150. package/templates/typescript-auth/src/widgets/app/address-deleted/page.tsx +0 -105
  151. package/templates/typescript-auth/src/widgets/app/address-list/page.tsx +0 -139
  152. package/templates/typescript-auth/src/widgets/app/address-updated/page.tsx +0 -153
  153. package/templates/typescript-auth/src/widgets/app/cart-cleared/page.tsx +0 -86
  154. package/templates/typescript-auth/src/widgets/app/cart-updated/page.tsx +0 -116
  155. package/templates/typescript-auth/src/widgets/app/categories/page.tsx +0 -134
  156. package/templates/typescript-auth/src/widgets/app/layout.tsx +0 -21
  157. package/templates/typescript-auth/src/widgets/app/login-result/page.tsx +0 -129
  158. package/templates/typescript-auth/src/widgets/app/order-confirmation/page.tsx +0 -231
  159. package/templates/typescript-auth/src/widgets/app/order-details/page.tsx +0 -225
  160. package/templates/typescript-auth/src/widgets/app/order-history/page.tsx +0 -218
  161. package/templates/typescript-auth/src/widgets/app/product-card/page.tsx +0 -121
  162. package/templates/typescript-auth/src/widgets/app/products-grid/page.tsx +0 -198
  163. package/templates/typescript-auth/src/widgets/app/shopping-cart/page.tsx +0 -187
  164. package/templates/typescript-auth/src/widgets/app/whoami/page.tsx +0 -165
  165. package/templates/typescript-auth/src/widgets/next.config.js +0 -38
  166. package/templates/typescript-auth/src/widgets/package.json +0 -18
  167. package/templates/typescript-auth/src/widgets/styles/ecommerce.ts +0 -169
  168. package/templates/typescript-auth/src/widgets/tsconfig.json +0 -28
  169. package/templates/typescript-auth/src/widgets/types/tool-data.ts +0 -141
  170. package/templates/typescript-auth/src/widgets/widget-manifest.json +0 -464
  171. package/templates/typescript-auth/tsconfig.json +0 -27
  172. package/templates/typescript-auth-api-key/AI_AGENT_CLI_REFERENCE.md +0 -701
  173. package/templates/typescript-auth-api-key/AI_AGENT_SDK_REFERENCE.md +0 -1260
  174. package/templates/typescript-auth-api-key/README.md +0 -485
  175. package/templates/typescript-auth-api-key/env.example +0 -17
  176. package/templates/typescript-auth-api-key/package.json +0 -21
  177. package/templates/typescript-auth-api-key/src/app.module.ts +0 -38
  178. package/templates/typescript-auth-api-key/src/guards/apikey.guard.ts +0 -47
  179. package/templates/typescript-auth-api-key/src/guards/multi-auth.guard.ts +0 -157
  180. package/templates/typescript-auth-api-key/src/index.ts +0 -47
  181. package/templates/typescript-auth-api-key/src/modules/calculator/calculator.module.ts +0 -12
  182. package/templates/typescript-auth-api-key/src/modules/calculator/calculator.prompts.ts +0 -73
  183. package/templates/typescript-auth-api-key/src/modules/calculator/calculator.resources.ts +0 -60
  184. package/templates/typescript-auth-api-key/src/modules/calculator/calculator.tools.ts +0 -71
  185. package/templates/typescript-auth-api-key/src/modules/demo/demo.module.ts +0 -18
  186. package/templates/typescript-auth-api-key/src/modules/demo/demo.tools.ts +0 -155
  187. package/templates/typescript-auth-api-key/src/modules/demo/multi-auth.tools.ts +0 -123
  188. package/templates/typescript-auth-api-key/src/widgets/app/calculator-operations/page.tsx +0 -133
  189. package/templates/typescript-auth-api-key/src/widgets/app/calculator-result/page.tsx +0 -134
  190. package/templates/typescript-auth-api-key/src/widgets/app/layout.tsx +0 -14
  191. package/templates/typescript-auth-api-key/src/widgets/package.json +0 -24
  192. package/templates/typescript-auth-api-key/src/widgets/widget-manifest.json +0 -48
  193. package/templates/typescript-auth-api-key/tsconfig.json +0 -23
  194. package/templates/typescript-oauth/OAUTH_SETUP.md +0 -592
  195. package/templates/typescript-oauth/src/modules/demo/demo.module.ts +0 -16
  196. package/templates/typescript-oauth/src/modules/demo/demo.tools.ts +0 -190
  197. package/templates/typescript-oauth/src/widgets/app/calculator-operations/page.tsx +0 -133
  198. package/templates/typescript-oauth/src/widgets/app/calculator-result/page.tsx +0 -134
  199. package/templates/typescript-oauth/src/widgets/out/404.html +0 -1
  200. package/templates/typescript-oauth/src/widgets/out/_next/static/WU9THacVqL52RZbrZOLS1/_buildManifest.js +0 -1
  201. package/templates/typescript-oauth/src/widgets/out/_next/static/WU9THacVqL52RZbrZOLS1/_ssgManifest.js +0 -1
  202. package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/117-eb57c7ef86f964a4.js +0 -2
  203. package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/app/_not-found/page-dcb83ba3e4d0aafd.js +0 -1
  204. package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/app/calculator-operations/page-b8913a740073ea8a.js +0 -1
  205. package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/app/calculator-result/page-ddaaab2fce95dea2.js +0 -1
  206. package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/app/layout-cbd3ebdc4ecc5247.js +0 -1
  207. package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/fd9d1056-749e5812300142af.js +0 -1
  208. package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/framework-f66176bb897dc684.js +0 -1
  209. package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/main-76df43fcef3db344.js +0 -1
  210. package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/main-app-f9c40224d04023c5.js +0 -1
  211. package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/pages/_app-72b849fbd24ac258.js +0 -1
  212. package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/pages/_error-7ba65e1336b92748.js +0 -1
  213. package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/polyfills-42372ed130431b0a.js +0 -1
  214. package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/webpack-100b9e646d9c912e.js +0 -1
  215. package/templates/typescript-oauth/src/widgets/out/calculator-operations.html +0 -1
  216. package/templates/typescript-oauth/src/widgets/out/calculator-operations.txt +0 -7
  217. package/templates/typescript-oauth/src/widgets/out/calculator-result.html +0 -1
  218. package/templates/typescript-oauth/src/widgets/out/calculator-result.txt +0 -7
  219. package/templates/typescript-starter/src/widgets/app/calculator-operations/page.tsx +0 -133
  220. /package/templates/{typescript-auth-api-key → typescript-oauth}/src/health/system.health.ts +0 -0
  221. /package/templates/{typescript-auth-api-key → typescript-pizzaz}/src/widgets/next.config.js +0 -0
  222. /package/templates/{typescript-auth-api-key → typescript-pizzaz}/src/widgets/tsconfig.json +0 -0
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import { useEffect, useRef } from 'react';
3
+ import { useEffect, useRef, useState } from 'react';
4
4
  import { getWidgetUrl, createWidgetHTML, postMessageToWidget } from '@/lib/widget-loader';
5
5
 
6
6
  interface WidgetRendererProps {
@@ -11,6 +11,7 @@ interface WidgetRendererProps {
11
11
 
12
12
  export function WidgetRenderer({ uri, data, className = '' }: WidgetRendererProps) {
13
13
  const iframeRef = useRef<HTMLIFrameElement>(null);
14
+ const [contentHeight, setContentHeight] = useState<number>(200); // Start with smaller default
14
15
 
15
16
  // Check if we're in dev mode (localhost)
16
17
  const isDevMode =
@@ -20,20 +21,212 @@ export function WidgetRenderer({ uri, data, className = '' }: WidgetRendererProp
20
21
  useEffect(() => {
21
22
  if (!iframeRef.current) return;
22
23
 
24
+ const injectOpenAiRuntime = (iframe: HTMLIFrameElement) => {
25
+ if (!iframe.contentWindow) return;
26
+
27
+ // Detect system theme
28
+ const getSystemTheme = (): 'light' | 'dark' => {
29
+ if (typeof window === 'undefined') return 'light';
30
+ return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
31
+ };
32
+
33
+ // Detect device capabilities
34
+ const getUserAgent = () => ({
35
+ device: {
36
+ type: (window.matchMedia('(max-width: 768px)').matches
37
+ ? 'mobile'
38
+ : window.matchMedia('(max-width: 1024px)').matches
39
+ ? 'tablet'
40
+ : 'desktop') as 'mobile' | 'tablet' | 'desktop',
41
+ },
42
+ capabilities: {
43
+ hover: window.matchMedia('(hover: hover)').matches,
44
+ touch: window.matchMedia('(pointer: coarse)').matches,
45
+ },
46
+ });
47
+
48
+ // Create window.openai polyfill
49
+ const openaiRuntime = {
50
+ // Data
51
+ toolInput: {},
52
+ toolOutput: data,
53
+ toolResponseMetadata: null,
54
+ widgetState: null,
55
+
56
+ // Visuals
57
+ theme: getSystemTheme(),
58
+ locale: navigator.language || 'en-US',
59
+ userAgent: getUserAgent(),
60
+
61
+ // Layout
62
+ maxHeight: 450, // Match iframe height
63
+ displayMode: 'inline' as const,
64
+ safeArea: {
65
+ insets: { top: 0, bottom: 0, left: 0, right: 0 },
66
+ },
67
+
68
+ // State management
69
+ setWidgetState: async (state: any) => {
70
+ console.log('📦 Widget state updated:', state);
71
+ openaiRuntime.widgetState = state;
72
+
73
+ // Dispatch event for hooks to react
74
+ const event = new CustomEvent('openai:set_globals', {
75
+ detail: { globals: { widgetState: state } },
76
+ });
77
+ iframe.contentWindow?.dispatchEvent(event);
78
+
79
+ // TODO: Persist to chat message context
80
+ },
81
+
82
+ // Actions
83
+ callTool: async (name: string, args: Record<string, unknown>) => {
84
+ console.log('🔧 Widget calling tool:', name, args);
85
+ // TODO: Implement tool call via studio API
86
+ return { result: 'Tool call not yet implemented' };
87
+ },
88
+
89
+ sendFollowUpMessage: async ({ prompt }: { prompt: string }) => {
90
+ console.log('💬 Widget sending follow-up:', prompt);
91
+ // TODO: Implement follow-up message
92
+ },
93
+
94
+ openExternal: ({ href }: { href: string }) => {
95
+ window.open(href, '_blank', 'noopener,noreferrer');
96
+ },
97
+
98
+ requestClose: () => {
99
+ console.log('❌ Widget requested close');
100
+ // TODO: Implement widget close
101
+ },
102
+
103
+ requestDisplayMode: async ({ mode }: { mode: 'inline' | 'pip' | 'fullscreen' }) => {
104
+ console.log('🖼️ Widget requested display mode:', mode);
105
+ // TODO: Implement display mode change
106
+ return { mode: 'inline' as const };
107
+ },
108
+ };
109
+
110
+ // Prepare serializable data (no functions)
111
+ const openaiData = {
112
+ // Data
113
+ toolInput: {},
114
+ toolOutput: data,
115
+ toolResponseMetadata: null,
116
+ widgetState: null,
117
+
118
+ // Visuals
119
+ theme: getSystemTheme(),
120
+ locale: navigator.language || 'en-US',
121
+ userAgent: getUserAgent(),
122
+
123
+ // Layout
124
+ maxHeight: 450,
125
+ displayMode: 'inline' as const,
126
+ safeArea: {
127
+ insets: { top: 0, bottom: 0, left: 0, right: 0 },
128
+ },
129
+ };
130
+
131
+ // Send openai data to iframe via postMessage (cross-origin safe)
132
+ const sendData = () => {
133
+ try {
134
+ iframe.contentWindow?.postMessage({
135
+ type: 'NITRO_INJECT_OPENAI',
136
+ data: openaiData
137
+ }, '*');
138
+ console.log('✅ window.openai data sent to widget via postMessage');
139
+ } catch (e) {
140
+ console.error('❌ Failed to send window.openai:', e);
141
+ }
142
+ };
143
+
144
+ // Send immediately
145
+ sendData();
146
+
147
+ // Retry after delays to ensure widget React app has mounted
148
+ setTimeout(sendData, 100);
149
+ setTimeout(sendData, 300);
150
+ setTimeout(sendData, 500);
151
+
152
+ // Set up message listener for widget RPC calls
153
+ const handleWidgetMessage = (event: MessageEvent) => {
154
+ if (event.data?.type === 'NITRO_WIDGET_RPC') {
155
+ const { method, args, id } = event.data;
156
+
157
+ switch (method) {
158
+ case 'setWidgetState':
159
+ console.log('📦 Widget state updated:', args[0]);
160
+ openaiData.widgetState = args[0];
161
+ // Send response
162
+ iframe.contentWindow?.postMessage({
163
+ type: 'NITRO_WIDGET_RPC_RESPONSE',
164
+ id,
165
+ result: null
166
+ }, '*');
167
+ break;
168
+
169
+ case 'callTool':
170
+ console.log('🔧 Widget calling tool:', args[0], args[1]);
171
+ // Dispatch event for chat page to handle
172
+ window.dispatchEvent(new CustomEvent('widget-tool-call', {
173
+ detail: { toolName: args[0], toolArgs: args[1] }
174
+ }));
175
+ iframe.contentWindow?.postMessage({
176
+ type: 'NITRO_WIDGET_RPC_RESPONSE',
177
+ id,
178
+ result: { success: true }
179
+ }, '*');
180
+ break;
181
+
182
+ case 'openExternal':
183
+ window.open(args[0].href, '_blank', 'noopener,noreferrer');
184
+ iframe.contentWindow?.postMessage({
185
+ type: 'NITRO_WIDGET_RPC_RESPONSE',
186
+ id,
187
+ result: null
188
+ }, '*');
189
+ break;
190
+
191
+ case 'requestDisplayMode':
192
+ console.log('🖼️ Widget requested display mode:', args[0].mode);
193
+ if (args[0].mode === 'fullscreen') {
194
+ // Dispatch custom event for chat page to handle
195
+ window.dispatchEvent(new CustomEvent('widget-fullscreen-request', {
196
+ detail: { uri, data }
197
+ }));
198
+ }
199
+ iframe.contentWindow?.postMessage({
200
+ type: 'NITRO_WIDGET_RPC_RESPONSE',
201
+ id,
202
+ result: { mode: args[0].mode }
203
+ }, '*');
204
+ break;
205
+ }
206
+ }
207
+
208
+ // Handle resize messages from widget
209
+ if (event.data?.type === 'NITRO_WIDGET_RESIZE') {
210
+ const { height } = event.data;
211
+ console.log('📏 Received widget resize:', height);
212
+ if (height && typeof height === 'number') {
213
+ const newHeight = Math.min(height, 400);
214
+ console.log('📏 Setting content height to:', newHeight);
215
+ setContentHeight(newHeight); // Cap at 400px max
216
+ }
217
+ }
218
+ };
219
+
220
+ window.addEventListener('message', handleWidgetMessage);
221
+ };
222
+
23
223
  if (isDevMode) {
24
224
  // Dev mode: load from widget dev server (port 3001)
25
- // Parse the widget path from various URI formats:
26
- // - "ui://widget/calculator-result.html" -> "calculator-result"
27
- // - "/calculator-result" -> "calculator-result"
28
- // - "calculator-result" -> "calculator-result"
29
- // - "/widgets/calculator-result" -> "calculator-result"
30
-
31
225
  let widgetPath = uri;
32
226
 
33
227
  // Handle ui://widget/ URIs
34
228
  if (widgetPath.startsWith('ui://widget/')) {
35
229
  widgetPath = widgetPath.replace('ui://widget/', '');
36
- // Remove .html extension if present
37
230
  widgetPath = widgetPath.replace(/\.html$/, '');
38
231
  }
39
232
  // Handle /widgets/ prefix (legacy)
@@ -51,8 +244,14 @@ export function WidgetRenderer({ uri, data, className = '' }: WidgetRendererProp
51
244
 
52
245
  // Set up onload handler BEFORE setting src
53
246
  iframeRef.current.onload = () => {
54
- console.log('Widget iframe loaded, posting data...');
55
- // Post message after a short delay to ensure widget is ready
247
+ console.log('Widget iframe loaded, injecting window.openai...');
248
+
249
+ // Inject window.openai runtime
250
+ if (iframeRef.current) {
251
+ injectOpenAiRuntime(iframeRef.current);
252
+ }
253
+
254
+ // Also send legacy postMessage for backward compatibility
56
255
  setTimeout(() => {
57
256
  try {
58
257
  iframeRef.current?.contentWindow?.postMessage(
@@ -62,7 +261,7 @@ export function WidgetRenderer({ uri, data, className = '' }: WidgetRendererProp
62
261
  },
63
262
  '*'
64
263
  );
65
- console.log('✅ Data posted to widget:', data);
264
+ console.log('✅ Legacy data posted to widget:', data);
66
265
  } catch (e) {
67
266
  console.error('❌ Failed to post message to widget:', e);
68
267
  }
@@ -76,10 +275,8 @@ export function WidgetRenderer({ uri, data, className = '' }: WidgetRendererProp
76
275
  const loadProductionWidget = async () => {
77
276
  try {
78
277
  // Convert widget route/path to resource URI format if needed
79
- // Routes like "/calculator-result" or "calculator-result" should become "widget://calculator-result"
80
278
  let resourceUri = uri;
81
279
  if (!uri.startsWith('widget://') && !uri.startsWith('http://') && !uri.startsWith('https://')) {
82
- // Remove leading slash if present
83
280
  const widgetPath = uri.startsWith('/') ? uri.substring(1) : uri;
84
281
  resourceUri = `widget://${widgetPath}`;
85
282
  }
@@ -100,6 +297,11 @@ export function WidgetRenderer({ uri, data, className = '' }: WidgetRendererProp
100
297
  if (iframeRef.current) {
101
298
  iframeRef.current.src = blobUrl;
102
299
  iframeRef.current.onload = () => {
300
+ // Inject window.openai runtime
301
+ if (iframeRef.current) {
302
+ injectOpenAiRuntime(iframeRef.current);
303
+ }
304
+
103
305
  URL.revokeObjectURL(blobUrl);
104
306
  };
105
307
  }
@@ -110,7 +312,6 @@ export function WidgetRenderer({ uri, data, className = '' }: WidgetRendererProp
110
312
  } catch (error) {
111
313
  console.error('❌ Failed to load widget:', {
112
314
  originalUri: uri,
113
- resourceUri,
114
315
  error: error instanceof Error ? error.message : String(error),
115
316
  stack: error instanceof Error ? error.stack : undefined
116
317
  });
@@ -122,6 +323,7 @@ export function WidgetRenderer({ uri, data, className = '' }: WidgetRendererProp
122
323
  }, [uri, data, isDevMode]);
123
324
 
124
325
  const isInChat = className?.includes('widget-in-chat');
326
+ const finalHeight = isInChat ? `${contentHeight}px` : '100%';
125
327
 
126
328
  return (
127
329
  <iframe
@@ -129,10 +331,14 @@ export function WidgetRenderer({ uri, data, className = '' }: WidgetRendererProp
129
331
  className={className}
130
332
  sandbox="allow-scripts allow-same-origin"
131
333
  style={{
132
- width: isInChat ? '650px' : '100%',
133
- height: isInChat ? '450px' : '100%',
334
+ width: '100%',
335
+ height: finalHeight,
336
+ maxHeight: isInChat ? '400px' : '100%',
134
337
  border: 'none',
135
338
  background: 'transparent',
339
+ overflow: 'hidden',
340
+ transition: 'height 0.2s ease-out',
341
+ display: 'block',
136
342
  }}
137
343
  />
138
344
  );
@@ -148,7 +148,7 @@ User: "list all resources"
148
148
  ...messages,
149
149
  ];
150
150
  }
151
-
151
+
152
152
  if (provider === 'openai') {
153
153
  return this.chatOpenAI(messages, tools, apiKey);
154
154
  } else if (provider === 'gemini') {
@@ -170,7 +170,7 @@ User: "list all resources"
170
170
  tool_call_id: msg.toolCallId,
171
171
  };
172
172
  }
173
-
173
+
174
174
  // Handle assistant messages with tool calls
175
175
  if (msg.role === 'assistant' && msg.toolCalls && msg.toolCalls.length > 0) {
176
176
  return {
@@ -186,13 +186,13 @@ User: "list all resources"
186
186
  })),
187
187
  };
188
188
  }
189
-
189
+
190
190
  return {
191
191
  role: msg.role,
192
192
  content: msg.content,
193
193
  };
194
194
  });
195
-
195
+
196
196
  console.log('Formatted messages for OpenAI:', JSON.stringify(formattedMessages, null, 2));
197
197
 
198
198
  const requestBody: any = {
@@ -204,11 +204,11 @@ User: "list all resources"
204
204
  requestBody.tools = tools.map((tool) => {
205
205
  // Clean the schema for OpenAI - remove unsupported properties
206
206
  const cleanSchema = { ...tool.inputSchema };
207
-
207
+
208
208
  // Remove properties that OpenAI doesn't support
209
209
  delete cleanSchema.$schema;
210
210
  delete cleanSchema.additionalProperties;
211
-
211
+
212
212
  // Ensure required properties for OpenAI
213
213
  if (!cleanSchema.type) {
214
214
  cleanSchema.type = 'object';
@@ -216,7 +216,7 @@ User: "list all resources"
216
216
  if (!cleanSchema.properties) {
217
217
  cleanSchema.properties = {};
218
218
  }
219
-
219
+
220
220
  return {
221
221
  type: 'function',
222
222
  function: {
@@ -226,7 +226,7 @@ User: "list all resources"
226
226
  },
227
227
  };
228
228
  });
229
-
229
+
230
230
  console.log('Sending tools to OpenAI:', JSON.stringify(requestBody.tools, null, 2));
231
231
  }
232
232
 
@@ -276,22 +276,22 @@ User: "list all resources"
276
276
  // Convert messages to Gemini format
277
277
  const contents: any[] = [];
278
278
  let systemInstruction = '';
279
-
279
+
280
280
  // Group consecutive tool messages together for Gemini
281
281
  let i = 0;
282
282
  while (i < messages.length) {
283
283
  const msg = messages[i];
284
-
284
+
285
285
  if (msg.role === 'system') {
286
286
  systemInstruction = msg.content;
287
287
  i++;
288
288
  continue;
289
289
  }
290
-
290
+
291
291
  if (msg.role === 'tool') {
292
292
  // Collect all consecutive tool messages and group them into ONE function response
293
293
  const functionParts: any[] = [];
294
-
294
+
295
295
  while (i < messages.length && messages[i].role === 'tool') {
296
296
  const toolMsg = messages[i];
297
297
  functionParts.push({
@@ -304,7 +304,7 @@ User: "list all resources"
304
304
  });
305
305
  i++;
306
306
  }
307
-
307
+
308
308
  // Add all function responses as ONE entry with multiple parts
309
309
  contents.push({
310
310
  role: 'function',
@@ -313,11 +313,11 @@ User: "list all resources"
313
313
  } else if (msg.role === 'assistant' && msg.toolCalls && msg.toolCalls.length > 0) {
314
314
  // Assistant message with tool calls
315
315
  const parts: any[] = [];
316
-
316
+
317
317
  if (msg.content) {
318
318
  parts.push({ text: msg.content });
319
319
  }
320
-
320
+
321
321
  for (const tc of msg.toolCalls) {
322
322
  parts.push({
323
323
  functionCall: {
@@ -326,7 +326,7 @@ User: "list all resources"
326
326
  },
327
327
  });
328
328
  }
329
-
329
+
330
330
  contents.push({
331
331
  role: 'model',
332
332
  parts,
@@ -341,38 +341,38 @@ User: "list all resources"
341
341
  i++;
342
342
  }
343
343
  }
344
-
345
- console.log('Formatted contents for Gemini:', JSON.stringify(contents, null, 2));
346
-
344
+
345
+ // console.log('Formatted contents for Gemini:', JSON.stringify(contents, null, 2));
346
+
347
347
  // Prepare request body
348
348
  const requestBody: any = {
349
349
  contents,
350
350
  };
351
-
351
+
352
352
  // Add system instruction if present
353
353
  if (systemInstruction) {
354
354
  requestBody.systemInstruction = {
355
355
  parts: [{ text: systemInstruction }],
356
356
  };
357
357
  }
358
-
358
+
359
359
  // Add tools if present
360
360
  if (tools.length > 0) {
361
361
  requestBody.tools = [{
362
362
  functionDeclarations: tools.map((tool) => {
363
363
  const cleanSchema = { ...tool.inputSchema };
364
-
364
+
365
365
  // Remove unsupported properties
366
366
  delete cleanSchema.$schema;
367
367
  delete cleanSchema.additionalProperties;
368
-
368
+
369
369
  // Convert to Gemini's expected format
370
370
  const parameters: any = {
371
371
  type: cleanSchema.type || 'OBJECT',
372
372
  properties: {},
373
373
  required: cleanSchema.required || [],
374
374
  };
375
-
375
+
376
376
  // Convert properties
377
377
  if (cleanSchema.properties) {
378
378
  for (const [key, value] of Object.entries(cleanSchema.properties)) {
@@ -381,14 +381,14 @@ User: "list all resources"
381
381
  type: this.convertTypeToGemini(prop.type),
382
382
  description: prop.description || '',
383
383
  };
384
-
384
+
385
385
  // Handle enums
386
386
  if (prop.enum) {
387
387
  parameters.properties[key].enum = prop.enum;
388
388
  }
389
389
  }
390
390
  }
391
-
391
+
392
392
  return {
393
393
  name: tool.name,
394
394
  description: tool.description || 'No description provided',
@@ -396,10 +396,10 @@ User: "list all resources"
396
396
  };
397
397
  }),
398
398
  }];
399
-
400
- console.log('Sending tools to Gemini:', JSON.stringify(requestBody.tools, null, 2));
399
+
400
+ // console.log('Sending tools to Gemini:', JSON.stringify(requestBody.tools, null, 2));
401
401
  }
402
-
402
+
403
403
  // Use Gemini 2.0 Flash Experimental (latest model with function calling)
404
404
  // The v1beta API uses 'gemini-2.0-flash-exp' for the newest features
405
405
  const model = 'gemini-2.0-flash-exp';
@@ -420,23 +420,23 @@ User: "list all resources"
420
420
 
421
421
  const data = await response.json();
422
422
  console.log('Gemini response:', JSON.stringify(data, null, 2));
423
-
423
+
424
424
  const candidate = data.candidates?.[0];
425
425
  if (!candidate) {
426
426
  throw new Error('No response from Gemini');
427
427
  }
428
-
428
+
429
429
  const parts = candidate.content?.parts || [];
430
-
430
+
431
431
  // Extract text content
432
432
  let content = '';
433
433
  const toolCalls: ToolCall[] = [];
434
-
434
+
435
435
  for (const part of parts) {
436
436
  if (part.text) {
437
437
  content += part.text;
438
438
  }
439
-
439
+
440
440
  if (part.functionCall) {
441
441
  toolCalls.push({
442
442
  id: `call_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
@@ -445,7 +445,7 @@ User: "list all resources"
445
445
  });
446
446
  }
447
447
  }
448
-
448
+
449
449
  const result: ChatResponse = {
450
450
  message: {
451
451
  role: 'assistant',
@@ -453,7 +453,7 @@ User: "list all resources"
453
453
  },
454
454
  finishReason: candidate.finishReason,
455
455
  };
456
-
456
+
457
457
  if (toolCalls.length > 0) {
458
458
  result.toolCalls = toolCalls;
459
459
  result.message.toolCalls = toolCalls;
@@ -461,10 +461,10 @@ User: "list all resources"
461
461
 
462
462
  return result;
463
463
  }
464
-
464
+
465
465
  private convertTypeToGemini(type?: string): string {
466
466
  if (!type) return 'STRING';
467
-
467
+
468
468
  const typeMap: Record<string, string> = {
469
469
  'string': 'STRING',
470
470
  'number': 'NUMBER',
@@ -473,7 +473,7 @@ User: "list all resources"
473
473
  'array': 'ARRAY',
474
474
  'object': 'OBJECT',
475
475
  };
476
-
476
+
477
477
  return typeMap[type.toLowerCase()] || 'STRING';
478
478
  }
479
479
  }
@@ -1,3 +1,4 @@
1
+
1
2
  # OAuth 2.1 MCP Server Configuration
2
3
  # =============================================================================
3
4
  # TRANSPORT MODE (AUTO-CONFIGURED)
@@ -6,28 +7,21 @@
6
7
  # - STDIO: For MCP protocol communication with Studio/Claude
7
8
  # - HTTP: For OAuth metadata endpoints (/.well-known/oauth-protected-resource)
8
9
  # Both transports run simultaneously on different channels.
9
- # =============================================================================
10
-
11
10
  # =============================================================================
12
11
  # REQUIRED: Server Configuration
13
12
  # =============================================================================
14
-
15
13
  # =============================================================================
16
14
  # Auth0 Configuration
17
15
  # =============================================================================
18
16
  # After creating your API and Application in Auth0, fill in these values:
19
-
20
17
  # Your Auth0 API Identifier (from APIs → MCP Server → Identifier)
21
18
  # This MUST match exactly what you set when creating the API
22
19
  RESOURCE_URI=https://mcplocal
23
-
24
20
  # Your Auth0 tenant domain (authorization server)
25
- AUTH_SERVER_URL=https://dev-5dt0utuk37h13tjm.us.auth0.com
26
-
21
+ AUTH_SERVER_URL=https://dev-5dt0utuk31h13tjm.us.auth0.com
27
22
  # Expected token audience (should match RESOURCE_URI)
28
23
  TOKEN_AUDIENCE=https://mcplocal
29
-
30
24
  # Expected token issuer (your Auth0 tenant domain with trailing slash)
31
- TOKEN_ISSUER=https://dev-5dt0utuk37h13tjm.us.auth0.com/
32
-
25
+ TOKEN_ISSUER=https://dev-5dt0utuk31h13tjm.us.auth0.com/
33
26
 
27
+ DUFFEL_API_KEY=duffel_test_-w0wGDHB0M3DU9k-sBeUbxLqwcibUQqfEbjWDTKNnlf