@ptkl/toolkit 0.7.2 → 0.8.8

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.
@@ -14,12 +14,13 @@ program.hook('preAction', (thisCommand, actionCommand) => {
14
14
  });
15
15
  commands.forEach(c => program.addCommand(c));
16
16
  program.parseAsync(process.argv).catch((err) => {
17
+ console.log("An error occurred while executing the command.", err);
17
18
  const { response } = err;
18
19
  if (response && response.data) {
19
- console.error(response.data.message);
20
+ console.error(response.data.message || "An error occurred with the API request.");
20
21
  }
21
22
  else {
22
- console.error(err.message || err);
23
+ console.error(err.message || err || "An unknown error occurred.");
23
24
  }
24
25
  process.exit(1);
25
26
  });
@@ -1,14 +1,14 @@
1
1
  import CompilerSDK4 from "./sdk4/vue2.js";
2
2
  import CompilerSDK5 from "./sdk5/vue2.js";
3
- import CompilerSDK5Vue3 from "./sdk5/vue3.js";
4
- import CompiltedSDK5React from "./sdk5/react.js";
5
- const latestVersion = 5;
6
- const defaultEngine = 'vue2';
3
+ import CompilerSDK6WebComponents from "./sdk6/webcomponents.js";
4
+ import CompilerSDK6Lit from "./sdk6/lit.js";
5
+ const latestVersion = 6;
6
+ const defaultEngine = 'webcomponents';
7
7
  const compilers = {
8
8
  'sdk4::vue2': new CompilerSDK4,
9
9
  'sdk5::vue2': new CompilerSDK5,
10
- 'sdk5::vue3': new CompilerSDK5Vue3,
11
- 'sdk5::react': new CompiltedSDK5React,
10
+ 'sdk6::webcomponents': new CompilerSDK6WebComponents,
11
+ 'sdk6::lit': new CompilerSDK6Lit,
12
12
  };
13
13
  export default {
14
14
  getCompiler(sdkVersion, engine) {
@@ -0,0 +1,52 @@
1
+ import * as Babel from '@babel/standalone';
2
+ import * as sass from 'sass';
3
+ export default class Compiler {
4
+ async compileBabel(expression) {
5
+ let code = Babel.transform(expression, {
6
+ sourceType: "module",
7
+ presets: [
8
+ "env",
9
+ ["typescript", {
10
+ onlyRemoveTypeImports: true,
11
+ allowDeclareFields: true
12
+ }]
13
+ ],
14
+ plugins: [
15
+ ["proposal-decorators", { version: "2023-05" }],
16
+ "proposal-class-properties"
17
+ ]
18
+ });
19
+ return code.code;
20
+ }
21
+ async compileCSS(scope, lang, expression) {
22
+ switch (lang) {
23
+ case 'scss':
24
+ case 'sass':
25
+ if (scope) {
26
+ const result = sass.compileString(`.${scope} { ${expression} }`);
27
+ return result.css;
28
+ }
29
+ const result = sass.compileString(expression);
30
+ return result.css;
31
+ default:
32
+ return expression;
33
+ }
34
+ }
35
+ async compile(ext, content) {
36
+ switch (ext) {
37
+ case 'js':
38
+ case 'ts':
39
+ return await this.compileBabel(content);
40
+ case 'css':
41
+ return await this.compileCSS(null, "css", content);
42
+ case 'scss':
43
+ case 'sass':
44
+ return await this.compileCSS(null, ext, content);
45
+ default:
46
+ return await Promise.resolve(content);
47
+ }
48
+ }
49
+ getSupportedExt() {
50
+ return ["js", "ts", "css", "scss", "sass", "json", "svg", "html"];
51
+ }
52
+ }
@@ -0,0 +1,56 @@
1
+ import * as Babel from '@babel/standalone';
2
+ import * as sass from 'sass';
3
+ export default class Compiler {
4
+ async compileBabel(expression) {
5
+ let code = Babel.transform(expression, {
6
+ sourceType: "module",
7
+ presets: [
8
+ "env",
9
+ ["react", { runtime: "automatic" }],
10
+ ["typescript", {
11
+ onlyRemoveTypeImports: true,
12
+ isTSX: true,
13
+ allExtensions: true
14
+ }]
15
+ ],
16
+ plugins: [
17
+ '@babel/plugin-proposal-class-properties',
18
+ '@babel/plugin-transform-class-static-block'
19
+ ]
20
+ });
21
+ return code.code;
22
+ }
23
+ async compileCSS(scope, lang, expression) {
24
+ switch (lang) {
25
+ case 'scss':
26
+ case 'sass':
27
+ if (scope) {
28
+ const result = sass.compileString(`.${scope} { ${expression} }`);
29
+ return result.css;
30
+ }
31
+ const result = sass.compileString(expression);
32
+ return result.css;
33
+ default:
34
+ return expression;
35
+ }
36
+ }
37
+ async compile(ext, content) {
38
+ switch (ext) {
39
+ case 'js':
40
+ case 'jsx':
41
+ case 'ts':
42
+ case 'tsx':
43
+ return await this.compileBabel(content);
44
+ case 'css':
45
+ return await this.compileCSS(null, "css", content);
46
+ case 'scss':
47
+ case 'sass':
48
+ return await this.compileCSS(null, ext, content);
49
+ default:
50
+ return await Promise.resolve(content);
51
+ }
52
+ }
53
+ getSupportedExt() {
54
+ return ["js", "jsx", "ts", "tsx", "css", "scss", "sass", "json", "svg", "html"];
55
+ }
56
+ }
@@ -0,0 +1,52 @@
1
+ import * as Babel from '@babel/standalone';
2
+ import * as sass from 'sass';
3
+ export default class Compiler {
4
+ async compileBabel(expression) {
5
+ let code = Babel.transform(expression, {
6
+ sourceType: "module",
7
+ presets: [
8
+ "env",
9
+ ["typescript", {
10
+ onlyRemoveTypeImports: true,
11
+ allExtensions: true
12
+ }]
13
+ ],
14
+ plugins: [
15
+ '@babel/plugin-proposal-class-properties',
16
+ '@babel/plugin-transform-class-static-block'
17
+ ]
18
+ });
19
+ return code.code;
20
+ }
21
+ async compileCSS(scope, lang, expression) {
22
+ switch (lang) {
23
+ case 'scss':
24
+ case 'sass':
25
+ if (scope) {
26
+ const result = sass.compileString(`.${scope} { ${expression} }`);
27
+ return result.css;
28
+ }
29
+ const result = sass.compileString(expression);
30
+ return result.css;
31
+ default:
32
+ return expression;
33
+ }
34
+ }
35
+ async compile(ext, content) {
36
+ switch (ext) {
37
+ case 'js':
38
+ case 'ts':
39
+ return await this.compileBabel(content);
40
+ case 'css':
41
+ return await this.compileCSS(null, "css", content);
42
+ case 'scss':
43
+ case 'sass':
44
+ return await this.compileCSS(null, ext, content);
45
+ default:
46
+ return await Promise.resolve(content);
47
+ }
48
+ }
49
+ getSupportedExt() {
50
+ return ["js", "ts", "css", "scss", "sass", "json", "svg", "html", "vue"];
51
+ }
52
+ }
@@ -0,0 +1,41 @@
1
+ import * as Babel from '@babel/standalone';
2
+ import * as sass from 'sass';
3
+ export default class Compiler {
4
+ async compileBabel(expression) {
5
+ let code = Babel.transform(expression, {
6
+ sourceType: "module",
7
+ presets: ["env"]
8
+ });
9
+ return code.code;
10
+ }
11
+ async compileCSS(scope, lang, expression) {
12
+ switch (lang) {
13
+ case 'scss':
14
+ case 'sass':
15
+ if (scope) {
16
+ const result = sass.compileString(`.${scope} { ${expression} }`);
17
+ return result.css;
18
+ }
19
+ const result = sass.compileString(expression);
20
+ return result.css;
21
+ default:
22
+ return expression;
23
+ }
24
+ }
25
+ async compile(ext, content) {
26
+ switch (ext) {
27
+ case 'js':
28
+ return await this.compileBabel(content);
29
+ case 'css':
30
+ return await this.compileCSS(null, "css", content);
31
+ case 'scss':
32
+ case 'sass':
33
+ return await this.compileCSS(null, ext, content);
34
+ default:
35
+ return await Promise.resolve(content);
36
+ }
37
+ }
38
+ getSupportedExt() {
39
+ return ["js", "css", "scss", "sass", "json", "svg", "html"];
40
+ }
41
+ }
@@ -1,6 +1,6 @@
1
1
  import { Command } from "commander";
2
2
  import util from "../lib/util.js";
3
- import Api from "@ptkl/sdk";
3
+ import { Platform as Api } from "@ptkl/sdk";
4
4
  import OutputFormatCommand from "./outputCommand.js";
5
5
  class ApiUsersCommand {
6
6
  register() {
@@ -1,6 +1,6 @@
1
1
  import { Command, Option } from "commander";
2
2
  import util from "../lib/util.js";
3
- import Api from "@ptkl/sdk";
3
+ import { Platform as Api } from "@ptkl/sdk";
4
4
  import { build, createServer } from 'vite';
5
5
  import { c } from 'tar';
6
6
  import { Writable } from "stream";
@@ -129,7 +129,7 @@ class AppsCommand {
129
129
  async bundle(options) {
130
130
  const { path, upload } = options;
131
131
  const module = await import(`${path}/ptkl.config.js`);
132
- const { views, name, version, distPath, icon, label, permissions, } = module.default ?? {};
132
+ const { views, name, version, distPath, icon, label, permissions, install_permissions, runtime_permissions, requires, scripts, } = module.default ?? {};
133
133
  // build manifest file
134
134
  const manifest = {
135
135
  name,
@@ -138,6 +138,10 @@ class AppsCommand {
138
138
  label,
139
139
  icon,
140
140
  permissions,
141
+ install_permissions: install_permissions ?? [],
142
+ runtime_permissions: runtime_permissions ?? [],
143
+ requires: requires ?? null,
144
+ scripts,
141
145
  };
142
146
  const profile = Util.getCurrentProfile();
143
147
  const client = Util.getClientForProfile();
@@ -161,9 +165,29 @@ class AppsCommand {
161
165
  }
162
166
  });
163
167
  });
168
+ console.log("manifest", manifest);
169
+ const buildScripts = Object.keys(scripts).map((script) => {
170
+ manifest.scripts[script] = `${script}.script.js`;
171
+ return build({
172
+ root: path,
173
+ base,
174
+ build: {
175
+ rollupOptions: {
176
+ input: scripts[script],
177
+ output: {
178
+ format: 'iife',
179
+ entryFileNames: `${script}.script.js`,
180
+ }
181
+ }
182
+ }
183
+ });
184
+ });
164
185
  await Promise.allSettled(buildViews).catch(err => {
165
186
  console.error('Error building:', err);
166
187
  });
188
+ await Promise.allSettled(buildScripts).catch(err => {
189
+ console.error('Error building:', err);
190
+ });
167
191
  console.log("Packaging app...");
168
192
  // // write manifest file
169
193
  const manifestPath = `${distPath}/manifest.json`;
@@ -1,10 +1,16 @@
1
1
  import { Command } from "commander";
2
2
  import Builder from "../builder/index.js";
3
3
  import { WebSocketServer } from "ws";
4
- import { resolve } from "path";
4
+ import { resolve, join, dirname } from "path";
5
5
  import { rollup } from "rollup";
6
6
  import util from "../lib/util.js";
7
- import Api from "@ptkl/sdk";
7
+ import { Platform as Api } from "@ptkl/sdk";
8
+ import { mkdirSync, writeFileSync, rmSync, readdirSync, existsSync, readFileSync } from "fs";
9
+ import { nodeResolve } from '@rollup/plugin-node-resolve';
10
+ // @ts-ignore
11
+ import commonjsPlugin from '@rollup/plugin-commonjs';
12
+ import { babel as babelPlugin } from '@rollup/plugin-babel';
13
+ import { execSync } from 'child_process';
8
14
  class ComponentCommand {
9
15
  register() {
10
16
  return new Command("component")
@@ -13,37 +19,314 @@ class ComponentCommand {
13
19
  .addCommand(new Command("builder")
14
20
  .description("Run builder for component templates")
15
21
  .requiredOption("-v, --version <version>", "SDK version to be used for build", "6")
16
- .requiredOption("-e, --engine <engine>", "SDK engine to be used for build", "react")
17
- .action(this.builder))
22
+ .requiredOption("-e, --engine <engine>", "SDK engine to be used for build", "webcomponents")
23
+ .option("-p, --port <port>", "WSS port", "11403")
24
+ .action(this.builder.bind(this)))
18
25
  .addCommand(new Command("build")
19
26
  .description("Build templates for component")
20
27
  .requiredOption("-p, --path <path>", "Path to the source files", "./")
21
28
  .action(this.build));
22
29
  }
30
+ nodesToActualFiles(nodes, basePath) {
31
+ nodes.forEach((node) => {
32
+ const currentPath = join(basePath, node.name);
33
+ if (node.isLeaf) {
34
+ // Create directory for the file if it doesn't exist
35
+ const dir = dirname(currentPath);
36
+ mkdirSync(dir, { recursive: true });
37
+ // Write the file content
38
+ writeFileSync(currentPath, node.content || '');
39
+ }
40
+ else {
41
+ // Create directory
42
+ mkdirSync(currentPath, { recursive: true });
43
+ // Process children recursively
44
+ if (node.children && node.children.length > 0) {
45
+ this.nodesToActualFiles(node.children, basePath);
46
+ }
47
+ }
48
+ });
49
+ }
23
50
  async builder(options) {
24
- const { version, engine } = options;
25
- console.log(`Running builder for SDK version ${version} with engine ${engine}`);
26
- const ws = new WebSocketServer({ port: 11400 });
51
+ const { version, engine, port } = options;
52
+ console.log(`Running builder for SDK version ${version} with engine ${engine} on port ${port}`);
53
+ const ws = new WebSocketServer({ port: port ?? 11403 });
27
54
  ws.on('connection', (socket) => {
28
55
  socket.on('message', async (message) => {
29
- console.log("Building component templates...");
56
+ console.log("\n🔨 Building component...");
30
57
  const nodes = JSON.parse(message.toString());
31
- try {
32
- let dist = null;
33
- const builder = new Builder(version, engine);
34
- const compiledFiles = await builder.buildFromNodes(nodes);
35
- dist = Object.assign({}, compiledFiles);
36
- socket.send(JSON.stringify({ dist }));
37
- console.log('Component templates built successfully');
38
- // Do something with the parsed JSON
58
+ // SDK 6 uses new build system with Rollup and multi-view bundling
59
+ if (parseInt(version) >= 6) {
60
+ await this.buildSDK6(nodes, version, engine, socket);
39
61
  }
40
- catch (error) { // Bad Request
41
- socket.send(JSON.stringify({ error: error.message }));
42
- console.error(error.message);
62
+ else {
63
+ // SDK 5 and below use the legacy build system
64
+ await this.buildLegacy(nodes, version, engine, socket);
43
65
  }
44
66
  });
45
67
  });
46
68
  }
69
+ async buildSDK6(nodes, version, engine, socket) {
70
+ // Create temporary directory with constant name
71
+ const tempDir = '/tmp/.ptkl/components';
72
+ try {
73
+ // Parse engine to extract framework and version (e.g., "lit@3" -> { framework: "lit", version: "3" })
74
+ const engineMatch = engine.match(/^([^@]+)(?:@(.+))?$/);
75
+ const framework = engineMatch ? engineMatch[1] : engine;
76
+ const frameworkVersion = engineMatch ? engineMatch[2] : null;
77
+ // Create temp directory
78
+ mkdirSync(tempDir, { recursive: true });
79
+ // Clear all files except node_modules
80
+ const entries = readdirSync(tempDir);
81
+ for (const entry of entries) {
82
+ if (entry !== 'node_modules') {
83
+ const fullPath = join(tempDir, entry);
84
+ rmSync(fullPath, { recursive: true, force: true });
85
+ }
86
+ }
87
+ // Convert nodes to actual files
88
+ this.nodesToActualFiles(nodes, tempDir);
89
+ // Look for component.js file that defines views
90
+ const componentsConfigPath = join(tempDir, 'component.js');
91
+ let viewsConfig = {};
92
+ if (!existsSync(componentsConfigPath)) {
93
+ throw new Error('component.js not found. Please create a component.js file that exports { views: { viewName: "./path/to/view.js" } }');
94
+ }
95
+ let componentConfig;
96
+ try {
97
+ // Read the component.js file as text
98
+ const componentContent = readFileSync(componentsConfigPath, 'utf-8');
99
+ // Parse the ES module manually
100
+ // Remove 'export default' and evaluate the object
101
+ const contentWithoutExport = componentContent
102
+ .replace(/export\s+default\s+/, '')
103
+ .trim();
104
+ // Use Function constructor to safely evaluate the object
105
+ componentConfig = new Function(`return ${contentWithoutExport}`)();
106
+ if (!componentConfig || !componentConfig.views) {
107
+ throw new Error('component.js must export default object with "views" property');
108
+ }
109
+ viewsConfig = componentConfig.views;
110
+ }
111
+ catch (error) {
112
+ throw new Error(`Failed to load component.js: ${error.message}. Please ensure component.js exports { views: { viewName: './path/to/view.js' } }`);
113
+ }
114
+ // Merge user packages with internal dependencies
115
+ const userPackages = componentConfig.packages || {};
116
+ const dependencies = {
117
+ '@ptkl/sdk': '^1.0.0',
118
+ // Lit is bundled into the component, not provided by platform
119
+ ...(framework === 'lit' ? {
120
+ 'lit': frameworkVersion ? `^${frameworkVersion}` : '^3.0.0'
121
+ } : {}),
122
+ ...userPackages
123
+ };
124
+ // Create package.json with merged dependencies
125
+ const packageJson = {
126
+ name: 'component-build',
127
+ version: '1.0.0',
128
+ type: 'module',
129
+ dependencies
130
+ };
131
+ const packageJsonPath = join(tempDir, 'package.json');
132
+ writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
133
+ // Run npm install
134
+ try {
135
+ execSync('npm install', {
136
+ cwd: tempDir,
137
+ stdio: 'pipe',
138
+ env: { ...process.env, NODE_ENV: 'production' }
139
+ });
140
+ }
141
+ catch (error) {
142
+ throw new Error(`npm install failed: ${error.message}`);
143
+ }
144
+ // Build each view separately with Rollup
145
+ const dist = {};
146
+ const warnings = [];
147
+ const viewCount = Object.keys(viewsConfig).length;
148
+ console.log(`📦 Bundling ${viewCount} view${viewCount !== 1 ? 's' : ''}...`);
149
+ for (const [viewName, viewPath] of Object.entries(viewsConfig)) {
150
+ const fullPath = join(tempDir, viewPath);
151
+ // Check and strip @customElement decorator for Lit components
152
+ if (framework === 'lit') {
153
+ const sourceContent = readFileSync(fullPath, 'utf-8');
154
+ const customElementDecoratorRegex = /@customElement\s*\(\s*['"`][^'"`]*['"`]\s*\)/g;
155
+ if (customElementDecoratorRegex.test(sourceContent)) {
156
+ const warning = `${viewName}: Found @customElement decorator which has been automatically removed. The platform handles element registration dynamically.`;
157
+ warnings.push(warning);
158
+ console.warn(`⚠️ ${warning}`);
159
+ // Strip the decorator from source
160
+ const strippedContent = sourceContent.replace(/@customElement\s*\(\s*['"`][^'"`]*['"`]\s*\)/g, '');
161
+ writeFileSync(fullPath, strippedContent, 'utf-8');
162
+ }
163
+ }
164
+ // Configure Babel based on framework
165
+ let babelConfig = null;
166
+ if (framework === 'lit') {
167
+ babelConfig = {
168
+ babelHelpers: 'bundled',
169
+ extensions: ['.js', '.ts'],
170
+ presets: [
171
+ ['@babel/preset-typescript', {
172
+ onlyRemoveTypeImports: true,
173
+ allowDeclareFields: true
174
+ }]
175
+ ],
176
+ plugins: [
177
+ ['@babel/plugin-proposal-decorators', { legacy: true }],
178
+ '@babel/plugin-proposal-class-properties',
179
+ '@babel/plugin-transform-class-static-block'
180
+ ]
181
+ };
182
+ }
183
+ else if (framework === 'webcomponents') {
184
+ babelConfig = {
185
+ babelHelpers: 'bundled',
186
+ extensions: ['.js', '.ts'],
187
+ presets: [
188
+ ['@babel/preset-typescript', {
189
+ onlyRemoveTypeImports: true,
190
+ allowDeclareFields: true
191
+ }]
192
+ ],
193
+ plugins: [
194
+ '@babel/plugin-proposal-class-properties',
195
+ '@babel/plugin-transform-class-static-block'
196
+ ]
197
+ };
198
+ }
199
+ // Define external dependencies based on framework
200
+ const getExternalDependencies = (framework) => {
201
+ const externalDeps = [];
202
+ // Lit is bundled into the component, not externalized
203
+ // webcomponents framework has no external dependencies
204
+ return externalDeps;
205
+ };
206
+ const bundle = await rollup({
207
+ input: fullPath,
208
+ plugins: [
209
+ nodeResolve({
210
+ browser: true,
211
+ preferBuiltins: false,
212
+ extensions: ['.js', '.ts', '.jsx', '.tsx', '.vue']
213
+ }),
214
+ // Add Babel plugin if configured
215
+ ...(babelConfig ? [babelPlugin(babelConfig)] : []),
216
+ // @ts-ignore
217
+ commonjsPlugin(),
218
+ ],
219
+ // Externalize framework dependencies - platform provides them
220
+ external: (id) => {
221
+ const externalDeps = getExternalDependencies(framework);
222
+ return externalDeps.some(dep => {
223
+ if (typeof dep === 'string') {
224
+ return id === dep;
225
+ }
226
+ return dep.test(id);
227
+ });
228
+ },
229
+ onwarn: (warning, warn) => {
230
+ if (warning.code === 'UNRESOLVED_IMPORT') {
231
+ console.warn(`⚠️ Unresolved import in ${viewName}`);
232
+ return;
233
+ }
234
+ warn(warning);
235
+ },
236
+ });
237
+ const { output } = await bundle.generate({
238
+ format: 'esm',
239
+ sourcemap: false,
240
+ inlineDynamicImports: true,
241
+ });
242
+ // Add to dist with view name
243
+ output.forEach((chunk) => {
244
+ if (chunk.type === 'chunk') {
245
+ let code = chunk.code;
246
+ // Check for common issues and add warnings
247
+ // 1. Check if code contains customElements.define and remove it
248
+ // Handle various formats including multiline
249
+ const customElementsDefineRegex = /customElements\.define\s*\([^)]*\([\s\S]*?\)\s*\)\s*;?|customElements\.define\s*\([^)]*\)\s*;?/g;
250
+ const hasCustomElementsDefine = customElementsDefineRegex.test(code);
251
+ if (hasCustomElementsDefine) {
252
+ const warning = `${viewName}: Found customElements.define() which has been automatically removed. The platform handles element registration dynamically based on component context.`;
253
+ warnings.push(warning);
254
+ console.warn(`⚠️ ${warning}`);
255
+ // Remove customElements.define calls (reset regex after test)
256
+ code = code.replace(/customElements\.define\s*\([^)]*\([\s\S]*?\)\s*\)\s*;?/g, '');
257
+ code = code.replace(/customElements\.define\s*\([^)]*\)\s*;?/g, '');
258
+ }
259
+ // 2. Check if code has a default export
260
+ const hasDefaultExport = /export\s+default/.test(code) || /export\s*\{[^}]*default[^}]*\}/.test(code);
261
+ if (!hasDefaultExport) {
262
+ const warning = `${viewName}: Missing default export. The view must export a default component/class for the platform to use.`;
263
+ warnings.push(warning);
264
+ console.warn(`⚠️ ${warning}`);
265
+ }
266
+ // 3. Check if code is suspiciously small (might indicate build issue)
267
+ if (code.length < 50) {
268
+ const warning = `${viewName}: Bundle size is very small (${code.length} bytes). This might indicate a build issue.`;
269
+ warnings.push(warning);
270
+ console.warn(`⚠️ ${warning}`);
271
+ }
272
+ // 4. Check for missing imports that might cause runtime errors
273
+ if (framework === 'lit' && !code.includes('lit')) {
274
+ const warning = `${viewName}: Lit framework not detected in bundle. Make sure you're importing from 'lit'.`;
275
+ warnings.push(warning);
276
+ console.warn(`⚠️ ${warning}`);
277
+ }
278
+ dist[`${viewName}.js`] = code;
279
+ }
280
+ else if (chunk.type === 'asset') {
281
+ dist[`${viewName}-${chunk.fileName}`] = chunk.source.toString();
282
+ }
283
+ });
284
+ }
285
+ const totalSize = Object.values(dist).reduce((sum, code) => sum + code.length, 0);
286
+ const formattedSize = totalSize > 1024 ? `${(totalSize / 1024).toFixed(2)} KB` : `${totalSize} bytes`;
287
+ console.log(`✅ Build complete: ${Object.keys(dist).length} file${Object.keys(dist).length !== 1 ? 's' : ''} (${formattedSize})`);
288
+ Object.entries(dist).forEach(([name, code]) => {
289
+ const size = code.length > 1024 ? `${(code.length / 1024).toFixed(2)} KB` : `${code.length} bytes`;
290
+ console.log(` • ${name} - ${size}`);
291
+ });
292
+ socket.send(JSON.stringify({
293
+ dist,
294
+ views: Object.keys(viewsConfig),
295
+ warnings: warnings.length > 0 ? warnings : undefined,
296
+ sdk_version: version,
297
+ sdk_engine: engine
298
+ }));
299
+ }
300
+ catch (error) {
301
+ console.error(`❌ Build failed: ${error.message}`);
302
+ socket.send(JSON.stringify({ error: error.message }));
303
+ }
304
+ finally {
305
+ try {
306
+ rmSync(tempDir, { recursive: true, force: true });
307
+ console.log(`Cleaned up temporary directory: ${tempDir}`);
308
+ }
309
+ catch (cleanupError) {
310
+ console.error(`Failed to clean up temporary directory: ${cleanupError}`);
311
+ }
312
+ }
313
+ }
314
+ async buildLegacy(nodes, version, engine, socket) {
315
+ try {
316
+ const builder = new Builder(parseInt(version), engine);
317
+ const dist = await builder.buildFromNodes(nodes);
318
+ socket.send(JSON.stringify({
319
+ dist,
320
+ sdk_version: version,
321
+ sdk_engine: engine
322
+ }));
323
+ console.log(`✅ Build complete (SDK ${version})`);
324
+ }
325
+ catch (error) {
326
+ console.error(`❌ Build failed: ${error.message}`);
327
+ socket.send(JSON.stringify({ error: error.message }));
328
+ }
329
+ }
47
330
  async build(options) {
48
331
  try {
49
332
  const { path } = options;