@payloadcms/plugin-import-export 3.78.0-internal-debug.f663370 → 3.78.0-internal.ab11ffa
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.
- package/dist/components/ExportSaveButton/index.d.ts.map +1 -1
- package/dist/components/ExportSaveButton/index.js +11 -6
- package/dist/components/ExportSaveButton/index.js.map +1 -1
- package/dist/components/FormatField/index.d.ts +3 -0
- package/dist/components/FormatField/index.d.ts.map +1 -0
- package/dist/components/FormatField/index.js +95 -0
- package/dist/components/FormatField/index.js.map +1 -0
- package/dist/export/createExport.d.ts.map +1 -1
- package/dist/export/createExport.js +44 -16
- package/dist/export/createExport.js.map +1 -1
- package/dist/export/getCreateExportCollectionTask.d.ts.map +1 -1
- package/dist/export/getCreateExportCollectionTask.js +105 -24
- package/dist/export/getCreateExportCollectionTask.js.map +1 -1
- package/dist/export/getExportCollection.d.ts.map +1 -1
- package/dist/export/getExportCollection.js +75 -66
- package/dist/export/getExportCollection.js.map +1 -1
- package/dist/export/getFields.d.ts.map +1 -1
- package/dist/export/getFields.js +4 -7
- package/dist/export/getFields.js.map +1 -1
- package/dist/exports/rsc.d.ts +1 -0
- package/dist/exports/rsc.d.ts.map +1 -1
- package/dist/exports/rsc.js +1 -0
- package/dist/exports/rsc.js.map +1 -1
- package/dist/import/batchProcessor.d.ts.map +1 -1
- package/dist/import/batchProcessor.js +11 -5
- package/dist/import/batchProcessor.js.map +1 -1
- package/dist/import/createImport.d.ts.map +1 -1
- package/dist/import/createImport.js +2 -1
- package/dist/import/createImport.js.map +1 -1
- package/dist/import/getImportCollection.d.ts.map +1 -1
- package/dist/import/getImportCollection.js +229 -181
- package/dist/import/getImportCollection.js.map +1 -1
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +39 -16
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +13 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utilities/getPluginCollections.d.ts +4 -1
- package/dist/utilities/getPluginCollections.d.ts.map +1 -1
- package/dist/utilities/getPluginCollections.js +4 -43
- package/dist/utilities/getPluginCollections.js.map +1 -1
- package/dist/utilities/unflattenObject.d.ts.map +1 -1
- package/dist/utilities/unflattenObject.js +5 -0
- package/dist/utilities/unflattenObject.js.map +1 -1
- package/package.json +8 -8
|
@@ -4,13 +4,10 @@ import { resolveLimit } from '../utilities/resolveLimit.js';
|
|
|
4
4
|
import { createImport } from './createImport.js';
|
|
5
5
|
import { getFields } from './getFields.js';
|
|
6
6
|
import { handlePreview } from './handlePreview.js';
|
|
7
|
+
const FALLBACK_BATCH_SIZE = 100;
|
|
8
|
+
const FALLBACK_VERSION_STATUS = 'published';
|
|
7
9
|
export const getImportCollection = ({ collectionSlugs, importConfig, pluginConfig })=>{
|
|
8
|
-
const beforeOperation = [];
|
|
9
10
|
const afterChange = [];
|
|
10
|
-
// Extract import-specific settings
|
|
11
|
-
const disableJobsQueue = importConfig?.disableJobsQueue ?? false;
|
|
12
|
-
const batchSize = importConfig?.batchSize ?? 100;
|
|
13
|
-
const defaultVersionStatus = importConfig?.defaultVersionStatus ?? 'published';
|
|
14
11
|
const collection = {
|
|
15
12
|
slug: 'imports',
|
|
16
13
|
access: {
|
|
@@ -43,8 +40,7 @@ export const getImportCollection = ({ collectionSlugs, importConfig, pluginConfi
|
|
|
43
40
|
collectionSlugs
|
|
44
41
|
}),
|
|
45
42
|
hooks: {
|
|
46
|
-
afterChange
|
|
47
|
-
beforeOperation
|
|
43
|
+
afterChange
|
|
48
44
|
},
|
|
49
45
|
lockDocuments: false,
|
|
50
46
|
upload: {
|
|
@@ -57,198 +53,250 @@ export const getImportCollection = ({ collectionSlugs, importConfig, pluginConfi
|
|
|
57
53
|
]
|
|
58
54
|
}
|
|
59
55
|
};
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
56
|
+
afterChange.push(async ({ collection: collectionConfig, doc, operation, req })=>{
|
|
57
|
+
if (operation !== 'create' || doc.status !== 'pending') {
|
|
58
|
+
return doc;
|
|
59
|
+
}
|
|
60
|
+
const targetCollection = req.payload.collections[doc.collectionSlug];
|
|
61
|
+
const targetPluginConfig = targetCollection?.config.custom?.['plugin-import-export'];
|
|
62
|
+
const disableJobsQueue = targetPluginConfig?.importDisableJobsQueue ?? importConfig?.disableJobsQueue ?? false;
|
|
63
|
+
const debug = pluginConfig.debug || false;
|
|
64
|
+
if (debug) {
|
|
65
|
+
req.payload.logger.info({
|
|
66
|
+
collectionSlug: doc.collectionSlug,
|
|
67
|
+
disableJobsQueue,
|
|
68
|
+
docId: doc.id,
|
|
69
|
+
msg: '[Import Sync Hook] Starting',
|
|
70
|
+
transactionID: req.transactionID
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
if (!disableJobsQueue) {
|
|
74
|
+
return doc;
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
// Get file data from the uploaded document
|
|
78
|
+
// First try req.file which is available during the same request (especially important for cloud storage)
|
|
79
|
+
// Fall back to getFileFromDoc for cases where req.file isn't available
|
|
80
|
+
let fileData;
|
|
81
|
+
let fileMimetype;
|
|
82
|
+
if (req.file?.data) {
|
|
83
|
+
fileData = req.file.data;
|
|
84
|
+
fileMimetype = req.file.mimetype || doc.mimeType;
|
|
85
|
+
if (!fileMimetype) {
|
|
86
|
+
throw new FileRetrievalError(req.t, `Unable to determine mimetype for file: ${doc.filename}`);
|
|
91
87
|
}
|
|
92
|
-
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
88
|
+
} else {
|
|
89
|
+
const fileFromDoc = await getFileFromDoc({
|
|
90
|
+
collectionConfig,
|
|
91
|
+
doc: {
|
|
92
|
+
filename: doc.filename,
|
|
93
|
+
mimeType: doc.mimeType,
|
|
94
|
+
url: doc.url
|
|
95
|
+
},
|
|
96
96
|
req
|
|
97
97
|
});
|
|
98
|
-
|
|
98
|
+
fileData = fileFromDoc.data;
|
|
99
|
+
fileMimetype = fileFromDoc.mimetype;
|
|
100
|
+
}
|
|
101
|
+
const maxLimit = await resolveLimit({
|
|
102
|
+
limit: targetPluginConfig?.importLimit,
|
|
103
|
+
req
|
|
104
|
+
});
|
|
105
|
+
const defaultVersionStatus = targetPluginConfig?.defaultVersionStatus ?? importConfig?.defaultVersionStatus ?? pluginConfig.defaultVersionStatus ?? FALLBACK_VERSION_STATUS;
|
|
106
|
+
const batchSize = targetPluginConfig?.importBatchSize ?? importConfig?.batchSize ?? pluginConfig.batchSize ?? FALLBACK_BATCH_SIZE;
|
|
107
|
+
const result = await createImport({
|
|
108
|
+
id: doc.id,
|
|
109
|
+
name: doc.filename || 'import',
|
|
110
|
+
batchSize,
|
|
111
|
+
collectionSlug: doc.collectionSlug,
|
|
112
|
+
debug,
|
|
113
|
+
defaultVersionStatus,
|
|
114
|
+
file: {
|
|
115
|
+
name: doc.filename,
|
|
116
|
+
data: fileData,
|
|
117
|
+
mimetype: fileMimetype
|
|
118
|
+
},
|
|
119
|
+
format: fileMimetype === 'text/csv' ? 'csv' : 'json',
|
|
120
|
+
importMode: doc.importMode || 'create',
|
|
121
|
+
matchField: doc.matchField,
|
|
122
|
+
maxLimit,
|
|
123
|
+
req,
|
|
124
|
+
userCollection: req?.user?.collection || req?.user?.user?.collection,
|
|
125
|
+
userID: req?.user?.id || req?.user?.user?.id
|
|
126
|
+
});
|
|
127
|
+
// Determine status
|
|
128
|
+
let status;
|
|
129
|
+
if (result.errors.length === 0) {
|
|
130
|
+
status = 'completed';
|
|
131
|
+
} else if (result.imported + result.updated === 0) {
|
|
132
|
+
status = 'failed';
|
|
133
|
+
} else {
|
|
134
|
+
status = 'partial';
|
|
135
|
+
}
|
|
136
|
+
const summary = {
|
|
137
|
+
imported: result.imported,
|
|
138
|
+
issueDetails: result.errors.length > 0 ? result.errors.map((e)=>({
|
|
139
|
+
data: e.doc,
|
|
140
|
+
error: e.error,
|
|
141
|
+
row: e.index + 1
|
|
142
|
+
})) : undefined,
|
|
143
|
+
issues: result.errors.length,
|
|
144
|
+
total: result.total,
|
|
145
|
+
updated: result.updated
|
|
146
|
+
};
|
|
147
|
+
// Try to update the document with results
|
|
148
|
+
try {
|
|
149
|
+
await req.payload.update({
|
|
99
150
|
id: doc.id,
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
defaultVersionStatus,
|
|
105
|
-
file: {
|
|
106
|
-
name: doc.filename,
|
|
107
|
-
data: fileData,
|
|
108
|
-
mimetype: fileMimetype
|
|
151
|
+
collection: collectionConfig.slug,
|
|
152
|
+
data: {
|
|
153
|
+
status,
|
|
154
|
+
summary
|
|
109
155
|
},
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
matchField: doc.matchField,
|
|
113
|
-
maxLimit,
|
|
114
|
-
req,
|
|
115
|
-
userCollection: req?.user?.collection || req?.user?.user?.collection,
|
|
116
|
-
userID: req?.user?.id || req?.user?.user?.id
|
|
156
|
+
overrideAccess: true,
|
|
157
|
+
req
|
|
117
158
|
});
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
if (result.errors.length === 0) {
|
|
121
|
-
status = 'completed';
|
|
122
|
-
} else if (result.imported + result.updated === 0) {
|
|
123
|
-
status = 'failed';
|
|
124
|
-
} else {
|
|
125
|
-
status = 'partial';
|
|
126
|
-
}
|
|
127
|
-
const summary = {
|
|
128
|
-
imported: result.imported,
|
|
129
|
-
issueDetails: result.errors.length > 0 ? result.errors.map((e)=>({
|
|
130
|
-
data: e.doc,
|
|
131
|
-
error: e.error,
|
|
132
|
-
row: e.index + 1
|
|
133
|
-
})) : undefined,
|
|
134
|
-
issues: result.errors.length,
|
|
135
|
-
total: result.total,
|
|
136
|
-
updated: result.updated
|
|
137
|
-
};
|
|
138
|
-
// Try to update the document with results (may fail due to transaction timing)
|
|
139
|
-
try {
|
|
140
|
-
await req.payload.update({
|
|
141
|
-
id: doc.id,
|
|
142
|
-
collection: collectionConfig.slug,
|
|
143
|
-
data: {
|
|
144
|
-
status,
|
|
145
|
-
summary
|
|
146
|
-
},
|
|
147
|
-
overrideAccess: true,
|
|
148
|
-
req
|
|
149
|
-
});
|
|
150
|
-
} catch (updateErr) {
|
|
151
|
-
// Update may fail if document not yet committed, log but continue
|
|
152
|
-
if (debug) {
|
|
153
|
-
req.payload.logger.error({
|
|
154
|
-
err: updateErr,
|
|
155
|
-
msg: `Failed to update import document ${doc.id} with results`
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
// Return updated doc for immediate response
|
|
160
|
-
return {
|
|
161
|
-
...doc,
|
|
162
|
-
status,
|
|
163
|
-
summary
|
|
164
|
-
};
|
|
165
|
-
} catch (err) {
|
|
166
|
-
const summary = {
|
|
167
|
-
imported: 0,
|
|
168
|
-
issueDetails: [
|
|
169
|
-
{
|
|
170
|
-
data: {},
|
|
171
|
-
error: err instanceof Error ? err.message : String(err),
|
|
172
|
-
row: 0
|
|
173
|
-
}
|
|
174
|
-
],
|
|
175
|
-
issues: 1,
|
|
176
|
-
total: 0,
|
|
177
|
-
updated: 0
|
|
178
|
-
};
|
|
179
|
-
// Try to update document with error status
|
|
180
|
-
try {
|
|
181
|
-
await req.payload.update({
|
|
182
|
-
id: doc.id,
|
|
183
|
-
collection: collectionConfig.slug,
|
|
184
|
-
data: {
|
|
185
|
-
status: 'failed',
|
|
186
|
-
summary
|
|
187
|
-
},
|
|
188
|
-
overrideAccess: true,
|
|
189
|
-
req
|
|
190
|
-
});
|
|
191
|
-
} catch (updateErr) {
|
|
192
|
-
// Update may fail if document not yet committed, log but continue
|
|
193
|
-
if (debug) {
|
|
194
|
-
req.payload.logger.error({
|
|
195
|
-
err: updateErr,
|
|
196
|
-
msg: `Failed to update import document ${doc.id} with error status`
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
}
|
|
159
|
+
} catch (updateErr) {
|
|
160
|
+
// Update may fail if document not yet committed
|
|
200
161
|
if (debug) {
|
|
201
162
|
req.payload.logger.error({
|
|
202
|
-
err,
|
|
203
|
-
msg:
|
|
163
|
+
err: updateErr,
|
|
164
|
+
msg: `Failed to update import document ${doc.id} with results`
|
|
204
165
|
});
|
|
205
166
|
}
|
|
206
|
-
// Return error status for immediate response
|
|
207
|
-
return {
|
|
208
|
-
...doc,
|
|
209
|
-
status: 'failed',
|
|
210
|
-
summary
|
|
211
|
-
};
|
|
212
167
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
168
|
+
// Return updated doc for immediate response
|
|
169
|
+
return {
|
|
170
|
+
...doc,
|
|
171
|
+
status,
|
|
172
|
+
summary
|
|
173
|
+
};
|
|
174
|
+
} catch (err) {
|
|
175
|
+
const summary = {
|
|
176
|
+
imported: 0,
|
|
177
|
+
issueDetails: [
|
|
178
|
+
{
|
|
179
|
+
data: {},
|
|
180
|
+
error: err instanceof Error ? err.message : String(err),
|
|
181
|
+
row: 0
|
|
182
|
+
}
|
|
183
|
+
],
|
|
184
|
+
issues: 1,
|
|
185
|
+
total: 0,
|
|
186
|
+
updated: 0
|
|
187
|
+
};
|
|
188
|
+
if (debug) {
|
|
189
|
+
req.payload.logger.error({
|
|
190
|
+
docId: doc.id,
|
|
191
|
+
err,
|
|
192
|
+
msg: '[Import Sync Hook] Import processing failed, attempting to update status',
|
|
193
|
+
transactionID: req.transactionID
|
|
194
|
+
});
|
|
220
195
|
}
|
|
196
|
+
// Try to update document with error status
|
|
221
197
|
try {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
198
|
+
if (debug) {
|
|
199
|
+
req.payload.logger.info({
|
|
200
|
+
collectionSlug: collectionConfig.slug,
|
|
201
|
+
docId: doc.id,
|
|
202
|
+
msg: '[Import Sync Hook] About to update document with failed status'
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
await req.payload.update({
|
|
206
|
+
id: doc.id,
|
|
207
|
+
collection: collectionConfig.slug,
|
|
208
|
+
data: {
|
|
209
|
+
status: 'failed',
|
|
210
|
+
summary
|
|
211
|
+
},
|
|
212
|
+
overrideAccess: true,
|
|
227
213
|
req
|
|
228
214
|
});
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
userID: req?.user?.id || req?.user?.user?.id
|
|
239
|
-
};
|
|
240
|
-
await req.payload.jobs.queue({
|
|
241
|
-
input,
|
|
242
|
-
task: 'createCollectionImport'
|
|
243
|
-
});
|
|
244
|
-
} catch (err) {
|
|
215
|
+
if (debug) {
|
|
216
|
+
req.payload.logger.info({
|
|
217
|
+
docId: doc.id,
|
|
218
|
+
msg: '[Import Sync Hook] Successfully updated document with failed status'
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
} catch (updateErr) {
|
|
222
|
+
// Update may fail if document not yet committed, log but continue
|
|
223
|
+
// ALWAYS log this error to help debug Postgres issues
|
|
245
224
|
req.payload.logger.error({
|
|
246
|
-
err,
|
|
247
|
-
msg: `Failed to
|
|
225
|
+
err: updateErr,
|
|
226
|
+
msg: `[Import Sync Hook] Failed to update import document ${doc.id} with error status`,
|
|
227
|
+
transactionID: req.transactionID
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
if (debug) {
|
|
231
|
+
req.payload.logger.info({
|
|
232
|
+
docId: doc.id,
|
|
233
|
+
msg: '[Import Sync Hook] Returning failed doc',
|
|
234
|
+
status: 'failed'
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
// Return error status for immediate response
|
|
238
|
+
return {
|
|
239
|
+
...doc,
|
|
240
|
+
status: 'failed',
|
|
241
|
+
summary
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
afterChange.push(async ({ collection: collectionConfig, doc, operation, req })=>{
|
|
246
|
+
if (operation !== 'create') {
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
const targetCollection = req.payload.collections[doc.collectionSlug];
|
|
250
|
+
const targetPluginConfig = targetCollection?.config.custom?.['plugin-import-export'];
|
|
251
|
+
const disableJobsQueue = targetPluginConfig?.importDisableJobsQueue ?? importConfig?.disableJobsQueue ?? false;
|
|
252
|
+
if (pluginConfig.debug) {
|
|
253
|
+
req.payload.logger.info({
|
|
254
|
+
collectionSlug: doc.collectionSlug,
|
|
255
|
+
disableJobsQueue,
|
|
256
|
+
docId: doc.id,
|
|
257
|
+
docStatus: doc.status,
|
|
258
|
+
msg: '[Import Job Hook] Checking if should queue job',
|
|
259
|
+
transactionID: req.transactionID
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
if (disableJobsQueue) {
|
|
263
|
+
if (pluginConfig.debug) {
|
|
264
|
+
req.payload.logger.info({
|
|
265
|
+
docId: doc.id,
|
|
266
|
+
msg: '[Import Job Hook] Skipping job queue (sync mode)'
|
|
248
267
|
});
|
|
249
268
|
}
|
|
250
|
-
|
|
251
|
-
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
try {
|
|
272
|
+
// Resolve maxLimit ahead of time since it may involve async config resolution
|
|
273
|
+
const maxLimit = await resolveLimit({
|
|
274
|
+
limit: targetPluginConfig?.importLimit,
|
|
275
|
+
req
|
|
276
|
+
});
|
|
277
|
+
const defaultVersionStatus = targetPluginConfig?.defaultVersionStatus ?? importConfig?.defaultVersionStatus ?? pluginConfig.defaultVersionStatus ?? FALLBACK_VERSION_STATUS;
|
|
278
|
+
const batchSize = targetPluginConfig?.importBatchSize ?? importConfig?.batchSize ?? pluginConfig.batchSize ?? FALLBACK_BATCH_SIZE;
|
|
279
|
+
const input = {
|
|
280
|
+
batchSize,
|
|
281
|
+
debug: pluginConfig.debug,
|
|
282
|
+
defaultVersionStatus,
|
|
283
|
+
importCollection: collectionConfig.slug,
|
|
284
|
+
importId: doc.id,
|
|
285
|
+
maxLimit,
|
|
286
|
+
userCollection: req.user?.collection || req?.user?.user?.collection,
|
|
287
|
+
userID: req?.user?.id || req?.user?.user?.id
|
|
288
|
+
};
|
|
289
|
+
await req.payload.jobs.queue({
|
|
290
|
+
input,
|
|
291
|
+
task: 'createCollectionImport'
|
|
292
|
+
});
|
|
293
|
+
} catch (err) {
|
|
294
|
+
req.payload.logger.error({
|
|
295
|
+
err,
|
|
296
|
+
msg: `Failed to queue import job for document ${doc.id}`
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
});
|
|
252
300
|
return collection;
|
|
253
301
|
};
|
|
254
302
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/import/getImportCollection.ts"],"sourcesContent":["import type {\n CollectionAfterChangeHook,\n CollectionBeforeOperationHook,\n CollectionConfig,\n} from 'payload'\n\nimport { FileRetrievalError } from 'payload'\n\nimport type { ImportConfig, ImportExportPluginConfig, Limit } from '../types.js'\nimport type { ImportTaskInput } from './getCreateImportCollectionTask.js'\n\nimport { getFileFromDoc } from '../utilities/getFileFromDoc.js'\nimport { resolveLimit } from '../utilities/resolveLimit.js'\nimport { createImport } from './createImport.js'\nimport { getFields } from './getFields.js'\nimport { handlePreview } from './handlePreview.js'\n\nexport const getImportCollection = ({\n collectionSlugs,\n importConfig,\n pluginConfig,\n}: {\n /**\n * Collection slugs that this import collection supports.\n */\n collectionSlugs: string[]\n importConfig?: ImportConfig\n pluginConfig: ImportExportPluginConfig\n}): CollectionConfig => {\n const beforeOperation: CollectionBeforeOperationHook[] = []\n const afterChange: CollectionAfterChangeHook[] = []\n\n // Extract import-specific settings\n const disableJobsQueue = importConfig?.disableJobsQueue ?? false\n const batchSize = importConfig?.batchSize ?? 100\n const defaultVersionStatus = importConfig?.defaultVersionStatus ?? 'published'\n\n const collection: CollectionConfig = {\n slug: 'imports',\n access: {\n update: () => false,\n },\n admin: {\n components: {\n edit: {\n SaveButton: '@payloadcms/plugin-import-export/rsc#ImportSaveButton',\n },\n },\n custom: {\n 'plugin-import-export': {\n collectionSlugs,\n },\n },\n disableCopyToLocale: true,\n group: false,\n useAsTitle: 'filename',\n },\n disableDuplicate: true,\n endpoints: [\n {\n handler: handlePreview,\n method: 'post',\n path: '/preview-data',\n },\n ],\n fields: getFields({ collectionSlugs }),\n hooks: {\n afterChange,\n beforeOperation,\n },\n lockDocuments: false,\n upload: {\n filesRequiredOnCreate: true,\n hideFileInputOnCreate: false,\n hideRemoveFile: true,\n mimeTypes: ['text/csv', 'application/json'],\n },\n }\n\n if (disableJobsQueue) {\n // Process the import synchronously after the document (with file) has been created\n afterChange.push(async ({ collection: collectionConfig, doc, operation, req }) => {\n if (operation !== 'create' || doc.status !== 'pending') {\n return doc\n }\n\n const debug = pluginConfig.debug || false\n\n try {\n // Get file data from the uploaded document\n // First try req.file which is available during the same request (especially important for cloud storage)\n // Fall back to getFileFromDoc for cases where req.file isn't available\n let fileData: Buffer\n let fileMimetype: string\n\n if (req.file?.data) {\n fileData = req.file.data\n fileMimetype = req.file.mimetype || doc.mimeType\n\n if (!fileMimetype) {\n throw new FileRetrievalError(\n req.t,\n `Unable to determine mimetype for file: ${doc.filename}`,\n )\n }\n } else {\n const fileFromDoc = await getFileFromDoc({\n collectionConfig,\n doc: {\n filename: doc.filename,\n mimeType: doc.mimeType,\n url: doc.url,\n },\n req,\n })\n fileData = fileFromDoc.data\n fileMimetype = fileFromDoc.mimetype\n }\n\n const targetCollection = req.payload.collections[doc.collectionSlug]\n const importLimitConfig: Limit | undefined =\n targetCollection?.config.custom?.['plugin-import-export']?.importLimit\n const maxLimit = await resolveLimit({\n limit: importLimitConfig,\n req,\n })\n\n const result = await createImport({\n id: doc.id,\n name: doc.filename || 'import',\n batchSize,\n collectionSlug: doc.collectionSlug,\n debug,\n defaultVersionStatus,\n file: {\n name: doc.filename,\n data: fileData,\n mimetype: fileMimetype,\n },\n format: fileMimetype === 'text/csv' ? 'csv' : 'json',\n importMode: doc.importMode || 'create',\n matchField: doc.matchField,\n maxLimit,\n req,\n userCollection: req?.user?.collection || req?.user?.user?.collection,\n userID: req?.user?.id || req?.user?.user?.id,\n })\n\n // Determine status\n let status: 'completed' | 'failed' | 'partial'\n if (result.errors.length === 0) {\n status = 'completed'\n } else if (result.imported + result.updated === 0) {\n status = 'failed'\n } else {\n status = 'partial'\n }\n\n const summary = {\n imported: result.imported,\n issueDetails:\n result.errors.length > 0\n ? result.errors.map((e) => ({\n data: e.doc,\n error: e.error,\n row: e.index + 1,\n }))\n : undefined,\n issues: result.errors.length,\n total: result.total,\n updated: result.updated,\n }\n\n // Try to update the document with results (may fail due to transaction timing)\n try {\n await req.payload.update({\n id: doc.id,\n collection: collectionConfig.slug,\n data: {\n status,\n summary,\n },\n overrideAccess: true,\n req,\n })\n } catch (updateErr) {\n // Update may fail if document not yet committed, log but continue\n if (debug) {\n req.payload.logger.error({\n err: updateErr,\n msg: `Failed to update import document ${doc.id} with results`,\n })\n }\n }\n\n // Return updated doc for immediate response\n return {\n ...doc,\n status,\n summary,\n }\n } catch (err) {\n const summary = {\n imported: 0,\n issueDetails: [\n {\n data: {},\n error: err instanceof Error ? err.message : String(err),\n row: 0,\n },\n ],\n issues: 1,\n total: 0,\n updated: 0,\n }\n\n // Try to update document with error status\n try {\n await req.payload.update({\n id: doc.id,\n collection: collectionConfig.slug,\n data: {\n status: 'failed',\n summary,\n },\n overrideAccess: true,\n req,\n })\n } catch (updateErr) {\n // Update may fail if document not yet committed, log but continue\n if (debug) {\n req.payload.logger.error({\n err: updateErr,\n msg: `Failed to update import document ${doc.id} with error status`,\n })\n }\n }\n\n if (debug) {\n req.payload.logger.error({\n err,\n msg: 'Import processing failed',\n })\n }\n\n // Return error status for immediate response\n return {\n ...doc,\n status: 'failed',\n summary,\n }\n }\n })\n } else {\n // When jobs queue is enabled, queue the import as a job\n // The job handler will fetch the file from storage using getFileFromDoc\n afterChange.push(async ({ collection: collectionConfig, doc, operation, req }) => {\n if (operation !== 'create') {\n return\n }\n\n try {\n // Resolve maxLimit ahead of time since it may involve async config resolution\n const targetCollection = req.payload.collections[doc.collectionSlug]\n const importLimitConfig: Limit | undefined =\n targetCollection?.config.custom?.['plugin-import-export']?.importLimit\n const maxLimit = await resolveLimit({\n limit: importLimitConfig,\n req,\n })\n\n // Only pass minimal data to the job - the handler will fetch the file from storage\n const input: ImportTaskInput = {\n batchSize,\n debug: pluginConfig.debug,\n defaultVersionStatus,\n importCollection: collectionConfig.slug,\n importId: doc.id,\n maxLimit,\n userCollection: req.user?.collection || req?.user?.user?.collection,\n userID: req?.user?.id || req?.user?.user?.id,\n }\n\n await req.payload.jobs.queue({\n input,\n task: 'createCollectionImport',\n })\n } catch (err) {\n req.payload.logger.error({\n err,\n msg: `Failed to queue import job for document ${doc.id}`,\n })\n }\n })\n }\n\n return collection\n}\n"],"names":["FileRetrievalError","getFileFromDoc","resolveLimit","createImport","getFields","handlePreview","getImportCollection","collectionSlugs","importConfig","pluginConfig","beforeOperation","afterChange","disableJobsQueue","batchSize","defaultVersionStatus","collection","slug","access","update","admin","components","edit","SaveButton","custom","disableCopyToLocale","group","useAsTitle","disableDuplicate","endpoints","handler","method","path","fields","hooks","lockDocuments","upload","filesRequiredOnCreate","hideFileInputOnCreate","hideRemoveFile","mimeTypes","push","collectionConfig","doc","operation","req","status","debug","fileData","fileMimetype","file","data","mimetype","mimeType","t","filename","fileFromDoc","url","targetCollection","payload","collections","collectionSlug","importLimitConfig","config","importLimit","maxLimit","limit","result","id","name","format","importMode","matchField","userCollection","user","userID","errors","length","imported","updated","summary","issueDetails","map","e","error","row","index","undefined","issues","total","overrideAccess","updateErr","logger","err","msg","Error","message","String","input","importCollection","importId","jobs","queue","task"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/import/getImportCollection.ts"],"sourcesContent":["import type { CollectionAfterChangeHook, CollectionConfig } from 'payload'\n\nimport { FileRetrievalError } from 'payload'\n\nimport type { ImportConfig, ImportExportPluginConfig } from '../types.js'\nimport type { ImportTaskInput } from './getCreateImportCollectionTask.js'\n\nimport { getFileFromDoc } from '../utilities/getFileFromDoc.js'\nimport { resolveLimit } from '../utilities/resolveLimit.js'\nimport { createImport } from './createImport.js'\nimport { getFields } from './getFields.js'\nimport { handlePreview } from './handlePreview.js'\n\nconst FALLBACK_BATCH_SIZE = 100\nconst FALLBACK_VERSION_STATUS = 'published'\n\nexport const getImportCollection = ({\n collectionSlugs,\n importConfig,\n pluginConfig,\n}: {\n /**\n * Collection slugs that this import collection supports.\n */\n collectionSlugs: string[]\n importConfig?: ImportConfig\n pluginConfig: ImportExportPluginConfig\n}): CollectionConfig => {\n const afterChange: CollectionAfterChangeHook[] = []\n\n const collection: CollectionConfig = {\n slug: 'imports',\n access: {\n update: () => false,\n },\n admin: {\n components: {\n edit: {\n SaveButton: '@payloadcms/plugin-import-export/rsc#ImportSaveButton',\n },\n },\n custom: {\n 'plugin-import-export': {\n collectionSlugs,\n },\n },\n disableCopyToLocale: true,\n group: false,\n useAsTitle: 'filename',\n },\n disableDuplicate: true,\n endpoints: [\n {\n handler: handlePreview,\n method: 'post',\n path: '/preview-data',\n },\n ],\n fields: getFields({ collectionSlugs }),\n hooks: {\n afterChange,\n },\n lockDocuments: false,\n upload: {\n filesRequiredOnCreate: true,\n hideFileInputOnCreate: false,\n hideRemoveFile: true,\n mimeTypes: ['text/csv', 'application/json'],\n },\n }\n\n afterChange.push(async ({ collection: collectionConfig, doc, operation, req }) => {\n if (operation !== 'create' || doc.status !== 'pending') {\n return doc\n }\n\n const targetCollection = req.payload.collections[doc.collectionSlug]\n const targetPluginConfig = targetCollection?.config.custom?.['plugin-import-export']\n\n const disableJobsQueue =\n targetPluginConfig?.importDisableJobsQueue ?? importConfig?.disableJobsQueue ?? false\n\n const debug = pluginConfig.debug || false\n\n if (debug) {\n req.payload.logger.info({\n collectionSlug: doc.collectionSlug,\n disableJobsQueue,\n docId: doc.id,\n msg: '[Import Sync Hook] Starting',\n transactionID: req.transactionID,\n })\n }\n\n if (!disableJobsQueue) {\n return doc\n }\n\n try {\n // Get file data from the uploaded document\n // First try req.file which is available during the same request (especially important for cloud storage)\n // Fall back to getFileFromDoc for cases where req.file isn't available\n let fileData: Buffer\n let fileMimetype: string\n\n if (req.file?.data) {\n fileData = req.file.data\n fileMimetype = req.file.mimetype || doc.mimeType\n\n if (!fileMimetype) {\n throw new FileRetrievalError(\n req.t,\n `Unable to determine mimetype for file: ${doc.filename}`,\n )\n }\n } else {\n const fileFromDoc = await getFileFromDoc({\n collectionConfig,\n doc: {\n filename: doc.filename,\n mimeType: doc.mimeType,\n url: doc.url,\n },\n req,\n })\n fileData = fileFromDoc.data\n fileMimetype = fileFromDoc.mimetype\n }\n\n const maxLimit = await resolveLimit({\n limit: targetPluginConfig?.importLimit,\n req,\n })\n const defaultVersionStatus =\n targetPluginConfig?.defaultVersionStatus ??\n importConfig?.defaultVersionStatus ??\n pluginConfig.defaultVersionStatus ??\n FALLBACK_VERSION_STATUS\n const batchSize =\n targetPluginConfig?.importBatchSize ??\n importConfig?.batchSize ??\n pluginConfig.batchSize ??\n FALLBACK_BATCH_SIZE\n\n const result = await createImport({\n id: doc.id,\n name: doc.filename || 'import',\n batchSize,\n collectionSlug: doc.collectionSlug,\n debug,\n defaultVersionStatus,\n file: {\n name: doc.filename,\n data: fileData,\n mimetype: fileMimetype,\n },\n format: fileMimetype === 'text/csv' ? 'csv' : 'json',\n importMode: doc.importMode || 'create',\n matchField: doc.matchField,\n maxLimit,\n req,\n userCollection: req?.user?.collection || req?.user?.user?.collection,\n userID: req?.user?.id || req?.user?.user?.id,\n })\n\n // Determine status\n let status: 'completed' | 'failed' | 'partial'\n if (result.errors.length === 0) {\n status = 'completed'\n } else if (result.imported + result.updated === 0) {\n status = 'failed'\n } else {\n status = 'partial'\n }\n\n const summary = {\n imported: result.imported,\n issueDetails:\n result.errors.length > 0\n ? result.errors.map((e) => ({\n data: e.doc,\n error: e.error,\n row: e.index + 1,\n }))\n : undefined,\n issues: result.errors.length,\n total: result.total,\n updated: result.updated,\n }\n\n // Try to update the document with results\n try {\n await req.payload.update({\n id: doc.id,\n collection: collectionConfig.slug,\n data: {\n status,\n summary,\n },\n overrideAccess: true,\n req,\n })\n } catch (updateErr) {\n // Update may fail if document not yet committed\n if (debug) {\n req.payload.logger.error({\n err: updateErr,\n msg: `Failed to update import document ${doc.id} with results`,\n })\n }\n }\n\n // Return updated doc for immediate response\n return {\n ...doc,\n status,\n summary,\n }\n } catch (err) {\n const summary = {\n imported: 0,\n issueDetails: [\n {\n data: {},\n error: err instanceof Error ? err.message : String(err),\n row: 0,\n },\n ],\n issues: 1,\n total: 0,\n updated: 0,\n }\n\n if (debug) {\n req.payload.logger.error({\n docId: doc.id,\n err,\n msg: '[Import Sync Hook] Import processing failed, attempting to update status',\n transactionID: req.transactionID,\n })\n }\n\n // Try to update document with error status\n try {\n if (debug) {\n req.payload.logger.info({\n collectionSlug: collectionConfig.slug,\n docId: doc.id,\n msg: '[Import Sync Hook] About to update document with failed status',\n })\n }\n await req.payload.update({\n id: doc.id,\n collection: collectionConfig.slug,\n data: {\n status: 'failed',\n summary,\n },\n overrideAccess: true,\n req,\n })\n if (debug) {\n req.payload.logger.info({\n docId: doc.id,\n msg: '[Import Sync Hook] Successfully updated document with failed status',\n })\n }\n } catch (updateErr) {\n // Update may fail if document not yet committed, log but continue\n // ALWAYS log this error to help debug Postgres issues\n req.payload.logger.error({\n err: updateErr,\n msg: `[Import Sync Hook] Failed to update import document ${doc.id} with error status`,\n transactionID: req.transactionID,\n })\n }\n\n if (debug) {\n req.payload.logger.info({\n docId: doc.id,\n msg: '[Import Sync Hook] Returning failed doc',\n status: 'failed',\n })\n }\n\n // Return error status for immediate response\n return {\n ...doc,\n status: 'failed',\n summary,\n }\n }\n })\n\n afterChange.push(async ({ collection: collectionConfig, doc, operation, req }) => {\n if (operation !== 'create') {\n return\n }\n\n const targetCollection = req.payload.collections[doc.collectionSlug]\n const targetPluginConfig = targetCollection?.config.custom?.['plugin-import-export']\n\n const disableJobsQueue =\n targetPluginConfig?.importDisableJobsQueue ?? importConfig?.disableJobsQueue ?? false\n\n if (pluginConfig.debug) {\n req.payload.logger.info({\n collectionSlug: doc.collectionSlug,\n disableJobsQueue,\n docId: doc.id,\n docStatus: doc.status,\n msg: '[Import Job Hook] Checking if should queue job',\n transactionID: req.transactionID,\n })\n }\n\n if (disableJobsQueue) {\n if (pluginConfig.debug) {\n req.payload.logger.info({\n docId: doc.id,\n msg: '[Import Job Hook] Skipping job queue (sync mode)',\n })\n }\n return\n }\n\n try {\n // Resolve maxLimit ahead of time since it may involve async config resolution\n const maxLimit = await resolveLimit({\n limit: targetPluginConfig?.importLimit,\n req,\n })\n const defaultVersionStatus =\n targetPluginConfig?.defaultVersionStatus ??\n importConfig?.defaultVersionStatus ??\n pluginConfig.defaultVersionStatus ??\n FALLBACK_VERSION_STATUS\n const batchSize =\n targetPluginConfig?.importBatchSize ??\n importConfig?.batchSize ??\n pluginConfig.batchSize ??\n FALLBACK_BATCH_SIZE\n\n const input: ImportTaskInput = {\n batchSize,\n debug: pluginConfig.debug,\n defaultVersionStatus,\n importCollection: collectionConfig.slug,\n importId: doc.id,\n maxLimit,\n userCollection: req.user?.collection || req?.user?.user?.collection,\n userID: req?.user?.id || req?.user?.user?.id,\n }\n\n await req.payload.jobs.queue({\n input,\n task: 'createCollectionImport',\n })\n } catch (err) {\n req.payload.logger.error({\n err,\n msg: `Failed to queue import job for document ${doc.id}`,\n })\n }\n })\n\n return collection\n}\n"],"names":["FileRetrievalError","getFileFromDoc","resolveLimit","createImport","getFields","handlePreview","FALLBACK_BATCH_SIZE","FALLBACK_VERSION_STATUS","getImportCollection","collectionSlugs","importConfig","pluginConfig","afterChange","collection","slug","access","update","admin","components","edit","SaveButton","custom","disableCopyToLocale","group","useAsTitle","disableDuplicate","endpoints","handler","method","path","fields","hooks","lockDocuments","upload","filesRequiredOnCreate","hideFileInputOnCreate","hideRemoveFile","mimeTypes","push","collectionConfig","doc","operation","req","status","targetCollection","payload","collections","collectionSlug","targetPluginConfig","config","disableJobsQueue","importDisableJobsQueue","debug","logger","info","docId","id","msg","transactionID","fileData","fileMimetype","file","data","mimetype","mimeType","t","filename","fileFromDoc","url","maxLimit","limit","importLimit","defaultVersionStatus","batchSize","importBatchSize","result","name","format","importMode","matchField","userCollection","user","userID","errors","length","imported","updated","summary","issueDetails","map","e","error","row","index","undefined","issues","total","overrideAccess","updateErr","err","Error","message","String","docStatus","input","importCollection","importId","jobs","queue","task"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -31,6 +31,14 @@ declare module 'payload' {
|
|
|
31
31
|
* These paths are collected from fields marked with `custom['plugin-import-export'].disabled = true`.
|
|
32
32
|
*/
|
|
33
33
|
disabledFields?: string[];
|
|
34
|
+
/**
|
|
35
|
+
* If true, disables the download button in the export preview UI.
|
|
36
|
+
*/
|
|
37
|
+
disableDownload?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* If true, disables the save button in the export preview UI.
|
|
40
|
+
*/
|
|
41
|
+
disableSave?: boolean;
|
|
34
42
|
/**
|
|
35
43
|
* When set, forces exports from this collection to use this format.
|
|
36
44
|
* This value is read from the plugin config's `export.format` option.
|
|
@@ -40,12 +48,38 @@ declare module 'payload' {
|
|
|
40
48
|
}
|
|
41
49
|
interface CollectionCustom {
|
|
42
50
|
'plugin-import-export'?: {
|
|
51
|
+
/**
|
|
52
|
+
* Default version status for imported documents when _status field is not provided.
|
|
53
|
+
* Only applies to collections with versions enabled.
|
|
54
|
+
* @default 'published'
|
|
55
|
+
*/
|
|
56
|
+
defaultVersionStatus?: 'draft' | 'published';
|
|
57
|
+
/**
|
|
58
|
+
* Number of documents to process in each batch during export.
|
|
59
|
+
* @default 100
|
|
60
|
+
*/
|
|
61
|
+
exportBatchSize?: number;
|
|
62
|
+
/**
|
|
63
|
+
* If true, disables the jobs queue for exports and runs them synchronously.
|
|
64
|
+
* @default false
|
|
65
|
+
*/
|
|
66
|
+
exportDisableJobsQueue?: boolean;
|
|
43
67
|
/**
|
|
44
68
|
* Maximum number of documents that can be exported from this collection.
|
|
45
69
|
* Set to 0 for unlimited (default). Can be a number or function.
|
|
46
70
|
* Stored in collection.custom (server-only) since functions cannot be serialized to client.
|
|
47
71
|
*/
|
|
48
72
|
exportLimit?: Limit;
|
|
73
|
+
/**
|
|
74
|
+
* Number of documents to process in each batch during import.
|
|
75
|
+
* @default 100
|
|
76
|
+
*/
|
|
77
|
+
importBatchSize?: number;
|
|
78
|
+
/**
|
|
79
|
+
* If true, disables the jobs queue for imports and runs them synchronously.
|
|
80
|
+
* @default false
|
|
81
|
+
*/
|
|
82
|
+
importDisableJobsQueue?: boolean;
|
|
49
83
|
/**
|
|
50
84
|
* Maximum number of documents that can be imported to this collection.
|
|
51
85
|
* Set to 0 for unlimited (default). Can be a number or function.
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAKrC,OAAO,KAAK,EACV,eAAe,EACf,wBAAwB,EACxB,KAAK,EAEL,aAAa,EACd,MAAM,YAAY,CAAA;AAQnB,eAAO,MAAM,kBAAkB,iBACd,wBAAwB,cACxB,MAAM,KAAG,OAAO,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAKrC,OAAO,KAAK,EACV,eAAe,EACf,wBAAwB,EACxB,KAAK,EAEL,aAAa,EACd,MAAM,YAAY,CAAA;AAQnB,eAAO,MAAM,kBAAkB,iBACd,wBAAwB,cACxB,MAAM,KAAG,OAAO,CAAC,MAAM,CA4LrC,CAAA;AAEH,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAiB,WAAW;QAC1B,sBAAsB,CAAC,EAAE;YACvB;;;;;;eAMG;YACH,QAAQ,CAAC,EAAE,OAAO,CAAA;YAClB,OAAO,CAAC,EAAE,eAAe,CAAA;YACzB;;eAEG;YACH,KAAK,CAAC,EAAE,aAAa,CAAA;SACtB,CAAA;KACF;IAED,UAAiB,qBAAqB;QACpC,sBAAsB,CAAC,EAAE;YACvB;;;eAGG;YACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;YAC1B;;;eAGG;YACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAA;YACzB;;eAEG;YACH,eAAe,CAAC,EAAE,OAAO,CAAA;YACzB;;eAEG;YACH,WAAW,CAAC,EAAE,OAAO,CAAA;YACrB;;;eAGG;YACH,YAAY,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;SAC9B,CAAA;KACF;IAED,UAAiB,gBAAgB;QAC/B,sBAAsB,CAAC,EAAE;YACvB;;;;eAIG;YACH,oBAAoB,CAAC,EAAE,OAAO,GAAG,WAAW,CAAA;YAC5C;;;eAGG;YACH,eAAe,CAAC,EAAE,MAAM,CAAA;YACxB;;;eAGG;YACH,sBAAsB,CAAC,EAAE,OAAO,CAAA;YAChC;;;;eAIG;YACH,WAAW,CAAC,EAAE,KAAK,CAAA;YACnB;;;eAGG;YACH,eAAe,CAAC,EAAE,MAAM,CAAA;YACxB;;;eAGG;YACH,sBAAsB,CAAC,EAAE,OAAO,CAAA;YAChC;;;;eAIG;YACH,WAAW,CAAC,EAAE,KAAK,CAAA;SACpB,CAAA;KACF;CACF"}
|