@fias/plugin-dev-harness 1.5.2 → 1.5.4
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/dist/server/harness-server.d.ts.map +1 -1
- package/dist/server/harness-server.js +7 -1
- package/dist/server/harness-server.js.map +1 -1
- package/dist/server/static/harness.css +255 -8
- package/dist/server/static/harness.html +80 -11
- package/dist/server/static/harness.js +390 -93
- package/package.json +1 -1
- package/dist/server/static/static/harness.css +0 -642
- package/dist/server/static/static/harness.html +0 -139
- package/dist/server/static/static/harness.js +0 -1090
|
@@ -16,14 +16,9 @@
|
|
|
16
16
|
var themeToggle = document.getElementById('theme-toggle');
|
|
17
17
|
var reloadBtn = document.getElementById('reload-btn');
|
|
18
18
|
var modeBadge = document.getElementById('mode-badge');
|
|
19
|
+
var modeToggle = document.getElementById('mode-toggle');
|
|
19
20
|
var pluginStatus = document.getElementById('plugin-status');
|
|
20
21
|
var themeBadge = document.getElementById('theme-badge');
|
|
21
|
-
var loginModal = document.getElementById('login-modal');
|
|
22
|
-
var loginEmail = document.getElementById('login-email');
|
|
23
|
-
var loginPassword = document.getElementById('login-password');
|
|
24
|
-
var loginError = document.getElementById('login-error');
|
|
25
|
-
var loginSubmit = document.getElementById('login-submit');
|
|
26
|
-
var loginCancel = document.getElementById('login-cancel');
|
|
27
22
|
var envSelector = document.getElementById('env-selector');
|
|
28
23
|
|
|
29
24
|
var messageCount = 0;
|
|
@@ -38,6 +33,7 @@
|
|
|
38
33
|
get_user: 'user:profile:read',
|
|
39
34
|
get_theme: 'theme:read',
|
|
40
35
|
entity_invoke: 'entities:invoke',
|
|
36
|
+
image_generate: 'entities:image_generate',
|
|
41
37
|
storage_read: 'storage:sandbox',
|
|
42
38
|
storage_write: 'storage:sandbox',
|
|
43
39
|
storage_list: 'storage:sandbox',
|
|
@@ -47,6 +43,7 @@
|
|
|
47
43
|
/** Rate limits per message type (matches production) */
|
|
48
44
|
var RATE_LIMITS = {
|
|
49
45
|
entity_invoke: { maxPerMinute: 60 },
|
|
46
|
+
image_generate: { maxPerMinute: 10 },
|
|
50
47
|
storage_write: { maxPerMinute: 120 },
|
|
51
48
|
storage_read: { maxPerMinute: 300 },
|
|
52
49
|
storage_list: { maxPerMinute: 60 },
|
|
@@ -124,11 +121,11 @@
|
|
|
124
121
|
logMessage('send', 'theme_update', { mode: currentTheme });
|
|
125
122
|
});
|
|
126
123
|
|
|
127
|
-
// Mode toggle
|
|
128
|
-
|
|
124
|
+
// Mode toggle button
|
|
125
|
+
modeToggle.addEventListener('click', function () {
|
|
129
126
|
if (currentMode === 'mock') {
|
|
130
127
|
if (!hasCredentials) {
|
|
131
|
-
|
|
128
|
+
logMessage('error', 'Not authenticated. Run: npx fias-dev login');
|
|
132
129
|
return;
|
|
133
130
|
}
|
|
134
131
|
switchMode('live');
|
|
@@ -205,88 +202,6 @@
|
|
|
205
202
|
});
|
|
206
203
|
}
|
|
207
204
|
|
|
208
|
-
// ────────────────────────────────────────────────────────────────
|
|
209
|
-
// Login Modal
|
|
210
|
-
// ────────────────────────────────────────────────────────────────
|
|
211
|
-
|
|
212
|
-
var loginTarget = document.getElementById('login-target');
|
|
213
|
-
|
|
214
|
-
function showLoginModal() {
|
|
215
|
-
loginModal.style.display = 'flex';
|
|
216
|
-
loginEmail.value = '';
|
|
217
|
-
loginPassword.value = '';
|
|
218
|
-
loginError.style.display = 'none';
|
|
219
|
-
loginSubmit.disabled = false;
|
|
220
|
-
loginSubmit.textContent = 'Sign in';
|
|
221
|
-
loginTarget.textContent = currentEnvironment === 'production' ? 'fias.io' : 'staging.fias.io';
|
|
222
|
-
loginEmail.focus();
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
function hideLoginModal() {
|
|
226
|
-
loginModal.style.display = 'none';
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
loginCancel.addEventListener('click', hideLoginModal);
|
|
230
|
-
|
|
231
|
-
loginModal.addEventListener('click', function (e) {
|
|
232
|
-
if (e.target === loginModal) hideLoginModal();
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
loginEmail.addEventListener('keydown', function (e) {
|
|
236
|
-
if (e.key === 'Enter') loginPassword.focus();
|
|
237
|
-
if (e.key === 'Escape') hideLoginModal();
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
loginPassword.addEventListener('keydown', function (e) {
|
|
241
|
-
if (e.key === 'Enter') submitLogin();
|
|
242
|
-
if (e.key === 'Escape') hideLoginModal();
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
loginSubmit.addEventListener('click', submitLogin);
|
|
246
|
-
|
|
247
|
-
function submitLogin() {
|
|
248
|
-
var email = loginEmail.value.trim();
|
|
249
|
-
var password = loginPassword.value;
|
|
250
|
-
|
|
251
|
-
if (!email || !password) {
|
|
252
|
-
loginError.textContent = 'Email and password are required.';
|
|
253
|
-
loginError.style.display = 'block';
|
|
254
|
-
return;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
loginSubmit.disabled = true;
|
|
258
|
-
loginSubmit.textContent = 'Signing in...';
|
|
259
|
-
loginError.style.display = 'none';
|
|
260
|
-
|
|
261
|
-
fetch('/api/auth/login', {
|
|
262
|
-
method: 'POST',
|
|
263
|
-
headers: { 'Content-Type': 'application/json' },
|
|
264
|
-
body: JSON.stringify({ email: email, password: password }),
|
|
265
|
-
})
|
|
266
|
-
.then(function (r) {
|
|
267
|
-
if (!r.ok) {
|
|
268
|
-
return r.json().then(function (err) {
|
|
269
|
-
throw new Error(err.error || 'Sign in failed');
|
|
270
|
-
});
|
|
271
|
-
}
|
|
272
|
-
return r.json();
|
|
273
|
-
})
|
|
274
|
-
.then(function () {
|
|
275
|
-
hasCredentials = true;
|
|
276
|
-
hideLoginModal();
|
|
277
|
-
logMessage('info', 'Signed in for ' + currentEnvironment.toUpperCase());
|
|
278
|
-
switchMode('live');
|
|
279
|
-
})
|
|
280
|
-
.catch(function (err) {
|
|
281
|
-
loginError.textContent = err.message;
|
|
282
|
-
loginError.style.display = 'block';
|
|
283
|
-
})
|
|
284
|
-
.finally(function () {
|
|
285
|
-
loginSubmit.disabled = false;
|
|
286
|
-
loginSubmit.textContent = 'Sign in';
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
|
|
290
205
|
// ────────────────────────────────────────────────────────────────
|
|
291
206
|
// Message Handling
|
|
292
207
|
// ────────────────────────────────────────────────────────────────
|
|
@@ -475,6 +390,388 @@
|
|
|
475
390
|
});
|
|
476
391
|
}
|
|
477
392
|
|
|
393
|
+
// ────────────────────────────────────────────────────────────────
|
|
394
|
+
// Publish Wizard
|
|
395
|
+
// ────────────────────────────────────────────────────────────────
|
|
396
|
+
|
|
397
|
+
var publishBtn = document.getElementById('publish-btn');
|
|
398
|
+
var publishModal = document.getElementById('publish-modal');
|
|
399
|
+
var pubCancel = document.getElementById('pub-cancel');
|
|
400
|
+
var pubBack = document.getElementById('pub-back');
|
|
401
|
+
var pubNext = document.getElementById('pub-next');
|
|
402
|
+
var pubError = document.getElementById('pub-error');
|
|
403
|
+
var pubStep = 1;
|
|
404
|
+
var pubManifest = null;
|
|
405
|
+
var pubSubmissionId = null;
|
|
406
|
+
var pubPollTimer = null;
|
|
407
|
+
var pubValidationPassed = false;
|
|
408
|
+
|
|
409
|
+
publishBtn.addEventListener('click', function () {
|
|
410
|
+
if (currentMode !== 'live' || !hasCredentials) {
|
|
411
|
+
pubError.textContent = 'Switch to live mode and sign in to publish.';
|
|
412
|
+
pubError.style.display = 'block';
|
|
413
|
+
publishModal.style.display = 'flex';
|
|
414
|
+
showPublishStep(1);
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
pubError.style.display = 'none';
|
|
418
|
+
fetch('/api/manifest')
|
|
419
|
+
.then(function (r) {
|
|
420
|
+
if (!r.ok) throw new Error('fias-plugin.json not found');
|
|
421
|
+
return r.json();
|
|
422
|
+
})
|
|
423
|
+
.then(function (manifest) {
|
|
424
|
+
pubManifest = manifest;
|
|
425
|
+
populatePublishForm(manifest);
|
|
426
|
+
publishModal.style.display = 'flex';
|
|
427
|
+
showPublishStep(1);
|
|
428
|
+
})
|
|
429
|
+
.catch(function (err) {
|
|
430
|
+
pubError.textContent = err.message;
|
|
431
|
+
pubError.style.display = 'block';
|
|
432
|
+
publishModal.style.display = 'flex';
|
|
433
|
+
showPublishStep(1);
|
|
434
|
+
});
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
pubCancel.addEventListener('click', closePublishModal);
|
|
438
|
+
publishModal.addEventListener('click', function (e) {
|
|
439
|
+
if (e.target === publishModal) closePublishModal();
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
function closePublishModal() {
|
|
443
|
+
publishModal.style.display = 'none';
|
|
444
|
+
if (pubPollTimer) { clearInterval(pubPollTimer); pubPollTimer = null; }
|
|
445
|
+
pubStep = 1;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
pubBack.addEventListener('click', function () {
|
|
449
|
+
if (pubStep > 1) showPublishStep(pubStep - 1);
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
pubNext.addEventListener('click', function () {
|
|
453
|
+
pubError.style.display = 'none';
|
|
454
|
+
if (pubStep === 1) {
|
|
455
|
+
collectAndSaveManifest().then(function () { showPublishStep(2); startValidation(); });
|
|
456
|
+
} else if (pubStep === 2 && pubValidationPassed) {
|
|
457
|
+
showPublishStep(3);
|
|
458
|
+
showCostInfo();
|
|
459
|
+
} else if (pubStep === 3) {
|
|
460
|
+
startBuildAndSubmit();
|
|
461
|
+
} else if (pubStep === 4) {
|
|
462
|
+
closePublishModal();
|
|
463
|
+
}
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
function showPublishStep(step) {
|
|
467
|
+
pubStep = step;
|
|
468
|
+
for (var i = 1; i <= 4; i++) {
|
|
469
|
+
var el = document.getElementById('publish-step-' + i);
|
|
470
|
+
if (el) el.style.display = i === step ? 'block' : 'none';
|
|
471
|
+
}
|
|
472
|
+
var steps = document.querySelectorAll('.publish-step');
|
|
473
|
+
steps.forEach(function (s, idx) {
|
|
474
|
+
s.className = 'publish-step' + (idx + 1 === step ? ' active' : idx + 1 < step ? ' completed' : '');
|
|
475
|
+
});
|
|
476
|
+
pubBack.style.display = step > 1 && step < 4 ? 'inline-block' : 'none';
|
|
477
|
+
if (step === 1) { pubNext.textContent = 'Validate'; pubNext.style.display = 'inline-block'; }
|
|
478
|
+
else if (step === 2) { pubNext.textContent = 'Build & Submit'; pubNext.style.display = 'inline-block'; pubNext.disabled = !pubValidationPassed; }
|
|
479
|
+
else if (step === 3) { pubNext.textContent = 'Confirm & Build'; pubNext.style.display = 'inline-block'; }
|
|
480
|
+
else if (step === 4) { pubNext.textContent = 'Close'; pubNext.style.display = 'inline-block'; }
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
function populatePublishForm(m) {
|
|
484
|
+
document.getElementById('pub-name').value = m.name || '';
|
|
485
|
+
document.getElementById('pub-version').value = m.version || '1.0.0';
|
|
486
|
+
document.getElementById('pub-description').value = m.description || '';
|
|
487
|
+
document.getElementById('pub-expanded-desc').value = m.expandedDescription || '';
|
|
488
|
+
document.getElementById('pub-archetype').value = m.archeType || 'tool';
|
|
489
|
+
document.getElementById('pub-pricing-model').value = m.pricing?.model || 'free';
|
|
490
|
+
document.getElementById('pub-price').value = m.pricing?.priceCents || '';
|
|
491
|
+
document.getElementById('pub-price-row').style.display = m.pricing?.model === 'free' ? 'none' : 'block';
|
|
492
|
+
|
|
493
|
+
// Tags
|
|
494
|
+
var tagsList = document.getElementById('pub-tags-list');
|
|
495
|
+
tagsList.innerHTML = '';
|
|
496
|
+
(m.tags || []).forEach(function (t) { addPublishTag(t); });
|
|
497
|
+
|
|
498
|
+
// Permissions
|
|
499
|
+
var checkboxes = document.querySelectorAll('#pub-permissions input[type="checkbox"]');
|
|
500
|
+
var perms = m.permissions || [];
|
|
501
|
+
checkboxes.forEach(function (cb) { cb.checked = perms.indexOf(cb.value) !== -1; });
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// Tag management
|
|
505
|
+
document.getElementById('pub-tags-input').addEventListener('keydown', function (e) {
|
|
506
|
+
if (e.key === 'Enter' || e.key === ',') {
|
|
507
|
+
e.preventDefault();
|
|
508
|
+
var val = this.value.trim().replace(/,/g, '');
|
|
509
|
+
if (val) { addPublishTag(val); this.value = ''; }
|
|
510
|
+
}
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
function addPublishTag(text) {
|
|
514
|
+
var tag = document.createElement('span');
|
|
515
|
+
tag.className = 'pub-tag';
|
|
516
|
+
tag.innerHTML = escapeHtml(text) + ' <button class="pub-tag-remove">×</button>';
|
|
517
|
+
tag.querySelector('.pub-tag-remove').addEventListener('click', function () { tag.remove(); });
|
|
518
|
+
document.getElementById('pub-tags-list').appendChild(tag);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// Pricing model change
|
|
522
|
+
document.getElementById('pub-pricing-model').addEventListener('change', function () {
|
|
523
|
+
document.getElementById('pub-price-row').style.display = this.value === 'free' ? 'none' : 'block';
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
function collectManifest() {
|
|
527
|
+
var tags = [];
|
|
528
|
+
document.querySelectorAll('#pub-tags-list .pub-tag').forEach(function (t) {
|
|
529
|
+
tags.push(t.textContent.replace('\u00d7', '').trim());
|
|
530
|
+
});
|
|
531
|
+
var perms = [];
|
|
532
|
+
document.querySelectorAll('#pub-permissions input:checked').forEach(function (cb) { perms.push(cb.value); });
|
|
533
|
+
var pricingModel = document.getElementById('pub-pricing-model').value;
|
|
534
|
+
var pricing = { model: pricingModel, currency: 'usd' };
|
|
535
|
+
if (pricingModel !== 'free') pricing.priceCents = parseInt(document.getElementById('pub-price').value, 10) || 0;
|
|
536
|
+
|
|
537
|
+
return {
|
|
538
|
+
name: document.getElementById('pub-name').value.trim(),
|
|
539
|
+
version: document.getElementById('pub-version').value.trim(),
|
|
540
|
+
description: document.getElementById('pub-description').value.trim(),
|
|
541
|
+
expandedDescription: document.getElementById('pub-expanded-desc').value.trim() || undefined,
|
|
542
|
+
main: (pubManifest && pubManifest.main) || 'src/index.tsx',
|
|
543
|
+
archeType: document.getElementById('pub-archetype').value,
|
|
544
|
+
tags: tags,
|
|
545
|
+
pricing: pricing,
|
|
546
|
+
permissions: perms,
|
|
547
|
+
sdk: (pubManifest && pubManifest.sdk) || '^1.0.0',
|
|
548
|
+
dependencies: pubManifest && pubManifest.dependencies,
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
function collectAndSaveManifest() {
|
|
553
|
+
var manifest = collectManifest();
|
|
554
|
+
pubManifest = manifest;
|
|
555
|
+
return fetch('/api/manifest', {
|
|
556
|
+
method: 'PUT',
|
|
557
|
+
headers: { 'Content-Type': 'application/json' },
|
|
558
|
+
body: JSON.stringify(manifest),
|
|
559
|
+
}).then(function (r) {
|
|
560
|
+
if (!r.ok) throw new Error('Failed to save manifest');
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
function startValidation() {
|
|
565
|
+
pubValidationPassed = false;
|
|
566
|
+
pubNext.disabled = true;
|
|
567
|
+
document.getElementById('pub-validate-loading').style.display = 'flex';
|
|
568
|
+
document.getElementById('pub-validate-results').style.display = 'none';
|
|
569
|
+
|
|
570
|
+
fetch('/api/publish/validate', { method: 'POST' })
|
|
571
|
+
.then(function (r) { return r.json(); })
|
|
572
|
+
.then(function (data) {
|
|
573
|
+
document.getElementById('pub-validate-loading').style.display = 'none';
|
|
574
|
+
document.getElementById('pub-validate-results').style.display = 'block';
|
|
575
|
+
|
|
576
|
+
var statusEl = document.getElementById('pub-validate-status');
|
|
577
|
+
var errorsEl = document.getElementById('pub-validate-errors');
|
|
578
|
+
var warningsEl = document.getElementById('pub-validate-warnings');
|
|
579
|
+
errorsEl.innerHTML = '';
|
|
580
|
+
warningsEl.innerHTML = '';
|
|
581
|
+
|
|
582
|
+
if (data.valid && (!data.errors || data.errors.length === 0)) {
|
|
583
|
+
statusEl.innerHTML = '<div class="pub-valid">Manifest is valid</div>';
|
|
584
|
+
pubValidationPassed = true;
|
|
585
|
+
pubNext.disabled = false;
|
|
586
|
+
} else {
|
|
587
|
+
statusEl.innerHTML = '<div style="color:#fca5a5;font-weight:500;margin-bottom:8px">Validation failed</div>';
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
if (data.errors) {
|
|
591
|
+
data.errors.forEach(function (e) {
|
|
592
|
+
var div = document.createElement('div');
|
|
593
|
+
div.className = 'pub-error-item';
|
|
594
|
+
div.textContent = e;
|
|
595
|
+
errorsEl.appendChild(div);
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
if (data.warnings) {
|
|
599
|
+
data.warnings.forEach(function (w) {
|
|
600
|
+
var div = document.createElement('div');
|
|
601
|
+
div.className = 'pub-warn-item';
|
|
602
|
+
div.textContent = w;
|
|
603
|
+
warningsEl.appendChild(div);
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// Listing preview
|
|
608
|
+
var preview = document.getElementById('pub-listing-preview');
|
|
609
|
+
var m = pubManifest;
|
|
610
|
+
preview.innerHTML =
|
|
611
|
+
'<div class="pub-listing-name">' + escapeHtml(m.name) + '</div>' +
|
|
612
|
+
'<div class="pub-listing-desc">' + escapeHtml(m.description) + '</div>' +
|
|
613
|
+
'<div class="pub-listing-meta">' +
|
|
614
|
+
'<span>v' + escapeHtml(m.version) + '</span>' +
|
|
615
|
+
'<span>' + escapeHtml(m.archeType) + '</span>' +
|
|
616
|
+
'<span>' + escapeHtml(m.pricing.model) + '</span>' +
|
|
617
|
+
'</div>';
|
|
618
|
+
})
|
|
619
|
+
.catch(function (err) {
|
|
620
|
+
document.getElementById('pub-validate-loading').style.display = 'none';
|
|
621
|
+
pubError.textContent = err.message;
|
|
622
|
+
pubError.style.display = 'block';
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
function showCostInfo() {
|
|
627
|
+
var costEl = document.getElementById('pub-cost-info');
|
|
628
|
+
costEl.innerHTML = '<p>Submission cost: <strong>5,000 credits ($50.00)</strong> for first listing, <strong>100 credits ($1.00)</strong> for updates.</p>';
|
|
629
|
+
fetch('/api/credits').then(function (r) { return r.json(); }).then(function (d) {
|
|
630
|
+
if (d.balance != null && isFinite(d.balance)) {
|
|
631
|
+
costEl.innerHTML += '<p style="margin-top:8px">Your balance: <strong>' + d.balance.toFixed(2) + ' credits</strong></p>';
|
|
632
|
+
}
|
|
633
|
+
}).catch(function () {});
|
|
634
|
+
document.getElementById('pub-build-output').style.display = 'none';
|
|
635
|
+
document.getElementById('pub-build-output').textContent = '';
|
|
636
|
+
document.getElementById('pub-submit-progress').innerHTML = '';
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
function startBuildAndSubmit() {
|
|
640
|
+
pubNext.style.display = 'none';
|
|
641
|
+
pubBack.style.display = 'none';
|
|
642
|
+
var outputEl = document.getElementById('pub-build-output');
|
|
643
|
+
var progressEl = document.getElementById('pub-submit-progress');
|
|
644
|
+
outputEl.style.display = 'block';
|
|
645
|
+
outputEl.textContent = '';
|
|
646
|
+
progressEl.innerHTML = '<div class="pub-phase active" id="phase-build">Building...</div>' +
|
|
647
|
+
'<div class="pub-phase" id="phase-package">Packaging...</div>' +
|
|
648
|
+
'<div class="pub-phase" id="phase-submit">Uploading & submitting...</div>';
|
|
649
|
+
|
|
650
|
+
// SSE build
|
|
651
|
+
fetch('/api/publish/build', { method: 'POST' })
|
|
652
|
+
.then(function (response) {
|
|
653
|
+
var reader = response.body.getReader();
|
|
654
|
+
var decoder = new TextDecoder();
|
|
655
|
+
var buffer = '';
|
|
656
|
+
|
|
657
|
+
function pump() {
|
|
658
|
+
return reader.read().then(function (chunk) {
|
|
659
|
+
if (chunk.done) return;
|
|
660
|
+
buffer += decoder.decode(chunk.value, { stream: true });
|
|
661
|
+
var lines = buffer.split('\n');
|
|
662
|
+
buffer = lines.pop() || '';
|
|
663
|
+
for (var i = 0; i < lines.length; i++) {
|
|
664
|
+
if (lines[i].indexOf('data: ') !== 0) continue;
|
|
665
|
+
try {
|
|
666
|
+
var parsed = JSON.parse(lines[i].slice(6));
|
|
667
|
+
if (parsed.line) {
|
|
668
|
+
outputEl.textContent += parsed.line + '\n';
|
|
669
|
+
outputEl.scrollTop = outputEl.scrollHeight;
|
|
670
|
+
}
|
|
671
|
+
if (parsed.done) {
|
|
672
|
+
if (parsed.code !== 0) throw new Error('Build failed (exit code ' + parsed.code + ')');
|
|
673
|
+
document.getElementById('phase-build').className = 'pub-phase done';
|
|
674
|
+
document.getElementById('phase-build').textContent = 'Build complete';
|
|
675
|
+
return doPackageAndSubmit();
|
|
676
|
+
}
|
|
677
|
+
} catch (e) {
|
|
678
|
+
if (e instanceof SyntaxError) continue;
|
|
679
|
+
throw e;
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
return pump();
|
|
683
|
+
});
|
|
684
|
+
}
|
|
685
|
+
return pump();
|
|
686
|
+
})
|
|
687
|
+
.catch(function (err) {
|
|
688
|
+
document.getElementById('phase-build').className = 'pub-phase error';
|
|
689
|
+
document.getElementById('phase-build').textContent = 'Build failed: ' + err.message;
|
|
690
|
+
pubBack.style.display = 'inline-block';
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
function doPackageAndSubmit() {
|
|
695
|
+
var progressPhase = document.getElementById('phase-package');
|
|
696
|
+
progressPhase.className = 'pub-phase active';
|
|
697
|
+
|
|
698
|
+
return fetch('/api/publish/package', { method: 'POST' })
|
|
699
|
+
.then(function (r) {
|
|
700
|
+
if (!r.ok) return r.json().then(function (e) { throw new Error(e.error); });
|
|
701
|
+
return r.json();
|
|
702
|
+
})
|
|
703
|
+
.then(function (data) {
|
|
704
|
+
progressPhase.className = 'pub-phase done';
|
|
705
|
+
progressPhase.textContent = 'Packaged (' + Math.round(data.sizeBytes / 1024) + ' KB)';
|
|
706
|
+
document.getElementById('phase-submit').className = 'pub-phase active';
|
|
707
|
+
|
|
708
|
+
return fetch('/api/publish/submit', {
|
|
709
|
+
method: 'POST',
|
|
710
|
+
headers: { 'Content-Type': 'application/json' },
|
|
711
|
+
body: JSON.stringify({}),
|
|
712
|
+
});
|
|
713
|
+
})
|
|
714
|
+
.then(function (r) {
|
|
715
|
+
if (!r.ok) return r.json().then(function (e) { throw new Error(e.error); });
|
|
716
|
+
return r.json();
|
|
717
|
+
})
|
|
718
|
+
.then(function (data) {
|
|
719
|
+
document.getElementById('phase-submit').className = 'pub-phase done';
|
|
720
|
+
document.getElementById('phase-submit').textContent = 'Submitted for review';
|
|
721
|
+
pubSubmissionId = data.submissionId;
|
|
722
|
+
logMessage('info', 'Submitted: ' + pubSubmissionId);
|
|
723
|
+
setTimeout(function () { showPublishStep(4); startStatusPolling(); }, 1000);
|
|
724
|
+
})
|
|
725
|
+
.catch(function (err) {
|
|
726
|
+
var active = document.querySelector('.pub-phase.active');
|
|
727
|
+
if (active) { active.className = 'pub-phase error'; active.textContent += ' — ' + err.message; }
|
|
728
|
+
pubBack.style.display = 'inline-block';
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
function startStatusPolling() {
|
|
733
|
+
if (pubPollTimer) clearInterval(pubPollTimer);
|
|
734
|
+
document.getElementById('pub-review-status').style.display = 'block';
|
|
735
|
+
document.getElementById('pub-review-result').style.display = 'none';
|
|
736
|
+
|
|
737
|
+
pubPollTimer = setInterval(function () {
|
|
738
|
+
fetch('/api/publish/status/' + pubSubmissionId)
|
|
739
|
+
.then(function (r) { return r.json(); })
|
|
740
|
+
.then(function (data) {
|
|
741
|
+
var sub = data.submission || data;
|
|
742
|
+
var status = sub.status;
|
|
743
|
+
var statusEl = document.getElementById('pub-review-status');
|
|
744
|
+
|
|
745
|
+
if (status === 'reviewing') {
|
|
746
|
+
statusEl.innerHTML = '<div class="status-spinner"></div><p>AI is reviewing your plugin...</p>';
|
|
747
|
+
} else if (status === 'building') {
|
|
748
|
+
statusEl.innerHTML = '<div class="status-spinner"></div><p>Building your plugin...</p>';
|
|
749
|
+
} else if (status === 'published') {
|
|
750
|
+
clearInterval(pubPollTimer);
|
|
751
|
+
pubPollTimer = null;
|
|
752
|
+
statusEl.style.display = 'none';
|
|
753
|
+
document.getElementById('pub-review-result').style.display = 'block';
|
|
754
|
+
document.getElementById('pub-review-result').innerHTML =
|
|
755
|
+
'<div class="pub-congrats">Published!</div>' +
|
|
756
|
+
'<p style="text-align:center;color:#a1a1aa;font-size:13px">Your plugin is now live on the Fias marketplace.</p>';
|
|
757
|
+
logMessage('info', 'Plugin published!');
|
|
758
|
+
} else if (status === 'rejected') {
|
|
759
|
+
clearInterval(pubPollTimer);
|
|
760
|
+
pubPollTimer = null;
|
|
761
|
+
statusEl.style.display = 'none';
|
|
762
|
+
document.getElementById('pub-review-result').style.display = 'block';
|
|
763
|
+
var html = '<div class="pub-rejected">Submission Rejected</div>';
|
|
764
|
+
if (sub.errorMessage) html += '<p style="color:#a1a1aa;font-size:12px;margin-bottom:8px">' + escapeHtml(sub.errorMessage) + '</p>';
|
|
765
|
+
if (data.review) {
|
|
766
|
+
html += '<p style="color:#6b7280;font-size:11px">Risk score: ' + (data.review.riskScore || 'N/A') + '</p>';
|
|
767
|
+
}
|
|
768
|
+
document.getElementById('pub-review-result').innerHTML = html;
|
|
769
|
+
}
|
|
770
|
+
})
|
|
771
|
+
.catch(function () {});
|
|
772
|
+
}, 3000);
|
|
773
|
+
}
|
|
774
|
+
|
|
478
775
|
// ────────────────────────────────────────────────────────────────
|
|
479
776
|
// Iframe Init
|
|
480
777
|
// ────────────────────────────────────────────────────────────────
|
|
@@ -501,9 +798,9 @@
|
|
|
501
798
|
|
|
502
799
|
function updateModeBadge() {
|
|
503
800
|
var opposite = currentMode === 'live' ? 'Mock' : 'Live';
|
|
504
|
-
modeBadge.textContent = currentMode.toUpperCase()
|
|
801
|
+
modeBadge.textContent = currentMode.toUpperCase();
|
|
505
802
|
modeBadge.className = 'mode-badge ' + (currentMode === 'live' ? 'mode-live' : 'mode-mock');
|
|
506
|
-
|
|
803
|
+
modeToggle.textContent = 'Switch to ' + opposite;
|
|
507
804
|
}
|
|
508
805
|
|
|
509
806
|
function updateThemeBadge() {
|