@fias/plugin-dev-harness 1.6.5 → 1.6.7

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 +56 -7
  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 +141 -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();
@@ -192,6 +197,7 @@
192
197
  })
193
198
  .then(function (data) {
194
199
  currentMode = data.mode;
200
+ hasCredentials = data.hasCredentials || false;
195
201
  updateModeBadge();
196
202
  logMessage('info', 'Mode switched to ' + currentMode.toUpperCase());
197
203
 
@@ -516,13 +522,6 @@
516
522
  var pubValidationPassed = false;
517
523
 
518
524
  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
525
  pubError.style.display = 'none';
527
526
  fetch('/api/manifest')
528
527
  .then(function (r) {
@@ -561,6 +560,20 @@
561
560
  pubNext.addEventListener('click', function () {
562
561
  pubError.style.display = 'none';
563
562
  if (pubStep === 1) {
563
+ // Validate About is filled in
564
+ var about = document.getElementById('pub-expanded-desc').value.trim();
565
+ if (!about) {
566
+ pubError.textContent = 'About is required. Describe what your plugin does and how to use it.';
567
+ pubError.style.display = 'block';
568
+ document.getElementById('pub-expanded-desc').focus();
569
+ return;
570
+ }
571
+ // Live mode required from validation onward
572
+ if (currentMode !== 'live' || !hasCredentials) {
573
+ pubError.textContent = 'Switch to live mode and sign in to publish.';
574
+ pubError.style.display = 'block';
575
+ return;
576
+ }
564
577
  collectAndSaveManifest().then(function () { showPublishStep(2); startValidation(); });
565
578
  } else if (pubStep === 2 && pubValidationPassed) {
566
579
  showPublishStep(3);
@@ -591,70 +604,123 @@
591
604
 
592
605
  function populatePublishForm(m) {
593
606
  document.getElementById('pub-name').value = m.name || '';
594
- document.getElementById('pub-version').value = m.version || '1.0.0';
595
607
  document.getElementById('pub-description').value = m.description || '';
596
608
  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"]');
609
+
610
+ // Display options
611
+ var isFullScreen = m.isFullScreen || m.archeType === 'site';
612
+ document.getElementById('pub-listed').checked = m.isListed !== false; // default true
613
+ document.getElementById('pub-public').checked = m.isPublic || false;
614
+ document.getElementById('pub-fullscreen').checked = isFullScreen;
615
+
616
+ // Pricing — hidden when full screen mode (sites are always free)
617
+ updatePricingVisibility(isFullScreen);
618
+ if (!isFullScreen) {
619
+ // Normalize legacy 'free'/'per_use' to the two supported values
620
+ var pModel = m.pricing?.model || 'free';
621
+ if (pModel === 'free' || pModel === 'included' || pModel === 'no_base_cost') pModel = 'free';
622
+ else pModel = 'fixed';
623
+ document.getElementById('pub-pricing-model').value = pModel;
624
+ document.getElementById('pub-price').value = m.pricing?.priceCents || '';
625
+ document.getElementById('pub-price-row').style.display = pModel === 'free' ? 'none' : 'block';
626
+ }
627
+ updatePublicAccessAvailability();
628
+
629
+ // Permissions (read-only, derived from fias-plugin.json)
630
+ var permsContainer = document.getElementById('pub-permissions');
609
631
  var perms = m.permissions || [];
610
- checkboxes.forEach(function (cb) { cb.checked = perms.indexOf(cb.value) !== -1; });
632
+ permsContainer.innerHTML = perms.length
633
+ ? perms.map(function (p) { return '<span class="pub-perm-tag">' + escapeHtml(p) + '</span>'; }).join(' ')
634
+ : '<span style="color:#6b7280;font-size:12px">None declared in fias-plugin.json</span>';
611
635
  }
612
636
 
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 = ''; }
637
+ function updatePricingVisibility(isFullScreen) {
638
+ var pricingLabel = document.getElementById('pub-pricing-model').previousElementSibling;
639
+ var pricingSelect = document.getElementById('pub-pricing-model');
640
+ var priceRow = document.getElementById('pub-price-row');
641
+ if (isFullScreen) {
642
+ pricingLabel.style.display = 'none';
643
+ pricingSelect.style.display = 'none';
644
+ priceRow.style.display = 'none';
645
+ } else {
646
+ pricingLabel.style.display = '';
647
+ pricingSelect.style.display = '';
648
+ priceRow.style.display = pricingSelect.value === 'free' ? 'none' : 'block';
619
649
  }
620
- });
650
+ }
621
651
 
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);
652
+ /** Disable Public Access when the plugin is paid or uses AI entities */
653
+ function updatePublicAccessAvailability() {
654
+ var pubPublic = document.getElementById('pub-public');
655
+ var pricingModel = document.getElementById('pub-pricing-model').value;
656
+ var perms = (pubManifest && pubManifest.permissions) || [];
657
+ var hasAi = perms.indexOf('entities:invoke') !== -1 || perms.indexOf('entities:image_generate') !== -1;
658
+ var isPaid = pricingModel === 'fixed';
659
+
660
+ if (hasAi || isPaid) {
661
+ pubPublic.checked = false;
662
+ pubPublic.disabled = true;
663
+ pubPublic.parentElement.style.opacity = '0.5';
664
+ pubPublic.parentElement.title = 'Only available for free arches that don\'t require credits';
665
+ } else {
666
+ pubPublic.disabled = false;
667
+ pubPublic.parentElement.style.opacity = '';
668
+ pubPublic.parentElement.title = '';
669
+ }
628
670
  }
629
671
 
672
+ // Full Screen Mode toggle — controls pricing visibility
673
+ document.getElementById('pub-fullscreen').addEventListener('change', function () {
674
+ updatePricingVisibility(this.checked);
675
+ updatePublicAccessAvailability();
676
+ });
677
+
630
678
  // Pricing model change
631
679
  document.getElementById('pub-pricing-model').addEventListener('change', function () {
632
680
  document.getElementById('pub-price-row').style.display = this.value === 'free' ? 'none' : 'block';
681
+ updatePublicAccessAvailability();
633
682
  });
634
683
 
684
+ // Permissions are read-only (from fias-plugin.json), no change listeners needed.
685
+
635
686
  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;
687
+ var perms = (pubManifest && pubManifest.permissions) || [];
688
+
689
+ var isFullScreen = document.getElementById('pub-fullscreen').checked;
690
+ var isListed = document.getElementById('pub-listed').checked;
691
+ var isPublic = document.getElementById('pub-public').checked;
692
+
693
+ // Infer arche type: public → site (display-only), otherwise → tool
694
+ var archeType = isPublic ? 'site' : 'tool';
695
+
696
+ // Pricing: user picks "free" or "fixed" — these are the valid manifest values.
697
+ var pricing;
698
+ if (isFullScreen) {
699
+ pricing = { model: 'free', currency: 'usd' };
700
+ } else {
701
+ var pricingChoice = document.getElementById('pub-pricing-model').value;
702
+ if (pricingChoice === 'fixed') {
703
+ pricing = { model: 'fixed', currency: 'usd', priceCents: parseInt(document.getElementById('pub-price').value, 10) || 0 };
704
+ } else {
705
+ pricing = { model: 'free', currency: 'usd' };
706
+ }
707
+ }
645
708
 
646
709
  return {
647
710
  name: document.getElementById('pub-name').value.trim(),
648
- version: document.getElementById('pub-version').value.trim(),
711
+ version: (pubManifest && pubManifest.version) || '1.0.0',
649
712
  description: document.getElementById('pub-description').value.trim(),
650
713
  expandedDescription: document.getElementById('pub-expanded-desc').value.trim() || undefined,
651
714
  main: (pubManifest && pubManifest.main) || 'src/index.tsx',
652
- archeType: document.getElementById('pub-archetype').value,
653
- tags: tags,
715
+ archeType: archeType,
716
+ tags: (pubManifest && pubManifest.tags) || [],
654
717
  pricing: pricing,
655
718
  permissions: perms,
656
719
  sdk: (pubManifest && pubManifest.sdk) || '^1.0.0',
657
720
  dependencies: pubManifest && pubManifest.dependencies,
721
+ isListed: isListed,
722
+ isPublic: isPublic,
723
+ isFullScreen: isFullScreen,
658
724
  };
659
725
  }
660
726
 
@@ -716,13 +782,18 @@
716
782
  // Listing preview
717
783
  var preview = document.getElementById('pub-listing-preview');
718
784
  var m = pubManifest;
785
+ var pricingLabel = m.pricing.model === 'fixed' ? 'Paid' : 'Free';
786
+ var flags = [];
787
+ if (m.isListed !== false) flags.push('Listed');
788
+ if (m.isPublic) flags.push('Public');
789
+ if (m.isFullScreen) flags.push('Full Screen');
719
790
  preview.innerHTML =
720
791
  '<div class="pub-listing-name">' + escapeHtml(m.name) + '</div>' +
721
792
  '<div class="pub-listing-desc">' + escapeHtml(m.description) + '</div>' +
722
793
  '<div class="pub-listing-meta">' +
723
794
  '<span>v' + escapeHtml(m.version) + '</span>' +
724
- '<span>' + escapeHtml(m.archeType) + '</span>' +
725
- '<span>' + escapeHtml(m.pricing.model) + '</span>' +
795
+ '<span>' + escapeHtml(pricingLabel) + '</span>' +
796
+ (flags.length ? '<span>' + escapeHtml(flags.join(', ')) + '</span>' : '') +
726
797
  '</div>';
727
798
  })
728
799
  .catch(function (err) {
@@ -734,15 +805,31 @@
734
805
 
735
806
  function showCostInfo() {
736
807
  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 () {});
808
+ costEl.innerHTML = '<p>Checking submission cost...</p>';
743
809
  document.getElementById('pub-build-output').style.display = 'none';
744
810
  document.getElementById('pub-build-output').textContent = '';
745
811
  document.getElementById('pub-submit-progress').innerHTML = '';
812
+
813
+ // Determine if this is a first listing or update by checking existing submissions
814
+ Promise.all([
815
+ fetch('/api/publish/submissions').then(function (r) { return r.ok ? r.json() : { submissions: [] }; }),
816
+ fetch('/api/credits').then(function (r) { return r.json(); }),
817
+ ]).then(function (results) {
818
+ var subsData = results[0];
819
+ var creditsData = results[1];
820
+ var existingCount = (subsData.submissions || []).length;
821
+ var isUpdate = existingCount > 0;
822
+ var cost = isUpdate ? '100 credits ($1.00)' : '5,000 credits ($50.00)';
823
+ var costType = isUpdate ? 'Update' : 'First listing';
824
+
825
+ costEl.innerHTML = '<p>' + costType + ' cost: <strong>' + cost + '</strong></p>';
826
+
827
+ if (creditsData.balance != null && isFinite(creditsData.balance)) {
828
+ costEl.innerHTML += '<p style="margin-top:8px">Your balance: <strong>' + creditsData.balance.toFixed(2) + ' credits</strong></p>';
829
+ }
830
+ }).catch(function () {
831
+ costEl.innerHTML = '<p>Submission cost: <strong>5,000 credits ($50.00)</strong> for first listing, <strong>100 credits ($1.00)</strong> for updates.</p>';
832
+ });
746
833
  }
747
834
 
748
835
  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.7",
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"