@trayio/commons 5.20.0 → 5.21.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.
@@ -1 +1 @@
1
- {"version":3,"file":"Http.d.ts","sourceRoot":"","sources":["../../src/http/Http.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Http.d.ts","sourceRoot":"","sources":["../../src/http/Http.ts"],"names":[],"mappings":"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"}
package/dist/http/Http.js CHANGED
@@ -93,7 +93,9 @@ exports.MultipartHttpRequestBody = {
93
93
  // Extract fields, using dot notation for nested structures
94
94
  const fields = extractFields(value);
95
95
  return (0, function_1.pipe)(TE.sequenceArray(fileDescriptorPaths.map(({ path, descriptor }) => (0, function_1.pipe)(fileStorage.read(descriptor.key), TE.map((file) => ({
96
- key: file.reference.key,
96
+ // Use the object path (not the file key) as the form field name
97
+ // This tells the server where to place the FileDescriptor in the reconstructed object
98
+ key: path.join('.'),
97
99
  file: {
98
100
  ...file,
99
101
  reference: {
@@ -168,7 +168,8 @@ describe('MultipartHttpRequestBody - E2E', () => {
168
168
  }
169
169
  const multipartBody = multipartResult.right;
170
170
  // Verify the file was detected in the nested structure
171
- expect(Object.keys(multipartBody.files)).toContain('test-image-key');
171
+ // Files are now keyed by their object path, not storage key
172
+ expect(Object.keys(multipartBody.files)).toContain('imageContent.reference');
172
173
  expect(multipartBody.fields).toHaveProperty('fileName', 'test-image.png');
173
174
  expect(multipartBody.fields).toHaveProperty('overrideIfPresent', 'true');
174
175
  // 3. Send HTTP POST with multipart data
@@ -220,9 +221,10 @@ describe('MultipartHttpRequestBody - E2E', () => {
220
221
  });
221
222
  });
222
223
  // 4. Verify server received the file correctly
224
+ // Files are now keyed by object path, not storage key
223
225
  expect(response.files).toBeDefined();
224
- expect(response.files['test-image-key']).toBeDefined();
225
- const receivedFile = response.files['test-image-key'];
226
+ expect(response.files['imageContent.reference']).toBeDefined();
227
+ const receivedFile = response.files['imageContent.reference'];
226
228
  expect(receivedFile.content).toBe(originalContent);
227
229
  expect(receivedFile.hash).toBe(originalHash);
228
230
  // 5. Verify fields were sent correctly
@@ -275,9 +277,10 @@ describe('MultipartHttpRequestBody - E2E', () => {
275
277
  }
276
278
  const multipartBody = multipartResult.right;
277
279
  // Verify both files were detected
280
+ // Files are now keyed by their object paths, not storage keys
278
281
  expect(Object.keys(multipartBody.files)).toHaveLength(2);
279
- expect(multipartBody.files['file-1']).toBeDefined();
280
- expect(multipartBody.files['file-2']).toBeDefined();
282
+ expect(multipartBody.files['rootFile']).toBeDefined();
283
+ expect(multipartBody.files['nested.deepFile.reference']).toBeDefined();
281
284
  // Send to server
282
285
  // eslint-disable-next-line global-require
283
286
  const FormData = require('form-data');
@@ -323,10 +326,11 @@ describe('MultipartHttpRequestBody - E2E', () => {
323
326
  });
324
327
  });
325
328
  // Verify both files received correctly
326
- expect(response.files['file-1'].content).toBe(content1);
327
- expect(response.files['file-1'].hash).toBe(hash1);
328
- expect(response.files['file-2'].content).toBe(content2);
329
- expect(response.files['file-2'].hash).toBe(hash2);
329
+ // Files are now keyed by object path, not storage key
330
+ expect(response.files['rootFile'].content).toBe(content1);
331
+ expect(response.files['rootFile'].hash).toBe(hash1);
332
+ expect(response.files['nested.deepFile.reference'].content).toBe(content2);
333
+ expect(response.files['nested.deepFile.reference'].hash).toBe(hash2);
330
334
  // eslint-disable-next-line no-console
331
335
  console.log('✅ Multiple nested files successfully transferred!');
332
336
  });
@@ -59,7 +59,8 @@ describe('MultipartHttpRequestBody.create', () => {
59
59
  const result = await Http_1.MultipartHttpRequestBody.create({ file: fileDescriptor }, clientStorage)();
60
60
  expect(result._tag).toBe('Right');
61
61
  if (result._tag === 'Right') {
62
- expect(Object.keys(result.right.files)).toContain('root-file');
62
+ // Files are now keyed by object path, not storage key
63
+ expect(Object.keys(result.right.files)).toContain('file');
63
64
  }
64
65
  });
65
66
  it('should detect FileDescriptor nested one level deep', async () => {
@@ -76,7 +77,8 @@ describe('MultipartHttpRequestBody.create', () => {
76
77
  }, clientStorage)();
77
78
  expect(result._tag).toBe('Right');
78
79
  if (result._tag === 'Right') {
79
- expect(Object.keys(result.right.files)).toContain('nested-file');
80
+ // Files are now keyed by object path, not storage key
81
+ expect(Object.keys(result.right.files)).toContain('data.file');
80
82
  }
81
83
  });
82
84
  it('should detect FileDescriptor nested multiple levels deep', async () => {
@@ -97,7 +99,8 @@ describe('MultipartHttpRequestBody.create', () => {
97
99
  }, clientStorage)();
98
100
  expect(result._tag).toBe('Right');
99
101
  if (result._tag === 'Right') {
100
- expect(Object.keys(result.right.files)).toContain('deep-file');
102
+ // Files are now keyed by object path, not storage key
103
+ expect(Object.keys(result.right.files)).toContain('level1.level2.level3.file');
101
104
  }
102
105
  });
103
106
  it('should detect multiple FileDescriptors at different levels', async () => {
@@ -122,8 +125,9 @@ describe('MultipartHttpRequestBody.create', () => {
122
125
  expect(result._tag).toBe('Right');
123
126
  if (result._tag === 'Right') {
124
127
  expect(Object.keys(result.right.files)).toHaveLength(2);
125
- expect(result.right.files['file-1']).toBeDefined();
126
- expect(result.right.files['file-2']).toBeDefined();
128
+ // Files are now keyed by object path, not storage key
129
+ expect(result.right.files['rootFile']).toBeDefined();
130
+ expect(result.right.files['nested.deepFile']).toBeDefined();
127
131
  }
128
132
  });
129
133
  });
@@ -227,7 +231,8 @@ describe('MultipartHttpRequestBody.create', () => {
227
231
  const result = await Http_1.MultipartHttpRequestBody.create({ file: fileDescriptor }, clientStorage)();
228
232
  expect(result._tag).toBe('Right');
229
233
  if (result._tag === 'Right') {
230
- const file = result.right.files['test-file'];
234
+ // Files are now keyed by object path, not storage key
235
+ const { file } = result.right.files;
231
236
  expect(file.reference.metadata.contentType).toBe('image/png');
232
237
  expect(file.reference.metadata.name).toBe('image.png');
233
238
  }
@@ -261,9 +266,160 @@ describe('MultipartHttpRequestBody.create', () => {
261
266
  expect(result.right.fields.category).toBe('report');
262
267
  expect(result.right.fields['metadata.author']).toBe('Alice');
263
268
  expect(result.right.fields['metadata.tags']).toBe('important,confidential');
264
- // Check file
265
- expect(result.right.files.doc).toBeDefined();
266
- expect(result.right.files.doc.reference.metadata.contentType).toBe('application/pdf');
269
+ // Check file - Files are now keyed by object path, not storage key
270
+ expect(result.right.files.document).toBeDefined();
271
+ expect(result.right.files.document.reference.metadata.contentType).toBe('application/pdf');
272
+ }
273
+ });
274
+ });
275
+ describe('File Field Naming with Object Paths', () => {
276
+ it('should use object path (not file key) as the form field name for root-level files', async () => {
277
+ const fileDescriptor = {
278
+ _tag: 'FileDescriptor',
279
+ key: 'some-storage-key-123',
280
+ metadata: {
281
+ name: 'document.pdf',
282
+ size: 1024,
283
+ contentType: 'application/pdf',
284
+ },
285
+ };
286
+ await clientStorage.write({ reference: fileDescriptor, content: stream_1.Readable.from('file content') }, undefined)();
287
+ const result = await Http_1.MultipartHttpRequestBody.create({
288
+ file: fileDescriptor,
289
+ }, clientStorage)();
290
+ expect(result._tag).toBe('Right');
291
+ if (result._tag === 'Right') {
292
+ // The file should be keyed by the object path 'file', not the storage key
293
+ expect(Object.keys(result.right.files)).toContain('file');
294
+ expect(result.right.files['file']).toBeDefined();
295
+ }
296
+ });
297
+ it('should use nested object path as form field name for nested files', async () => {
298
+ const fileDescriptor = {
299
+ _tag: 'FileDescriptor',
300
+ key: 'storage-key-456',
301
+ metadata: {
302
+ name: 'attachment.png',
303
+ size: 2048,
304
+ contentType: 'image/png',
305
+ },
306
+ };
307
+ await clientStorage.write({ reference: fileDescriptor, content: stream_1.Readable.from('image data') }, undefined)();
308
+ const result = await Http_1.MultipartHttpRequestBody.create({
309
+ data: {
310
+ attachment: fileDescriptor,
311
+ },
312
+ }, clientStorage)();
313
+ expect(result._tag).toBe('Right');
314
+ if (result._tag === 'Right') {
315
+ // The file should be keyed by 'data.attachment', not the storage key
316
+ expect(Object.keys(result.right.files)).toContain('data.attachment');
317
+ expect(result.right.files['data.attachment']).toBeDefined();
318
+ }
319
+ });
320
+ it('should use deeply nested object path as form field name', async () => {
321
+ const fileDescriptor = {
322
+ _tag: 'FileDescriptor',
323
+ key: 'deep-storage-key',
324
+ metadata: {
325
+ name: 'report.pdf',
326
+ size: 5000,
327
+ contentType: 'application/pdf',
328
+ },
329
+ };
330
+ await clientStorage.write({ reference: fileDescriptor, content: stream_1.Readable.from('report content') }, undefined)();
331
+ const result = await Http_1.MultipartHttpRequestBody.create({
332
+ project: {
333
+ documents: {
334
+ reports: {
335
+ annual: fileDescriptor,
336
+ },
337
+ },
338
+ },
339
+ }, clientStorage)();
340
+ expect(result._tag).toBe('Right');
341
+ if (result._tag === 'Right') {
342
+ // The file should be keyed by the full object path
343
+ expect(Object.keys(result.right.files)).toContain('project.documents.reports.annual');
344
+ expect(result.right.files['project.documents.reports.annual']).toBeDefined();
345
+ }
346
+ });
347
+ it('should use correct object paths for multiple files at different levels', async () => {
348
+ const file1 = {
349
+ _tag: 'FileDescriptor',
350
+ key: 'key-1',
351
+ metadata: {
352
+ name: 'file1.txt',
353
+ size: 100,
354
+ contentType: 'text/plain',
355
+ },
356
+ };
357
+ const file2 = {
358
+ _tag: 'FileDescriptor',
359
+ key: 'key-2',
360
+ metadata: {
361
+ name: 'file2.txt',
362
+ size: 200,
363
+ contentType: 'text/plain',
364
+ },
365
+ };
366
+ const file3 = {
367
+ _tag: 'FileDescriptor',
368
+ key: 'key-3',
369
+ metadata: {
370
+ name: 'file3.txt',
371
+ size: 300,
372
+ contentType: 'text/plain',
373
+ },
374
+ };
375
+ await clientStorage.write({ reference: file1, content: stream_1.Readable.from('content1') }, undefined)();
376
+ await clientStorage.write({ reference: file2, content: stream_1.Readable.from('content2') }, undefined)();
377
+ await clientStorage.write({ reference: file3, content: stream_1.Readable.from('content3') }, undefined)();
378
+ const result = await Http_1.MultipartHttpRequestBody.create({
379
+ avatar: file1,
380
+ data: {
381
+ document: file2,
382
+ nested: {
383
+ attachment: file3,
384
+ },
385
+ },
386
+ }, clientStorage)();
387
+ expect(result._tag).toBe('Right');
388
+ if (result._tag === 'Right') {
389
+ // Each file should be keyed by its object path, not its storage key
390
+ expect(Object.keys(result.right.files)).toHaveLength(3);
391
+ expect(result.right.files['avatar']).toBeDefined();
392
+ expect(result.right.files['data.document']).toBeDefined();
393
+ expect(result.right.files['data.nested.attachment']).toBeDefined();
394
+ // Verify storage keys are NOT used as field names
395
+ expect(result.right.files['key-1']).toBeUndefined();
396
+ expect(result.right.files['key-2']).toBeUndefined();
397
+ expect(result.right.files['key-3']).toBeUndefined();
398
+ }
399
+ });
400
+ it('should preserve metadata when using object path as field name', async () => {
401
+ const fileDescriptor = {
402
+ _tag: 'FileDescriptor',
403
+ key: 'some-key',
404
+ metadata: {
405
+ name: 'important.pdf',
406
+ size: 999,
407
+ contentType: 'application/pdf',
408
+ },
409
+ };
410
+ await clientStorage.write({ reference: fileDescriptor, content: stream_1.Readable.from('pdf data') }, undefined)();
411
+ const result = await Http_1.MultipartHttpRequestBody.create({
412
+ nested: {
413
+ file: fileDescriptor,
414
+ },
415
+ }, clientStorage)();
416
+ expect(result._tag).toBe('Right');
417
+ if (result._tag === 'Right') {
418
+ const file = result.right.files['nested.file'];
419
+ expect(file).toBeDefined();
420
+ expect(file.reference.metadata.name).toBe('important.pdf');
421
+ expect(file.reference.metadata.size).toBe(999);
422
+ expect(file.reference.metadata.contentType).toBe('application/pdf');
267
423
  }
268
424
  });
269
425
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trayio/commons",
3
- "version": "5.20.0",
3
+ "version": "5.21.0",
4
4
  "description": "Extensions to the standard/core libraries and basic features",
5
5
  "exports": {
6
6
  "./*": "./dist/*.js"