apache-iggy 0.8.1-edge.3 → 0.8.1-edge.4
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/README.md
CHANGED
|
@@ -57,11 +57,7 @@ from the SDK command table use `Operation::NonReplicated` and carry the command
|
|
|
57
57
|
code in the request header's reserved field. The server remains authoritative
|
|
58
58
|
for classifying or rejecting extension commands.
|
|
59
59
|
|
|
60
|
-
The same npm package supports both framing modes. VSR
|
|
61
|
-
only and restricts `Client` to one pooled connection because authentication,
|
|
62
|
-
request sequencing, and consumer-group assignments belong to one consensus
|
|
63
|
-
session. Configurations requesting VSR over TLS or more than one pooled
|
|
64
|
-
connection fail before a socket is opened.
|
|
60
|
+
The same npm package supports both framing modes over TCP and TLS. VSR restricts `Client` to one pooled connection because authentication, request sequencing, and consumer-group assignments belong to one consensus session. Configurations requesting more than one pooled connection fail before a socket is opened.
|
|
65
61
|
|
|
66
62
|
VSR authentication translates the existing password and personal-access-token
|
|
67
63
|
login APIs into the register handshake required by the consensus protocol. A
|
|
@@ -24,8 +24,6 @@ export const normalizeClientConfig = (config) => {
|
|
|
24
24
|
if (!Number.isSafeInteger(maxResponseFrameSize) ||
|
|
25
25
|
maxResponseFrameSize < 256)
|
|
26
26
|
throw new TypeError('maxResponseFrameSize must be a safe integer of at least 256 bytes');
|
|
27
|
-
if (protocol === 'vsr' && config.transport === 'TLS')
|
|
28
|
-
throw new TypeError('VSR framing currently supports the TCP transport only');
|
|
29
27
|
if (protocol === 'vsr' &&
|
|
30
28
|
((config.poolSize?.min ?? 1) > 1 || (config.poolSize?.max ?? 1) > 1))
|
|
31
29
|
throw new TypeError('VSR clients currently support exactly one pooled connection');
|
|
@@ -50,12 +50,15 @@ describe('normalizeClientConfig', () => {
|
|
|
50
50
|
protocol: 'auto'
|
|
51
51
|
}), /unsupported wire protocol/);
|
|
52
52
|
});
|
|
53
|
-
it('
|
|
54
|
-
|
|
53
|
+
it('supports VSR over TLS', () => {
|
|
54
|
+
const normalized = normalizeClientConfig({
|
|
55
55
|
...config(),
|
|
56
56
|
protocol: 'vsr',
|
|
57
57
|
transport: 'TLS'
|
|
58
|
-
})
|
|
58
|
+
});
|
|
59
|
+
assert.equal(normalized.protocol, 'vsr');
|
|
60
|
+
assert.equal(normalized.transport, 'TLS');
|
|
61
|
+
assert.deepEqual(normalized.poolSize, { min: 1, max: 1 });
|
|
59
62
|
});
|
|
60
63
|
it('rejects unsafe response frame limits', () => {
|
|
61
64
|
for (const maxResponseFrameSize of [0, 255, 1.5, Number.MAX_VALUE])
|
|
@@ -17,8 +17,10 @@
|
|
|
17
17
|
//
|
|
18
18
|
import assert from 'node:assert/strict';
|
|
19
19
|
import { once } from 'node:events';
|
|
20
|
+
import { readFileSync } from 'node:fs';
|
|
20
21
|
import { createServer } from 'node:net';
|
|
21
22
|
import { describe, it } from 'node:test';
|
|
23
|
+
import { createServer as createTlsServer } from 'node:tls';
|
|
22
24
|
import { COMMAND_CODE } from '../wire/command.code.js';
|
|
23
25
|
import { ResponseError } from '../wire/error.utils.js';
|
|
24
26
|
import { Command2, EVICTION_OFFSET, EvictionReason, HEADER_SIZE, REPLY_OFFSET, REQUEST_OFFSET } from '../wire/vsr/header.js';
|
|
@@ -26,10 +28,13 @@ import { Operation } from '../wire/vsr/operation.js';
|
|
|
26
28
|
import { VsrEvictionError } from '../wire/vsr/reply.js';
|
|
27
29
|
import { CommandResponseStream } from './client.socket.js';
|
|
28
30
|
const TEST_SESSION = 42n;
|
|
31
|
+
const TLS_CERTIFICATE = readFileSync(new URL('../../../../core/certs/iggy_cert.pem', import.meta.url));
|
|
32
|
+
const TLS_KEY = readFileSync(new URL('../../../../core/certs/iggy_key.pem', import.meta.url));
|
|
33
|
+
const TLS_CA_CERTIFICATE = readFileSync(new URL('../../../../core/certs/iggy_ca_cert.pem', import.meta.url));
|
|
29
34
|
/** Loopback server speaking just enough VSR framing for the client tests. */
|
|
30
|
-
const startVsrServer = async (handler) => {
|
|
35
|
+
const startVsrServer = async (handler, transport = 'TCP') => {
|
|
31
36
|
const frames = [];
|
|
32
|
-
const
|
|
37
|
+
const handleConnection = (socket) => {
|
|
33
38
|
let pending = Buffer.alloc(0);
|
|
34
39
|
socket.on('data', (data) => {
|
|
35
40
|
pending = Buffer.concat([pending, data]);
|
|
@@ -44,7 +49,10 @@ const startVsrServer = async (handler) => {
|
|
|
44
49
|
}
|
|
45
50
|
});
|
|
46
51
|
socket.on('error', () => { });
|
|
47
|
-
}
|
|
52
|
+
};
|
|
53
|
+
const server = transport === 'TLS'
|
|
54
|
+
? createTlsServer({ cert: TLS_CERTIFICATE, key: TLS_KEY }, handleConnection)
|
|
55
|
+
: createServer(handleConnection);
|
|
48
56
|
server.listen(0, '127.0.0.1');
|
|
49
57
|
await once(server, 'listening');
|
|
50
58
|
return {
|
|
@@ -160,6 +168,28 @@ const vsrConfig = (port) => ({
|
|
|
160
168
|
reconnect: { enabled: false, interval: 100, maxRetries: 1 }
|
|
161
169
|
});
|
|
162
170
|
describe('VSR client socket', () => {
|
|
171
|
+
it('exchanges VSR frames over TLS', async () => {
|
|
172
|
+
const server = await startVsrServer((frame, socket) => singleNodeHandler(server.port)(frame, socket), 'TLS');
|
|
173
|
+
const client = new CommandResponseStream({
|
|
174
|
+
...vsrConfig(server.port),
|
|
175
|
+
transport: 'TLS',
|
|
176
|
+
options: {
|
|
177
|
+
host: '127.0.0.1',
|
|
178
|
+
port: server.port,
|
|
179
|
+
servername: 'localhost',
|
|
180
|
+
ca: TLS_CA_CERTIFICATE
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
try {
|
|
184
|
+
const response = await client.sendCommand(60_015, Buffer.from('tls'));
|
|
185
|
+
assert.equal(response.status, 0);
|
|
186
|
+
assert.equal(server.frames.length, 3);
|
|
187
|
+
}
|
|
188
|
+
finally {
|
|
189
|
+
client.destroy();
|
|
190
|
+
await server.close();
|
|
191
|
+
}
|
|
192
|
+
});
|
|
163
193
|
it('registers one session before the first authenticated command', async () => {
|
|
164
194
|
const server = await startVsrServer((frame, socket) => singleNodeHandler(server.port)(frame, socket));
|
|
165
195
|
const client = new CommandResponseStream(vsrConfig(server.port));
|
|
@@ -46,9 +46,13 @@ const caCertPath = process.env.E2E_ROOT_CA_CERT
|
|
|
46
46
|
const getTlsClient = () => {
|
|
47
47
|
const [, port] = getIggyAddress();
|
|
48
48
|
const caCert = readFileSync(caCertPath);
|
|
49
|
+
const protocol = process.env.IGGY_TEST_PROTOCOL === 'vsr'
|
|
50
|
+
? 'vsr'
|
|
51
|
+
: 'classic';
|
|
49
52
|
// The server certificate SAN is DNS:localhost, so we connect via 'localhost'
|
|
50
53
|
// for proper hostname verification (consistent with Python and C# TLS tests).
|
|
51
54
|
return new Client({
|
|
55
|
+
protocol,
|
|
52
56
|
transport: 'TLS',
|
|
53
57
|
options: {
|
|
54
58
|
port,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "apache-iggy",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.8.1-edge.
|
|
4
|
+
"version": "0.8.1-edge.4",
|
|
5
5
|
"description": "Official Apache Iggy NodeJS SDK",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"iggy",
|
|
@@ -58,8 +58,8 @@
|
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@commitlint/cli": "21.2.1",
|
|
60
60
|
"@commitlint/config-conventional": "21.2.0",
|
|
61
|
-
"@cucumber/cucumber": "13.
|
|
62
|
-
"@swc-node/register": "1.12.
|
|
61
|
+
"@cucumber/cucumber": "13.2.0",
|
|
62
|
+
"@swc-node/register": "1.12.1",
|
|
63
63
|
"@types/debug": "4.1.13",
|
|
64
64
|
"@types/node": "26.1.1",
|
|
65
65
|
"c8": "^12.0.0",
|