@catbee/utils 1.0.5 → 2.0.0-next.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 (121) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +27 -27
  3. package/array/array.utils.d.ts +191 -0
  4. package/array/index.cjs +246 -0
  5. package/array/index.d.ts +25 -0
  6. package/array/index.mjs +228 -0
  7. package/async/async.utils.d.ts +296 -0
  8. package/async/index.cjs +428 -0
  9. package/async/index.d.ts +25 -0
  10. package/async/index.mjs +407 -0
  11. package/cache/cache.utils.d.ts +176 -0
  12. package/cache/index.cjs +292 -0
  13. package/cache/index.d.ts +25 -0
  14. package/cache/index.mjs +290 -0
  15. package/config/config.d.ts +57 -0
  16. package/config/index.cjs +136 -0
  17. package/config/index.d.ts +26 -0
  18. package/config/index.mjs +131 -0
  19. package/context-store/context-store.utils.d.ts +212 -0
  20. package/context-store/index.cjs +267 -0
  21. package/context-store/index.d.ts +25 -0
  22. package/context-store/index.mjs +261 -0
  23. package/crypto/crypto.utils.d.ts +183 -0
  24. package/crypto/index.cjs +182 -0
  25. package/crypto/index.d.ts +25 -0
  26. package/crypto/index.mjs +166 -0
  27. package/date/date.utils.d.ts +190 -0
  28. package/date/index.cjs +295 -0
  29. package/date/index.d.ts +25 -0
  30. package/date/index.mjs +283 -0
  31. package/decorators/decorators.utils.d.ts +705 -0
  32. package/decorators/index.cjs +913 -0
  33. package/decorators/index.d.ts +25 -0
  34. package/decorators/index.mjs +872 -0
  35. package/dir/dir.utils.d.ts +216 -0
  36. package/dir/index.cjs +416 -0
  37. package/dir/index.d.ts +25 -0
  38. package/dir/index.mjs +389 -0
  39. package/env/env.utils.d.ts +400 -0
  40. package/env/index.cjs +761 -0
  41. package/env/index.d.ts +25 -0
  42. package/env/index.mjs +758 -0
  43. package/exception/exception.utils.d.ts +253 -0
  44. package/exception/index.cjs +362 -0
  45. package/exception/index.d.ts +25 -0
  46. package/exception/index.mjs +338 -0
  47. package/fs/fs.utils.d.ts +196 -0
  48. package/fs/index.cjs +253 -0
  49. package/fs/index.d.ts +25 -0
  50. package/fs/index.mjs +228 -0
  51. package/http-status-codes/http-status-codes.d.ts +289 -0
  52. package/http-status-codes/index.cjs +96 -0
  53. package/http-status-codes/index.d.ts +25 -0
  54. package/http-status-codes/index.mjs +94 -0
  55. package/id/id.utils.d.ts +59 -0
  56. package/id/index.cjs +62 -0
  57. package/id/index.d.ts +25 -0
  58. package/id/index.mjs +56 -0
  59. package/index.cjs +218 -0
  60. package/index.d.ts +51 -0
  61. package/index.mjs +51 -0
  62. package/logger/index.cjs +334 -0
  63. package/logger/index.d.ts +25 -0
  64. package/logger/index.mjs +313 -0
  65. package/logger/logger.utils.d.ts +210 -0
  66. package/middleware/index.cjs +177 -0
  67. package/middleware/index.d.ts +25 -0
  68. package/middleware/index.mjs +170 -0
  69. package/middleware/middleware.utils.d.ts +123 -0
  70. package/obj/index.cjs +317 -0
  71. package/obj/index.d.ts +25 -0
  72. package/obj/index.mjs +301 -0
  73. package/obj/obj.utils.d.ts +156 -0
  74. package/package.json +172 -20
  75. package/performance/index.cjs +231 -0
  76. package/performance/index.d.ts +25 -0
  77. package/performance/index.mjs +225 -0
  78. package/performance/performance.utils.d.ts +159 -0
  79. package/request/index.cjs +202 -0
  80. package/request/index.d.ts +26 -0
  81. package/request/index.mjs +194 -0
  82. package/request/request.utils.d.ts +109 -0
  83. package/response/index.cjs +234 -0
  84. package/response/index.d.ts +26 -0
  85. package/response/index.mjs +222 -0
  86. package/response/response.utils.d.ts +186 -0
  87. package/server/index.cjs +1627 -0
  88. package/server/index.d.ts +28 -0
  89. package/server/index.mjs +1617 -0
  90. package/server/server.builder.d.ts +531 -0
  91. package/server/server.d.ts +303 -0
  92. package/stream/index.cjs +151 -0
  93. package/stream/index.d.ts +25 -0
  94. package/stream/index.mjs +144 -0
  95. package/stream/stream.utils.d.ts +111 -0
  96. package/string/index.cjs +109 -0
  97. package/string/index.d.ts +25 -0
  98. package/string/index.mjs +95 -0
  99. package/string/string.utils.d.ts +124 -0
  100. package/type/index.cjs +129 -0
  101. package/type/index.d.ts +25 -0
  102. package/type/index.mjs +119 -0
  103. package/type/type.utils.d.ts +129 -0
  104. package/types/api-response.d.ts +175 -0
  105. package/types/common.d.ts +148 -0
  106. package/types/config.d.ts +88 -0
  107. package/types/index.cjs +34 -0
  108. package/types/index.d.ts +28 -0
  109. package/types/index.mjs +32 -0
  110. package/types/server.d.ts +291 -0
  111. package/url/index.cjs +201 -0
  112. package/url/index.d.ts +25 -0
  113. package/url/index.mjs +189 -0
  114. package/url/url.utils.d.ts +164 -0
  115. package/validate/index.cjs +212 -0
  116. package/validate/index.d.ts +25 -0
  117. package/validate/index.mjs +188 -0
  118. package/validate/validate.utils.d.ts +200 -0
  119. package/build/index.cjs +0 -7579
  120. package/build/index.d.ts +0 -5774
  121. package/build/index.mjs +0 -7274
@@ -0,0 +1,303 @@
1
+ /*
2
+ * The MIT License
3
+ *
4
+ * Copyright (c) 2025 Catbee Technologies. https://catbee.in/license
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
24
+
25
+ import express, { Express, Router } from 'express';
26
+ import http from 'http';
27
+ import https from 'https';
28
+ import { ServerConfig, ServerHooks } from '@catbee/utils/types';
29
+ /**
30
+ * Generate standardized error message for missing dependencies.
31
+ */
32
+ export declare const getDependencyErrorMessage: (packageName: string, x?: string) => string;
33
+ /**
34
+ * Map of critical dependencies to their error messages.
35
+ */
36
+ export declare const DependencyErrors: {
37
+ express: string;
38
+ helmet: string;
39
+ cors: string;
40
+ compression: string;
41
+ 'express-rate-limit': string;
42
+ 'cookie-parser': string;
43
+ '@scalar/express-api-reference': string;
44
+ 'prom-client': string;
45
+ };
46
+ /**
47
+ * Production-ready Express server with enterprise features.
48
+ *
49
+ * Core Features:
50
+ * - Security: Helmet, CORS, rate limiting, timeouts
51
+ * - Monitoring: Request logs, metrics, health checks
52
+ * - Performance: Compression, caching, static files
53
+ * - Reliability: Graceful shutdown, error handling
54
+ * - Developer UX: OpenAPI docs, debugging tools
55
+ * - Extensibility: Hooks, middleware, custom routes
56
+ *
57
+ * Designed for microservices and production workloads.
58
+ * Includes K8s readiness probes and zero-downtime support.
59
+ */
60
+ export declare class ExpressServer {
61
+ /** Prometheus client registry for metrics collection */
62
+ private register;
63
+ /** HTTP server instance (null when not running) */
64
+ protected server: http.Server | https.Server | null;
65
+ /** Merged configuration with defaults applied */
66
+ protected config: ServerConfig;
67
+ /** User-defined lifecycle hooks */
68
+ protected hooks: ServerHooks;
69
+ /** Global API prefix (from config) */
70
+ protected globalPrefix: string;
71
+ /** Internal fallback router */
72
+ private rootRouter;
73
+ /** User-supplied router */
74
+ private externalRouter?;
75
+ /** Internal Express app instance */
76
+ private app;
77
+ /** Set of active WebSocket connections */
78
+ private connections;
79
+ /** Flag indicating if the server is shutting down */
80
+ private isShuttingDown;
81
+ /**
82
+ * Collection of registered health check functions.
83
+ * These are executed when the health check endpoint is accessed.
84
+ */
85
+ private healthChecks;
86
+ /** Prometheus metrics for monitoring */
87
+ private requestCounter?;
88
+ private routeTimings?;
89
+ private requestSizes?;
90
+ private clientIPs?;
91
+ /** Promise that resolves when initialization (middleware + routes) is complete */
92
+ private initPromise;
93
+ /**
94
+ * Initializes server with intelligent defaults and security best practices.
95
+ * All settings can be customized via config and hooks.
96
+ *
97
+ * Default Security:
98
+ * - Secure headers (Helmet)
99
+ * - Rate limiting
100
+ * - Request timeouts
101
+ * - Body size limits
102
+ * - CORS protection
103
+ *
104
+ * Default Monitoring:
105
+ * - Request/Response logging
106
+ * - Prometheus metrics
107
+ * - Health checks
108
+ * - Request tracing
109
+ */
110
+ constructor(config: Partial<ServerConfig>, hooks?: ServerHooks);
111
+ /**
112
+ * Execute a lifecycle hook safely with comprehensive error handling.
113
+ * Prevents hook failures from crashing the server while logging issues.
114
+ *
115
+ * @param hook Name of the lifecycle hook to execute
116
+ * @param args Arguments to pass to the hook function
117
+ */
118
+ private runHook;
119
+ /**
120
+ * Initialize the Express server with middleware and routes.
121
+ */
122
+ private initialize;
123
+ /**
124
+ * Configure and register all middlewares in the optimal order.
125
+ *
126
+ * Middleware Order (CRITICAL - don't change without understanding implications):
127
+ * 1. Basic server configuration (trust proxy, x-powered-by)
128
+ * 2. Request ID generation (for tracing)
129
+ * 3. Request context setup (for logging correlation)
130
+ * 4. Timeout protection (prevents hanging requests)
131
+ * 5. Response time tracking (for performance monitoring)
132
+ * 6. Request logging (after ID/context setup)
133
+ * 7. Custom request hooks
134
+ * 8. Security middleware (rate limiting, CORS, Helmet)
135
+ * 9. Response compression
136
+ * 10. Static file serving
137
+ * 11. Request parsing (body parsing, cookies)
138
+ * 12. API documentation (OpenAPI)
139
+ * 13. Global headers
140
+ * 14. Custom response hooks
141
+ */
142
+ protected setupMiddleware(): Promise<void>;
143
+ /**
144
+ * Configure server routes and error handling.
145
+ * Sets up in following order:
146
+ *
147
+ * 1. Built-in routes (health, metrics)
148
+ * 2. Application routes
149
+ * 3. 404 handler
150
+ * 4. Error handler
151
+ */
152
+ protected setupRoutes(): Promise<void>;
153
+ /**
154
+ * Register a new health check function for monitoring service dependencies.
155
+ *
156
+ * Health checks are executed when the health endpoint is accessed and
157
+ * help determine if the service is ready to handle requests.
158
+ *
159
+ * Examples:
160
+ * - Database connectivity
161
+ * - External service availability
162
+ * - File system access
163
+ * - Memory/CPU usage checks
164
+ *
165
+ * @param name Unique identifier for the check (used in detailed responses)
166
+ * @param check Function returning boolean or Promise<boolean> indicating health
167
+ * @returns This instance for method chaining
168
+ */
169
+ registerHealthCheck(name: string, check: () => Promise<boolean> | boolean): this;
170
+ /**
171
+ * Run registered health checks and return whether the service is ready.
172
+ * Useful for readiness probes in deployment tooling.
173
+ *
174
+ * @returns Promise resolving to `true` when all checks pass, otherwise `false`.
175
+ */
176
+ ready(): Promise<boolean>;
177
+ /**
178
+ * Get the underlying Express application instance.
179
+ * Use this for advanced Express features not exposed by this wrapper.
180
+ *
181
+ * @returns The raw Express app instance
182
+ */
183
+ getApp(): Express;
184
+ /**
185
+ * Get the active HTTP/HTTPS server instance.
186
+ * Returns null if the server is not currently running.
187
+ *
188
+ * @returns The HTTP/HTTPS server instance or null
189
+ */
190
+ getServer(): http.Server | https.Server | null;
191
+ /**
192
+ * Start the HTTP server and begin listening for requests.
193
+ *
194
+ * This method:
195
+ * - Executes beforeStart hooks
196
+ * - Binds to the configured host/port
197
+ * - Sets up error handling for startup failures
198
+ * - Executes afterStart hooks on success
199
+ * - Logs startup information
200
+ *
201
+ * @returns Promise resolving to the running HTTP server instance
202
+ * @throws Error if server fails to start or port is already in use
203
+ */
204
+ start(): Promise<http.Server | https.Server>;
205
+ /**
206
+ * Stop the HTTP server gracefully.
207
+ *
208
+ * This method:
209
+ * - Executes beforeStop hooks
210
+ * - Stops accepting new connections
211
+ * - Waits for existing connections to finish
212
+ * - Closes the server
213
+ * - Executes afterStop hooks
214
+ * - Logs shutdown information
215
+ *
216
+ * Graceful shutdown ensures:
217
+ * - No requests are dropped
218
+ * - Resources are properly cleaned up
219
+ * - Monitoring systems are notified
220
+ */
221
+ stop(force?: boolean): Promise<void>;
222
+ /**
223
+ * Enable graceful shutdown on OS signals for production deployment.
224
+ *
225
+ * This is essential for:
226
+ * - Container orchestration (Docker, Kubernetes)
227
+ * - Process managers (PM2, systemd)
228
+ * - Load balancer health checks
229
+ * - Zero-downtime deployments
230
+ *
231
+ * @param signals Array of process signals to listen for (default: SIGINT, SIGTERM)
232
+ */
233
+ enableGracefulShutdown(signals?: NodeJS.Signals[]): this;
234
+ /**
235
+ * Set an externally created base router.
236
+ * This will override the internal rootRouter.
237
+ */
238
+ setBaseRouter(router: Router): this;
239
+ /**
240
+ * Create and register a new router (only used if not injecting one externally - use `setBaseRouter` instead).
241
+ */
242
+ createRouter(prefix?: string): Router;
243
+ /**
244
+ * Register a new route handler with support for multiple HTTP methods.
245
+ * The route is automatically registered under the globalPrefix if set.
246
+ *
247
+ * @param methods Array of HTTP methods (get, post, put, delete, etc.)
248
+ * @param path Route path with Express path patterns support
249
+ * @param handlers One or more Express request handlers (middleware + final handler)
250
+ * @returns This instance for method chaining
251
+ */
252
+ registerRoute(methods: Array<keyof Pick<Express, 'get' | 'post' | 'put' | 'delete' | 'patch' | 'options' | 'head'>>, path: string, ...handlers: Array<express.RequestHandler>): this;
253
+ /**
254
+ * Register custom middleware with optional path restriction.
255
+ *
256
+ * Use this for:
257
+ * - Adding authentication to specific routes
258
+ * - Custom logging or validation
259
+ * - Request transformation
260
+ * - Third-party middleware integration
261
+ *
262
+ * @param path Optional path prefix or middleware function if no path
263
+ * @param middleware Middleware handler (required if path is provided)
264
+ * @returns This instance for method chaining
265
+ */
266
+ registerMiddleware(path: string | express.RequestHandler, middleware?: express.RequestHandler): this;
267
+ /**
268
+ * Register one or more middleware functions to be applied globally.
269
+ * This is a simpler alternative to registerMiddleware when you just want
270
+ * to add middleware without path restrictions.
271
+ *
272
+ * @param middlewares One or more Express middleware functions
273
+ * @returns This instance for method chaining
274
+ */
275
+ useMiddleware(...middlewares: express.RequestHandler[]): this;
276
+ /**
277
+ * Get Prometheus registry (to add custom counters/histograms)
278
+ *
279
+ * @return {*} {client.Registry}
280
+ */
281
+ getMetricsRegistry(): typeof import("prom-client").Registry;
282
+ /**
283
+ * Get server configuration
284
+ *
285
+ * @return {*} {ServerConfig}
286
+ */
287
+ getConfig(): ServerConfig;
288
+ /**
289
+ * Wait until server initialization (middleware + routes) has completed.
290
+ * Useful for integration tests that inspect app before starting.
291
+ */
292
+ waitUntilReady(): Promise<void>;
293
+ private normalizePath;
294
+ private normalizeRouteForMetrics;
295
+ /**
296
+ * Destroy all active connections (gracefully if possible).
297
+ * If a connection does not close cleanly, it will be force-destroyed.
298
+ */
299
+ private destroyConnections;
300
+ private validateHttpsFiles;
301
+ private isBuiltServerConfig;
302
+ private throwDependancyError;
303
+ }
@@ -0,0 +1,151 @@
1
+ /*
2
+ * The MIT License
3
+ *
4
+ * Copyright (c) 2025 Catbee Technologies. https://catbee.in/license
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
24
+
25
+ 'use strict';
26
+
27
+ var stream = require('stream');
28
+
29
+ var __defProp = Object.defineProperty;
30
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
31
+ function bufferToStream(data) {
32
+ const readable = new stream.Readable();
33
+ readable.push(data);
34
+ readable.push(null);
35
+ return readable;
36
+ }
37
+ __name(bufferToStream, "bufferToStream");
38
+ async function streamToBuffer(stream) {
39
+ return new Promise((resolve, reject) => {
40
+ const chunks = [];
41
+ stream.on("data", (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
42
+ stream.on("end", () => resolve(Buffer.concat(chunks)));
43
+ stream.on("error", reject);
44
+ });
45
+ }
46
+ __name(streamToBuffer, "streamToBuffer");
47
+ async function streamToString(stream, encoding = "utf8") {
48
+ const buffer = await streamToBuffer(stream);
49
+ return buffer.toString(encoding);
50
+ }
51
+ __name(streamToString, "streamToString");
52
+ function createThrottleStream(bytesPerSecond) {
53
+ let bytesSent = 0;
54
+ let startTime = Date.now();
55
+ return new stream.Transform({
56
+ transform(chunk, _encoding, callback) {
57
+ const elapsedSeconds = (Date.now() - startTime) / 1e3;
58
+ const targetBytes = bytesPerSecond * elapsedSeconds;
59
+ const chunkSize = chunk.length;
60
+ if (bytesSent + chunkSize <= targetBytes) {
61
+ bytesSent += chunkSize;
62
+ callback(null, chunk);
63
+ return;
64
+ }
65
+ const delay = ((bytesSent + chunkSize) / bytesPerSecond - elapsedSeconds) * 1e3;
66
+ setTimeout(() => {
67
+ bytesSent += chunkSize;
68
+ callback(null, chunk);
69
+ }, delay);
70
+ }
71
+ });
72
+ }
73
+ __name(createThrottleStream, "createThrottleStream");
74
+ function createBatchStream(size, options = {}) {
75
+ const objectMode = options.objectMode !== false;
76
+ let batch = [];
77
+ let buffers = [];
78
+ let bufferSize = 0;
79
+ return new stream.Transform({
80
+ objectMode,
81
+ transform(chunk, _encoding, callback) {
82
+ if (objectMode) {
83
+ batch.push(chunk);
84
+ if (batch.length >= size) {
85
+ this.push(batch);
86
+ batch = [];
87
+ }
88
+ } else {
89
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
90
+ buffers.push(buffer);
91
+ bufferSize += buffer.length;
92
+ let combined = Buffer.concat(buffers, bufferSize);
93
+ while (combined.length >= size) {
94
+ this.push(combined.slice(0, size));
95
+ combined = combined.slice(size);
96
+ }
97
+ buffers = combined.length > 0 ? [
98
+ combined
99
+ ] : [];
100
+ bufferSize = combined.length;
101
+ }
102
+ callback();
103
+ },
104
+ flush(callback) {
105
+ if (objectMode && batch.length > 0) {
106
+ this.push(batch);
107
+ } else if (!objectMode && buffers.length > 0 && bufferSize > 0) {
108
+ let combined = Buffer.concat(buffers, bufferSize);
109
+ while (combined.length >= size) {
110
+ this.push(combined.slice(0, size));
111
+ combined = combined.slice(size);
112
+ }
113
+ if (combined.length > 0) {
114
+ this.push(combined);
115
+ }
116
+ }
117
+ callback();
118
+ }
119
+ });
120
+ }
121
+ __name(createBatchStream, "createBatchStream");
122
+ function createLineStream(options = {}) {
123
+ const { encoding = "utf8", includeNewlines = false } = options;
124
+ let buffer = "";
125
+ return new stream.Transform({
126
+ objectMode: true,
127
+ transform(chunk, _encoding, callback) {
128
+ const str = buffer + (Buffer.isBuffer(chunk) ? chunk.toString(encoding) : chunk);
129
+ const lines = str.split(/\r?\n/);
130
+ buffer = lines.pop() || "";
131
+ for (const line of lines) {
132
+ this.push(includeNewlines ? line + "\n" : line);
133
+ }
134
+ callback();
135
+ },
136
+ flush(callback) {
137
+ if (buffer) {
138
+ this.push(buffer);
139
+ }
140
+ callback();
141
+ }
142
+ });
143
+ }
144
+ __name(createLineStream, "createLineStream");
145
+
146
+ exports.bufferToStream = bufferToStream;
147
+ exports.createBatchStream = createBatchStream;
148
+ exports.createLineStream = createLineStream;
149
+ exports.createThrottleStream = createThrottleStream;
150
+ exports.streamToBuffer = streamToBuffer;
151
+ exports.streamToString = streamToString;
@@ -0,0 +1,25 @@
1
+ /*
2
+ * The MIT License
3
+ *
4
+ * Copyright (c) 2025 Catbee Technologies. https://catbee.in/license
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
24
+
25
+ export * from './stream.utils';
@@ -0,0 +1,144 @@
1
+ /*
2
+ * The MIT License
3
+ *
4
+ * Copyright (c) 2025 Catbee Technologies. https://catbee.in/license
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
24
+
25
+ import { Readable, Transform } from 'stream';
26
+
27
+ var __defProp = Object.defineProperty;
28
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
29
+ function bufferToStream(data) {
30
+ const readable = new Readable();
31
+ readable.push(data);
32
+ readable.push(null);
33
+ return readable;
34
+ }
35
+ __name(bufferToStream, "bufferToStream");
36
+ async function streamToBuffer(stream) {
37
+ return new Promise((resolve, reject) => {
38
+ const chunks = [];
39
+ stream.on("data", (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
40
+ stream.on("end", () => resolve(Buffer.concat(chunks)));
41
+ stream.on("error", reject);
42
+ });
43
+ }
44
+ __name(streamToBuffer, "streamToBuffer");
45
+ async function streamToString(stream, encoding = "utf8") {
46
+ const buffer = await streamToBuffer(stream);
47
+ return buffer.toString(encoding);
48
+ }
49
+ __name(streamToString, "streamToString");
50
+ function createThrottleStream(bytesPerSecond) {
51
+ let bytesSent = 0;
52
+ let startTime = Date.now();
53
+ return new Transform({
54
+ transform(chunk, _encoding, callback) {
55
+ const elapsedSeconds = (Date.now() - startTime) / 1e3;
56
+ const targetBytes = bytesPerSecond * elapsedSeconds;
57
+ const chunkSize = chunk.length;
58
+ if (bytesSent + chunkSize <= targetBytes) {
59
+ bytesSent += chunkSize;
60
+ callback(null, chunk);
61
+ return;
62
+ }
63
+ const delay = ((bytesSent + chunkSize) / bytesPerSecond - elapsedSeconds) * 1e3;
64
+ setTimeout(() => {
65
+ bytesSent += chunkSize;
66
+ callback(null, chunk);
67
+ }, delay);
68
+ }
69
+ });
70
+ }
71
+ __name(createThrottleStream, "createThrottleStream");
72
+ function createBatchStream(size, options = {}) {
73
+ const objectMode = options.objectMode !== false;
74
+ let batch = [];
75
+ let buffers = [];
76
+ let bufferSize = 0;
77
+ return new Transform({
78
+ objectMode,
79
+ transform(chunk, _encoding, callback) {
80
+ if (objectMode) {
81
+ batch.push(chunk);
82
+ if (batch.length >= size) {
83
+ this.push(batch);
84
+ batch = [];
85
+ }
86
+ } else {
87
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
88
+ buffers.push(buffer);
89
+ bufferSize += buffer.length;
90
+ let combined = Buffer.concat(buffers, bufferSize);
91
+ while (combined.length >= size) {
92
+ this.push(combined.slice(0, size));
93
+ combined = combined.slice(size);
94
+ }
95
+ buffers = combined.length > 0 ? [
96
+ combined
97
+ ] : [];
98
+ bufferSize = combined.length;
99
+ }
100
+ callback();
101
+ },
102
+ flush(callback) {
103
+ if (objectMode && batch.length > 0) {
104
+ this.push(batch);
105
+ } else if (!objectMode && buffers.length > 0 && bufferSize > 0) {
106
+ let combined = Buffer.concat(buffers, bufferSize);
107
+ while (combined.length >= size) {
108
+ this.push(combined.slice(0, size));
109
+ combined = combined.slice(size);
110
+ }
111
+ if (combined.length > 0) {
112
+ this.push(combined);
113
+ }
114
+ }
115
+ callback();
116
+ }
117
+ });
118
+ }
119
+ __name(createBatchStream, "createBatchStream");
120
+ function createLineStream(options = {}) {
121
+ const { encoding = "utf8", includeNewlines = false } = options;
122
+ let buffer = "";
123
+ return new Transform({
124
+ objectMode: true,
125
+ transform(chunk, _encoding, callback) {
126
+ const str = buffer + (Buffer.isBuffer(chunk) ? chunk.toString(encoding) : chunk);
127
+ const lines = str.split(/\r?\n/);
128
+ buffer = lines.pop() || "";
129
+ for (const line of lines) {
130
+ this.push(includeNewlines ? line + "\n" : line);
131
+ }
132
+ callback();
133
+ },
134
+ flush(callback) {
135
+ if (buffer) {
136
+ this.push(buffer);
137
+ }
138
+ callback();
139
+ }
140
+ });
141
+ }
142
+ __name(createLineStream, "createLineStream");
143
+
144
+ export { bufferToStream, createBatchStream, createLineStream, createThrottleStream, streamToBuffer, streamToString };