@payloadcms/plugin-import-export 3.77.0-internal.9837b1e → 3.77.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 (75) hide show
  1. package/dist/components/CollectionField/index.d.ts +2 -2
  2. package/dist/components/CollectionField/index.d.ts.map +1 -1
  3. package/dist/components/CollectionField/index.js +5 -28
  4. package/dist/components/CollectionField/index.js.map +1 -1
  5. package/dist/components/CollectionSelectField/index.d.ts +13 -0
  6. package/dist/components/CollectionSelectField/index.d.ts.map +1 -0
  7. package/dist/components/CollectionSelectField/index.js +159 -0
  8. package/dist/components/CollectionSelectField/index.js.map +1 -0
  9. package/dist/components/ExportListMenuItem/index.d.ts.map +1 -1
  10. package/dist/components/ExportListMenuItem/index.js +5 -1
  11. package/dist/components/ExportListMenuItem/index.js.map +1 -1
  12. package/dist/components/ExportPreview/index.d.ts.map +1 -1
  13. package/dist/components/ExportPreview/index.js.map +1 -1
  14. package/dist/components/FieldsToExport/index.js +1 -1
  15. package/dist/components/FieldsToExport/index.js.map +1 -1
  16. package/dist/components/ImportPreview/index.d.ts.map +1 -1
  17. package/dist/components/ImportPreview/index.js +50 -30
  18. package/dist/components/ImportPreview/index.js.map +1 -1
  19. package/dist/export/createExport.d.ts +1 -2
  20. package/dist/export/createExport.d.ts.map +1 -1
  21. package/dist/export/createExport.js +2 -1
  22. package/dist/export/createExport.js.map +1 -1
  23. package/dist/export/getCreateExportCollectionTask.d.ts.map +1 -1
  24. package/dist/export/getCreateExportCollectionTask.js +12 -1
  25. package/dist/export/getCreateExportCollectionTask.js.map +1 -1
  26. package/dist/export/getExportCollection.d.ts +5 -1
  27. package/dist/export/getExportCollection.d.ts.map +1 -1
  28. package/dist/export/getExportCollection.js +20 -5
  29. package/dist/export/getExportCollection.js.map +1 -1
  30. package/dist/export/getFields.d.ts +7 -1
  31. package/dist/export/getFields.d.ts.map +1 -1
  32. package/dist/export/getFields.js +15 -3
  33. package/dist/export/getFields.js.map +1 -1
  34. package/dist/exports/rsc.d.ts +0 -1
  35. package/dist/exports/rsc.d.ts.map +1 -1
  36. package/dist/exports/rsc.js +0 -1
  37. package/dist/exports/rsc.js.map +1 -1
  38. package/dist/import/batchProcessor.d.ts.map +1 -1
  39. package/dist/import/batchProcessor.js +9 -3
  40. package/dist/import/batchProcessor.js.map +1 -1
  41. package/dist/import/getFields.d.ts +7 -3
  42. package/dist/import/getFields.d.ts.map +1 -1
  43. package/dist/import/getFields.js +12 -7
  44. package/dist/import/getFields.js.map +1 -1
  45. package/dist/import/getImportCollection.d.ts +6 -3
  46. package/dist/import/getImportCollection.d.ts.map +1 -1
  47. package/dist/import/getImportCollection.js +7 -4
  48. package/dist/import/getImportCollection.js.map +1 -1
  49. package/dist/index.d.ts +5 -0
  50. package/dist/index.d.ts.map +1 -1
  51. package/dist/index.js +2 -0
  52. package/dist/index.js.map +1 -1
  53. package/dist/utilities/collectTimezoneCompanionFields.d.ts +24 -0
  54. package/dist/utilities/collectTimezoneCompanionFields.d.ts.map +1 -0
  55. package/dist/utilities/collectTimezoneCompanionFields.js +89 -0
  56. package/dist/utilities/collectTimezoneCompanionFields.js.map +1 -0
  57. package/dist/utilities/collectTimezoneCompanionFields.spec.js +319 -0
  58. package/dist/utilities/collectTimezoneCompanionFields.spec.js.map +1 -0
  59. package/dist/utilities/getFilename.d.ts +1 -1
  60. package/dist/utilities/getFilename.js +3 -3
  61. package/dist/utilities/getFilename.js.map +1 -1
  62. package/dist/utilities/getPluginCollections.d.ts.map +1 -1
  63. package/dist/utilities/getPluginCollections.js +106 -34
  64. package/dist/utilities/getPluginCollections.js.map +1 -1
  65. package/dist/utilities/getSchemaColumns.d.ts.map +1 -1
  66. package/dist/utilities/getSchemaColumns.js +9 -56
  67. package/dist/utilities/getSchemaColumns.js.map +1 -1
  68. package/dist/utilities/getSchemaColumns.spec.js +157 -0
  69. package/dist/utilities/getSchemaColumns.spec.js.map +1 -0
  70. package/dist/utilities/parseCSV.d.ts.map +1 -1
  71. package/dist/utilities/parseCSV.js +1 -0
  72. package/dist/utilities/parseCSV.js.map +1 -1
  73. package/dist/utilities/parseCSV.spec.js +26 -0
  74. package/dist/utilities/parseCSV.spec.js.map +1 -1
  75. package/package.json +7 -7
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utilities/parseCSV.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nimport { parse } from 'csv-parse'\n\nexport type ParseCSVArgs = {\n data: Buffer | string\n req: PayloadRequest\n}\n\n/**\n * Parses CSV data into an array of record objects.\n * Handles type coercion for booleans, numbers, and null values.\n */\nexport const parseCSV = async ({ data, req }: ParseCSVArgs): Promise<Record<string, unknown>[]> => {\n return new Promise((resolve, reject) => {\n const records: Record<string, unknown>[] = []\n\n const parser = parse({\n cast: (value, _context) => {\n // Empty strings become undefined to preserve existing data during updates\n if (value === '') {\n return undefined\n }\n\n if (value === 'true') {\n return true\n }\n if (value === 'false') {\n return false\n }\n\n // Explicit null requires typing \"null\" or \"NULL\"\n if (value === 'null' || value === 'NULL') {\n return null\n }\n\n // Keep comma-separated values as strings for hasMany fields\n if (value.includes(',')) {\n return value\n }\n\n if (!isNaN(Number(value)) && value !== '') {\n const num = Number(value)\n if (String(num) === value || value.includes('.')) {\n return num\n }\n }\n\n return value\n },\n columns: true,\n skip_empty_lines: true,\n trim: true,\n })\n\n parser.on('readable', () => {\n let record\n while ((record = parser.read()) !== null) {\n records.push(record)\n }\n })\n\n parser.on('error', (err) => {\n req.payload.logger.error({ err, msg: 'Error parsing CSV' })\n reject(err)\n })\n\n parser.on('end', () => {\n resolve(records)\n })\n\n parser.write(data)\n parser.end()\n })\n}\n"],"names":["parse","parseCSV","data","req","Promise","resolve","reject","records","parser","cast","value","_context","undefined","includes","isNaN","Number","num","String","columns","skip_empty_lines","trim","on","record","read","push","err","payload","logger","error","msg","write","end"],"mappings":"AAEA,SAASA,KAAK,QAAQ,YAAW;AAOjC;;;CAGC,GACD,OAAO,MAAMC,WAAW,OAAO,EAAEC,IAAI,EAAEC,GAAG,EAAgB;IACxD,OAAO,IAAIC,QAAQ,CAACC,SAASC;QAC3B,MAAMC,UAAqC,EAAE;QAE7C,MAAMC,SAASR,MAAM;YACnBS,MAAM,CAACC,OAAOC;gBACZ,0EAA0E;gBAC1E,IAAID,UAAU,IAAI;oBAChB,OAAOE;gBACT;gBAEA,IAAIF,UAAU,QAAQ;oBACpB,OAAO;gBACT;gBACA,IAAIA,UAAU,SAAS;oBACrB,OAAO;gBACT;gBAEA,iDAAiD;gBACjD,IAAIA,UAAU,UAAUA,UAAU,QAAQ;oBACxC,OAAO;gBACT;gBAEA,4DAA4D;gBAC5D,IAAIA,MAAMG,QAAQ,CAAC,MAAM;oBACvB,OAAOH;gBACT;gBAEA,IAAI,CAACI,MAAMC,OAAOL,WAAWA,UAAU,IAAI;oBACzC,MAAMM,MAAMD,OAAOL;oBACnB,IAAIO,OAAOD,SAASN,SAASA,MAAMG,QAAQ,CAAC,MAAM;wBAChD,OAAOG;oBACT;gBACF;gBAEA,OAAON;YACT;YACAQ,SAAS;YACTC,kBAAkB;YAClBC,MAAM;QACR;QAEAZ,OAAOa,EAAE,CAAC,YAAY;YACpB,IAAIC;YACJ,MAAO,AAACA,CAAAA,SAASd,OAAOe,IAAI,EAAC,MAAO,KAAM;gBACxChB,QAAQiB,IAAI,CAACF;YACf;QACF;QAEAd,OAAOa,EAAE,CAAC,SAAS,CAACI;YAClBtB,IAAIuB,OAAO,CAACC,MAAM,CAACC,KAAK,CAAC;gBAAEH;gBAAKI,KAAK;YAAoB;YACzDvB,OAAOmB;QACT;QAEAjB,OAAOa,EAAE,CAAC,OAAO;YACfhB,QAAQE;QACV;QAEAC,OAAOsB,KAAK,CAAC5B;QACbM,OAAOuB,GAAG;IACZ;AACF,EAAC"}
1
+ {"version":3,"sources":["../../src/utilities/parseCSV.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nimport { parse } from 'csv-parse'\n\nexport type ParseCSVArgs = {\n data: Buffer | string\n req: PayloadRequest\n}\n\n/**\n * Parses CSV data into an array of record objects.\n * Handles type coercion for booleans, numbers, and null values.\n */\nexport const parseCSV = async ({ data, req }: ParseCSVArgs): Promise<Record<string, unknown>[]> => {\n return new Promise((resolve, reject) => {\n const records: Record<string, unknown>[] = []\n\n const parser = parse({\n bom: true,\n cast: (value, _context) => {\n // Empty strings become undefined to preserve existing data during updates\n if (value === '') {\n return undefined\n }\n\n if (value === 'true') {\n return true\n }\n if (value === 'false') {\n return false\n }\n\n // Explicit null requires typing \"null\" or \"NULL\"\n if (value === 'null' || value === 'NULL') {\n return null\n }\n\n // Keep comma-separated values as strings for hasMany fields\n if (value.includes(',')) {\n return value\n }\n\n if (!isNaN(Number(value)) && value !== '') {\n const num = Number(value)\n if (String(num) === value || value.includes('.')) {\n return num\n }\n }\n\n return value\n },\n columns: true,\n skip_empty_lines: true,\n trim: true,\n })\n\n parser.on('readable', () => {\n let record\n while ((record = parser.read()) !== null) {\n records.push(record)\n }\n })\n\n parser.on('error', (err) => {\n req.payload.logger.error({ err, msg: 'Error parsing CSV' })\n reject(err)\n })\n\n parser.on('end', () => {\n resolve(records)\n })\n\n parser.write(data)\n parser.end()\n })\n}\n"],"names":["parse","parseCSV","data","req","Promise","resolve","reject","records","parser","bom","cast","value","_context","undefined","includes","isNaN","Number","num","String","columns","skip_empty_lines","trim","on","record","read","push","err","payload","logger","error","msg","write","end"],"mappings":"AAEA,SAASA,KAAK,QAAQ,YAAW;AAOjC;;;CAGC,GACD,OAAO,MAAMC,WAAW,OAAO,EAAEC,IAAI,EAAEC,GAAG,EAAgB;IACxD,OAAO,IAAIC,QAAQ,CAACC,SAASC;QAC3B,MAAMC,UAAqC,EAAE;QAE7C,MAAMC,SAASR,MAAM;YACnBS,KAAK;YACLC,MAAM,CAACC,OAAOC;gBACZ,0EAA0E;gBAC1E,IAAID,UAAU,IAAI;oBAChB,OAAOE;gBACT;gBAEA,IAAIF,UAAU,QAAQ;oBACpB,OAAO;gBACT;gBACA,IAAIA,UAAU,SAAS;oBACrB,OAAO;gBACT;gBAEA,iDAAiD;gBACjD,IAAIA,UAAU,UAAUA,UAAU,QAAQ;oBACxC,OAAO;gBACT;gBAEA,4DAA4D;gBAC5D,IAAIA,MAAMG,QAAQ,CAAC,MAAM;oBACvB,OAAOH;gBACT;gBAEA,IAAI,CAACI,MAAMC,OAAOL,WAAWA,UAAU,IAAI;oBACzC,MAAMM,MAAMD,OAAOL;oBACnB,IAAIO,OAAOD,SAASN,SAASA,MAAMG,QAAQ,CAAC,MAAM;wBAChD,OAAOG;oBACT;gBACF;gBAEA,OAAON;YACT;YACAQ,SAAS;YACTC,kBAAkB;YAClBC,MAAM;QACR;QAEAb,OAAOc,EAAE,CAAC,YAAY;YACpB,IAAIC;YACJ,MAAO,AAACA,CAAAA,SAASf,OAAOgB,IAAI,EAAC,MAAO,KAAM;gBACxCjB,QAAQkB,IAAI,CAACF;YACf;QACF;QAEAf,OAAOc,EAAE,CAAC,SAAS,CAACI;YAClBvB,IAAIwB,OAAO,CAACC,MAAM,CAACC,KAAK,CAAC;gBAAEH;gBAAKI,KAAK;YAAoB;YACzDxB,OAAOoB;QACT;QAEAlB,OAAOc,EAAE,CAAC,OAAO;YACfjB,QAAQE;QACV;QAEAC,OAAOuB,KAAK,CAAC7B;QACbM,OAAOwB,GAAG;IACZ;AACF,EAAC"}
@@ -153,6 +153,32 @@ describe('parseCSV', ()=>{
153
153
  }
154
154
  ]);
155
155
  });
156
+ it('should strip UTF-8 BOM from column names', async ()=>{
157
+ // UTF-8 BOM is 0xEF 0xBB 0xBF
158
+ const bomBytes = Buffer.from([
159
+ 0xef,
160
+ 0xbb,
161
+ 0xbf
162
+ ]);
163
+ const csvContent = Buffer.from('id,title,createdAt\ntesssst,test,2026-02-11T21:03:39.020Z');
164
+ const csvWithBOM = Buffer.concat([
165
+ bomBytes,
166
+ csvContent
167
+ ]);
168
+ const result = await parseCSV({
169
+ data: csvWithBOM,
170
+ req: mockReq
171
+ });
172
+ expect(result).toEqual([
173
+ {
174
+ id: 'tesssst',
175
+ title: 'test',
176
+ createdAt: '2026-02-11T21:03:39.020Z'
177
+ }
178
+ ]);
179
+ // Verify the column name is exactly "id" without BOM character
180
+ expect(Object.keys(result[0])[0]).toBe('id');
181
+ });
156
182
  });
157
183
  describe('error handling', ()=>{
158
184
  it('should handle parsing errors', async ()=>{
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utilities/parseCSV.spec.ts"],"sourcesContent":["import { PayloadRequest } from 'payload'\n\nimport { parseCSV } from './parseCSV.js'\nimport { describe, it, expect, vi } from 'vitest'\n\ndescribe('parseCSV', () => {\n const mockReq = {\n payload: {\n logger: {\n error: vi.fn(),\n },\n },\n } as unknown as PayloadRequest\n\n describe('cast function behavior', () => {\n it('should preserve comma-separated values as strings', async () => {\n const csvData = Buffer.from('numbers,ids\\n\"1,2,3,5,8\",\"id1,id2,id3\"')\n const result = await parseCSV({ data: csvData, req: mockReq })\n\n expect(result).toEqual([\n {\n numbers: '1,2,3,5,8',\n ids: 'id1,id2,id3',\n },\n ])\n })\n\n it('should convert single numbers to numbers', async () => {\n const csvData = Buffer.from('single,decimal\\n\"42\",\"3.14\"')\n const result = await parseCSV({ data: csvData, req: mockReq })\n\n expect(result).toEqual([\n {\n single: 42,\n decimal: 3.14,\n },\n ])\n })\n\n it('should handle booleans correctly', async () => {\n const csvData = Buffer.from('bool1,bool2,notBool\\n\"true\",\"false\",\"True\"')\n const result = await parseCSV({ data: csvData, req: mockReq })\n\n expect(result).toEqual([\n {\n bool1: true,\n bool2: false,\n notBool: 'True', // Case-sensitive\n },\n ])\n })\n\n it('should convert empty strings to undefined', async () => {\n const csvData = Buffer.from('field1,field2\\n\"\",\"value\"')\n const result = await parseCSV({ data: csvData, req: mockReq })\n\n expect(result).toEqual([\n {\n // field1 is undefined (not present) - empty cells don't update fields\n field2: 'value',\n },\n ])\n })\n\n it('should handle null strings', async () => {\n const csvData = Buffer.from('field1,field2,field3\\n\"null\",\"NULL\",\"Null\"')\n const result = await parseCSV({ data: csvData, req: mockReq })\n\n expect(result).toEqual([\n {\n field1: null,\n field2: null,\n field3: 'Null', // Case-sensitive for mixed case\n },\n ])\n })\n\n it('should preserve spaces in comma-separated values', async () => {\n const csvData = Buffer.from('numbers\\n\" 10 , 20 , 30 \"')\n const result = await parseCSV({ data: csvData, req: mockReq })\n\n expect(result).toEqual([\n {\n numbers: ' 10 , 20 , 30 ', // CSV parser trims outer quotes but preserves the content\n },\n ])\n })\n\n it('should handle mixed comma-separated values with empty entries', async () => {\n const csvData = Buffer.from('mixed\\n\"1,,3,,5\"')\n const result = await parseCSV({ data: csvData, req: mockReq })\n\n expect(result).toEqual([\n {\n mixed: '1,,3,,5',\n },\n ])\n })\n\n it('should handle MongoDB ObjectIds as strings', async () => {\n const csvData = Buffer.from('id\\n\"507f1f77bcf86cd799439011\"')\n const result = await parseCSV({ data: csvData, req: mockReq })\n\n expect(result).toEqual([\n {\n id: '507f1f77bcf86cd799439011',\n },\n ])\n })\n\n it('should handle multiple rows with various data types', async () => {\n const csvData = Buffer.from(\n 'title,count,tags,active\\n' +\n '\"Item 1\",\"5\",\"tag1,tag2,tag3\",\"true\"\\n' +\n '\"Item 2\",\"\",\"\",\"false\"\\n' +\n '\"Item 3\",\"10\",\"single\",\"\"\\n',\n )\n const result = await parseCSV({ data: csvData, req: mockReq })\n\n expect(result).toEqual([\n {\n title: 'Item 1',\n count: 5,\n tags: 'tag1,tag2,tag3',\n active: true,\n },\n {\n title: 'Item 2',\n // count is undefined (empty cell - field not updated)\n // tags is undefined (empty cell - field not updated)\n active: false,\n },\n {\n title: 'Item 3',\n count: 10,\n tags: 'single',\n // active is undefined (empty cell - field not updated)\n },\n ])\n })\n\n it('should skip empty lines', async () => {\n const csvData = Buffer.from('field\\n\"value1\"\\n\\n\"value2\"\\n\\n')\n const result = await parseCSV({ data: csvData, req: mockReq })\n\n expect(result).toEqual([{ field: 'value1' }, { field: 'value2' }])\n })\n })\n\n describe('error handling', () => {\n it('should handle parsing errors', async () => {\n const invalidCsv = Buffer.from('field1,field2\\n\"value1')\n\n await expect(parseCSV({ data: invalidCsv, req: mockReq })).rejects.toThrow()\n expect(mockReq.payload.logger.error).toHaveBeenCalled()\n })\n })\n})\n"],"names":["parseCSV","describe","it","expect","vi","mockReq","payload","logger","error","fn","csvData","Buffer","from","result","data","req","toEqual","numbers","ids","single","decimal","bool1","bool2","notBool","field2","field1","field3","mixed","id","title","count","tags","active","field","invalidCsv","rejects","toThrow","toHaveBeenCalled"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/utilities/parseCSV.spec.ts"],"sourcesContent":["import { PayloadRequest } from 'payload'\n\nimport { parseCSV } from './parseCSV.js'\nimport { describe, it, expect, vi } from 'vitest'\n\ndescribe('parseCSV', () => {\n const mockReq = {\n payload: {\n logger: {\n error: vi.fn(),\n },\n },\n } as unknown as PayloadRequest\n\n describe('cast function behavior', () => {\n it('should preserve comma-separated values as strings', async () => {\n const csvData = Buffer.from('numbers,ids\\n\"1,2,3,5,8\",\"id1,id2,id3\"')\n const result = await parseCSV({ data: csvData, req: mockReq })\n\n expect(result).toEqual([\n {\n numbers: '1,2,3,5,8',\n ids: 'id1,id2,id3',\n },\n ])\n })\n\n it('should convert single numbers to numbers', async () => {\n const csvData = Buffer.from('single,decimal\\n\"42\",\"3.14\"')\n const result = await parseCSV({ data: csvData, req: mockReq })\n\n expect(result).toEqual([\n {\n single: 42,\n decimal: 3.14,\n },\n ])\n })\n\n it('should handle booleans correctly', async () => {\n const csvData = Buffer.from('bool1,bool2,notBool\\n\"true\",\"false\",\"True\"')\n const result = await parseCSV({ data: csvData, req: mockReq })\n\n expect(result).toEqual([\n {\n bool1: true,\n bool2: false,\n notBool: 'True', // Case-sensitive\n },\n ])\n })\n\n it('should convert empty strings to undefined', async () => {\n const csvData = Buffer.from('field1,field2\\n\"\",\"value\"')\n const result = await parseCSV({ data: csvData, req: mockReq })\n\n expect(result).toEqual([\n {\n // field1 is undefined (not present) - empty cells don't update fields\n field2: 'value',\n },\n ])\n })\n\n it('should handle null strings', async () => {\n const csvData = Buffer.from('field1,field2,field3\\n\"null\",\"NULL\",\"Null\"')\n const result = await parseCSV({ data: csvData, req: mockReq })\n\n expect(result).toEqual([\n {\n field1: null,\n field2: null,\n field3: 'Null', // Case-sensitive for mixed case\n },\n ])\n })\n\n it('should preserve spaces in comma-separated values', async () => {\n const csvData = Buffer.from('numbers\\n\" 10 , 20 , 30 \"')\n const result = await parseCSV({ data: csvData, req: mockReq })\n\n expect(result).toEqual([\n {\n numbers: ' 10 , 20 , 30 ', // CSV parser trims outer quotes but preserves the content\n },\n ])\n })\n\n it('should handle mixed comma-separated values with empty entries', async () => {\n const csvData = Buffer.from('mixed\\n\"1,,3,,5\"')\n const result = await parseCSV({ data: csvData, req: mockReq })\n\n expect(result).toEqual([\n {\n mixed: '1,,3,,5',\n },\n ])\n })\n\n it('should handle MongoDB ObjectIds as strings', async () => {\n const csvData = Buffer.from('id\\n\"507f1f77bcf86cd799439011\"')\n const result = await parseCSV({ data: csvData, req: mockReq })\n\n expect(result).toEqual([\n {\n id: '507f1f77bcf86cd799439011',\n },\n ])\n })\n\n it('should handle multiple rows with various data types', async () => {\n const csvData = Buffer.from(\n 'title,count,tags,active\\n' +\n '\"Item 1\",\"5\",\"tag1,tag2,tag3\",\"true\"\\n' +\n '\"Item 2\",\"\",\"\",\"false\"\\n' +\n '\"Item 3\",\"10\",\"single\",\"\"\\n',\n )\n const result = await parseCSV({ data: csvData, req: mockReq })\n\n expect(result).toEqual([\n {\n title: 'Item 1',\n count: 5,\n tags: 'tag1,tag2,tag3',\n active: true,\n },\n {\n title: 'Item 2',\n // count is undefined (empty cell - field not updated)\n // tags is undefined (empty cell - field not updated)\n active: false,\n },\n {\n title: 'Item 3',\n count: 10,\n tags: 'single',\n // active is undefined (empty cell - field not updated)\n },\n ])\n })\n\n it('should skip empty lines', async () => {\n const csvData = Buffer.from('field\\n\"value1\"\\n\\n\"value2\"\\n\\n')\n const result = await parseCSV({ data: csvData, req: mockReq })\n\n expect(result).toEqual([{ field: 'value1' }, { field: 'value2' }])\n })\n\n it('should strip UTF-8 BOM from column names', async () => {\n // UTF-8 BOM is 0xEF 0xBB 0xBF\n const bomBytes = Buffer.from([0xef, 0xbb, 0xbf])\n const csvContent = Buffer.from('id,title,createdAt\\ntesssst,test,2026-02-11T21:03:39.020Z')\n const csvWithBOM = Buffer.concat([bomBytes, csvContent])\n\n const result = await parseCSV({ data: csvWithBOM, req: mockReq })\n\n expect(result).toEqual([\n {\n id: 'tesssst',\n title: 'test',\n createdAt: '2026-02-11T21:03:39.020Z',\n },\n ])\n\n // Verify the column name is exactly \"id\" without BOM character\n expect(Object.keys(result[0])[0]).toBe('id')\n })\n })\n\n describe('error handling', () => {\n it('should handle parsing errors', async () => {\n const invalidCsv = Buffer.from('field1,field2\\n\"value1')\n\n await expect(parseCSV({ data: invalidCsv, req: mockReq })).rejects.toThrow()\n expect(mockReq.payload.logger.error).toHaveBeenCalled()\n })\n })\n})\n"],"names":["parseCSV","describe","it","expect","vi","mockReq","payload","logger","error","fn","csvData","Buffer","from","result","data","req","toEqual","numbers","ids","single","decimal","bool1","bool2","notBool","field2","field1","field3","mixed","id","title","count","tags","active","field","bomBytes","csvContent","csvWithBOM","concat","createdAt","Object","keys","toBe","invalidCsv","rejects","toThrow","toHaveBeenCalled"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@payloadcms/plugin-import-export",
3
- "version": "3.77.0-internal.9837b1e",
3
+ "version": "3.77.0",
4
4
  "description": "Import-Export plugin for Payload",
5
5
  "keywords": [
6
6
  "payload",
@@ -64,17 +64,17 @@
64
64
  "csv-parse": "5.6.0",
65
65
  "csv-stringify": "6.5.2",
66
66
  "qs-esm": "7.0.2",
67
- "@payloadcms/translations": "3.77.0-internal.9837b1e",
68
- "@payloadcms/ui": "3.77.0-internal.9837b1e"
67
+ "@payloadcms/ui": "3.77.0",
68
+ "@payloadcms/translations": "3.77.0"
69
69
  },
70
70
  "devDependencies": {
71
+ "@payloadcms/ui": "3.77.0",
71
72
  "@payloadcms/eslint-config": "3.28.0",
72
- "@payloadcms/ui": "3.77.0-internal.9837b1e",
73
- "payload": "3.77.0-internal.9837b1e"
73
+ "payload": "3.77.0"
74
74
  },
75
75
  "peerDependencies": {
76
- "payload": "3.77.0-internal.9837b1e",
77
- "@payloadcms/ui": "3.77.0-internal.9837b1e"
76
+ "@payloadcms/ui": "3.77.0",
77
+ "payload": "3.77.0"
78
78
  },
79
79
  "homepage:": "https://payloadcms.com",
80
80
  "scripts": {