@heyputer/puter.js 1.0.1 → 2.0.1

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 (74) hide show
  1. package/README.md +14 -43
  2. package/index.d.ts +479 -0
  3. package/package.json +13 -3
  4. package/APACHE_LICENSE.txt +0 -201
  5. package/doc/devlog.md +0 -49
  6. package/src/bg.png +0 -0
  7. package/src/bg.webp +0 -0
  8. package/src/lib/APICallLogger.js +0 -110
  9. package/src/lib/EventListener.js +0 -51
  10. package/src/lib/RequestError.js +0 -6
  11. package/src/lib/filesystem/APIFS.js +0 -73
  12. package/src/lib/filesystem/CacheFS.js +0 -243
  13. package/src/lib/filesystem/PostMessageFS.js +0 -40
  14. package/src/lib/filesystem/definitions.js +0 -39
  15. package/src/lib/path.js +0 -509
  16. package/src/lib/polyfills/localStorage.js +0 -92
  17. package/src/lib/polyfills/xhrshim.js +0 -233
  18. package/src/lib/socket.io/socket.io.esm.min.js +0 -7
  19. package/src/lib/socket.io/socket.io.esm.min.js.map +0 -1
  20. package/src/lib/socket.io/socket.io.js +0 -4385
  21. package/src/lib/socket.io/socket.io.js.map +0 -1
  22. package/src/lib/socket.io/socket.io.min.js +0 -7
  23. package/src/lib/socket.io/socket.io.min.js.map +0 -1
  24. package/src/lib/socket.io/socket.io.msgpack.min.js +0 -7
  25. package/src/lib/socket.io/socket.io.msgpack.min.js.map +0 -1
  26. package/src/lib/utils.js +0 -620
  27. package/src/lib/xdrpc.js +0 -104
  28. package/src/modules/AI.js +0 -680
  29. package/src/modules/Apps.js +0 -215
  30. package/src/modules/Auth.js +0 -171
  31. package/src/modules/Debug.js +0 -39
  32. package/src/modules/Drivers.js +0 -278
  33. package/src/modules/FSItem.js +0 -139
  34. package/src/modules/FileSystem/index.js +0 -187
  35. package/src/modules/FileSystem/operations/copy.js +0 -64
  36. package/src/modules/FileSystem/operations/deleteFSEntry.js +0 -59
  37. package/src/modules/FileSystem/operations/getReadUrl.js +0 -42
  38. package/src/modules/FileSystem/operations/mkdir.js +0 -62
  39. package/src/modules/FileSystem/operations/move.js +0 -75
  40. package/src/modules/FileSystem/operations/read.js +0 -46
  41. package/src/modules/FileSystem/operations/readdir.js +0 -102
  42. package/src/modules/FileSystem/operations/rename.js +0 -58
  43. package/src/modules/FileSystem/operations/sign.js +0 -103
  44. package/src/modules/FileSystem/operations/space.js +0 -40
  45. package/src/modules/FileSystem/operations/stat.js +0 -95
  46. package/src/modules/FileSystem/operations/symlink.js +0 -55
  47. package/src/modules/FileSystem/operations/upload.js +0 -440
  48. package/src/modules/FileSystem/operations/write.js +0 -65
  49. package/src/modules/FileSystem/utils/getAbsolutePathForApp.js +0 -21
  50. package/src/modules/Hosting.js +0 -138
  51. package/src/modules/KV.js +0 -301
  52. package/src/modules/OS.js +0 -95
  53. package/src/modules/Perms.js +0 -109
  54. package/src/modules/PuterDialog.js +0 -481
  55. package/src/modules/Threads.js +0 -75
  56. package/src/modules/UI.js +0 -1555
  57. package/src/modules/Util.js +0 -38
  58. package/src/modules/Workers.js +0 -120
  59. package/src/modules/networking/PSocket.js +0 -87
  60. package/src/modules/networking/PTLS.js +0 -100
  61. package/src/modules/networking/PWispHandler.js +0 -89
  62. package/src/modules/networking/parsers.js +0 -157
  63. package/src/modules/networking/requests.js +0 -282
  64. package/src/services/APIAccess.js +0 -46
  65. package/src/services/FSRelay.js +0 -20
  66. package/src/services/Filesystem.js +0 -122
  67. package/src/services/NoPuterYet.js +0 -20
  68. package/src/services/XDIncoming.js +0 -44
  69. package/test/ai.test.js +0 -214
  70. package/test/fs.test.js +0 -798
  71. package/test/index.html +0 -1183
  72. package/test/kv.test.js +0 -548
  73. package/test/txt2speech.test.js +0 -178
  74. package/webpack.config.js +0 -25
package/test/index.html DELETED
@@ -1,1183 +0,0 @@
1
- <html>
2
- <head>
3
- <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
4
- <script id="puter-script"></script>
5
- <script src="./kv.test.js"></script>
6
- <script src="./fs.test.js"></script>
7
- <script src="./ai.test.js"></script>
8
- <script src="./txt2speech.test.js"></script>
9
- <style>
10
- body {
11
- font-family: Arial, sans-serif;
12
- }
13
- nav {
14
- z-index: 1000;
15
- display: flex;
16
- align-items: center;
17
- position: fixed;
18
- top: 0;
19
- width: 100%;
20
- background: #EEE;
21
- left: 0;
22
- padding-left: 10px;
23
- /* disable text selection */
24
- user-select: none;
25
- }
26
- #tests {
27
- padding-top: 50px;
28
- }
29
- #run-tests {
30
- margin-top: 20px;
31
- margin-bottom: 20px;
32
- background-color: #4c84af;
33
- border: none;
34
- color: white;
35
- padding: 10px 20px;
36
- text-align: center;
37
- text-decoration: none;
38
- display: inline-block;
39
- font-size: 16px;
40
- cursor: pointer;
41
- margin-left: 20px;
42
- }
43
- #settings-btn {
44
- margin-left: auto;
45
- margin-top: 20px;
46
- margin-bottom: 20px;
47
- background-color: #666;
48
- border: none;
49
- color: white;
50
- padding: 10px 20px;
51
- text-align: center;
52
- text-decoration: none;
53
- display: inline-block;
54
- font-size: 16px;
55
- cursor: pointer;
56
- float: right;
57
- margin-right: 30px;
58
- }
59
- #settings-btn:hover {
60
- background-color: #555;
61
- }
62
- #auth-section {
63
- float: right;
64
- margin-right: 20px;
65
- display: flex;
66
- align-items: center;
67
- font-size: 14px;
68
- }
69
- #login-btn {
70
- background-color: #4c84af;
71
- border: none;
72
- color: white;
73
- padding: 12px 16px;
74
- text-align: center;
75
- text-decoration: none;
76
- display: inline-block;
77
- font-size: 14px;
78
- cursor: pointer;
79
- }
80
- #login-btn:hover {
81
- background-color: #3a6a8a;
82
- }
83
- #user-info {
84
- color: #333;
85
- }
86
- #logout-link {
87
- color: #666;
88
- text-decoration: underline;
89
- cursor: pointer;
90
- margin-left: 5px;
91
- }
92
- #logout-link:hover {
93
- color: #333;
94
- }
95
- #unselect-all {
96
- margin-left: 20px;
97
- cursor: pointer;
98
- }
99
- #select-all {
100
- margin-left: 20px;
101
- cursor: pointer;
102
- }
103
- .test-container{
104
- margin-bottom: 10px;
105
- padding: 10px;
106
- border-radius: 5px;
107
- }
108
- .test-container{
109
- font-family: monospace;
110
- }
111
- .test-checkbox-container{
112
- display: flex;
113
- align-items: center;
114
- }
115
- .test-container:hover{
116
- background-color: #f0f0f0;
117
- }
118
- .test-container label{
119
- display: block;
120
- margin-left: 5px;
121
- }
122
- .test-container input{
123
- float: left;
124
- }
125
- .test-name {
126
- color: #727272;
127
- }
128
- .test-description {
129
- font-size: 12px;
130
- color: #262626;
131
- margin-top: 2px;
132
- }
133
- .test-run-button {
134
- margin-left: 10px;
135
- background-color: #4c84af;
136
- border: none;
137
- color: white;
138
- padding: 5px 10px;
139
- text-align: center;
140
- text-decoration: none;
141
- display: inline-block;
142
- font-size: 12px;
143
- cursor: pointer;
144
- border-radius: 3px;
145
- opacity: 0;
146
- transition: opacity 0.2s ease;
147
- }
148
- .test-container:hover .test-run-button {
149
- opacity: 1;
150
- }
151
- .test-run-button:hover {
152
- background-color: #3a6a8a;
153
- }
154
- .test-run-button:disabled {
155
- background-color: #999;
156
- cursor: not-allowed;
157
- opacity: 1;
158
- }
159
- .test-run-button:disabled:hover {
160
- background-color: #999;
161
- }
162
-
163
- /* Make h2 headers sticky */
164
- #tests h2 {
165
- position: sticky;
166
- top: 78px; /* Position below the fixed nav */
167
- background-color: white;
168
- padding: 20px 0;
169
- margin: 20px 0 10px 0;
170
- border-bottom: 2px solid #ddd;
171
- z-index: 10;
172
- font-size: 18px;
173
- font-weight: bold;
174
- }
175
-
176
- /* Adjust sticky headings when progress panel is visible */
177
- #progress-panel.show ~ #tests h2 {
178
- top: 158px; /* 78px + 80px to account for progress panel */
179
- }
180
-
181
- /* Style for h2 checkboxes */
182
- #tests h2 input[type="checkbox"] {
183
- margin-right: 18px;
184
- transform: scale(1.2);
185
- }
186
-
187
- #tests h2 label {
188
- cursor: pointer;
189
- display: flex;
190
- align-items: center;
191
- padding-left: 10px;
192
- font-size: 25px;
193
- }
194
- #test-counter {
195
- font-size: 14px;
196
- color: #666;
197
- margin-right: 10px;
198
- font-size: 20px;
199
- }
200
-
201
- /* Progress panel styles */
202
- #progress-panel {
203
- position: fixed;
204
- top: 78px;
205
- left: 0;
206
- right: 0;
207
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
208
- color: white;
209
- padding: 15px 20px;
210
- z-index: 999;
211
- box-shadow: 0 2px 10px rgba(0,0,0,0.1);
212
- transform: translateY(-100%);
213
- transition: transform 0.3s ease-in-out;
214
- border-bottom: 3px solid #4c84af;
215
- }
216
-
217
- #progress-panel.show {
218
- transform: translateY(0);
219
- }
220
-
221
- #progress-panel.show ~ #tests {
222
- padding-top: 120px !important;
223
- }
224
-
225
- .progress-content {
226
- display: flex;
227
- justify-content: space-between;
228
- align-items: center;
229
- max-width: 1200px;
230
- margin: 0 auto;
231
- }
232
-
233
- .progress-left {
234
- flex: 1;
235
- }
236
-
237
- .progress-right {
238
- display: flex;
239
- gap: 30px;
240
- align-items: center;
241
- }
242
-
243
- .progress-stats {
244
- display: flex;
245
- gap: 20px;
246
- margin-top: 8px;
247
- }
248
-
249
- .progress-stat {
250
- display: flex;
251
- flex-direction: column;
252
- align-items: center;
253
- min-width: 80px;
254
- }
255
-
256
- .progress-stat-number {
257
- font-size: 24px;
258
- font-weight: bold;
259
- line-height: 1;
260
- }
261
-
262
- .progress-stat-label {
263
- font-size: 11px;
264
- opacity: 0.9;
265
- text-transform: uppercase;
266
- letter-spacing: 0.5px;
267
- }
268
-
269
- .current-test {
270
- font-size: 16px;
271
- font-weight: 500;
272
- margin-bottom: 5px;
273
- }
274
-
275
- .progress-bar-container {
276
- background: rgba(255,255,255,0.2);
277
- border-radius: 10px;
278
- height: 8px;
279
- overflow: hidden;
280
- margin-top: 10px;
281
- }
282
-
283
- .progress-bar {
284
- background: linear-gradient(90deg, #00c851 0%, #00ff88 100%);
285
- height: 100%;
286
- border-radius: 10px;
287
- transition: width 0.3s ease;
288
- width: 0%;
289
- }
290
-
291
- .progress-percentage {
292
- font-size: 28px;
293
- font-weight: bold;
294
- color: #fff;
295
- }
296
-
297
- .stat-passed {
298
- color: #00ff88;
299
- }
300
-
301
- .stat-failed {
302
- color: #ff6b6b;
303
- }
304
-
305
- .stat-total {
306
- color: #fff;
307
- }
308
-
309
- .elapsed-time {
310
- font-size: 12px;
311
- opacity: 0.8;
312
- margin-top: 2px;
313
- }
314
-
315
- #reset-results:hover {
316
- color: #333;
317
- text-decoration: none;
318
- }
319
-
320
- /* Modal styles */
321
- .modal {
322
- display: none;
323
- position: fixed;
324
- z-index: 2000;
325
- left: 0;
326
- top: 0;
327
- width: 100%;
328
- height: 100%;
329
- background-color: rgba(0, 0, 0, 0.5);
330
- }
331
-
332
- .modal-content {
333
- background-color: #fefefe;
334
- margin: 10% auto;
335
- padding: 20px;
336
- border: 1px solid #888;
337
- border-radius: 8px;
338
- width: 500px;
339
- max-width: 90%;
340
- position: relative;
341
- }
342
-
343
- .close {
344
- color: #aaa;
345
- float: right;
346
- font-size: 28px;
347
- font-weight: bold;
348
- cursor: pointer;
349
- line-height: 1;
350
- }
351
-
352
- .close:hover,
353
- .close:focus {
354
- color: black;
355
- text-decoration: none;
356
- }
357
-
358
- .modal h2 {
359
- margin-top: 0;
360
- margin-bottom: 20px;
361
- color: #333;
362
- }
363
-
364
- .setting-group {
365
- margin-bottom: 15px;
366
- }
367
-
368
- .setting-group label {
369
- display: block;
370
- margin-bottom: 5px;
371
- font-weight: bold;
372
- color: #555;
373
- }
374
-
375
- .setting-group input {
376
- width: 100%;
377
- padding: 8px;
378
- border: 1px solid #ddd;
379
- border-radius: 4px;
380
- font-size: 14px;
381
- box-sizing: border-box;
382
- }
383
-
384
- .modal-buttons {
385
- margin-top: 20px;
386
- text-align: right;
387
- }
388
-
389
- .modal-buttons button {
390
- margin-left: 10px;
391
- padding: 8px 16px;
392
- border: none;
393
- border-radius: 4px;
394
- cursor: pointer;
395
- font-size: 14px;
396
- }
397
-
398
- .btn-cancel {
399
- background-color: #ccc;
400
- color: #333;
401
- }
402
-
403
- .btn-cancel:hover {
404
- background-color: #bbb;
405
- }
406
-
407
- .btn-save {
408
- background-color: #4c84af;
409
- color: white;
410
- }
411
-
412
- .btn-save:hover {
413
- background-color: #3a6a8a;
414
- }
415
- </style>
416
- <script>
417
- // Settings management
418
- const DEFAULT_SETTINGS = {
419
- puterJsUrl: 'https://js.puter.com/v2/',
420
- apiOrigin: 'https://api.puter.com'
421
- };
422
-
423
- let currentSettings = { ...DEFAULT_SETTINGS };
424
-
425
- // Authentication functionality
426
- async function updateAuthUI() {
427
- try {
428
- if (typeof puter === 'undefined' || !puter.auth) {
429
- // Puter not loaded yet, show login button
430
- $('#login-btn').show();
431
- $('#user-info').hide();
432
- return;
433
- }
434
-
435
- const isSignedIn = await puter.auth.isSignedIn();
436
-
437
- if (isSignedIn) {
438
- let user = await puter.auth.getUser();
439
- // User is signed in, show username and logout option
440
- $('#login-btn').hide();
441
- $('#user-info').show();
442
-
443
- // Get user info - for now we'll use a placeholder
444
- // In a real app, you might want to get the actual username from puter
445
- $('#username').text(user.username); // You may need to get actual username from puter API
446
- } else {
447
- // User is not signed in, show login button
448
- $('#login-btn').show();
449
- $('#user-info').hide();
450
- }
451
- } catch (error) {
452
- console.error('Error checking auth state:', error);
453
- // If there's an error, default to showing login button
454
- $('#login-btn').show();
455
- $('#user-info').hide();
456
- }
457
- }
458
-
459
- // Load settings from localStorage or use defaults
460
- function loadSettings() {
461
- const saved = localStorage.getItem('puter-test-settings');
462
- if (saved) {
463
- try {
464
- currentSettings = { ...DEFAULT_SETTINGS, ...JSON.parse(saved) };
465
- } catch (e) {
466
- console.warn('Failed to parse saved settings, using defaults');
467
- currentSettings = { ...DEFAULT_SETTINGS };
468
- }
469
- }
470
- }
471
-
472
- // Save settings to localStorage
473
- function saveSettings() {
474
- localStorage.setItem('puter-test-settings', JSON.stringify(currentSettings));
475
- }
476
-
477
- // Load Puter.js script dynamically
478
- function loadPuterScript() {
479
- return new Promise((resolve, reject) => {
480
- const script = document.getElementById('puter-script');
481
-
482
- // Remove existing script if any
483
- if (script.src) {
484
- script.remove();
485
- const newScript = document.createElement('script');
486
- newScript.id = 'puter-script';
487
- document.head.insertBefore(newScript, script.nextSibling);
488
- }
489
-
490
- const puterScript = document.getElementById('puter-script');
491
- puterScript.onload = resolve;
492
- puterScript.onerror = reject;
493
- puterScript.src = currentSettings.puterJsUrl;
494
- });
495
- }
496
-
497
- // Initialize Puter with settings
498
- async function initializePuter() {
499
- try {
500
- await loadPuterScript();
501
-
502
- // Wait a bit for the script to initialize
503
- await new Promise(resolve => setTimeout(resolve, 100));
504
-
505
- // Set API origin if puter object exists
506
- if (typeof puter !== 'undefined' && puter.setAPIOrigin) {
507
- puter.setAPIOrigin(currentSettings.apiOrigin);
508
- }
509
-
510
- // Update auth UI after puter is loaded
511
- await updateAuthUI();
512
- } catch (error) {
513
- console.error('Failed to load Puter.js:', error);
514
- alert('Failed to load Puter.js. Please check the URL in settings.');
515
- }
516
- }
517
-
518
- // Initialize on page load
519
- document.addEventListener("DOMContentLoaded", async () => {
520
- loadSettings();
521
- await initializePuter();
522
-
523
- // Progress tracking variables
524
- let testProgress = {
525
- total: 0,
526
- completed: 0,
527
- passed: 0,
528
- failed: 0,
529
- startTime: null,
530
- currentTest: '',
531
- timerInterval: null
532
- };
533
-
534
- // Progress panel functions
535
- function showProgressPanel() {
536
- $('#progress-panel').addClass('show');
537
- $('#run-tests').prop('disabled', true).text('Running Tests...');
538
- startProgressTimer();
539
- }
540
-
541
- function hideProgressPanel() {
542
- $('#progress-panel').removeClass('show');
543
- $('#run-tests').prop('disabled', false).text('Run Tests');
544
- stopProgressTimer();
545
- }
546
-
547
- function updateProgressPanel() {
548
- const { total, completed, passed, failed, currentTest } = testProgress;
549
- const percentage = total > 0 ? Math.round((completed / total) * 100) : 0;
550
-
551
- $('#current-test').text(currentTest || 'Preparing tests...');
552
- $('#progress-bar').css('width', percentage + '%');
553
- $('#progress-percentage').text(percentage + '%');
554
- $('#passed-count').text(passed);
555
- $('#failed-count').text(failed);
556
- $('#total-count').text(total);
557
- }
558
-
559
- function startProgressTimer() {
560
- testProgress.startTime = Date.now();
561
- testProgress.timerInterval = setInterval(() => {
562
- const elapsed = Math.floor((Date.now() - testProgress.startTime) / 1000);
563
- $('#elapsed-time').text(`Elapsed: ${elapsed}s`);
564
- }, 1000);
565
- }
566
-
567
- function stopProgressTimer() {
568
- if (testProgress.timerInterval) {
569
- clearInterval(testProgress.timerInterval);
570
- testProgress.timerInterval = null;
571
- }
572
- }
573
-
574
- function resetProgress() {
575
- testProgress.total = 0;
576
- testProgress.completed = 0;
577
- testProgress.passed = 0;
578
- testProgress.failed = 0;
579
- testProgress.currentTest = '';
580
- testProgress.startTime = null;
581
- }
582
-
583
- function getSelectedTestsCount() {
584
- return $('.test-checkbox:checked').length;
585
- }
586
-
587
- // Small delay to make progress visible
588
- function delay(ms) {
589
- return new Promise(resolve => setTimeout(resolve, ms));
590
- }
591
-
592
- window.pass = function(msg) {
593
- // $('#tests').append(`<p style="color:green;">${msg}</p>`);
594
- }
595
-
596
- window.fail = function(msg, error) {
597
- // Include the full error information in the thrown error
598
- let fullMessage = msg;
599
- if (error) {
600
- if (typeof error === 'string') {
601
- fullMessage += ' ' + error;
602
- } else if (error.message) {
603
- fullMessage += ' ' + error.message;
604
- } else {
605
- fullMessage += ' ' + JSON.stringify(error);
606
- }
607
- }
608
- const err = new Error(fullMessage);
609
- // Attach the original error for detailed display
610
- err.originalError = error;
611
- throw err;
612
- }
613
-
614
- // Function to get test name and description
615
- function getTestInfo(test) {
616
- if (typeof test === 'function') {
617
- return {
618
- name: test.name,
619
- description: test.description || 'No description provided'
620
- };
621
- } else if (typeof test === 'object' && test.name && test.test) {
622
- return {
623
- name: test.name,
624
- description: test.description || 'No description provided'
625
- };
626
- }
627
- return {
628
- name: 'Unknown Test',
629
- description: 'No description provided'
630
- };
631
- }
632
-
633
- // Function to execute a test
634
- async function executeTest(test) {
635
- if (typeof test === 'function') {
636
- return await test();
637
- } else if (typeof test === 'object' && test.test) {
638
- return await test.test();
639
- }
640
- throw new Error('Invalid test format');
641
- }
642
-
643
- // print the test name with checkbox for each test
644
- $('#tests').append('<h2><label><input type="checkbox" id="fsTests-group"> FileSystem</label></h2>');
645
- for (let i = 0; i < fsTests.length; i++) {
646
- const testInfo = getTestInfo(fsTests[i]);
647
- $('#tests').append(`<div class="test-container" id="fsTests-container-${i}">
648
- <div class="test-checkbox-container">
649
- <input type="checkbox" class="test-checkbox fsTests-checkbox" id="fsTests${i}">
650
- <label for="fsTests${i}">
651
- <div class="test-name">${testInfo.name}</div>
652
- <div class="test-description">${testInfo.description}</div>
653
- </label><br>
654
- <button class="test-run-button" onclick="runSingleTest('fs', ${i})">Run Test</button>
655
- </div>
656
- </div>`);
657
- }
658
-
659
- $('#tests').append('<h2><label><input type="checkbox" id="kvTests-group"> Key Value Store</label></h2>');
660
- for (let i = 0; i < kvTests.length; i++) {
661
- const testInfo = getTestInfo(kvTests[i]);
662
- $('#tests').append(`<div class="test-container" id="kvTests-container-${i}">
663
- <div class="test-checkbox-container">
664
- <input type="checkbox" class="test-checkbox kvTests-checkbox" id="kvTests${i}">
665
- <label for="kvTests${i}">
666
- <div class="test-name">${testInfo.name}</div>
667
- <div class="test-description">${testInfo.description}</div>
668
- </label><br>
669
- <button class="test-run-button" onclick="runSingleTest('kv', ${i})">Run Test</button>
670
- </div>
671
- </div>`);
672
- }
673
-
674
- $('#tests').append('<h2><label><input type="checkbox" id="aiTests-group"> AI</label></h2>');
675
- for (let i = 0; i < aiTests.length; i++) {
676
- const testInfo = getTestInfo(aiTests[i]);
677
- $('#tests').append(`<div class="test-container" id="aiTests-container-${i}">
678
- <div class="test-checkbox-container">
679
- <input type="checkbox" class="test-checkbox aiTests-checkbox" id="aiTests${i}">
680
- <label for="aiTests${i}">
681
- <div class="test-name">${testInfo.name}</div>
682
- <div class="test-description">${testInfo.description}</div>
683
- </label><br>
684
- <button class="test-run-button" onclick="runSingleTest('ai', ${i})">Run Test</button>
685
- </div>
686
- </div>`);
687
- }
688
-
689
- $('#tests').append('<h2><label><input type="checkbox" id="txt2speechTests-group"> Text-to-Speech</label></h2>');
690
- for (let i = 0; i < txt2speechTests.length; i++) {
691
- const testInfo = getTestInfo(txt2speechTests[i]);
692
- $('#tests').append(`<div class="test-container" id="txt2speechTests-container-${i}">
693
- <div class="test-checkbox-container">
694
- <input type="checkbox" class="test-checkbox txt2speechTests-checkbox" id="txt2speechTests${i}">
695
- <label for="txt2speechTests${i}">
696
- <div class="test-name">${testInfo.name}</div>
697
- <div class="test-description">${testInfo.description}</div>
698
- </label><br>
699
- <button class="test-run-button" onclick="runSingleTest('txt2speech', ${i})">Run Test</button>
700
- </div>
701
- </div>`);
702
- }
703
-
704
- // Add event listeners for group checkboxes
705
- $('#fsTests-group').change(function() {
706
- const isChecked = $(this).prop('checked');
707
- $('.fsTests-checkbox').prop('checked', isChecked);
708
- });
709
-
710
- $('#kvTests-group').change(function() {
711
- const isChecked = $(this).prop('checked');
712
- $('.kvTests-checkbox').prop('checked', isChecked);
713
- });
714
-
715
- $('#aiTests-group').change(function() {
716
- const isChecked = $(this).prop('checked');
717
- $('.aiTests-checkbox').prop('checked', isChecked);
718
- });
719
-
720
- $('#txt2speechTests-group').change(function() {
721
- const isChecked = $(this).prop('checked');
722
- $('.txt2speechTests-checkbox').prop('checked', isChecked);
723
- });
724
-
725
- // Add event listeners for individual checkboxes to update group checkbox state
726
- $(document).on('change', '.fsTests-checkbox', function() {
727
- const totalFsTests = $('.fsTests-checkbox').length;
728
- const checkedFsTests = $('.fsTests-checkbox:checked').length;
729
-
730
- if (checkedFsTests === 0) {
731
- $('#fsTests-group').prop('checked', false).prop('indeterminate', false);
732
- } else if (checkedFsTests === totalFsTests) {
733
- $('#fsTests-group').prop('checked', true).prop('indeterminate', false);
734
- } else {
735
- $('#fsTests-group').prop('checked', false).prop('indeterminate', true);
736
- }
737
- });
738
-
739
- $(document).on('change', '.kvTests-checkbox', function() {
740
- const totalKvTests = $('.kvTests-checkbox').length;
741
- const checkedKvTests = $('.kvTests-checkbox:checked').length;
742
-
743
- if (checkedKvTests === 0) {
744
- $('#kvTests-group').prop('checked', false).prop('indeterminate', false);
745
- } else if (checkedKvTests === totalKvTests) {
746
- $('#kvTests-group').prop('checked', true).prop('indeterminate', false);
747
- } else {
748
- $('#kvTests-group').prop('checked', false).prop('indeterminate', true);
749
- }
750
- });
751
-
752
- $(document).on('change', '.aiTests-checkbox', function() {
753
- const totalAiTests = $('.aiTests-checkbox').length;
754
- const checkedAiTests = $('.aiTests-checkbox:checked').length;
755
-
756
- if (checkedAiTests === 0) {
757
- $('#aiTests-group').prop('checked', false).prop('indeterminate', false);
758
- } else if (checkedAiTests === totalAiTests) {
759
- $('#aiTests-group').prop('checked', true).prop('indeterminate', false);
760
- } else {
761
- $('#aiTests-group').prop('checked', false).prop('indeterminate', true);
762
- }
763
- });
764
-
765
- $(document).on('change', '.txt2speechTests-checkbox', function() {
766
- const totalTxt2speechTests = $('.txt2speechTests-checkbox').length;
767
- const checkedTxt2speechTests = $('.txt2speechTests-checkbox:checked').length;
768
-
769
- if (checkedTxt2speechTests === 0) {
770
- $('#txt2speechTests-group').prop('checked', false).prop('indeterminate', false);
771
- } else if (checkedTxt2speechTests === totalTxt2speechTests) {
772
- $('#txt2speechTests-group').prop('checked', true).prop('indeterminate', false);
773
- } else {
774
- $('#txt2speechTests-group').prop('checked', false).prop('indeterminate', true);
775
- }
776
- });
777
-
778
- window.assert = function(condition, message) {
779
- if (!condition) {
780
- throw new Error(message || "Assertion failed");
781
- }
782
- }
783
-
784
- async function runSingleTest(testType, index) {
785
- const testSuites = {
786
- 'fs': fsTests,
787
- 'kv': kvTests,
788
- 'ai': aiTests,
789
- 'txt2speech': txt2speechTests
790
- };
791
-
792
- const tests = testSuites[testType];
793
- const containerId = `${testType}Tests-container-${index}`;
794
- const buttonSelector = `#${containerId} .test-run-button`;
795
-
796
- // Disable the button and show it while running
797
- $(buttonSelector).prop('disabled', true).text('Running...');
798
-
799
- // Clear previous results
800
- $(`#${containerId}`).css('background-color', '');
801
- $(`#${containerId} pre`).remove();
802
-
803
- try {
804
- await executeTest(tests[index]);
805
- // make this test's container green
806
- $(`#${containerId}`).css('background-color', '#85e085');
807
- } catch (e) {
808
- const testInfo = getTestInfo(tests[index]);
809
- console.error(`${testType.toUpperCase()} Test failed:`, testInfo.name, e);
810
- // make this test's container red
811
- $(`#${containerId}`).css('background-color', '#ffbfbf');
812
- // message - show full error information including JSON details
813
- let errorMessage = e.message || e.toString();
814
- if (e.originalError) {
815
- errorMessage += '\n\nOriginal Error:\n' + JSON.stringify(e.originalError, null, 2);
816
- }
817
- $(`#${containerId}`).append(`<pre style="color:#c00000; white-space: pre-wrap; font-size: 12px; margin: 5px 0; padding: 10px; background-color: #f8f8f8; border-radius: 3px;">${errorMessage}</pre>`);
818
- } finally {
819
- // Re-enable the button
820
- $(buttonSelector).prop('disabled', false).text('Run Test');
821
- }
822
- }
823
-
824
- window.runSingleTest = runSingleTest;
825
-
826
- async function runTests() {
827
- // Reset and initialize progress tracking
828
- resetProgress();
829
- testProgress.total = getSelectedTestsCount();
830
-
831
- // Show progress panel
832
- showProgressPanel();
833
- updateProgressPanel();
834
-
835
- // Clear previous test results
836
- $('.test-container').css('background-color', '');
837
- $('.test-container pre').remove();
838
-
839
- // go through fsTests and run each test
840
- for (let i = 0; i < fsTests.length; i++) {
841
- if (document.getElementById(`fsTests${i}`).checked) {
842
- const testInfo = getTestInfo(fsTests[i]);
843
- testProgress.currentTest = `FileSystem: ${testInfo.name}`;
844
- updateProgressPanel();
845
-
846
- try{
847
- await executeTest(fsTests[i]);
848
- // make this test's container green
849
- $(`#fsTests-container-${i}`).css('background-color', '#85e085');
850
- testProgress.passed++;
851
- } catch (e) {
852
- console.error('FS Test failed:', testInfo.name, e);
853
- // make this test's container red
854
- $(`#fsTests-container-${i}`).css('background-color', '#ffbfbf');
855
- // message - show full error information including JSON details
856
- let errorMessage = e.message || e.toString();
857
- if (e.originalError) {
858
- errorMessage += '\n\nOriginal Error:\n' + JSON.stringify(e.originalError, null, 2);
859
- }
860
- $(`#fsTests-container-${i}`).append(`<pre style="color:#c00000; white-space: pre-wrap; font-size: 12px; margin: 5px 0; padding: 10px; background-color: #f8f8f8; border-radius: 3px;">${errorMessage}</pre>`);
861
- testProgress.failed++;
862
- }
863
-
864
- testProgress.completed++;
865
- updateProgressPanel();
866
-
867
- // Small delay to make progress visible
868
- await delay(100);
869
- }
870
- }
871
-
872
- for (let i = 0; i < kvTests.length; i++) {
873
- if (document.getElementById(`kvTests${i}`).checked) {
874
- const testInfo = getTestInfo(kvTests[i]);
875
- testProgress.currentTest = `Key-Value Store: ${testInfo.name}`;
876
- updateProgressPanel();
877
-
878
- try{
879
- await executeTest(kvTests[i]);
880
- // make this test's container green
881
- $(`#kvTests-container-${i}`).css('background-color', '#85e085');
882
- testProgress.passed++;
883
- } catch (e) {
884
- console.error('KV Test failed:', testInfo.name, e);
885
- // make this test's container red
886
- $(`#kvTests-container-${i}`).css('background-color', '#ff8484');
887
- // message - show full error information including JSON details
888
- let errorMessage = e.message || e.toString();
889
- if (e.originalError) {
890
- errorMessage += '\n\nOriginal Error:\n' + JSON.stringify(e.originalError, null, 2);
891
- }
892
- $(`#kvTests-container-${i}`).append(`<pre style="color:red; white-space: pre-wrap; font-size: 12px; margin: 5px 0; padding: 10px; background-color: #f8f8f8; border-radius: 3px;">${errorMessage}</pre>`);
893
- testProgress.failed++;
894
- }
895
-
896
- testProgress.completed++;
897
- updateProgressPanel();
898
-
899
- // Small delay to make progress visible
900
- await delay(100);
901
- }
902
- }
903
-
904
- for (let i = 0; i < aiTests.length; i++) {
905
- if (document.getElementById(`aiTests${i}`).checked) {
906
- const testInfo = getTestInfo(aiTests[i]);
907
- testProgress.currentTest = `AI: ${testInfo.name}`;
908
- updateProgressPanel();
909
-
910
- try{
911
- await executeTest(aiTests[i]);
912
- // make this test's container green
913
- $(`#aiTests-container-${i}`).css('background-color', '#85e085');
914
- testProgress.passed++;
915
- } catch (e) {
916
- console.error('AI Test failed:', testInfo.name, e);
917
- // make this test's container red
918
- $(`#aiTests-container-${i}`).css('background-color', '#ff8484');
919
- // message - show full error information including JSON details
920
- let errorMessage = e.message || e.toString();
921
- if (e.originalError) {
922
- errorMessage += '\n\nOriginal Error:\n' + JSON.stringify(e.originalError, null, 2);
923
- }
924
- $(`#aiTests-container-${i}`).append(`<pre style="color:red; white-space: pre-wrap; font-size: 12px; margin: 5px 0; padding: 10px; background-color: #f8f8f8; border-radius: 3px;">${errorMessage}</pre>`);
925
- testProgress.failed++;
926
- }
927
-
928
- testProgress.completed++;
929
- updateProgressPanel();
930
-
931
- // Small delay to make progress visible
932
- await delay(100);
933
- }
934
- }
935
-
936
- for (let i = 0; i < txt2speechTests.length; i++) {
937
- if (document.getElementById(`txt2speechTests${i}`).checked) {
938
- const testInfo = getTestInfo(txt2speechTests[i]);
939
- testProgress.currentTest = `Text-to-Speech: ${testInfo.name}`;
940
- updateProgressPanel();
941
-
942
- try{
943
- await executeTest(txt2speechTests[i]);
944
- // make this test's container green
945
- $(`#txt2speechTests-container-${i}`).css('background-color', '#85e085');
946
- testProgress.passed++;
947
- } catch (e) {
948
- console.error('Txt2Speech Test failed:', testInfo.name, e);
949
- // make this test's container red
950
- $(`#txt2speechTests-container-${i}`).css('background-color', '#ff8484');
951
- // message - show full error information including JSON details
952
- let errorMessage = e.message || e.toString();
953
- if (e.originalError) {
954
- errorMessage += '\n\nOriginal Error:\n' + JSON.stringify(e.originalError, null, 2);
955
- }
956
- $(`#txt2speechTests-container-${i}`).append(`<pre style="color:red; white-space: pre-wrap; font-size: 12px; margin: 5px 0; padding: 10px; background-color: #f8f8f8; border-radius: 3px;">${errorMessage}</pre>`);
957
- testProgress.failed++;
958
- }
959
-
960
- testProgress.completed++;
961
- updateProgressPanel();
962
-
963
- // Small delay to make progress visible
964
- await delay(100);
965
- }
966
- }
967
-
968
- // Show completion message
969
- testProgress.currentTest = `Complete! ${testProgress.passed} passed, ${testProgress.failed} failed`;
970
- updateProgressPanel();
971
-
972
- // Stop the elapsed timer but keep panel visible
973
- stopProgressTimer();
974
-
975
- // Re-enable the run tests button
976
- $('#run-tests').prop('disabled', false).text('Run Tests');
977
- }
978
-
979
- $('#run-tests').click(() => {
980
- runTests();
981
- });
982
-
983
- // Reset results functionality
984
- $('#reset-results').click(() => {
985
- // Clear all test container background colors
986
- $('.test-container').css('background-color', '');
987
- // Remove all error message pre elements
988
- $('.test-container pre').remove();
989
- // Hide progress panel if it's showing
990
- hideProgressPanel();
991
- // Reset progress tracking
992
- resetProgress();
993
- });
994
-
995
- // Master checkbox functionality
996
- $('#master-checkbox').change(function() {
997
- const isChecked = $(this).prop('checked');
998
- $('.test-checkbox').prop('checked', isChecked);
999
- $('#fsTests-group, #kvTests-group, #aiTests-group, #txt2speechTests-group').prop('checked', isChecked);
1000
- // Update the counter display
1001
- updateMasterCheckboxState();
1002
- });
1003
-
1004
- // Function to update master checkbox state
1005
- function updateMasterCheckboxState() {
1006
- const totalCheckboxes = $('.test-checkbox').length;
1007
- const checkedCheckboxes = $('.test-checkbox:checked').length;
1008
-
1009
- // Update the counter display
1010
- $('#test-counter').text(`${checkedCheckboxes} / ${totalCheckboxes}`);
1011
-
1012
- if (checkedCheckboxes === 0) {
1013
- $('#master-checkbox').prop('checked', false).prop('indeterminate', false);
1014
- } else if (checkedCheckboxes === totalCheckboxes) {
1015
- $('#master-checkbox').prop('checked', true).prop('indeterminate', false);
1016
- } else {
1017
- $('#master-checkbox').prop('checked', false).prop('indeterminate', true);
1018
- }
1019
- }
1020
-
1021
- // Update master checkbox state when individual checkboxes change
1022
- $(document).on('change', '.test-checkbox', function() {
1023
- updateMasterCheckboxState();
1024
- });
1025
-
1026
- // Update master checkbox state when group checkboxes change
1027
- $('#fsTests-group, #kvTests-group, #aiTests-group, #txt2speechTests-group').change(function() {
1028
- updateMasterCheckboxState();
1029
- });
1030
-
1031
- // Initialize the counter display
1032
- updateMasterCheckboxState();
1033
-
1034
- // Login functionality
1035
- $('#login-btn').click(async () => {
1036
- try {
1037
- $('#login-btn').prop('disabled', true);
1038
- await puter.auth.signIn();
1039
- await updateAuthUI();
1040
- } catch (error) {
1041
- console.error('Login error:', error);
1042
- alert('Login failed. Please try again.');
1043
- } finally {
1044
- $('#login-btn').prop('disabled', false);
1045
- }
1046
- });
1047
-
1048
- // Logout functionality
1049
- $('#logout-link').click(async () => {
1050
- try {
1051
- await puter.auth.signOut();
1052
- await updateAuthUI();
1053
- } catch (error) {
1054
- console.error('Logout error:', error);
1055
- alert('Logout failed. Please try again.');
1056
- }
1057
- });
1058
-
1059
- // Initialize auth UI after puter is loaded
1060
- updateAuthUI();
1061
-
1062
- // Settings modal functionality
1063
- $('#settings-btn').click(() => {
1064
- // Populate modal with current settings
1065
- $('#puter-js-url').val(currentSettings.puterJsUrl);
1066
- $('#api-origin').val(currentSettings.apiOrigin);
1067
- $('#settings-modal').show();
1068
- });
1069
-
1070
- // Close modal
1071
- $('.close, .btn-cancel').click(() => {
1072
- $('#settings-modal').hide();
1073
- });
1074
-
1075
- // Save settings
1076
- $('.btn-save').click(async () => {
1077
- const newSettings = {
1078
- puterJsUrl: $('#puter-js-url').val().trim(),
1079
- apiOrigin: $('#api-origin').val().trim()
1080
- };
1081
-
1082
- // Validate URLs
1083
- if (!newSettings.puterJsUrl || !newSettings.apiOrigin) {
1084
- alert('Please provide both Puter.js URL and API Origin');
1085
- return;
1086
- }
1087
-
1088
- // Update current settings
1089
- currentSettings = { ...newSettings };
1090
- saveSettings();
1091
-
1092
- // Reinitialize Puter with new settings
1093
- await initializePuter();
1094
-
1095
- $('#settings-modal').hide();
1096
- });
1097
-
1098
- // Close modal when clicking outside
1099
- $(window).click((event) => {
1100
- if (event.target === $('#settings-modal')[0]) {
1101
- $('#settings-modal').hide();
1102
- }
1103
- });
1104
- });
1105
-
1106
- </script>
1107
- </head>
1108
- <body>
1109
-
1110
- <nav>
1111
- <label style="margin-left: 8px; margin-right: 10px; cursor: pointer; display: inline-flex; align-items: center;">
1112
- <input type="checkbox" id="master-checkbox" style="margin-right: 5px; transform: scale(1.2);">
1113
- </label>
1114
- <span id="test-counter"></span>
1115
- <div style="flex: 1; display: flex; align-items: center;">
1116
- <button id="run-tests" style="margin-right: 10px;">Run Tests</button>
1117
- <span id="reset-results" style="margin-right: 20px; cursor: pointer; color: #666; text-decoration: underline; font-size: 14px;">Reset results</span>
1118
- <button id="settings-btn">Settings</button>
1119
- <div id="auth-section">
1120
- <button id="login-btn" style="display: none;">Login</button>
1121
- <div id="user-info" style="display: none;">
1122
- <span id="username"></span>
1123
- <span id="logout-link">(logout)</span>
1124
- </div>
1125
- </div>
1126
- </div>
1127
- </nav>
1128
-
1129
- <div id="progress-panel">
1130
- <div class="progress-content">
1131
- <div class="progress-left">
1132
- <div class="current-test" id="current-test">Preparing tests...</div>
1133
- <div class="progress-bar-container">
1134
- <div class="progress-bar" id="progress-bar"></div>
1135
- </div>
1136
- <div class="elapsed-time" id="elapsed-time">Elapsed: 0s</div>
1137
- </div>
1138
- <div class="progress-right">
1139
- <div class="progress-stats">
1140
- <div class="progress-stat">
1141
- <div class="progress-stat-number stat-passed" id="passed-count">0</div>
1142
- <div class="progress-stat-label">Passed</div>
1143
- </div>
1144
- <div class="progress-stat">
1145
- <div class="progress-stat-number stat-failed" id="failed-count">0</div>
1146
- <div class="progress-stat-label">Failed</div>
1147
- </div>
1148
- <div class="progress-stat">
1149
- <div class="progress-stat-number stat-total" id="total-count">0</div>
1150
- <div class="progress-stat-label">Total</div>
1151
- </div>
1152
- </div>
1153
- <div class="progress-percentage" id="progress-percentage">0%</div>
1154
- </div>
1155
- </div>
1156
- </div>
1157
-
1158
- <!-- Settings Modal -->
1159
- <div id="settings-modal" class="modal">
1160
- <div class="modal-content">
1161
- <span class="close">&times;</span>
1162
- <h2>Settings</h2>
1163
-
1164
- <div class="setting-group">
1165
- <label for="puter-js-url">Puter.js URL:</label>
1166
- <input type="text" id="puter-js-url" placeholder="https://js.puter.com/v2/">
1167
- </div>
1168
-
1169
- <div class="setting-group">
1170
- <label for="api-origin">API Origin:</label>
1171
- <input type="text" id="api-origin" placeholder="https://api.puter.com">
1172
- </div>
1173
-
1174
- <div class="modal-buttons">
1175
- <button class="btn-cancel">Cancel</button>
1176
- <button class="btn-save">Save</button>
1177
- </div>
1178
- </div>
1179
- </div>
1180
-
1181
- <div id="tests"></div>
1182
- </body>
1183
- </html>