electrobun 0.5.0-beta.0 โ†’ 0.6.0-beta.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.
Files changed (78) hide show
  1. package/{templates/multitab-browser/bun.lock โ†’ bun.lock} +20 -13
  2. package/dist/api/bun/proc/native.ts +84 -16
  3. package/package.json +14 -16
  4. package/BETA_RELEASE.md +0 -67
  5. package/BUILD.md +0 -90
  6. package/LICENSE +0 -21
  7. package/README.md +0 -102
  8. package/debug.js +0 -5
  9. package/templates/hello-world/README.md +0 -57
  10. package/templates/hello-world/bun.lock +0 -225
  11. package/templates/hello-world/electrobun.config.ts +0 -28
  12. package/templates/hello-world/package.json +0 -16
  13. package/templates/hello-world/src/bun/index.ts +0 -15
  14. package/templates/hello-world/src/mainview/index.css +0 -124
  15. package/templates/hello-world/src/mainview/index.html +0 -46
  16. package/templates/hello-world/src/mainview/index.ts +0 -1
  17. package/templates/interactive-playground/README.md +0 -26
  18. package/templates/interactive-playground/assets/tray-icon.png +0 -0
  19. package/templates/interactive-playground/electrobun.config.ts +0 -36
  20. package/templates/interactive-playground/package-lock.json +0 -1112
  21. package/templates/interactive-playground/package.json +0 -15
  22. package/templates/interactive-playground/src/bun/demos/files.ts +0 -70
  23. package/templates/interactive-playground/src/bun/demos/menus.ts +0 -139
  24. package/templates/interactive-playground/src/bun/demos/rpc.ts +0 -83
  25. package/templates/interactive-playground/src/bun/demos/system.ts +0 -72
  26. package/templates/interactive-playground/src/bun/demos/updates.ts +0 -105
  27. package/templates/interactive-playground/src/bun/demos/windows.ts +0 -90
  28. package/templates/interactive-playground/src/bun/index.ts +0 -124
  29. package/templates/interactive-playground/src/bun/types/rpc.ts +0 -109
  30. package/templates/interactive-playground/src/mainview/components/EventLog.ts +0 -107
  31. package/templates/interactive-playground/src/mainview/components/Sidebar.ts +0 -65
  32. package/templates/interactive-playground/src/mainview/components/Toast.ts +0 -57
  33. package/templates/interactive-playground/src/mainview/demos/FileDemo.ts +0 -211
  34. package/templates/interactive-playground/src/mainview/demos/MenuDemo.ts +0 -102
  35. package/templates/interactive-playground/src/mainview/demos/RPCDemo.ts +0 -229
  36. package/templates/interactive-playground/src/mainview/demos/TrayDemo.ts +0 -132
  37. package/templates/interactive-playground/src/mainview/demos/WebViewDemo.ts +0 -465
  38. package/templates/interactive-playground/src/mainview/demos/WindowDemo.ts +0 -207
  39. package/templates/interactive-playground/src/mainview/index.css +0 -538
  40. package/templates/interactive-playground/src/mainview/index.html +0 -103
  41. package/templates/interactive-playground/src/mainview/index.ts +0 -238
  42. package/templates/multitab-browser/README.md +0 -34
  43. package/templates/multitab-browser/electrobun.config.ts +0 -32
  44. package/templates/multitab-browser/package-lock.json +0 -20
  45. package/templates/multitab-browser/package.json +0 -12
  46. package/templates/multitab-browser/src/bun/index.ts +0 -144
  47. package/templates/multitab-browser/src/bun/tabManager.ts +0 -200
  48. package/templates/multitab-browser/src/bun/types/rpc.ts +0 -78
  49. package/templates/multitab-browser/src/mainview/index.css +0 -487
  50. package/templates/multitab-browser/src/mainview/index.html +0 -94
  51. package/templates/multitab-browser/src/mainview/index.ts +0 -634
  52. package/templates/photo-booth/README.md +0 -108
  53. package/templates/photo-booth/bun.lock +0 -239
  54. package/templates/photo-booth/electrobun.config.ts +0 -32
  55. package/templates/photo-booth/package.json +0 -17
  56. package/templates/photo-booth/src/bun/index.ts +0 -92
  57. package/templates/photo-booth/src/mainview/index.css +0 -465
  58. package/templates/photo-booth/src/mainview/index.html +0 -124
  59. package/templates/photo-booth/src/mainview/index.ts +0 -499
  60. package/test-new-window-events.ts +0 -26
  61. package/test-new-window.html +0 -75
  62. package/test-npm-install.sh +0 -34
  63. package/tests/bun.lock +0 -14
  64. package/tests/electrobun.config.ts +0 -45
  65. package/tests/package-lock.json +0 -36
  66. package/tests/package.json +0 -13
  67. package/tests/src/bun/index.ts +0 -100
  68. package/tests/src/bun/test-runner.ts +0 -508
  69. package/tests/src/mainview/index.html +0 -110
  70. package/tests/src/mainview/index.ts +0 -458
  71. package/tests/src/mainview/styles/main.css +0 -451
  72. package/tests/src/testviews/tray-test.html +0 -57
  73. package/tests/src/testviews/webview-mask.html +0 -114
  74. package/tests/src/testviews/webview-navigation.html +0 -36
  75. package/tests/src/testviews/window-create.html +0 -17
  76. package/tests/src/testviews/window-events.html +0 -29
  77. package/tests/src/testviews/window-focus.html +0 -37
  78. package/tests/src/webviewtag/index.ts +0 -11
@@ -1,110 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Electrobun Test Harness</title>
7
- <link rel="stylesheet" href="styles/main.css">
8
- </head>
9
- <body>
10
- <div class="app-container">
11
- <header class="header">
12
- <h1>๐Ÿงช Electrobun Test Harness</h1>
13
- <div class="header-actions">
14
- <button id="run-all-btn" class="btn btn-primary">Run All Tests</button>
15
- <button id="cleanup-btn" class="btn btn-secondary">Cleanup</button>
16
- <div class="platform-info">
17
- <span id="platform-name">Platform: Loading...</span>
18
- </div>
19
- </div>
20
- </header>
21
-
22
- <div class="main-content">
23
- <aside class="sidebar">
24
- <div class="test-categories">
25
- <h3>Test Categories</h3>
26
- <div id="category-filters">
27
- <label class="filter-item">
28
- <input type="checkbox" value="Windows" checked> Windows
29
- </label>
30
- <label class="filter-item">
31
- <input type="checkbox" value="WebViews" checked> WebViews
32
- </label>
33
- <label class="filter-item">
34
- <input type="checkbox" value="System" checked> System
35
- </label>
36
- </div>
37
- </div>
38
-
39
- <div class="test-status-summary">
40
- <h3>Status Summary</h3>
41
- <div class="status-counts">
42
- <div class="count-item">
43
- <span class="count" id="passed-count">0</span>
44
- <span class="label">Passed</span>
45
- </div>
46
- <div class="count-item">
47
- <span class="count" id="failed-count">0</span>
48
- <span class="label">Failed</span>
49
- </div>
50
- <div class="count-item">
51
- <span class="count" id="pending-count">0</span>
52
- <span class="label">Pending</span>
53
- </div>
54
- </div>
55
- </div>
56
- </aside>
57
-
58
- <main class="test-area">
59
- <div class="auto-tests-section">
60
- <h2>๐Ÿค– Auto-Detected Tests</h2>
61
- <p class="section-description">These tests can automatically detect success/failure</p>
62
- <div id="auto-tests-container" class="tests-container">
63
- <!-- Auto tests will be populated here -->
64
- </div>
65
- </div>
66
-
67
- <div class="manual-tests-section">
68
- <h2>๐Ÿ‘๏ธ Manual Verification Tests</h2>
69
- <p class="section-description">These tests require human verification - follow instructions carefully</p>
70
- <div id="manual-tests-container" class="tests-container">
71
- <!-- Manual tests will be populated here -->
72
- </div>
73
- </div>
74
-
75
- <div class="hybrid-tests-section">
76
- <h2>๐Ÿ”„ Hybrid Tests</h2>
77
- <p class="section-description">These tests have both automatic detection and manual verification components</p>
78
- <div id="hybrid-tests-container" class="tests-container">
79
- <!-- Hybrid tests will be populated here -->
80
- </div>
81
- </div>
82
- </main>
83
- </div>
84
-
85
- <div class="event-log">
86
- <h3>Event Log</h3>
87
- <div id="event-log-content" class="log-content">
88
- <div class="log-entry">
89
- <span class="timestamp">Starting test harness...</span>
90
- </div>
91
- </div>
92
- </div>
93
- </div>
94
-
95
- <!-- Modal for detailed test results -->
96
- <div id="test-modal" class="modal" style="display: none;">
97
- <div class="modal-content">
98
- <div class="modal-header">
99
- <h3 id="modal-title">Test Details</h3>
100
- <button class="modal-close">&times;</button>
101
- </div>
102
- <div class="modal-body" id="modal-body">
103
- <!-- Test details will be shown here -->
104
- </div>
105
- </div>
106
- </div>
107
-
108
- <script type="module" src="index.js"></script>
109
- </body>
110
- </html>
@@ -1,458 +0,0 @@
1
- import { Electroview } from "electrobun/view";
2
- import type { TestRPCSchema } from "../bun/index";
3
-
4
- interface TestData {
5
- id: string;
6
- name: string;
7
- category: string;
8
- type: 'auto' | 'manual' | 'hybrid';
9
- status: 'pending' | 'running' | 'passed' | 'failed';
10
- description?: string;
11
- instructions?: string[];
12
- lastResult?: { success: boolean; message?: string; timestamp: number };
13
- }
14
-
15
- class TestHarnessUI {
16
- private electroview: Electroview<TestRPCSchema>;
17
- private tests = new Map<string, TestData>();
18
- private logContainer: HTMLElement;
19
-
20
- constructor() {
21
- this.electroview = new Electroview({
22
- rpc: Electroview.defineRPC<TestRPCSchema>({
23
- handlers: {
24
- requests: {
25
- markTestResult: async ({ testId, passed, notes }) => {
26
- this.handleManualTestResult(testId, passed, notes);
27
- return { acknowledged: true };
28
- }
29
- },
30
- messages: {
31
- showInstructions: ({ testId, instructions }) => {
32
- this.showInstructions(testId, instructions);
33
- },
34
- updateStatus: ({ testId, status, details }) => {
35
- this.updateTestStatus(testId, status, details);
36
- }
37
- }
38
- }
39
- })
40
- });
41
-
42
- this.logContainer = document.getElementById('event-log-content')!;
43
- this.initialize();
44
- }
45
-
46
- private async initialize() {
47
- this.log('Initializing test harness UI...');
48
-
49
- // Set platform info
50
- this.updatePlatformInfo();
51
-
52
- // Set up event listeners
53
- this.setupEventListeners();
54
-
55
- // Load tests from backend
56
- await this.loadTests();
57
-
58
- this.log('Test harness UI ready', 'info');
59
- }
60
-
61
- private updatePlatformInfo() {
62
- const platformEl = document.getElementById('platform-name');
63
- const userAgent = navigator.userAgent;
64
- let platform = 'Unknown';
65
-
66
- if (userAgent.includes('Mac')) {
67
- platform = 'macOS';
68
- } else if (userAgent.includes('Win')) {
69
- platform = 'Windows';
70
- } else if (userAgent.includes('Linux')) {
71
- platform = 'Linux';
72
- }
73
-
74
- if (platformEl) {
75
- platformEl.textContent = `Platform: ${platform}`;
76
- }
77
- }
78
-
79
- private setupEventListeners() {
80
- // Run all tests button
81
- document.getElementById('run-all-btn')?.addEventListener('click', () => {
82
- this.runAllTests();
83
- });
84
-
85
- // Cleanup button
86
- document.getElementById('cleanup-btn')?.addEventListener('click', () => {
87
- this.cleanup();
88
- });
89
-
90
- // Category filters
91
- const filters = document.querySelectorAll('#category-filters input[type="checkbox"]');
92
- filters.forEach(filter => {
93
- filter.addEventListener('change', () => {
94
- this.filterTests();
95
- });
96
- });
97
-
98
- // Modal close
99
- document.querySelector('.modal-close')?.addEventListener('click', () => {
100
- this.closeModal();
101
- });
102
-
103
- document.getElementById('test-modal')?.addEventListener('click', (e) => {
104
- if (e.target === e.currentTarget) {
105
- this.closeModal();
106
- }
107
- });
108
- }
109
-
110
- private async loadTests() {
111
- try {
112
- const response = await this.electroview.rpc.request.getTestStatus({});
113
-
114
- for (const testData of response.tests) {
115
- this.tests.set(testData.id, testData);
116
- }
117
-
118
- this.renderTests();
119
- this.updateStatusCounts();
120
- this.log(`Loaded ${response.tests.length} tests`);
121
- } catch (error) {
122
- this.log(`Failed to load tests: ${error.message}`, 'error');
123
- }
124
- }
125
-
126
- private renderTests() {
127
- const autoContainer = document.getElementById('auto-tests-container')!;
128
- const manualContainer = document.getElementById('manual-tests-container')!;
129
- const hybridContainer = document.getElementById('hybrid-tests-container')!;
130
-
131
- // Clear containers
132
- autoContainer.innerHTML = '';
133
- manualContainer.innerHTML = '';
134
- hybridContainer.innerHTML = '';
135
-
136
- for (const test of this.tests.values()) {
137
- const testElement = this.createTestElement(test);
138
-
139
- switch (test.type) {
140
- case 'auto':
141
- autoContainer.appendChild(testElement);
142
- break;
143
- case 'manual':
144
- manualContainer.appendChild(testElement);
145
- break;
146
- case 'hybrid':
147
- hybridContainer.appendChild(testElement);
148
- break;
149
- }
150
- }
151
- }
152
-
153
- private createTestElement(test: TestData): HTMLElement {
154
- const card = document.createElement('div');
155
- card.className = `test-card ${test.type} ${test.status}`;
156
- card.id = `test-${test.id}`;
157
-
158
- const statusIcon = this.getStatusIcon(test.status, test.type);
159
- const typeIcon = this.getTypeIcon(test.type);
160
-
161
- card.innerHTML = `
162
- <div class="test-header">
163
- <div>
164
- <div class="test-title">${typeIcon} ${test.name}</div>
165
- <div class="test-meta">
166
- <span class="test-badge">${test.category}</span>
167
- <span class="test-badge">${test.type}</span>
168
- </div>
169
- </div>
170
- <div class="test-actions">
171
- ${test.status === 'pending' || test.status === 'failed' ?
172
- `<button class="btn btn-run" onclick="testUI.runTest('${test.id}')">Run Test</button>` :
173
- ''}
174
- </div>
175
- </div>
176
-
177
- ${test.description ? `<div class="test-description">${test.description}</div>` : ''}
178
-
179
- <div class="test-status">
180
- <span class="status-indicator">${statusIcon}</span>
181
- <span class="status-text">${this.getStatusText(test.status)}</span>
182
- ${test.lastResult?.message ?
183
- `<span class="status-details">- ${test.lastResult.message}</span>` :
184
- ''}
185
- </div>
186
-
187
- ${test.type === 'manual' || test.type === 'hybrid' ? this.createInstructionsHTML(test) : ''}
188
-
189
- ${test.type === 'manual' ? this.createManualVerifyHTML(test) : ''}
190
- `;
191
-
192
- return card;
193
- }
194
-
195
- private createInstructionsHTML(test: TestData): string {
196
- if (!test.instructions || test.instructions.length === 0) {
197
- return '';
198
- }
199
-
200
- return `
201
- <div class="test-instructions">
202
- <h4>Instructions:</h4>
203
- <ol>
204
- ${test.instructions.map(instruction => `<li>${instruction}</li>`).join('')}
205
- </ol>
206
- </div>
207
- `;
208
- }
209
-
210
- private createManualVerifyHTML(test: TestData): string {
211
- if (test.status === 'passed' || test.status === 'failed') {
212
- return '';
213
- }
214
-
215
- return `
216
- <div class="manual-verify">
217
- <span class="manual-verify-text">Did this test work correctly?</span>
218
- <button class="btn btn-success" onclick="testUI.markTestPassed('${test.id}')">โœ… Pass</button>
219
- <button class="btn btn-danger" onclick="testUI.markTestFailed('${test.id}')">โŒ Fail</button>
220
- </div>
221
- `;
222
- }
223
-
224
- private getStatusIcon(status: string, type: string): string {
225
- switch (status) {
226
- case 'passed': return 'โœ…';
227
- case 'failed': return 'โŒ';
228
- case 'running': return 'โณ';
229
- default: return 'โšช';
230
- }
231
- }
232
-
233
- private getTypeIcon(type: string): string {
234
- switch (type) {
235
- case 'auto': return '๐Ÿค–';
236
- case 'manual': return '๐Ÿ‘๏ธ';
237
- case 'hybrid': return '๐Ÿ”„';
238
- default: return '๐Ÿ”';
239
- }
240
- }
241
-
242
- private getStatusText(status: string): string {
243
- switch (status) {
244
- case 'passed': return 'PASSED';
245
- case 'failed': return 'FAILED';
246
- case 'running': return 'RUNNING';
247
- case 'pending': return 'PENDING';
248
- default: return 'UNKNOWN';
249
- }
250
- }
251
-
252
- private async runTest(testId: string) {
253
- const test = this.tests.get(testId);
254
- if (!test) return;
255
-
256
- this.log(`Starting test: ${test.name}`);
257
- test.status = 'running';
258
- this.updateTestDisplay(test);
259
-
260
- try {
261
- const result = await this.electroview.rpc.request.runTest({ testId });
262
-
263
- if (result.success) {
264
- this.log(`Test setup completed: ${test.name}`, 'info');
265
- } else {
266
- this.log(`Test setup failed: ${test.name} - ${result.message}`, 'error');
267
- }
268
- } catch (error) {
269
- this.log(`Test error: ${test.name} - ${error.message}`, 'error');
270
- test.status = 'failed';
271
- this.updateTestDisplay(test);
272
- }
273
- }
274
-
275
- private async runAllTests() {
276
- this.log('Running all tests...', 'info');
277
-
278
- const pendingTests = Array.from(this.tests.values()).filter(t => t.status === 'pending');
279
-
280
- for (const test of pendingTests) {
281
- await this.runTest(test.id);
282
- // Add small delay between tests
283
- await new Promise(resolve => setTimeout(resolve, 500));
284
- }
285
-
286
- this.log(`Completed running ${pendingTests.length} tests`, 'info');
287
- }
288
-
289
- markTestPassed(testId: string) {
290
- this.electroview.rpc.send.markTestResult({
291
- testId,
292
- passed: true,
293
- notes: 'Manual verification: User confirmed test passed'
294
- });
295
- }
296
-
297
- markTestFailed(testId: string) {
298
- const notes = prompt('Optional: Describe what went wrong:');
299
- this.electroview.rpc.send.markTestResult({
300
- testId,
301
- passed: false,
302
- notes: notes || 'Manual verification: User reported test failed'
303
- });
304
- }
305
-
306
- private handleManualTestResult(testId: string, passed: boolean, notes?: string) {
307
- const test = this.tests.get(testId);
308
- if (!test) return;
309
-
310
- test.status = passed ? 'passed' : 'failed';
311
- test.lastResult = {
312
- success: passed,
313
- message: notes,
314
- timestamp: Date.now()
315
- };
316
-
317
- this.updateTestDisplay(test);
318
- this.updateStatusCounts();
319
-
320
- const status = passed ? 'PASSED' : 'FAILED';
321
- this.log(`Manual test ${status}: ${test.name}${notes ? ` - ${notes}` : ''}`, passed ? 'success' : 'error');
322
- }
323
-
324
- private updateTestStatus(testId: string, status: string, details?: string) {
325
- const test = this.tests.get(testId);
326
- if (!test) return;
327
-
328
- test.status = status as any;
329
- if (details) {
330
- test.lastResult = {
331
- success: status === 'passed',
332
- message: details,
333
- timestamp: Date.now()
334
- };
335
- }
336
-
337
- this.updateTestDisplay(test);
338
- this.updateStatusCounts();
339
- }
340
-
341
- private updateTestDisplay(test: TestData) {
342
- const element = document.getElementById(`test-${test.id}`);
343
- if (!element) return;
344
-
345
- // Update classes
346
- element.className = `test-card ${test.type} ${test.status}`;
347
-
348
- // Flash animation for status changes
349
- if (test.status === 'passed') {
350
- element.classList.add('flash-success');
351
- setTimeout(() => element.classList.remove('flash-success'), 600);
352
- } else if (test.status === 'failed') {
353
- element.classList.add('flash-error');
354
- setTimeout(() => element.classList.remove('flash-error'), 600);
355
- }
356
-
357
- // Re-render the element
358
- const newElement = this.createTestElement(test);
359
- element.innerHTML = newElement.innerHTML;
360
- }
361
-
362
- private updateStatusCounts() {
363
- const counts = { passed: 0, failed: 0, pending: 0, running: 0 };
364
-
365
- for (const test of this.tests.values()) {
366
- counts[test.status]++;
367
- }
368
-
369
- document.getElementById('passed-count')!.textContent = counts.passed.toString();
370
- document.getElementById('failed-count')!.textContent = counts.failed.toString();
371
- document.getElementById('pending-count')!.textContent = (counts.pending + counts.running).toString();
372
- }
373
-
374
- private filterTests() {
375
- const checkboxes = document.querySelectorAll('#category-filters input[type="checkbox"]') as NodeListOf<HTMLInputElement>;
376
- const activeCategories = Array.from(checkboxes)
377
- .filter(cb => cb.checked)
378
- .map(cb => cb.value);
379
-
380
- for (const test of this.tests.values()) {
381
- const element = document.getElementById(`test-${test.id}`);
382
- if (element) {
383
- element.style.display = activeCategories.includes(test.category) ? 'block' : 'none';
384
- }
385
- }
386
- }
387
-
388
- private showInstructions(testId: string, instructions: string[]) {
389
- // Instructions are already shown in the test cards
390
- this.log(`Instructions shown for test: ${testId}`, 'info');
391
- }
392
-
393
- private async cleanup() {
394
- this.log('Cleaning up all tests...', 'info');
395
-
396
- try {
397
- const result = await this.electroview.rpc.request.cleanup({});
398
-
399
- if (result.success) {
400
- this.log(result.message, 'success');
401
-
402
- setTimeout(() => {
403
- // Reset all test statuses to pending
404
- this.tests.forEach(test => {
405
- test.status = 'pending';
406
- test.lastResult = undefined;
407
- });
408
- // Refresh the UI
409
- this.renderTests();
410
- this.updateStatusCounts();
411
- }, 100)
412
-
413
- this.log('All tests reset to pending state', 'info');
414
- } else {
415
- this.log(result.message, 'error');
416
- }
417
- } catch (error) {
418
- this.log(`Cleanup failed: ${error}`, 'error');
419
- }
420
- }
421
-
422
- private closeModal() {
423
- const modal = document.getElementById('test-modal');
424
- if (modal) {
425
- modal.style.display = 'none';
426
- }
427
- }
428
-
429
- private log(message: string, type: 'info' | 'success' | 'error' = 'info') {
430
- const timestamp = new Date().toLocaleTimeString();
431
- const entry = document.createElement('div');
432
- entry.className = 'log-entry';
433
-
434
- const typeClass = type === 'success' ? 'log-success' :
435
- type === 'error' ? 'log-error' : 'log-info';
436
-
437
- entry.innerHTML = `
438
- <span class="timestamp">[${timestamp}]</span>
439
- <span class="${typeClass}">${message}</span>
440
- `;
441
-
442
- this.logContainer.appendChild(entry);
443
- this.logContainer.scrollTop = this.logContainer.scrollHeight;
444
-
445
- console.log(`[TestHarness] ${message}`);
446
- }
447
- }
448
-
449
- // Make testUI available globally for button onclick handlers
450
- declare global {
451
- interface Window {
452
- testUI: TestHarnessUI;
453
- }
454
- }
455
-
456
- // Initialize the test harness UI
457
- const testUI = new TestHarnessUI();
458
- window.testUI = testUI;