@venizia/ignis-docs 0.2.0 → 0.2.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 (142) hide show
  1. package/README.md +14 -14
  2. package/content/best-practices/api-usage-examples.md +39 -19
  3. package/content/best-practices/architectural-patterns.md +22 -11
  4. package/content/best-practices/architecture-decisions.md +29 -16
  5. package/content/best-practices/code-style-standards/advanced-patterns.md +43 -31
  6. package/content/best-practices/code-style-standards/constants-configuration.md +19 -4
  7. package/content/best-practices/code-style-standards/control-flow.md +33 -1
  8. package/content/best-practices/code-style-standards/documentation.md +28 -8
  9. package/content/best-practices/code-style-standards/function-patterns.md +15 -4
  10. package/content/best-practices/code-style-standards/index.md +7 -2
  11. package/content/best-practices/code-style-standards/naming-conventions.md +26 -2
  12. package/content/best-practices/code-style-standards/route-definitions.md +9 -5
  13. package/content/best-practices/code-style-standards/tooling.md +14 -1
  14. package/content/best-practices/code-style-standards/type-safety.md +39 -6
  15. package/content/best-practices/common-pitfalls.md +59 -35
  16. package/content/best-practices/contribution-workflow.md +6 -2
  17. package/content/best-practices/data-modeling.md +78 -62
  18. package/content/best-practices/deployment-strategies.md +56 -19
  19. package/content/best-practices/error-handling.md +182 -93
  20. package/content/best-practices/index.md +6 -0
  21. package/content/best-practices/performance-optimization.md +26 -13
  22. package/content/best-practices/security-guidelines.md +35 -9
  23. package/content/best-practices/testing-strategies.md +7 -2
  24. package/content/best-practices/troubleshooting-tips.md +27 -17
  25. package/content/extensions/components/api-reference.md +107 -322
  26. package/content/extensions/components/authentication/api.md +454 -603
  27. package/content/extensions/components/authentication/errors.md +121 -498
  28. package/content/extensions/components/authentication/index.md +88 -801
  29. package/content/extensions/components/authentication/usage.md +207 -956
  30. package/content/extensions/components/authorization/api.md +736 -656
  31. package/content/extensions/components/authorization/errors.md +168 -206
  32. package/content/extensions/components/authorization/index.md +82 -797
  33. package/content/extensions/components/authorization/usage.md +194 -527
  34. package/content/extensions/components/health-check.md +71 -243
  35. package/content/extensions/components/mail/api.md +504 -287
  36. package/content/extensions/components/mail/errors.md +73 -61
  37. package/content/extensions/components/mail/index.md +96 -467
  38. package/content/extensions/components/mail/usage.md +130 -172
  39. package/content/extensions/components/request-tracker.md +66 -173
  40. package/content/extensions/components/socket-io/api.md +195 -13
  41. package/content/extensions/components/socket-io/errors.md +3 -3
  42. package/content/extensions/components/socket-io/index.md +50 -337
  43. package/content/extensions/components/socket-io/usage.md +143 -26
  44. package/content/extensions/components/static-asset/api.md +410 -142
  45. package/content/extensions/components/static-asset/errors.md +110 -53
  46. package/content/extensions/components/static-asset/index.md +79 -608
  47. package/content/extensions/components/static-asset/usage.md +180 -300
  48. package/content/extensions/components/websocket/api.md +275 -399
  49. package/content/extensions/components/websocket/errors.md +47 -56
  50. package/content/extensions/components/websocket/index.md +74 -407
  51. package/content/extensions/components/websocket/usage.md +110 -341
  52. package/content/extensions/helpers/cron/index.md +51 -160
  53. package/content/extensions/helpers/crypto/index.md +62 -483
  54. package/content/extensions/helpers/crypto/reference.md +456 -0
  55. package/content/extensions/helpers/env/index.md +60 -178
  56. package/content/extensions/helpers/error/index.md +221 -207
  57. package/content/extensions/helpers/inversion/index.md +65 -556
  58. package/content/extensions/helpers/inversion/reference.md +522 -0
  59. package/content/extensions/helpers/kafka/admin.md +20 -1
  60. package/content/extensions/helpers/kafka/compile-binary.md +41 -35
  61. package/content/extensions/helpers/kafka/consumer.md +54 -20
  62. package/content/extensions/helpers/kafka/examples.md +21 -16
  63. package/content/extensions/helpers/kafka/index.md +80 -610
  64. package/content/extensions/helpers/kafka/producer.md +134 -5
  65. package/content/extensions/helpers/kafka/schema-registry.md +45 -70
  66. package/content/extensions/helpers/logger/hf-logger.md +193 -0
  67. package/content/extensions/helpers/logger/index.md +64 -563
  68. package/content/extensions/helpers/logger/pino.md +85 -0
  69. package/content/extensions/helpers/logger/reference.md +746 -0
  70. package/content/extensions/helpers/network/api.md +241 -195
  71. package/content/extensions/helpers/network/index.md +72 -530
  72. package/content/extensions/helpers/queue/index.md +72 -900
  73. package/content/extensions/helpers/queue/reference.md +467 -0
  74. package/content/extensions/helpers/redis/index.md +73 -645
  75. package/content/extensions/helpers/redis/reference.md +727 -0
  76. package/content/extensions/helpers/secrets/index.md +66 -0
  77. package/content/extensions/helpers/socket-io/api.md +305 -203
  78. package/content/extensions/helpers/socket-io/index.md +66 -432
  79. package/content/extensions/helpers/storage/api.md +564 -462
  80. package/content/extensions/helpers/storage/index.md +77 -573
  81. package/content/extensions/helpers/types/index.md +66 -499
  82. package/content/extensions/helpers/types/reference.md +650 -0
  83. package/content/extensions/helpers/uid/index.md +58 -227
  84. package/content/extensions/helpers/websocket/api.md +329 -216
  85. package/content/extensions/helpers/websocket/index.md +65 -503
  86. package/content/extensions/helpers/worker-thread/index.md +58 -396
  87. package/content/extensions/helpers/worker-thread/reference.md +428 -0
  88. package/content/guides/core-concepts/persistent/models.md +1 -1
  89. package/content/guides/core-concepts/persistent/search-typesense.md +3 -3
  90. package/content/guides/core-concepts/persistent/transactions.md +1 -1
  91. package/content/guides/core-concepts/secrets-vault.md +177 -0
  92. package/content/guides/core-concepts/services.md +1 -1
  93. package/content/guides/migrations/redis-helpers-migration.md +1 -1
  94. package/content/guides/migrations/unified-connectors-migration.md +2 -2
  95. package/content/guides/tutorials/ecommerce-api.md +3 -8
  96. package/content/references/base/application.md +1 -1
  97. package/content/references/base/connectors.md +79 -136
  98. package/content/references/base/datasources-reference.md +599 -0
  99. package/content/references/base/datasources.md +84 -444
  100. package/content/references/base/dependency-injection.md +17 -39
  101. package/content/references/base/filter-system/application-usage.md +69 -121
  102. package/content/references/base/filter-system/array-operators.md +12 -0
  103. package/content/references/base/filter-system/comparison-operators.md +12 -0
  104. package/content/references/base/filter-system/default-filter.md +136 -348
  105. package/content/references/base/filter-system/fields-order-pagination.md +38 -16
  106. package/content/references/base/filter-system/index.md +106 -257
  107. package/content/references/base/filter-system/json-filtering.md +12 -2
  108. package/content/references/base/filter-system/list-operators.md +16 -2
  109. package/content/references/base/filter-system/logical-operators.md +13 -0
  110. package/content/references/base/filter-system/null-operators.md +13 -0
  111. package/content/references/base/filter-system/pattern-matching.md +12 -0
  112. package/content/references/base/filter-system/quick-reference.md +11 -2
  113. package/content/references/base/filter-system/range-operators.md +12 -0
  114. package/content/references/base/filter-system/tips.md +70 -133
  115. package/content/references/base/filter-system/use-cases.md +156 -233
  116. package/content/references/base/middlewares.md +35 -21
  117. package/content/references/base/models-reference.md +886 -0
  118. package/content/references/base/models.md +80 -1452
  119. package/content/references/base/repositories/advanced.md +156 -192
  120. package/content/references/base/repositories/index.md +77 -650
  121. package/content/references/base/repositories/mixins.md +22 -18
  122. package/content/references/base/repositories/relations.md +123 -171
  123. package/content/references/base/repositories/soft-deletable.md +58 -56
  124. package/content/references/base/secrets.md +263 -0
  125. package/content/references/base/services.md +2 -2
  126. package/content/references/configuration/environment-variables.md +48 -4
  127. package/content/references/configuration/index.md +49 -31
  128. package/content/references/quick-reference.md +3 -16
  129. package/content/references/utilities/crypto.md +35 -76
  130. package/content/references/utilities/date.md +33 -73
  131. package/content/references/utilities/index.md +1 -1
  132. package/content/references/utilities/jsx-reference.md +298 -0
  133. package/content/references/utilities/jsx.md +82 -525
  134. package/content/references/utilities/module.md +29 -62
  135. package/content/references/utilities/parse.md +34 -64
  136. package/content/references/utilities/performance.md +33 -58
  137. package/content/references/utilities/promise.md +28 -62
  138. package/content/references/utilities/request.md +57 -218
  139. package/content/references/utilities/schema.md +43 -137
  140. package/content/references/utilities/statuses-reference.md +361 -0
  141. package/content/references/utilities/statuses.md +63 -667
  142. package/package.json +8 -8
@@ -1,626 +1,168 @@
1
- # Network
2
-
3
- Multi-protocol network communication helpers for HTTP requests, TCP/TLS sockets, and UDP datagrams with scoped logging, auto-reconnect, and client authentication support.
4
-
5
- ## Quick Reference
6
-
7
- | Class | Extends | Protocol | Type |
8
- |-------|---------|----------|------|
9
- | `AxiosNetworkRequest` | `BaseNetworkRequest<'axios'>` | HTTP/HTTPS | Client |
10
- | `NodeFetchNetworkRequest` | `BaseNetworkRequest<'node-fetch'>` | HTTP/HTTPS | Client |
11
- | `NetworkTcpClient` | `BaseNetworkTcpClient` | TCP | Client |
12
- | `NetworkTcpServer` | `BaseNetworkTcpServer` | TCP | Server |
13
- | `NetworkTlsTcpClient` | `BaseNetworkTcpClient` | TLS/SSL | Client |
14
- | `NetworkTlsTcpServer` | `BaseNetworkTcpServer` | TLS/SSL | Server |
15
- | `NetworkUdpClient` | `BaseHelper` | UDP | Client |
16
-
17
- #### Import Paths
18
-
19
- ```typescript
20
- // Main package -- TCP, UDP, and Node Fetch
21
- import {
22
- NodeFetchNetworkRequest,
23
- BaseNetworkRequest,
24
- NetworkTcpClient,
25
- NetworkTcpServer,
26
- NetworkTlsTcpClient,
27
- NetworkTlsTcpServer,
28
- BaseNetworkTcpClient,
29
- BaseNetworkTcpServer,
30
- NetworkUdpClient,
31
- } from '@venizia/ignis-helpers';
32
-
33
- // Axios (separate export -- optional peer dependency)
34
- import {
35
- AxiosNetworkRequest,
36
- AxiosFetcher,
37
- type IAxiosNetworkRequestOptions,
38
- type IAxiosRequestOptions,
39
- } from '@venizia/ignis-helpers/axios';
40
-
41
- // Types
42
- import type {
43
- INodeFetchNetworkRequestOptions,
44
- INodeFetchRequestOptions,
45
- INetworkTcpClientProps,
46
- ITcpSocketServerOptions,
47
- ITcpSocketClient,
48
- IRequestOptions,
49
- IFetchable,
50
- TFetcherVariant,
51
- } from '@venizia/ignis-helpers';
52
- ```
1
+ ---
2
+ title: Network
3
+ description: HTTP request clients, TCP/TLS socket clients and servers, and a UDP client, all built on scoped logging with automatic secret redaction
4
+ difficulty: intermediate
5
+ ---
53
6
 
54
- ## Creating an Instance
7
+ # Network
55
8
 
56
- ### HTTP Request
9
+ Network helpers give you HTTP request clients (fetch or Axios), symmetric TCP/TLS socket client-server pairs, and a UDP client, all sharing the same options-object construction and scoped logging as the rest of the framework.
57
10
 
58
- HTTP helpers follow a two-layer design: a `BaseNetworkRequest` that holds the base URL and delegates to an underlying `IFetchable` fetcher (either Axios or native `fetch`). You typically extend one of the concrete classes to create a typed API client.
11
+ ## In one example
59
12
 
60
- #### Axios
13
+ Extend `NodeFetchNetworkRequest` to build a typed HTTP client backed by native `fetch` - no extra dependency required.
61
14
 
62
15
  ```typescript
63
- import { AxiosNetworkRequest } from '@venizia/ignis-helpers/axios';
16
+ import { NodeFetchNetworkRequest } from '@venizia/ignis-helpers';
64
17
 
65
- class PaymentGateway extends AxiosNetworkRequest {
18
+ class GitHubApi extends NodeFetchNetworkRequest {
66
19
  constructor() {
67
20
  super({
68
- name: 'PaymentGateway',
69
- networkOptions: {
70
- baseUrl: 'https://api.payments.com',
71
- timeout: 30000,
72
- headers: {
73
- 'X-API-Key': process.env.PAYMENT_API_KEY,
74
- },
75
- },
21
+ name: 'GitHubApi',
22
+ networkOptions: { baseUrl: 'https://api.github.com' },
76
23
  });
77
24
  }
78
- }
79
- ```
80
-
81
- #### `IAxiosNetworkRequestOptions`
82
-
83
- | Option | Type | Default | Description |
84
- |--------|------|---------|-------------|
85
- | `name` | `string` | -- | Helper name, used for scoped logging |
86
- | `networkOptions.baseUrl` | `string` | `undefined` | Base URL prepended to all request paths |
87
- | `networkOptions.timeout` | `number` | `60000` | Request timeout in milliseconds |
88
- | `networkOptions.headers` | `object` | `{ 'content-type': 'application/json; charset=utf-8' }` | Default headers; your values override the default content-type |
89
- | `networkOptions.*` | `AxiosRequestConfig` | -- | All other Axios config options are accepted |
90
25
 
91
- > [!TIP]
92
- > `AxiosNetworkRequest` sets sensible defaults: `Content-Type: application/json`, `withCredentials: true`, `validateStatus: status < 500`, and `timeout: 60000` (1 minute). Your options override these defaults.
93
-
94
- #### Node.js Fetch
95
-
96
- ```typescript
97
- import { NodeFetchNetworkRequest } from '@venizia/ignis-helpers';
98
-
99
- class MyApiClient extends NodeFetchNetworkRequest {
100
- constructor() {
101
- super({
102
- name: 'MyApiClient',
103
- networkOptions: {
104
- baseUrl: 'https://api.example.com',
105
- headers: {
106
- 'Authorization': 'Bearer my-token',
107
- },
108
- credentials: 'include',
109
- mode: 'cors',
110
- },
111
- });
26
+ async getUser(username: string) {
27
+ const url = this.getRequestUrl({ paths: ['users', username] });
28
+ const response = await this.getNetworkService().get({ url });
29
+ return response.json();
112
30
  }
113
31
  }
114
32
  ```
115
33
 
116
- #### `INodeFetchNetworkRequestOptions`
34
+ `getRequestUrl()` joins the constructor's `baseUrl` with the path segments; `getNetworkService()` returns the underlying fetcher, which exposes `send()` plus `get`/`post`/`put`/`patch`/`delete`/`query` shortcuts.
117
35
 
118
- | Option | Type | Default | Description |
119
- |--------|------|---------|-------------|
120
- | `name` | `string` | -- | Helper name, used for scoped logging |
121
- | `networkOptions.baseUrl` | `string` | `undefined` | Base URL prepended to all request paths |
122
- | `networkOptions.headers` | `HeadersInit` | `{ 'content-type': 'application/json; charset=utf-8' }` | Default headers; supports `Headers` object or plain object |
123
- | `networkOptions.*` | `RequestInit` | -- | All other `fetch` options are accepted |
36
+ ## How it works
124
37
 
125
- ### TCP Client / Server
38
+ - **HTTP is two layers.** `BaseNetworkRequest` holds a base URL and delegates every call to an `IFetchable` fetcher. `NodeFetchNetworkRequest` (root barrel, wraps native `fetch`) and `AxiosNetworkRequest` (`@venizia/ignis-helpers/axios` sub-path, wraps Axios) are the two concrete clients - you typically extend one to build a typed API client, as in the example above.
39
+ - **`axios` is optional.** It's an optional peer dependency, so `AxiosNetworkRequest`'s fetcher is never exported from the root barrel - only from the `/axios` sub-path.
40
+ - **TCP and TLS share one hierarchy.** `BaseNetworkTcpServer`/`BaseNetworkTcpClient` are abstract classes that take a `createServerFn`/`createClientFn` (`net.*` for plain TCP, `tls.*` for TLS). `NetworkTcpServer`/`NetworkTcpClient` and `NetworkTlsTcpServer`/`NetworkTlsTcpClient` pre-wire those functions - constructor options and every method are otherwise identical between the plain and encrypted variants.
41
+ - **Servers track per-client authentication state.** `unauthorized` → `authenticating` → `authenticated`.
42
+ - **Clients auto-reconnect on a fixed delay.** 5 seconds between attempts, up to `maxRetry` attempts, when `reconnect: true`. See the [Full reference](/extensions/helpers/network/api) for the `maxRetry: -1` edge case.
43
+ - **UDP has no client/server split.** `NetworkUdpClient` is a single class wrapping `node:dgram` (UDP4), with optional multicast group joining via `onBind`.
44
+ - **Every class extends `BaseHelper`.** `this.logger.for('methodName')` scoped logging is available throughout.
126
45
 
127
- #### TCP Client
46
+ **HTTP method case**
128
47
 
129
- ```typescript
130
- import { NetworkTcpClient } from '@venizia/ignis-helpers';
48
+ | Layer | Case | Why |
49
+ |-------|------|-----|
50
+ | `HTTP.Methods.GET`/`.POST`/`.QUERY`/... tokens | always lowercase | Required by `@hono/zod-openapi` route definitions |
51
+ | Wire dispatch | uppercased right before send | Node's undici only auto-normalizes `DELETE`/`GET`/`HEAD`/`OPTIONS`/`POST`/`PUT` - a lowercase `patch` or `query` would go out unchanged |
131
52
 
132
- const tcpClient = new NetworkTcpClient({
133
- identifier: 'sensor-reader',
134
- options: {
135
- host: 'localhost',
136
- port: 8080,
137
- },
138
- reconnect: true,
139
- maxRetry: 10,
140
- encoding: 'utf8',
141
- onConnected: ({ client }) => { console.log('Connected'); },
142
- onData: ({ identifier, message }) => { console.log('Data:', message.toString()); },
143
- onClosed: ({ client }) => { console.log('Closed'); },
144
- onError: (error) => { console.error('Error:', error); },
145
- });
146
- ```
53
+ ## Common tasks
147
54
 
148
- #### TCP Client Options (`INetworkTcpClientProps`)
55
+ ### Use Axios instead of fetch
149
56
 
150
- | Option | Type | Default | Description |
151
- |--------|------|---------|-------------|
152
- | `identifier` | `string` | -- | Unique client identifier for logging |
153
- | `scope` | `string` | `identifier` | Logger scope name |
154
- | `options` | `TcpSocketConnectOpts` | -- | Node.js `net.connect` options (`host`, `port`, etc.) |
155
- | `reconnect` | `boolean` | `false` | Enable automatic reconnection on error |
156
- | `maxRetry` | `number` | `5` | Maximum reconnection attempts |
157
- | `encoding` | `BufferEncoding` | `undefined` | Socket encoding (e.g., `'utf8'`) |
158
- | `onConnected` | `(opts: { client }) => void` | Internal logger | Called when connection is established |
159
- | `onData` | `(opts: { identifier, message }) => void` | No-op | Called when data is received |
160
- | `onClosed` | `(opts: { client }) => void` | Internal logger | Called when connection closes |
161
- | `onError` | `(error: any) => void` | Internal handler with auto-reconnect | Called on connection errors |
162
-
163
- #### TCP Server
57
+ Import from the `/axios` sub-path - never from the root barrel, since `axios` is an optional peer dependency.
164
58
 
165
59
  ```typescript
166
- import { NetworkTcpServer } from '@venizia/ignis-helpers';
167
-
168
- const tcpServer = new NetworkTcpServer({
169
- identifier: 'my-tcp-server',
170
- serverOptions: {},
171
- listenOptions: { port: 8080, host: '0.0.0.0' },
172
- authenticateOptions: { required: true, duration: 5000 },
173
- onServerReady: ({ server }) => { console.log('Listening'); },
174
- onClientConnected: ({ id, socket }) => { console.log(`Client ${id} connected`); },
175
- onClientData: ({ id, socket, data }) => { console.log(`Data from ${id}:`, data.toString()); },
176
- onClientClose: ({ id, socket }) => { console.log(`Client ${id} disconnected`); },
177
- onClientError: ({ id, socket, error }) => { console.error(`Error from ${id}:`, error); },
178
- });
179
- ```
180
-
181
- > [!IMPORTANT]
182
- > When `authenticateOptions.required` is `true`, you **must** provide a positive `duration` value. Clients that do not authenticate within this duration are automatically disconnected with an "Unauthorized Client" message. Use `doAuthenticate()` in your `onClientData` handler to transition the client's state.
183
-
184
- #### TCP Server Options (`ITcpSocketServerOptions`)
185
-
186
- | Option | Type | Default | Description |
187
- |--------|------|---------|-------------|
188
- | `identifier` | `string` | -- | Server identifier for logging |
189
- | `scope` | `string` | `identifier` | Logger scope name |
190
- | `serverOptions` | `Partial<ServerOpts>` | -- | Node.js `net.Server` options |
191
- | `listenOptions` | `Partial<ListenOptions>` | -- | Listen options (`port`, `host`, `backlog`, etc.) |
192
- | `authenticateOptions.required` | `boolean` | -- | Whether clients must authenticate |
193
- | `authenticateOptions.duration` | `number` | `undefined` | Auth timeout in ms (required when `required: true`) |
194
- | `extraEvents` | `Record<string, (opts) => void>` | `{}` | Additional socket events to register per client |
195
- | `onServerReady` | `(opts: { server }) => void` | `undefined` | Called when server starts listening |
196
- | `onClientConnected` | `(opts: { id, socket }) => void` | `undefined` | Called on new client connection |
197
- | `onClientData` | `(opts: { id, socket, data }) => void` | `undefined` | Called when data is received from a client |
198
- | `onClientClose` | `(opts: { id, socket }) => void` | `undefined` | Called when a client disconnects |
199
- | `onClientError` | `(opts: { id, socket, error }) => void` | `undefined` | Called on client socket error |
200
-
201
- ### TLS Client / Server
202
-
203
- TLS variants are identical to their TCP counterparts but use `node:tls` under the hood for encrypted connections. The constructor options accept TLS-specific fields (`cert`, `key`, `ca`, `rejectUnauthorized`, etc.) in addition to all the same handler options.
204
-
205
- #### TLS Client
206
-
207
- ```typescript
208
- import { NetworkTlsTcpClient } from '@venizia/ignis-helpers';
209
- import fs from 'node:fs';
210
-
211
- const tlsClient = new NetworkTlsTcpClient({
212
- identifier: 'secure-client',
213
- options: {
214
- host: 'secure.example.com',
215
- port: 8443,
216
- rejectUnauthorized: true,
217
- ca: fs.readFileSync('ca.crt'),
218
- cert: fs.readFileSync('client.crt'),
219
- key: fs.readFileSync('client.key'),
220
- },
221
- reconnect: true,
222
- maxRetry: 3,
223
- onData: ({ message }) => { console.log('Secure data:', message); },
224
- });
225
-
226
- tlsClient.connect({ resetReconnectCounter: true });
227
- ```
228
-
229
- > [!NOTE]
230
- > `NetworkTlsTcpClient` accepts `ConnectionOptions` from `node:tls` in the `options` field. All other options (`reconnect`, `maxRetry`, callbacks) are identical to `NetworkTcpClient`.
231
-
232
- #### TLS Server
233
-
234
- ```typescript
235
- import { NetworkTlsTcpServer } from '@venizia/ignis-helpers';
236
- import fs from 'node:fs';
237
-
238
- const tlsServer = new NetworkTlsTcpServer({
239
- identifier: 'secure-tcp-server',
240
- serverOptions: {
241
- cert: fs.readFileSync('server.crt'),
242
- key: fs.readFileSync('server.key'),
243
- ca: [fs.readFileSync('ca.crt')],
244
- requestCert: true,
245
- },
246
- listenOptions: { port: 8443, host: '0.0.0.0' },
247
- authenticateOptions: { required: false },
248
- onClientData: ({ id, data }) => { console.log(`Secure data from ${id}:`, data.toString()); },
249
- });
250
- ```
251
-
252
- > [!NOTE]
253
- > `NetworkTlsTcpServer` accepts `TlsOptions` from `node:tls` in `serverOptions`. All handlers and methods are identical to `NetworkTcpServer`.
254
-
255
- ### UDP Client
256
-
257
- ```typescript
258
- import { NetworkUdpClient } from '@venizia/ignis-helpers';
259
-
260
- const udpClient = NetworkUdpClient.newInstance({
261
- identifier: 'my-udp-client',
262
- port: 8081,
263
- host: '0.0.0.0',
264
- reuseAddr: true,
265
- multicastAddress: {
266
- groups: ['239.1.2.3'],
267
- interface: '0.0.0.0',
268
- },
269
- onData: ({ message, remoteInfo }) => {
270
- console.log(`From ${remoteInfo.address}:${remoteInfo.port}:`, message.toString());
271
- },
272
- onBind: async ({ socket, multicastAddress }) => {
273
- if (multicastAddress?.groups) {
274
- for (const group of multicastAddress.groups) {
275
- socket.addMembership(group, multicastAddress.interface);
276
- }
277
- }
278
- },
279
- });
280
- ```
281
-
282
- #### UDP Client Options (`INetworkUdpClientProps`)
283
-
284
- | Option | Type | Default | Description |
285
- |--------|------|---------|-------------|
286
- | `identifier` | `string` | -- | Unique client identifier for logging |
287
- | `host` | `string` | `undefined` | Bind address |
288
- | `port` | `number` | -- | Bind port |
289
- | `reuseAddr` | `boolean` | `undefined` | Allow address reuse (`SO_REUSEADDR`) |
290
- | `multicastAddress.groups` | `string[]` | `undefined` | Multicast group addresses to join |
291
- | `multicastAddress.interface` | `string` | `undefined` | Network interface for multicast |
292
- | `onConnected` | `(opts: { identifier, host?, port }) => void` | Internal logger | Called when socket starts listening |
293
- | `onData` | `(opts: { identifier, message, remoteInfo }) => void` | Internal logger | Called when data is received |
294
- | `onClosed` | `(opts: { identifier, host?, port }) => void` | Internal logger | Called when socket is closed |
295
- | `onError` | `(opts: { identifier, host?, port, error }) => void` | Internal logger | Called on socket error |
296
- | `onBind` | `(opts: { identifier, socket, host?, port, reuseAddr?, multicastAddress? }) => void` | `undefined` | Called after socket is bound; use to join multicast groups |
297
-
298
- ## Usage
299
-
300
- ### HTTP Requests
301
-
302
- Access the underlying fetcher via `getNetworkService()`, then use `send()` or the convenience methods (`get`, `post`, `put`, `patch`, `delete`):
60
+ import { AxiosNetworkRequest } from '@venizia/ignis-helpers/axios';
303
61
 
304
- ```typescript
305
62
  class PaymentGateway extends AxiosNetworkRequest {
306
63
  constructor() {
307
64
  super({
308
65
  name: 'PaymentGateway',
309
66
  networkOptions: {
310
- baseUrl: process.env.PAYMENT_API_URL,
67
+ baseUrl: 'https://api.payments.com',
311
68
  timeout: 30000,
312
69
  headers: { 'X-API-Key': process.env.PAYMENT_API_KEY },
313
70
  },
314
71
  });
315
72
  }
316
-
317
- async charge(amount: number, currency: string) {
318
- const url = this.getRequestUrl({ paths: ['v1', 'charges'] });
319
- const response = await this.getNetworkService().send({
320
- url,
321
- method: 'post',
322
- body: { amount, currency },
323
- });
324
- this.logger.for('charge').info('Payment processed: %s', response.data.id);
325
- return response.data;
326
- }
327
-
328
- async getTransaction(id: string) {
329
- const url = this.getRequestUrl({ paths: ['v1', 'transactions', id] });
330
- return this.getNetworkService().get({ url });
331
- }
332
73
  }
333
74
  ```
334
75
 
335
- #### Request Logging & Redaction
336
-
337
- Both `NodeFetcher` and `AxiosFetcher` log every outbound request at `info` level (`URL: %s | Props: %s | ...`), including the request config -- headers, body, and any other options passed to `send()`. Before that log line is written, the request config is run through `redactSecrets()`, so values under secret-looking keys never reach the log.
338
-
339
- Redaction matches by key name, case-insensitively, at any depth -- both options-object spellings (`apiKey`, `token`, `password`, `authorization`, ...) and HTTP header spellings (`x-api-key`, `x-csrf-token`, `cookie`, `set-cookie`, `proxy-authorization`, `www-authenticate`, ...). A header like `'X-API-Key': process.env.PAYMENT_API_KEY` or `'Authorization': 'Bearer my-token'` (as in the examples above) is logged as `'[REDACTED]'`, not the real value. This redaction happens automatically -- there is nothing to configure.
340
-
341
- #### Convenience Methods
342
-
343
- ```typescript
344
- const fetcher = this.getNetworkService();
345
-
346
- // These are equivalent:
347
- await fetcher.send({ url: '/users', method: 'get' });
348
- await fetcher.get({ url: '/users' });
349
-
350
- // POST with body
351
- await fetcher.post({ url: '/users', body: { name: 'Alice' } });
352
-
353
- // All methods: get(), post(), put(), patch(), delete()
354
- ```
76
+ `AxiosNetworkRequest` applies defaults you can override: `Content-Type: application/json`, `withCredentials: true`, `validateStatus: status < 500`, `timeout: 60000`.
355
77
 
356
- #### HTTPS with Axios
78
+ ### Log a request with secrets redacted
357
79
 
358
- For HTTPS requests, the `AxiosFetcher` automatically creates an `https.Agent`. By default, `rejectUnauthorized` is `false`. Override it per request:
80
+ Pass a logger (typically `this.logger` from a `BaseHelper` subclass) as the second argument to `send()` or any shortcut method - the fetcher logs the URL and config at `info` level with the config run through `redactSecrets()` first, so values like `Authorization` or `X-API-Key` reach the log as `'[REDACTED]'`. Without a logger argument, nothing is logged.
359
81
 
360
82
  ```typescript
361
- await fetcher.send({
362
- url: 'https://strict-api.example.com/data',
363
- method: 'get',
364
- rejectUnauthorized: true,
365
- });
366
- ```
367
-
368
- #### Timeout with Node Fetch
369
-
370
- The `NodeFetcher` implements timeout via `AbortController`. Pass `timeout` in each `send()` call:
371
-
372
- ```typescript
373
- await fetcher.send({
374
- url: '/slow-endpoint',
375
- method: 'get',
376
- timeout: 5000, // Aborts after 5 seconds
377
- });
83
+ async charge(amount: number, currency: string) {
84
+ const url = this.getRequestUrl({ paths: ['v1', 'charges'] });
85
+ const response = await this.getNetworkService().post(
86
+ { url, body: { amount, currency } },
87
+ this.logger,
88
+ );
89
+ return response.data;
90
+ }
378
91
  ```
379
92
 
380
- ### TCP Communication
93
+ ### Open a TCP connection
381
94
 
382
95
  ```typescript
383
96
  import { NetworkTcpClient, NetworkTcpServer } from '@venizia/ignis-helpers';
384
97
 
385
- // --- Server ---
386
98
  const server = new NetworkTcpServer({
387
99
  identifier: 'echo-server',
388
100
  serverOptions: {},
389
101
  listenOptions: { port: 9000, host: '0.0.0.0' },
390
102
  authenticateOptions: { required: false },
391
- onClientData: ({ id, data }) => {
392
- // Echo back to the sender
393
- server.emit({ clientId: id, payload: data });
394
- },
103
+ onClientData: ({ id, data }) => server.emit({ clientId: id, payload: data }),
395
104
  });
396
105
 
397
- // --- Client ---
398
106
  const client = new NetworkTcpClient({
399
107
  identifier: 'echo-client',
400
108
  options: { host: 'localhost', port: 9000 },
401
109
  reconnect: true,
402
110
  maxRetry: 5,
403
- encoding: 'utf8',
404
- onData: ({ message }) => { console.log('Echo:', message); },
111
+ onData: ({ message }) => console.log('Echo:', message),
405
112
  });
406
113
 
407
114
  client.connect({ resetReconnectCounter: true });
408
115
  client.emit({ payload: 'Hello, Server!' });
409
116
  ```
410
117
 
411
- #### Server with Authentication Flow
118
+ `NetworkTlsTcpServer`/`NetworkTlsTcpClient` use the identical API - pass certificates in `serverOptions`/`options` (types `TlsOptions`/`ConnectionOptions` from `node:tls`).
119
+
120
+ ### Require TCP client authentication
121
+
122
+ Set `authenticateOptions.required: true` with a positive `duration` (milliseconds); the constructor throws if `duration` is missing or negative. Clients that never call `doAuthenticate()` within that window are disconnected automatically.
412
123
 
413
124
  ```typescript
414
125
  const server = new NetworkTcpServer({
415
- identifier: 'auth-tcp-server',
126
+ identifier: 'auth-server',
416
127
  serverOptions: {},
417
128
  listenOptions: { port: 9000, host: '0.0.0.0' },
418
129
  authenticateOptions: { required: true, duration: 5000 },
419
-
420
130
  onClientData: ({ id, data }) => {
421
- const message = data.toString();
422
- const client = server.getClient({ id });
423
-
424
- if (client?.state === 'unauthorized') {
425
- if (message === 'secret-token') {
426
- server.doAuthenticate({ id, state: 'authenticated' });
427
- server.emit({ clientId: id, payload: 'Authenticated!' });
428
- } else {
429
- server.emit({ clientId: id, payload: 'Invalid credentials' });
430
- }
431
- return;
131
+ if (data.toString() === 'secret-token') {
132
+ server.doAuthenticate({ id, state: 'authenticated' });
432
133
  }
433
-
434
- // Handle authenticated client messages
435
- console.log(`[${id}] ${message}`);
436
134
  },
437
135
  });
438
136
  ```
439
137
 
440
- #### Client State Tracking
441
-
442
- Each connected client is tracked as an `ITcpSocketClient`:
443
-
444
- ```typescript
445
- interface ITcpSocketClient<SocketClientType> {
446
- id: string;
447
- socket: SocketClientType;
448
- state: 'unauthorized' | 'authenticating' | 'authenticated';
449
- subscriptions: Set<string>;
450
- storage: {
451
- connectedAt: dayjs.Dayjs;
452
- authenticatedAt: dayjs.Dayjs | null;
453
- [additionField: symbol | string]: any; // Extensible storage
454
- };
455
- }
456
- ```
457
-
458
- ### TLS Encrypted Communication
459
-
460
- TLS classes share the same API as their TCP counterparts. Provide TLS certificates in the `options` or `serverOptions` field:
461
-
462
- ```typescript
463
- import { NetworkTlsTcpServer, NetworkTlsTcpClient } from '@venizia/ignis-helpers';
464
- import fs from 'node:fs';
465
-
466
- // --- TLS Server ---
467
- const tlsServer = new NetworkTlsTcpServer({
468
- identifier: 'secure-server',
469
- serverOptions: {
470
- cert: fs.readFileSync('server.crt'),
471
- key: fs.readFileSync('server.key'),
472
- ca: [fs.readFileSync('ca.crt')],
473
- requestCert: true,
474
- },
475
- listenOptions: { port: 8443, host: '0.0.0.0' },
476
- authenticateOptions: { required: false },
477
- onClientData: ({ id, data }) => {
478
- console.log(`Secure data from ${id}:`, data.toString());
479
- },
480
- });
481
-
482
- // --- TLS Client ---
483
- const tlsClient = new NetworkTlsTcpClient({
484
- identifier: 'secure-client',
485
- options: {
486
- host: 'localhost',
487
- port: 8443,
488
- rejectUnauthorized: true,
489
- ca: fs.readFileSync('ca.crt'),
490
- cert: fs.readFileSync('client.crt'),
491
- key: fs.readFileSync('client.key'),
492
- },
493
- onData: ({ message }) => { console.log('Secure:', message); },
494
- });
495
-
496
- tlsClient.connect({ resetReconnectCounter: true });
497
- tlsClient.emit({ payload: 'Hello over TLS!' });
498
- ```
499
-
500
- ### UDP Communication
138
+ ### Send a UDP datagram
501
139
 
502
140
  ```typescript
503
141
  import { NetworkUdpClient } from '@venizia/ignis-helpers';
504
142
 
505
143
  const udpClient = NetworkUdpClient.newInstance({
506
- identifier: 'multicast-listener',
507
- port: 5000,
144
+ identifier: 'my-udp-client',
145
+ port: 8081,
508
146
  host: '0.0.0.0',
509
- reuseAddr: true,
510
- multicastAddress: {
511
- groups: ['239.1.2.3'],
512
- interface: '0.0.0.0',
513
- },
514
147
  onData: ({ message, remoteInfo }) => {
515
148
  console.log(`From ${remoteInfo.address}:${remoteInfo.port}:`, message.toString());
516
149
  },
517
- onBind: async ({ socket, multicastAddress }) => {
518
- // Join multicast groups after socket is bound
519
- if (multicastAddress?.groups) {
520
- for (const group of multicastAddress.groups) {
521
- socket.addMembership(group, multicastAddress.interface);
522
- }
523
- }
524
- },
525
150
  });
526
151
 
527
- // Start listening
528
152
  udpClient.connect();
529
-
530
- // Access the underlying dgram.Socket
531
- const socket = udpClient.getClient();
532
-
533
- // Check if bound
534
- if (udpClient.isConnected()) {
535
- // Send a datagram via the raw socket
536
- socket.send('Hello', 5001, '239.1.2.3');
537
- }
538
-
539
- // Stop listening
540
- udpClient.disconnect();
541
- ```
542
-
543
- ## Troubleshooting
544
-
545
- ### HTTP: "[getRequestUrl] Invalid configuration for third party request base url!"
546
-
547
- **Cause:** `getRequestUrl()` was called but no `baseUrl` was provided at construction time or in the call's `opts.baseUrl` parameter.
548
-
549
- **Fix:** Provide a `baseUrl` either in the constructor's `networkOptions` or pass it in the `opts` parameter of `getRequestUrl()`:
550
-
551
- ```typescript
552
- // At construction
553
- const client = new AxiosNetworkRequest({
554
- name: 'MyClient',
555
- networkOptions: { baseUrl: 'https://api.example.com' },
556
- });
557
-
558
- // Or per call
559
- const url = client.getRequestUrl({
560
- baseUrl: 'https://api.example.com',
561
- paths: ['v1', 'users'],
562
- });
563
- ```
564
-
565
- ### HTTP: Timeout not working with NodeFetchNetworkRequest
566
-
567
- **Cause:** The `timeout` option on the constructor's `networkOptions` is not automatically applied to individual requests. Timeout must be set per-request.
568
-
569
- **Fix:** Pass `timeout` in each `send()` call:
570
-
571
- ```typescript
572
- await this.getNetworkService().send({
573
- url: '/slow-endpoint',
574
- method: 'get',
575
- timeout: 5000,
576
- });
577
- ```
578
-
579
- The `NodeFetcher` internally creates an `AbortController` and aborts the request after the specified timeout.
580
-
581
- ### TCP Server: "Invalid authenticate duration"
582
-
583
- **Cause:** `authenticateOptions.required` is `true` but `duration` is missing, zero, or negative.
584
-
585
- **Fix:** Provide a positive `duration` value when authentication is required:
586
-
587
- ```typescript
588
- // Correct
589
- authenticateOptions: { required: true, duration: 5000 }
590
-
591
- // Wrong -- throws at construction time
592
- authenticateOptions: { required: true }
593
- authenticateOptions: { required: true, duration: -1 }
153
+ udpClient.getClient()?.send('Hello', 5001, '239.1.2.3');
594
154
  ```
595
155
 
596
- ### TCP Client: Reconnect loop never stops
156
+ ## See also
597
157
 
598
- **Cause:** `maxRetry` is set to `-1` (infinite retries) and the target server is unreachable. The reconnect delay is fixed at 5 seconds between attempts.
599
-
600
- **Fix:** Use a finite `maxRetry` value, or set `reconnect: false` if you handle reconnection externally:
601
-
602
- ```typescript
603
- const client = new NetworkTcpClient({
604
- identifier: 'my-client',
605
- options: { host: 'localhost', port: 8080 },
606
- reconnect: true,
607
- maxRetry: 5, // Stop after 5 attempts
608
- });
609
- ```
610
-
611
- ### TCP Server: Client emit does nothing
612
-
613
- **Cause:** The target client socket is not writable (already closed or half-closed), or the payload is empty. The server logs a warning but does not throw.
614
-
615
- **Fix:** Check the client state before emitting:
616
-
617
- ```typescript
618
- const client = server.getClient({ id: clientId });
619
- if (client && client.socket.writable) {
620
- server.emit({ clientId, payload: 'Hello' });
621
- }
622
- ```
158
+ - [Full reference](/extensions/helpers/network/api) - every class, method signature, and type in the module
159
+ - [Redis helper](/extensions/helpers/redis/) - another `BaseHelper`-based connection helper with the same scoped-logging conventions
623
160
 
624
- ## See Also
161
+ **Files:**
625
162
 
626
- - [API Reference](./api) -- Full method signatures and types
163
+ - [`packages/helpers/src/modules/network/http-request/base-network-request.helper.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/network/http-request/base-network-request.helper.ts) - `BaseNetworkRequest`
164
+ - [`packages/helpers/src/modules/network/http-request/fetcher/node-fetcher.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/network/http-request/fetcher/node-fetcher.ts) - `NodeFetcher`, `NodeFetchNetworkRequest`
165
+ - [`packages/helpers/src/modules/network/http-request/fetcher/axios-fetcher.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/network/http-request/fetcher/axios-fetcher.ts) - `AxiosFetcher`, `AxiosNetworkRequest` (sub-path export)
166
+ - [`packages/helpers/src/modules/network/tcp-socket/base-tcp-server.helper.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/network/tcp-socket/base-tcp-server.helper.ts) - `BaseNetworkTcpServer`
167
+ - [`packages/helpers/src/modules/network/tcp-socket/base-tcp-client.helper.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/network/tcp-socket/base-tcp-client.helper.ts) - `BaseNetworkTcpClient`
168
+ - [`packages/helpers/src/modules/network/udp-socket/network-udp-client.helper.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/network/udp-socket/network-udp-client.helper.ts) - `NetworkUdpClient`