meadow-integration 1.0.5 → 1.0.6

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 (67) hide show
  1. package/.dockerignore +11 -0
  2. package/Docker-Build.sh +2 -0
  3. package/Docker-Compose.sh +2 -0
  4. package/Docker-Push.sh +2 -0
  5. package/Docker-Tag.sh +2 -0
  6. package/Dockerfile +28 -0
  7. package/Dockerfile_LUXURYCode +23 -0
  8. package/README.md +139 -25
  9. package/docker-compose.yml +16 -0
  10. package/docs/README.md +65 -18
  11. package/docs/_cover.md +3 -2
  12. package/docs/_sidebar.md +52 -7
  13. package/docs/_topbar.md +2 -0
  14. package/docs/api/clone-rest-client.md +278 -0
  15. package/docs/api/connection-manager.md +179 -0
  16. package/docs/api/guid-map.md +234 -0
  17. package/docs/api/integration-adapter.md +283 -0
  18. package/docs/api/operation.md +241 -0
  19. package/docs/api/sync-entity-initial.md +227 -0
  20. package/docs/api/sync-entity-ongoing.md +244 -0
  21. package/docs/api/sync.md +213 -0
  22. package/docs/api/tabular-check.md +213 -0
  23. package/docs/api/tabular-transform.md +316 -0
  24. package/docs/architecture.md +423 -0
  25. package/docs/cli/comprehensionarray.md +111 -0
  26. package/docs/cli/comprehensionintersect.md +132 -0
  27. package/docs/cli/csvcheck.md +111 -0
  28. package/docs/cli/csvtransform.md +170 -0
  29. package/docs/cli/data-clone.md +277 -0
  30. package/docs/cli/jsonarraytransform.md +166 -0
  31. package/docs/cli/load-comprehension.md +129 -0
  32. package/docs/cli/objectarraytocsv.md +159 -0
  33. package/docs/cli/overview.md +96 -0
  34. package/docs/cli/serve.md +102 -0
  35. package/docs/cli/tsvtransform.md +144 -0
  36. package/docs/data-clone/configuration.md +357 -0
  37. package/docs/data-clone/connection-manager.md +206 -0
  38. package/docs/data-clone/docker.md +290 -0
  39. package/docs/data-clone/overview.md +173 -0
  40. package/docs/data-clone/sync-modes.md +186 -0
  41. package/docs/implementation-reference.md +311 -0
  42. package/docs/overview.md +156 -0
  43. package/docs/quickstart.md +233 -0
  44. package/docs/rest/comprehension-push.md +209 -0
  45. package/docs/rest/comprehension.md +506 -0
  46. package/docs/rest/csv.md +255 -0
  47. package/docs/rest/entity-generation.md +158 -0
  48. package/docs/rest/json-array.md +243 -0
  49. package/docs/rest/overview.md +120 -0
  50. package/docs/rest/status.md +63 -0
  51. package/docs/rest/tsv.md +241 -0
  52. package/docs/retold-catalog.json +93 -3
  53. package/docs/retold-keyword-index.json +23683 -1901
  54. package/package.json +6 -3
  55. package/scripts/run.sh +18 -0
  56. package/source/Meadow-Integration.js +15 -1
  57. package/source/cli/Default-Meadow-Integration-Configuration.json +37 -2
  58. package/source/cli/Meadow-Integration-CLI-Program.js +4 -1
  59. package/source/cli/commands/Meadow-Integration-Command-DataClone.js +284 -0
  60. package/source/services/clone/Meadow-Service-ConnectionManager.js +251 -0
  61. package/source/services/clone/Meadow-Service-Operation.js +196 -0
  62. package/source/services/clone/Meadow-Service-RestClient.js +364 -0
  63. package/source/services/clone/Meadow-Service-Sync-Entity-Initial.js +367 -0
  64. package/source/services/clone/Meadow-Service-Sync-Entity-Ongoing.js +457 -0
  65. package/source/services/clone/Meadow-Service-Sync.js +142 -0
  66. /package/docs/examples/bookstore/{mapping_books_Author.json → mapping_books_author.json} +0 -0
  67. /package/docs/examples/bookstore/{mapping_books_Book.json → mapping_books_book.json} +0 -0
@@ -0,0 +1,209 @@
1
+ # Comprehension Push Endpoints
2
+
3
+ These endpoints push comprehension data to Meadow REST API servers using the Integration Adapter. Each entity in the comprehension is pushed via create/upsert operations against the target API.
4
+
5
+ ---
6
+
7
+ ## POST /1.0/Comprehension/Push
8
+
9
+ Push an in-memory comprehension object to Meadow REST APIs.
10
+
11
+ ### Request Body
12
+
13
+ | Property | Type | Required | Default | Description |
14
+ |----------|------|----------|---------|-------------|
15
+ | `Comprehension` | object | Yes | - | The comprehension object to push |
16
+ | `ServerURL` | string | No | Configured default | Target Meadow API server base URL (e.g. `http://localhost:8080/1.0/`) |
17
+ | `GUIDPrefix` | string | No | - | GUID prefix applied across the entire adapter set |
18
+ | `EntityGUIDPrefix` | string | No | - | GUID prefix applied per entity |
19
+
20
+ ### Response
21
+
22
+ ```json
23
+ {
24
+ "Success": true,
25
+ "EntitiesPushed": ["Book", "Author"],
26
+ "Message": "Pushed comprehension for 2 entity(ies)."
27
+ }
28
+ ```
29
+
30
+ ### Error Responses
31
+
32
+ | Status | Condition |
33
+ |--------|-----------|
34
+ | 400 | No valid `Comprehension` object provided |
35
+ | 500 | Error during the push operation |
36
+
37
+ ### curl Example
38
+
39
+ ```bash
40
+ curl -s -X POST http://localhost:8086/1.0/Comprehension/Push \
41
+ -H "Content-Type: application/json" \
42
+ -d '{
43
+ "Comprehension": {
44
+ "Book": {
45
+ "B001": { "GUIDBook": "B001", "Title": "Dune", "Author": "Frank Herbert" },
46
+ "B002": { "GUIDBook": "B002", "Title": "Neuromancer", "Author": "William Gibson" }
47
+ }
48
+ },
49
+ "ServerURL": "http://localhost:8080/1.0/"
50
+ }'
51
+ ```
52
+
53
+ With GUID prefix:
54
+
55
+ ```bash
56
+ curl -s -X POST http://localhost:8086/1.0/Comprehension/Push \
57
+ -H "Content-Type: application/json" \
58
+ -d '{
59
+ "Comprehension": {
60
+ "Book": {
61
+ "B001": { "GUIDBook": "B001", "Title": "Dune" }
62
+ }
63
+ },
64
+ "ServerURL": "http://localhost:8080/1.0/",
65
+ "GUIDPrefix": "INTG-",
66
+ "EntityGUIDPrefix": "BK-"
67
+ }'
68
+ ```
69
+
70
+ ### JavaScript Example (dependency-free)
71
+
72
+ ```javascript
73
+ const http = require('http');
74
+
75
+ const requestBody = JSON.stringify({
76
+ Comprehension: {
77
+ Book: {
78
+ 'B001': { GUIDBook: 'B001', Title: 'Dune', Author: 'Frank Herbert' },
79
+ 'B002': { GUIDBook: 'B002', Title: 'Neuromancer', Author: 'William Gibson' }
80
+ }
81
+ },
82
+ ServerURL: 'http://localhost:8080/1.0/'
83
+ });
84
+
85
+ const options = {
86
+ hostname: 'localhost',
87
+ port: 8086,
88
+ path: '/1.0/Comprehension/Push',
89
+ method: 'POST',
90
+ headers: {
91
+ 'Content-Type': 'application/json',
92
+ 'Content-Length': Buffer.byteLength(requestBody)
93
+ }
94
+ };
95
+
96
+ const req = http.request(options, (res) => {
97
+ let data = '';
98
+ res.on('data', (chunk) => { data += chunk; });
99
+ res.on('end', () => {
100
+ const result = JSON.parse(data);
101
+ if (result.Success) {
102
+ console.log('Push successful!');
103
+ console.log('Entities pushed:', result.EntitiesPushed.join(', '));
104
+ } else {
105
+ console.error('Push failed:', result.Error);
106
+ }
107
+ });
108
+ });
109
+ req.on('error', (err) => { console.error('Request error:', err.message); });
110
+ req.write(requestBody);
111
+ req.end();
112
+ ```
113
+
114
+ ---
115
+
116
+ ## POST /1.0/Comprehension/PushFile
117
+
118
+ Push a comprehension stored in a JSON file to Meadow REST APIs.
119
+
120
+ ### Request Body
121
+
122
+ | Property | Type | Required | Default | Description |
123
+ |----------|------|----------|---------|-------------|
124
+ | `File` | string | Yes | - | Path to a comprehension JSON file |
125
+ | `ServerURL` | string | No | Configured default | Target Meadow API server base URL |
126
+ | `GUIDPrefix` | string | No | - | GUID prefix applied across the entire adapter set |
127
+ | `EntityGUIDPrefix` | string | No | - | GUID prefix applied per entity |
128
+
129
+ ### Response
130
+
131
+ ```json
132
+ {
133
+ "Success": true,
134
+ "EntitiesPushed": ["Book"],
135
+ "Message": "Pushed comprehension for 1 entity(ies)."
136
+ }
137
+ ```
138
+
139
+ ### Error Responses
140
+
141
+ | Status | Condition |
142
+ |--------|-----------|
143
+ | 400 | Missing `File` or file is not valid JSON |
144
+ | 404 | File does not exist |
145
+ | 500 | Error during the push operation |
146
+
147
+ ### curl Example
148
+
149
+ ```bash
150
+ curl -s -X POST http://localhost:8086/1.0/Comprehension/PushFile \
151
+ -H "Content-Type: application/json" \
152
+ -d '{
153
+ "File": "/data/books_comprehension.json",
154
+ "ServerURL": "http://localhost:8080/1.0/"
155
+ }'
156
+ ```
157
+
158
+ ### JavaScript Example (dependency-free)
159
+
160
+ ```javascript
161
+ const http = require('http');
162
+
163
+ const requestBody = JSON.stringify({
164
+ File: '/data/books_comprehension.json',
165
+ ServerURL: 'http://localhost:8080/1.0/'
166
+ });
167
+
168
+ const options = {
169
+ hostname: 'localhost',
170
+ port: 8086,
171
+ path: '/1.0/Comprehension/PushFile',
172
+ method: 'POST',
173
+ headers: {
174
+ 'Content-Type': 'application/json',
175
+ 'Content-Length': Buffer.byteLength(requestBody)
176
+ }
177
+ };
178
+
179
+ const req = http.request(options, (res) => {
180
+ let data = '';
181
+ res.on('data', (chunk) => { data += chunk; });
182
+ res.on('end', () => {
183
+ const result = JSON.parse(data);
184
+ if (result.Success) {
185
+ console.log('Push successful!');
186
+ console.log('Entities pushed:', result.EntitiesPushed.join(', '));
187
+ console.log(result.Message);
188
+ } else {
189
+ console.error('Push failed:', result.Error);
190
+ }
191
+ });
192
+ });
193
+ req.on('error', (err) => { console.error('Request error:', err.message); });
194
+ req.write(requestBody);
195
+ req.end();
196
+ ```
197
+
198
+ ---
199
+
200
+ ## How the Push Works
201
+
202
+ The push operation uses the Meadow Integration Adapter to send records to a target Meadow REST API server:
203
+
204
+ 1. Each top-level key in the comprehension is treated as an entity name.
205
+ 2. An Integration Adapter is created for each entity.
206
+ 3. All records under that entity are added as source records.
207
+ 4. The adapter calls `integrateRecords`, which issues create or upsert calls to the target server.
208
+
209
+ The GUID prefix is derived automatically from the capital letters of the entity name (e.g. `BookAuthor` becomes `BA`), but you can override it with `GUIDPrefix` and `EntityGUIDPrefix`.
@@ -0,0 +1,506 @@
1
+ # Comprehension Endpoints
2
+
3
+ These endpoints operate on comprehension objects -- GUID-keyed hashes of entity records. They provide intersection (merging), conversion to arrays, and conversion to CSV.
4
+
5
+ ---
6
+
7
+ ## POST /1.0/Comprehension/Intersect
8
+
9
+ Merge two in-memory comprehension objects together. Records from the secondary comprehension are merged into the primary. When both comprehensions contain the same GUID, the secondary record's properties are merged onto the primary record using `Object.assign`.
10
+
11
+ ### Request Body
12
+
13
+ | Property | Type | Required | Default | Description |
14
+ |----------|------|----------|---------|-------------|
15
+ | `PrimaryComprehension` | object | Yes | - | The primary comprehension object |
16
+ | `SecondaryComprehension` | object | Yes | - | The secondary comprehension to merge in |
17
+ | `Entity` | string | No | Auto-inferred from first key | Entity name to intersect on |
18
+
19
+ ### Response
20
+
21
+ Returns the merged comprehension object.
22
+
23
+ ### Error Responses
24
+
25
+ | Status | Condition |
26
+ |--------|-----------|
27
+ | 400 | Missing `PrimaryComprehension` or `SecondaryComprehension`, or no entity could be inferred |
28
+
29
+ ### curl Example
30
+
31
+ ```bash
32
+ curl -s -X POST http://localhost:8086/1.0/Comprehension/Intersect \
33
+ -H "Content-Type: application/json" \
34
+ -d '{
35
+ "PrimaryComprehension": {
36
+ "Book": {
37
+ "B001": { "GUIDBook": "B001", "title": "Dune" },
38
+ "B002": { "GUIDBook": "B002", "title": "Neuromancer" }
39
+ }
40
+ },
41
+ "SecondaryComprehension": {
42
+ "Book": {
43
+ "B001": { "GUIDBook": "B001", "author": "Frank Herbert" },
44
+ "B003": { "GUIDBook": "B003", "title": "Snow Crash", "author": "Neal Stephenson" }
45
+ }
46
+ },
47
+ "Entity": "Book"
48
+ }'
49
+ ```
50
+
51
+ ### JavaScript Example (dependency-free)
52
+
53
+ ```javascript
54
+ const http = require('http');
55
+
56
+ const requestBody = JSON.stringify({
57
+ PrimaryComprehension: {
58
+ Book: {
59
+ 'B001': { GUIDBook: 'B001', title: 'Dune' },
60
+ 'B002': { GUIDBook: 'B002', title: 'Neuromancer' }
61
+ }
62
+ },
63
+ SecondaryComprehension: {
64
+ Book: {
65
+ 'B001': { GUIDBook: 'B001', author: 'Frank Herbert' },
66
+ 'B003': { GUIDBook: 'B003', title: 'Snow Crash', author: 'Neal Stephenson' }
67
+ }
68
+ },
69
+ Entity: 'Book'
70
+ });
71
+
72
+ const options = {
73
+ hostname: 'localhost',
74
+ port: 8086,
75
+ path: '/1.0/Comprehension/Intersect',
76
+ method: 'POST',
77
+ headers: {
78
+ 'Content-Type': 'application/json',
79
+ 'Content-Length': Buffer.byteLength(requestBody)
80
+ }
81
+ };
82
+
83
+ const req = http.request(options, (res) => {
84
+ let data = '';
85
+ res.on('data', (chunk) => { data += chunk; });
86
+ res.on('end', () => {
87
+ const merged = JSON.parse(data);
88
+ console.log('Merged Books:', Object.keys(merged.Book).length);
89
+ // B001 now has both title and author
90
+ console.log('B001:', merged.Book['B001']);
91
+ });
92
+ });
93
+ req.on('error', (err) => { console.error('Request error:', err.message); });
94
+ req.write(requestBody);
95
+ req.end();
96
+ ```
97
+
98
+ ---
99
+
100
+ ## POST /1.0/Comprehension/IntersectFiles
101
+
102
+ Merge two comprehension files together. Identical behavior to `/Intersect` but reads comprehensions from JSON files on disk.
103
+
104
+ ### Request Body
105
+
106
+ | Property | Type | Required | Default | Description |
107
+ |----------|------|----------|---------|-------------|
108
+ | `File` | string | Yes | - | Path to the primary comprehension JSON file |
109
+ | `IntersectFile` | string | Yes | - | Path to the secondary comprehension JSON file |
110
+ | `Entity` | string | No | Auto-inferred | Entity name to intersect on |
111
+
112
+ ### Error Responses
113
+
114
+ | Status | Condition |
115
+ |--------|-----------|
116
+ | 400 | Missing `File` or `IntersectFile`, or files are not valid JSON |
117
+ | 404 | Primary or secondary file does not exist |
118
+
119
+ ### curl Example
120
+
121
+ ```bash
122
+ curl -s -X POST http://localhost:8086/1.0/Comprehension/IntersectFiles \
123
+ -H "Content-Type: application/json" \
124
+ -d '{
125
+ "File": "/data/books_primary.json",
126
+ "IntersectFile": "/data/books_secondary.json",
127
+ "Entity": "Book"
128
+ }'
129
+ ```
130
+
131
+ ### JavaScript Example (dependency-free)
132
+
133
+ ```javascript
134
+ const http = require('http');
135
+
136
+ const requestBody = JSON.stringify({
137
+ File: '/data/books_primary.json',
138
+ IntersectFile: '/data/books_secondary.json',
139
+ Entity: 'Book'
140
+ });
141
+
142
+ const options = {
143
+ hostname: 'localhost',
144
+ port: 8086,
145
+ path: '/1.0/Comprehension/IntersectFiles',
146
+ method: 'POST',
147
+ headers: {
148
+ 'Content-Type': 'application/json',
149
+ 'Content-Length': Buffer.byteLength(requestBody)
150
+ }
151
+ };
152
+
153
+ const req = http.request(options, (res) => {
154
+ let data = '';
155
+ res.on('data', (chunk) => { data += chunk; });
156
+ res.on('end', () => {
157
+ const merged = JSON.parse(data);
158
+ console.log('Merged comprehension:', JSON.stringify(merged, null, 2));
159
+ });
160
+ });
161
+ req.on('error', (err) => { console.error('Request error:', err.message); });
162
+ req.write(requestBody);
163
+ req.end();
164
+ ```
165
+
166
+ ---
167
+
168
+ ## POST /1.0/Comprehension/ToArray
169
+
170
+ Convert a GUID-keyed comprehension object into a flat array of records. This is useful when you need to iterate over records without dealing with GUID keys.
171
+
172
+ ### Request Body
173
+
174
+ | Property | Type | Required | Default | Description |
175
+ |----------|------|----------|---------|-------------|
176
+ | `Comprehension` | object | Yes | - | The comprehension object to convert |
177
+ | `Entity` | string | No | Auto-inferred from first key | Entity name to extract records from |
178
+
179
+ ### Response
180
+
181
+ Returns a JSON array of record objects:
182
+
183
+ ```json
184
+ [
185
+ { "GUIDBook": "B001", "title": "Dune", "author": "Frank Herbert" },
186
+ { "GUIDBook": "B002", "title": "Neuromancer", "author": "William Gibson" }
187
+ ]
188
+ ```
189
+
190
+ ### Error Responses
191
+
192
+ | Status | Condition |
193
+ |--------|-----------|
194
+ | 400 | Missing `Comprehension`, or no entity could be inferred |
195
+
196
+ ### curl Example
197
+
198
+ ```bash
199
+ curl -s -X POST http://localhost:8086/1.0/Comprehension/ToArray \
200
+ -H "Content-Type: application/json" \
201
+ -d '{
202
+ "Comprehension": {
203
+ "Book": {
204
+ "B001": { "GUIDBook": "B001", "title": "Dune" },
205
+ "B002": { "GUIDBook": "B002", "title": "Neuromancer" }
206
+ }
207
+ },
208
+ "Entity": "Book"
209
+ }'
210
+ ```
211
+
212
+ ### JavaScript Example (dependency-free)
213
+
214
+ ```javascript
215
+ const http = require('http');
216
+
217
+ const requestBody = JSON.stringify({
218
+ Comprehension: {
219
+ Book: {
220
+ 'B001': { GUIDBook: 'B001', title: 'Dune', author: 'Frank Herbert' },
221
+ 'B002': { GUIDBook: 'B002', title: 'Neuromancer', author: 'William Gibson' }
222
+ }
223
+ },
224
+ Entity: 'Book'
225
+ });
226
+
227
+ const options = {
228
+ hostname: 'localhost',
229
+ port: 8086,
230
+ path: '/1.0/Comprehension/ToArray',
231
+ method: 'POST',
232
+ headers: {
233
+ 'Content-Type': 'application/json',
234
+ 'Content-Length': Buffer.byteLength(requestBody)
235
+ }
236
+ };
237
+
238
+ const req = http.request(options, (res) => {
239
+ let data = '';
240
+ res.on('data', (chunk) => { data += chunk; });
241
+ res.on('end', () => {
242
+ const records = JSON.parse(data);
243
+ console.log(`Converted ${records.length} records to array`);
244
+ records.forEach((rec) => {
245
+ console.log(` ${rec.GUIDBook}: ${rec.title}`);
246
+ });
247
+ });
248
+ });
249
+ req.on('error', (err) => { console.error('Request error:', err.message); });
250
+ req.write(requestBody);
251
+ req.end();
252
+ ```
253
+
254
+ ---
255
+
256
+ ## POST /1.0/Comprehension/ToArrayFromFile
257
+
258
+ Convert a comprehension JSON file to an array of records.
259
+
260
+ ### Request Body
261
+
262
+ | Property | Type | Required | Default | Description |
263
+ |----------|------|----------|---------|-------------|
264
+ | `File` | string | Yes | - | Path to a comprehension JSON file |
265
+ | `Entity` | string | No | Auto-inferred | Entity name to extract records from |
266
+
267
+ ### Error Responses
268
+
269
+ | Status | Condition |
270
+ |--------|-----------|
271
+ | 400 | Missing `File`, or file is not valid JSON |
272
+ | 404 | File does not exist |
273
+
274
+ ### curl Example
275
+
276
+ ```bash
277
+ curl -s -X POST http://localhost:8086/1.0/Comprehension/ToArrayFromFile \
278
+ -H "Content-Type: application/json" \
279
+ -d '{
280
+ "File": "/data/books_comprehension.json",
281
+ "Entity": "Book"
282
+ }'
283
+ ```
284
+
285
+ ### JavaScript Example (dependency-free)
286
+
287
+ ```javascript
288
+ const http = require('http');
289
+
290
+ const requestBody = JSON.stringify({
291
+ File: '/data/books_comprehension.json',
292
+ Entity: 'Book'
293
+ });
294
+
295
+ const options = {
296
+ hostname: 'localhost',
297
+ port: 8086,
298
+ path: '/1.0/Comprehension/ToArrayFromFile',
299
+ method: 'POST',
300
+ headers: {
301
+ 'Content-Type': 'application/json',
302
+ 'Content-Length': Buffer.byteLength(requestBody)
303
+ }
304
+ };
305
+
306
+ const req = http.request(options, (res) => {
307
+ let data = '';
308
+ res.on('data', (chunk) => { data += chunk; });
309
+ res.on('end', () => {
310
+ const records = JSON.parse(data);
311
+ console.log(`${records.length} records loaded from file`);
312
+ });
313
+ });
314
+ req.on('error', (err) => { console.error('Request error:', err.message); });
315
+ req.write(requestBody);
316
+ req.end();
317
+ ```
318
+
319
+ ---
320
+
321
+ ## POST /1.0/Comprehension/ToCSV
322
+
323
+ Convert a comprehension or an array of records to CSV format. Nested objects are flattened using dot-notation keys. The response Content-Type is `text/csv`.
324
+
325
+ ### Request Body
326
+
327
+ You can provide data in one of two forms:
328
+
329
+ **Option A -- Records array:**
330
+
331
+ | Property | Type | Required | Description |
332
+ |----------|------|----------|-------------|
333
+ | `Records` | array | Yes | Array of record objects |
334
+
335
+ **Option B -- Comprehension object:**
336
+
337
+ | Property | Type | Required | Description |
338
+ |----------|------|----------|-------------|
339
+ | `Comprehension` | object | Yes | Comprehension object |
340
+ | `Entity` | string | No | Entity name (auto-detected if single entity) |
341
+
342
+ ### Response
343
+
344
+ Returns raw CSV text with `Content-Type: text/csv`:
345
+
346
+ ```
347
+ GUIDBook,author,title
348
+ B001,Frank Herbert,Dune
349
+ B002,William Gibson,Neuromancer
350
+ ```
351
+
352
+ ### Error Responses
353
+
354
+ | Status | Condition |
355
+ |--------|-----------|
356
+ | 400 | No valid `Records` or `Comprehension` provided, empty records, or multiple entities without `Entity` specified |
357
+
358
+ ### curl Example
359
+
360
+ From a records array:
361
+
362
+ ```bash
363
+ curl -s -X POST http://localhost:8086/1.0/Comprehension/ToCSV \
364
+ -H "Content-Type: application/json" \
365
+ -d '{
366
+ "Records": [
367
+ { "id": 1, "name": "Alice", "role": "Engineer" },
368
+ { "id": 2, "name": "Bob", "role": "Designer" }
369
+ ]
370
+ }'
371
+ ```
372
+
373
+ From a comprehension:
374
+
375
+ ```bash
376
+ curl -s -X POST http://localhost:8086/1.0/Comprehension/ToCSV \
377
+ -H "Content-Type: application/json" \
378
+ -d '{
379
+ "Comprehension": {
380
+ "Employee": {
381
+ "E1": { "id": 1, "name": "Alice" },
382
+ "E2": { "id": 2, "name": "Bob" }
383
+ }
384
+ },
385
+ "Entity": "Employee"
386
+ }'
387
+ ```
388
+
389
+ ### JavaScript Example (dependency-free)
390
+
391
+ ```javascript
392
+ const http = require('http');
393
+
394
+ const requestBody = JSON.stringify({
395
+ Records: [
396
+ { id: 1, name: 'Alice', role: 'Engineer' },
397
+ { id: 2, name: 'Bob', role: 'Designer' },
398
+ { id: 3, name: 'Carol', role: 'Manager' }
399
+ ]
400
+ });
401
+
402
+ const options = {
403
+ hostname: 'localhost',
404
+ port: 8086,
405
+ path: '/1.0/Comprehension/ToCSV',
406
+ method: 'POST',
407
+ headers: {
408
+ 'Content-Type': 'application/json',
409
+ 'Content-Length': Buffer.byteLength(requestBody)
410
+ }
411
+ };
412
+
413
+ const req = http.request(options, (res) => {
414
+ let data = '';
415
+ res.on('data', (chunk) => { data += chunk; });
416
+ res.on('end', () => {
417
+ // Response is raw CSV text
418
+ console.log('CSV output:');
419
+ console.log(data);
420
+ });
421
+ });
422
+ req.on('error', (err) => { console.error('Request error:', err.message); });
423
+ req.write(requestBody);
424
+ req.end();
425
+ ```
426
+
427
+ ---
428
+
429
+ ## POST /1.0/Comprehension/ToCSVFromFile
430
+
431
+ Convert a JSON file (containing either a comprehension or an array) to CSV format.
432
+
433
+ ### Request Body
434
+
435
+ | Property | Type | Required | Default | Description |
436
+ |----------|------|----------|---------|-------------|
437
+ | `File` | string | Yes | - | Path to a JSON file (array or comprehension) |
438
+ | `Entity` | string | No | Auto-detected | Entity name (required if comprehension has multiple entities) |
439
+
440
+ ### Response
441
+
442
+ Returns raw CSV text with `Content-Type: text/csv`.
443
+
444
+ ### Error Responses
445
+
446
+ | Status | Condition |
447
+ |--------|-----------|
448
+ | 400 | Missing `File`, file is not valid JSON, or no records found |
449
+ | 404 | File does not exist |
450
+
451
+ ### curl Example
452
+
453
+ ```bash
454
+ curl -s -X POST http://localhost:8086/1.0/Comprehension/ToCSVFromFile \
455
+ -H "Content-Type: application/json" \
456
+ -d '{
457
+ "File": "/data/employees.json",
458
+ "Entity": "Employee"
459
+ }'
460
+ ```
461
+
462
+ Save the CSV output to a file:
463
+
464
+ ```bash
465
+ curl -s -X POST http://localhost:8086/1.0/Comprehension/ToCSVFromFile \
466
+ -H "Content-Type: application/json" \
467
+ -d '{
468
+ "File": "/data/employees.json"
469
+ }' > /data/employees.csv
470
+ ```
471
+
472
+ ### JavaScript Example (dependency-free)
473
+
474
+ ```javascript
475
+ const http = require('http');
476
+ const fs = require('fs');
477
+
478
+ const requestBody = JSON.stringify({
479
+ File: '/data/employees.json',
480
+ Entity: 'Employee'
481
+ });
482
+
483
+ const options = {
484
+ hostname: 'localhost',
485
+ port: 8086,
486
+ path: '/1.0/Comprehension/ToCSVFromFile',
487
+ method: 'POST',
488
+ headers: {
489
+ 'Content-Type': 'application/json',
490
+ 'Content-Length': Buffer.byteLength(requestBody)
491
+ }
492
+ };
493
+
494
+ const req = http.request(options, (res) => {
495
+ let data = '';
496
+ res.on('data', (chunk) => { data += chunk; });
497
+ res.on('end', () => {
498
+ // Write CSV to file
499
+ fs.writeFileSync('/data/employees.csv', data);
500
+ console.log('CSV written to /data/employees.csv');
501
+ });
502
+ });
503
+ req.on('error', (err) => { console.error('Request error:', err.message); });
504
+ req.write(requestBody);
505
+ req.end();
506
+ ```