@push.rocks/smartrust 1.3.2 → 1.4.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.
- package/.smartconfig.json +42 -0
- package/dist_ts/00_commitinfo_data.js +3 -3
- package/dist_ts/classes.rustbridge.d.ts +5 -2
- package/dist_ts/classes.rustbridge.js +158 -40
- package/dist_ts/classes.rustbridgerequesterror.d.ts +23 -0
- package/dist_ts/classes.rustbridgerequesterror.js +20 -0
- package/dist_ts/index.d.ts +1 -0
- package/dist_ts/index.js +2 -1
- package/dist_ts/interfaces/config.d.ts +9 -0
- package/license +19 -0
- package/package.json +41 -12
- package/readme.md +58 -6
- package/ts/00_commitinfo_data.ts +2 -2
- package/ts/classes.rustbridge.ts +204 -44
- package/ts/classes.rustbridgerequesterror.ts +37 -0
- package/ts/index.ts +5 -0
- package/ts/interfaces/config.ts +10 -0
- package/.gitea/workflows/default_nottags.yaml +0 -66
- package/.gitea/workflows/default_tags.yaml +0 -124
- package/.vscode/launch.json +0 -11
- package/.vscode/settings.json +0 -26
- package/changelog.md +0 -84
- package/npmextra.json +0 -24
- package/test/helpers/mock-rust-binary.mjs +0 -104
- package/test/helpers/mock-socket-server.mjs +0 -124
- package/test/test.linescanner.node.ts +0 -89
- package/test/test.rustbinarylocator.node.ts +0 -98
- package/test/test.rustbridge.node.ts +0 -440
- package/test/test.sockettransport.node.ts +0 -312
- package/test/test.ts +0 -12
- package/tsconfig.json +0 -12
|
@@ -1,312 +0,0 @@
|
|
|
1
|
-
import { expect, tap } from '@git.zone/tstest/tapbundle';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
import * as fs from 'fs';
|
|
4
|
-
import * as childProcess from 'child_process';
|
|
5
|
-
import * as os from 'os';
|
|
6
|
-
import { RustBridge } from '../ts/classes.rustbridge.js';
|
|
7
|
-
import type { ICommandDefinition } from '../ts/interfaces/index.js';
|
|
8
|
-
|
|
9
|
-
const testDir = path.resolve(path.dirname(new URL(import.meta.url).pathname));
|
|
10
|
-
const mockServerPath = path.join(testDir, 'helpers/mock-socket-server.mjs');
|
|
11
|
-
|
|
12
|
-
// Define the command types for our mock binary
|
|
13
|
-
type TMockCommands = {
|
|
14
|
-
echo: { params: Record<string, any>; result: Record<string, any> };
|
|
15
|
-
largeEcho: { params: Record<string, any>; result: Record<string, any> };
|
|
16
|
-
error: { params: {}; result: never };
|
|
17
|
-
emitEvent: { params: { eventName: string; eventData: any }; result: null };
|
|
18
|
-
slow: { params: {}; result: { delayed: boolean } };
|
|
19
|
-
exit: { params: {}; result: null };
|
|
20
|
-
streamEcho: { params: { count: number }; chunk: { index: number; value: string }; result: { totalChunks: number } };
|
|
21
|
-
streamError: { params: {}; chunk: { index: number; value: string }; result: never };
|
|
22
|
-
streamEmpty: { params: {}; chunk: never; result: { totalChunks: number } };
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Start the mock socket server and return the socket path.
|
|
27
|
-
* Returns { proc, socketPath }.
|
|
28
|
-
*/
|
|
29
|
-
async function startMockServer(testName: string): Promise<{ proc: childProcess.ChildProcess; socketPath: string }> {
|
|
30
|
-
const socketPath = path.join(os.tmpdir(), `smartrust-test-${Date.now()}-${testName}.sock`);
|
|
31
|
-
|
|
32
|
-
const proc = childProcess.spawn('node', [mockServerPath, socketPath], {
|
|
33
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
// Wait for the server to signal readiness via stdout
|
|
37
|
-
return new Promise((resolve, reject) => {
|
|
38
|
-
let stdoutData = '';
|
|
39
|
-
const timeout = setTimeout(() => {
|
|
40
|
-
proc.kill();
|
|
41
|
-
reject(new Error('Mock server did not start within 5s'));
|
|
42
|
-
}, 5000);
|
|
43
|
-
|
|
44
|
-
proc.stdout!.on('data', (data: Buffer) => {
|
|
45
|
-
stdoutData += data.toString();
|
|
46
|
-
const lines = stdoutData.split('\n');
|
|
47
|
-
for (const line of lines) {
|
|
48
|
-
if (line.trim()) {
|
|
49
|
-
try {
|
|
50
|
-
const parsed = JSON.parse(line.trim());
|
|
51
|
-
if (parsed.ready) {
|
|
52
|
-
clearTimeout(timeout);
|
|
53
|
-
resolve({ proc, socketPath: parsed.socketPath });
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
} catch { /* not JSON yet */ }
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
proc.on('error', (err) => {
|
|
62
|
-
clearTimeout(timeout);
|
|
63
|
-
reject(err);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
proc.on('exit', (code) => {
|
|
67
|
-
clearTimeout(timeout);
|
|
68
|
-
reject(new Error(`Mock server exited with code ${code}`));
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function stopMockServer(proc: childProcess.ChildProcess, socketPath: string) {
|
|
74
|
-
try { proc.kill('SIGTERM'); } catch { /* ignore */ }
|
|
75
|
-
try { fs.unlinkSync(socketPath); } catch { /* ignore */ }
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// === Socket Transport Tests via RustBridge.connect() ===
|
|
79
|
-
|
|
80
|
-
tap.test('socket: should connect and receive ready event', async () => {
|
|
81
|
-
const { proc, socketPath } = await startMockServer('connect-ready');
|
|
82
|
-
try {
|
|
83
|
-
const bridge = new RustBridge<TMockCommands>({
|
|
84
|
-
binaryName: 'mock-daemon',
|
|
85
|
-
readyTimeoutMs: 5000,
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
const result = await bridge.connect(socketPath);
|
|
89
|
-
expect(result).toBeTrue();
|
|
90
|
-
expect(bridge.running).toBeTrue();
|
|
91
|
-
|
|
92
|
-
bridge.kill();
|
|
93
|
-
expect(bridge.running).toBeFalse();
|
|
94
|
-
} finally {
|
|
95
|
-
stopMockServer(proc, socketPath);
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
tap.test('socket: should send command and receive response', async () => {
|
|
100
|
-
const { proc, socketPath } = await startMockServer('send-command');
|
|
101
|
-
try {
|
|
102
|
-
const bridge = new RustBridge<TMockCommands>({
|
|
103
|
-
binaryName: 'mock-daemon',
|
|
104
|
-
readyTimeoutMs: 5000,
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
await bridge.connect(socketPath);
|
|
108
|
-
|
|
109
|
-
const result = await bridge.sendCommand('echo', { hello: 'world', num: 42 });
|
|
110
|
-
expect(result).toEqual({ hello: 'world', num: 42 });
|
|
111
|
-
|
|
112
|
-
bridge.kill();
|
|
113
|
-
} finally {
|
|
114
|
-
stopMockServer(proc, socketPath);
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
tap.test('socket: should handle error responses', async () => {
|
|
119
|
-
const { proc, socketPath } = await startMockServer('error-response');
|
|
120
|
-
try {
|
|
121
|
-
const bridge = new RustBridge<TMockCommands>({
|
|
122
|
-
binaryName: 'mock-daemon',
|
|
123
|
-
readyTimeoutMs: 5000,
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
await bridge.connect(socketPath);
|
|
127
|
-
|
|
128
|
-
let threw = false;
|
|
129
|
-
try {
|
|
130
|
-
await bridge.sendCommand('error', {});
|
|
131
|
-
} catch (err: any) {
|
|
132
|
-
threw = true;
|
|
133
|
-
expect(err.message).toInclude('Test error message');
|
|
134
|
-
}
|
|
135
|
-
expect(threw).toBeTrue();
|
|
136
|
-
|
|
137
|
-
bridge.kill();
|
|
138
|
-
} finally {
|
|
139
|
-
stopMockServer(proc, socketPath);
|
|
140
|
-
}
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
tap.test('socket: should receive custom events', async () => {
|
|
144
|
-
const { proc, socketPath } = await startMockServer('custom-events');
|
|
145
|
-
try {
|
|
146
|
-
const bridge = new RustBridge<TMockCommands>({
|
|
147
|
-
binaryName: 'mock-daemon',
|
|
148
|
-
readyTimeoutMs: 5000,
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
await bridge.connect(socketPath);
|
|
152
|
-
|
|
153
|
-
const eventPromise = new Promise<any>((resolve) => {
|
|
154
|
-
bridge.once('management:testEvent', (data) => resolve(data));
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
await bridge.sendCommand('emitEvent', {
|
|
158
|
-
eventName: 'testEvent',
|
|
159
|
-
eventData: { key: 'value' },
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
const eventData = await eventPromise;
|
|
163
|
-
expect(eventData).toEqual({ key: 'value' });
|
|
164
|
-
|
|
165
|
-
bridge.kill();
|
|
166
|
-
} finally {
|
|
167
|
-
stopMockServer(proc, socketPath);
|
|
168
|
-
}
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
tap.test('socket: should handle multiple concurrent commands', async () => {
|
|
172
|
-
const { proc, socketPath } = await startMockServer('concurrent');
|
|
173
|
-
try {
|
|
174
|
-
const bridge = new RustBridge<TMockCommands>({
|
|
175
|
-
binaryName: 'mock-daemon',
|
|
176
|
-
readyTimeoutMs: 5000,
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
await bridge.connect(socketPath);
|
|
180
|
-
|
|
181
|
-
const results = await Promise.all([
|
|
182
|
-
bridge.sendCommand('echo', { id: 1 }),
|
|
183
|
-
bridge.sendCommand('echo', { id: 2 }),
|
|
184
|
-
bridge.sendCommand('echo', { id: 3 }),
|
|
185
|
-
]);
|
|
186
|
-
|
|
187
|
-
expect(results[0]).toEqual({ id: 1 });
|
|
188
|
-
expect(results[1]).toEqual({ id: 2 });
|
|
189
|
-
expect(results[2]).toEqual({ id: 3 });
|
|
190
|
-
|
|
191
|
-
bridge.kill();
|
|
192
|
-
} finally {
|
|
193
|
-
stopMockServer(proc, socketPath);
|
|
194
|
-
}
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
tap.test('socket: should handle 1MB payload round-trip', async () => {
|
|
198
|
-
const { proc, socketPath } = await startMockServer('large-payload');
|
|
199
|
-
try {
|
|
200
|
-
const bridge = new RustBridge<TMockCommands>({
|
|
201
|
-
binaryName: 'mock-daemon',
|
|
202
|
-
readyTimeoutMs: 5000,
|
|
203
|
-
requestTimeoutMs: 30000,
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
await bridge.connect(socketPath);
|
|
207
|
-
|
|
208
|
-
const largeString = 'x'.repeat(1024 * 1024);
|
|
209
|
-
const result = await bridge.sendCommand('largeEcho', { data: largeString });
|
|
210
|
-
expect(result.data).toEqual(largeString);
|
|
211
|
-
expect(result.data.length).toEqual(1024 * 1024);
|
|
212
|
-
|
|
213
|
-
bridge.kill();
|
|
214
|
-
} finally {
|
|
215
|
-
stopMockServer(proc, socketPath);
|
|
216
|
-
}
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
tap.test('socket: should disconnect without killing the daemon', async () => {
|
|
220
|
-
const { proc, socketPath } = await startMockServer('no-kill-daemon');
|
|
221
|
-
try {
|
|
222
|
-
// First connection
|
|
223
|
-
const bridge1 = new RustBridge<TMockCommands>({
|
|
224
|
-
binaryName: 'mock-daemon',
|
|
225
|
-
readyTimeoutMs: 5000,
|
|
226
|
-
});
|
|
227
|
-
await bridge1.connect(socketPath);
|
|
228
|
-
expect(bridge1.running).toBeTrue();
|
|
229
|
-
|
|
230
|
-
// Disconnect
|
|
231
|
-
bridge1.kill();
|
|
232
|
-
expect(bridge1.running).toBeFalse();
|
|
233
|
-
|
|
234
|
-
// Second connection — daemon should still be alive
|
|
235
|
-
const bridge2 = new RustBridge<TMockCommands>({
|
|
236
|
-
binaryName: 'mock-daemon',
|
|
237
|
-
readyTimeoutMs: 5000,
|
|
238
|
-
});
|
|
239
|
-
const result = await bridge2.connect(socketPath);
|
|
240
|
-
expect(result).toBeTrue();
|
|
241
|
-
expect(bridge2.running).toBeTrue();
|
|
242
|
-
|
|
243
|
-
// Verify the daemon is functional
|
|
244
|
-
const echoResult = await bridge2.sendCommand('echo', { reconnected: true });
|
|
245
|
-
expect(echoResult).toEqual({ reconnected: true });
|
|
246
|
-
|
|
247
|
-
bridge2.kill();
|
|
248
|
-
} finally {
|
|
249
|
-
stopMockServer(proc, socketPath);
|
|
250
|
-
}
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
tap.test('socket: should stream responses via socket', async () => {
|
|
254
|
-
const { proc, socketPath } = await startMockServer('streaming');
|
|
255
|
-
try {
|
|
256
|
-
const bridge = new RustBridge<TMockCommands>({
|
|
257
|
-
binaryName: 'mock-daemon',
|
|
258
|
-
readyTimeoutMs: 5000,
|
|
259
|
-
requestTimeoutMs: 10000,
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
await bridge.connect(socketPath);
|
|
263
|
-
|
|
264
|
-
const stream = bridge.sendCommandStreaming('streamEcho', { count: 5 });
|
|
265
|
-
const chunks: Array<{ index: number; value: string }> = [];
|
|
266
|
-
|
|
267
|
-
for await (const chunk of stream) {
|
|
268
|
-
chunks.push(chunk);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
expect(chunks.length).toEqual(5);
|
|
272
|
-
for (let i = 0; i < 5; i++) {
|
|
273
|
-
expect(chunks[i].index).toEqual(i);
|
|
274
|
-
expect(chunks[i].value).toEqual(`chunk_${i}`);
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
const result = await stream.result;
|
|
278
|
-
expect(result.totalChunks).toEqual(5);
|
|
279
|
-
|
|
280
|
-
bridge.kill();
|
|
281
|
-
} finally {
|
|
282
|
-
stopMockServer(proc, socketPath);
|
|
283
|
-
}
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
tap.test('socket: should return false when socket path does not exist', async () => {
|
|
287
|
-
const bridge = new RustBridge<TMockCommands>({
|
|
288
|
-
binaryName: 'mock-daemon',
|
|
289
|
-
readyTimeoutMs: 3000,
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
const result = await bridge.connect('/tmp/nonexistent-smartrust-test.sock');
|
|
293
|
-
expect(result).toBeFalse();
|
|
294
|
-
expect(bridge.running).toBeFalse();
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
tap.test('socket: should throw when sending command while not connected', async () => {
|
|
298
|
-
const bridge = new RustBridge<TMockCommands>({
|
|
299
|
-
binaryName: 'mock-daemon',
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
let threw = false;
|
|
303
|
-
try {
|
|
304
|
-
await bridge.sendCommand('echo', {});
|
|
305
|
-
} catch (err: any) {
|
|
306
|
-
threw = true;
|
|
307
|
-
expect(err.message).toInclude('not running');
|
|
308
|
-
}
|
|
309
|
-
expect(threw).toBeTrue();
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
export default tap.start();
|
package/test/test.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { expect, tap } from '@git.zone/tstest/tapbundle';
|
|
2
|
-
import * as smartrust from '../ts/index.js';
|
|
3
|
-
|
|
4
|
-
tap.test('should export RustBridge', async () => {
|
|
5
|
-
expect(smartrust.RustBridge).toBeTypeOf('function');
|
|
6
|
-
});
|
|
7
|
-
|
|
8
|
-
tap.test('should export RustBinaryLocator', async () => {
|
|
9
|
-
expect(smartrust.RustBinaryLocator).toBeTypeOf('function');
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
export default tap.start();
|