@push.rocks/smartrust 1.3.1 → 1.4.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.
@@ -1,104 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Mock "Rust binary" for testing the RustBridge IPC protocol.
5
- * Reads JSON lines from stdin via Buffer-based scanner, writes JSON lines to stdout.
6
- * Emits a ready event on startup.
7
- */
8
-
9
- // Emit ready event
10
- const readyEvent = JSON.stringify({ event: 'ready', data: { version: '1.0.0' } });
11
- process.stdout.write(readyEvent + '\n');
12
-
13
- // Buffer-based newline scanner for stdin (mirrors the RustBridge approach)
14
- let stdinBuffer = Buffer.alloc(0);
15
-
16
- process.stdin.on('data', (chunk) => {
17
- stdinBuffer = Buffer.concat([stdinBuffer, chunk]);
18
-
19
- let newlineIndex;
20
- while ((newlineIndex = stdinBuffer.indexOf(0x0A)) !== -1) {
21
- const lineBuffer = stdinBuffer.subarray(0, newlineIndex);
22
- stdinBuffer = stdinBuffer.subarray(newlineIndex + 1);
23
- const line = lineBuffer.toString('utf8').trim();
24
- if (line) {
25
- handleLine(line);
26
- }
27
- }
28
- });
29
-
30
- /**
31
- * Backpressure-aware write to stdout.
32
- */
33
- function writeResponse(data) {
34
- const json = JSON.stringify(data) + '\n';
35
- if (!process.stdout.write(json)) {
36
- // Wait for drain before continuing
37
- process.stdout.once('drain', () => {});
38
- }
39
- }
40
-
41
- function handleLine(line) {
42
- let request;
43
- try {
44
- request = JSON.parse(line);
45
- } catch {
46
- return;
47
- }
48
-
49
- const { id, method, params } = request;
50
-
51
- if (method === 'echo') {
52
- // Echo back the params as result
53
- writeResponse({ id, success: true, result: params });
54
- } else if (method === 'largeEcho') {
55
- // Echo back params (same as echo, named distinctly for large payload tests)
56
- writeResponse({ id, success: true, result: params });
57
- } else if (method === 'error') {
58
- // Return an error
59
- writeResponse({ id, success: false, error: 'Test error message' });
60
- } else if (method === 'emitEvent') {
61
- // Emit a custom event, then respond with success
62
- writeResponse({ event: params.eventName, data: params.eventData });
63
- writeResponse({ id, success: true, result: null });
64
- } else if (method === 'slow') {
65
- // Respond after a delay
66
- setTimeout(() => {
67
- writeResponse({ id, success: true, result: { delayed: true } });
68
- }, 100);
69
- } else if (method === 'streamEcho') {
70
- // Send params.count stream chunks, then final response
71
- const count = params.count || 0;
72
- let sent = 0;
73
- const interval = setInterval(() => {
74
- if (sent < count) {
75
- writeResponse({ id, stream: true, data: { index: sent, value: `chunk_${sent}` } });
76
- sent++;
77
- } else {
78
- clearInterval(interval);
79
- writeResponse({ id, success: true, result: { totalChunks: count } });
80
- }
81
- }, 10);
82
- } else if (method === 'streamError') {
83
- // Send 1 chunk, then error
84
- writeResponse({ id, stream: true, data: { index: 0, value: 'before_error' } });
85
- setTimeout(() => {
86
- writeResponse({ id, success: false, error: 'Stream error after chunk' });
87
- }, 20);
88
- } else if (method === 'streamEmpty') {
89
- // Zero chunks, immediate final response
90
- writeResponse({ id, success: true, result: { totalChunks: 0 } });
91
- } else if (method === 'exit') {
92
- // Graceful exit
93
- writeResponse({ id, success: true, result: null });
94
- process.exit(0);
95
- } else {
96
- // Unknown command
97
- writeResponse({ id, success: false, error: `Unknown method: ${method}` });
98
- }
99
- }
100
-
101
- // Handle SIGTERM gracefully
102
- process.on('SIGTERM', () => {
103
- process.exit(0);
104
- });
@@ -1,124 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Mock "Rust daemon" for testing the SocketTransport and RustBridge socket mode.
5
- * Creates a Unix socket server, accepts connections, and speaks the same
6
- * JSON-over-newline IPC protocol as mock-rust-binary.mjs.
7
- *
8
- * Usage: node mock-socket-server.mjs <socket-path>
9
- * Signals readiness by writing a JSON line to stdout: {"socketPath":"...","ready":true}
10
- */
11
-
12
- import * as net from 'net';
13
- import * as fs from 'fs';
14
-
15
- const socketPath = process.argv[2];
16
- if (!socketPath) {
17
- process.stderr.write('Usage: mock-socket-server.mjs <socket-path>\n');
18
- process.exit(1);
19
- }
20
-
21
- // Remove stale socket file
22
- try { fs.unlinkSync(socketPath); } catch { /* ignore */ }
23
-
24
- /**
25
- * Backpressure-aware write to a socket.
26
- */
27
- function writeResponse(conn, data) {
28
- const json = JSON.stringify(data) + '\n';
29
- if (!conn.write(json)) {
30
- conn.once('drain', () => {});
31
- }
32
- }
33
-
34
- function handleLine(line, conn) {
35
- let request;
36
- try {
37
- request = JSON.parse(line);
38
- } catch {
39
- return;
40
- }
41
-
42
- const { id, method, params } = request;
43
-
44
- if (method === 'echo') {
45
- writeResponse(conn, { id, success: true, result: params });
46
- } else if (method === 'largeEcho') {
47
- writeResponse(conn, { id, success: true, result: params });
48
- } else if (method === 'error') {
49
- writeResponse(conn, { id, success: false, error: 'Test error message' });
50
- } else if (method === 'emitEvent') {
51
- writeResponse(conn, { event: params.eventName, data: params.eventData });
52
- writeResponse(conn, { id, success: true, result: null });
53
- } else if (method === 'slow') {
54
- setTimeout(() => {
55
- writeResponse(conn, { id, success: true, result: { delayed: true } });
56
- }, 100);
57
- } else if (method === 'streamEcho') {
58
- const count = params.count || 0;
59
- let sent = 0;
60
- const interval = setInterval(() => {
61
- if (sent < count) {
62
- writeResponse(conn, { id, stream: true, data: { index: sent, value: `chunk_${sent}` } });
63
- sent++;
64
- } else {
65
- clearInterval(interval);
66
- writeResponse(conn, { id, success: true, result: { totalChunks: count } });
67
- }
68
- }, 10);
69
- } else if (method === 'streamError') {
70
- writeResponse(conn, { id, stream: true, data: { index: 0, value: 'before_error' } });
71
- setTimeout(() => {
72
- writeResponse(conn, { id, success: false, error: 'Stream error after chunk' });
73
- }, 20);
74
- } else if (method === 'streamEmpty') {
75
- writeResponse(conn, { id, success: true, result: { totalChunks: 0 } });
76
- } else if (method === 'exit') {
77
- writeResponse(conn, { id, success: true, result: null });
78
- // In socket mode, 'exit' just closes this connection, not the server
79
- setTimeout(() => conn.end(), 50);
80
- } else {
81
- writeResponse(conn, { id, success: false, error: `Unknown method: ${method}` });
82
- }
83
- }
84
-
85
- const server = net.createServer((conn) => {
86
- // Send ready event on each new connection
87
- writeResponse(conn, { event: 'ready', data: { version: '1.0.0' } });
88
-
89
- // Buffer-based newline scanner for incoming data
90
- let buffer = Buffer.alloc(0);
91
- conn.on('data', (chunk) => {
92
- buffer = Buffer.concat([buffer, chunk]);
93
- let idx;
94
- while ((idx = buffer.indexOf(0x0A)) !== -1) {
95
- const lineBuffer = buffer.subarray(0, idx);
96
- buffer = buffer.subarray(idx + 1);
97
- const line = lineBuffer.toString('utf8').trim();
98
- if (line) {
99
- handleLine(line, conn);
100
- }
101
- }
102
- });
103
-
104
- conn.on('error', () => { /* ignore client errors */ });
105
- });
106
-
107
- server.listen(socketPath, () => {
108
- // Signal to parent that the server is ready
109
- process.stdout.write(JSON.stringify({ socketPath, ready: true }) + '\n');
110
- });
111
-
112
- // Handle SIGTERM gracefully
113
- process.on('SIGTERM', () => {
114
- server.close();
115
- try { fs.unlinkSync(socketPath); } catch { /* ignore */ }
116
- process.exit(0);
117
- });
118
-
119
- // Handle SIGINT
120
- process.on('SIGINT', () => {
121
- server.close();
122
- try { fs.unlinkSync(socketPath); } catch { /* ignore */ }
123
- process.exit(0);
124
- });
@@ -1,89 +0,0 @@
1
- import { expect, tap } from '@git.zone/tstest/tapbundle';
2
- import { LineScanner } from '../ts/classes.linescanner.js';
3
-
4
- const noopLogger = { log() {} };
5
-
6
- tap.test('should parse a single complete line', async () => {
7
- const scanner = new LineScanner(1024 * 1024, noopLogger);
8
- const lines: string[] = [];
9
- scanner.push(Buffer.from('{"hello":"world"}\n'), (line) => lines.push(line));
10
- expect(lines.length).toEqual(1);
11
- expect(lines[0]).toEqual('{"hello":"world"}');
12
- });
13
-
14
- tap.test('should parse multiple lines in one chunk', async () => {
15
- const scanner = new LineScanner(1024 * 1024, noopLogger);
16
- const lines: string[] = [];
17
- scanner.push(Buffer.from('{"a":1}\n{"b":2}\n{"c":3}\n'), (line) => lines.push(line));
18
- expect(lines.length).toEqual(3);
19
- expect(lines[0]).toEqual('{"a":1}');
20
- expect(lines[1]).toEqual('{"b":2}');
21
- expect(lines[2]).toEqual('{"c":3}');
22
- });
23
-
24
- tap.test('should handle a line split across chunks', async () => {
25
- const scanner = new LineScanner(1024 * 1024, noopLogger);
26
- const lines: string[] = [];
27
- scanner.push(Buffer.from('{"hel'), (line) => lines.push(line));
28
- expect(lines.length).toEqual(0);
29
- scanner.push(Buffer.from('lo":"world"}\n'), (line) => lines.push(line));
30
- expect(lines.length).toEqual(1);
31
- expect(lines[0]).toEqual('{"hello":"world"}');
32
- });
33
-
34
- tap.test('should drop oversized lines', async () => {
35
- const scanner = new LineScanner(100, noopLogger);
36
- const lines: string[] = [];
37
- // Line is 200 chars + newline, exceeds maxPayloadSize of 100
38
- const oversized = 'x'.repeat(200) + '\n';
39
- scanner.push(Buffer.from(oversized), (line) => lines.push(line));
40
- expect(lines.length).toEqual(0);
41
- });
42
-
43
- tap.test('should clear buffer on OOM (no newline, exceeds max)', async () => {
44
- const scanner = new LineScanner(100, noopLogger);
45
- const lines: string[] = [];
46
- // Push 200 bytes without any newline — exceeds maxPayloadSize
47
- scanner.push(Buffer.from('x'.repeat(200)), (line) => lines.push(line));
48
- expect(lines.length).toEqual(0);
49
- // After clearing, should work normally again
50
- scanner.push(Buffer.from('{"ok":true}\n'), (line) => lines.push(line));
51
- expect(lines.length).toEqual(1);
52
- expect(lines[0]).toEqual('{"ok":true}');
53
- });
54
-
55
- tap.test('should skip empty lines', async () => {
56
- const scanner = new LineScanner(1024 * 1024, noopLogger);
57
- const lines: string[] = [];
58
- scanner.push(Buffer.from('\n\n{"a":1}\n\n'), (line) => lines.push(line));
59
- expect(lines.length).toEqual(1);
60
- expect(lines[0]).toEqual('{"a":1}');
61
- });
62
-
63
- tap.test('should handle mixed complete and partial lines', async () => {
64
- const scanner = new LineScanner(1024 * 1024, noopLogger);
65
- const lines: string[] = [];
66
- // First chunk: one complete line + start of second line
67
- scanner.push(Buffer.from('{"first":1}\n{"sec'), (line) => lines.push(line));
68
- expect(lines.length).toEqual(1);
69
- // Second chunk: end of second line + complete third line
70
- scanner.push(Buffer.from('ond":2}\n{"third":3}\n'), (line) => lines.push(line));
71
- expect(lines.length).toEqual(3);
72
- expect(lines[1]).toEqual('{"second":2}');
73
- expect(lines[2]).toEqual('{"third":3}');
74
- });
75
-
76
- tap.test('clear should reset the buffer', async () => {
77
- const scanner = new LineScanner(1024 * 1024, noopLogger);
78
- const lines: string[] = [];
79
- // Push partial data
80
- scanner.push(Buffer.from('{"partial":'), (line) => lines.push(line));
81
- // Clear
82
- scanner.clear();
83
- // Now push a complete new line — old partial should not affect it
84
- scanner.push(Buffer.from('{"fresh":true}\n'), (line) => lines.push(line));
85
- expect(lines.length).toEqual(1);
86
- expect(lines[0]).toEqual('{"fresh":true}');
87
- });
88
-
89
- export default tap.start();
@@ -1,98 +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 { RustBinaryLocator } from '../ts/classes.rustbinarylocator.js';
5
-
6
- const testDir = path.resolve(path.dirname(new URL(import.meta.url).pathname));
7
-
8
- tap.test('should return null when no binary is found', async () => {
9
- const locator = new RustBinaryLocator({
10
- binaryName: 'nonexistent-binary-xyz',
11
- searchSystemPath: false,
12
- });
13
- const result = await locator.findBinary();
14
- expect(result).toBeNull();
15
- });
16
-
17
- tap.test('should use explicit binaryPath when provided', async () => {
18
- const mockBinaryPath = path.join(testDir, 'helpers/mock-rust-binary.mjs');
19
- const locator = new RustBinaryLocator({
20
- binaryName: 'mock-rust-binary',
21
- binaryPath: mockBinaryPath,
22
- searchSystemPath: false,
23
- });
24
- const result = await locator.findBinary();
25
- expect(result).toEqual(mockBinaryPath);
26
- });
27
-
28
- tap.test('should cache the result', async () => {
29
- const mockBinaryPath = path.join(testDir, 'helpers/mock-rust-binary.mjs');
30
- const locator = new RustBinaryLocator({
31
- binaryName: 'mock-rust-binary',
32
- binaryPath: mockBinaryPath,
33
- searchSystemPath: false,
34
- });
35
-
36
- const first = await locator.findBinary();
37
- const second = await locator.findBinary();
38
- expect(first).toEqual(second);
39
- expect(first).toEqual(mockBinaryPath);
40
- });
41
-
42
- tap.test('should clear cache', async () => {
43
- const mockBinaryPath = path.join(testDir, 'helpers/mock-rust-binary.mjs');
44
- const locator = new RustBinaryLocator({
45
- binaryName: 'mock-rust-binary',
46
- binaryPath: mockBinaryPath,
47
- searchSystemPath: false,
48
- });
49
-
50
- const first = await locator.findBinary();
51
- expect(first).toEqual(mockBinaryPath);
52
-
53
- locator.clearCache();
54
- // After clearing, next call should re-search and still find it
55
- const second = await locator.findBinary();
56
- expect(second).toEqual(mockBinaryPath);
57
- });
58
-
59
- tap.test('should fall back to env var when binaryPath not set', async () => {
60
- const mockBinaryPath = path.join(testDir, 'helpers/mock-rust-binary.mjs');
61
- const envVar = 'TEST_SMARTRUST_BINARY_' + Date.now();
62
- process.env[envVar] = mockBinaryPath;
63
-
64
- const locator = new RustBinaryLocator({
65
- binaryName: 'mock-rust-binary',
66
- envVarName: envVar,
67
- searchSystemPath: false,
68
- });
69
-
70
- const result = await locator.findBinary();
71
- expect(result).toEqual(mockBinaryPath);
72
-
73
- delete process.env[envVar];
74
- });
75
-
76
- tap.test('should find binary in local paths', async () => {
77
- const mockBinaryPath = path.join(testDir, 'helpers/mock-rust-binary.mjs');
78
- const locator = new RustBinaryLocator({
79
- binaryName: 'mock-rust-binary',
80
- localPaths: ['/nonexistent/path/binary', mockBinaryPath],
81
- searchSystemPath: false,
82
- });
83
-
84
- const result = await locator.findBinary();
85
- expect(result).toEqual(mockBinaryPath);
86
- });
87
-
88
- tap.test('should find node in system PATH', async () => {
89
- const locator = new RustBinaryLocator({
90
- binaryName: 'node',
91
- searchSystemPath: true,
92
- });
93
-
94
- const result = await locator.findBinary();
95
- expect(result).not.toBeNull();
96
- });
97
-
98
- export default tap.start();