@minnai/create-aura-app 0.0.2

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 (55) hide show
  1. package/dist/index.js +108 -0
  2. package/dist/scaffold.js +61 -0
  3. package/package.json +36 -0
  4. package/templates/blank/index.html +12 -0
  5. package/templates/blank/package.json +23 -0
  6. package/templates/blank/src/App.tsx +21 -0
  7. package/templates/blank/src/index.css +40 -0
  8. package/templates/blank/src/main.tsx +10 -0
  9. package/templates/blank/tsconfig.json +31 -0
  10. package/templates/blank/tsconfig.node.json +12 -0
  11. package/templates/blank/vite.config.ts +7 -0
  12. package/templates/starter/.env.example +14 -0
  13. package/templates/starter/README.md +31 -0
  14. package/templates/starter/_gitignore +24 -0
  15. package/templates/starter/aura.config.ts +19 -0
  16. package/templates/starter/eslint.config.js +23 -0
  17. package/templates/starter/index.html +16 -0
  18. package/templates/starter/package.json +37 -0
  19. package/templates/starter/public/favicon.png +0 -0
  20. package/templates/starter/public/usd.json +9 -0
  21. package/templates/starter/public/vite.svg +1 -0
  22. package/templates/starter/src/App.css +32 -0
  23. package/templates/starter/src/App.tsx +82 -0
  24. package/templates/starter/src/ambiance/currency-air/index.tsx +25 -0
  25. package/templates/starter/src/ambiance/currency-air/logic.ts +49 -0
  26. package/templates/starter/src/ambiance/currency-air/manifest.ts +15 -0
  27. package/templates/starter/src/ambiance/currency-air/resources.ts +16 -0
  28. package/templates/starter/src/ambiance/currency-air/ui/index.tsx +42 -0
  29. package/templates/starter/src/ambiance/index.ts +48 -0
  30. package/templates/starter/src/ambiance/stocks-air/index.ts +3 -0
  31. package/templates/starter/src/ambiance/stocks-air/index.tsx +28 -0
  32. package/templates/starter/src/ambiance/stocks-air/logic.ts +87 -0
  33. package/templates/starter/src/ambiance/stocks-air/manifest.ts +15 -0
  34. package/templates/starter/src/ambiance/stocks-air/resources.ts +23 -0
  35. package/templates/starter/src/ambiance/stocks-air/ui/index.tsx +67 -0
  36. package/templates/starter/src/assets/react.svg +1 -0
  37. package/templates/starter/src/components/AnalyticsTracker.tsx +13 -0
  38. package/templates/starter/src/components/Playground/CodeEditor.tsx +121 -0
  39. package/templates/starter/src/components/Playground/Debugger.tsx +71 -0
  40. package/templates/starter/src/components/Playground/Playground.tsx +221 -0
  41. package/templates/starter/src/components/Playground/Sidebar.tsx +68 -0
  42. package/templates/starter/src/components/ProjectSidebar/ProjectSidebar.tsx +219 -0
  43. package/templates/starter/src/components/TourGuide/TourGuide.tsx +16 -0
  44. package/templates/starter/src/components/TourGuide/index.ts +1 -0
  45. package/templates/starter/src/components/TourGuide/tour-flow.yaml +137 -0
  46. package/templates/starter/src/components/TourGuide/useTourEngine.ts +376 -0
  47. package/templates/starter/src/index.css +68 -0
  48. package/templates/starter/src/main.tsx +10 -0
  49. package/templates/starter/src/services/AnalyticsService.ts +181 -0
  50. package/templates/starter/src/types/ContextHandler.ts +13 -0
  51. package/templates/starter/tsconfig.app.json +40 -0
  52. package/templates/starter/tsconfig.json +7 -0
  53. package/templates/starter/tsconfig.node.json +26 -0
  54. package/templates/starter/verify_backend.ts +42 -0
  55. package/templates/starter/vite.config.ts +286 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "files": [],
3
+ "references": [
4
+ { "path": "./tsconfig.app.json" },
5
+ { "path": "./tsconfig.node.json" }
6
+ ]
7
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "compilerOptions": {
3
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
4
+ "target": "ES2023",
5
+ "lib": ["ES2023"],
6
+ "module": "ESNext",
7
+ "types": ["node"],
8
+ "skipLibCheck": true,
9
+
10
+ /* Bundler mode */
11
+ "moduleResolution": "bundler",
12
+ "allowImportingTsExtensions": true,
13
+ "verbatimModuleSyntax": true,
14
+ "moduleDetection": "force",
15
+ "noEmit": true,
16
+
17
+ /* Linting */
18
+ "strict": true,
19
+ "noUnusedLocals": true,
20
+ "noUnusedParameters": true,
21
+ "erasableSyntaxOnly": true,
22
+ "noFallthroughCasesInSwitch": true,
23
+ "noUncheckedSideEffectImports": true
24
+ },
25
+ "include": ["vite.config.ts"]
26
+ }
@@ -0,0 +1,42 @@
1
+
2
+ const apiUrl = 'https://auraproxy-7bpt7e5tua-uc.a.run.app';
3
+
4
+ async function testBackend() {
5
+ console.log(`Testing backend at: ${apiUrl}/api/chat/reflect`);
6
+
7
+ // Mimic the payload from useControllerLogic.ts
8
+ const payload = {
9
+ message: "Hello, can you hear me? This is a test.",
10
+ messages: [],
11
+ available_airs: [],
12
+ open_airs: [],
13
+ additional_context: {}
14
+ };
15
+
16
+ try {
17
+ const start = Date.now();
18
+ const res = await fetch(`${apiUrl}/api/chat/reflect`, {
19
+ method: 'POST',
20
+ headers: { 'Content-Type': 'application/json' },
21
+ body: JSON.stringify(payload)
22
+ });
23
+
24
+ const duration = Date.now() - start;
25
+ console.log(`Response status: ${res.status}`);
26
+ console.log(`Duration: ${duration}ms`);
27
+
28
+ if (!res.ok) {
29
+ const text = await res.text();
30
+ console.error("Error response:", text);
31
+ process.exit(1);
32
+ }
33
+
34
+ const data = await res.json();
35
+ console.log("Success! Response data:", JSON.stringify(data, null, 2));
36
+ } catch (err) {
37
+ console.error("Fetch failed:", err);
38
+ process.exit(1);
39
+ }
40
+ }
41
+
42
+ testBackend();
@@ -0,0 +1,286 @@
1
+ import { defineConfig } from 'vite'
2
+ import react from '@vitejs/plugin-react'
3
+ import path from 'path';
4
+ import fs from 'fs';
5
+
6
+ // https://vite.dev/config/
7
+ export default defineConfig({
8
+ plugins: [
9
+ react(),
10
+ {
11
+ name: 'save-code-plugin',
12
+ configureServer(server: any) {
13
+ server.middlewares.use((req: any, res: any, next: any) => {
14
+ if (req.method === 'POST' && req.url === '/api/save-code') {
15
+ let body = '';
16
+ req.on('data', (chunk: any) => body += chunk);
17
+ req.on('end', () => {
18
+ try {
19
+ const { filePath, content } = JSON.parse(body);
20
+ const absolutePath = path.resolve(__dirname, filePath);
21
+ if (!absolutePath.startsWith(__dirname)) {
22
+ throw new Error("Invalid path");
23
+ }
24
+ fs.writeFileSync(absolutePath, content, 'utf8');
25
+ res.statusCode = 200;
26
+ res.setHeader('Content-Type', 'application/json');
27
+ res.end(JSON.stringify({ success: true }));
28
+ } catch (err: any) {
29
+ res.statusCode = 500;
30
+ res.setHeader('Content-Type', 'application/json');
31
+ res.end(JSON.stringify({ success: false, error: err.message }));
32
+ }
33
+ });
34
+ } else if (req.method === 'GET' && req.url?.startsWith('/api/list-files')) {
35
+ const url = new URL(req.url, `http://${req.headers.host}`);
36
+ const airId = url.searchParams.get('airId');
37
+ if (!airId) {
38
+ res.statusCode = 400;
39
+ res.end("Missing airId");
40
+ return;
41
+ }
42
+
43
+ const airDir = path.resolve(__dirname, 'src/airs', airId);
44
+ if (!fs.existsSync(airDir)) {
45
+ res.statusCode = 200;
46
+ res.setHeader('Content-Type', 'application/json');
47
+ res.end(JSON.stringify({ files: [] }));
48
+ return;
49
+ }
50
+
51
+ const getFiles = (dir: string): string[] => {
52
+ let results: string[] = [];
53
+ if (!fs.existsSync(dir)) return [];
54
+ const list = fs.readdirSync(dir);
55
+ list.forEach(file => {
56
+ const filePath = path.join(dir, file);
57
+ const stat = fs.statSync(filePath);
58
+ if (stat && stat.isDirectory()) {
59
+ results = results.concat(getFiles(filePath));
60
+ } else {
61
+ // Return path relative to project root, prefixed with /
62
+ const relativePath = path.relative(__dirname, filePath).replace(/\\/g, '/');
63
+ results.push(relativePath.startsWith('/') ? relativePath : '/' + relativePath);
64
+ }
65
+ });
66
+ return results;
67
+ };
68
+
69
+ const files = getFiles(airDir);
70
+ res.statusCode = 200;
71
+ res.setHeader('Content-Type', 'application/json');
72
+ res.end(JSON.stringify({ files }));
73
+ } else if (req.method === 'POST' && req.url === '/api/scaffold-air') {
74
+ let body = '';
75
+ req.on('data', (chunk: any) => body += chunk);
76
+ req.on('end', () => {
77
+ try {
78
+ const { airId, name } = JSON.parse(body);
79
+ if (!airId || !name) throw new Error("Missing airId or name");
80
+
81
+ const airDir = path.resolve(__dirname, 'src/airs', airId);
82
+ if (fs.existsSync(airDir)) throw new Error("AIR already exists");
83
+
84
+ fs.mkdirSync(airDir, { recursive: true });
85
+ fs.mkdirSync(path.join(airDir, 'ui'), { recursive: true });
86
+
87
+ const templates: Record<string, string> = {
88
+ 'manifest.ts': `export const ${name.replace(/[^a-zA-Z0-9]/g, '')}Manifest = {
89
+ id: '${airId}',
90
+ meta: {
91
+ title: '${name}',
92
+ icon: '🚀',
93
+ description: 'A brand new custom AIR.',
94
+ width: 400,
95
+ height: 500
96
+ }
97
+ };`,
98
+ 'logic.ts': `import { useState } from 'react';
99
+
100
+ export function use${name.replace(/[^a-zA-Z0-9]/g, '')}Logic(props: any) {
101
+ const [count, setCount] = useState(0);
102
+ const increment = () => setCount(prev => prev + 1);
103
+
104
+ return { count, increment };
105
+ }`,
106
+ 'resources.ts': `export const resources = {};`,
107
+ 'ui/index.tsx': `import React from 'react';
108
+
109
+ export default function UI({ count, onIncrement }: any) {
110
+ return (
111
+ <div style={{ padding: 20, textAlign: 'center' }}>
112
+ <h2>${name} UI</h2>
113
+ <p>Count: {count}</p>
114
+ <button
115
+ onClick={onIncrement}
116
+ style={{
117
+ padding: '10px 20px',
118
+ background: '#007aff',
119
+ color: 'white',
120
+ border: 'none',
121
+ borderRadius: 8,
122
+ cursor: 'pointer'
123
+ }}
124
+ >
125
+ Increment
126
+ </button>
127
+ </div>
128
+ );
129
+ }`,
130
+ 'index.tsx': `import React from 'react';
131
+ import { ${name.replace(/[^a-zA-Z0-9]/g, '')}Manifest } from './manifest';
132
+ import { resources } from './resources';
133
+ import UI from './ui';
134
+ import { use${name.replace(/[^a-zA-Z0-9]/g, '')}Logic } from './logic';
135
+
136
+ const Component: React.FC<any> = (props) => {
137
+ const logic = use${name.replace(/[^a-zA-Z0-9]/g, '')}Logic(props);
138
+ return <UI count={logic.count} onIncrement={logic.increment} />;
139
+ };
140
+
141
+ export default {
142
+ manifest: ${name.replace(/[^a-zA-Z0-9]/g, '')}Manifest,
143
+ resources,
144
+ component: Component
145
+ };`
146
+ };
147
+
148
+ Object.entries(templates).forEach(([filename, content]) => {
149
+ fs.writeFileSync(path.join(airDir, filename), content, 'utf8');
150
+ });
151
+
152
+ res.statusCode = 200;
153
+ res.setHeader('Content-Type', 'application/json');
154
+ res.end(JSON.stringify({ success: true }));
155
+ } catch (err: any) {
156
+ res.statusCode = 500;
157
+ res.setHeader('Content-Type', 'application/json');
158
+ res.end(JSON.stringify({ success: false, error: err.message }));
159
+ }
160
+ });
161
+ } else if (req.method === 'POST' && req.url?.startsWith('/api/storage/documents')) {
162
+ console.log(`[StorageMiddleware] Request Path: ${req.url}`);
163
+ let body = '';
164
+ req.on('data', (chunk: any) => body += chunk);
165
+ req.on('end', () => {
166
+ try {
167
+ const url = new URL(req.url, `http://${req.headers.host}`);
168
+ const pathParts = url.pathname.split('/');
169
+ const action = pathParts[4]; // create, update, get, list, delete
170
+ console.log(`[StorageMiddleware] Action: ${action}, Body: ${body.substring(0, 200)}`);
171
+ const { collection, id, data } = JSON.parse(body);
172
+
173
+ const storageDir = path.resolve(__dirname, 'temp_data_storage', collection);
174
+ if (!fs.existsSync(storageDir)) fs.mkdirSync(storageDir, { recursive: true });
175
+
176
+ if (action === 'get') {
177
+ const filePath = path.join(storageDir, `${id}.json`);
178
+ console.log(`[StorageMiddleware] GET File: ${filePath}`);
179
+ if (fs.existsSync(filePath)) {
180
+ res.end(fs.readFileSync(filePath, 'utf8'));
181
+ } else {
182
+ res.statusCode = 200; // Return 200 with null per Aura client expectation
183
+ res.setHeader('Content-Type', 'application/json');
184
+ res.end(JSON.stringify(null));
185
+ }
186
+ } else if (action === 'create' || action === 'update') {
187
+ const docId = id || data.id || Math.random().toString(36).substr(2, 9);
188
+ const filePath = path.join(storageDir, `${docId}.json`);
189
+ const finalData = action === 'update' && fs.existsSync(filePath)
190
+ ? { ...JSON.parse(fs.readFileSync(filePath, 'utf8')), ...data }
191
+ : { ...data, id: docId };
192
+ fs.writeFileSync(filePath, JSON.stringify(finalData, null, 2), 'utf8');
193
+ res.end(JSON.stringify({ id: docId, success: true }));
194
+ } else if (action === 'list') {
195
+ const files = fs.readdirSync(storageDir);
196
+ const docs = files.map(f => JSON.parse(fs.readFileSync(path.join(storageDir, f), 'utf8')));
197
+ res.end(JSON.stringify(docs));
198
+ } else if (action === 'delete') {
199
+ const filePath = path.join(storageDir, `${id}.json`);
200
+ console.log(`[StorageMiddleware] DELETE File: ${filePath}`);
201
+ if (fs.existsSync(filePath)) {
202
+ fs.unlinkSync(filePath);
203
+ }
204
+ res.end(JSON.stringify({ success: true }));
205
+ }
206
+ } catch (err: any) {
207
+ res.statusCode = 500;
208
+ res.end(JSON.stringify({ error: err.message }));
209
+ }
210
+ });
211
+ } else if (req.method === 'GET' && req.url?.startsWith('/api/get-file-path')) {
212
+ const url = new URL(req.url, `http://${req.headers.host}`);
213
+ const relativePath = url.searchParams.get('path');
214
+ if (!relativePath) {
215
+ res.statusCode = 400;
216
+ res.end(JSON.stringify({ error: "Missing path parameter" }));
217
+ return;
218
+ }
219
+
220
+ try {
221
+ const absolutePath = path.resolve(__dirname, relativePath);
222
+ // Security check
223
+ if (!absolutePath.startsWith(__dirname)) {
224
+ throw new Error("Invalid path - outside project directory");
225
+ }
226
+
227
+ // Convert to vscode:// URI format
228
+ // Windows: vscode://file/c:/path/to/file
229
+ // macOS/Linux: vscode://file//Users/path/to/file
230
+ const normalizedPath = absolutePath.replace(/\\/g, '/');
231
+ const vscodeUri = `vscode://file/${normalizedPath}`;
232
+
233
+ res.statusCode = 200;
234
+ res.setHeader('Content-Type', 'application/json');
235
+ res.end(JSON.stringify({
236
+ absolutePath: normalizedPath,
237
+ vscodeUri,
238
+ projectRoot: __dirname.replace(/\\/g, '/')
239
+ }));
240
+ } catch (err: any) {
241
+ res.statusCode = 500;
242
+ res.setHeader('Content-Type', 'application/json');
243
+ res.end(JSON.stringify({ error: err.message }));
244
+ }
245
+ } else if (req.url?.startsWith('/api/storage/objects')) {
246
+ const url = new URL(req.url, `http://${req.headers.host}`);
247
+ const objectPath = url.searchParams.get('path');
248
+ if (!objectPath) { res.statusCode = 400; res.end("Missing path"); return; }
249
+
250
+ const filePath = path.resolve(__dirname, 'temp_data_storage/objects', objectPath);
251
+ if (req.method === 'GET') {
252
+ if (fs.existsSync(filePath)) {
253
+ res.end(fs.readFileSync(filePath));
254
+ } else {
255
+ res.statusCode = 404;
256
+ res.end("Not found");
257
+ }
258
+ } else if (req.method === 'POST' || req.method === 'PUT') {
259
+ let buffer = Buffer.alloc(0);
260
+ req.on('data', (chunk: Buffer) => buffer = Buffer.concat([buffer, chunk]));
261
+ req.on('end', () => {
262
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
263
+ fs.writeFileSync(filePath, buffer);
264
+ res.end(JSON.stringify({ success: true }));
265
+ });
266
+ }
267
+ } else {
268
+ next();
269
+ }
270
+ });
271
+ }
272
+ }
273
+ ],
274
+ resolve: {
275
+ alias: {
276
+ // Alias @minnai/aura to the local source directory for verifying changes
277
+ '@minnai/aura': path.resolve(__dirname, '../../Aura/src'),
278
+ 'react': path.resolve(__dirname, './node_modules/react'),
279
+ 'react-dom': path.resolve(__dirname, './node_modules/react-dom'),
280
+ },
281
+ dedupe: ['react', 'react-dom']
282
+ },
283
+ server: {
284
+ port: 5175
285
+ }
286
+ })