@mostfeatured/dbi 0.2.14 → 0.2.16
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/src/types/Components/HTMLComponentsV2/index.d.ts +35 -1
- package/dist/src/types/Components/HTMLComponentsV2/index.d.ts.map +1 -1
- package/dist/src/types/Components/HTMLComponentsV2/index.js +416 -83
- package/dist/src/types/Components/HTMLComponentsV2/index.js.map +1 -1
- package/dist/src/types/Components/HTMLComponentsV2/parser.d.ts +52 -0
- package/dist/src/types/Components/HTMLComponentsV2/parser.d.ts.map +1 -1
- package/dist/src/types/Components/HTMLComponentsV2/parser.js +275 -0
- package/dist/src/types/Components/HTMLComponentsV2/parser.js.map +1 -1
- package/dist/src/types/Components/HTMLComponentsV2/svelteParser.d.ts +28 -1
- package/dist/src/types/Components/HTMLComponentsV2/svelteParser.d.ts.map +1 -1
- package/dist/src/types/Components/HTMLComponentsV2/svelteParser.js +478 -34
- package/dist/src/types/Components/HTMLComponentsV2/svelteParser.js.map +1 -1
- package/dist/src/types/Components/HTMLComponentsV2/svelteRenderer.d.ts +12 -0
- package/dist/src/types/Components/HTMLComponentsV2/svelteRenderer.d.ts.map +1 -1
- package/dist/src/types/Components/HTMLComponentsV2/svelteRenderer.js +102 -18
- package/dist/src/types/Components/HTMLComponentsV2/svelteRenderer.js.map +1 -1
- package/dist/test/index.js +76 -3
- package/dist/test/index.js.map +1 -1
- package/dist/test/test.d.ts +2 -0
- package/dist/test/test.d.ts.map +1 -0
- package/dist/test/test.js +7 -0
- package/dist/test/test.js.map +1 -0
- package/docs/ADVANCED_FEATURES.md +4 -0
- package/docs/API_REFERENCE.md +4 -0
- package/docs/CHAT_INPUT.md +4 -0
- package/docs/COMPONENTS.md +4 -0
- package/docs/EVENTS.md +4 -0
- package/docs/GETTING_STARTED.md +4 -0
- package/docs/LOCALIZATION.md +4 -0
- package/docs/README.md +4 -0
- package/docs/SVELTE_COMPONENTS.md +162 -6
- package/docs/llm/ADVANCED_FEATURES.txt +521 -0
- package/docs/llm/API_REFERENCE.txt +659 -0
- package/docs/llm/CHAT_INPUT.txt +514 -0
- package/docs/llm/COMPONENTS.txt +595 -0
- package/docs/llm/EVENTS.txt +449 -0
- package/docs/llm/GETTING_STARTED.txt +296 -0
- package/docs/llm/LOCALIZATION.txt +501 -0
- package/docs/llm/README.txt +193 -0
- package/docs/llm/SVELTE_COMPONENTS.txt +566 -0
- package/generated/svelte-dbi.d.ts +122 -0
- package/package.json +1 -1
- package/src/types/Components/HTMLComponentsV2/index.ts +478 -95
- package/src/types/Components/HTMLComponentsV2/parser.ts +317 -0
- package/src/types/Components/HTMLComponentsV2/svelteParser.ts +536 -35
- package/src/types/Components/HTMLComponentsV2/svelteRenderer.ts +121 -20
- package/test/index.ts +76 -3
- package/test/product-showcase.svelte +383 -24
- package/test/test.ts +3 -0
- package/llm.txt +0 -1088
|
@@ -1,20 +1,33 @@
|
|
|
1
1
|
import { compile } from "svelte/compiler";
|
|
2
2
|
import { DBI } from "../../../DBI";
|
|
3
3
|
import { NamespaceEnums } from "../../../../generated/namespaceData";
|
|
4
|
-
import { parseHTMLComponentsV2 } from "./parser";
|
|
5
|
-
import { parseSvelteComponent, createHandlerContext, SvelteComponentInfo, HandlerContextResult } from "./svelteParser";
|
|
4
|
+
import { parseHTMLComponentsV2, parseHTMLComponentsV2Multi } from "./parser";
|
|
5
|
+
import { parseSvelteComponent, createHandlerContext, SvelteComponentInfo, HandlerContextResult, validateSvelteComponent, logValidationWarnings } from "./svelteParser";
|
|
6
6
|
import * as stuffs from "stuffs";
|
|
7
7
|
import * as vm from "vm";
|
|
8
8
|
|
|
9
9
|
export interface SvelteRenderOptions {
|
|
10
10
|
data?: Record<string, any>;
|
|
11
11
|
ttl?: number;
|
|
12
|
+
/** If true, skips validation warnings (useful for production) */
|
|
13
|
+
skipValidation?: boolean;
|
|
14
|
+
/** The file path of the Svelte component (used for resolving relative imports) */
|
|
15
|
+
filePath?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface ModalDefinition {
|
|
19
|
+
title: string;
|
|
20
|
+
customId: string;
|
|
21
|
+
components: any[];
|
|
22
|
+
modalId: string;
|
|
12
23
|
}
|
|
13
24
|
|
|
14
25
|
export interface SvelteRenderResult {
|
|
15
26
|
components: any[];
|
|
16
27
|
handlers: Map<string, { handlerFn: Function, context: any }>;
|
|
17
28
|
componentInfo: SvelteComponentInfo;
|
|
29
|
+
/** Modal definitions parsed from <components type="modal"> elements */
|
|
30
|
+
modals: Map<string, ModalDefinition>;
|
|
18
31
|
}
|
|
19
32
|
|
|
20
33
|
/**
|
|
@@ -26,35 +39,99 @@ export async function renderSvelteComponent(
|
|
|
26
39
|
dbiName: string,
|
|
27
40
|
options: SvelteRenderOptions = {}
|
|
28
41
|
): Promise<SvelteRenderResult> {
|
|
29
|
-
const { data = {}, ttl = 0 } = options;
|
|
42
|
+
const { data = {}, ttl = 0, skipValidation = false, filePath } = options;
|
|
30
43
|
|
|
31
44
|
// Parse the Svelte component to extract handlers
|
|
32
45
|
// This also injects auto-generated names into elements without name attribute
|
|
33
46
|
const componentInfo = await parseSvelteComponent(source, data);
|
|
34
47
|
|
|
48
|
+
// Validate the component and log warnings (only on first render, not re-renders)
|
|
49
|
+
if (!skipValidation && !data.$ref) {
|
|
50
|
+
const warnings = validateSvelteComponent(componentInfo, data, dbiName);
|
|
51
|
+
if (warnings.length > 0) {
|
|
52
|
+
logValidationWarnings(warnings);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
35
56
|
// Use the processed source (with auto-generated names injected)
|
|
36
57
|
const processedSource = componentInfo.processedSource;
|
|
37
58
|
|
|
38
59
|
// Compile the Svelte component for SSR (Svelte 5)
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
60
|
+
let compiled;
|
|
61
|
+
try {
|
|
62
|
+
compiled = compile(processedSource, {
|
|
63
|
+
generate: "server",
|
|
64
|
+
css: "injected",
|
|
65
|
+
dev: false,
|
|
66
|
+
} as any);
|
|
67
|
+
} catch (compileError: any) {
|
|
68
|
+
// Format Svelte compile error with helpful details
|
|
69
|
+
const errorMessage = compileError.message || 'Unknown compile error';
|
|
70
|
+
const location = compileError.start || compileError.loc || compileError.position;
|
|
71
|
+
let details = errorMessage;
|
|
72
|
+
|
|
73
|
+
if (location) {
|
|
74
|
+
const lines = processedSource.split('\n');
|
|
75
|
+
const lineNum = location.line || 1;
|
|
76
|
+
const column = location.column || 0;
|
|
77
|
+
const errorLine = lines[lineNum - 1] || '';
|
|
78
|
+
const prevLine = lines[lineNum - 2] || '';
|
|
79
|
+
const nextLine = lines[lineNum] || '';
|
|
80
|
+
|
|
81
|
+
details = `
|
|
82
|
+
Svelte Compile Error at line ${lineNum}, column ${column}:
|
|
83
|
+
${errorMessage}
|
|
84
|
+
|
|
85
|
+
${lineNum > 1 ? `${lineNum - 1} | ${prevLine}\n` : ''}${lineNum} | ${errorLine}
|
|
86
|
+
${' '.repeat(String(lineNum).length + 3 + column)}^
|
|
87
|
+
${nextLine ? `${lineNum + 1} | ${nextLine}` : ''}
|
|
88
|
+
`.trim();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Check for common mistakes and add hints
|
|
92
|
+
let hint = '';
|
|
93
|
+
if (errorMessage.includes('Unexpected token')) {
|
|
94
|
+
hint = '\n\n💡 Hint: Check for missing closing tags, unclosed braces, or invalid JavaScript syntax.';
|
|
95
|
+
} else if (errorMessage.includes('is not defined')) {
|
|
96
|
+
hint = '\n\n💡 Hint: Make sure all variables are declared in $props() or as local variables.';
|
|
97
|
+
} else if (errorMessage.includes('Expected')) {
|
|
98
|
+
hint = '\n\n💡 Hint: There might be a syntax error in your template or script.';
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const enhancedError = new Error(`[DBI-Svelte] Failed to compile component "${dbiName}":\n${details}${hint}`);
|
|
102
|
+
(enhancedError as any).originalError = compileError;
|
|
103
|
+
(enhancedError as any).type = 'svelte-compile-error';
|
|
104
|
+
throw enhancedError;
|
|
105
|
+
}
|
|
44
106
|
|
|
45
107
|
// Create a module context for the compiled code
|
|
46
108
|
let html = "";
|
|
47
109
|
try {
|
|
48
110
|
const moduleContext = createModuleContext(dbi, data, ttl);
|
|
49
|
-
const Component = evaluateCompiledComponent(compiled.js.code, moduleContext);
|
|
111
|
+
const Component = evaluateCompiledComponent(compiled.js.code, moduleContext, filePath);
|
|
50
112
|
|
|
51
113
|
// Svelte 5 SSR: Use render from svelte/server
|
|
52
114
|
const { render } = require("svelte/server");
|
|
53
115
|
// Pass data properties as top-level props (Svelte 5 expects flat props object)
|
|
54
116
|
const renderResult = render(Component, { props: data });
|
|
55
117
|
html = renderResult.body || "";
|
|
56
|
-
} catch (
|
|
57
|
-
|
|
118
|
+
} catch (runtimeError: any) {
|
|
119
|
+
// Format runtime error with helpful details
|
|
120
|
+
const errorMessage = runtimeError.message || 'Unknown runtime error';
|
|
121
|
+
let hint = '';
|
|
122
|
+
|
|
123
|
+
if (errorMessage.includes('is not a function')) {
|
|
124
|
+
hint = '\n\n💡 Hint: A function you are trying to call is undefined. Check handler names.';
|
|
125
|
+
} else if (errorMessage.includes('Cannot read properties of undefined') || errorMessage.includes('undefined is not an object')) {
|
|
126
|
+
hint = '\n\n💡 Hint: You are trying to access a property of an undefined value. Check your data object.';
|
|
127
|
+
} else if (errorMessage.includes('is not defined')) {
|
|
128
|
+
hint = '\n\n💡 Hint: A variable is used but not declared. Make sure it is in $props() or declared locally.';
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const enhancedError = new Error(`[DBI-Svelte] Runtime error in component "${dbiName}":\n${errorMessage}${hint}`);
|
|
132
|
+
(enhancedError as any).originalError = runtimeError;
|
|
133
|
+
(enhancedError as any).type = 'svelte-runtime-error';
|
|
134
|
+
throw enhancedError;
|
|
58
135
|
}
|
|
59
136
|
|
|
60
137
|
// For Svelte mode, inject state into interactive elements as a ref
|
|
@@ -102,11 +179,17 @@ export async function renderSvelteComponent(
|
|
|
102
179
|
});
|
|
103
180
|
}
|
|
104
181
|
|
|
105
|
-
// Parse the rendered HTML to Discord components
|
|
106
|
-
const
|
|
182
|
+
// Parse the rendered HTML to Discord components (with modal support)
|
|
183
|
+
const parseResult = parseHTMLComponentsV2Multi(dbi, html, dbiName, { data, ttl });
|
|
184
|
+
const components = parseResult.components;
|
|
185
|
+
const modals = parseResult.modals;
|
|
186
|
+
|
|
187
|
+
// Get source directory for resolving relative imports
|
|
188
|
+
const path = require("path");
|
|
189
|
+
const sourceDir = filePath ? path.dirname(path.resolve(filePath)) : undefined;
|
|
107
190
|
|
|
108
191
|
// Create handler context (also captures $effect callbacks)
|
|
109
|
-
const handlerContext = createHandlerContext(componentInfo.scriptContent, data);
|
|
192
|
+
const handlerContext = createHandlerContext(componentInfo.scriptContent, data, undefined, undefined, sourceDir);
|
|
110
193
|
const handlers = new Map<string, { handlerFn: Function, context: any }>();
|
|
111
194
|
|
|
112
195
|
// Run effects on initial render
|
|
@@ -126,7 +209,8 @@ export async function renderSvelteComponent(
|
|
|
126
209
|
return {
|
|
127
210
|
components,
|
|
128
211
|
handlers,
|
|
129
|
-
componentInfo
|
|
212
|
+
componentInfo,
|
|
213
|
+
modals
|
|
130
214
|
};
|
|
131
215
|
}
|
|
132
216
|
|
|
@@ -155,10 +239,14 @@ function createModuleContext(dbi: DBI<NamespaceEnums>, data: Record<string, any>
|
|
|
155
239
|
/**
|
|
156
240
|
* Evaluate the compiled Svelte component code
|
|
157
241
|
*/
|
|
158
|
-
function evaluateCompiledComponent(code: string, context: Record<string, any
|
|
242
|
+
function evaluateCompiledComponent(code: string, context: Record<string, any>, filePath?: string): any {
|
|
159
243
|
try {
|
|
160
244
|
// Load Svelte 5 internal runtime
|
|
161
245
|
const svelteInternal = require("svelte/internal/server");
|
|
246
|
+
const path = require("path");
|
|
247
|
+
|
|
248
|
+
// Get the directory of the source file for resolving relative imports
|
|
249
|
+
const sourceDir = filePath ? path.dirname(path.resolve(filePath)) : process.cwd();
|
|
162
250
|
|
|
163
251
|
// Process the code to work in our context
|
|
164
252
|
let processedCode = code;
|
|
@@ -186,7 +274,11 @@ function evaluateCompiledComponent(code: string, context: Record<string, any>):
|
|
|
186
274
|
// Skip svelte imports
|
|
187
275
|
if (modulePath.startsWith('svelte')) return '';
|
|
188
276
|
try {
|
|
189
|
-
|
|
277
|
+
// Resolve relative paths from source file directory
|
|
278
|
+
const resolvedPath = modulePath.startsWith('.')
|
|
279
|
+
? path.resolve(sourceDir, modulePath)
|
|
280
|
+
: modulePath;
|
|
281
|
+
const mod = require(resolvedPath);
|
|
190
282
|
externalModules[varName] = mod.default || mod;
|
|
191
283
|
return `const ${varName} = __externalModules.${varName};`;
|
|
192
284
|
} catch (e) {
|
|
@@ -202,7 +294,11 @@ function evaluateCompiledComponent(code: string, context: Record<string, any>):
|
|
|
202
294
|
// Skip svelte imports
|
|
203
295
|
if (modulePath.startsWith('svelte')) return '';
|
|
204
296
|
try {
|
|
205
|
-
|
|
297
|
+
// Resolve relative paths from source file directory
|
|
298
|
+
const resolvedPath = modulePath.startsWith('.')
|
|
299
|
+
? path.resolve(sourceDir, modulePath)
|
|
300
|
+
: modulePath;
|
|
301
|
+
const mod = require(resolvedPath);
|
|
206
302
|
const importList = imports.split(',').map((i: string) => i.trim());
|
|
207
303
|
importList.forEach((importName: string) => {
|
|
208
304
|
const [name, alias] = importName.split(' as ').map(s => s.trim());
|
|
@@ -225,7 +321,11 @@ function evaluateCompiledComponent(code: string, context: Record<string, any>):
|
|
|
225
321
|
// Skip svelte imports
|
|
226
322
|
if (modulePath.startsWith('svelte')) return '';
|
|
227
323
|
try {
|
|
228
|
-
|
|
324
|
+
// Resolve relative paths from source file directory
|
|
325
|
+
const resolvedPath = modulePath.startsWith('.')
|
|
326
|
+
? path.resolve(sourceDir, modulePath)
|
|
327
|
+
: modulePath;
|
|
328
|
+
const mod = require(resolvedPath);
|
|
229
329
|
externalModules[varName] = mod;
|
|
230
330
|
return `const ${varName} = __externalModules.${varName};`;
|
|
231
331
|
} catch (e) {
|
|
@@ -311,5 +411,6 @@ export async function renderSvelteComponentFromFile(
|
|
|
311
411
|
): Promise<SvelteRenderResult> {
|
|
312
412
|
const fs = require("fs");
|
|
313
413
|
const source = fs.readFileSync(filePath, "utf-8");
|
|
314
|
-
|
|
414
|
+
// Pass filePath to options for resolving relative imports
|
|
415
|
+
return await renderSvelteComponent(dbi, source, dbiName, { ...options, filePath });
|
|
315
416
|
}
|
package/test/index.ts
CHANGED
|
@@ -26,8 +26,7 @@ dbi.register(({ ChatInput, HTMLComponentsV2 }) => {
|
|
|
26
26
|
HTMLComponentsV2({
|
|
27
27
|
name: "product-showcase",
|
|
28
28
|
mode: 'svelte',
|
|
29
|
-
file: path.join(__dirname, "product-showcase.svelte")
|
|
30
|
-
onExecute(ctx) {}
|
|
29
|
+
file: path.join(__dirname, "product-showcase.svelte")
|
|
31
30
|
});
|
|
32
31
|
|
|
33
32
|
// Test command
|
|
@@ -73,6 +72,78 @@ dbi.register(({ ChatInput, HTMLComponentsV2 }) => {
|
|
|
73
72
|
category: "Furniture",
|
|
74
73
|
rating: 4.6,
|
|
75
74
|
stock: 31
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: "Webcam 4K",
|
|
78
|
+
description: "Ultra HD webcam with autofocus and noise-canceling mic",
|
|
79
|
+
price: 129,
|
|
80
|
+
image: "https://cdn.discordapp.com/embed/avatars/4.png",
|
|
81
|
+
category: "Electronics",
|
|
82
|
+
rating: 4.7,
|
|
83
|
+
stock: 15
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: "Desk Lamp",
|
|
87
|
+
description: "LED desk lamp with adjustable brightness and color temperature",
|
|
88
|
+
price: 45,
|
|
89
|
+
image: "https://cdn.discordapp.com/embed/avatars/0.png",
|
|
90
|
+
category: "Furniture",
|
|
91
|
+
rating: 4.4,
|
|
92
|
+
stock: 60
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
name: "Headphone Stand",
|
|
96
|
+
description: "Aluminum headphone stand with cable holder",
|
|
97
|
+
price: 35,
|
|
98
|
+
image: "https://cdn.discordapp.com/embed/avatars/1.png",
|
|
99
|
+
category: "Accessories",
|
|
100
|
+
rating: 4.2,
|
|
101
|
+
stock: 28
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
name: "Gaming Headset",
|
|
105
|
+
description: "7.1 surround sound gaming headset with RGB lighting",
|
|
106
|
+
price: 99,
|
|
107
|
+
image: "https://cdn.discordapp.com/embed/avatars/2.png",
|
|
108
|
+
category: "Electronics",
|
|
109
|
+
rating: 4.6,
|
|
110
|
+
stock: 35
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
name: "Mouse Pad XL",
|
|
114
|
+
description: "Extended mouse pad with stitched edges, 900x400mm",
|
|
115
|
+
price: 25,
|
|
116
|
+
image: "https://cdn.discordapp.com/embed/avatars/3.png",
|
|
117
|
+
category: "Accessories",
|
|
118
|
+
rating: 4.8,
|
|
119
|
+
stock: 100
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
name: "Ergonomic Chair",
|
|
123
|
+
description: "Mesh office chair with lumbar support and adjustable armrests",
|
|
124
|
+
price: 299,
|
|
125
|
+
image: "https://cdn.discordapp.com/embed/avatars/4.png",
|
|
126
|
+
category: "Furniture",
|
|
127
|
+
rating: 4.9,
|
|
128
|
+
stock: 8
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
name: "Cable Management Kit",
|
|
132
|
+
description: "Complete kit with cable clips, ties, and sleeve",
|
|
133
|
+
price: 19,
|
|
134
|
+
image: "https://cdn.discordapp.com/embed/avatars/0.png",
|
|
135
|
+
category: "Accessories",
|
|
136
|
+
rating: 4.1,
|
|
137
|
+
stock: 75
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
name: "Portable SSD 1TB",
|
|
141
|
+
description: "Ultra-fast portable SSD with USB 3.2 Gen 2",
|
|
142
|
+
price: 109,
|
|
143
|
+
image: "https://cdn.discordapp.com/embed/avatars/1.png",
|
|
144
|
+
category: "Electronics",
|
|
145
|
+
rating: 4.7,
|
|
146
|
+
stock: 22
|
|
76
147
|
}
|
|
77
148
|
];
|
|
78
149
|
|
|
@@ -84,7 +155,9 @@ dbi.register(({ ChatInput, HTMLComponentsV2 }) => {
|
|
|
84
155
|
currentIndex: 0,
|
|
85
156
|
cart: [],
|
|
86
157
|
view: 'browse',
|
|
87
|
-
elapsedTime: 0
|
|
158
|
+
elapsedTime: 0,
|
|
159
|
+
reviews: [],
|
|
160
|
+
editingProduct: null
|
|
88
161
|
}
|
|
89
162
|
});
|
|
90
163
|
}
|