nitrostack 1.0.33 → 1.0.35
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/cli/build-widgets.mjs +165 -0
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/build.js +53 -7
- package/dist/cli/commands/build.js.map +1 -1
- package/dist/core/component.d.ts +7 -1
- package/dist/core/component.d.ts.map +1 -1
- package/dist/core/component.js +49 -4
- package/dist/core/component.js.map +1 -1
- package/dist/core/server.d.ts.map +1 -1
- package/dist/core/server.js +9 -3
- package/dist/core/server.js.map +1 -1
- package/dist/core/tool.d.ts.map +1 -1
- package/dist/core/tool.js +16 -1
- package/dist/core/tool.js.map +1 -1
- package/dist/ui-next/index.d.ts +1 -0
- package/dist/ui-next/index.d.ts.map +1 -1
- package/dist/ui-next/index.js +126 -125
- package/dist/ui-next/index.js.map +1 -1
- package/package.json +4 -3
- package/src/studio/components/WidgetRenderer.tsx +24 -15
- package/templates/typescript-auth/src/modules/products/products.tools.ts +29 -29
- package/templates/typescript-oauth/src/widgets/next-env.d.ts +5 -0
- package/templates/typescript-oauth/src/widgets/out/404.html +1 -0
- package/templates/typescript-oauth/src/widgets/out/_next/static/WU9THacVqL52RZbrZOLS1/_buildManifest.js +1 -0
- package/templates/typescript-oauth/src/widgets/out/_next/static/WU9THacVqL52RZbrZOLS1/_ssgManifest.js +1 -0
- package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/117-eb57c7ef86f964a4.js +2 -0
- package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/app/_not-found/page-dcb83ba3e4d0aafd.js +1 -0
- package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/app/calculator-operations/page-b8913a740073ea8a.js +1 -0
- package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/app/calculator-result/page-ddaaab2fce95dea2.js +1 -0
- package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/app/layout-cbd3ebdc4ecc5247.js +1 -0
- package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/fd9d1056-749e5812300142af.js +1 -0
- package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/framework-f66176bb897dc684.js +1 -0
- package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/main-76df43fcef3db344.js +1 -0
- package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/main-app-f9c40224d04023c5.js +1 -0
- package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/pages/_app-72b849fbd24ac258.js +1 -0
- package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/pages/_error-7ba65e1336b92748.js +1 -0
- package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- package/templates/typescript-oauth/src/widgets/out/_next/static/chunks/webpack-100b9e646d9c912e.js +1 -0
- package/templates/typescript-oauth/src/widgets/out/calculator-operations.html +1 -0
- package/templates/typescript-oauth/src/widgets/out/calculator-operations.txt +7 -0
- package/templates/typescript-oauth/src/widgets/out/calculator-result.html +1 -0
- package/templates/typescript-oauth/src/widgets/out/calculator-result.txt +7 -0
package/dist/ui-next/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { execSync } from 'node:child_process';
|
|
|
2
2
|
import * as fs from 'node:fs';
|
|
3
3
|
import * as path from 'node:path';
|
|
4
4
|
import { createComponent } from '../core/component.js';
|
|
5
|
-
function inlineHtmlWithAssets(htmlPath, outDir) {
|
|
5
|
+
export function inlineHtmlWithAssets(htmlPath, outDir) {
|
|
6
6
|
let html = fs.readFileSync(htmlPath, 'utf8');
|
|
7
7
|
// Inline <link rel="stylesheet" href="...">
|
|
8
8
|
html = html.replace(/<link[^>]*rel=["']stylesheet["'][^>]*href=["']([^"']+)["'][^>]*>/g, (_m, href) => {
|
|
@@ -162,14 +162,14 @@ export function createComponentFromNextRoute(arg1, arg2) {
|
|
|
162
162
|
// Try flat structure (route-name.html)
|
|
163
163
|
outPath = path.resolve(projectDir, 'out', `${routePath}.html`);
|
|
164
164
|
if (!fs.existsSync(outPath)) {
|
|
165
|
-
throw new Error(`Exported HTML for route '${routePath}' not found. Tried
|
|
166
|
-
` - ${path.resolve(projectDir, 'out', routePath, 'index.html')}
|
|
165
|
+
throw new Error(`Exported HTML for route '${routePath}' not found. Tried:\\n` +
|
|
166
|
+
` - ${path.resolve(projectDir, 'out', routePath, 'index.html')}\\n` +
|
|
167
167
|
` - ${path.resolve(projectDir, 'out', `${routePath}.html`)}`);
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
|
-
//
|
|
171
|
-
|
|
172
|
-
const widgetHtml =
|
|
170
|
+
// Inline all Next.js assets (JS, CSS) into a single HTML file
|
|
171
|
+
const outDir = path.resolve(projectDir, 'out');
|
|
172
|
+
const widgetHtml = inlineHtmlWithAssets(outPath, outDir);
|
|
173
173
|
return createComponent({
|
|
174
174
|
id,
|
|
175
175
|
name,
|
|
@@ -185,187 +185,188 @@ export function createComponentFromNextRoute(arg1, arg2) {
|
|
|
185
185
|
*/
|
|
186
186
|
function generateSimpleWidgetHtml(routePath, widgetId) {
|
|
187
187
|
// Base template that all widgets use
|
|
188
|
-
const baseTemplate =
|
|
189
|
-
<html>
|
|
190
|
-
<head>
|
|
191
|
-
<meta charset="UTF-8">
|
|
192
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
193
|
-
<style>
|
|
194
|
-
* { box-sizing: border-box;
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
188
|
+
const baseTemplate = `< !DOCTYPE html >
|
|
189
|
+
<html>
|
|
190
|
+
<head>
|
|
191
|
+
<meta charset="UTF-8" >
|
|
192
|
+
<meta name="viewport" content = "width=device-width, initial-scale=1.0" >
|
|
193
|
+
<style>
|
|
194
|
+
* { box- sizing: border - box;
|
|
195
|
+
}
|
|
196
|
+
body {
|
|
197
|
+
margin: 16px;
|
|
198
|
+
padding: 0;
|
|
199
|
+
font - family: -apple - system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans - serif;
|
|
199
200
|
background: #ffffff;
|
|
200
201
|
color: #1a1a1a;
|
|
201
|
-
min-height: 100px;
|
|
202
|
+
min - height: 100px;
|
|
202
203
|
}
|
|
203
|
-
.widget-container {
|
|
204
|
+
.widget - container {
|
|
204
205
|
background: #ffffff;
|
|
205
206
|
border: 1px solid #e5e7eb;
|
|
206
|
-
border-radius: 12px;
|
|
207
|
+
border - radius: 12px;
|
|
207
208
|
padding: 0;
|
|
208
209
|
overflow: hidden;
|
|
209
|
-
max-width: 100%;
|
|
210
|
-
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
210
|
+
max - width: 100 %;
|
|
211
|
+
box - shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
211
212
|
}
|
|
212
|
-
.widget-header {
|
|
213
|
+
.widget - header {
|
|
213
214
|
padding: 20px;
|
|
214
|
-
background: linear-gradient(135deg, #D4AF37 0%, #F5C842 100%);
|
|
215
|
+
background: linear - gradient(135deg, #D4AF37 0 %, #F5C842 100 %);
|
|
215
216
|
color: #000;
|
|
216
|
-
font-weight: 700;
|
|
217
|
-
font-size: 18px;
|
|
217
|
+
font - weight: 700;
|
|
218
|
+
font - size: 18px;
|
|
218
219
|
}
|
|
219
|
-
.widget-body {
|
|
220
|
+
.widget - body {
|
|
220
221
|
padding: 20px;
|
|
221
222
|
}
|
|
222
|
-
.success {
|
|
223
|
-
color: #D4AF37;
|
|
224
|
-
font-weight: 700;
|
|
225
|
-
margin-bottom: 16px;
|
|
226
|
-
font-size: 18px;
|
|
223
|
+
.success {
|
|
224
|
+
color: #D4AF37;
|
|
225
|
+
font - weight: 700;
|
|
226
|
+
margin - bottom: 16px;
|
|
227
|
+
font - size: 18px;
|
|
227
228
|
display: flex;
|
|
228
|
-
align-items: center;
|
|
229
|
+
align - items: center;
|
|
229
230
|
gap: 8px;
|
|
230
231
|
}
|
|
231
|
-
.error {
|
|
232
|
-
color: #ef4444;
|
|
233
|
-
font-weight: 700;
|
|
234
|
-
margin-bottom: 16px;
|
|
235
|
-
font-size: 18px;
|
|
232
|
+
.error {
|
|
233
|
+
color: #ef4444;
|
|
234
|
+
font - weight: 700;
|
|
235
|
+
margin - bottom: 16px;
|
|
236
|
+
font - size: 18px;
|
|
236
237
|
}
|
|
237
|
-
.profile-img {
|
|
238
|
+
.profile - img {
|
|
238
239
|
width: 100px;
|
|
239
240
|
height: 100px;
|
|
240
|
-
border-radius: 50%;
|
|
241
|
-
object-fit: cover;
|
|
241
|
+
border - radius: 50 %;
|
|
242
|
+
object - fit: cover;
|
|
242
243
|
border: 4px solid #D4AF37;
|
|
243
|
-
margin-bottom: 16px;
|
|
244
|
-
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
244
|
+
margin - bottom: 16px;
|
|
245
|
+
box - shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
245
246
|
}
|
|
246
|
-
.product-img {
|
|
247
|
-
width: 100%;
|
|
247
|
+
.product - img {
|
|
248
|
+
width: 100 %;
|
|
248
249
|
height: 200px;
|
|
249
|
-
object-fit: cover;
|
|
250
|
-
border-radius: 8px;
|
|
251
|
-
margin-bottom: 12px;
|
|
250
|
+
object - fit: cover;
|
|
251
|
+
border - radius: 8px;
|
|
252
|
+
margin - bottom: 12px;
|
|
252
253
|
}
|
|
253
|
-
.card {
|
|
254
|
-
border: 1px solid #e5e7eb;
|
|
255
|
-
padding: 16px;
|
|
256
|
-
border-radius: 12px;
|
|
254
|
+
.card {
|
|
255
|
+
border: 1px solid #e5e7eb;
|
|
256
|
+
padding: 16px;
|
|
257
|
+
border - radius: 12px;
|
|
257
258
|
background: #f9fafb;
|
|
258
|
-
margin-bottom: 12px;
|
|
259
|
+
margin - bottom: 12px;
|
|
259
260
|
transition: all 0.2s ease;
|
|
260
|
-
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
261
|
+
box - shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
261
262
|
}
|
|
262
263
|
.card:hover {
|
|
263
|
-
border-color: #D4AF37;
|
|
264
|
-
box-shadow: 0 4px 6px rgba(212, 175, 55, 0.2);
|
|
264
|
+
border - color: #D4AF37;
|
|
265
|
+
box - shadow: 0 4px 6px rgba(212, 175, 55, 0.2);
|
|
265
266
|
transform: translateY(-2px);
|
|
266
267
|
}
|
|
267
|
-
.field { margin: 10px 0; font-size: 14px; color: #374151; }
|
|
268
|
-
.label { color: #6b7280; font-size: 13px; margin-right: 8px; font-weight: 500; }
|
|
269
|
-
.token {
|
|
270
|
-
margin-top: 12px;
|
|
271
|
-
padding: 12px;
|
|
272
|
-
background: #f3f4f6;
|
|
273
|
-
border-radius: 8px;
|
|
274
|
-
font-size: 12px;
|
|
275
|
-
word-break: break-all;
|
|
276
|
-
font-family: monospace;
|
|
268
|
+
.field { margin: 10px 0; font - size: 14px; color: #374151; }
|
|
269
|
+
.label { color: #6b7280; font - size: 13px; margin - right: 8px; font - weight: 500; }
|
|
270
|
+
.token {
|
|
271
|
+
margin - top: 12px;
|
|
272
|
+
padding: 12px;
|
|
273
|
+
background: #f3f4f6;
|
|
274
|
+
border - radius: 8px;
|
|
275
|
+
font - size: 12px;
|
|
276
|
+
word -break: break-all;
|
|
277
|
+
font - family: monospace;
|
|
277
278
|
border: 1px solid #D4AF37;
|
|
278
279
|
color: #D4AF37;
|
|
279
280
|
}
|
|
280
|
-
.grid {
|
|
281
|
-
display: grid;
|
|
282
|
-
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
|
|
283
|
-
gap: 16px;
|
|
281
|
+
.grid {
|
|
282
|
+
display: grid;
|
|
283
|
+
grid - template - columns: repeat(auto - fill, minmax(240px, 1fr));
|
|
284
|
+
gap: 16px;
|
|
284
285
|
}
|
|
285
|
-
.product-card {
|
|
286
|
-
border: 1px solid #e5e7eb;
|
|
287
|
-
border-radius: 12px;
|
|
286
|
+
.product - card {
|
|
287
|
+
border: 1px solid #e5e7eb;
|
|
288
|
+
border - radius: 12px;
|
|
288
289
|
background: #ffffff;
|
|
289
290
|
transition: all 0.3s ease;
|
|
290
291
|
cursor: pointer;
|
|
291
292
|
overflow: hidden;
|
|
292
|
-
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
293
|
+
box - shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
293
294
|
}
|
|
294
|
-
.product-card:hover {
|
|
295
|
-
border-color: #D4AF37;
|
|
296
|
-
box-shadow: 0 8px 16px rgba(212, 175, 55, 0.3);
|
|
295
|
+
.product - card:hover {
|
|
296
|
+
border - color: #D4AF37;
|
|
297
|
+
box - shadow: 0 8px 16px rgba(212, 175, 55, 0.3);
|
|
297
298
|
transform: translateY(-4px);
|
|
298
299
|
}
|
|
299
|
-
.product-card-img {
|
|
300
|
-
width: 100%;
|
|
300
|
+
.product - card - img {
|
|
301
|
+
width: 100 %;
|
|
301
302
|
height: 200px;
|
|
302
|
-
object-fit: cover;
|
|
303
|
+
object - fit: cover;
|
|
303
304
|
background: #f9fafb;
|
|
304
305
|
}
|
|
305
|
-
.product-card-body {
|
|
306
|
+
.product - card - body {
|
|
306
307
|
padding: 16px;
|
|
307
308
|
}
|
|
308
|
-
.product-name {
|
|
309
|
-
font-weight: 700;
|
|
310
|
-
font-size: 16px;
|
|
311
|
-
margin-bottom: 8px;
|
|
312
|
-
line-height: 1.3;
|
|
309
|
+
.product - name {
|
|
310
|
+
font - weight: 700;
|
|
311
|
+
font - size: 16px;
|
|
312
|
+
margin - bottom: 8px;
|
|
313
|
+
line - height: 1.3;
|
|
313
314
|
color: #1a1a1a;
|
|
314
315
|
}
|
|
315
|
-
.product-desc {
|
|
316
|
-
font-size: 13px;
|
|
316
|
+
.product - desc {
|
|
317
|
+
font - size: 13px;
|
|
317
318
|
color: #6b7280;
|
|
318
|
-
margin-bottom: 12px;
|
|
319
|
-
line-height: 1.5;
|
|
319
|
+
margin - bottom: 12px;
|
|
320
|
+
line - height: 1.5;
|
|
320
321
|
}
|
|
321
|
-
.empty {
|
|
322
|
-
color: #9ca3af;
|
|
323
|
-
text-align: center;
|
|
324
|
-
padding: 60px 20px;
|
|
325
|
-
font-size: 15px;
|
|
322
|
+
.empty {
|
|
323
|
+
color: #9ca3af;
|
|
324
|
+
text - align: center;
|
|
325
|
+
padding: 60px 20px;
|
|
326
|
+
font - size: 15px;
|
|
326
327
|
}
|
|
327
328
|
.price {
|
|
328
329
|
color: #D4AF37;
|
|
329
|
-
font-weight: 700;
|
|
330
|
-
font-size: 20px;
|
|
330
|
+
font - weight: 700;
|
|
331
|
+
font - size: 20px;
|
|
331
332
|
}
|
|
332
|
-
.stock-badge {
|
|
333
|
-
display: inline-block;
|
|
333
|
+
.stock - badge {
|
|
334
|
+
display: inline - block;
|
|
334
335
|
padding: 6px 12px;
|
|
335
|
-
border-radius: 6px;
|
|
336
|
-
font-size: 12px;
|
|
337
|
-
font-weight: 600;
|
|
336
|
+
border - radius: 6px;
|
|
337
|
+
font - size: 12px;
|
|
338
|
+
font - weight: 600;
|
|
338
339
|
background: rgba(212, 175, 55, 0.1);
|
|
339
340
|
color: #D4AF37;
|
|
340
341
|
border: 1px solid rgba(212, 175, 55, 0.3);
|
|
341
|
-
margin-top: 8px;
|
|
342
|
+
margin - top: 8px;
|
|
342
343
|
}
|
|
343
344
|
</style>
|
|
344
|
-
</head>
|
|
345
|
-
<body>
|
|
346
|
-
<div id="root">Loading...</div>
|
|
347
|
-
<script>
|
|
348
|
-
(function() {
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
345
|
+
</head>
|
|
346
|
+
< body >
|
|
347
|
+
<div id="root" > Loading...</div>
|
|
348
|
+
<script>
|
|
349
|
+
(function () {
|
|
350
|
+
function render() {
|
|
351
|
+
const data = (window.openai && window.openai.toolOutput) || {};
|
|
352
|
+
const root = document.getElementById('root');
|
|
352
353
|
|
|
353
354
|
${getWidgetRenderFunction(routePath)}
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
})();
|
|
355
|
+
|
|
356
|
+
root.innerHTML = html;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Render immediately if data available
|
|
360
|
+
if (window.openai && window.openai.toolOutput) {
|
|
361
|
+
render();
|
|
362
|
+
} else {
|
|
363
|
+
// Wait for data to be injected
|
|
364
|
+
setTimeout(render, 50);
|
|
365
|
+
}
|
|
366
|
+
})();
|
|
366
367
|
</script>
|
|
367
|
-
</body>
|
|
368
|
-
</html>`;
|
|
368
|
+
</body>
|
|
369
|
+
</html>`;
|
|
369
370
|
return baseTemplate;
|
|
370
371
|
}
|
|
371
372
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ui-next/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,eAAe,EAAa,MAAM,sBAAsB,CAAC;AAGlE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ui-next/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nitrostack",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.35",
|
|
4
4
|
"description": "NitroStack - Build powerful MCP servers with TypeScript",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/core/index.js",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
}
|
|
35
35
|
},
|
|
36
36
|
"scripts": {
|
|
37
|
-
"build": "tsc && chmod +x dist/cli/index.js",
|
|
37
|
+
"build": "tsc && cp src/cli/build-widgets.mjs dist/cli/build-widgets.mjs && chmod +x dist/cli/index.js",
|
|
38
38
|
"dev": "tsc --watch",
|
|
39
39
|
"test": "jest",
|
|
40
40
|
"prepublishOnly": "npm run build"
|
|
@@ -62,6 +62,7 @@
|
|
|
62
62
|
"commander": "^12.1.0",
|
|
63
63
|
"cors": "^2.8.5",
|
|
64
64
|
"dotenv": "^17.2.3",
|
|
65
|
+
"esbuild": "^0.24.2",
|
|
65
66
|
"express": "^4.21.2",
|
|
66
67
|
"fs-extra": "^11.3.2",
|
|
67
68
|
"http-proxy-middleware": "^3.0.3",
|
|
@@ -107,4 +108,4 @@
|
|
|
107
108
|
"url": "https://github.com/abhishekpanditofficial/nitrostack/issues"
|
|
108
109
|
},
|
|
109
110
|
"homepage": "https://nitrostack.vercel.app"
|
|
110
|
-
}
|
|
111
|
+
}
|
|
@@ -11,7 +11,7 @@ interface WidgetRendererProps {
|
|
|
11
11
|
|
|
12
12
|
export function WidgetRenderer({ uri, data, className = '' }: WidgetRendererProps) {
|
|
13
13
|
const iframeRef = useRef<HTMLIFrameElement>(null);
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
// Check if we're in dev mode (localhost)
|
|
16
16
|
const isDevMode =
|
|
17
17
|
typeof window !== 'undefined' &&
|
|
@@ -26,9 +26,9 @@ export function WidgetRenderer({ uri, data, className = '' }: WidgetRendererProp
|
|
|
26
26
|
// Remove leading slash if present
|
|
27
27
|
const widgetPath = uri.startsWith('/') ? uri.substring(1) : uri;
|
|
28
28
|
const widgetUrl = `http://localhost:3001/${widgetPath}`;
|
|
29
|
-
|
|
29
|
+
|
|
30
30
|
console.log('Loading widget in dev mode:', { uri, widgetPath, widgetUrl, data });
|
|
31
|
-
|
|
31
|
+
|
|
32
32
|
// Set up onload handler BEFORE setting src
|
|
33
33
|
iframeRef.current.onload = () => {
|
|
34
34
|
console.log('Widget iframe loaded, posting data...');
|
|
@@ -48,7 +48,7 @@ export function WidgetRenderer({ uri, data, className = '' }: WidgetRendererProp
|
|
|
48
48
|
}
|
|
49
49
|
}, 300);
|
|
50
50
|
};
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
// Set src AFTER onload handler is set
|
|
53
53
|
iframeRef.current.src = widgetUrl;
|
|
54
54
|
} else {
|
|
@@ -56,16 +56,25 @@ export function WidgetRenderer({ uri, data, className = '' }: WidgetRendererProp
|
|
|
56
56
|
const loadProductionWidget = async () => {
|
|
57
57
|
try {
|
|
58
58
|
// Convert widget route/path to resource URI format if needed
|
|
59
|
-
// Routes like "/calculator-result" or "calculator-result" should become "widget
|
|
59
|
+
// Routes like "/calculator-result" or "calculator-result" should become "ui://widget/calculator-result.html"
|
|
60
|
+
// But if it's already a full URI, use it.
|
|
60
61
|
let resourceUri = uri;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
|
|
63
|
+
if (!uri.includes('://')) {
|
|
64
|
+
// It's a path or ID
|
|
65
|
+
const widgetId = uri.startsWith('/') ? uri.substring(1) : uri;
|
|
66
|
+
// Remove .html extension if present in ID to avoid double extension
|
|
67
|
+
const cleanId = widgetId.replace(/\.html$/, '');
|
|
68
|
+
resourceUri = `ui://widget/${cleanId}.html`;
|
|
69
|
+
} else if (uri.startsWith('widget://')) {
|
|
70
|
+
// Legacy support or if user manually used widget://
|
|
71
|
+
// Convert to ui://widget/ if needed, or just use as is if the server supports it.
|
|
72
|
+
// But component.ts uses ui://widget/
|
|
73
|
+
// Let's assume the server resource map uses the full URI as key.
|
|
65
74
|
}
|
|
66
|
-
|
|
75
|
+
|
|
67
76
|
console.log('Loading widget in production mode:', { originalUri: uri, resourceUri, data });
|
|
68
|
-
|
|
77
|
+
|
|
69
78
|
const response = await fetch(`/api/resources/${encodeURIComponent(resourceUri)}`);
|
|
70
79
|
const result = await response.json();
|
|
71
80
|
|
|
@@ -88,9 +97,9 @@ export function WidgetRenderer({ uri, data, className = '' }: WidgetRendererProp
|
|
|
88
97
|
console.warn('⚠️ Widget resource found but no content:', { resourceUri, result });
|
|
89
98
|
}
|
|
90
99
|
} catch (error) {
|
|
91
|
-
console.error('❌ Failed to load widget:', {
|
|
92
|
-
originalUri: uri,
|
|
93
|
-
resourceUri,
|
|
100
|
+
console.error('❌ Failed to load widget:', {
|
|
101
|
+
originalUri: uri,
|
|
102
|
+
resourceUri,
|
|
94
103
|
error: error instanceof Error ? error.message : String(error),
|
|
95
104
|
stack: error instanceof Error ? error.stack : undefined
|
|
96
105
|
});
|
|
@@ -102,7 +111,7 @@ export function WidgetRenderer({ uri, data, className = '' }: WidgetRendererProp
|
|
|
102
111
|
}, [uri, data, isDevMode]);
|
|
103
112
|
|
|
104
113
|
const isInChat = className?.includes('widget-in-chat');
|
|
105
|
-
|
|
114
|
+
|
|
106
115
|
return (
|
|
107
116
|
<iframe
|
|
108
117
|
ref={iframeRef}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ToolDecorator as Tool,
|
|
3
|
-
Widget,
|
|
4
|
-
z,
|
|
1
|
+
import {
|
|
2
|
+
ToolDecorator as Tool,
|
|
3
|
+
Widget,
|
|
4
|
+
z,
|
|
5
5
|
ExecutionContext,
|
|
6
6
|
Injectable,
|
|
7
7
|
UseMiddleware,
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
} from 'nitrostack';
|
|
14
14
|
import { DatabaseService } from '../../services/database.service.js';
|
|
15
15
|
import { LoggingMiddleware } from '../../middleware/logging.middleware.js';
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
import { ValidationPipe } from '../../pipes/validation.pipe.js';
|
|
18
18
|
import { GlobalExceptionFilter } from '../../filters/global-exception.filter.js';
|
|
19
19
|
|
|
@@ -31,7 +31,7 @@ import { GlobalExceptionFilter } from '../../filters/global-exception.filter.js'
|
|
|
31
31
|
*/
|
|
32
32
|
@Injectable()
|
|
33
33
|
export class ProductsTools {
|
|
34
|
-
constructor(private database: DatabaseService) {}
|
|
34
|
+
constructor(private database: DatabaseService) { }
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
37
|
* Browse products - No authentication required
|
|
@@ -102,7 +102,7 @@ export class ProductsTools {
|
|
|
102
102
|
})
|
|
103
103
|
@Widget('products-grid')
|
|
104
104
|
@UseMiddleware(LoggingMiddleware)
|
|
105
|
-
|
|
105
|
+
|
|
106
106
|
@UsePipes(ValidationPipe)
|
|
107
107
|
@UseFilters(GlobalExceptionFilter)
|
|
108
108
|
@Cache({ ttl: 60, key: (input) => `products:${input.category}:${input.search}:${input.page}` })
|
|
@@ -112,50 +112,50 @@ export class ProductsTools {
|
|
|
112
112
|
const page = input.page || 1;
|
|
113
113
|
const limit = input.limit || 10;
|
|
114
114
|
const search = input.search || '';
|
|
115
|
-
|
|
115
|
+
|
|
116
116
|
const offset = (page - 1) * limit;
|
|
117
|
-
|
|
117
|
+
|
|
118
118
|
let query = 'SELECT * FROM products WHERE 1=1';
|
|
119
119
|
const params: any[] = [];
|
|
120
|
-
|
|
120
|
+
|
|
121
121
|
// Filter by category
|
|
122
122
|
if (category && category !== 'All') {
|
|
123
123
|
query += ' AND category = ?';
|
|
124
124
|
params.push(category);
|
|
125
125
|
}
|
|
126
|
-
|
|
126
|
+
|
|
127
127
|
// Search by name
|
|
128
128
|
if (search) {
|
|
129
129
|
query += ' AND name LIKE ?';
|
|
130
130
|
params.push(`%${search}%`);
|
|
131
131
|
}
|
|
132
|
-
|
|
132
|
+
|
|
133
133
|
// Add pagination
|
|
134
134
|
query += ' ORDER BY name LIMIT ? OFFSET ?';
|
|
135
135
|
params.push(limit, offset);
|
|
136
|
-
|
|
136
|
+
|
|
137
137
|
const products = this.database.query(query, params);
|
|
138
|
-
|
|
138
|
+
|
|
139
139
|
// Get total count
|
|
140
140
|
let countQuery = 'SELECT COUNT(*) as count FROM products WHERE 1=1';
|
|
141
141
|
const countParams: any[] = [];
|
|
142
|
-
|
|
142
|
+
|
|
143
143
|
if (category && category !== 'All') {
|
|
144
144
|
countQuery += ' AND category = ?';
|
|
145
145
|
countParams.push(category);
|
|
146
146
|
}
|
|
147
|
-
|
|
147
|
+
|
|
148
148
|
if (search) {
|
|
149
149
|
countQuery += ' AND name LIKE ?';
|
|
150
150
|
countParams.push(`%${search}%`);
|
|
151
151
|
}
|
|
152
|
-
|
|
152
|
+
|
|
153
153
|
const result = this.database.queryOne<{ count: number }>(countQuery, countParams);
|
|
154
154
|
const count = result?.count || 0;
|
|
155
155
|
const totalPages = Math.ceil(count / limit);
|
|
156
|
-
|
|
156
|
+
|
|
157
157
|
context.logger.info(`Browsing products: category=${category}, search=${search}, page=${page}, found=${products.length} products`);
|
|
158
|
-
|
|
158
|
+
|
|
159
159
|
return {
|
|
160
160
|
products,
|
|
161
161
|
pagination: {
|
|
@@ -199,27 +199,27 @@ export class ProductsTools {
|
|
|
199
199
|
})
|
|
200
200
|
@Widget('product-card')
|
|
201
201
|
@UseMiddleware(LoggingMiddleware)
|
|
202
|
-
|
|
202
|
+
|
|
203
203
|
@UsePipes(ValidationPipe)
|
|
204
204
|
@UseFilters(GlobalExceptionFilter)
|
|
205
205
|
@Cache({ ttl: 300, key: (input) => `product:${input.product_id}` }) // Cache for 5 minutes
|
|
206
206
|
@RateLimit({ requests: 100, window: '1m' }) // 100 requests per minute
|
|
207
207
|
async getProductDetails(input: any, context: ExecutionContext) {
|
|
208
208
|
const product = this.database.queryOne(`SELECT * FROM products WHERE id = ?`, [input.product_id]);
|
|
209
|
-
|
|
209
|
+
|
|
210
210
|
if (!product) {
|
|
211
211
|
throw new Error(`Product with ID ${input.product_id} not found`);
|
|
212
212
|
}
|
|
213
|
-
|
|
213
|
+
|
|
214
214
|
context.logger.info(`Retrieved details for product: ${(product as any).name}`);
|
|
215
|
-
|
|
215
|
+
|
|
216
216
|
return {
|
|
217
217
|
product,
|
|
218
218
|
availability: (product as any).stock > 0 ? 'In Stock' : 'Out of Stock',
|
|
219
|
-
stockMessage: (product as any).stock > 10
|
|
220
|
-
? 'Available'
|
|
221
|
-
: (product as any).stock > 0
|
|
222
|
-
? `Only ${(product as any).stock} left!`
|
|
219
|
+
stockMessage: (product as any).stock > 10
|
|
220
|
+
? 'Available'
|
|
221
|
+
: (product as any).stock > 0
|
|
222
|
+
? `Only ${(product as any).stock} left!`
|
|
223
223
|
: 'Currently unavailable',
|
|
224
224
|
};
|
|
225
225
|
}
|
|
@@ -246,7 +246,7 @@ export class ProductsTools {
|
|
|
246
246
|
})
|
|
247
247
|
@Widget('categories')
|
|
248
248
|
@UseMiddleware(LoggingMiddleware)
|
|
249
|
-
|
|
249
|
+
|
|
250
250
|
@Cache({ ttl: 300 }) // Cache for 5 minutes
|
|
251
251
|
async getCategories(input: any, context: ExecutionContext) {
|
|
252
252
|
const categories = this.database.query(`
|
|
@@ -255,7 +255,7 @@ export class ProductsTools {
|
|
|
255
255
|
GROUP BY category
|
|
256
256
|
ORDER BY category
|
|
257
257
|
`);
|
|
258
|
-
|
|
258
|
+
|
|
259
259
|
return {
|
|
260
260
|
categories: categories.map((c: any) => ({
|
|
261
261
|
name: c.category,
|