almostnode 0.1.0
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/LICENSE +21 -0
- package/README.md +731 -0
- package/dist/__sw__.js +394 -0
- package/dist/ai-chatbot-demo-entry.d.ts +6 -0
- package/dist/ai-chatbot-demo-entry.d.ts.map +1 -0
- package/dist/ai-chatbot-demo.d.ts +42 -0
- package/dist/ai-chatbot-demo.d.ts.map +1 -0
- package/dist/assets/runtime-worker-D9x_Ddwz.js +60543 -0
- package/dist/assets/runtime-worker-D9x_Ddwz.js.map +1 -0
- package/dist/convex-app-demo-entry.d.ts +6 -0
- package/dist/convex-app-demo-entry.d.ts.map +1 -0
- package/dist/convex-app-demo.d.ts +68 -0
- package/dist/convex-app-demo.d.ts.map +1 -0
- package/dist/cors-proxy.d.ts +46 -0
- package/dist/cors-proxy.d.ts.map +1 -0
- package/dist/create-runtime.d.ts +42 -0
- package/dist/create-runtime.d.ts.map +1 -0
- package/dist/demo.d.ts +6 -0
- package/dist/demo.d.ts.map +1 -0
- package/dist/dev-server.d.ts +97 -0
- package/dist/dev-server.d.ts.map +1 -0
- package/dist/frameworks/next-dev-server.d.ts +202 -0
- package/dist/frameworks/next-dev-server.d.ts.map +1 -0
- package/dist/frameworks/vite-dev-server.d.ts +85 -0
- package/dist/frameworks/vite-dev-server.d.ts.map +1 -0
- package/dist/index.cjs +14965 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +71 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +14867 -0
- package/dist/index.mjs.map +1 -0
- package/dist/next-demo.d.ts +49 -0
- package/dist/next-demo.d.ts.map +1 -0
- package/dist/npm/index.d.ts +71 -0
- package/dist/npm/index.d.ts.map +1 -0
- package/dist/npm/registry.d.ts +66 -0
- package/dist/npm/registry.d.ts.map +1 -0
- package/dist/npm/resolver.d.ts +52 -0
- package/dist/npm/resolver.d.ts.map +1 -0
- package/dist/npm/tarball.d.ts +29 -0
- package/dist/npm/tarball.d.ts.map +1 -0
- package/dist/runtime-interface.d.ts +90 -0
- package/dist/runtime-interface.d.ts.map +1 -0
- package/dist/runtime.d.ts +103 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/sandbox-helpers.d.ts +43 -0
- package/dist/sandbox-helpers.d.ts.map +1 -0
- package/dist/sandbox-runtime.d.ts +65 -0
- package/dist/sandbox-runtime.d.ts.map +1 -0
- package/dist/server-bridge.d.ts +89 -0
- package/dist/server-bridge.d.ts.map +1 -0
- package/dist/shims/assert.d.ts +51 -0
- package/dist/shims/assert.d.ts.map +1 -0
- package/dist/shims/async_hooks.d.ts +37 -0
- package/dist/shims/async_hooks.d.ts.map +1 -0
- package/dist/shims/buffer.d.ts +20 -0
- package/dist/shims/buffer.d.ts.map +1 -0
- package/dist/shims/child_process-browser.d.ts +92 -0
- package/dist/shims/child_process-browser.d.ts.map +1 -0
- package/dist/shims/child_process.d.ts +93 -0
- package/dist/shims/child_process.d.ts.map +1 -0
- package/dist/shims/chokidar.d.ts +55 -0
- package/dist/shims/chokidar.d.ts.map +1 -0
- package/dist/shims/cluster.d.ts +52 -0
- package/dist/shims/cluster.d.ts.map +1 -0
- package/dist/shims/crypto.d.ts +122 -0
- package/dist/shims/crypto.d.ts.map +1 -0
- package/dist/shims/dgram.d.ts +34 -0
- package/dist/shims/dgram.d.ts.map +1 -0
- package/dist/shims/diagnostics_channel.d.ts +80 -0
- package/dist/shims/diagnostics_channel.d.ts.map +1 -0
- package/dist/shims/dns.d.ts +87 -0
- package/dist/shims/dns.d.ts.map +1 -0
- package/dist/shims/domain.d.ts +25 -0
- package/dist/shims/domain.d.ts.map +1 -0
- package/dist/shims/esbuild.d.ts +105 -0
- package/dist/shims/esbuild.d.ts.map +1 -0
- package/dist/shims/events.d.ts +37 -0
- package/dist/shims/events.d.ts.map +1 -0
- package/dist/shims/fs.d.ts +115 -0
- package/dist/shims/fs.d.ts.map +1 -0
- package/dist/shims/fsevents.d.ts +67 -0
- package/dist/shims/fsevents.d.ts.map +1 -0
- package/dist/shims/http.d.ts +217 -0
- package/dist/shims/http.d.ts.map +1 -0
- package/dist/shims/http2.d.ts +81 -0
- package/dist/shims/http2.d.ts.map +1 -0
- package/dist/shims/https.d.ts +36 -0
- package/dist/shims/https.d.ts.map +1 -0
- package/dist/shims/inspector.d.ts +25 -0
- package/dist/shims/inspector.d.ts.map +1 -0
- package/dist/shims/module.d.ts +22 -0
- package/dist/shims/module.d.ts.map +1 -0
- package/dist/shims/net.d.ts +100 -0
- package/dist/shims/net.d.ts.map +1 -0
- package/dist/shims/os.d.ts +159 -0
- package/dist/shims/os.d.ts.map +1 -0
- package/dist/shims/path.d.ts +72 -0
- package/dist/shims/path.d.ts.map +1 -0
- package/dist/shims/perf_hooks.d.ts +50 -0
- package/dist/shims/perf_hooks.d.ts.map +1 -0
- package/dist/shims/process.d.ts +93 -0
- package/dist/shims/process.d.ts.map +1 -0
- package/dist/shims/querystring.d.ts +23 -0
- package/dist/shims/querystring.d.ts.map +1 -0
- package/dist/shims/readdirp.d.ts +52 -0
- package/dist/shims/readdirp.d.ts.map +1 -0
- package/dist/shims/readline.d.ts +62 -0
- package/dist/shims/readline.d.ts.map +1 -0
- package/dist/shims/rollup.d.ts +34 -0
- package/dist/shims/rollup.d.ts.map +1 -0
- package/dist/shims/sentry.d.ts +163 -0
- package/dist/shims/sentry.d.ts.map +1 -0
- package/dist/shims/stream.d.ts +181 -0
- package/dist/shims/stream.d.ts.map +1 -0
- package/dist/shims/tls.d.ts +53 -0
- package/dist/shims/tls.d.ts.map +1 -0
- package/dist/shims/tty.d.ts +30 -0
- package/dist/shims/tty.d.ts.map +1 -0
- package/dist/shims/url.d.ts +64 -0
- package/dist/shims/url.d.ts.map +1 -0
- package/dist/shims/util.d.ts +106 -0
- package/dist/shims/util.d.ts.map +1 -0
- package/dist/shims/v8.d.ts +73 -0
- package/dist/shims/v8.d.ts.map +1 -0
- package/dist/shims/vfs-adapter.d.ts +126 -0
- package/dist/shims/vfs-adapter.d.ts.map +1 -0
- package/dist/shims/vm.d.ts +45 -0
- package/dist/shims/vm.d.ts.map +1 -0
- package/dist/shims/worker_threads.d.ts +66 -0
- package/dist/shims/worker_threads.d.ts.map +1 -0
- package/dist/shims/ws.d.ts +66 -0
- package/dist/shims/ws.d.ts.map +1 -0
- package/dist/shims/zlib.d.ts +161 -0
- package/dist/shims/zlib.d.ts.map +1 -0
- package/dist/transform.d.ts +24 -0
- package/dist/transform.d.ts.map +1 -0
- package/dist/virtual-fs.d.ts +226 -0
- package/dist/virtual-fs.d.ts.map +1 -0
- package/dist/vite-demo.d.ts +35 -0
- package/dist/vite-demo.d.ts.map +1 -0
- package/dist/vite-sw.js +132 -0
- package/dist/worker/runtime-worker.d.ts +8 -0
- package/dist/worker/runtime-worker.d.ts.map +1 -0
- package/dist/worker-runtime.d.ts +50 -0
- package/dist/worker-runtime.d.ts.map +1 -0
- package/package.json +85 -0
- package/src/ai-chatbot-demo-entry.ts +244 -0
- package/src/ai-chatbot-demo.ts +509 -0
- package/src/convex-app-demo-entry.ts +1107 -0
- package/src/convex-app-demo.ts +1316 -0
- package/src/cors-proxy.ts +81 -0
- package/src/create-runtime.ts +147 -0
- package/src/demo.ts +304 -0
- package/src/dev-server.ts +274 -0
- package/src/frameworks/next-dev-server.ts +2224 -0
- package/src/frameworks/vite-dev-server.ts +702 -0
- package/src/index.ts +101 -0
- package/src/next-demo.ts +1784 -0
- package/src/npm/index.ts +347 -0
- package/src/npm/registry.ts +152 -0
- package/src/npm/resolver.ts +385 -0
- package/src/npm/tarball.ts +209 -0
- package/src/runtime-interface.ts +103 -0
- package/src/runtime.ts +1046 -0
- package/src/sandbox-helpers.ts +173 -0
- package/src/sandbox-runtime.ts +252 -0
- package/src/server-bridge.ts +426 -0
- package/src/shims/assert.ts +664 -0
- package/src/shims/async_hooks.ts +86 -0
- package/src/shims/buffer.ts +75 -0
- package/src/shims/child_process-browser.ts +217 -0
- package/src/shims/child_process.ts +463 -0
- package/src/shims/chokidar.ts +313 -0
- package/src/shims/cluster.ts +67 -0
- package/src/shims/crypto.ts +830 -0
- package/src/shims/dgram.ts +47 -0
- package/src/shims/diagnostics_channel.ts +196 -0
- package/src/shims/dns.ts +172 -0
- package/src/shims/domain.ts +58 -0
- package/src/shims/esbuild.ts +805 -0
- package/src/shims/events.ts +195 -0
- package/src/shims/fs.ts +803 -0
- package/src/shims/fsevents.ts +63 -0
- package/src/shims/http.ts +904 -0
- package/src/shims/http2.ts +96 -0
- package/src/shims/https.ts +86 -0
- package/src/shims/inspector.ts +30 -0
- package/src/shims/module.ts +82 -0
- package/src/shims/net.ts +359 -0
- package/src/shims/os.ts +195 -0
- package/src/shims/path.ts +199 -0
- package/src/shims/perf_hooks.ts +92 -0
- package/src/shims/process.ts +346 -0
- package/src/shims/querystring.ts +97 -0
- package/src/shims/readdirp.ts +228 -0
- package/src/shims/readline.ts +110 -0
- package/src/shims/rollup.ts +80 -0
- package/src/shims/sentry.ts +133 -0
- package/src/shims/stream.ts +1126 -0
- package/src/shims/tls.ts +95 -0
- package/src/shims/tty.ts +64 -0
- package/src/shims/url.ts +171 -0
- package/src/shims/util.ts +312 -0
- package/src/shims/v8.ts +113 -0
- package/src/shims/vfs-adapter.ts +402 -0
- package/src/shims/vm.ts +83 -0
- package/src/shims/worker_threads.ts +111 -0
- package/src/shims/ws.ts +382 -0
- package/src/shims/zlib.ts +289 -0
- package/src/transform.ts +313 -0
- package/src/types/external.d.ts +67 -0
- package/src/virtual-fs.ts +903 -0
- package/src/vite-demo.ts +577 -0
- package/src/worker/runtime-worker.ts +128 -0
- package/src/worker-runtime.ts +145 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entry point for AI Chatbot Demo
|
|
3
|
+
* This file is loaded by the HTML and bootstraps the demo
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { VirtualFS } from './virtual-fs';
|
|
7
|
+
import { Runtime } from './runtime';
|
|
8
|
+
import { NextDevServer } from './frameworks/next-dev-server';
|
|
9
|
+
import { getServerBridge } from './server-bridge';
|
|
10
|
+
import { Buffer } from './shims/stream';
|
|
11
|
+
import { createAIChatbotProject } from './ai-chatbot-demo';
|
|
12
|
+
|
|
13
|
+
// DOM elements
|
|
14
|
+
const logsEl = document.getElementById('logs') as HTMLDivElement;
|
|
15
|
+
const previewContainer = document.getElementById('previewContainer') as HTMLDivElement;
|
|
16
|
+
const statusDot = document.getElementById('statusDot') as HTMLSpanElement;
|
|
17
|
+
const statusText = document.getElementById('statusText') as HTMLSpanElement;
|
|
18
|
+
const refreshBtn = document.getElementById('refreshBtn') as HTMLButtonElement;
|
|
19
|
+
const openBtn = document.getElementById('openBtn') as HTMLButtonElement;
|
|
20
|
+
const apiKeyInput = document.getElementById('apiKey') as HTMLInputElement;
|
|
21
|
+
const connectBtn = document.getElementById('connectBtn') as HTMLButtonElement;
|
|
22
|
+
const connectionStatus = document.getElementById('connectionStatus') as HTMLDivElement;
|
|
23
|
+
const connectionStatusText = document.getElementById('connectionStatusText') as HTMLSpanElement;
|
|
24
|
+
|
|
25
|
+
let serverUrl: string | null = null;
|
|
26
|
+
let iframe: HTMLIFrameElement | null = null;
|
|
27
|
+
let vfs: VirtualFS | null = null;
|
|
28
|
+
let devServer: NextDevServer | null = null;
|
|
29
|
+
let apiKeyConfigured = false;
|
|
30
|
+
|
|
31
|
+
function log(message: string, type: 'info' | 'error' | 'warn' | 'success' = 'info') {
|
|
32
|
+
const line = document.createElement('div');
|
|
33
|
+
const time = new Date().toLocaleTimeString();
|
|
34
|
+
line.textContent = `[${time}] ${message}`;
|
|
35
|
+
if (type === 'error') line.className = 'error';
|
|
36
|
+
if (type === 'warn') line.className = 'warn';
|
|
37
|
+
if (type === 'success') line.className = 'success';
|
|
38
|
+
logsEl.appendChild(line);
|
|
39
|
+
logsEl.scrollTop = logsEl.scrollHeight;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function setStatus(text: string, state: 'loading' | 'running' | 'error' = 'loading') {
|
|
43
|
+
statusText.textContent = text;
|
|
44
|
+
statusDot.className = 'status-dot ' + state;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Configure the OpenAI API key
|
|
49
|
+
*/
|
|
50
|
+
function configureApiKey(apiKey: string): void {
|
|
51
|
+
if (!vfs || !devServer) {
|
|
52
|
+
log('Server not ready yet', 'error');
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Sanitize the API key: trim whitespace and remove non-ASCII characters
|
|
57
|
+
// This prevents "String contains non ISO-8859-1 code point" errors in fetch headers
|
|
58
|
+
const sanitizedKey = apiKey.trim().replace(/[^\x00-\x7F]/g, '');
|
|
59
|
+
|
|
60
|
+
if (!sanitizedKey) {
|
|
61
|
+
log('Please enter an OpenAI API key', 'error');
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Validate key format (basic check)
|
|
66
|
+
if (!sanitizedKey.startsWith('sk-')) {
|
|
67
|
+
log('Invalid API key format. OpenAI keys start with "sk-"', 'warn');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Set the environment variable on the dev server
|
|
71
|
+
console.log('[Entry] Setting API key, length:', sanitizedKey.length);
|
|
72
|
+
console.log('[Entry] API key starts with:', sanitizedKey.substring(0, 10));
|
|
73
|
+
devServer.setEnv('OPENAI_API_KEY', sanitizedKey);
|
|
74
|
+
|
|
75
|
+
// Verify it was set correctly
|
|
76
|
+
const verifyEnv = devServer.getEnv();
|
|
77
|
+
console.log('[Entry] Verified env key length:', verifyEnv.OPENAI_API_KEY?.length);
|
|
78
|
+
console.log('[Entry] Verified env key starts with:', verifyEnv.OPENAI_API_KEY?.substring(0, 10));
|
|
79
|
+
|
|
80
|
+
log(`OpenAI API key configured`, 'success');
|
|
81
|
+
|
|
82
|
+
// Update UI
|
|
83
|
+
apiKeyConfigured = true;
|
|
84
|
+
apiKeyInput.classList.add('connected');
|
|
85
|
+
connectBtn.textContent = 'Connected';
|
|
86
|
+
connectBtn.classList.add('success');
|
|
87
|
+
connectionStatus.style.display = 'inline-flex';
|
|
88
|
+
connectionStatusText.textContent = 'API Key Set';
|
|
89
|
+
|
|
90
|
+
// Refresh the preview to pick up the new config
|
|
91
|
+
if (iframe) {
|
|
92
|
+
log('Refreshing preview...');
|
|
93
|
+
const currentSrc = iframe.src;
|
|
94
|
+
iframe.src = 'about:blank';
|
|
95
|
+
setTimeout(() => {
|
|
96
|
+
if (iframe) iframe.src = currentSrc;
|
|
97
|
+
}, 100);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
log('You can now start chatting with the AI!', 'success');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function main() {
|
|
104
|
+
try {
|
|
105
|
+
setStatus('Creating virtual file system...', 'loading');
|
|
106
|
+
log('Creating virtual file system...');
|
|
107
|
+
vfs = new VirtualFS();
|
|
108
|
+
|
|
109
|
+
setStatus('Setting up project...', 'loading');
|
|
110
|
+
log('Creating AI Chatbot project structure...');
|
|
111
|
+
createAIChatbotProject(vfs);
|
|
112
|
+
log('Project files created', 'success');
|
|
113
|
+
|
|
114
|
+
setStatus('Initializing runtime...', 'loading');
|
|
115
|
+
log('Initializing runtime...');
|
|
116
|
+
const runtime = new Runtime(vfs, {
|
|
117
|
+
cwd: '/',
|
|
118
|
+
env: { NODE_ENV: 'development' },
|
|
119
|
+
onConsole: (method, args) => {
|
|
120
|
+
const msg = args.map(a => String(a)).join(' ');
|
|
121
|
+
if (method === 'error') log(msg, 'error');
|
|
122
|
+
else if (method === 'warn') log(msg, 'warn');
|
|
123
|
+
else log(msg);
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
setStatus('Starting dev server...', 'loading');
|
|
128
|
+
log('Starting Next.js dev server...');
|
|
129
|
+
|
|
130
|
+
const port = 3003;
|
|
131
|
+
devServer = new NextDevServer(vfs, {
|
|
132
|
+
port,
|
|
133
|
+
root: '/',
|
|
134
|
+
preferAppRouter: true,
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
const bridge = getServerBridge();
|
|
138
|
+
|
|
139
|
+
try {
|
|
140
|
+
log('Initializing Service Worker...');
|
|
141
|
+
await bridge.initServiceWorker();
|
|
142
|
+
log('Service Worker ready', 'success');
|
|
143
|
+
} catch (error) {
|
|
144
|
+
log(`Service Worker warning: ${error}`, 'warn');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Create HTTP server wrapper
|
|
148
|
+
const httpServer = {
|
|
149
|
+
listening: true,
|
|
150
|
+
address: () => ({ port, address: '0.0.0.0', family: 'IPv4' }),
|
|
151
|
+
async handleRequest(
|
|
152
|
+
method: string,
|
|
153
|
+
url: string,
|
|
154
|
+
headers: Record<string, string>,
|
|
155
|
+
body?: string | Buffer
|
|
156
|
+
) {
|
|
157
|
+
const bodyBuffer = body
|
|
158
|
+
? typeof body === 'string' ? Buffer.from(body) : body
|
|
159
|
+
: undefined;
|
|
160
|
+
return devServer!.handleRequest(method, url, headers, bodyBuffer);
|
|
161
|
+
},
|
|
162
|
+
// Streaming request handler - forwards to devServer's streaming support
|
|
163
|
+
async handleStreamingRequest(
|
|
164
|
+
method: string,
|
|
165
|
+
url: string,
|
|
166
|
+
headers: Record<string, string>,
|
|
167
|
+
body: Buffer | undefined,
|
|
168
|
+
onStart: (statusCode: number, statusMessage: string, headers: Record<string, string>) => void,
|
|
169
|
+
onChunk: (chunk: string | Uint8Array) => void,
|
|
170
|
+
onEnd: () => void
|
|
171
|
+
) {
|
|
172
|
+
return devServer!.handleStreamingRequest(method, url, headers, body, onStart, onChunk, onEnd);
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
bridge.registerServer(httpServer as any, port);
|
|
177
|
+
devServer.start();
|
|
178
|
+
|
|
179
|
+
serverUrl = bridge.getServerUrl(port) + '/';
|
|
180
|
+
log(`Server running at: ${serverUrl}`, 'success');
|
|
181
|
+
|
|
182
|
+
setStatus('Running', 'running');
|
|
183
|
+
|
|
184
|
+
// Show iframe
|
|
185
|
+
previewContainer.innerHTML = '';
|
|
186
|
+
iframe = document.createElement('iframe');
|
|
187
|
+
iframe.src = serverUrl;
|
|
188
|
+
iframe.id = 'preview-iframe';
|
|
189
|
+
iframe.name = 'preview-iframe';
|
|
190
|
+
iframe.setAttribute('sandbox', 'allow-forms allow-scripts allow-same-origin allow-popups allow-pointer-lock allow-modals allow-downloads allow-orientation-lock allow-presentation allow-popups-to-escape-sandbox');
|
|
191
|
+
|
|
192
|
+
iframe.onload = () => {
|
|
193
|
+
if (iframe?.contentWindow && devServer) {
|
|
194
|
+
devServer.setHMRTarget(iframe.contentWindow);
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
previewContainer.appendChild(iframe);
|
|
199
|
+
|
|
200
|
+
// Enable buttons
|
|
201
|
+
refreshBtn.disabled = false;
|
|
202
|
+
openBtn.disabled = false;
|
|
203
|
+
connectBtn.disabled = false;
|
|
204
|
+
|
|
205
|
+
refreshBtn.onclick = () => {
|
|
206
|
+
if (iframe) {
|
|
207
|
+
log('Refreshing preview...');
|
|
208
|
+
iframe.src = iframe.src;
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
openBtn.onclick = () => {
|
|
213
|
+
if (serverUrl) {
|
|
214
|
+
window.open(serverUrl, '_blank');
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
connectBtn.onclick = () => {
|
|
219
|
+
const key = apiKeyInput.value.trim();
|
|
220
|
+
configureApiKey(key);
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
// Allow pressing Enter to connect
|
|
224
|
+
apiKeyInput.onkeydown = (e) => {
|
|
225
|
+
if (e.key === 'Enter') {
|
|
226
|
+
const key = apiKeyInput.value.trim();
|
|
227
|
+
configureApiKey(key);
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
log('Demo ready!', 'success');
|
|
232
|
+
log('Enter your OpenAI API key and click Connect to start chatting.');
|
|
233
|
+
log('Note: API calls go through a CORS proxy (corsproxy.io)');
|
|
234
|
+
|
|
235
|
+
} catch (error) {
|
|
236
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
237
|
+
log(`Error: ${errorMessage}`, 'error');
|
|
238
|
+
console.error(error);
|
|
239
|
+
setStatus('Error', 'error');
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Start the demo
|
|
244
|
+
main();
|