@fias/plugin-dev-harness 1.6.5 → 1.6.6

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 (48) hide show
  1. package/dist/bridge/live-handler.d.ts.map +1 -1
  2. package/dist/bridge/live-handler.js +9 -0
  3. package/dist/bridge/live-handler.js.map +1 -1
  4. package/dist/bridge/mock-handler.d.ts +2 -0
  5. package/dist/bridge/mock-handler.d.ts.map +1 -1
  6. package/dist/bridge/mock-handler.js +120 -0
  7. package/dist/bridge/mock-handler.js.map +1 -1
  8. package/dist/cli/dev.d.ts.map +1 -1
  9. package/dist/cli/dev.js +12 -1
  10. package/dist/cli/dev.js.map +1 -1
  11. package/dist/cli/dev.test.js +19 -0
  12. package/dist/cli/dev.test.js.map +1 -1
  13. package/dist/cli/index.d.ts.map +1 -1
  14. package/dist/cli/index.js +2 -1
  15. package/dist/cli/index.js.map +1 -1
  16. package/dist/cli/index.test.js +11 -4
  17. package/dist/cli/index.test.js.map +1 -1
  18. package/dist/cli/submit.d.ts.map +1 -1
  19. package/dist/cli/submit.js +11 -5
  20. package/dist/cli/submit.js.map +1 -1
  21. package/dist/cli/submit.test.js +9 -5
  22. package/dist/cli/submit.test.js.map +1 -1
  23. package/dist/cli/sync.d.ts.map +1 -1
  24. package/dist/cli/sync.js +1 -6
  25. package/dist/cli/sync.js.map +1 -1
  26. package/dist/cli/sync.test.d.ts +2 -0
  27. package/dist/cli/sync.test.d.ts.map +1 -0
  28. package/dist/cli/sync.test.js +75 -0
  29. package/dist/cli/sync.test.js.map +1 -0
  30. package/dist/cli/update-checker.d.ts +29 -0
  31. package/dist/cli/update-checker.d.ts.map +1 -0
  32. package/dist/cli/update-checker.js +186 -0
  33. package/dist/cli/update-checker.js.map +1 -0
  34. package/dist/cli/update-checker.test.d.ts +2 -0
  35. package/dist/cli/update-checker.test.d.ts.map +1 -0
  36. package/dist/cli/update-checker.test.js +170 -0
  37. package/dist/cli/update-checker.test.js.map +1 -0
  38. package/dist/index.js +0 -0
  39. package/dist/server/harness-server.d.ts +4 -0
  40. package/dist/server/harness-server.d.ts.map +1 -1
  41. package/dist/server/harness-server.js +55 -6
  42. package/dist/server/harness-server.js.map +1 -1
  43. package/dist/server/harness-server.test.js +6 -0
  44. package/dist/server/harness-server.test.js.map +1 -1
  45. package/dist/server/static/harness.css +53 -12
  46. package/dist/server/static/harness.html +11 -23
  47. package/dist/server/static/harness.js +140 -54
  48. package/package.json +2 -2
@@ -18,6 +18,7 @@
18
18
  var modeBadge = document.getElementById('mode-badge');
19
19
  var modeToggle = document.getElementById('mode-toggle');
20
20
  var pluginStatus = document.getElementById('plugin-status');
21
+ var versionBadge = document.getElementById('version-badge');
21
22
 
22
23
  /** Extract a human-readable message from backend error responses.
23
24
  * Backend returns { error: { code, message } } but callers expect a string. */
@@ -76,6 +77,10 @@
76
77
  updateThemeBadge();
77
78
  updateModeBadge();
78
79
 
80
+ if (config.harnessVersion && versionBadge) {
81
+ versionBadge.textContent = 'v' + config.harnessVersion;
82
+ }
83
+
79
84
  if (currentMode === 'live') {
80
85
  creditBalance.style.display = 'inline';
81
86
  fetchCredits();
@@ -516,13 +521,6 @@
516
521
  var pubValidationPassed = false;
517
522
 
518
523
  publishBtn.addEventListener('click', function () {
519
- if (currentMode !== 'live' || !hasCredentials) {
520
- pubError.textContent = 'Switch to live mode and sign in to publish.';
521
- pubError.style.display = 'block';
522
- publishModal.style.display = 'flex';
523
- showPublishStep(1);
524
- return;
525
- }
526
524
  pubError.style.display = 'none';
527
525
  fetch('/api/manifest')
528
526
  .then(function (r) {
@@ -561,6 +559,20 @@
561
559
  pubNext.addEventListener('click', function () {
562
560
  pubError.style.display = 'none';
563
561
  if (pubStep === 1) {
562
+ // Validate About is filled in
563
+ var about = document.getElementById('pub-expanded-desc').value.trim();
564
+ if (!about) {
565
+ pubError.textContent = 'About is required. Describe what your plugin does and how to use it.';
566
+ pubError.style.display = 'block';
567
+ document.getElementById('pub-expanded-desc').focus();
568
+ return;
569
+ }
570
+ // Live mode required from validation onward
571
+ if (currentMode !== 'live' || !hasCredentials) {
572
+ pubError.textContent = 'Switch to live mode and sign in to publish.';
573
+ pubError.style.display = 'block';
574
+ return;
575
+ }
564
576
  collectAndSaveManifest().then(function () { showPublishStep(2); startValidation(); });
565
577
  } else if (pubStep === 2 && pubValidationPassed) {
566
578
  showPublishStep(3);
@@ -591,70 +603,123 @@
591
603
 
592
604
  function populatePublishForm(m) {
593
605
  document.getElementById('pub-name').value = m.name || '';
594
- document.getElementById('pub-version').value = m.version || '1.0.0';
595
606
  document.getElementById('pub-description').value = m.description || '';
596
607
  document.getElementById('pub-expanded-desc').value = m.expandedDescription || '';
597
- document.getElementById('pub-archetype').value = m.archeType || 'tool';
598
- document.getElementById('pub-pricing-model').value = m.pricing?.model || 'free';
599
- document.getElementById('pub-price').value = m.pricing?.priceCents || '';
600
- document.getElementById('pub-price-row').style.display = m.pricing?.model === 'free' ? 'none' : 'block';
601
-
602
- // Tags
603
- var tagsList = document.getElementById('pub-tags-list');
604
- tagsList.innerHTML = '';
605
- (m.tags || []).forEach(function (t) { addPublishTag(t); });
606
-
607
- // Permissions
608
- var checkboxes = document.querySelectorAll('#pub-permissions input[type="checkbox"]');
608
+
609
+ // Display options
610
+ var isFullScreen = m.isFullScreen || m.archeType === 'site';
611
+ document.getElementById('pub-listed').checked = m.isListed !== false; // default true
612
+ document.getElementById('pub-public').checked = m.isPublic || false;
613
+ document.getElementById('pub-fullscreen').checked = isFullScreen;
614
+
615
+ // Pricing — hidden when full screen mode (sites are always free)
616
+ updatePricingVisibility(isFullScreen);
617
+ if (!isFullScreen) {
618
+ // Normalize legacy 'free'/'per_use' to the two supported values
619
+ var pModel = m.pricing?.model || 'free';
620
+ if (pModel === 'free' || pModel === 'included' || pModel === 'no_base_cost') pModel = 'free';
621
+ else pModel = 'fixed';
622
+ document.getElementById('pub-pricing-model').value = pModel;
623
+ document.getElementById('pub-price').value = m.pricing?.priceCents || '';
624
+ document.getElementById('pub-price-row').style.display = pModel === 'free' ? 'none' : 'block';
625
+ }
626
+ updatePublicAccessAvailability();
627
+
628
+ // Permissions (read-only, derived from fias-plugin.json)
629
+ var permsContainer = document.getElementById('pub-permissions');
609
630
  var perms = m.permissions || [];
610
- checkboxes.forEach(function (cb) { cb.checked = perms.indexOf(cb.value) !== -1; });
631
+ permsContainer.innerHTML = perms.length
632
+ ? perms.map(function (p) { return '<span class="pub-perm-tag">' + escapeHtml(p) + '</span>'; }).join(' ')
633
+ : '<span style="color:#6b7280;font-size:12px">None declared in fias-plugin.json</span>';
611
634
  }
612
635
 
613
- // Tag management
614
- document.getElementById('pub-tags-input').addEventListener('keydown', function (e) {
615
- if (e.key === 'Enter' || e.key === ',') {
616
- e.preventDefault();
617
- var val = this.value.trim().replace(/,/g, '');
618
- if (val) { addPublishTag(val); this.value = ''; }
636
+ function updatePricingVisibility(isFullScreen) {
637
+ var pricingLabel = document.getElementById('pub-pricing-model').previousElementSibling;
638
+ var pricingSelect = document.getElementById('pub-pricing-model');
639
+ var priceRow = document.getElementById('pub-price-row');
640
+ if (isFullScreen) {
641
+ pricingLabel.style.display = 'none';
642
+ pricingSelect.style.display = 'none';
643
+ priceRow.style.display = 'none';
644
+ } else {
645
+ pricingLabel.style.display = '';
646
+ pricingSelect.style.display = '';
647
+ priceRow.style.display = pricingSelect.value === 'free' ? 'none' : 'block';
619
648
  }
620
- });
649
+ }
621
650
 
622
- function addPublishTag(text) {
623
- var tag = document.createElement('span');
624
- tag.className = 'pub-tag';
625
- tag.innerHTML = escapeHtml(text) + ' <button class="pub-tag-remove">&times;</button>';
626
- tag.querySelector('.pub-tag-remove').addEventListener('click', function () { tag.remove(); });
627
- document.getElementById('pub-tags-list').appendChild(tag);
651
+ /** Disable Public Access when the plugin is paid or uses AI entities */
652
+ function updatePublicAccessAvailability() {
653
+ var pubPublic = document.getElementById('pub-public');
654
+ var pricingModel = document.getElementById('pub-pricing-model').value;
655
+ var perms = (pubManifest && pubManifest.permissions) || [];
656
+ var hasAi = perms.indexOf('entities:invoke') !== -1 || perms.indexOf('entities:image_generate') !== -1;
657
+ var isPaid = pricingModel === 'fixed';
658
+
659
+ if (hasAi || isPaid) {
660
+ pubPublic.checked = false;
661
+ pubPublic.disabled = true;
662
+ pubPublic.parentElement.style.opacity = '0.5';
663
+ pubPublic.parentElement.title = 'Only available for free arches that don\'t require credits';
664
+ } else {
665
+ pubPublic.disabled = false;
666
+ pubPublic.parentElement.style.opacity = '';
667
+ pubPublic.parentElement.title = '';
668
+ }
628
669
  }
629
670
 
671
+ // Full Screen Mode toggle — controls pricing visibility
672
+ document.getElementById('pub-fullscreen').addEventListener('change', function () {
673
+ updatePricingVisibility(this.checked);
674
+ updatePublicAccessAvailability();
675
+ });
676
+
630
677
  // Pricing model change
631
678
  document.getElementById('pub-pricing-model').addEventListener('change', function () {
632
679
  document.getElementById('pub-price-row').style.display = this.value === 'free' ? 'none' : 'block';
680
+ updatePublicAccessAvailability();
633
681
  });
634
682
 
683
+ // Permissions are read-only (from fias-plugin.json), no change listeners needed.
684
+
635
685
  function collectManifest() {
636
- var tags = [];
637
- document.querySelectorAll('#pub-tags-list .pub-tag').forEach(function (t) {
638
- tags.push(t.textContent.replace('\u00d7', '').trim());
639
- });
640
- var perms = [];
641
- document.querySelectorAll('#pub-permissions input:checked').forEach(function (cb) { perms.push(cb.value); });
642
- var pricingModel = document.getElementById('pub-pricing-model').value;
643
- var pricing = { model: pricingModel, currency: 'usd' };
644
- if (pricingModel !== 'free') pricing.priceCents = parseInt(document.getElementById('pub-price').value, 10) || 0;
686
+ var perms = (pubManifest && pubManifest.permissions) || [];
687
+
688
+ var isFullScreen = document.getElementById('pub-fullscreen').checked;
689
+ var isListed = document.getElementById('pub-listed').checked;
690
+ var isPublic = document.getElementById('pub-public').checked;
691
+
692
+ // Infer arche type: public → site (display-only), otherwise → tool
693
+ var archeType = isPublic ? 'site' : 'tool';
694
+
695
+ // Pricing: user picks "free" or "fixed" — these are the valid manifest values.
696
+ var pricing;
697
+ if (isFullScreen) {
698
+ pricing = { model: 'free', currency: 'usd' };
699
+ } else {
700
+ var pricingChoice = document.getElementById('pub-pricing-model').value;
701
+ if (pricingChoice === 'fixed') {
702
+ pricing = { model: 'fixed', currency: 'usd', priceCents: parseInt(document.getElementById('pub-price').value, 10) || 0 };
703
+ } else {
704
+ pricing = { model: 'free', currency: 'usd' };
705
+ }
706
+ }
645
707
 
646
708
  return {
647
709
  name: document.getElementById('pub-name').value.trim(),
648
- version: document.getElementById('pub-version').value.trim(),
710
+ version: (pubManifest && pubManifest.version) || '1.0.0',
649
711
  description: document.getElementById('pub-description').value.trim(),
650
712
  expandedDescription: document.getElementById('pub-expanded-desc').value.trim() || undefined,
651
713
  main: (pubManifest && pubManifest.main) || 'src/index.tsx',
652
- archeType: document.getElementById('pub-archetype').value,
653
- tags: tags,
714
+ archeType: archeType,
715
+ tags: (pubManifest && pubManifest.tags) || [],
654
716
  pricing: pricing,
655
717
  permissions: perms,
656
718
  sdk: (pubManifest && pubManifest.sdk) || '^1.0.0',
657
719
  dependencies: pubManifest && pubManifest.dependencies,
720
+ isListed: isListed,
721
+ isPublic: isPublic,
722
+ isFullScreen: isFullScreen,
658
723
  };
659
724
  }
660
725
 
@@ -716,13 +781,18 @@
716
781
  // Listing preview
717
782
  var preview = document.getElementById('pub-listing-preview');
718
783
  var m = pubManifest;
784
+ var pricingLabel = m.pricing.model === 'fixed' ? 'Paid' : 'Free';
785
+ var flags = [];
786
+ if (m.isListed !== false) flags.push('Listed');
787
+ if (m.isPublic) flags.push('Public');
788
+ if (m.isFullScreen) flags.push('Full Screen');
719
789
  preview.innerHTML =
720
790
  '<div class="pub-listing-name">' + escapeHtml(m.name) + '</div>' +
721
791
  '<div class="pub-listing-desc">' + escapeHtml(m.description) + '</div>' +
722
792
  '<div class="pub-listing-meta">' +
723
793
  '<span>v' + escapeHtml(m.version) + '</span>' +
724
- '<span>' + escapeHtml(m.archeType) + '</span>' +
725
- '<span>' + escapeHtml(m.pricing.model) + '</span>' +
794
+ '<span>' + escapeHtml(pricingLabel) + '</span>' +
795
+ (flags.length ? '<span>' + escapeHtml(flags.join(', ')) + '</span>' : '') +
726
796
  '</div>';
727
797
  })
728
798
  .catch(function (err) {
@@ -734,15 +804,31 @@
734
804
 
735
805
  function showCostInfo() {
736
806
  var costEl = document.getElementById('pub-cost-info');
737
- costEl.innerHTML = '<p>Submission cost: <strong>5,000 credits ($50.00)</strong> for first listing, <strong>100 credits ($1.00)</strong> for updates.</p>';
738
- fetch('/api/credits').then(function (r) { return r.json(); }).then(function (d) {
739
- if (d.balance != null && isFinite(d.balance)) {
740
- costEl.innerHTML += '<p style="margin-top:8px">Your balance: <strong>' + d.balance.toFixed(2) + ' credits</strong></p>';
741
- }
742
- }).catch(function () {});
807
+ costEl.innerHTML = '<p>Checking submission cost...</p>';
743
808
  document.getElementById('pub-build-output').style.display = 'none';
744
809
  document.getElementById('pub-build-output').textContent = '';
745
810
  document.getElementById('pub-submit-progress').innerHTML = '';
811
+
812
+ // Determine if this is a first listing or update by checking existing submissions
813
+ Promise.all([
814
+ fetch('/api/publish/submissions').then(function (r) { return r.ok ? r.json() : { submissions: [] }; }),
815
+ fetch('/api/credits').then(function (r) { return r.json(); }),
816
+ ]).then(function (results) {
817
+ var subsData = results[0];
818
+ var creditsData = results[1];
819
+ var existingCount = (subsData.submissions || []).length;
820
+ var isUpdate = existingCount > 0;
821
+ var cost = isUpdate ? '100 credits ($1.00)' : '5,000 credits ($50.00)';
822
+ var costType = isUpdate ? 'Update' : 'First listing';
823
+
824
+ costEl.innerHTML = '<p>' + costType + ' cost: <strong>' + cost + '</strong></p>';
825
+
826
+ if (creditsData.balance != null && isFinite(creditsData.balance)) {
827
+ costEl.innerHTML += '<p style="margin-top:8px">Your balance: <strong>' + creditsData.balance.toFixed(2) + ' credits</strong></p>';
828
+ }
829
+ }).catch(function () {
830
+ costEl.innerHTML = '<p>Submission cost: <strong>5,000 credits ($50.00)</strong> for first listing, <strong>100 credits ($1.00)</strong> for updates.</p>';
831
+ });
746
832
  }
747
833
 
748
834
  function startBuildAndSubmit() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fias/plugin-dev-harness",
3
- "version": "1.6.5",
3
+ "version": "1.6.6",
4
4
  "description": "Development harness for building and testing FIAS plugin arches locally",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -16,7 +16,7 @@
16
16
  "access": "public"
17
17
  },
18
18
  "scripts": {
19
- "build": "rm -rf dist && tsc && cp -r src/server/static dist/server/static",
19
+ "build": "rm -rf dist && tsc && cp -r src/server/static dist/server/static && chmod +x dist/index.js",
20
20
  "clean": "rm -rf dist",
21
21
  "watch": "tsc -w",
22
22
  "typecheck": "tsc --noEmit"