jtcsv 2.2.8 → 3.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 (246) hide show
  1. package/README.md +204 -115
  2. package/bin/jtcsv.ts +2612 -0
  3. package/browser.d.ts +142 -0
  4. package/dist/benchmark.js +446 -0
  5. package/dist/benchmark.js.map +1 -0
  6. package/dist/bin/jtcsv.js +1940 -0
  7. package/dist/bin/jtcsv.js.map +1 -0
  8. package/dist/csv-to-json.js +1262 -0
  9. package/dist/csv-to-json.js.map +1 -0
  10. package/dist/errors.js +291 -0
  11. package/dist/errors.js.map +1 -0
  12. package/dist/eslint.config.js +147 -0
  13. package/dist/eslint.config.js.map +1 -0
  14. package/dist/index-core.js +95 -0
  15. package/dist/index-core.js.map +1 -0
  16. package/dist/index.js +93 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/json-save.js +229 -0
  19. package/dist/json-save.js.map +1 -0
  20. package/dist/json-to-csv.js +576 -0
  21. package/dist/json-to-csv.js.map +1 -0
  22. package/dist/jtcsv-core.cjs.js +1736 -0
  23. package/dist/jtcsv-core.cjs.js.map +1 -0
  24. package/dist/jtcsv-core.esm.js +1708 -0
  25. package/dist/jtcsv-core.esm.js.map +1 -0
  26. package/dist/jtcsv-core.umd.js +1742 -0
  27. package/dist/jtcsv-core.umd.js.map +1 -0
  28. package/dist/jtcsv-full.cjs.js +2241 -0
  29. package/dist/jtcsv-full.cjs.js.map +1 -0
  30. package/dist/jtcsv-full.esm.js +2209 -0
  31. package/dist/jtcsv-full.esm.js.map +1 -0
  32. package/dist/jtcsv-full.umd.js +2247 -0
  33. package/dist/jtcsv-full.umd.js.map +1 -0
  34. package/dist/jtcsv-workers.esm.js +768 -0
  35. package/dist/jtcsv-workers.esm.js.map +1 -0
  36. package/dist/jtcsv-workers.umd.js +782 -0
  37. package/dist/jtcsv-workers.umd.js.map +1 -0
  38. package/dist/jtcsv.cjs.js +1996 -2048
  39. package/dist/jtcsv.cjs.js.map +1 -1
  40. package/dist/jtcsv.esm.js +1992 -2048
  41. package/dist/jtcsv.esm.js.map +1 -1
  42. package/dist/jtcsv.umd.js +2157 -2209
  43. package/dist/jtcsv.umd.js.map +1 -1
  44. package/dist/plugins/express-middleware/index.js +350 -0
  45. package/dist/plugins/express-middleware/index.js.map +1 -0
  46. package/dist/plugins/fastify-plugin/index.js +315 -0
  47. package/dist/plugins/fastify-plugin/index.js.map +1 -0
  48. package/dist/plugins/hono/index.js +111 -0
  49. package/dist/plugins/hono/index.js.map +1 -0
  50. package/dist/plugins/nestjs/index.js +112 -0
  51. package/dist/plugins/nestjs/index.js.map +1 -0
  52. package/dist/plugins/nuxt/index.js +53 -0
  53. package/dist/plugins/nuxt/index.js.map +1 -0
  54. package/dist/plugins/remix/index.js +133 -0
  55. package/dist/plugins/remix/index.js.map +1 -0
  56. package/dist/plugins/sveltekit/index.js +155 -0
  57. package/dist/plugins/sveltekit/index.js.map +1 -0
  58. package/dist/plugins/trpc/index.js +136 -0
  59. package/dist/plugins/trpc/index.js.map +1 -0
  60. package/dist/run-demo.js +49 -0
  61. package/dist/run-demo.js.map +1 -0
  62. package/dist/src/browser/browser-functions.js +193 -0
  63. package/dist/src/browser/browser-functions.js.map +1 -0
  64. package/dist/src/browser/core.js +123 -0
  65. package/dist/src/browser/core.js.map +1 -0
  66. package/dist/src/browser/csv-to-json-browser.js +353 -0
  67. package/dist/src/browser/csv-to-json-browser.js.map +1 -0
  68. package/dist/src/browser/errors-browser.js +219 -0
  69. package/dist/src/browser/errors-browser.js.map +1 -0
  70. package/dist/src/browser/extensions/plugins.js +106 -0
  71. package/dist/src/browser/extensions/plugins.js.map +1 -0
  72. package/dist/src/browser/extensions/workers.js +66 -0
  73. package/dist/src/browser/extensions/workers.js.map +1 -0
  74. package/dist/src/browser/index.js +140 -0
  75. package/dist/src/browser/index.js.map +1 -0
  76. package/dist/src/browser/json-to-csv-browser.js +225 -0
  77. package/dist/src/browser/json-to-csv-browser.js.map +1 -0
  78. package/dist/src/browser/streams.js +340 -0
  79. package/dist/src/browser/streams.js.map +1 -0
  80. package/dist/src/browser/workers/csv-parser.worker.js +264 -0
  81. package/dist/src/browser/workers/csv-parser.worker.js.map +1 -0
  82. package/dist/src/browser/workers/worker-pool.js +338 -0
  83. package/dist/src/browser/workers/worker-pool.js.map +1 -0
  84. package/dist/src/core/delimiter-cache.js +196 -0
  85. package/dist/src/core/delimiter-cache.js.map +1 -0
  86. package/dist/src/core/node-optimizations.js +279 -0
  87. package/dist/src/core/node-optimizations.js.map +1 -0
  88. package/dist/src/core/plugin-system.js +399 -0
  89. package/dist/src/core/plugin-system.js.map +1 -0
  90. package/dist/src/core/transform-hooks.js +348 -0
  91. package/dist/src/core/transform-hooks.js.map +1 -0
  92. package/dist/src/engines/fast-path-engine-new.js +262 -0
  93. package/dist/src/engines/fast-path-engine-new.js.map +1 -0
  94. package/dist/src/engines/fast-path-engine.js +671 -0
  95. package/dist/src/engines/fast-path-engine.js.map +1 -0
  96. package/dist/src/errors.js +18 -0
  97. package/dist/src/errors.js.map +1 -0
  98. package/dist/src/formats/ndjson-parser.js +332 -0
  99. package/dist/src/formats/ndjson-parser.js.map +1 -0
  100. package/dist/src/formats/tsv-parser.js +230 -0
  101. package/dist/src/formats/tsv-parser.js.map +1 -0
  102. package/dist/src/index-with-plugins.js +259 -0
  103. package/dist/src/index-with-plugins.js.map +1 -0
  104. package/dist/src/types/index.js +3 -0
  105. package/dist/src/types/index.js.map +1 -0
  106. package/dist/src/utils/bom-utils.js +267 -0
  107. package/dist/src/utils/bom-utils.js.map +1 -0
  108. package/dist/src/utils/encoding-support.js +77 -0
  109. package/dist/src/utils/encoding-support.js.map +1 -0
  110. package/dist/src/utils/schema-validator.js +609 -0
  111. package/dist/src/utils/schema-validator.js.map +1 -0
  112. package/dist/src/utils/transform-loader.js +281 -0
  113. package/dist/src/utils/transform-loader.js.map +1 -0
  114. package/dist/src/utils/validators.js +40 -0
  115. package/dist/src/utils/validators.js.map +1 -0
  116. package/dist/src/utils/zod-adapter.js +144 -0
  117. package/dist/src/utils/zod-adapter.js.map +1 -0
  118. package/dist/src/web-server/index.js +648 -0
  119. package/dist/src/web-server/index.js.map +1 -0
  120. package/dist/src/workers/csv-multithreaded.js +211 -0
  121. package/dist/src/workers/csv-multithreaded.js.map +1 -0
  122. package/dist/src/workers/csv-parser.worker.js +179 -0
  123. package/dist/src/workers/csv-parser.worker.js.map +1 -0
  124. package/dist/src/workers/worker-pool.js +228 -0
  125. package/dist/src/workers/worker-pool.js.map +1 -0
  126. package/dist/stream-csv-to-json.js +665 -0
  127. package/dist/stream-csv-to-json.js.map +1 -0
  128. package/dist/stream-json-to-csv.js +389 -0
  129. package/dist/stream-json-to-csv.js.map +1 -0
  130. package/examples/advanced/conditional-transformations.ts +446 -0
  131. package/examples/advanced/csv-parser.worker.ts +89 -0
  132. package/examples/advanced/nested-objects-example.ts +306 -0
  133. package/examples/advanced/performance-optimization.ts +504 -0
  134. package/examples/advanced/run-demo-server.ts +116 -0
  135. package/examples/advanced/web-worker-usage.html +874 -0
  136. package/examples/async-multithreaded-example.ts +335 -0
  137. package/examples/cli-advanced-usage.md +290 -0
  138. package/examples/{cli-batch-processing.js → cli-batch-processing.ts} +38 -38
  139. package/examples/{cli-tool.js → cli-tool.ts} +5 -8
  140. package/examples/{error-handling.js → error-handling.ts} +356 -324
  141. package/examples/{express-api.js → express-api.ts} +161 -164
  142. package/examples/{large-dataset-example.js → large-dataset-example.ts} +201 -182
  143. package/examples/{ndjson-processing.js → ndjson-processing.ts} +456 -434
  144. package/examples/{plugin-excel-exporter.js → plugin-excel-exporter.ts} +6 -7
  145. package/examples/react-integration.tsx +637 -0
  146. package/examples/{schema-validation.js → schema-validation.ts} +2 -2
  147. package/examples/simple-usage.ts +194 -0
  148. package/examples/{streaming-example.js → streaming-example.ts} +12 -12
  149. package/index.d.ts +187 -18
  150. package/package.json +75 -81
  151. package/plugins.d.ts +37 -0
  152. package/schema.d.ts +103 -0
  153. package/src/browser/browser-functions.ts +402 -0
  154. package/src/browser/core.ts +152 -0
  155. package/src/browser/csv-to-json-browser.d.ts +3 -0
  156. package/src/browser/csv-to-json-browser.ts +494 -0
  157. package/src/browser/{errors-browser.js → errors-browser.ts} +305 -197
  158. package/src/browser/extensions/plugins.ts +93 -0
  159. package/src/browser/extensions/workers.ts +39 -0
  160. package/src/browser/globals.d.ts +5 -0
  161. package/src/browser/index.ts +192 -0
  162. package/src/browser/json-to-csv-browser.d.ts +3 -0
  163. package/src/browser/json-to-csv-browser.ts +338 -0
  164. package/src/browser/streams.ts +403 -0
  165. package/src/browser/workers/{csv-parser.worker.js → csv-parser.worker.ts} +3 -3
  166. package/src/browser/workers/{worker-pool.js → worker-pool.ts} +51 -30
  167. package/src/core/delimiter-cache.ts +320 -0
  168. package/src/core/{node-optimizations.js → node-optimizations.ts} +448 -407
  169. package/src/core/plugin-system.ts +588 -0
  170. package/src/core/transform-hooks.ts +566 -0
  171. package/src/engines/{fast-path-engine-new.js → fast-path-engine-new.ts} +11 -2
  172. package/src/engines/{fast-path-engine.js → fast-path-engine.ts} +79 -53
  173. package/src/errors.ts +1 -0
  174. package/src/formats/{ndjson-parser.js → ndjson-parser.ts} +24 -16
  175. package/src/formats/{tsv-parser.js → tsv-parser.ts} +18 -17
  176. package/src/{index-with-plugins.js → index-with-plugins.ts} +381 -357
  177. package/src/types/index.ts +275 -0
  178. package/src/utils/bom-utils.ts +373 -0
  179. package/src/utils/encoding-support.ts +155 -0
  180. package/src/utils/{schema-validator.js → schema-validator.ts} +814 -589
  181. package/src/utils/transform-loader.ts +389 -0
  182. package/src/utils/validators.ts +35 -0
  183. package/src/utils/zod-adapter.ts +280 -0
  184. package/src/web-server/{index.js → index.ts} +19 -19
  185. package/src/workers/csv-multithreaded.ts +310 -0
  186. package/src/workers/csv-parser.worker.ts +227 -0
  187. package/src/workers/worker-pool.ts +409 -0
  188. package/bin/jtcsv.js +0 -2462
  189. package/csv-to-json.js +0 -688
  190. package/errors.js +0 -208
  191. package/examples/simple-usage.js +0 -282
  192. package/index.js +0 -68
  193. package/json-save.js +0 -254
  194. package/json-to-csv.js +0 -526
  195. package/plugins/README.md +0 -91
  196. package/plugins/express-middleware/README.md +0 -64
  197. package/plugins/express-middleware/example.js +0 -136
  198. package/plugins/express-middleware/index.d.ts +0 -114
  199. package/plugins/express-middleware/index.js +0 -360
  200. package/plugins/express-middleware/package.json +0 -52
  201. package/plugins/fastify-plugin/index.js +0 -406
  202. package/plugins/fastify-plugin/package.json +0 -55
  203. package/plugins/hono/README.md +0 -28
  204. package/plugins/hono/index.d.ts +0 -12
  205. package/plugins/hono/index.js +0 -36
  206. package/plugins/hono/package.json +0 -35
  207. package/plugins/nestjs/README.md +0 -35
  208. package/plugins/nestjs/index.d.ts +0 -25
  209. package/plugins/nestjs/index.js +0 -77
  210. package/plugins/nestjs/package.json +0 -37
  211. package/plugins/nextjs-api/README.md +0 -57
  212. package/plugins/nextjs-api/examples/ConverterComponent.jsx +0 -386
  213. package/plugins/nextjs-api/examples/api-convert.js +0 -69
  214. package/plugins/nextjs-api/index.js +0 -387
  215. package/plugins/nextjs-api/package.json +0 -63
  216. package/plugins/nextjs-api/route.js +0 -371
  217. package/plugins/nuxt/README.md +0 -24
  218. package/plugins/nuxt/index.js +0 -21
  219. package/plugins/nuxt/package.json +0 -35
  220. package/plugins/nuxt/runtime/composables/useJtcsv.js +0 -6
  221. package/plugins/nuxt/runtime/plugin.js +0 -6
  222. package/plugins/remix/README.md +0 -26
  223. package/plugins/remix/index.d.ts +0 -16
  224. package/plugins/remix/index.js +0 -62
  225. package/plugins/remix/package.json +0 -35
  226. package/plugins/sveltekit/README.md +0 -28
  227. package/plugins/sveltekit/index.d.ts +0 -17
  228. package/plugins/sveltekit/index.js +0 -54
  229. package/plugins/sveltekit/package.json +0 -33
  230. package/plugins/trpc/README.md +0 -25
  231. package/plugins/trpc/index.d.ts +0 -7
  232. package/plugins/trpc/index.js +0 -32
  233. package/plugins/trpc/package.json +0 -34
  234. package/src/browser/browser-functions.js +0 -219
  235. package/src/browser/csv-to-json-browser.js +0 -700
  236. package/src/browser/index.js +0 -113
  237. package/src/browser/json-to-csv-browser.js +0 -309
  238. package/src/browser/streams.js +0 -393
  239. package/src/core/delimiter-cache.js +0 -186
  240. package/src/core/plugin-system.js +0 -476
  241. package/src/core/transform-hooks.js +0 -350
  242. package/src/errors.js +0 -26
  243. package/src/utils/transform-loader.js +0 -205
  244. package/stream-csv-to-json.js +0 -542
  245. package/stream-json-to-csv.js +0 -464
  246. /package/examples/{web-workers-advanced.js → web-workers-advanced.ts} +0 -0
@@ -0,0 +1,350 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.jtcsvExpressMiddleware = jtcsvExpressMiddleware;
4
+ exports.jtcsvCsvToJsonRoute = jtcsvCsvToJsonRoute;
5
+ exports.jtcsvJsonToCsvRoute = jtcsvJsonToCsvRoute;
6
+ exports.jtcsvUploadCsvRoute = jtcsvUploadCsvRoute;
7
+ exports.jtcsvHealthCheck = jtcsvHealthCheck;
8
+ const index_core_1 = require("../../index-core");
9
+ const errors_1 = require("../../errors");
10
+ function parseSizeToBytes(sizeStr) {
11
+ if (typeof sizeStr === 'number') {
12
+ return sizeStr;
13
+ }
14
+ if (typeof sizeStr !== 'string') {
15
+ return 10 * 1024 * 1024;
16
+ }
17
+ const match = sizeStr.match(/^(\d+(?:\.\d+)?)\s*(B|KB|MB|GB|TB)$/i);
18
+ if (!match) {
19
+ return 10 * 1024 * 1024;
20
+ }
21
+ const value = parseFloat(match[1]);
22
+ const unit = match[2].toUpperCase();
23
+ switch (unit) {
24
+ case 'B': return value;
25
+ case 'KB': return value * 1024;
26
+ case 'MB': return value * 1024 * 1024;
27
+ case 'GB': return value * 1024 * 1024 * 1024;
28
+ case 'TB': return value * 1024 * 1024 * 1024 * 1024;
29
+ default: return value * 1024 * 1024;
30
+ }
31
+ }
32
+ function jtcsvExpressMiddleware(options = {}) {
33
+ const { maxSize = '10mb', maxFileSize = '500MB', maxFieldSize = 1024 * 1024, timeout = 300000, autoDetect = true, delimiter = ',', enableFastPath = true, preventCsvInjection = true, rfc4180Compliant = true, useAsync = true, useWorkers, workerCount, conversionOptions = {} } = options;
34
+ return async (req, res, next) => {
35
+ if (process.env.NODE_ENV !== 'test') {
36
+ console.log('[jtcsv-middleware] Request received:', req.method, req.url, req.headers['content-type']);
37
+ }
38
+ req.startTime = Date.now();
39
+ if (!req.body || (typeof req.body !== 'string' && typeof req.body !== 'object')) {
40
+ if (process.env.NODE_ENV !== 'test') {
41
+ console.log('[jtcsv-middleware] No body, skipping');
42
+ }
43
+ return next();
44
+ }
45
+ const contentLength = req.get('content-length');
46
+ if (process.env.NODE_ENV !== 'test') {
47
+ console.log(`[jtcsv-middleware] Content-Length: "${contentLength}"`);
48
+ }
49
+ if (contentLength && contentLength.trim() !== '') {
50
+ const maxBytes = parseSizeToBytes(maxFileSize);
51
+ const contentLengthInt = parseInt(contentLength, 10);
52
+ if (process.env.NODE_ENV !== 'test') {
53
+ console.log(`[jtcsv-middleware] maxBytes: ${maxBytes}, contentLengthInt: ${contentLengthInt}`);
54
+ }
55
+ if (contentLengthInt > maxBytes) {
56
+ if (process.env.NODE_ENV !== 'test') {
57
+ console.log(`[jtcsv-middleware] File size limit exceeded: ${contentLengthInt} > ${maxBytes}`);
58
+ }
59
+ res.status(413).json({
60
+ success: false,
61
+ error: `File size exceeds limit of ${maxFileSize}`,
62
+ code: 'FILE_SIZE_LIMIT_EXCEEDED'
63
+ });
64
+ return;
65
+ }
66
+ }
67
+ const contentType = req.get('content-type') || '';
68
+ const acceptHeader = req.get('accept') || 'application/json';
69
+ let inputFormat = 'unknown';
70
+ const inputData = req.body;
71
+ if (autoDetect) {
72
+ if (contentType.includes('application/json') ||
73
+ (req.body !== null && typeof req.body === 'object' && !Array.isArray(req.body))) {
74
+ inputFormat = 'json';
75
+ }
76
+ else if (contentType.includes('text/csv') ||
77
+ contentType.includes('text/plain') ||
78
+ (typeof req.body === 'string' && req.body.includes(','))) {
79
+ inputFormat = 'csv';
80
+ }
81
+ }
82
+ else {
83
+ if (contentType.includes('application/json')) {
84
+ inputFormat = 'json';
85
+ }
86
+ else if (contentType.includes('text/csv')) {
87
+ inputFormat = 'csv';
88
+ }
89
+ }
90
+ if (inputFormat === 'unknown') {
91
+ return next();
92
+ }
93
+ let timeoutId;
94
+ const timeoutPromise = new Promise((_, reject) => {
95
+ timeoutId = setTimeout(() => {
96
+ reject(new Error(`Request processing timeout (${timeout}ms)`));
97
+ }, timeout);
98
+ });
99
+ try {
100
+ const processingPromise = (async () => {
101
+ let outputFormat = 'json';
102
+ if (acceptHeader.includes('text/csv')) {
103
+ outputFormat = 'csv';
104
+ }
105
+ else if (req.query.format === 'csv') {
106
+ outputFormat = 'csv';
107
+ }
108
+ else if (req.body?.format === 'csv') {
109
+ outputFormat = 'csv';
110
+ }
111
+ const mergedConversionOptions = {
112
+ delimiter,
113
+ preventCsvInjection,
114
+ rfc4180Compliant,
115
+ useFastPath: enableFastPath,
116
+ maxFieldSize,
117
+ useWorkers,
118
+ workerCount,
119
+ ...req.query,
120
+ ...conversionOptions
121
+ };
122
+ delete mergedConversionOptions.maxSize;
123
+ delete mergedConversionOptions.maxFileSize;
124
+ delete mergedConversionOptions.maxFieldSize;
125
+ delete mergedConversionOptions.timeout;
126
+ delete mergedConversionOptions.autoDetect;
127
+ delete mergedConversionOptions.enableFastPath;
128
+ delete mergedConversionOptions.useAsync;
129
+ delete mergedConversionOptions.useWorkers;
130
+ delete mergedConversionOptions.workerCount;
131
+ let result;
132
+ const stats = {
133
+ inputSize: 0,
134
+ outputSize: 0,
135
+ processingTime: 0,
136
+ conversion: `${inputFormat}→${outputFormat}`
137
+ };
138
+ const startTime = Date.now();
139
+ if (inputFormat === 'json' && outputFormat === 'csv') {
140
+ const jsonData = typeof inputData === 'string' ? JSON.parse(inputData) : inputData;
141
+ stats.inputSize = Buffer.byteLength(JSON.stringify(jsonData));
142
+ if (useAsync) {
143
+ result = await (0, index_core_1.jsonToCsvAsync)(jsonData, mergedConversionOptions);
144
+ }
145
+ else {
146
+ result = (0, index_core_1.jsonToCsv)(jsonData, mergedConversionOptions);
147
+ }
148
+ stats.outputSize = Buffer.byteLength(result);
149
+ }
150
+ else if (inputFormat === 'csv' && outputFormat === 'json') {
151
+ const csvData = typeof inputData === 'string' ? inputData : String(inputData);
152
+ stats.inputSize = Buffer.byteLength(csvData);
153
+ if (useAsync) {
154
+ result = await (0, index_core_1.csvToJsonAsync)(csvData, mergedConversionOptions);
155
+ }
156
+ else {
157
+ result = (0, index_core_1.csvToJson)(csvData, mergedConversionOptions);
158
+ }
159
+ stats.outputSize = Buffer.byteLength(JSON.stringify(result));
160
+ }
161
+ else {
162
+ result = inputData;
163
+ stats.conversion = 'none';
164
+ }
165
+ stats.processingTime = Date.now() - startTime;
166
+ req.converted = {
167
+ data: result,
168
+ format: outputFormat,
169
+ inputFormat,
170
+ outputFormat,
171
+ stats,
172
+ options: mergedConversionOptions
173
+ };
174
+ if (outputFormat === 'csv') {
175
+ res.set('Content-Type', 'text/csv; charset=utf-8');
176
+ }
177
+ else {
178
+ res.set('Content-Type', 'application/json; charset=utf-8');
179
+ }
180
+ next();
181
+ })();
182
+ await Promise.race([processingPromise, timeoutPromise]);
183
+ }
184
+ catch (error) {
185
+ const err = error;
186
+ if (process.env.NODE_ENV !== 'test') {
187
+ console.log('[jtcsv-middleware] Conversion error:', err.message, err.stack?.split('\n')[0]);
188
+ }
189
+ let statusCode = 400;
190
+ if (err.message.includes('timeout') || err.message.includes('Timeout')) {
191
+ statusCode = 408;
192
+ }
193
+ else if (err.message.includes('File size exceeds limit')) {
194
+ statusCode = 413;
195
+ }
196
+ else if (err instanceof errors_1.SecurityError) {
197
+ statusCode = 403;
198
+ }
199
+ else if (err instanceof errors_1.ValidationError) {
200
+ statusCode = 422;
201
+ }
202
+ else if (err instanceof errors_1.FileSystemError) {
203
+ statusCode = 500;
204
+ }
205
+ else if (err instanceof errors_1.JtcsvError) {
206
+ statusCode = 400;
207
+ }
208
+ const errorResponse = {
209
+ success: false,
210
+ error: err.message,
211
+ code: err.code || 'CONVERSION_ERROR',
212
+ timestamp: new Date().toISOString()
213
+ };
214
+ if (process.env.NODE_ENV === 'development') {
215
+ errorResponse.stack = err.stack;
216
+ errorResponse.details = {
217
+ contentType: req.get('content-type'),
218
+ contentLength: req.get('content-length'),
219
+ method: req.method,
220
+ url: req.url
221
+ };
222
+ }
223
+ res.status(statusCode).json(errorResponse);
224
+ }
225
+ finally {
226
+ if (timeoutId) {
227
+ clearTimeout(timeoutId);
228
+ }
229
+ }
230
+ };
231
+ }
232
+ function jtcsvCsvToJsonRoute(options = {}) {
233
+ return async (req, res) => {
234
+ try {
235
+ const csvData = req.body;
236
+ if (!csvData || (typeof csvData !== 'string' && !Buffer.isBuffer(csvData))) {
237
+ res.status(400).json({
238
+ success: false,
239
+ error: 'CSV data is required'
240
+ });
241
+ return;
242
+ }
243
+ const csvString = Buffer.isBuffer(csvData) ? csvData.toString() : csvData;
244
+ const result = await (0, index_core_1.csvToJsonAsync)(csvString, options);
245
+ res.json({
246
+ success: true,
247
+ data: result,
248
+ stats: {
249
+ rows: result.length,
250
+ processingTime: Date.now() - (req.startTime || Date.now())
251
+ }
252
+ });
253
+ }
254
+ catch (error) {
255
+ const err = error;
256
+ res.status(400).json({
257
+ success: false,
258
+ error: err.message
259
+ });
260
+ }
261
+ };
262
+ }
263
+ function jtcsvJsonToCsvRoute(options = {}) {
264
+ return async (req, res) => {
265
+ try {
266
+ const jsonData = req.body;
267
+ if (!jsonData || (typeof jsonData !== 'object' && typeof jsonData !== 'string')) {
268
+ res.status(400).json({
269
+ success: false,
270
+ error: 'JSON data is required'
271
+ });
272
+ return;
273
+ }
274
+ const data = typeof jsonData === 'string' ? JSON.parse(jsonData) : jsonData;
275
+ const result = await (0, index_core_1.jsonToCsvAsync)(data, options);
276
+ res.set('Content-Type', 'text/csv; charset=utf-8');
277
+ res.set('Content-Disposition', 'attachment; filename="data.csv"');
278
+ res.send(result);
279
+ }
280
+ catch (error) {
281
+ const err = error;
282
+ res.status(400).json({
283
+ success: false,
284
+ error: err.message
285
+ });
286
+ }
287
+ };
288
+ }
289
+ function jtcsvUploadCsvRoute(options = {}) {
290
+ return async (req, res) => {
291
+ try {
292
+ if (!req.file) {
293
+ res.status(400).json({
294
+ success: false,
295
+ error: 'CSV file is required'
296
+ });
297
+ return;
298
+ }
299
+ const fs = require('fs').promises;
300
+ const csvData = await fs.readFile(req.file.path, 'utf8');
301
+ const result = await (0, index_core_1.csvToJsonAsync)(csvData, options);
302
+ await fs.unlink(req.file.path);
303
+ res.json({
304
+ success: true,
305
+ data: result,
306
+ stats: {
307
+ rows: result.length,
308
+ fileSize: req.file.size,
309
+ processingTime: Date.now() - (req.startTime || Date.now())
310
+ }
311
+ });
312
+ }
313
+ catch (error) {
314
+ const err = error;
315
+ res.status(400).json({
316
+ success: false,
317
+ error: err.message
318
+ });
319
+ }
320
+ };
321
+ }
322
+ function jtcsvHealthCheck() {
323
+ return (req, res) => {
324
+ res.json({
325
+ service: 'jtcsv-express-middleware',
326
+ status: 'healthy',
327
+ version: '2.0.0',
328
+ timestamp: new Date().toISOString(),
329
+ features: {
330
+ csvToJson: true,
331
+ jsonToCsv: true,
332
+ fastPathEngine: true,
333
+ csvInjectionProtection: true,
334
+ streaming: true,
335
+ asyncProcessing: true,
336
+ workerPool: true
337
+ }
338
+ });
339
+ };
340
+ }
341
+ exports.default = {
342
+ middleware: jtcsvExpressMiddleware,
343
+ csvToJsonRoute: jtcsvCsvToJsonRoute,
344
+ jsonToCsvRoute: jtcsvJsonToCsvRoute,
345
+ uploadCsvRoute: jtcsvUploadCsvRoute,
346
+ healthCheck: jtcsvHealthCheck,
347
+ jtcsvMiddleware: jtcsvExpressMiddleware,
348
+ createMiddleware: jtcsvExpressMiddleware
349
+ };
350
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../plugins/express-middleware/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * Express middleware для JTCSV\r\n * Автоматическая конвертация CSV/JSON в HTTP запросах\r\n *\r\n * @version 2.0.0 - TypeScript версия с асинхронной поддержкой\r\n * @date 2026-01-29\r\n */\r\n\r\nimport { Request, Response, NextFunction } from 'express';\r\nimport { csvToJson, csvToJsonAsync, jsonToCsv, jsonToCsvAsync } from '../../index-core';\r\nimport { JtcsvError, ValidationError, SecurityError, FileSystemError } from '../../errors';\r\n\r\n/**\r\n * Интерфейс опций Express middleware\r\n */\r\nexport interface JtcsvExpressMiddlewareOptions {\r\n /** Максимальный размер тела запроса (default: '10mb') */\r\n maxSize?: string;\r\n /** Максимальный размер файла (например, '500MB', default: '500MB') */\r\n maxFileSize?: string;\r\n /** Максимальный размер поля в байтах (default: 1MB) */\r\n maxFieldSize?: number;\r\n /** Таймаут обработки в миллисекундах (default: 300000 = 5 минут) */\r\n timeout?: number;\r\n /** Автоматическое определение формата (default: true) */\r\n autoDetect?: boolean;\r\n /** Разделитель CSV (default: ',') */\r\n delimiter?: string;\r\n /** Включить Fast-Path Engine (default: true) */\r\n enableFastPath?: boolean;\r\n /** Защита от CSV инъекций (default: true) */\r\n preventCsvInjection?: boolean;\r\n /** Соблюдение RFC4180 (default: true) */\r\n rfc4180Compliant?: boolean;\r\n /** Дополнительные опции конвертации */\r\n conversionOptions?: Record<string, any>;\r\n /** Использовать асинхронные версии функций (default: true) */\r\n useAsync?: boolean;\r\n /** Использовать многопоточную обработку для больших данных (default: auto-detect) */\r\n useWorkers?: boolean;\r\n /** Количество worker'ов для многопоточной обработки (default: CPU cores - 1) */\r\n workerCount?: number;\r\n}\r\n\r\n/**\r\n * Интерфейс конвертированных данных в request object\r\n */\r\nexport interface ConvertedData {\r\n /** Конвертированные данные */\r\n data: any;\r\n /** Формат вывода */\r\n format: 'json' | 'csv';\r\n /** Формат ввода */\r\n inputFormat: 'json' | 'csv' | 'unknown';\r\n /** Формат вывода */\r\n outputFormat: 'json' | 'csv';\r\n /** Статистика обработки */\r\n stats: {\r\n inputSize: number;\r\n outputSize: number;\r\n processingTime: number;\r\n conversion: string;\r\n workerCount?: number;\r\n };\r\n /** Опции конвертации */\r\n options: Record<string, any>;\r\n}\r\n\r\n/**\r\n * Расширенный интерфейс Request с конвертированными данными\r\n */\r\ndeclare global {\r\n namespace Express {\r\n interface Request {\r\n /** Конвертированные данные */\r\n converted?: ConvertedData;\r\n /** Время начала обработки */\r\n startTime?: number;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Преобразует строку размера (например, '500MB') в байты\r\n * @param sizeStr - Строка размера (например, '10MB', '1GB', '500KB')\r\n * @returns Размер в байтах\r\n */\r\nfunction parseSizeToBytes(sizeStr: string | number): number {\r\n if (typeof sizeStr === 'number') {\r\n return sizeStr;\r\n }\r\n if (typeof sizeStr !== 'string') {\r\n return 10 * 1024 * 1024; // default 10MB\r\n }\r\n \r\n const match = sizeStr.match(/^(\\d+(?:\\.\\d+)?)\\s*(B|KB|MB|GB|TB)$/i);\r\n if (!match) {\r\n return 10 * 1024 * 1024;\r\n }\r\n \r\n const value = parseFloat(match[1]);\r\n const unit = match[2].toUpperCase();\r\n \r\n switch (unit) {\r\n case 'B': return value;\r\n case 'KB': return value * 1024;\r\n case 'MB': return value * 1024 * 1024;\r\n case 'GB': return value * 1024 * 1024 * 1024;\r\n case 'TB': return value * 1024 * 1024 * 1024 * 1024;\r\n default: return value * 1024 * 1024;\r\n }\r\n}\r\n\r\n/**\r\n * Express middleware для обработки CSV/JSON конвертации\r\n * \r\n * @param options - Опции middleware\r\n * @returns Express middleware\r\n * \r\n * @example\r\n * // Базовое использование\r\n * const app = express();\r\n * app.use(express.json());\r\n * app.use(express.text({ type: 'text/csv' }));\r\n * app.use(jtcsvExpressMiddleware());\r\n * \r\n * @example\r\n * // С кастомными опциями\r\n * app.use(jtcsvExpressMiddleware({\r\n * maxSize: '50mb',\r\n * maxFileSize: '1GB',\r\n * maxFieldSize: 5 * 1024 * 1024, // 5MB\r\n * timeout: 600000, // 10 минут\r\n * delimiter: ';',\r\n * enableFastPath: true,\r\n * useAsync: true, // Использовать асинхронные функции\r\n * useWorkers: true // Включить многопоточную обработку\r\n * }));\r\n */\r\nexport function jtcsvExpressMiddleware(options: JtcsvExpressMiddlewareOptions = {}): (req: Request, res: Response, next: NextFunction) => Promise<void> {\r\n const {\r\n maxSize = '10mb',\r\n maxFileSize = '500MB',\r\n maxFieldSize = 1024 * 1024, // 1MB\r\n timeout = 300000, // 5 minutes\r\n autoDetect = true,\r\n delimiter = ',',\r\n enableFastPath = true,\r\n preventCsvInjection = true,\r\n rfc4180Compliant = true,\r\n useAsync = true,\r\n useWorkers,\r\n workerCount,\r\n conversionOptions = {}\r\n } = options;\r\n\r\n return async (req: Request, res: Response, next: NextFunction): Promise<void> => {\r\n if (process.env.NODE_ENV !== 'test') {\r\n console.log('[jtcsv-middleware] Request received:', req.method, req.url, req.headers['content-type']);\r\n }\r\n \r\n // Устанавливаем время начала обработки\r\n req.startTime = Date.now();\r\n \r\n // Пропускаем запросы без тела\r\n if (!req.body || (typeof req.body !== 'string' && typeof req.body !== 'object')) {\r\n if (process.env.NODE_ENV !== 'test') {\r\n console.log('[jtcsv-middleware] No body, skipping');\r\n }\r\n return next();\r\n }\r\n\r\n // Проверка размера файла\r\n const contentLength = req.get('content-length');\r\n if (process.env.NODE_ENV !== 'test') {\r\n console.log(`[jtcsv-middleware] Content-Length: \"${contentLength}\"`);\r\n }\r\n if (contentLength && contentLength.trim() !== '') {\r\n const maxBytes = parseSizeToBytes(maxFileSize);\r\n const contentLengthInt = parseInt(contentLength, 10);\r\n if (process.env.NODE_ENV !== 'test') {\r\n console.log(`[jtcsv-middleware] maxBytes: ${maxBytes}, contentLengthInt: ${contentLengthInt}`);\r\n }\r\n if (contentLengthInt > maxBytes) {\r\n if (process.env.NODE_ENV !== 'test') {\r\n console.log(`[jtcsv-middleware] File size limit exceeded: ${contentLengthInt} > ${maxBytes}`);\r\n }\r\n res.status(413).json({\r\n success: false,\r\n error: `File size exceeds limit of ${maxFileSize}`,\r\n code: 'FILE_SIZE_LIMIT_EXCEEDED'\r\n });\r\n return;\r\n }\r\n }\r\n\r\n const contentType = req.get('content-type') || '';\r\n const acceptHeader = req.get('accept') || 'application/json';\r\n \r\n // Определяем формат входных данных заранее\r\n let inputFormat: 'json' | 'csv' | 'unknown' = 'unknown';\r\n const inputData = req.body;\r\n \r\n if (autoDetect) {\r\n if (contentType.includes('application/json') ||\r\n (req.body !== null && typeof req.body === 'object' && !Array.isArray(req.body))) {\r\n inputFormat = 'json';\r\n } else if (contentType.includes('text/csv') ||\r\n contentType.includes('text/plain') ||\r\n (typeof req.body === 'string' && req.body.includes(','))) {\r\n inputFormat = 'csv';\r\n }\r\n } else {\r\n // Ручное определение на основе content-type\r\n if (contentType.includes('application/json')) {\r\n inputFormat = 'json';\r\n } else if (contentType.includes('text/csv')) {\r\n inputFormat = 'csv';\r\n }\r\n }\r\n\r\n // Если формат не определен, пропускаем\r\n if (inputFormat === 'unknown') {\r\n return next();\r\n }\r\n \r\n // Установка таймаута\r\n let timeoutId: NodeJS.Timeout;\r\n const timeoutPromise = new Promise((_, reject) => {\r\n timeoutId = setTimeout(() => {\r\n reject(new Error(`Request processing timeout (${timeout}ms)`));\r\n }, timeout);\r\n });\r\n \r\n try {\r\n // Обернем основную логику в Promise.race с таймаутом\r\n const processingPromise = (async () => {\r\n // Определяем желаемый формат вывода на основе Accept header\r\n let outputFormat: 'json' | 'csv' = 'json';\r\n if (acceptHeader.includes('text/csv')) {\r\n outputFormat = 'csv';\r\n } else if (req.query.format === 'csv') {\r\n outputFormat = 'csv';\r\n } else if ((req.body as any)?.format === 'csv') {\r\n outputFormat = 'csv';\r\n }\r\n\r\n // Опции конвертации\r\n const mergedConversionOptions: Record<string, any> = {\r\n delimiter,\r\n preventCsvInjection,\r\n rfc4180Compliant,\r\n useFastPath: enableFastPath,\r\n maxFieldSize,\r\n useWorkers,\r\n workerCount,\r\n ...req.query,\r\n ...conversionOptions\r\n };\r\n\r\n // Удаляем параметры, которые не относятся к конвертации\r\n delete mergedConversionOptions.maxSize;\r\n delete mergedConversionOptions.maxFileSize;\r\n delete mergedConversionOptions.maxFieldSize;\r\n delete mergedConversionOptions.timeout;\r\n delete mergedConversionOptions.autoDetect;\r\n delete mergedConversionOptions.enableFastPath;\r\n delete mergedConversionOptions.useAsync;\r\n delete mergedConversionOptions.useWorkers;\r\n delete mergedConversionOptions.workerCount;\r\n\r\n let result: any;\r\n const stats: ConvertedData['stats'] = {\r\n inputSize: 0,\r\n outputSize: 0,\r\n processingTime: 0,\r\n conversion: `${inputFormat}→${outputFormat}`\r\n };\r\n\r\n const startTime = Date.now();\r\n\r\n // Выполняем конвертацию\r\n if (inputFormat === 'json' && outputFormat === 'csv') {\r\n const jsonData = typeof inputData === 'string' ? JSON.parse(inputData) : inputData;\r\n stats.inputSize = Buffer.byteLength(JSON.stringify(jsonData));\r\n \r\n if (useAsync) {\r\n result = await jsonToCsvAsync(jsonData, mergedConversionOptions);\r\n } else {\r\n result = jsonToCsv(jsonData, mergedConversionOptions);\r\n }\r\n stats.outputSize = Buffer.byteLength(result);\r\n \r\n } else if (inputFormat === 'csv' && outputFormat === 'json') {\r\n const csvData = typeof inputData === 'string' ? inputData : String(inputData);\r\n stats.inputSize = Buffer.byteLength(csvData);\r\n \r\n if (useAsync) {\r\n result = await csvToJsonAsync(csvData, mergedConversionOptions);\r\n } else {\r\n result = csvToJson(csvData, mergedConversionOptions);\r\n }\r\n stats.outputSize = Buffer.byteLength(JSON.stringify(result));\r\n \r\n } else {\r\n // Нет необходимости в конвертации\r\n result = inputData;\r\n stats.conversion = 'none';\r\n }\r\n\r\n stats.processingTime = Date.now() - startTime;\r\n\r\n // Сохраняем результат в request object\r\n req.converted = {\r\n data: result,\r\n format: outputFormat,\r\n inputFormat,\r\n outputFormat,\r\n stats,\r\n options: mergedConversionOptions\r\n };\r\n\r\n // Устанавливаем соответствующий Content-Type для ответа\r\n if (outputFormat === 'csv') {\r\n res.set('Content-Type', 'text/csv; charset=utf-8');\r\n } else {\r\n res.set('Content-Type', 'application/json; charset=utf-8');\r\n }\r\n\r\n next();\r\n })();\r\n\r\n // Ждем либо обработку, либо таймаут\r\n await Promise.race([processingPromise, timeoutPromise]);\r\n } catch (error) {\r\n // Обработка ошибок конвертации\r\n const err = error as Error & { code?: string };\r\n if (process.env.NODE_ENV !== 'test') {\r\n console.log('[jtcsv-middleware] Conversion error:', err.message, err.stack?.split('\\n')[0]);\r\n }\r\n \r\n // Определяем статус код на основе типа ошибки\r\n let statusCode = 400;\r\n if (err.message.includes('timeout') || err.message.includes('Timeout')) {\r\n statusCode = 408; // Request Timeout\r\n } else if (err.message.includes('File size exceeds limit')) {\r\n statusCode = 413; // Payload Too Large\r\n } else if (err instanceof SecurityError) {\r\n statusCode = 403; // Forbidden\r\n } else if (err instanceof ValidationError) {\r\n statusCode = 422; // Unprocessable Entity\r\n } else if (err instanceof FileSystemError) {\r\n statusCode = 500; // Internal Server Error\r\n } else if (err instanceof JtcsvError) {\r\n statusCode = 400; // Bad Request\r\n }\r\n \r\n const errorResponse: any = {\r\n success: false,\r\n error: err.message,\r\n code: err.code || 'CONVERSION_ERROR',\r\n timestamp: new Date().toISOString()\r\n };\r\n\r\n // Добавляем дополнительную информацию для отладки\r\n if (process.env.NODE_ENV === 'development') {\r\n errorResponse.stack = err.stack;\r\n errorResponse.details = {\r\n contentType: req.get('content-type'),\r\n contentLength: req.get('content-length'),\r\n method: req.method,\r\n url: req.url\r\n };\r\n }\r\n\r\n res.status(statusCode).json(errorResponse);\r\n } finally {\r\n // Очищаем таймаут\r\n if (timeoutId) {\r\n clearTimeout(timeoutId);\r\n }\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Express route для конвертации CSV в JSON\r\n * \r\n * @param options - Опции конвертации\r\n * @returns Express route handler\r\n * \r\n * @example\r\n * app.post('/api/csv-to-json', jtcsvCsvToJsonRoute());\r\n */\r\nexport function jtcsvCsvToJsonRoute(options: Record<string, any> = {}): (req: Request, res: Response) => Promise<void> {\r\n return async (req: Request, res: Response): Promise<void> => {\r\n try {\r\n const csvData = req.body;\r\n \r\n if (!csvData || (typeof csvData !== 'string' && !Buffer.isBuffer(csvData))) {\r\n res.status(400).json({\r\n success: false,\r\n error: 'CSV data is required'\r\n });\r\n return;\r\n }\r\n\r\n const csvString = Buffer.isBuffer(csvData) ? csvData.toString() : csvData;\r\n const result = await csvToJsonAsync(csvString, options);\r\n \r\n res.json({\r\n success: true,\r\n data: result,\r\n stats: {\r\n rows: result.length,\r\n processingTime: Date.now() - (req.startTime || Date.now())\r\n }\r\n });\r\n } catch (error) {\r\n const err = error as Error;\r\n res.status(400).json({\r\n success: false,\r\n error: err.message\r\n });\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Express route для конвертации JSON в CSV\r\n * \r\n * @param options - Опции конвертации\r\n * @returns Express route handler\r\n * \r\n * @example\r\n * app.post('/api/json-to-csv', jtcsvJsonToCsvRoute());\r\n */\r\nexport function jtcsvJsonToCsvRoute(options: Record<string, any> = {}): (req: Request, res: Response) => Promise<void> {\r\n return async (req: Request, res: Response): Promise<void> => {\r\n try {\r\n const jsonData = req.body;\r\n \r\n if (!jsonData || (typeof jsonData !== 'object' && typeof jsonData !== 'string')) {\r\n res.status(400).json({\r\n success: false,\r\n error: 'JSON data is required'\r\n });\r\n return;\r\n }\r\n\r\n const data = typeof jsonData === 'string' ? JSON.parse(jsonData) : jsonData;\r\n const result = await jsonToCsvAsync(data, options);\r\n \r\n res.set('Content-Type', 'text/csv; charset=utf-8');\r\n res.set('Content-Disposition', 'attachment; filename=\"data.csv\"');\r\n \r\n res.send(result);\r\n } catch (error) {\r\n const err = error as Error;\r\n res.status(400).json({\r\n success: false,\r\n error: err.message\r\n });\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Express route для загрузки CSV файла\r\n * \r\n * @param options - Опции конвертации\r\n * @returns Express route handler\r\n * \r\n * @example\r\n * const multer = require('multer');\r\n * const upload = multer({ dest: 'uploads/' });\r\n * app.post('/api/upload-csv', upload.single('file'), jtcsvUploadCsvRoute());\r\n */\r\nexport function jtcsvUploadCsvRoute(options: Record<string, any> = {}): (req: Request, res: Response) => Promise<void> {\r\n return async (req: Request, res: Response): Promise<void> => {\r\n try {\r\n if (!(req as any).file) {\r\n res.status(400).json({\r\n success: false,\r\n error: 'CSV file is required'\r\n });\r\n return;\r\n }\r\n\r\n const fs = require('fs').promises;\r\n const csvData = await fs.readFile((req as any).file.path, 'utf8');\r\n \r\n const result = await csvToJsonAsync(csvData, options);\r\n \r\n // Очищаем временный файл\r\n await fs.unlink((req as any).file.path);\r\n \r\n res.json({\r\n success: true,\r\n data: result,\r\n stats: {\r\n rows: result.length,\r\n fileSize: (req as any).file.size,\r\n processingTime: Date.now() - (req.startTime || Date.now())\r\n }\r\n });\r\n } catch (error) {\r\n const err = error as Error;\r\n res.status(400).json({\r\n success: false,\r\n error: err.message\r\n });\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Health check endpoint для JTCSV\r\n * \r\n * @returns Express route handler\r\n * \r\n * @example\r\n * app.get('/api/health', jtcsvHealthCheck());\r\n */\r\nexport function jtcsvHealthCheck(): (req: Request, res: Response) => void {\r\n return (req: Request, res: Response): void => {\r\n res.json({\r\n service: 'jtcsv-express-middleware',\r\n status: 'healthy',\r\n version: '2.0.0',\r\n timestamp: new Date().toISOString(),\r\n features: {\r\n csvToJson: true,\r\n jsonToCsv: true,\r\n fastPathEngine: true,\r\n csvInjectionProtection: true,\r\n streaming: true,\r\n asyncProcessing: true,\r\n workerPool: true\r\n }\r\n });\r\n };\r\n}\r\n\r\n// Экспорт всех функций\r\nexport default {\r\n middleware: jtcsvExpressMiddleware,\r\n csvToJsonRoute: jtcsvCsvToJsonRoute,\r\n jsonToCsvRoute: jtcsvJsonToCsvRoute,\r\n uploadCsvRoute: jtcsvUploadCsvRoute,\r\n healthCheck: jtcsvHealthCheck,\r\n \r\n // Aliases для удобства\r\n jtcsvMiddleware: jtcsvExpressMiddleware,\r\n createMiddleware: jtcsvExpressMiddleware\r\n};\r\n\r\n"]}