galileo-generated 0.2.7 → 0.2.9

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 (60) hide show
  1. package/.release-please-config.json +7 -0
  2. package/.release-please-manifest.json +1 -1
  3. package/dist/commonjs/hooks/cert-management.d.ts +73 -0
  4. package/dist/commonjs/hooks/cert-management.d.ts.map +1 -0
  5. package/dist/commonjs/hooks/cert-management.js +258 -0
  6. package/dist/commonjs/hooks/cert-management.js.map +1 -0
  7. package/dist/commonjs/hooks/registration.d.ts.map +1 -1
  8. package/dist/commonjs/hooks/registration.js +8 -0
  9. package/dist/commonjs/hooks/registration.js.map +1 -1
  10. package/dist/commonjs/hooks/sdk-identifier.d.ts +5 -0
  11. package/dist/commonjs/hooks/sdk-identifier.d.ts.map +1 -0
  12. package/dist/commonjs/hooks/sdk-identifier.js +37 -0
  13. package/dist/commonjs/hooks/sdk-identifier.js.map +1 -0
  14. package/dist/commonjs/lib/galileo-config.d.ts +101 -12
  15. package/dist/commonjs/lib/galileo-config.d.ts.map +1 -1
  16. package/dist/commonjs/lib/galileo-config.js +153 -12
  17. package/dist/commonjs/lib/galileo-config.js.map +1 -1
  18. package/dist/commonjs/tests/hooks/cert-management.test.d.ts +2 -0
  19. package/dist/commonjs/tests/hooks/cert-management.test.d.ts.map +1 -0
  20. package/dist/commonjs/tests/hooks/cert-management.test.js +794 -0
  21. package/dist/commonjs/tests/hooks/cert-management.test.js.map +1 -0
  22. package/dist/commonjs/tests/hooks/sdk-identifier.test.d.ts +2 -0
  23. package/dist/commonjs/tests/hooks/sdk-identifier.test.d.ts.map +1 -0
  24. package/dist/commonjs/tests/hooks/sdk-identifier.test.js +136 -0
  25. package/dist/commonjs/tests/hooks/sdk-identifier.test.js.map +1 -0
  26. package/dist/commonjs/tests/lib/galileo-config.test.js +101 -0
  27. package/dist/commonjs/tests/lib/galileo-config.test.js.map +1 -1
  28. package/dist/esm/hooks/cert-management.d.ts +73 -0
  29. package/dist/esm/hooks/cert-management.d.ts.map +1 -0
  30. package/dist/esm/hooks/cert-management.js +254 -0
  31. package/dist/esm/hooks/cert-management.js.map +1 -0
  32. package/dist/esm/hooks/registration.d.ts.map +1 -1
  33. package/dist/esm/hooks/registration.js +8 -0
  34. package/dist/esm/hooks/registration.js.map +1 -1
  35. package/dist/esm/hooks/sdk-identifier.d.ts +5 -0
  36. package/dist/esm/hooks/sdk-identifier.d.ts.map +1 -0
  37. package/dist/esm/hooks/sdk-identifier.js +33 -0
  38. package/dist/esm/hooks/sdk-identifier.js.map +1 -0
  39. package/dist/esm/lib/galileo-config.d.ts +101 -12
  40. package/dist/esm/lib/galileo-config.d.ts.map +1 -1
  41. package/dist/esm/lib/galileo-config.js +153 -12
  42. package/dist/esm/lib/galileo-config.js.map +1 -1
  43. package/dist/esm/tests/hooks/cert-management.test.d.ts +2 -0
  44. package/dist/esm/tests/hooks/cert-management.test.d.ts.map +1 -0
  45. package/dist/esm/tests/hooks/cert-management.test.js +792 -0
  46. package/dist/esm/tests/hooks/cert-management.test.js.map +1 -0
  47. package/dist/esm/tests/hooks/sdk-identifier.test.d.ts +2 -0
  48. package/dist/esm/tests/hooks/sdk-identifier.test.d.ts.map +1 -0
  49. package/dist/esm/tests/hooks/sdk-identifier.test.js +134 -0
  50. package/dist/esm/tests/hooks/sdk-identifier.test.js.map +1 -0
  51. package/dist/esm/tests/lib/galileo-config.test.js +101 -0
  52. package/dist/esm/tests/lib/galileo-config.test.js.map +1 -1
  53. package/package.json +5 -3
  54. package/src/hooks/cert-management.ts +288 -0
  55. package/src/hooks/registration.ts +10 -0
  56. package/src/hooks/sdk-identifier.ts +41 -0
  57. package/src/lib/galileo-config.ts +214 -15
  58. package/src/tests/hooks/cert-management.test.ts +958 -0
  59. package/src/tests/hooks/sdk-identifier.test.ts +176 -0
  60. package/src/tests/lib/galileo-config.test.ts +110 -0
@@ -0,0 +1,794 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const cert_management_js_1 = require("../../hooks/cert-management.js");
5
+ const galileo_config_js_1 = require("../../lib/galileo-config.js");
6
+ const http_js_1 = require("../../lib/http.js");
7
+ const fs_1 = require("fs");
8
+ const path_1 = require("path");
9
+ const os_1 = require("os");
10
+ // Mock runtime detection - default to Node.js environment
11
+ const { mockIsNodeLike, mockIsBrowserLike } = vitest_1.vi.hoisted(() => ({
12
+ mockIsNodeLike: vitest_1.vi.fn(() => true),
13
+ mockIsBrowserLike: vitest_1.vi.fn(() => false),
14
+ }));
15
+ vitest_1.vi.mock('../../lib/runtime.js', () => ({
16
+ isNodeLike: mockIsNodeLike,
17
+ isBrowserLike: mockIsBrowserLike,
18
+ isDeno: vitest_1.vi.fn(() => false),
19
+ }));
20
+ const ENV_KEYS = [
21
+ 'GALILEO_API_KEY',
22
+ 'GALILEO_CA_CERT_PATH',
23
+ 'SSL_CERT_FILE',
24
+ 'NODE_EXTRA_CA_CERTS',
25
+ 'GALILEO_CLIENT_CERT_PATH',
26
+ 'GALILEO_CLIENT_KEY_PATH',
27
+ 'GALILEO_REJECT_UNAUTHORIZED',
28
+ 'NODE_TLS_REJECT_UNAUTHORIZED',
29
+ ];
30
+ function clearEnv() {
31
+ for (const key of ENV_KEYS) {
32
+ delete process.env[key];
33
+ }
34
+ }
35
+ (0, vitest_1.describe)('CertManagementHook', () => {
36
+ let tmpDir;
37
+ let caCertPath;
38
+ let clientCertPath;
39
+ let clientKeyPath;
40
+ (0, vitest_1.beforeEach)(() => {
41
+ // Create temporary directory and test certificate files
42
+ tmpDir = (0, path_1.join)((0, os_1.tmpdir)(), `galileo-cert-test-${Date.now()}`);
43
+ (0, fs_1.mkdirSync)(tmpDir, { recursive: true });
44
+ caCertPath = (0, path_1.join)(tmpDir, 'ca.pem');
45
+ clientCertPath = (0, path_1.join)(tmpDir, 'client.pem');
46
+ clientKeyPath = (0, path_1.join)(tmpDir, 'key.pem');
47
+ (0, fs_1.writeFileSync)(caCertPath, '-----BEGIN CERTIFICATE-----\nMOCK_CA_CERT\n-----END CERTIFICATE-----');
48
+ (0, fs_1.writeFileSync)(clientCertPath, '-----BEGIN CERTIFICATE-----\nMOCK_CLIENT_CERT\n-----END CERTIFICATE-----');
49
+ (0, fs_1.writeFileSync)(clientKeyPath, '-----BEGIN PRIVATE KEY-----\nMOCK_PRIVATE_KEY\n-----END PRIVATE KEY-----');
50
+ // Default to Node.js environment
51
+ mockIsNodeLike.mockReturnValue(true);
52
+ mockIsBrowserLike.mockReturnValue(false);
53
+ });
54
+ (0, vitest_1.afterEach)(() => {
55
+ vitest_1.vi.clearAllMocks();
56
+ clearEnv();
57
+ galileo_config_js_1.GalileoConfig.reset();
58
+ // Clean up temporary directory
59
+ if (tmpDir) {
60
+ (0, fs_1.rmSync)(tmpDir, { recursive: true, force: true });
61
+ }
62
+ });
63
+ (0, vitest_1.describe)('sdkInit', () => {
64
+ (0, vitest_1.test)('test sdkInit returns httpClient when CA cert configured', () => {
65
+ galileo_config_js_1.GalileoConfig.reset();
66
+ galileo_config_js_1.GalileoConfig.get({
67
+ apiKey: 'test-key',
68
+ apiUrl: 'https://api.example.com',
69
+ caCertPath,
70
+ });
71
+ const hook = new cert_management_js_1.CertManagementHook();
72
+ const opts = { serverURL: 'https://api.example.com' };
73
+ const result = hook.sdkInit(opts);
74
+ (0, vitest_1.expect)(result.httpClient).toBeDefined();
75
+ (0, vitest_1.expect)(result.httpClient).not.toBe(opts.httpClient);
76
+ });
77
+ (0, vitest_1.test)('test sdkInit returns httpClient when CA cert content configured', () => {
78
+ galileo_config_js_1.GalileoConfig.reset();
79
+ galileo_config_js_1.GalileoConfig.get({
80
+ apiKey: 'test-key',
81
+ apiUrl: 'https://api.example.com',
82
+ caCertContent: '-----BEGIN CERTIFICATE-----\nMOCK_CONTENT\n-----END CERTIFICATE-----',
83
+ });
84
+ const hook = new cert_management_js_1.CertManagementHook();
85
+ const opts = { serverURL: 'https://api.example.com' };
86
+ const result = hook.sdkInit(opts);
87
+ (0, vitest_1.expect)(result.httpClient).toBeDefined();
88
+ });
89
+ (0, vitest_1.test)('test sdkInit returns httpClient with client certificates', () => {
90
+ galileo_config_js_1.GalileoConfig.reset();
91
+ galileo_config_js_1.GalileoConfig.get({
92
+ apiKey: 'test-key',
93
+ apiUrl: 'https://api.example.com',
94
+ caCertPath,
95
+ clientCertPath,
96
+ clientKeyPath,
97
+ });
98
+ const hook = new cert_management_js_1.CertManagementHook();
99
+ const opts = { serverURL: 'https://api.example.com' };
100
+ const result = hook.sdkInit(opts);
101
+ (0, vitest_1.expect)(result.httpClient).toBeDefined();
102
+ });
103
+ (0, vitest_1.test)('test sdkInit returns original opts when no cert configured', () => {
104
+ galileo_config_js_1.GalileoConfig.reset();
105
+ galileo_config_js_1.GalileoConfig.get({
106
+ apiKey: 'test-key',
107
+ apiUrl: 'https://api.example.com',
108
+ });
109
+ const hook = new cert_management_js_1.CertManagementHook();
110
+ const opts = { serverURL: 'https://api.example.com' };
111
+ const result = hook.sdkInit(opts);
112
+ (0, vitest_1.expect)(result).toBe(opts);
113
+ (0, vitest_1.expect)(result.httpClient).toBeUndefined();
114
+ });
115
+ (0, vitest_1.test)('test sdkInit augments existing httpClient instead of replacing it', async () => {
116
+ galileo_config_js_1.GalileoConfig.reset();
117
+ galileo_config_js_1.GalileoConfig.get({
118
+ apiKey: 'test-key',
119
+ apiUrl: 'https://api.example.com',
120
+ caCertPath,
121
+ });
122
+ const hook = new cert_management_js_1.CertManagementHook();
123
+ const mockFetcher = vitest_1.vi.fn().mockResolvedValue(new Response());
124
+ const existingClient = new http_js_1.HTTPClient({ fetcher: mockFetcher });
125
+ const opts = {
126
+ serverURL: 'https://api.example.com',
127
+ httpClient: existingClient,
128
+ };
129
+ const result = hook.sdkInit(opts);
130
+ (0, vitest_1.expect)(result.serverURL).toBe(opts.serverURL);
131
+ (0, vitest_1.expect)(result.httpClient).toBeDefined();
132
+ // Most important: the same httpClient instance is returned, not a new one
133
+ (0, vitest_1.expect)(result.httpClient).toBe(existingClient);
134
+ // Verify that the TLS hook was added by making a request
135
+ const req = new Request('https://api.example.com/test', { method: 'GET' });
136
+ await result.httpClient?.request(req);
137
+ // The custom fetcher should have been called
138
+ (0, vitest_1.expect)(mockFetcher).toHaveBeenCalledTimes(1);
139
+ const callArgs = mockFetcher.mock.calls[0];
140
+ (0, vitest_1.expect)(callArgs).toBeDefined();
141
+ if (!callArgs)
142
+ throw new Error('unreachable');
143
+ const [calledReq] = callArgs;
144
+ // Verify dispatcher was injected into the request
145
+ (0, vitest_1.expect)(calledReq).toBeInstanceOf(Request);
146
+ (0, vitest_1.expect)(calledReq.url).toBe('https://api.example.com/test');
147
+ });
148
+ (0, vitest_1.test)('test sdkInit skips cert loading in browser environment', () => {
149
+ mockIsNodeLike.mockReturnValue(false);
150
+ mockIsBrowserLike.mockReturnValue(true);
151
+ galileo_config_js_1.GalileoConfig.reset();
152
+ galileo_config_js_1.GalileoConfig.get({
153
+ apiKey: 'test-key',
154
+ apiUrl: 'https://api.example.com',
155
+ caCertPath,
156
+ });
157
+ const hook = new cert_management_js_1.CertManagementHook();
158
+ const opts = { serverURL: 'https://api.example.com' };
159
+ const result = hook.sdkInit(opts);
160
+ (0, vitest_1.expect)(result).toBe(opts);
161
+ (0, vitest_1.expect)(result.httpClient).toBeUndefined();
162
+ });
163
+ (0, vitest_1.test)('test sdkInit returns original opts when CA cert file missing', () => {
164
+ galileo_config_js_1.GalileoConfig.reset();
165
+ galileo_config_js_1.GalileoConfig.get({
166
+ apiKey: 'test-key',
167
+ apiUrl: 'https://api.example.com',
168
+ caCertPath: '/nonexistent/ca.pem',
169
+ });
170
+ const hook = new cert_management_js_1.CertManagementHook();
171
+ const opts = { serverURL: 'https://api.example.com' };
172
+ const result = hook.sdkInit(opts);
173
+ // When cert file is missing, no httpClient should be configured
174
+ (0, vitest_1.expect)(result).toBe(opts);
175
+ (0, vitest_1.expect)(result.httpClient).toBeUndefined();
176
+ });
177
+ (0, vitest_1.test)('test sdkInit returns original opts when client key file missing', () => {
178
+ galileo_config_js_1.GalileoConfig.reset();
179
+ galileo_config_js_1.GalileoConfig.get({
180
+ apiKey: 'test-key',
181
+ apiUrl: 'https://api.example.com',
182
+ caCertPath,
183
+ clientCertPath,
184
+ clientKeyPath: '/nonexistent/key.pem',
185
+ });
186
+ const hook = new cert_management_js_1.CertManagementHook();
187
+ const opts = { serverURL: 'https://api.example.com' };
188
+ const result = hook.sdkInit(opts);
189
+ (0, vitest_1.expect)(result).toBe(opts);
190
+ (0, vitest_1.expect)(result.httpClient).toBeUndefined();
191
+ });
192
+ (0, vitest_1.test)('test sdkInit returns original opts when only client cert configured', () => {
193
+ galileo_config_js_1.GalileoConfig.reset();
194
+ galileo_config_js_1.GalileoConfig.get({
195
+ apiKey: 'test-key',
196
+ apiUrl: 'https://api.example.com',
197
+ caCertPath,
198
+ clientCertPath,
199
+ });
200
+ const hook = new cert_management_js_1.CertManagementHook();
201
+ const opts = { serverURL: 'https://api.example.com' };
202
+ const result = hook.sdkInit(opts);
203
+ // When only client cert is provided (missing key), should return original opts
204
+ (0, vitest_1.expect)(result).toBe(opts);
205
+ (0, vitest_1.expect)(result.httpClient).toBeUndefined();
206
+ });
207
+ (0, vitest_1.test)('test sdkInit returns original opts when only client key configured', () => {
208
+ galileo_config_js_1.GalileoConfig.reset();
209
+ galileo_config_js_1.GalileoConfig.get({
210
+ apiKey: 'test-key',
211
+ apiUrl: 'https://api.example.com',
212
+ caCertPath,
213
+ clientKeyPath,
214
+ });
215
+ const hook = new cert_management_js_1.CertManagementHook();
216
+ const opts = { serverURL: 'https://api.example.com' };
217
+ const result = hook.sdkInit(opts);
218
+ // When only client key is provided (missing cert), should return original opts
219
+ (0, vitest_1.expect)(result).toBe(opts);
220
+ (0, vitest_1.expect)(result.httpClient).toBeUndefined();
221
+ });
222
+ (0, vitest_1.test)('test sdkInit returns original opts when client cert file missing', () => {
223
+ galileo_config_js_1.GalileoConfig.reset();
224
+ galileo_config_js_1.GalileoConfig.get({
225
+ apiKey: 'test-key',
226
+ apiUrl: 'https://api.example.com',
227
+ caCertPath,
228
+ clientCertPath: '/nonexistent/cert.pem',
229
+ clientKeyPath,
230
+ });
231
+ const hook = new cert_management_js_1.CertManagementHook();
232
+ const opts = { serverURL: 'https://api.example.com' };
233
+ const result = hook.sdkInit(opts);
234
+ (0, vitest_1.expect)(result).toBe(opts);
235
+ (0, vitest_1.expect)(result.httpClient).toBeUndefined();
236
+ });
237
+ });
238
+ (0, vitest_1.describe)('environment variable priority', () => {
239
+ (0, vitest_1.test)('test GALILEO_CA_CERT_PATH from env is used', () => {
240
+ galileo_config_js_1.GalileoConfig.reset();
241
+ process.env['GALILEO_API_KEY'] = 'env-key';
242
+ process.env['GALILEO_CA_CERT_PATH'] = caCertPath;
243
+ const config = galileo_config_js_1.GalileoConfig.get({});
244
+ const cert = config.getCertConfig();
245
+ (0, vitest_1.expect)(cert).not.toBeNull();
246
+ if (!cert)
247
+ throw new Error("unreachable");
248
+ (0, vitest_1.expect)(cert.caCertPath).toBe(caCertPath);
249
+ });
250
+ (0, vitest_1.test)('test only GALILEO_CA_CERT_PATH is supported for CA cert from env', () => {
251
+ galileo_config_js_1.GalileoConfig.reset();
252
+ process.env['GALILEO_API_KEY'] = 'env-key';
253
+ process.env['SSL_CERT_FILE'] = caCertPath;
254
+ const config = galileo_config_js_1.GalileoConfig.get({});
255
+ const cert = config.getCertConfig();
256
+ (0, vitest_1.expect)(cert).toBeNull();
257
+ });
258
+ (0, vitest_1.test)('test only GALILEO_CA_CERT_PATH is supported not NODE_EXTRA_CA_CERTS', () => {
259
+ galileo_config_js_1.GalileoConfig.reset();
260
+ process.env['GALILEO_API_KEY'] = 'env-key';
261
+ process.env['NODE_EXTRA_CA_CERTS'] = caCertPath;
262
+ const config = galileo_config_js_1.GalileoConfig.get({});
263
+ const cert = config.getCertConfig();
264
+ (0, vitest_1.expect)(cert).toBeNull();
265
+ });
266
+ });
267
+ (0, vitest_1.describe)('client certificate environment variables', () => {
268
+ (0, vitest_1.test)('test GALILEO_CLIENT_CERT_PATH and GALILEO_CLIENT_KEY_PATH from env', () => {
269
+ galileo_config_js_1.GalileoConfig.reset();
270
+ process.env['GALILEO_API_KEY'] = 'env-key';
271
+ process.env['GALILEO_CA_CERT_PATH'] = caCertPath;
272
+ process.env['GALILEO_CLIENT_CERT_PATH'] = clientCertPath;
273
+ process.env['GALILEO_CLIENT_KEY_PATH'] = clientKeyPath;
274
+ const config = galileo_config_js_1.GalileoConfig.get({});
275
+ const cert = config.getCertConfig();
276
+ (0, vitest_1.expect)(cert).not.toBeNull();
277
+ if (!cert)
278
+ throw new Error("unreachable");
279
+ (0, vitest_1.expect)(cert.clientCertPath).toBe(clientCertPath);
280
+ (0, vitest_1.expect)(cert.clientKeyPath).toBe(clientKeyPath);
281
+ });
282
+ });
283
+ (0, vitest_1.describe)('rejectUnauthorized configuration', () => {
284
+ (0, vitest_1.test)('test GALILEO_REJECT_UNAUTHORIZED takes priority over NODE_TLS_REJECT_UNAUTHORIZED', () => {
285
+ galileo_config_js_1.GalileoConfig.reset();
286
+ process.env['GALILEO_API_KEY'] = 'env-key';
287
+ process.env['GALILEO_CA_CERT_PATH'] = caCertPath;
288
+ process.env['GALILEO_REJECT_UNAUTHORIZED'] = 'false';
289
+ process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '1';
290
+ const config = galileo_config_js_1.GalileoConfig.get({});
291
+ const cert = config.getCertConfig();
292
+ (0, vitest_1.expect)(cert).not.toBeNull();
293
+ if (!cert)
294
+ throw new Error("unreachable");
295
+ (0, vitest_1.expect)(cert.rejectUnauthorized).toBe(false);
296
+ });
297
+ (0, vitest_1.test)('test NODE_TLS_REJECT_UNAUTHORIZED used when GALILEO_REJECT_UNAUTHORIZED absent', () => {
298
+ galileo_config_js_1.GalileoConfig.reset();
299
+ process.env['GALILEO_API_KEY'] = 'env-key';
300
+ process.env['GALILEO_CA_CERT_PATH'] = caCertPath;
301
+ process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
302
+ const config = galileo_config_js_1.GalileoConfig.get({});
303
+ const cert = config.getCertConfig();
304
+ (0, vitest_1.expect)(cert).not.toBeNull();
305
+ if (!cert)
306
+ throw new Error("unreachable");
307
+ (0, vitest_1.expect)(cert.rejectUnauthorized).toBe(false);
308
+ });
309
+ (0, vitest_1.test)('test rejectUnauthorized defaults to true when no env vars set', () => {
310
+ galileo_config_js_1.GalileoConfig.reset();
311
+ const config = galileo_config_js_1.GalileoConfig.get({
312
+ apiKey: 'test-key',
313
+ apiUrl: 'https://api.example.com',
314
+ caCertPath,
315
+ });
316
+ const cert = config.getCertConfig();
317
+ (0, vitest_1.expect)(cert).not.toBeNull();
318
+ if (!cert)
319
+ throw new Error("unreachable");
320
+ // rejectUnauthorized is undefined in config, defaults to true in hook
321
+ (0, vitest_1.expect)(cert.rejectUnauthorized).toBeUndefined();
322
+ });
323
+ (0, vitest_1.test)('test sdkInit configures agent with custom CA cert even when rejectUnauthorized is true', () => {
324
+ galileo_config_js_1.GalileoConfig.reset();
325
+ galileo_config_js_1.GalileoConfig.get({
326
+ apiKey: 'test-key',
327
+ apiUrl: 'https://api.example.com',
328
+ caCertPath,
329
+ rejectUnauthorized: true,
330
+ });
331
+ const hook = new cert_management_js_1.CertManagementHook();
332
+ const opts = { serverURL: 'https://api.example.com' };
333
+ const result = hook.sdkInit(opts);
334
+ // Custom CA cert should be configured regardless of rejectUnauthorized value
335
+ // rejectUnauthorized=true means strict validation with custom CA; this is a valid configuration
336
+ (0, vitest_1.expect)(result.httpClient).toBeDefined();
337
+ (0, vitest_1.expect)(result.httpClient).not.toBe(opts.httpClient);
338
+ });
339
+ (0, vitest_1.test)('test rejectUnauthorized false is passed to connectOptions', () => {
340
+ galileo_config_js_1.GalileoConfig.reset();
341
+ galileo_config_js_1.GalileoConfig.get({
342
+ apiKey: 'test-key',
343
+ apiUrl: 'https://api.example.com',
344
+ caCertPath,
345
+ rejectUnauthorized: false,
346
+ });
347
+ const hook = new cert_management_js_1.CertManagementHook();
348
+ const opts = { serverURL: 'https://api.example.com' };
349
+ const result = hook.sdkInit(opts);
350
+ (0, vitest_1.expect)(result.httpClient).toBeDefined();
351
+ (0, vitest_1.expect)(result.httpClient).not.toBe(opts.httpClient);
352
+ });
353
+ });
354
+ (0, vitest_1.describe)('CertAgent availability', () => {
355
+ (0, vitest_1.test)('test sdkInit returns original opts when CertAgent is unavailable', () => {
356
+ // Mock isNodeLike to return true but simulate missing undici by not being in Node-like environment for Agent
357
+ // This tests the guard at line 53: if (!isNodeLike() || !CertAgent)
358
+ galileo_config_js_1.GalileoConfig.reset();
359
+ galileo_config_js_1.GalileoConfig.get({
360
+ apiKey: 'test-key',
361
+ apiUrl: 'https://api.example.com',
362
+ caCertPath,
363
+ });
364
+ // Simulate CertAgent being undefined by mocking the module reload scenario
365
+ const hook = new cert_management_js_1.CertManagementHook();
366
+ const opts = { serverURL: 'https://api.example.com' };
367
+ // This test verifies that even with valid config, if CertAgent is not available,
368
+ // the hook gracefully returns original opts
369
+ // Note: In real scenario, CertAgent would be undefined if undici import fails
370
+ const result = hook.sdkInit(opts);
371
+ // If undici is available (which it should be in test environment), httpClient should be created
372
+ // If undici is not available, result should be opts
373
+ (0, vitest_1.expect)(result).toBeDefined();
374
+ (0, vitest_1.expect)(result.serverURL).toBe(opts.serverURL);
375
+ });
376
+ });
377
+ (0, vitest_1.describe)('integration - certificate mechanism', () => {
378
+ (0, vitest_1.test)('test TLS hook is added via beforeRequest hook', async () => {
379
+ galileo_config_js_1.GalileoConfig.reset();
380
+ galileo_config_js_1.GalileoConfig.get({
381
+ apiKey: 'test-key',
382
+ apiUrl: 'https://api.example.com',
383
+ caCertPath,
384
+ });
385
+ const hook = new cert_management_js_1.CertManagementHook();
386
+ const mockFetcher = vitest_1.vi.fn().mockResolvedValue(new Response('OK'));
387
+ const httpClient = new http_js_1.HTTPClient({ fetcher: mockFetcher });
388
+ const opts = { httpClient };
389
+ const result = hook.sdkInit(opts);
390
+ (0, vitest_1.expect)(result.httpClient).toBe(httpClient);
391
+ // Make a GET request (no body) through the augmented client
392
+ const request = new Request('https://api.example.com/test', {
393
+ method: 'GET',
394
+ headers: { 'Content-Type': 'application/json' },
395
+ });
396
+ const response = await result.httpClient?.request(request);
397
+ // Verify the custom fetcher was called
398
+ (0, vitest_1.expect)(mockFetcher).toHaveBeenCalledTimes(1);
399
+ const callArgs = mockFetcher.mock.calls[0];
400
+ (0, vitest_1.expect)(callArgs).toBeDefined();
401
+ if (!callArgs)
402
+ throw new Error('unreachable');
403
+ const [calledReq] = callArgs;
404
+ // Verify the request properties are preserved
405
+ (0, vitest_1.expect)(calledReq).toBeInstanceOf(Request);
406
+ (0, vitest_1.expect)(calledReq.url).toBe('https://api.example.com/test');
407
+ (0, vitest_1.expect)(calledReq.method).toBe('GET');
408
+ (0, vitest_1.expect)(calledReq.headers.get('Content-Type')).toBe('application/json');
409
+ // Verify response was returned
410
+ (0, vitest_1.expect)(response?.status).toBe(200);
411
+ });
412
+ (0, vitest_1.test)('test httpClient uses undici dispatcher with certificates', async () => {
413
+ galileo_config_js_1.GalileoConfig.reset();
414
+ galileo_config_js_1.GalileoConfig.get({
415
+ apiKey: 'test-key',
416
+ apiUrl: 'https://api.example.com',
417
+ caCertPath,
418
+ });
419
+ const hook = new cert_management_js_1.CertManagementHook();
420
+ // Use a custom fetcher that captures what it receives
421
+ let receivedRequest = null;
422
+ const testFetcher = vitest_1.vi.fn(async (input, _init) => {
423
+ if (input instanceof Request) {
424
+ receivedRequest = input;
425
+ }
426
+ return new Response(JSON.stringify({ success: true }), {
427
+ status: 200,
428
+ headers: { 'Content-Type': 'application/json' },
429
+ });
430
+ });
431
+ const httpClient = new http_js_1.HTTPClient({ fetcher: testFetcher });
432
+ const opts = { httpClient };
433
+ const result = hook.sdkInit(opts);
434
+ (0, vitest_1.expect)(result.httpClient).toBeDefined();
435
+ // Make a request using the httpClient
436
+ const request = new Request('https://api.example.com/test', {
437
+ method: 'GET',
438
+ headers: { 'Content-Type': 'application/json' },
439
+ });
440
+ await result.httpClient?.request(request);
441
+ // Verify the custom fetcher was called
442
+ (0, vitest_1.expect)(testFetcher).toHaveBeenCalledTimes(1);
443
+ (0, vitest_1.expect)(receivedRequest).toBeDefined();
444
+ // The hook should have transformed the request
445
+ if (!receivedRequest)
446
+ throw new Error('unreachable');
447
+ (0, vitest_1.expect)(receivedRequest).toBeInstanceOf(Request);
448
+ (0, vitest_1.expect)(receivedRequest.url).toBe('https://api.example.com/test');
449
+ });
450
+ (0, vitest_1.test)('test httpClient with certificates can make successful requests', async () => {
451
+ galileo_config_js_1.GalileoConfig.reset();
452
+ galileo_config_js_1.GalileoConfig.get({
453
+ apiKey: 'test-key',
454
+ apiUrl: 'https://api.example.com',
455
+ caCertPath,
456
+ rejectUnauthorized: false, // For testing purposes
457
+ });
458
+ const hook = new cert_management_js_1.CertManagementHook();
459
+ const opts = { serverURL: 'https://api.example.com' };
460
+ const result = hook.sdkInit(opts);
461
+ (0, vitest_1.expect)(result.httpClient).toBeDefined();
462
+ // Mock successful response
463
+ const mockResponse = new Response(JSON.stringify({ data: 'test' }), {
464
+ status: 200,
465
+ headers: { 'Content-Type': 'application/json' },
466
+ });
467
+ const fetchSpy = vitest_1.vi.spyOn(globalThis, 'fetch').mockResolvedValue(mockResponse);
468
+ // Make a GET request (no body)
469
+ const request = new Request('https://api.example.com/endpoint', {
470
+ method: 'GET',
471
+ headers: { 'Content-Type': 'application/json' },
472
+ });
473
+ const response = await result.httpClient?.request(request);
474
+ // Verify request succeeded
475
+ (0, vitest_1.expect)(response).toBeDefined();
476
+ (0, vitest_1.expect)(response?.status).toBe(200);
477
+ (0, vitest_1.expect)(fetchSpy).toHaveBeenCalled();
478
+ fetchSpy.mockRestore();
479
+ });
480
+ (0, vitest_1.test)('test httpClient created with mTLS configuration without CA cert', async () => {
481
+ galileo_config_js_1.GalileoConfig.reset();
482
+ galileo_config_js_1.GalileoConfig.get({
483
+ apiKey: 'test-key',
484
+ apiUrl: 'https://api.example.com',
485
+ clientCertPath,
486
+ clientKeyPath,
487
+ });
488
+ const hook = new cert_management_js_1.CertManagementHook();
489
+ const mockFetcher = vitest_1.vi.fn().mockResolvedValue(new Response(JSON.stringify({ success: true }), { status: 200 }));
490
+ const httpClient = new http_js_1.HTTPClient({ fetcher: mockFetcher });
491
+ const opts = { httpClient };
492
+ const result = hook.sdkInit(opts);
493
+ (0, vitest_1.expect)(result.httpClient).toBeDefined();
494
+ // With augmentation approach, same instance is returned
495
+ (0, vitest_1.expect)(result.httpClient).toBe(opts.httpClient);
496
+ // Verify the httpClient can make requests with the configured certificates
497
+ const request = new Request('https://api.example.com/test', {
498
+ method: 'GET',
499
+ });
500
+ await result.httpClient?.request(request);
501
+ (0, vitest_1.expect)(mockFetcher).toHaveBeenCalledTimes(1);
502
+ const callArgs = mockFetcher.mock.calls[0];
503
+ (0, vitest_1.expect)(callArgs).toBeDefined();
504
+ if (!callArgs)
505
+ throw new Error('unreachable');
506
+ const [calledReq] = callArgs;
507
+ (0, vitest_1.expect)(calledReq).toBeInstanceOf(Request);
508
+ (0, vitest_1.expect)(calledReq.url).toBe('https://api.example.com/test');
509
+ });
510
+ (0, vitest_1.test)('test sdkInit returns original opts when no meaningful TLS customization', () => {
511
+ galileo_config_js_1.GalileoConfig.reset();
512
+ galileo_config_js_1.GalileoConfig.get({
513
+ apiKey: 'test-key',
514
+ apiUrl: 'https://api.example.com',
515
+ rejectUnauthorized: true,
516
+ });
517
+ const hook = new cert_management_js_1.CertManagementHook();
518
+ const opts = { serverURL: 'https://api.example.com' };
519
+ const result = hook.sdkInit(opts);
520
+ // When only rejectUnauthorized=true is set (no CA/client certs), hasCertCustomization is false
521
+ // because hasCertCustomization requires CA, cert, key, or rejectUnauthorized === false (line 118)
522
+ (0, vitest_1.expect)(result).toBe(opts);
523
+ (0, vitest_1.expect)(result.httpClient).toBeUndefined();
524
+ });
525
+ (0, vitest_1.test)('test sdkInit configures mTLS with client certs even when rejectUnauthorized is true', () => {
526
+ galileo_config_js_1.GalileoConfig.reset();
527
+ galileo_config_js_1.GalileoConfig.get({
528
+ apiKey: 'test-key',
529
+ apiUrl: 'https://api.example.com',
530
+ clientCertPath,
531
+ clientKeyPath,
532
+ rejectUnauthorized: true,
533
+ });
534
+ const hook = new cert_management_js_1.CertManagementHook();
535
+ const opts = { serverURL: 'https://api.example.com' };
536
+ const result = hook.sdkInit(opts);
537
+ // mTLS client certs should be configured regardless of rejectUnauthorized value
538
+ // rejectUnauthorized and custom certs are orthogonal concerns
539
+ (0, vitest_1.expect)(result.httpClient).toBeDefined();
540
+ });
541
+ });
542
+ (0, vitest_1.describe)('user hook preservation', () => {
543
+ (0, vitest_1.test)('test user-registered hooks are preserved when TLS is configured', async () => {
544
+ galileo_config_js_1.GalileoConfig.reset();
545
+ galileo_config_js_1.GalileoConfig.get({
546
+ apiKey: 'test-key',
547
+ apiUrl: 'https://api.example.com',
548
+ caCertPath,
549
+ });
550
+ let userHookCalled = false;
551
+ const mockFetcher = vitest_1.vi.fn().mockResolvedValue(new Response('OK'));
552
+ const userClient = new http_js_1.HTTPClient({ fetcher: mockFetcher });
553
+ userClient.addHook('beforeRequest', (req) => {
554
+ userHookCalled = true;
555
+ // User hook can modify headers
556
+ const newReq = new Request(req.url, {
557
+ method: req.method,
558
+ headers: req.headers,
559
+ body: req.body,
560
+ });
561
+ newReq.headers.set('X-Custom-Header', 'user-value');
562
+ return newReq;
563
+ });
564
+ const hook = new cert_management_js_1.CertManagementHook();
565
+ const opts = { httpClient: userClient };
566
+ const result = hook.sdkInit(opts);
567
+ const request = new Request('https://api.example.com/test', {
568
+ method: 'GET',
569
+ });
570
+ await result.httpClient?.request(request);
571
+ // Verify user hook was called
572
+ (0, vitest_1.expect)(userHookCalled).toBe(true);
573
+ // Verify the custom fetcher was called
574
+ (0, vitest_1.expect)(mockFetcher).toHaveBeenCalledTimes(1);
575
+ const callArgs = mockFetcher.mock.calls[0];
576
+ (0, vitest_1.expect)(callArgs).toBeDefined();
577
+ if (!callArgs)
578
+ throw new Error('unreachable');
579
+ const [calledReq] = callArgs;
580
+ // Verify user's header was preserved in the final request
581
+ (0, vitest_1.expect)(calledReq).toBeInstanceOf(Request);
582
+ (0, vitest_1.expect)(calledReq.headers.get('X-Custom-Header')).toBe('user-value');
583
+ });
584
+ (0, vitest_1.test)('test TLS hook runs after user hooks', async () => {
585
+ galileo_config_js_1.GalileoConfig.reset();
586
+ galileo_config_js_1.GalileoConfig.get({
587
+ apiKey: 'test-key',
588
+ apiUrl: 'https://api.example.com',
589
+ caCertPath,
590
+ });
591
+ const callOrder = [];
592
+ const userClient = new http_js_1.HTTPClient();
593
+ userClient.addHook('beforeRequest', (req) => {
594
+ callOrder.push('user-hook');
595
+ return req;
596
+ });
597
+ const hook = new cert_management_js_1.CertManagementHook();
598
+ const opts = { httpClient: userClient };
599
+ const result = hook.sdkInit(opts);
600
+ // Mock fetch to capture when it's called
601
+ const fetchSpy = vitest_1.vi.spyOn(globalThis, 'fetch').mockImplementation(async () => {
602
+ callOrder.push('fetch');
603
+ return new Response('OK');
604
+ });
605
+ const request = new Request('https://api.example.com/test', {
606
+ method: 'GET',
607
+ });
608
+ await result.httpClient?.request(request);
609
+ // User hook should run before fetch (and before TLS hook which is closest to fetch)
610
+ (0, vitest_1.expect)(callOrder).toEqual(['user-hook', 'fetch']);
611
+ fetchSpy.mockRestore();
612
+ });
613
+ (0, vitest_1.test)('test multiple user hooks are all executed with TLS', async () => {
614
+ galileo_config_js_1.GalileoConfig.reset();
615
+ galileo_config_js_1.GalileoConfig.get({
616
+ apiKey: 'test-key',
617
+ apiUrl: 'https://api.example.com',
618
+ caCertPath,
619
+ });
620
+ const mockFetcher = vitest_1.vi.fn().mockResolvedValue(new Response('OK'));
621
+ const userClient = new http_js_1.HTTPClient({ fetcher: mockFetcher });
622
+ const calls = [];
623
+ userClient.addHook('beforeRequest', (req) => {
624
+ calls.push('hook1');
625
+ return req;
626
+ });
627
+ userClient.addHook('beforeRequest', (req) => {
628
+ calls.push('hook2');
629
+ return req;
630
+ });
631
+ const hook = new cert_management_js_1.CertManagementHook();
632
+ const opts = { httpClient: userClient };
633
+ const result = hook.sdkInit(opts);
634
+ const request = new Request('https://api.example.com/test', {
635
+ method: 'GET',
636
+ });
637
+ await result.httpClient?.request(request);
638
+ // Both user hooks should be called
639
+ (0, vitest_1.expect)(calls).toContain('hook1');
640
+ (0, vitest_1.expect)(calls).toContain('hook2');
641
+ // And the fetcher should be called with a request
642
+ (0, vitest_1.expect)(mockFetcher).toHaveBeenCalled();
643
+ const callArgs = mockFetcher.mock.calls[0];
644
+ (0, vitest_1.expect)(callArgs).toBeDefined();
645
+ if (!callArgs)
646
+ throw new Error('unreachable');
647
+ const [calledReq] = callArgs;
648
+ (0, vitest_1.expect)(calledReq).toBeInstanceOf(Request);
649
+ });
650
+ });
651
+ (0, vitest_1.describe)('request body handling', () => {
652
+ (0, vitest_1.test)('test TLS hook preserves request headers and url', async () => {
653
+ galileo_config_js_1.GalileoConfig.reset();
654
+ galileo_config_js_1.GalileoConfig.get({
655
+ apiKey: 'test-key',
656
+ apiUrl: 'https://api.example.com',
657
+ caCertPath,
658
+ });
659
+ const hook = new cert_management_js_1.CertManagementHook();
660
+ const opts = {};
661
+ const result = hook.sdkInit(opts);
662
+ const fetchSpy = vitest_1.vi.spyOn(globalThis, 'fetch').mockResolvedValue(new Response('OK'));
663
+ const request = new Request('https://api.example.com/test', {
664
+ method: 'GET',
665
+ headers: { 'X-Custom': 'value', 'Content-Type': 'application/json' },
666
+ });
667
+ await result.httpClient?.request(request);
668
+ (0, vitest_1.expect)(fetchSpy).toHaveBeenCalledTimes(1);
669
+ const callArgs = fetchSpy.mock.calls[0];
670
+ (0, vitest_1.expect)(callArgs).toBeDefined();
671
+ if (!callArgs)
672
+ throw new Error('unreachable');
673
+ const [calledReq] = callArgs;
674
+ (0, vitest_1.expect)(calledReq.url).toBe('https://api.example.com/test');
675
+ (0, vitest_1.expect)(calledReq.headers.get('X-Custom')).toBe('value');
676
+ (0, vitest_1.expect)(calledReq.headers.get('Content-Type')).toBe('application/json');
677
+ fetchSpy.mockRestore();
678
+ });
679
+ });
680
+ (0, vitest_1.describe)('runtime version detection and warnings', () => {
681
+ (0, vitest_1.test)('test version detection correctly identifies supported Node.js versions', () => {
682
+ galileo_config_js_1.GalileoConfig.reset();
683
+ galileo_config_js_1.GalileoConfig.get({
684
+ apiKey: 'test-key',
685
+ apiUrl: 'https://api.example.com',
686
+ caCertPath,
687
+ });
688
+ const hook = new cert_management_js_1.CertManagementHook();
689
+ // Access the private method via type casting for testing
690
+ const hookAny = hook;
691
+ // Test various version strings
692
+ (0, vitest_1.expect)(hookAny.isNodeVersionSupported('20.18.0')).toBe(false); // Minor < 18
693
+ (0, vitest_1.expect)(hookAny.isNodeVersionSupported('20.18.1')).toBe(true); // Exact minimum
694
+ (0, vitest_1.expect)(hookAny.isNodeVersionSupported('20.19.0')).toBe(true); // Minor > 18
695
+ (0, vitest_1.expect)(hookAny.isNodeVersionSupported('21.0.0')).toBe(true); // Major > 20
696
+ (0, vitest_1.expect)(hookAny.isNodeVersionSupported('22.5.0')).toBe(true); // Much newer
697
+ (0, vitest_1.expect)(hookAny.isNodeVersionSupported('19.10.0')).toBe(false); // Too old
698
+ });
699
+ (0, vitest_1.test)('test version string parsing handles various formats', () => {
700
+ galileo_config_js_1.GalileoConfig.reset();
701
+ galileo_config_js_1.GalileoConfig.get({
702
+ apiKey: 'test-key',
703
+ apiUrl: 'https://api.example.com',
704
+ caCertPath,
705
+ });
706
+ const hook = new cert_management_js_1.CertManagementHook();
707
+ const hookAny = hook;
708
+ // Test edge cases
709
+ (0, vitest_1.expect)(hookAny.isNodeVersionSupported('20')).toBe(false); // No minor version (defaults to 0)
710
+ (0, vitest_1.expect)(hookAny.isNodeVersionSupported('20.18')).toBe(false); // No patch version (defaults to 0, which is < 1)
711
+ (0, vitest_1.expect)(hookAny.isNodeVersionSupported('20.19')).toBe(true); // Minor > 18
712
+ // Note: parseInt('invalid') returns NaN, but parts[0] would be NaN which !== undefined
713
+ // so the check major === undefined won't catch it. It would return false.
714
+ // For truly invalid versions, they'd fail the >= check anyway
715
+ (0, vitest_1.expect)(hookAny.isNodeVersionSupported('')).toBe(true); // Empty string → optimistic
716
+ });
717
+ (0, vitest_1.test)('test Node.js version extraction from process.versions', () => {
718
+ galileo_config_js_1.GalileoConfig.reset();
719
+ galileo_config_js_1.GalileoConfig.get({
720
+ apiKey: 'test-key',
721
+ apiUrl: 'https://api.example.com',
722
+ caCertPath,
723
+ });
724
+ const hook = new cert_management_js_1.CertManagementHook();
725
+ const hookAny = hook;
726
+ // Get the actual Node version
727
+ const version = hookAny.getNodeVersion();
728
+ // Verify we got a version string (or null in non-Node environments)
729
+ if (version !== null) {
730
+ (0, vitest_1.expect)(typeof version).toBe('string');
731
+ (0, vitest_1.expect)(version.length).toBeGreaterThan(0);
732
+ }
733
+ });
734
+ });
735
+ (0, vitest_1.describe)('dispatcher integration', () => {
736
+ (0, vitest_1.test)('test dispatcher is passed correctly through the request chain', async () => {
737
+ galileo_config_js_1.GalileoConfig.reset();
738
+ galileo_config_js_1.GalileoConfig.get({
739
+ apiKey: 'test-key',
740
+ apiUrl: 'https://api.example.com',
741
+ caCertPath,
742
+ });
743
+ const hook = new cert_management_js_1.CertManagementHook();
744
+ const mockFetcher = vitest_1.vi.fn().mockResolvedValue(new Response('OK'));
745
+ const httpClient = new http_js_1.HTTPClient({ fetcher: mockFetcher });
746
+ const opts = { httpClient };
747
+ const result = hook.sdkInit(opts);
748
+ const request = new Request('https://api.example.com/test', {
749
+ method: 'GET',
750
+ });
751
+ await result.httpClient?.request(request);
752
+ (0, vitest_1.expect)(mockFetcher).toHaveBeenCalledTimes(1);
753
+ const callArgs = mockFetcher.mock.calls[0];
754
+ (0, vitest_1.expect)(callArgs).toBeDefined();
755
+ if (!callArgs)
756
+ throw new Error('unreachable');
757
+ const [calledReq] = callArgs;
758
+ // Dispatcher should be attached to the request object
759
+ // (In a real Node.js environment with undici, this would be used by fetch)
760
+ (0, vitest_1.expect)(calledReq).toBeInstanceOf(Request);
761
+ // Verify it's a proper Request with all properties
762
+ (0, vitest_1.expect)(calledReq.url).toBeDefined();
763
+ (0, vitest_1.expect)(calledReq.method).toBeDefined();
764
+ (0, vitest_1.expect)(calledReq.headers).toBeDefined();
765
+ });
766
+ (0, vitest_1.test)('test TLS hook creates new Request instances', async () => {
767
+ galileo_config_js_1.GalileoConfig.reset();
768
+ galileo_config_js_1.GalileoConfig.get({
769
+ apiKey: 'test-key',
770
+ apiUrl: 'https://api.example.com',
771
+ caCertPath,
772
+ });
773
+ const hook = new cert_management_js_1.CertManagementHook();
774
+ const mockFetcher = vitest_1.vi.fn().mockResolvedValue(new Response('OK'));
775
+ const httpClient = new http_js_1.HTTPClient({ fetcher: mockFetcher });
776
+ const opts = { httpClient };
777
+ const result = hook.sdkInit(opts);
778
+ const originalRequest = new Request('https://api.example.com/test', {
779
+ method: 'GET',
780
+ });
781
+ await result.httpClient?.request(originalRequest);
782
+ (0, vitest_1.expect)(mockFetcher).toHaveBeenCalledTimes(1);
783
+ const callArgs = mockFetcher.mock.calls[0];
784
+ (0, vitest_1.expect)(callArgs).toBeDefined();
785
+ if (!callArgs)
786
+ throw new Error('unreachable');
787
+ const [calledReq] = callArgs;
788
+ // The request passed to the fetcher should be a new instance
789
+ // (Request objects are immutable, so the hook creates a new one)
790
+ (0, vitest_1.expect)(calledReq).not.toBe(originalRequest);
791
+ });
792
+ });
793
+ });
794
+ //# sourceMappingURL=cert-management.test.js.map