@fias/plugin-dev-harness 1.1.0

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 (125) hide show
  1. package/dist/bridge/live-handler.d.ts +27 -0
  2. package/dist/bridge/live-handler.d.ts.map +1 -0
  3. package/dist/bridge/live-handler.js +47 -0
  4. package/dist/bridge/live-handler.js.map +1 -0
  5. package/dist/bridge/live-handler.test.d.ts +2 -0
  6. package/dist/bridge/live-handler.test.d.ts.map +1 -0
  7. package/dist/bridge/live-handler.test.js +182 -0
  8. package/dist/bridge/live-handler.test.js.map +1 -0
  9. package/dist/bridge/mock-handler.d.ts +25 -0
  10. package/dist/bridge/mock-handler.d.ts.map +1 -0
  11. package/dist/bridge/mock-handler.js +81 -0
  12. package/dist/bridge/mock-handler.js.map +1 -0
  13. package/dist/bridge/mock-handler.test.d.ts +2 -0
  14. package/dist/bridge/mock-handler.test.d.ts.map +1 -0
  15. package/dist/bridge/mock-handler.test.js +322 -0
  16. package/dist/bridge/mock-handler.test.js.map +1 -0
  17. package/dist/bridge/types.d.ts +18 -0
  18. package/dist/bridge/types.d.ts.map +1 -0
  19. package/dist/bridge/types.js +8 -0
  20. package/dist/bridge/types.js.map +1 -0
  21. package/dist/cli/dev.d.ts +15 -0
  22. package/dist/cli/dev.d.ts.map +1 -0
  23. package/dist/cli/dev.js +64 -0
  24. package/dist/cli/dev.js.map +1 -0
  25. package/dist/cli/dev.test.d.ts +2 -0
  26. package/dist/cli/dev.test.d.ts.map +1 -0
  27. package/dist/cli/dev.test.js +114 -0
  28. package/dist/cli/dev.test.js.map +1 -0
  29. package/dist/cli/entities.d.ts +9 -0
  30. package/dist/cli/entities.d.ts.map +1 -0
  31. package/dist/cli/entities.js +71 -0
  32. package/dist/cli/entities.js.map +1 -0
  33. package/dist/cli/entities.test.d.ts +2 -0
  34. package/dist/cli/entities.test.d.ts.map +1 -0
  35. package/dist/cli/entities.test.js +179 -0
  36. package/dist/cli/entities.test.js.map +1 -0
  37. package/dist/cli/index.d.ts +9 -0
  38. package/dist/cli/index.d.ts.map +1 -0
  39. package/dist/cli/index.js +29 -0
  40. package/dist/cli/index.js.map +1 -0
  41. package/dist/cli/index.test.d.ts +2 -0
  42. package/dist/cli/index.test.d.ts.map +1 -0
  43. package/dist/cli/index.test.js +55 -0
  44. package/dist/cli/index.test.js.map +1 -0
  45. package/dist/cli/login.d.ts +9 -0
  46. package/dist/cli/login.d.ts.map +1 -0
  47. package/dist/cli/login.js +80 -0
  48. package/dist/cli/login.js.map +1 -0
  49. package/dist/cli/login.test.d.ts +2 -0
  50. package/dist/cli/login.test.d.ts.map +1 -0
  51. package/dist/cli/login.test.js +53 -0
  52. package/dist/cli/login.test.js.map +1 -0
  53. package/dist/cli/submit.d.ts +9 -0
  54. package/dist/cli/submit.d.ts.map +1 -0
  55. package/dist/cli/submit.js +250 -0
  56. package/dist/cli/submit.js.map +1 -0
  57. package/dist/cli/submit.test.d.ts +2 -0
  58. package/dist/cli/submit.test.d.ts.map +1 -0
  59. package/dist/cli/submit.test.js +381 -0
  60. package/dist/cli/submit.test.js.map +1 -0
  61. package/dist/cli/validate.d.ts +9 -0
  62. package/dist/cli/validate.d.ts.map +1 -0
  63. package/dist/cli/validate.js +154 -0
  64. package/dist/cli/validate.js.map +1 -0
  65. package/dist/cli/validate.test.d.ts +2 -0
  66. package/dist/cli/validate.test.d.ts.map +1 -0
  67. package/dist/cli/validate.test.js +275 -0
  68. package/dist/cli/validate.test.js.map +1 -0
  69. package/dist/config/config-loader.d.ts +25 -0
  70. package/dist/config/config-loader.d.ts.map +1 -0
  71. package/dist/config/config-loader.js +78 -0
  72. package/dist/config/config-loader.js.map +1 -0
  73. package/dist/config/config-loader.test.d.ts +2 -0
  74. package/dist/config/config-loader.test.d.ts.map +1 -0
  75. package/dist/config/config-loader.test.js +163 -0
  76. package/dist/config/config-loader.test.js.map +1 -0
  77. package/dist/config/credentials.d.ts +11 -0
  78. package/dist/config/credentials.d.ts.map +1 -0
  79. package/dist/config/credentials.js +71 -0
  80. package/dist/config/credentials.js.map +1 -0
  81. package/dist/config/credentials.test.d.ts +2 -0
  82. package/dist/config/credentials.test.d.ts.map +1 -0
  83. package/dist/config/credentials.test.js +115 -0
  84. package/dist/config/credentials.test.js.map +1 -0
  85. package/dist/index.d.ts +9 -0
  86. package/dist/index.d.ts.map +1 -0
  87. package/dist/index.js +12 -0
  88. package/dist/index.js.map +1 -0
  89. package/dist/mocks/entity-responses.d.ts +15 -0
  90. package/dist/mocks/entity-responses.d.ts.map +1 -0
  91. package/dist/mocks/entity-responses.js +21 -0
  92. package/dist/mocks/entity-responses.js.map +1 -0
  93. package/dist/mocks/entity-responses.test.d.ts +2 -0
  94. package/dist/mocks/entity-responses.test.d.ts.map +1 -0
  95. package/dist/mocks/entity-responses.test.js +53 -0
  96. package/dist/mocks/entity-responses.test.js.map +1 -0
  97. package/dist/mocks/theme.d.ts +22 -0
  98. package/dist/mocks/theme.d.ts.map +1 -0
  99. package/dist/mocks/theme.js +37 -0
  100. package/dist/mocks/theme.js.map +1 -0
  101. package/dist/mocks/theme.test.d.ts +2 -0
  102. package/dist/mocks/theme.test.d.ts.map +1 -0
  103. package/dist/mocks/theme.test.js +66 -0
  104. package/dist/mocks/theme.test.js.map +1 -0
  105. package/dist/mocks/user.d.ts +12 -0
  106. package/dist/mocks/user.d.ts.map +1 -0
  107. package/dist/mocks/user.js +14 -0
  108. package/dist/mocks/user.js.map +1 -0
  109. package/dist/mocks/user.test.d.ts +2 -0
  110. package/dist/mocks/user.test.d.ts.map +1 -0
  111. package/dist/mocks/user.test.js +23 -0
  112. package/dist/mocks/user.test.js.map +1 -0
  113. package/dist/server/harness-server.d.ts +24 -0
  114. package/dist/server/harness-server.d.ts.map +1 -0
  115. package/dist/server/harness-server.js +433 -0
  116. package/dist/server/harness-server.js.map +1 -0
  117. package/dist/server/harness-server.test.d.ts +2 -0
  118. package/dist/server/harness-server.test.d.ts.map +1 -0
  119. package/dist/server/harness-server.test.js +178 -0
  120. package/dist/server/harness-server.test.js.map +1 -0
  121. package/dist/server/static/harness.css +160 -0
  122. package/dist/server/static/harness.html +35 -0
  123. package/dist/server/static/harness.js +345 -0
  124. package/package.json +43 -0
  125. package/templates/fias-dev.config.json +12 -0
@@ -0,0 +1,178 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const fs = __importStar(require("fs"));
37
+ jest.mock('fs');
38
+ const mockedFs = jest.mocked(fs);
39
+ const harness_server_1 = require("./harness-server");
40
+ // We need to test the server by actually starting it and making HTTP requests
41
+ // to avoid coupling to Express internals.
42
+ const http = require('http');
43
+ function httpGet(port, path) {
44
+ return new Promise((resolve, reject) => {
45
+ http
46
+ .get(`http://127.0.0.1:${port}${path}`, (res) => {
47
+ let data = '';
48
+ res.on('data', (chunk) => (data += chunk));
49
+ res.on('end', () => resolve({ status: res.statusCode, body: data }));
50
+ })
51
+ .on('error', reject);
52
+ });
53
+ }
54
+ function httpPost(port, path, body) {
55
+ return new Promise((resolve, reject) => {
56
+ const payload = JSON.stringify(body);
57
+ const req = http.request({
58
+ hostname: '127.0.0.1',
59
+ port,
60
+ path,
61
+ method: 'POST',
62
+ headers: {
63
+ 'Content-Type': 'application/json',
64
+ 'Content-Length': Buffer.byteLength(payload),
65
+ },
66
+ }, (res) => {
67
+ let data = '';
68
+ res.on('data', (chunk) => (data += chunk));
69
+ res.on('end', () => resolve({ status: res.statusCode, body: data }));
70
+ });
71
+ req.on('error', reject);
72
+ req.write(payload);
73
+ req.end();
74
+ });
75
+ }
76
+ describe('server/harness-server', () => {
77
+ // Use a random high port to avoid conflicts
78
+ const testPort = 19321 + Math.floor(Math.random() * 100);
79
+ let consoleSpy;
80
+ const defaultOptions = {
81
+ port: testPort,
82
+ pluginUrl: 'http://localhost:3100',
83
+ isLive: false,
84
+ apiKey: '',
85
+ apiUrl: 'https://api.fias.app/v1',
86
+ permissions: ['theme:read', 'entities:invoke'],
87
+ mockUser: { userId: 'dev_user_001', displayName: 'Dev User', avatar: null },
88
+ mockTheme: 'dark',
89
+ };
90
+ beforeAll(async () => {
91
+ consoleSpy = jest.spyOn(console, 'log').mockImplementation(() => { });
92
+ // Make fs.existsSync return false for static dirs so the server uses fallback HTML
93
+ mockedFs.existsSync.mockReturnValue(false);
94
+ await (0, harness_server_1.startHarnessServer)(defaultOptions);
95
+ // Small delay to ensure server is fully ready
96
+ await new Promise((resolve) => setTimeout(resolve, 100));
97
+ });
98
+ afterAll(() => {
99
+ consoleSpy.mockRestore();
100
+ });
101
+ describe('GET /api/config', () => {
102
+ it('returns plugin config as JSON', async () => {
103
+ const resp = await httpGet(testPort, '/api/config');
104
+ expect(resp.status).toBe(200);
105
+ const data = JSON.parse(resp.body);
106
+ expect(data.pluginUrl).toBe('http://localhost:3100');
107
+ expect(data.isLive).toBe(false);
108
+ expect(data.permissions).toEqual(['theme:read', 'entities:invoke']);
109
+ expect(data.mockTheme).toBe('dark');
110
+ });
111
+ });
112
+ describe('GET /api/credits', () => {
113
+ it('returns Infinity balance in mock mode', async () => {
114
+ const resp = await httpGet(testPort, '/api/credits');
115
+ expect(resp.status).toBe(200);
116
+ const data = JSON.parse(resp.body);
117
+ expect(data.balance).toBe(null); // Infinity serializes as null in JSON
118
+ expect(data.lifetimeUsed).toBe(0);
119
+ expect(data.lifetimeGranted).toBe(0);
120
+ });
121
+ });
122
+ describe('POST /api/bridge', () => {
123
+ it('handles get_user request', async () => {
124
+ const resp = await httpPost(testPort, '/api/bridge', {
125
+ type: 'get_user',
126
+ payload: {},
127
+ });
128
+ expect(resp.status).toBe(200);
129
+ const data = JSON.parse(resp.body);
130
+ expect(data.userId).toBe('dev_user_001');
131
+ expect(data.displayName).toBe('Dev User');
132
+ });
133
+ it('handles get_theme request', async () => {
134
+ const resp = await httpPost(testPort, '/api/bridge', {
135
+ type: 'get_theme',
136
+ payload: {},
137
+ });
138
+ expect(resp.status).toBe(200);
139
+ const data = JSON.parse(resp.body);
140
+ expect(data.mode).toBe('dark');
141
+ expect(data.colors).toBeDefined();
142
+ });
143
+ it('handles storage_write and storage_read', async () => {
144
+ const writeResp = await httpPost(testPort, '/api/bridge', {
145
+ type: 'storage_write',
146
+ payload: { path: 'test.txt', content: 'Hello Server' },
147
+ });
148
+ expect(writeResp.status).toBe(200);
149
+ const readResp = await httpPost(testPort, '/api/bridge', {
150
+ type: 'storage_read',
151
+ payload: { path: 'test.txt' },
152
+ });
153
+ expect(readResp.status).toBe(200);
154
+ const readData = JSON.parse(readResp.body);
155
+ expect(readData.exists).toBe(true);
156
+ expect(readData.content).toBe('Hello Server');
157
+ });
158
+ it('returns 400 for unknown bridge call type', async () => {
159
+ const resp = await httpPost(testPort, '/api/bridge', {
160
+ type: 'invalid_type',
161
+ payload: {},
162
+ });
163
+ expect(resp.status).toBe(400);
164
+ const data = JSON.parse(resp.body);
165
+ expect(data.error).toContain('Unknown bridge call type');
166
+ });
167
+ });
168
+ describe('GET /', () => {
169
+ it('serves fallback HTML when static files are not found', async () => {
170
+ const resp = await httpGet(testPort, '/');
171
+ expect(resp.status).toBe(200);
172
+ expect(resp.body).toContain('FIAS Dev Harness');
173
+ expect(resp.body).toContain('<!DOCTYPE html>');
174
+ expect(resp.body).toContain('MOCK');
175
+ });
176
+ });
177
+ });
178
+ //# sourceMappingURL=harness-server.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harness-server.test.js","sourceRoot":"","sources":["../../src/server/harness-server.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,160 @@
1
+ * {
2
+ margin: 0;
3
+ padding: 0;
4
+ box-sizing: border-box;
5
+ }
6
+
7
+ body {
8
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
9
+ background: #0a0a0f;
10
+ color: #e4e4e7;
11
+ display: flex;
12
+ flex-direction: column;
13
+ height: 100vh;
14
+ }
15
+
16
+ /* Toolbar */
17
+ .toolbar {
18
+ display: flex;
19
+ justify-content: space-between;
20
+ align-items: center;
21
+ padding: 8px 16px;
22
+ background: #18181b;
23
+ border-bottom: 1px solid #3f3f46;
24
+ flex-shrink: 0;
25
+ }
26
+
27
+ .toolbar-left,
28
+ .toolbar-right {
29
+ display: flex;
30
+ align-items: center;
31
+ gap: 12px;
32
+ }
33
+
34
+ .logo {
35
+ font-weight: 600;
36
+ font-size: 14px;
37
+ color: #a78bfa;
38
+ }
39
+
40
+ .mode-badge {
41
+ padding: 2px 8px;
42
+ border-radius: 4px;
43
+ font-size: 11px;
44
+ font-weight: 600;
45
+ text-transform: uppercase;
46
+ }
47
+
48
+ .mode-mock {
49
+ background: #166534;
50
+ color: #86efac;
51
+ }
52
+
53
+ .mode-live {
54
+ background: #854d0e;
55
+ color: #fde047;
56
+ }
57
+
58
+ .permissions {
59
+ display: flex;
60
+ gap: 4px;
61
+ }
62
+
63
+ .perm-badge {
64
+ padding: 2px 6px;
65
+ border-radius: 3px;
66
+ font-size: 10px;
67
+ background: #27272a;
68
+ color: #a1a1aa;
69
+ }
70
+
71
+ .credit-balance {
72
+ font-size: 12px;
73
+ color: #fde047;
74
+ }
75
+
76
+ .btn-icon {
77
+ background: #27272a;
78
+ border: 1px solid #3f3f46;
79
+ color: #e4e4e7;
80
+ padding: 4px 8px;
81
+ border-radius: 4px;
82
+ cursor: pointer;
83
+ font-size: 14px;
84
+ }
85
+
86
+ .btn-icon:hover {
87
+ background: #3f3f46;
88
+ }
89
+
90
+ /* Plugin iframe */
91
+ #plugin-iframe {
92
+ flex: 1;
93
+ border: none;
94
+ width: 100%;
95
+ }
96
+
97
+ /* Dev Console */
98
+ .console-panel {
99
+ flex-shrink: 0;
100
+ border-top: 1px solid #3f3f46;
101
+ background: #18181b;
102
+ max-height: 250px;
103
+ display: flex;
104
+ flex-direction: column;
105
+ }
106
+
107
+ .console-header {
108
+ display: flex;
109
+ justify-content: space-between;
110
+ padding: 6px 16px;
111
+ cursor: pointer;
112
+ font-size: 12px;
113
+ color: #a1a1aa;
114
+ border-bottom: 1px solid #27272a;
115
+ user-select: none;
116
+ }
117
+
118
+ .console-header:hover {
119
+ background: #1e1e22;
120
+ }
121
+
122
+ .console-body {
123
+ overflow-y: auto;
124
+ padding: 8px 16px;
125
+ font-family: 'SF Mono', 'Fira Code', monospace;
126
+ font-size: 11px;
127
+ flex: 1;
128
+ display: none;
129
+ }
130
+
131
+ .console-body.open {
132
+ display: block;
133
+ }
134
+
135
+ .log-entry {
136
+ padding: 2px 0;
137
+ border-bottom: 1px solid #1e1e22;
138
+ }
139
+
140
+ .log-info {
141
+ color: #93c5fd;
142
+ }
143
+
144
+ .log-warn {
145
+ color: #fde047;
146
+ }
147
+
148
+ .log-error {
149
+ color: #fca5a5;
150
+ }
151
+
152
+ .log-time {
153
+ color: #6b7280;
154
+ margin-right: 8px;
155
+ }
156
+
157
+ .log-cost {
158
+ color: #fbbf24;
159
+ margin-left: 8px;
160
+ }
@@ -0,0 +1,35 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>FIAS Dev Harness</title>
7
+ <link rel="stylesheet" href="/static/harness.css" />
8
+ </head>
9
+ <body>
10
+ <div class="toolbar">
11
+ <div class="toolbar-left">
12
+ <span class="logo">FIAS Dev Harness</span>
13
+ <span id="mode-badge" class="mode-badge mode-mock">MOCK</span>
14
+ <div id="permissions" class="permissions"></div>
15
+ </div>
16
+ <div class="toolbar-right">
17
+ <span id="credit-balance" class="credit-balance" style="display: none"></span>
18
+ <button id="theme-toggle" class="btn-icon" title="Toggle theme">&#9788;/&#9790;</button>
19
+ <button id="reload-btn" class="btn-icon" title="Reload plugin">&#8635;</button>
20
+ </div>
21
+ </div>
22
+ <iframe
23
+ id="plugin-iframe"
24
+ sandbox="allow-scripts allow-forms"
25
+ ></iframe>
26
+ <div id="console-panel" class="console-panel">
27
+ <div class="console-header" id="console-toggle">
28
+ <span>Dev Console</span>
29
+ <span id="console-count">0 messages</span>
30
+ </div>
31
+ <div class="console-body" id="console-body"></div>
32
+ </div>
33
+ <script src="/static/harness.js"></script>
34
+ </body>
35
+ </html>