@fias/plugin-dev-harness 1.2.0 → 1.3.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 (52) hide show
  1. package/dist/cli/check-auth.d.ts +3 -3
  2. package/dist/cli/check-auth.d.ts.map +1 -1
  3. package/dist/cli/check-auth.js +19 -8
  4. package/dist/cli/check-auth.js.map +1 -1
  5. package/dist/cli/check-auth.test.d.ts +2 -0
  6. package/dist/cli/check-auth.test.d.ts.map +1 -0
  7. package/dist/cli/check-auth.test.js +49 -0
  8. package/dist/cli/check-auth.test.js.map +1 -0
  9. package/dist/cli/dev.d.ts +2 -2
  10. package/dist/cli/dev.d.ts.map +1 -1
  11. package/dist/cli/dev.js +4 -20
  12. package/dist/cli/dev.js.map +1 -1
  13. package/dist/cli/dev.test.js +10 -38
  14. package/dist/cli/dev.test.js.map +1 -1
  15. package/dist/cli/entities.d.ts.map +1 -1
  16. package/dist/cli/entities.js +8 -6
  17. package/dist/cli/entities.js.map +1 -1
  18. package/dist/cli/entities.test.js +15 -24
  19. package/dist/cli/entities.test.js.map +1 -1
  20. package/dist/cli/index.test.js +2 -2
  21. package/dist/cli/login.d.ts +2 -0
  22. package/dist/cli/login.d.ts.map +1 -1
  23. package/dist/cli/login.js +19 -14
  24. package/dist/cli/login.js.map +1 -1
  25. package/dist/cli/login.test.js +46 -24
  26. package/dist/cli/login.test.js.map +1 -1
  27. package/dist/cli/submit.d.ts.map +1 -1
  28. package/dist/cli/submit.js +13 -11
  29. package/dist/cli/submit.js.map +1 -1
  30. package/dist/cli/submit.test.js +13 -22
  31. package/dist/cli/submit.test.js.map +1 -1
  32. package/dist/config/config-loader.d.ts +6 -0
  33. package/dist/config/config-loader.d.ts.map +1 -1
  34. package/dist/config/config-loader.js +12 -0
  35. package/dist/config/config-loader.js.map +1 -1
  36. package/dist/config/credentials.d.ts +19 -1
  37. package/dist/config/credentials.d.ts.map +1 -1
  38. package/dist/config/credentials.js +46 -6
  39. package/dist/config/credentials.js.map +1 -1
  40. package/dist/config/credentials.test.js +72 -27
  41. package/dist/config/credentials.test.js.map +1 -1
  42. package/dist/index.js +0 -0
  43. package/dist/server/harness-server.d.ts +2 -3
  44. package/dist/server/harness-server.d.ts.map +1 -1
  45. package/dist/server/harness-server.js +233 -41
  46. package/dist/server/harness-server.js.map +1 -1
  47. package/dist/server/harness-server.test.js +60 -3
  48. package/dist/server/harness-server.test.js.map +1 -1
  49. package/dist/server/static/static/harness.css +58 -0
  50. package/dist/server/static/static/harness.html +20 -7
  51. package/dist/server/static/static/harness.js +139 -2
  52. package/package.json +10 -10
@@ -37,6 +37,28 @@ body {
37
37
  color: #a78bfa;
38
38
  }
39
39
 
40
+ /* Environment selector */
41
+ .env-selector {
42
+ background: #27272a;
43
+ color: #a1a1aa;
44
+ border: 1px solid #3f3f46;
45
+ border-radius: 4px;
46
+ padding: 3px 8px;
47
+ font-size: 11px;
48
+ font-weight: 600;
49
+ cursor: pointer;
50
+ outline: none;
51
+ text-transform: uppercase;
52
+ }
53
+
54
+ .env-selector:hover {
55
+ border-color: #52525b;
56
+ }
57
+
58
+ .env-selector:focus {
59
+ border-color: #a78bfa;
60
+ }
61
+
40
62
  .mode-badge {
41
63
  padding: 3px 10px;
42
64
  border-radius: 4px;
@@ -193,6 +215,12 @@ body {
193
215
  cursor: not-allowed;
194
216
  }
195
217
 
218
+ .btn-full {
219
+ width: 100%;
220
+ padding: 10px 16px;
221
+ margin-bottom: 12px;
222
+ }
223
+
196
224
  .btn-secondary {
197
225
  background: transparent;
198
226
  color: #a1a1aa;
@@ -207,6 +235,36 @@ body {
207
235
  background: #3f3f46;
208
236
  }
209
237
 
238
+ .btn-link {
239
+ background: none;
240
+ border: none;
241
+ color: #a78bfa;
242
+ cursor: pointer;
243
+ font-size: 12px;
244
+ padding: 0;
245
+ }
246
+
247
+ .btn-link:hover {
248
+ text-decoration: underline;
249
+ }
250
+
251
+ .modal-divider {
252
+ display: flex;
253
+ align-items: center;
254
+ gap: 12px;
255
+ margin: 12px 0;
256
+ color: #6b7280;
257
+ font-size: 12px;
258
+ }
259
+
260
+ .modal-divider::before,
261
+ .modal-divider::after {
262
+ content: '';
263
+ flex: 1;
264
+ height: 1px;
265
+ background: #3f3f46;
266
+ }
267
+
210
268
  /* Plugin status overlay */
211
269
  .plugin-status {
212
270
  flex: 1;
@@ -10,6 +10,10 @@
10
10
  <div class="toolbar">
11
11
  <div class="toolbar-left">
12
12
  <span class="logo">Fias Arche Dev</span>
13
+ <select id="env-selector" class="env-selector">
14
+ <option value="staging">STAGING</option>
15
+ <option value="production">PRODUCTION</option>
16
+ </select>
13
17
  <button id="mode-badge" class="mode-badge mode-mock" title="Click to switch mode">MOCK &#8646;</button>
14
18
  </div>
15
19
  <div class="toolbar-right">
@@ -23,14 +27,23 @@
23
27
  <div id="login-modal" class="modal-overlay" style="display: none">
24
28
  <div class="modal">
25
29
  <h3>Connect to FIAS</h3>
26
- <p>Enter your API key to enable live mode with real AI responses.</p>
27
- <p class="modal-hint">Get an API key from your FIAS platform account settings.</p>
28
- <input id="login-input" type="password" class="modal-input" placeholder="fias_sk_..." autocomplete="off" />
29
- <div id="login-error" class="modal-error" style="display: none"></div>
30
- <div class="modal-actions">
31
- <button id="login-cancel" class="btn-secondary">Cancel</button>
32
- <button id="login-submit" class="btn-primary">Save &amp; Connect</button>
30
+ <p>Sign in to your FIAS account to enable live mode with real AI responses.</p>
31
+ <div id="login-popup-section">
32
+ <button id="login-popup-btn" class="btn-primary btn-full">Sign in with FIAS</button>
33
+ <p id="login-popup-hint" class="modal-hint" style="display:none">
34
+ Popup blocked? <a id="login-popup-link" href="#" target="_blank" style="color:#a78bfa">Open login page manually</a>
35
+ </p>
36
+ <div class="modal-divider"><span>or</span></div>
37
+ <button id="login-manual-toggle" class="btn-link">Enter API key manually</button>
38
+ </div>
39
+ <div id="login-manual-section" style="display:none">
40
+ <input id="login-input" type="password" class="modal-input" placeholder="fias_sk_..." autocomplete="off" />
41
+ <div class="modal-actions">
42
+ <button id="login-cancel" class="btn-secondary">Cancel</button>
43
+ <button id="login-submit" class="btn-primary">Save &amp; Connect</button>
44
+ </div>
33
45
  </div>
46
+ <div id="login-error" class="modal-error" style="display: none"></div>
34
47
  </div>
35
48
  </div>
36
49
  <div id="plugin-status" class="plugin-status">
@@ -26,12 +26,21 @@
26
26
  var loginError = document.getElementById('login-error');
27
27
  var loginSubmit = document.getElementById('login-submit');
28
28
  var loginCancel = document.getElementById('login-cancel');
29
+ var envSelector = document.getElementById('env-selector');
30
+ var loginPopupBtn = document.getElementById('login-popup-btn');
31
+ var loginPopupHint = document.getElementById('login-popup-hint');
32
+ var loginPopupLink = document.getElementById('login-popup-link');
33
+ var loginManualToggle = document.getElementById('login-manual-toggle');
34
+ var loginManualSection = document.getElementById('login-manual-section');
35
+ var loginPopupSection = document.getElementById('login-popup-section');
29
36
 
30
37
  var messageCount = 0;
31
38
  var currentTheme = 'dark';
32
39
  var currentMode = 'mock';
40
+ var currentEnvironment = 'staging';
33
41
  var hasCredentials = false;
34
42
  var cachedConfig = null;
43
+ var authPollInterval = null;
35
44
 
36
45
  /** Permission requirements per bridge call type (matches production) */
37
46
  var PERMISSION_MAP = {
@@ -62,8 +71,10 @@
62
71
  cachedConfig = config;
63
72
  currentTheme = config.mockTheme || 'dark';
64
73
  currentMode = config.mode || 'mock';
74
+ currentEnvironment = config.environment || 'staging';
65
75
  hasCredentials = config.hasCredentials || false;
66
76
 
77
+ envSelector.value = currentEnvironment;
67
78
  updateThemeBadge();
68
79
  updateModeBadge();
69
80
 
@@ -138,6 +149,42 @@
138
149
  }
139
150
  });
140
151
 
152
+ // Environment selector
153
+ envSelector.addEventListener('change', function () {
154
+ fetch('/api/environment', {
155
+ method: 'POST',
156
+ headers: { 'Content-Type': 'application/json' },
157
+ body: JSON.stringify({ environment: envSelector.value }),
158
+ })
159
+ .then(function (r) {
160
+ return r.json();
161
+ })
162
+ .then(function (data) {
163
+ currentEnvironment = data.environment;
164
+ currentMode = data.mode;
165
+ hasCredentials = data.hasCredentials;
166
+ updateModeBadge();
167
+
168
+ if (currentMode === 'live') {
169
+ creditBalance.style.display = 'inline';
170
+ fetchCredits();
171
+ } else {
172
+ creditBalance.style.display = 'none';
173
+ creditBalance.textContent = '';
174
+ }
175
+
176
+ logMessage(
177
+ 'info',
178
+ 'Environment: ' +
179
+ currentEnvironment.toUpperCase() +
180
+ (hasCredentials ? '' : ' (not authenticated)'),
181
+ );
182
+ })
183
+ .catch(function (err) {
184
+ logMessage('error', err.message);
185
+ });
186
+ });
187
+
141
188
  function switchMode(newMode) {
142
189
  fetch('/api/mode', {
143
190
  method: 'POST',
@@ -176,15 +223,19 @@
176
223
 
177
224
  function showLoginModal() {
178
225
  loginModal.style.display = 'flex';
179
- loginInput.value = '';
226
+ loginPopupSection.style.display = 'block';
227
+ loginManualSection.style.display = 'none';
228
+ loginPopupHint.style.display = 'none';
180
229
  loginError.style.display = 'none';
181
- loginInput.focus();
230
+ loginPopupBtn.disabled = false;
231
+ loginPopupBtn.textContent = 'Sign in with FIAS';
182
232
  }
183
233
 
184
234
  function hideLoginModal() {
185
235
  loginModal.style.display = 'none';
186
236
  loginInput.value = '';
187
237
  loginError.style.display = 'none';
238
+ stopAuthPolling();
188
239
  }
189
240
 
190
241
  loginCancel.addEventListener('click', hideLoginModal);
@@ -193,6 +244,13 @@
193
244
  if (e.target === loginModal) hideLoginModal();
194
245
  });
195
246
 
247
+ // Toggle to manual key entry
248
+ loginManualToggle.addEventListener('click', function () {
249
+ loginPopupSection.style.display = 'none';
250
+ loginManualSection.style.display = 'block';
251
+ loginInput.focus();
252
+ });
253
+
196
254
  loginInput.addEventListener('keydown', function (e) {
197
255
  if (e.key === 'Enter') submitLogin();
198
256
  if (e.key === 'Escape') hideLoginModal();
@@ -200,6 +258,39 @@
200
258
 
201
259
  loginSubmit.addEventListener('click', submitLogin);
202
260
 
261
+ // Popup-based login
262
+ loginPopupBtn.addEventListener('click', function () {
263
+ loginPopupBtn.disabled = true;
264
+ loginPopupBtn.textContent = 'Opening...';
265
+
266
+ fetch('/api/auth/start', { method: 'POST' })
267
+ .then(function (r) {
268
+ return r.json();
269
+ })
270
+ .then(function (data) {
271
+ var popup = window.open(data.authUrl, 'fias-auth', 'width=500,height=650');
272
+
273
+ if (!popup || popup.closed) {
274
+ // Popup was blocked — show fallback link
275
+ loginPopupHint.style.display = 'block';
276
+ loginPopupLink.href = data.authUrl;
277
+ loginPopupBtn.disabled = false;
278
+ loginPopupBtn.textContent = 'Sign in with FIAS';
279
+ } else {
280
+ loginPopupBtn.textContent = 'Waiting for sign-in...';
281
+ }
282
+
283
+ // Start polling as fallback (works even if popup can't postMessage)
284
+ startAuthPolling();
285
+ })
286
+ .catch(function (err) {
287
+ loginError.textContent = err.message;
288
+ loginError.style.display = 'block';
289
+ loginPopupBtn.disabled = false;
290
+ loginPopupBtn.textContent = 'Sign in with FIAS';
291
+ });
292
+ });
293
+
203
294
  function submitLogin() {
204
295
  var apiKey = loginInput.value.trim();
205
296
  if (!apiKey) {
@@ -241,11 +332,57 @@
241
332
  });
242
333
  }
243
334
 
335
+ // Auth polling — fallback for popup blocked or postMessage unavailable
336
+ function startAuthPolling() {
337
+ if (authPollInterval) return;
338
+ authPollInterval = setInterval(function () {
339
+ fetch('/api/config')
340
+ .then(function (r) {
341
+ return r.json();
342
+ })
343
+ .then(function (config) {
344
+ if (config.hasCredentials && !hasCredentials) {
345
+ hasCredentials = true;
346
+ stopAuthPolling();
347
+ hideLoginModal();
348
+ logMessage('info', 'Authenticated for ' + currentEnvironment.toUpperCase());
349
+ switchMode('live');
350
+ }
351
+ })
352
+ .catch(function () {});
353
+ }, 2000);
354
+ }
355
+
356
+ function stopAuthPolling() {
357
+ if (authPollInterval) {
358
+ clearInterval(authPollInterval);
359
+ authPollInterval = null;
360
+ }
361
+ }
362
+
244
363
  // ────────────────────────────────────────────────────────────────
245
364
  // Message Handling
246
365
  // ────────────────────────────────────────────────────────────────
247
366
 
248
367
  window.addEventListener('message', function (event) {
368
+ // Handle auth callback from popup
369
+ if (event.data && event.data.type === 'auth_callback') {
370
+ stopAuthPolling();
371
+ if (event.data.success) {
372
+ hasCredentials = true;
373
+ hideLoginModal();
374
+ logMessage('info', 'Authenticated for ' + currentEnvironment.toUpperCase());
375
+ switchMode('live');
376
+ } else {
377
+ loginError.textContent = event.data.error || 'Authentication failed';
378
+ loginError.style.display = 'block';
379
+ }
380
+ loginPopupBtn.disabled = false;
381
+ loginPopupBtn.textContent = 'Sign in with FIAS';
382
+ return;
383
+ }
384
+
385
+ // Handle plugin iframe messages
249
386
  if (event.source !== iframe.contentWindow) return;
250
387
 
251
388
  var data = event.data;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fias/plugin-dev-harness",
3
- "version": "1.2.0",
3
+ "version": "1.3.1",
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",
@@ -15,6 +15,12 @@
15
15
  "publishConfig": {
16
16
  "access": "public"
17
17
  },
18
+ "scripts": {
19
+ "build": "tsc && cp -r src/server/static dist/server/static",
20
+ "clean": "rm -rf dist",
21
+ "watch": "tsc -w",
22
+ "typecheck": "tsc --noEmit"
23
+ },
18
24
  "keywords": [
19
25
  "fias",
20
26
  "plugin",
@@ -24,20 +30,14 @@
24
30
  ],
25
31
  "license": "MIT",
26
32
  "dependencies": {
33
+ "@fias/arche-sdk": "^1.0.0",
27
34
  "chalk": "^4.1.2",
28
35
  "commander": "^12.0.0",
29
- "express": "^4.21.0",
30
- "@fias/arche-sdk": "1.2.1"
36
+ "express": "^4.21.0"
31
37
  },
32
38
  "devDependencies": {
33
39
  "@types/express": "^5.0.0",
34
40
  "@types/node": "^25.5.0",
35
41
  "typescript": "^5.3.3"
36
- },
37
- "scripts": {
38
- "build": "tsc && cp -r src/server/static dist/server/static",
39
- "clean": "rm -rf dist",
40
- "watch": "tsc -w",
41
- "typecheck": "tsc --noEmit"
42
42
  }
43
- }
43
+ }