@fias/plugin-dev-harness 1.4.0 → 1.4.2
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/cli/entities.d.ts.map +1 -1
- package/dist/cli/entities.js +1 -1
- package/dist/cli/entities.js.map +1 -1
- package/dist/cli/entities.test.js.map +1 -1
- package/dist/cli/login.test.js.map +1 -1
- package/dist/cli/submit.d.ts.map +1 -1
- package/dist/cli/submit.js +2 -2
- package/dist/cli/submit.js.map +1 -1
- package/dist/cli/submit.test.js.map +1 -1
- package/dist/cli/validate.test.js.map +1 -1
- package/dist/server/harness-server.d.ts.map +1 -1
- package/dist/server/harness-server.js +2 -2
- package/dist/server/harness-server.js.map +1 -1
- package/dist/server/harness-server.test.js +3 -3
- package/dist/server/harness-server.test.js.map +1 -1
- package/dist/server/static/harness.css +59 -1
- package/dist/server/static/harness.html +9 -5
- package/dist/server/static/harness.js +109 -39
- package/package.json +1 -1
- package/dist/server/static/static/harness.css +0 -390
- package/dist/server/static/static/harness.html +0 -57
- package/dist/server/static/static/harness.js +0 -603
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Fias Arche Dev — Client-side Bridge Host
|
|
3
3
|
*
|
|
4
|
-
* Ported from the production PluginBridgeHost
|
|
5
|
-
* (client/src/arche/components/PluginBridge.ts).
|
|
6
|
-
*
|
|
7
4
|
* Handles postMessage communication with the plugin iframe,
|
|
8
5
|
* enforcing permissions and rate limits, and proxying server-side
|
|
9
6
|
* operations through the harness Express server.
|
|
@@ -22,14 +19,17 @@
|
|
|
22
19
|
var pluginStatus = document.getElementById('plugin-status');
|
|
23
20
|
var themeBadge = document.getElementById('theme-badge');
|
|
24
21
|
var loginModal = document.getElementById('login-modal');
|
|
25
|
-
var
|
|
22
|
+
var loginEmail = document.getElementById('login-email');
|
|
23
|
+
var loginPassword = document.getElementById('login-password');
|
|
26
24
|
var loginError = document.getElementById('login-error');
|
|
27
25
|
var loginSubmit = document.getElementById('login-submit');
|
|
28
26
|
var loginCancel = document.getElementById('login-cancel');
|
|
27
|
+
var envSelector = document.getElementById('env-selector');
|
|
29
28
|
|
|
30
29
|
var messageCount = 0;
|
|
31
30
|
var currentTheme = 'dark';
|
|
32
31
|
var currentMode = 'mock';
|
|
32
|
+
var currentEnvironment = 'staging';
|
|
33
33
|
var hasCredentials = false;
|
|
34
34
|
var cachedConfig = null;
|
|
35
35
|
|
|
@@ -62,8 +62,10 @@
|
|
|
62
62
|
cachedConfig = config;
|
|
63
63
|
currentTheme = config.mockTheme || 'dark';
|
|
64
64
|
currentMode = config.mode || 'mock';
|
|
65
|
+
currentEnvironment = config.environment || 'staging';
|
|
65
66
|
hasCredentials = config.hasCredentials || false;
|
|
66
67
|
|
|
68
|
+
envSelector.value = currentEnvironment;
|
|
67
69
|
updateThemeBadge();
|
|
68
70
|
updateModeBadge();
|
|
69
71
|
|
|
@@ -72,7 +74,6 @@
|
|
|
72
74
|
fetchCredits();
|
|
73
75
|
}
|
|
74
76
|
|
|
75
|
-
// Check if plugin server is reachable, then load
|
|
76
77
|
checkPluginReachable(config.pluginUrl, function (reachable) {
|
|
77
78
|
if (reachable) {
|
|
78
79
|
pluginStatus.classList.add('hidden');
|
|
@@ -94,7 +95,6 @@
|
|
|
94
95
|
|
|
95
96
|
reloadBtn.addEventListener('click', function () {
|
|
96
97
|
if (cachedConfig) {
|
|
97
|
-
// Re-check reachability on reload
|
|
98
98
|
pluginStatus.classList.remove('hidden', 'error');
|
|
99
99
|
pluginStatus.innerHTML =
|
|
100
100
|
'<div class="status-spinner"></div><p>Connecting to plugin server...</p>';
|
|
@@ -124,10 +124,9 @@
|
|
|
124
124
|
logMessage('send', 'theme_update', { mode: currentTheme });
|
|
125
125
|
});
|
|
126
126
|
|
|
127
|
-
// Mode toggle
|
|
127
|
+
// Mode toggle
|
|
128
128
|
modeBadge.addEventListener('click', function () {
|
|
129
129
|
if (currentMode === 'mock') {
|
|
130
|
-
// Switching to live — need credentials
|
|
131
130
|
if (!hasCredentials) {
|
|
132
131
|
showLoginModal();
|
|
133
132
|
return;
|
|
@@ -138,6 +137,42 @@
|
|
|
138
137
|
}
|
|
139
138
|
});
|
|
140
139
|
|
|
140
|
+
// Environment selector
|
|
141
|
+
envSelector.addEventListener('change', function () {
|
|
142
|
+
fetch('/api/environment', {
|
|
143
|
+
method: 'POST',
|
|
144
|
+
headers: { 'Content-Type': 'application/json' },
|
|
145
|
+
body: JSON.stringify({ environment: envSelector.value }),
|
|
146
|
+
})
|
|
147
|
+
.then(function (r) {
|
|
148
|
+
return r.json();
|
|
149
|
+
})
|
|
150
|
+
.then(function (data) {
|
|
151
|
+
currentEnvironment = data.environment;
|
|
152
|
+
currentMode = data.mode;
|
|
153
|
+
hasCredentials = data.hasCredentials;
|
|
154
|
+
updateModeBadge();
|
|
155
|
+
|
|
156
|
+
if (currentMode === 'live') {
|
|
157
|
+
creditBalance.style.display = 'inline';
|
|
158
|
+
fetchCredits();
|
|
159
|
+
} else {
|
|
160
|
+
creditBalance.style.display = 'none';
|
|
161
|
+
creditBalance.textContent = '';
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
logMessage(
|
|
165
|
+
'info',
|
|
166
|
+
'Environment: ' +
|
|
167
|
+
currentEnvironment.toUpperCase() +
|
|
168
|
+
(hasCredentials ? '' : ' (not authenticated)'),
|
|
169
|
+
);
|
|
170
|
+
})
|
|
171
|
+
.catch(function (err) {
|
|
172
|
+
logMessage('error', err.message);
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
|
|
141
176
|
function switchMode(newMode) {
|
|
142
177
|
fetch('/api/mode', {
|
|
143
178
|
method: 'POST',
|
|
@@ -174,17 +209,21 @@
|
|
|
174
209
|
// Login Modal
|
|
175
210
|
// ────────────────────────────────────────────────────────────────
|
|
176
211
|
|
|
212
|
+
var loginTarget = document.getElementById('login-target');
|
|
213
|
+
|
|
177
214
|
function showLoginModal() {
|
|
178
215
|
loginModal.style.display = 'flex';
|
|
179
|
-
|
|
216
|
+
loginEmail.value = '';
|
|
217
|
+
loginPassword.value = '';
|
|
180
218
|
loginError.style.display = 'none';
|
|
181
|
-
|
|
219
|
+
loginSubmit.disabled = false;
|
|
220
|
+
loginSubmit.textContent = 'Sign in';
|
|
221
|
+
loginTarget.textContent = currentEnvironment === 'production' ? 'fias.io' : 'staging.fias.io';
|
|
222
|
+
loginEmail.focus();
|
|
182
223
|
}
|
|
183
224
|
|
|
184
225
|
function hideLoginModal() {
|
|
185
226
|
loginModal.style.display = 'none';
|
|
186
|
-
loginInput.value = '';
|
|
187
|
-
loginError.style.display = 'none';
|
|
188
227
|
}
|
|
189
228
|
|
|
190
229
|
loginCancel.addEventListener('click', hideLoginModal);
|
|
@@ -193,7 +232,12 @@
|
|
|
193
232
|
if (e.target === loginModal) hideLoginModal();
|
|
194
233
|
});
|
|
195
234
|
|
|
196
|
-
|
|
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) {
|
|
197
241
|
if (e.key === 'Enter') submitLogin();
|
|
198
242
|
if (e.key === 'Escape') hideLoginModal();
|
|
199
243
|
});
|
|
@@ -201,25 +245,28 @@
|
|
|
201
245
|
loginSubmit.addEventListener('click', submitLogin);
|
|
202
246
|
|
|
203
247
|
function submitLogin() {
|
|
204
|
-
var
|
|
205
|
-
|
|
206
|
-
|
|
248
|
+
var email = loginEmail.value.trim();
|
|
249
|
+
var password = loginPassword.value;
|
|
250
|
+
|
|
251
|
+
if (!email || !password) {
|
|
252
|
+
loginError.textContent = 'Email and password are required.';
|
|
207
253
|
loginError.style.display = 'block';
|
|
208
254
|
return;
|
|
209
255
|
}
|
|
210
256
|
|
|
211
257
|
loginSubmit.disabled = true;
|
|
212
|
-
loginSubmit.textContent = '
|
|
258
|
+
loginSubmit.textContent = 'Signing in...';
|
|
259
|
+
loginError.style.display = 'none';
|
|
213
260
|
|
|
214
|
-
fetch('/api/login', {
|
|
261
|
+
fetch('/api/auth/login', {
|
|
215
262
|
method: 'POST',
|
|
216
263
|
headers: { 'Content-Type': 'application/json' },
|
|
217
|
-
body: JSON.stringify({
|
|
264
|
+
body: JSON.stringify({ email: email, password: password }),
|
|
218
265
|
})
|
|
219
266
|
.then(function (r) {
|
|
220
267
|
if (!r.ok) {
|
|
221
268
|
return r.json().then(function (err) {
|
|
222
|
-
throw new Error(err.error || '
|
|
269
|
+
throw new Error(err.error || 'Sign in failed');
|
|
223
270
|
});
|
|
224
271
|
}
|
|
225
272
|
return r.json();
|
|
@@ -227,8 +274,7 @@
|
|
|
227
274
|
.then(function () {
|
|
228
275
|
hasCredentials = true;
|
|
229
276
|
hideLoginModal();
|
|
230
|
-
logMessage('info', '
|
|
231
|
-
// Automatically switch to live mode after login
|
|
277
|
+
logMessage('info', 'Signed in for ' + currentEnvironment.toUpperCase());
|
|
232
278
|
switchMode('live');
|
|
233
279
|
})
|
|
234
280
|
.catch(function (err) {
|
|
@@ -237,7 +283,7 @@
|
|
|
237
283
|
})
|
|
238
284
|
.finally(function () {
|
|
239
285
|
loginSubmit.disabled = false;
|
|
240
|
-
loginSubmit.textContent = '
|
|
286
|
+
loginSubmit.textContent = 'Sign in';
|
|
241
287
|
});
|
|
242
288
|
}
|
|
243
289
|
|
|
@@ -253,7 +299,6 @@
|
|
|
253
299
|
|
|
254
300
|
logMessage('recv', data.type, data.payload);
|
|
255
301
|
|
|
256
|
-
// Fire-and-forget messages
|
|
257
302
|
if (data.type === 'ready') return;
|
|
258
303
|
|
|
259
304
|
if (data.type === 'resize') {
|
|
@@ -281,19 +326,15 @@
|
|
|
281
326
|
return;
|
|
282
327
|
}
|
|
283
328
|
|
|
284
|
-
// Request/response messages — enforce permissions + rate limits, then proxy
|
|
285
329
|
handleRequest(data);
|
|
286
330
|
});
|
|
287
331
|
|
|
288
332
|
function handleRequest(data) {
|
|
289
333
|
try {
|
|
290
|
-
// Check permissions
|
|
291
334
|
var requiredPerm = PERMISSION_MAP[data.type];
|
|
292
335
|
if (requiredPerm && cachedConfig && cachedConfig.permissions.indexOf(requiredPerm) === -1) {
|
|
293
336
|
throw new Error('Permission denied: ' + requiredPerm + ' not granted');
|
|
294
337
|
}
|
|
295
|
-
|
|
296
|
-
// Check rate limit
|
|
297
338
|
checkRateLimit(data.type);
|
|
298
339
|
} catch (err) {
|
|
299
340
|
logMessage('error', err.message);
|
|
@@ -306,7 +347,6 @@
|
|
|
306
347
|
return;
|
|
307
348
|
}
|
|
308
349
|
|
|
309
|
-
// Proxy to harness server
|
|
310
350
|
fetch('/api/bridge', {
|
|
311
351
|
method: 'POST',
|
|
312
352
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -323,7 +363,6 @@
|
|
|
323
363
|
.then(function (result) {
|
|
324
364
|
logMessage('send', 'response', result);
|
|
325
365
|
|
|
326
|
-
// Show cost for entity invocations in live mode
|
|
327
366
|
if (
|
|
328
367
|
data.type === 'entity_invoke' &&
|
|
329
368
|
result.metadata &&
|
|
@@ -385,11 +424,26 @@
|
|
|
385
424
|
themeBadge.textContent = currentTheme.toUpperCase();
|
|
386
425
|
themeBadge.className = 'theme-badge theme-' + currentTheme;
|
|
387
426
|
document.body.style.background = currentTheme === 'light' ? '#ffffff' : '#0a0a0a';
|
|
427
|
+
|
|
428
|
+
// Update toolbar to match theme
|
|
429
|
+
var toolbar = document.querySelector('.toolbar');
|
|
430
|
+
var logo = document.querySelector('.logo');
|
|
431
|
+
var icons = document.querySelectorAll('.btn-icon');
|
|
432
|
+
var env = document.getElementById('env-selector');
|
|
433
|
+
if (currentTheme === 'light') {
|
|
434
|
+
if (toolbar) { toolbar.style.background = '#f5f5f5'; toolbar.style.borderBottomColor = '#e5e5e5'; }
|
|
435
|
+
if (logo) { logo.style.color = '#171717'; }
|
|
436
|
+
if (env) { env.style.background = '#e5e5e5'; env.style.color = '#171717'; env.style.borderColor = '#d4d4d4'; }
|
|
437
|
+
icons.forEach(function (btn) { btn.style.background = '#e5e5e5'; btn.style.color = '#171717'; btn.style.borderColor = '#d4d4d4'; });
|
|
438
|
+
} else {
|
|
439
|
+
if (toolbar) { toolbar.style.background = '#18181b'; toolbar.style.borderBottomColor = '#3f3f46'; }
|
|
440
|
+
if (logo) { logo.style.color = '#e4e4e7'; }
|
|
441
|
+
if (env) { env.style.background = '#27272a'; env.style.color = '#a1a1aa'; env.style.borderColor = '#3f3f46'; }
|
|
442
|
+
icons.forEach(function (btn) { btn.style.background = '#27272a'; btn.style.color = '#e4e4e7'; btn.style.borderColor = '#3f3f46'; });
|
|
443
|
+
}
|
|
388
444
|
}
|
|
389
445
|
|
|
390
446
|
function sendToPlugin(message) {
|
|
391
|
-
// targetOrigin '*' because the plugin may be on a different port.
|
|
392
|
-
// Security is enforced by checking event.source on incoming messages.
|
|
393
447
|
iframe.contentWindow && iframe.contentWindow.postMessage(message, '*');
|
|
394
448
|
}
|
|
395
449
|
|
|
@@ -419,32 +473,51 @@
|
|
|
419
473
|
var SPACING = { xs: '4px', sm: '8px', md: '16px', lg: '24px', xl: '32px' };
|
|
420
474
|
var FONTS = { body: SYSTEM_FONTS, heading: SYSTEM_FONTS, mono: MONO_FONTS };
|
|
421
475
|
|
|
476
|
+
var COMPONENTS = {
|
|
477
|
+
borderRadius: '0.5rem',
|
|
478
|
+
buttonRadius: '0.375rem',
|
|
479
|
+
cardRadius: '0.5rem',
|
|
480
|
+
inputRadius: '0.375rem',
|
|
481
|
+
shadowSm: '0 1px 2px 0 rgba(0, 0, 0, 0.05)',
|
|
482
|
+
shadowMd: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)',
|
|
483
|
+
shadowLg: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1)',
|
|
484
|
+
borderWidth: '1px',
|
|
485
|
+
};
|
|
486
|
+
|
|
422
487
|
function getTheme() {
|
|
423
488
|
if (currentTheme === 'light') {
|
|
424
489
|
return {
|
|
425
490
|
mode: 'light',
|
|
426
491
|
colors: {
|
|
427
|
-
primary: '#171717',
|
|
492
|
+
primary: '#171717', primaryText: '#ffffff',
|
|
493
|
+
secondary: '#e5e5e5', accent: '#2563eb',
|
|
428
494
|
background: '#ffffff', surface: '#fafafa',
|
|
495
|
+
card: '#ffffff', cardText: '#0a0a0a',
|
|
429
496
|
text: '#0a0a0a', textSecondary: '#737373',
|
|
497
|
+
muted: '#f5f5f5', mutedText: '#a3a3a3',
|
|
430
498
|
border: '#e5e5e5',
|
|
431
|
-
error: '#dc2626', warning: '#d97706', success: '#16a34a',
|
|
499
|
+
error: '#dc2626', warning: '#d97706', success: '#16a34a', info: '#2563eb',
|
|
432
500
|
},
|
|
433
501
|
spacing: SPACING,
|
|
434
502
|
fonts: FONTS,
|
|
503
|
+
components: COMPONENTS,
|
|
435
504
|
};
|
|
436
505
|
}
|
|
437
506
|
return {
|
|
438
507
|
mode: 'dark',
|
|
439
508
|
colors: {
|
|
440
|
-
primary: '#ffffff',
|
|
509
|
+
primary: '#ffffff', primaryText: '#0a0a0a',
|
|
510
|
+
secondary: '#1f1f1f', accent: '#3b82f6',
|
|
441
511
|
background: '#0a0a0a', surface: '#171717',
|
|
512
|
+
card: '#141414', cardText: '#ffffff',
|
|
442
513
|
text: '#ffffff', textSecondary: '#a6a6a6',
|
|
514
|
+
muted: '#1e1e1e', mutedText: '#737373',
|
|
443
515
|
border: '#2e2e2e',
|
|
444
|
-
error: '#ef4444', warning: '#f59e0b', success: '#22c55e',
|
|
516
|
+
error: '#ef4444', warning: '#f59e0b', success: '#22c55e', info: '#3b82f6',
|
|
445
517
|
},
|
|
446
518
|
spacing: SPACING,
|
|
447
519
|
fonts: FONTS,
|
|
520
|
+
components: COMPONENTS,
|
|
448
521
|
};
|
|
449
522
|
}
|
|
450
523
|
|
|
@@ -510,7 +583,6 @@
|
|
|
510
583
|
function checkPluginReachable(url, callback) {
|
|
511
584
|
var done = false;
|
|
512
585
|
|
|
513
|
-
// Try fetching through the harness server to avoid CORS issues
|
|
514
586
|
fetch('/api/check-plugin')
|
|
515
587
|
.then(function (r) { return r.json(); })
|
|
516
588
|
.then(function (data) {
|
|
@@ -522,12 +594,10 @@
|
|
|
522
594
|
.catch(function () {
|
|
523
595
|
if (!done) {
|
|
524
596
|
done = true;
|
|
525
|
-
// If the check endpoint doesn't exist, assume reachable and let iframe handle it
|
|
526
597
|
callback(true);
|
|
527
598
|
}
|
|
528
599
|
});
|
|
529
600
|
|
|
530
|
-
// Timeout after 5 seconds
|
|
531
601
|
setTimeout(function () {
|
|
532
602
|
if (!done) {
|
|
533
603
|
done = true;
|