@uploadcare/file-uploader 1.22.0 → 1.23.1

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 (114) hide show
  1. package/abstract/UploaderBlock.d.ts.map +1 -1
  2. package/abstract/UploaderBlock.js +27 -5
  3. package/abstract/UploaderPublicApi.d.ts.map +1 -1
  4. package/abstract/UploaderPublicApi.js +9 -1
  5. package/abstract/managers/ValidationManager.d.ts +71 -12
  6. package/abstract/managers/ValidationManager.d.ts.map +1 -1
  7. package/abstract/managers/ValidationManager.js +229 -53
  8. package/abstract/uploadEntrySchema.d.ts +10 -2
  9. package/abstract/uploadEntrySchema.d.ts.map +1 -1
  10. package/abstract/uploadEntrySchema.js +10 -2
  11. package/blocks/CloudImageEditor/src/CloudImageEditorBlock.js +1 -1
  12. package/blocks/Config/initialConfig.d.ts.map +1 -1
  13. package/blocks/Config/initialConfig.js +2 -0
  14. package/blocks/Config/normalizeConfigValue.d.ts.map +1 -1
  15. package/blocks/Config/normalizeConfigValue.js +2 -0
  16. package/blocks/ExternalSource/ExternalSource.d.ts +1 -0
  17. package/blocks/ExternalSource/ExternalSource.d.ts.map +1 -1
  18. package/blocks/ExternalSource/ExternalSource.js +19 -7
  19. package/blocks/FileItem/FileItem.d.ts +1 -1
  20. package/blocks/FileItem/FileItem.d.ts.map +1 -1
  21. package/blocks/FileItem/FileItem.js +68 -49
  22. package/blocks/UploadList/UploadList.d.ts +2 -0
  23. package/blocks/UploadList/UploadList.d.ts.map +1 -1
  24. package/blocks/UploadList/UploadList.js +18 -20
  25. package/env.d.ts +1 -1
  26. package/env.js +1 -1
  27. package/index.ssr.d.ts +1 -1
  28. package/index.ssr.d.ts.map +1 -1
  29. package/index.ssr.js +10 -2
  30. package/locales/file-uploader/ar.d.ts +3 -1
  31. package/locales/file-uploader/ar.js +4 -2
  32. package/locales/file-uploader/az.d.ts +3 -1
  33. package/locales/file-uploader/az.js +5 -2
  34. package/locales/file-uploader/ca.d.ts +3 -1
  35. package/locales/file-uploader/ca.js +5 -2
  36. package/locales/file-uploader/cs.d.ts +3 -1
  37. package/locales/file-uploader/cs.js +5 -2
  38. package/locales/file-uploader/da.d.ts +3 -1
  39. package/locales/file-uploader/da.js +5 -2
  40. package/locales/file-uploader/de.d.ts +3 -1
  41. package/locales/file-uploader/de.js +5 -2
  42. package/locales/file-uploader/el.d.ts +3 -1
  43. package/locales/file-uploader/el.js +5 -2
  44. package/locales/file-uploader/en.d.ts +3 -1
  45. package/locales/file-uploader/en.js +4 -2
  46. package/locales/file-uploader/es.d.ts +3 -1
  47. package/locales/file-uploader/es.js +5 -2
  48. package/locales/file-uploader/et.d.ts +3 -1
  49. package/locales/file-uploader/et.js +5 -2
  50. package/locales/file-uploader/fi.d.ts +3 -1
  51. package/locales/file-uploader/fi.js +5 -2
  52. package/locales/file-uploader/fr.d.ts +3 -1
  53. package/locales/file-uploader/fr.js +5 -2
  54. package/locales/file-uploader/he.d.ts +3 -1
  55. package/locales/file-uploader/he.js +5 -2
  56. package/locales/file-uploader/hy.d.ts +3 -1
  57. package/locales/file-uploader/hy.js +4 -2
  58. package/locales/file-uploader/is.d.ts +3 -1
  59. package/locales/file-uploader/is.js +5 -2
  60. package/locales/file-uploader/it.d.ts +3 -1
  61. package/locales/file-uploader/it.js +5 -2
  62. package/locales/file-uploader/ja.d.ts +3 -1
  63. package/locales/file-uploader/ja.js +5 -2
  64. package/locales/file-uploader/ka.d.ts +3 -1
  65. package/locales/file-uploader/ka.js +5 -2
  66. package/locales/file-uploader/kk.d.ts +3 -1
  67. package/locales/file-uploader/kk.js +5 -2
  68. package/locales/file-uploader/ko.d.ts +3 -1
  69. package/locales/file-uploader/ko.js +5 -2
  70. package/locales/file-uploader/lv.d.ts +3 -1
  71. package/locales/file-uploader/lv.js +5 -2
  72. package/locales/file-uploader/nb.d.ts +3 -1
  73. package/locales/file-uploader/nb.js +5 -2
  74. package/locales/file-uploader/nl.d.ts +3 -1
  75. package/locales/file-uploader/nl.js +5 -2
  76. package/locales/file-uploader/pl.d.ts +3 -1
  77. package/locales/file-uploader/pl.js +5 -2
  78. package/locales/file-uploader/pt.d.ts +3 -1
  79. package/locales/file-uploader/pt.js +5 -2
  80. package/locales/file-uploader/ro.d.ts +3 -1
  81. package/locales/file-uploader/ro.js +5 -2
  82. package/locales/file-uploader/ru.d.ts +3 -1
  83. package/locales/file-uploader/ru.js +5 -2
  84. package/locales/file-uploader/sk.d.ts +3 -1
  85. package/locales/file-uploader/sk.js +5 -2
  86. package/locales/file-uploader/sr.d.ts +3 -1
  87. package/locales/file-uploader/sr.js +5 -2
  88. package/locales/file-uploader/sv.d.ts +3 -1
  89. package/locales/file-uploader/sv.js +5 -2
  90. package/locales/file-uploader/tr.d.ts +3 -1
  91. package/locales/file-uploader/tr.js +5 -2
  92. package/locales/file-uploader/uk.d.ts +3 -1
  93. package/locales/file-uploader/uk.js +5 -2
  94. package/locales/file-uploader/vi.d.ts +3 -1
  95. package/locales/file-uploader/vi.js +5 -2
  96. package/locales/file-uploader/zh-TW.d.ts +3 -1
  97. package/locales/file-uploader/zh-TW.js +5 -2
  98. package/locales/file-uploader/zh.d.ts +3 -1
  99. package/locales/file-uploader/zh.js +5 -2
  100. package/package.json +8 -8
  101. package/types/exported.d.ts +26 -4
  102. package/utils/withResolvers.d.ts +6 -0
  103. package/utils/withResolvers.d.ts.map +1 -0
  104. package/utils/withResolvers.js +18 -0
  105. package/utils/withResolvers.test.d.ts +2 -0
  106. package/utils/withResolvers.test.d.ts.map +1 -0
  107. package/utils/withResolvers.test.js +36 -0
  108. package/web/file-uploader.iife.min.js +4 -4
  109. package/web/file-uploader.min.js +4 -4
  110. package/web/uc-cloud-image-editor.min.js +4 -4
  111. package/web/uc-file-uploader-inline.min.js +4 -4
  112. package/web/uc-file-uploader-minimal.min.js +4 -4
  113. package/web/uc-file-uploader-regular.min.js +4 -4
  114. package/web/uc-img.min.js +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"UploaderBlock.d.ts","sourceRoot":"","sources":["UploaderBlock.js"],"names":[],"mappings":"AAmBA;IACE,iBAAiB;IACjB,mCAAwB;IAExB,eAAe;IACf,mBAAmB;IAEnB;;;;;;;;;;;;;;MAA+B;IAE/B,eAAe;IACf,0BAOC;IA2BD;;;OAGG;IACH,mCAHa,iBAAiB,CAQ7B;IAED,mCAAmC;IACnC,WADc,iBAAiB,CAM9B;IAED,4BAEC;IAED,2DAA2D;IAC3D,wBADc,eAAe,CAAC,OAAO,iBAAiB,CAAC,CAMtD;IAgCD,eAAe;IACf,sBAYC;IAED,eAAe;IACf,iCAUC;IAPC,eAAe;IACf,6BAAiG;IAEjG,eAAe;IACf,uCAEC;IAGH,eAAe;IACf,mCAMC;IAED;;;OAGG;IACH,qBAkBC;IAED,eAAe;IACf,0BAYQ;IAER;;;OAGG;IACH,gCAkCE;IAEF;;;OAGG;IACH,0CA6FE;IAEF,eAAe;IACf,mCAsBE;IAEF,6BAiBC;IAED,eAAe;IACf,uBAyDC;IAED;;;OAGG;IACH,kCAHW,MAAM,qEAWhB;IAED;;;OAGG;IACH,oCAHa,OAAO,CAAC,OAAO,2BAA2B,EAAE,eAAe,CAAC,CA4BxE;IAED,kEAAkE;IAClE,iBADc,OAAO,sBAAsB,EAAE,eAAe,EAAE,CAK7D;CACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8BA7e6B,oBAAoB;qCAWb,oCAAoC;kCAGvC,iCAAiC;kCADjC,wBAAwB;gCAD1B,sBAAsB;kCAGpB,wBAAwB"}
1
+ {"version":3,"file":"UploaderBlock.d.ts","sourceRoot":"","sources":["UploaderBlock.js"],"names":[],"mappings":"AAmBA;IACE,iBAAiB;IACjB,mCAAwB;IAExB,eAAe;IACf,mBAAmB;IAEnB;;;;;;;;;;;;;;MAA+B;IAE/B,eAAe;IACf,0BAOC;IAmCD;;;OAGG;IACH,mCAHa,iBAAiB,CAQ7B;IAED,mCAAmC;IACnC,WADc,iBAAiB,CAM9B;IAED,4BAEC;IAED,2DAA2D;IAC3D,wBADc,eAAe,CAAC,OAAO,iBAAiB,CAAC,CAMtD;IAgCD,eAAe;IACf,sBAYC;IAED,eAAe;IACf,iCAUC;IAPC,eAAe;IACf,6BAAiG;IAEjG,eAAe;IACf,uCAEC;IAGH,eAAe;IACf,mCAMC;IAED;;;OAGG;IACH,qBAkBC;IAED,eAAe;IACf,0BAYQ;IAER;;;OAGG;IACH,gCAwCE;IAEF;;;OAGG;IACH,0CAqGE;IAEF,eAAe;IACf,mCAsBE;IAEF,6BAiBC;IAED,eAAe;IACf,uBAyDC;IAED;;;OAGG;IACH,kCAHW,MAAM,qEAWhB;IAED;;;OAGG;IACH,oCAHa,OAAO,CAAC,OAAO,2BAA2B,EAAE,eAAe,CAAC,CA4BxE;IAED,kEAAkE;IAClE,iBADc,OAAO,sBAAsB,EAAE,eAAe,EAAE,CAK7D;CACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8BAngB6B,oBAAoB;qCAWb,oCAAoC;kCAGvC,iCAAiC;kCADjC,wBAAwB;gCAD1B,sBAAsB;kCAGpB,wBAAwB"}
@@ -43,7 +43,15 @@ export class UploaderBlock extends ActivityBlock {
43
43
  if (!this.has('*uploadCollection')) {
44
44
  let uploadCollection = new TypedCollection({
45
45
  typedSchema: uploadEntrySchema,
46
- watchList: ['uploadProgress', 'uploadError', 'fileInfo', 'errors', 'cdnUrl', 'isUploading'],
46
+ watchList: [
47
+ 'uploadProgress',
48
+ 'uploadError',
49
+ 'fileInfo',
50
+ 'errors',
51
+ 'cdnUrl',
52
+ 'isUploading',
53
+ 'isValidationPending',
54
+ ],
47
55
  });
48
56
  this.add('*uploadCollection', uploadCollection);
49
57
  }
@@ -206,8 +214,11 @@ export class UploaderBlock extends ActivityBlock {
206
214
  if (added.size || removed.size) {
207
215
  this.$['*groupInfo'] = null;
208
216
  }
209
- this.validationManager.runFileValidators();
210
- this.validationManager.runCollectionValidators();
217
+
218
+ this.validationManager.runFileValidators(
219
+ 'add',
220
+ [...added].map((e) => e.uid),
221
+ );
211
222
 
212
223
  for (const entry of added) {
213
224
  if (!entry.getValue('silent')) {
@@ -215,9 +226,12 @@ export class UploaderBlock extends ActivityBlock {
215
226
  }
216
227
  }
217
228
 
229
+ this.validationManager.runCollectionValidators();
230
+
218
231
  for (const entry of removed) {
219
232
  /** @type {Set<string>} */ (this.$['*uploadTrigger']).delete(entry.uid);
220
233
 
234
+ this.validationManager.cleanupValidationForEntry(entry);
221
235
  entry.getValue('abortController')?.abort();
222
236
  entry.setMultipleValues({
223
237
  isRemoved: true,
@@ -249,7 +263,7 @@ export class UploaderBlock extends ActivityBlock {
249
263
  const entriesToRunValidation = [
250
264
  ...new Set(
251
265
  Object.entries(changeMap)
252
- .filter(([key]) => ['uploadError', 'fileInfo'].includes(key))
266
+ .filter(([key]) => ['uploadError', 'fileInfo', 'cdnUrl', 'cdnUrlModifiers'].includes(key))
253
267
  .map(([, ids]) => [...ids])
254
268
  .flat(),
255
269
  ),
@@ -258,7 +272,13 @@ export class UploaderBlock extends ActivityBlock {
258
272
  entriesToRunValidation.length > 0 &&
259
273
  setTimeout(() => {
260
274
  // We can't modify entry properties in the same tick, so we need to wait a bit
261
- this.validationManager.runFileValidators(entriesToRunValidation);
275
+ const entriesToRunOnUpload = entriesToRunValidation.filter(
276
+ (entryId) => changeMap.fileInfo?.has(entryId) && !!Data.getCtx(entryId).store.fileInfo,
277
+ );
278
+ if (entriesToRunOnUpload.length > 0) {
279
+ this.validationManager.runFileValidators('upload', entriesToRunOnUpload);
280
+ }
281
+ this.validationManager.runFileValidators('change', entriesToRunValidation);
262
282
  });
263
283
 
264
284
  if (changeMap.uploadProgress) {
@@ -295,6 +315,8 @@ export class UploaderBlock extends ActivityBlock {
295
315
  }
296
316
  }
297
317
  if (changeMap.errors) {
318
+ this.validationManager.runCollectionValidators();
319
+
298
320
  for (const entryId of changeMap.errors) {
299
321
  const { errors } = Data.getCtx(entryId).store;
300
322
  if (errors.length > 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"UploaderPublicApi.d.ts","sourceRoot":"","sources":["UploaderPublicApi.js"],"names":[],"mappings":"AAqBA;IAOE,8DAA8D;IAC9D,iBADY,OAAO,oBAAoB,EAAE,aAAa,EAGrD;IATD;;;OAGG;IACH,aAAK;IAOL,eAAe;IACf,gCAEC;IAED,yCAEC;IAED;;iBAEC;IAED;;;;;;OAMG;IACH,iBAAkB,KAJP,MAIU,EAAE,+BAHZ;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAGT,KAF3C,OAAO,UAAU,EAAE,eAAe,CAAC,MAAM,CAAC,CAUrD;IAEF;;;;OAIG;IACH,kBAAmB,MAJR,MAIY,EAAE,+BAHd;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAGP,KAF7C,OAAO,UAAU,EAAE,eAAe,CAAC,MAAM,CAAC,CAUrD;IAEF;;;;OAIG;IACH,oBAAqB,QAJV,MAIgB,EAAE,+BAHlB;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAGH,KAFjD,OAAO,UAAU,EAAE,eAAe,CAAC,MAAM,CAAC,CAgBrD;IAEF;;;;OAIG;IACH,oBAAqB,MAJV,IAIc,EAAE,yCAHhB;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAGd,KAFzD,OAAO,UAAU,EAAE,eAAe,CAAC,MAAM,CAAC,CAcrD;IAEF,iCAAiC;IACjC,yBAA0B,YADd,MACwB,UAKlC;IAEF,uBAEC;IAED,sBAgBE;IAEF,8HAA8H;IAC9H,mBAAoB,UADR;QAAE,aAAa,CAAC,EAAE,OAAO,CAAC;QAAC,UAAU,CAAC,EAAE,OAAO,qCAAqC,EAAE,cAAc,CAAA;KAChF,UA6D9B;IAEF;;;;OAIG;IACH,cAJmD,OAAO,SAA7C,OAAQ,UAAU,EAAE,gBAAiB,WACvC,MAAM,GACJ,OAAO,sBAAsB,EAAE,eAAe,CAAC,OAAO,CAAC,CA+CnE;IAED,oEAAoE;IACpE,yBAD0D,OAAO,SAAnD,OAAQ,UAAU,EAAE,sBAAuB,KAErC,UAAU,CAAC,OAAO,0BAA0B,CAAC,OAAO,CAAC,CAAC,CAGzE;IAED,+BAA+B;IAC/B,WAAY,eAAa,UA6DvB;IAEF,qBAQE;IAEF;;;;;;;;;OASG;IACH,oBATU,CAAC,CAAC,SAAS,OAAO,oBAAoB,EAAE,YAAY,EACzD,YAAY,EAAE,CAAC,EACnB,GAAO,MAAM,EAAE,CAAC,SAAS,MAAM,OAAO,oBAAoB,EAAE,iBAAiB,GACrE,CAAC,OAAO,oBAAoB,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC,GACnD,CAAC,SAAS,OAAO,oBAAoB,EAAE,sBAAsB,GAC3D,CAAC,SAAS,CAAC,CAAC,GACZ,CAAC,GAAG,CAAC,CAAC,KACT,IAAI,CAWV;IAEF,2DAA2D;IAC3D,0BADc,OAAO,oBAAoB,EAAE,YAAY,CAGrD;IAEF,8BAA8B;IAC9B,gBAAiB,QADL,OACW,UAYrB;IAEF;;;OAGG;IACH,0BAOC;CACF;2CA3X0C,iCAAiC"}
1
+ {"version":3,"file":"UploaderPublicApi.d.ts","sourceRoot":"","sources":["UploaderPublicApi.js"],"names":[],"mappings":"AAqBA;IAOE,8DAA8D;IAC9D,iBADY,OAAO,oBAAoB,EAAE,aAAa,EAGrD;IATD;;;OAGG;IACH,aAAK;IAOL,eAAe;IACf,gCAEC;IAED,yCAEC;IAED;;iBAEC;IAED;;;;;;OAMG;IACH,iBAAkB,KAJP,MAIU,EAAE,+BAHZ;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAGT,KAF3C,OAAO,UAAU,EAAE,eAAe,CAAC,MAAM,CAAC,CAUrD;IAEF;;;;OAIG;IACH,kBAAmB,MAJR,MAIY,EAAE,+BAHd;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAGP,KAF7C,OAAO,UAAU,EAAE,eAAe,CAAC,MAAM,CAAC,CAUrD;IAEF;;;;OAIG;IACH,oBAAqB,QAJV,MAIgB,EAAE,+BAHlB;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAGH,KAFjD,OAAO,UAAU,EAAE,eAAe,CAAC,MAAM,CAAC,CAgBrD;IAEF;;;;OAIG;IACH,oBAAqB,MAJV,IAIc,EAAE,yCAHhB;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAGd,KAFzD,OAAO,UAAU,EAAE,eAAe,CAAC,MAAM,CAAC,CAcrD;IAEF,iCAAiC;IACjC,yBAA0B,YADd,MACwB,UAKlC;IAEF,uBAEC;IAED,sBAuBE;IAEF,8HAA8H;IAC9H,mBAAoB,UADR;QAAE,aAAa,CAAC,EAAE,OAAO,CAAC;QAAC,UAAU,CAAC,EAAE,OAAO,qCAAqC,EAAE,cAAc,CAAA;KAChF,UA6D9B;IAEF;;;;OAIG;IACH,cAJmD,OAAO,SAA7C,OAAQ,UAAU,EAAE,gBAAiB,WACvC,MAAM,GACJ,OAAO,sBAAsB,EAAE,eAAe,CAAC,OAAO,CAAC,CAgDnE;IAED,oEAAoE;IACpE,yBAD0D,OAAO,SAAnD,OAAQ,UAAU,EAAE,sBAAuB,KAErC,UAAU,CAAC,OAAO,0BAA0B,CAAC,OAAO,CAAC,CAAC,CAGzE;IAED,+BAA+B;IAC/B,WAAY,eAAa,UA6DvB;IAEF,qBAQE;IAEF;;;;;;;;;OASG;IACH,oBATU,CAAC,CAAC,SAAS,OAAO,oBAAoB,EAAE,YAAY,EACzD,YAAY,EAAE,CAAC,EACnB,GAAO,MAAM,EAAE,CAAC,SAAS,MAAM,OAAO,oBAAoB,EAAE,iBAAiB,GACrE,CAAC,OAAO,oBAAoB,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC,GACnD,CAAC,SAAS,OAAO,oBAAoB,EAAE,sBAAsB,GAC3D,CAAC,SAAS,CAAC,CAAC,GACZ,CAAC,GAAG,CAAC,CAAC,KACT,IAAI,CAWV;IAEF,2DAA2D;IAC3D,0BADc,OAAO,oBAAoB,EAAE,YAAY,CAGrD;IAEF,8BAA8B;IAC9B,gBAAiB,QADL,OACW,UAYrB;IAEF;;;OAGG;IACH,0BAOC;CACF;2CAnY0C,iCAAiC"}
@@ -132,7 +132,14 @@ export class UploaderPublicApi {
132
132
  const itemsToUpload = this._uploadCollection.items().filter((id) => {
133
133
  const entry = this._uploadCollection.read(id);
134
134
  if (!entry) return false;
135
- return !entry.getValue('isRemoved') && !entry.getValue('isUploading') && !entry.getValue('fileInfo');
135
+ return (
136
+ !entry.getValue('isRemoved') &&
137
+ !entry.getValue('isUploading') &&
138
+ !entry.getValue('fileInfo') &&
139
+ entry.getValue('errors').length === 0 &&
140
+ !entry.getValue('isValidationPending') &&
141
+ !entry.getValue('isQueuedForValidation')
142
+ );
136
143
  });
137
144
 
138
145
  if (itemsToUpload.length === 0) {
@@ -254,6 +261,7 @@ export class UploaderPublicApi {
254
261
  isUploading: status === 'uploading',
255
262
  isFailed: status === 'failed',
256
263
  isRemoved: status === 'removed',
264
+ isValidationPending: uploadEntryData.isValidationPending,
257
265
  errors: /** @type {import('../types/exported.js').OutputFileEntry['errors']} */ (uploadEntryData.errors),
258
266
  status,
259
267
  source: uploadEntryData?.source,
@@ -7,9 +7,30 @@ export class ValidationManager {
7
7
  */
8
8
  private _blockInstance;
9
9
  /** @type {FuncFileValidator[]} */
10
- _fileValidators: FuncFileValidator[];
10
+ _commonFileValidators: FuncFileValidator[];
11
11
  /** @type {FuncCollectionValidator[]} */
12
- _collectionValidators: FuncCollectionValidator[];
12
+ _commonCollectionValidators: FuncCollectionValidator[];
13
+ _queue: Queue;
14
+ _runQueueDebounced: (() => void) & {
15
+ cancel: () => void;
16
+ };
17
+ /**
18
+ * @type {Map<
19
+ * string,
20
+ * {
21
+ * abortController?: AbortController;
22
+ * skippedValidators: WeakSet<FuncFileValidator>;
23
+ * promise?: Promise<void>;
24
+ * lastErrorThrownByValidator: WeakMap<FuncFileValidator, import('../../types').OutputErrorFile | undefined>;
25
+ * }
26
+ * >}
27
+ */
28
+ _entryValidationState: Map<string, {
29
+ abortController?: AbortController;
30
+ skippedValidators: WeakSet<FuncFileValidator>;
31
+ promise?: Promise<void>;
32
+ lastErrorThrownByValidator: WeakMap<FuncFileValidator, import("../../types").OutputErrorFile | undefined>;
33
+ }>;
13
34
  _uploadCollection: import("../TypedCollection.js").TypedCollection<Readonly<{
14
35
  file: Readonly<{
15
36
  type: {
@@ -114,7 +135,7 @@ export class ValidationManager {
114
135
  }>;
115
136
  errors: Readonly<{
116
137
  type: ArrayConstructor;
117
- value: Error[];
138
+ value: import("../../types").OutputErrorFile[];
118
139
  }>;
119
140
  uploadError: Readonly<{
120
141
  type: ErrorConstructor;
@@ -125,26 +146,64 @@ export class ValidationManager {
125
146
  type: BooleanConstructor;
126
147
  value: false;
127
148
  }>;
128
- isQueued: Readonly<{
149
+ isQueuedForUploading: Readonly<{
150
+ type: BooleanConstructor;
151
+ value: false;
152
+ }>;
153
+ isValidationPending: Readonly<{
154
+ type: BooleanConstructor;
155
+ value: false;
156
+ }>;
157
+ isQueuedForValidation: Readonly<{
129
158
  type: BooleanConstructor;
130
159
  value: false;
131
160
  }>;
132
161
  }>>;
133
- /** @param {string[]} [entryIds] */
134
- runFileValidators(entryIds?: string[]): void;
162
+ /**
163
+ * @param {FileValidatorDescriptor['runOn']} runOn
164
+ * @param {string[]} [entryIds]
165
+ */
166
+ runFileValidators(runOn: FileValidatorDescriptor["runOn"], entryIds?: string[]): void;
135
167
  runCollectionValidators(): void;
168
+ /** @param {import('../TypedData.js').TypedData<typeof import('../uploadEntrySchema.js').uploadEntrySchema>} entry */
169
+ cleanupValidationForEntry(entry: import("../TypedData.js").TypedData<typeof import("../uploadEntrySchema.js").uploadEntrySchema>): void;
136
170
  /**
137
171
  * @private
138
172
  * @param {import('../TypedData.js').TypedData<typeof import('../uploadEntrySchema.js').uploadEntrySchema>} entry
173
+ * @param {FileValidatorDescriptor['runOn']} runOn
139
174
  */
140
175
  private _runFileValidatorsForEntry;
141
176
  /**
142
- * @template T
143
- * @param {T[]} validators
144
- * @returns {T[]}
177
+ * @private
178
+ * @template {import('../../types').OutputError<
179
+ * import('../../types').OutputFileErrorType | import('../../types').OutputCollectionErrorType
180
+ * >} T
181
+ * @param {T} error
182
+ * @returns {T}
183
+ */
184
+ private _addCustomTypeToValidationError;
185
+ /**
186
+ * @private
187
+ * @param {import('../TypedData.js').TypedData<typeof import('../uploadEntrySchema.js').uploadEntrySchema>} entry
188
+ */
189
+ private _getEntryValidationState;
190
+ /** @private */
191
+ private _getValidatorDescriptors;
192
+ /**
193
+ * @private
194
+ * @param {import('../TypedData.js').TypedData<typeof import('../uploadEntrySchema.js').uploadEntrySchema>} entry
195
+ * @param {FileValidatorDescriptor['runOn']} runOn
145
196
  */
146
- _addCustomTypeToValidators<T>(validators: T[]): T[];
197
+ private _getValidatorDescriptorsForEntry;
147
198
  }
148
- export type FuncFileValidator = (outputEntry: import("../../types/index.js").OutputFileEntry, api: import("../UploaderPublicApi.js").UploaderPublicApi) => undefined | import("../../types/index.js").OutputErrorFile;
149
- export type FuncCollectionValidator = (collection: ReturnType<typeof import("../buildOutputCollectionState.js").buildOutputCollectionState<import("../../types/index.js").OutputCollectionStatus>>, api: import("../UploaderPublicApi.js").UploaderPublicApi) => undefined | import("../../types/index.js").OutputErrorCollection;
199
+ export type FuncFileValidator = (outputEntry: import("../../types").OutputFileEntry, api: import("../UploaderPublicApi.js").UploaderPublicApi, options?: {
200
+ signal?: AbortSignal;
201
+ }) => (undefined | import("../../types").OutputErrorFile) | Promise<undefined | import("../../types").OutputErrorFile>;
202
+ export type FileValidatorDescriptor = {
203
+ runOn: "add" | "upload" | "change";
204
+ validator: FuncFileValidator;
205
+ };
206
+ export type FileValidator = FileValidatorDescriptor | FuncFileValidator;
207
+ export type FuncCollectionValidator = (collection: ReturnType<typeof import("../buildOutputCollectionState.js").buildOutputCollectionState<import("../../types").OutputCollectionStatus>>, api: import("../UploaderPublicApi.js").UploaderPublicApi) => undefined | import("../../types").OutputErrorCollection;
208
+ import { Queue } from '@uploadcare/upload-client';
150
209
  //# sourceMappingURL=ValidationManager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ValidationManager.d.ts","sourceRoot":"","sources":["ValidationManager.js"],"names":[],"mappings":"AAkCA;IAaE,yEAAyE;IACzE,2BADY,OAAO,qBAAqB,EAAE,aAAa,EAiBtD;IA7BD;;;OAGG;IACH,uBAAe;IAEf,kCAAkC;IAClC,iBADW,iBAAiB,EAAE,CACmE;IAEjG,wCAAwC;IACxC,uBADW,uBAAuB,EAAE,CACsC;IAMxE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAA6D;IAe/D,mCAAmC;IACnC,6BADY,MAAM,EAAE,QASnB;IAED,gCAsCC;IAED;;;OAGG;IACH,mCA0BC;IAED;;;;OAIG;IACH,2BAJa,CAAC,cACH,CAAC,EAAE,GACD,CAAC,EAAE,CAUf;CACF;gCAxJY,CACR,WAAW,EAAE,OAAO,sBAAsB,EAAE,eAAe,EAC3D,GAAG,EAAE,OAAO,yBAAyB,EAAE,iBAAiB,KACrD,SAAS,GAAG,OAAO,sBAAsB,EAAE,eAAe;sCAIrD,CACR,UAAU,EAAE,UAAU,CAC1B,cAAoB,kCAAkC,EAAE,0BAA0B,CAClF,OAAe,sBAAsB,EAAE,sBAAsB,CACtD,CACF,EACD,GAAG,EAAE,OAAO,yBAAyB,EAAE,iBAAiB,KACrD,SAAS,GAAG,OAAO,sBAAsB,EAAE,qBAAqB"}
1
+ {"version":3,"file":"ValidationManager.d.ts","sourceRoot":"","sources":["ValidationManager.js"],"names":[],"mappings":"AA6DA;IA+BE,yEAAyE;IACzE,2BADY,OAAO,qBAAqB,EAAE,aAAa,EAqBtD;IAnDD;;;OAGG;IACH,uBAAe;IAEf,kCAAkC;IAClC,uBADW,iBAAiB,EAAE,CACyE;IAEvG,wCAAwC;IACxC,6BADW,uBAAuB,EAAE,CAC4C;IAEhF,cAAuB;IACvB;;MAEQ;IAER;;;;;;;;;;OAUG;IACH,uBAVU,GAAG,CACZ,MAAU,EACV;QACM,eAAe,CAAC,EAAE,eAAe,CAAC;QAClC,iBAAiB,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;QAC9C,OAAO,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QACxB,0BAA0B,EAAE,OAAO,CAAC,iBAAiB,EAAE,OAAO,aAAa,EAAE,eAAe,GAAG,SAAS,CAAC,CAAC;KAC3G,CACF,CAE8B;IAMhC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAA6D;IAmB/D;;;OAGG;IACH,yBAHW,uBAAuB,CAAC,OAAO,CAAC,aAChC,MAAM,EAAE,QAUlB;IAED,gCAkCC;IAED,qHAAqH;IACrH,iCADY,OAAO,iBAAiB,EAAE,SAAS,CAAC,cAAc,yBAAyB,EAAE,iBAAiB,CAAC,QAO1G;IAED;;;;OAIG;IACH,mCAyGC;IAED;;;;;;;OAOG;IACH,wCAKC;IAED;;;OAGG;IACH,iCAgBC;IAED,eAAe;IACf,iCAEC;IAED;;;;OAIG;IACH,yCAKC;CACF;gCArUY,CACR,WAAW,EAAE,OAAO,aAAa,EAAE,eAAe,EAClD,GAAG,EAAE,OAAO,yBAAyB,EAAE,iBAAiB,EACxD,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,WAAW,CAAA;CAAE,KAEhC,CAAC,SAAS,GAAG,OAAO,aAAa,EAAE,eAAe,CAAC,GACnD,OAAO,CAAC,SAAS,GAAG,OAAO,aAAa,EAAE,eAAe,CAAC;sCAIpD;IACR,KAAK,EAAE,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACnC,SAAS,EAAE,iBAAiB,CAAC;CAC9B;4BAGU,uBAAuB,GAAG,iBAAiB;sCAG5C,CACR,UAAU,EAAE,UAAU,CAC1B,cAAoB,kCAAkC,EAAE,0BAA0B,CAClF,OAAe,aAAa,EAAE,sBAAsB,CAC7C,CACF,EACD,GAAG,EAAE,OAAO,yBAAyB,EAAE,iBAAiB,KACrD,SAAS,GAAG,OAAO,aAAa,EAAE,qBAAqB;sBA/BzC,2BAA2B"}
@@ -7,29 +7,56 @@ import {
7
7
  validateUploadError,
8
8
  } from '../../utils/validators/file/index.js';
9
9
  import { validateMultiple, validateCollectionUploadError } from '../../utils/validators/collection/index.js';
10
+ import { Queue } from '@uploadcare/upload-client';
11
+ import { withResolvers } from '../../utils/withResolvers.js';
12
+ import { debounce } from '../../blocks/utils/debounce.js';
10
13
 
11
14
  /**
12
15
  * @typedef {(
13
- * outputEntry: import('../../types/index.js').OutputFileEntry,
16
+ * outputEntry: import('../../types').OutputFileEntry,
14
17
  * api: import('../UploaderPublicApi.js').UploaderPublicApi,
15
- * ) => undefined | import('../../types/index.js').OutputErrorFile} FuncFileValidator
18
+ * options?: { signal?: AbortSignal },
19
+ * ) =>
20
+ * | (undefined | import('../../types').OutputErrorFile)
21
+ * | Promise<undefined | import('../../types').OutputErrorFile>} FuncFileValidator
16
22
  */
17
23
 
24
+ /**
25
+ * @typedef {{
26
+ * runOn: 'add' | 'upload' | 'change';
27
+ * validator: FuncFileValidator;
28
+ * }} FileValidatorDescriptor
29
+ */
30
+
31
+ /** @typedef {FileValidatorDescriptor | FuncFileValidator} FileValidator */
32
+
18
33
  /**
19
34
  * @typedef {(
20
35
  * collection: ReturnType<
21
36
  * typeof import('../buildOutputCollectionState.js').buildOutputCollectionState<
22
- * import('../../types/index.js').OutputCollectionStatus
37
+ * import('../../types').OutputCollectionStatus
23
38
  * >
24
39
  * >,
25
40
  * api: import('../UploaderPublicApi.js').UploaderPublicApi,
26
- * ) => undefined | import('../../types/index.js').OutputErrorCollection} FuncCollectionValidator
41
+ * ) => undefined | import('../../types').OutputErrorCollection} FuncCollectionValidator
27
42
  */
28
43
 
29
- const LOGGER = {
30
- file: 'File validator execution has failed',
31
- collection: 'Collection validator execution has failed',
32
- message: 'Missing message. We recommend adding message: value.',
44
+ const LOG_TEXT = {
45
+ FILE_VALIDATION_FAILED: 'File validator execution has failed',
46
+ FILE_VALIDATION_TIMEOUT: 'File validator execution has timed out',
47
+ COLLECTION_VALIDATION_FAILED: 'Collection validator execution has failed',
48
+ MISSING_ERROR_MESSAGE: 'Missing message. We recommend adding message: value.',
49
+ };
50
+
51
+ /**
52
+ * @param {FileValidator} validator
53
+ * @returns {FileValidatorDescriptor}
54
+ */
55
+ const getValidatorDescriptor = (validator) => {
56
+ if (typeof validator === 'function') {
57
+ return { runOn: 'change', validator };
58
+ }
59
+ return validator;
33
60
  };
34
61
 
35
62
  export class ValidationManager {
@@ -40,10 +67,28 @@ export class ValidationManager {
40
67
  _blockInstance;
41
68
 
42
69
  /** @type {FuncFileValidator[]} */
43
- _fileValidators = [validateIsImage, validateFileType, validateMaxSizeLimit, validateUploadError];
70
+ _commonFileValidators = [validateIsImage, validateFileType, validateMaxSizeLimit, validateUploadError];
44
71
 
45
72
  /** @type {FuncCollectionValidator[]} */
46
- _collectionValidators = [validateMultiple, validateCollectionUploadError];
73
+ _commonCollectionValidators = [validateMultiple, validateCollectionUploadError];
74
+
75
+ _queue = new Queue(20);
76
+ _runQueueDebounced = debounce(() => {
77
+ this._queue.run();
78
+ }, 500);
79
+
80
+ /**
81
+ * @type {Map<
82
+ * string,
83
+ * {
84
+ * abortController?: AbortController;
85
+ * skippedValidators: WeakSet<FuncFileValidator>;
86
+ * promise?: Promise<void>;
87
+ * lastErrorThrownByValidator: WeakMap<FuncFileValidator, import('../../types').OutputErrorFile | undefined>;
88
+ * }
89
+ * >}
90
+ */
91
+ _entryValidationState = new Map();
47
92
 
48
93
  /** @param {import('../UploaderBlock.js').UploaderBlock} blockInstance */
49
94
  constructor(blockInstance) {
@@ -52,7 +97,7 @@ export class ValidationManager {
52
97
  this._uploadCollection = this._blockInstance.uploadCollection;
53
98
 
54
99
  const runAllValidators = () => {
55
- this.runFileValidators();
100
+ this.runFileValidators('change');
56
101
  this.runCollectionValidators();
57
102
  };
58
103
 
@@ -62,15 +107,22 @@ export class ValidationManager {
62
107
  this._blockInstance.subConfigValue('multiple', runAllValidators);
63
108
  this._blockInstance.subConfigValue('imgOnly', runAllValidators);
64
109
  this._blockInstance.subConfigValue('accept', runAllValidators);
110
+
111
+ this._blockInstance.subConfigValue('validationConcurrency', (concurrency) => {
112
+ this._queue.concurrency = concurrency;
113
+ });
65
114
  }
66
115
 
67
- /** @param {string[]} [entryIds] */
68
- runFileValidators(entryIds) {
116
+ /**
117
+ * @param {FileValidatorDescriptor['runOn']} runOn
118
+ * @param {string[]} [entryIds]
119
+ */
120
+ runFileValidators(runOn, entryIds) {
69
121
  const ids = entryIds ?? this._uploadCollection.items();
70
122
  for (const id of ids) {
71
123
  const entry = this._uploadCollection.read(id);
72
124
  if (entry) {
73
- this._runFileValidatorsForEntry(entry);
125
+ void this._runFileValidatorsForEntry(entry, runOn);
74
126
  }
75
127
  }
76
128
  }
@@ -79,25 +131,21 @@ export class ValidationManager {
79
131
  const collection = this._blockInstance.api.getOutputCollectionState();
80
132
  const errors = [];
81
133
 
82
- for (const validator of [
83
- ...this._collectionValidators,
84
- ...this._addCustomTypeToValidators(this._blockInstance.cfg.collectionValidators),
85
- ]) {
134
+ for (const validator of [...this._commonCollectionValidators, ...this._blockInstance.cfg.collectionValidators]) {
86
135
  try {
87
- const errorOrErrors = validator(collection, this._blockInstance.api);
88
- if (!errorOrErrors) {
136
+ const error = validator(collection, this._blockInstance.api);
137
+ if (!error) {
89
138
  continue;
90
139
  }
91
- if (errorOrErrors) {
92
- errors.push(errorOrErrors);
140
+ if (error) {
141
+ errors.push(this._addCustomTypeToValidationError(error));
93
142
 
94
- if (!errorOrErrors.message) {
95
- console.warn(LOGGER.message);
143
+ if (!error.message) {
144
+ console.warn(LOG_TEXT.MISSING_ERROR_MESSAGE);
96
145
  }
97
146
  }
98
147
  } catch (error) {
99
- console.warn(LOGGER.collection, error);
100
- this._blockInstance.telemetryManager.sendEventError(error, `collection validator. ${LOGGER.collection}`);
148
+ console.warn(LOG_TEXT.COLLECTION_VALIDATION_FAILED, error);
101
149
  }
102
150
  }
103
151
 
@@ -107,7 +155,7 @@ export class ValidationManager {
107
155
  this._blockInstance.emit(
108
156
  EventType.COMMON_UPLOAD_FAILED,
109
157
  () =>
110
- /** @type {import('../../types/index.js').OutputCollectionState<'failed'>} */ (
158
+ /** @type {import('../../types').OutputCollectionState<'failed'>} */ (
111
159
  this._blockInstance.api.getOutputCollectionState()
112
160
  ),
113
161
  { debounce: true },
@@ -115,50 +163,178 @@ export class ValidationManager {
115
163
  }
116
164
  }
117
165
 
166
+ /** @param {import('../TypedData.js').TypedData<typeof import('../uploadEntrySchema.js').uploadEntrySchema>} entry */
167
+ cleanupValidationForEntry(entry) {
168
+ const state = this._entryValidationState.get(entry.uid);
169
+ if (state) {
170
+ state.abortController?.abort();
171
+ this._entryValidationState.delete(entry.uid);
172
+ }
173
+ }
174
+
118
175
  /**
119
176
  * @private
120
177
  * @param {import('../TypedData.js').TypedData<typeof import('../uploadEntrySchema.js').uploadEntrySchema>} entry
178
+ * @param {FileValidatorDescriptor['runOn']} runOn
121
179
  */
122
- _runFileValidatorsForEntry(entry) {
180
+ async _runFileValidatorsForEntry(entry, runOn) {
181
+ const entryDescriptors = this._getValidatorDescriptorsForEntry(entry, runOn);
182
+ if (entryDescriptors.length === 0) {
183
+ return;
184
+ }
185
+ entry.setMultipleValues({
186
+ isQueuedForValidation: true,
187
+ isValidationPending: true,
188
+ });
123
189
  const outputEntry = this._blockInstance.api.getOutputItem(entry.uid);
190
+ const state = this._getEntryValidationState(entry);
191
+
192
+ if (state.promise) {
193
+ await state.promise;
194
+ }
195
+
196
+ const { promise, resolve } = withResolvers();
197
+ state.promise = promise;
198
+ const abortController = new AbortController();
199
+ state.abortController = abortController;
200
+
201
+ const timeoutMs = this._blockInstance.cfg.validationTimeout;
202
+ const allDescriptors = this._getValidatorDescriptors();
203
+
204
+ const entryValidatorSet = new Set(entryDescriptors.map((d) => d.validator));
205
+ /** @type {import('../../types').OutputErrorFile[]} */
124
206
  const errors = [];
207
+ for (const descriptor of allDescriptors) {
208
+ if (!entryValidatorSet.has(descriptor.validator)) {
209
+ const error = state.lastErrorThrownByValidator.get(descriptor.validator);
210
+ if (error) errors.push(error);
211
+ }
212
+ }
213
+
214
+ const tasks = entryDescriptors.map((validatorDescriptor) => async () => {
215
+ if (!this._blockInstance.isConnected) {
216
+ return;
217
+ }
218
+ const timeoutId = setTimeout(() => {
219
+ state.skippedValidators.add(validatorDescriptor.validator);
220
+ abortController.abort();
221
+ console.warn(LOG_TEXT.FILE_VALIDATION_TIMEOUT);
222
+ }, timeoutMs);
125
223
 
126
- for (const validator of [
127
- ...this._fileValidators,
128
- ...this._addCustomTypeToValidators(this._blockInstance.cfg.fileValidators),
129
- ]) {
130
224
  try {
131
- const error = validator(outputEntry, this._blockInstance.api);
132
- if (!error) {
133
- continue;
225
+ const error = await validatorDescriptor.validator(outputEntry, this._blockInstance.api, {
226
+ signal: abortController.signal,
227
+ });
228
+ if (!error || abortController.signal.aborted) {
229
+ state.lastErrorThrownByValidator.set(validatorDescriptor.validator, undefined);
230
+ return;
134
231
  }
135
- if (error) {
136
- errors.push(error);
232
+ const normalizedError = this._addCustomTypeToValidationError(error);
233
+ state.lastErrorThrownByValidator.set(validatorDescriptor.validator, normalizedError);
234
+ errors.push(normalizedError);
137
235
 
138
- if (!error.message) {
139
- console.warn(LOGGER.message);
140
- }
236
+ if (!error.message) {
237
+ console.warn(LOG_TEXT.MISSING_ERROR_MESSAGE);
141
238
  }
142
239
  } catch (error) {
143
- console.warn(LOGGER.file, error);
144
- this._blockInstance.telemetryManager.sendEventError(error, `file validator. ${LOGGER.file}`);
240
+ if (!abortController.signal.aborted) {
241
+ state.skippedValidators.add(validatorDescriptor.validator);
242
+
243
+ console.warn(LOG_TEXT.FILE_VALIDATION_FAILED, error);
244
+ this._blockInstance.telemetryManager.sendEventError(
245
+ error,
246
+ `file validator. ${LOG_TEXT.FILE_VALIDATION_FAILED}`,
247
+ );
248
+ }
249
+ } finally {
250
+ clearTimeout(timeoutId);
251
+ if (validatorDescriptor.runOn !== 'change') {
252
+ state.skippedValidators.add(validatorDescriptor.validator);
253
+ }
145
254
  }
255
+ });
256
+
257
+ this._runQueueDebounced();
258
+
259
+ await this._queue.add(
260
+ async () => {
261
+ entry.setValue('isQueuedForValidation', false);
262
+ await Promise.all(tasks.map((task) => task())).catch(() => {});
263
+ },
264
+ {
265
+ autoRun: false,
266
+ },
267
+ );
268
+
269
+ if (abortController.signal.aborted) {
270
+ entry.setMultipleValues({
271
+ isQueuedForValidation: false,
272
+ isValidationPending: false,
273
+ });
274
+ resolve();
275
+ return;
146
276
  }
147
- entry.setValue('errors', errors);
277
+
278
+ entry.setMultipleValues({
279
+ isValidationPending: false,
280
+ isQueuedForValidation: false,
281
+ errors,
282
+ });
283
+
284
+ resolve();
285
+ }
286
+
287
+ /**
288
+ * @private
289
+ * @template {import('../../types').OutputError<
290
+ * import('../../types').OutputFileErrorType | import('../../types').OutputCollectionErrorType
291
+ * >} T
292
+ * @param {T} error
293
+ * @returns {T}
294
+ */
295
+ _addCustomTypeToValidationError(error) {
296
+ return {
297
+ ...error,
298
+ type: error.type ?? 'CUSTOM_ERROR',
299
+ };
148
300
  }
149
301
 
150
302
  /**
151
- * @template T
152
- * @param {T[]} validators
153
- * @returns {T[]}
303
+ * @private
304
+ * @param {import('../TypedData.js').TypedData<typeof import('../uploadEntrySchema.js').uploadEntrySchema>} entry
154
305
  */
155
- _addCustomTypeToValidators(validators) {
156
- // @ts-ignore
157
- return validators.map((fn) => (...args) => {
158
- // @ts-ignore
159
- const result = fn(...args);
306
+ _getEntryValidationState(entry) {
307
+ const currentState = this._entryValidationState.get(entry.uid);
308
+ if (currentState) {
309
+ return currentState;
310
+ }
160
311
 
161
- return result ? { ...result, ...{ type: 'CUSTOM_ERROR' } } : undefined;
162
- });
312
+ const newState = {
313
+ abortController: undefined,
314
+ skippedValidators: new WeakSet(),
315
+ promise: undefined,
316
+ lastErrorThrownByValidator: /** @type {WeakMap<FuncFileValidator, import('../../types').OutputErrorFile>} */ (
317
+ new WeakMap()
318
+ ),
319
+ };
320
+ this._entryValidationState.set(entry.uid, newState);
321
+ return newState;
322
+ }
323
+
324
+ /** @private */
325
+ _getValidatorDescriptors() {
326
+ return [...this._commonFileValidators, ...this._blockInstance.cfg.fileValidators].map(getValidatorDescriptor);
327
+ }
328
+
329
+ /**
330
+ * @private
331
+ * @param {import('../TypedData.js').TypedData<typeof import('../uploadEntrySchema.js').uploadEntrySchema>} entry
332
+ * @param {FileValidatorDescriptor['runOn']} runOn
333
+ */
334
+ _getValidatorDescriptorsForEntry(entry, runOn) {
335
+ const state = this._getEntryValidationState(entry);
336
+ return this._getValidatorDescriptors()
337
+ .filter((descriptor) => !state.skippedValidators.has(descriptor.validator))
338
+ .filter((descriptor) => descriptor.runOn === runOn);
163
339
  }
164
340
  }
@@ -103,7 +103,7 @@ export const uploadEntrySchema: Readonly<{
103
103
  }>;
104
104
  errors: Readonly<{
105
105
  type: ArrayConstructor;
106
- value: Error[];
106
+ value: import("../types").OutputErrorFile[];
107
107
  }>;
108
108
  uploadError: Readonly<{
109
109
  type: ErrorConstructor;
@@ -114,7 +114,15 @@ export const uploadEntrySchema: Readonly<{
114
114
  type: BooleanConstructor;
115
115
  value: false;
116
116
  }>;
117
- isQueued: Readonly<{
117
+ isQueuedForUploading: Readonly<{
118
+ type: BooleanConstructor;
119
+ value: false;
120
+ }>;
121
+ isValidationPending: Readonly<{
122
+ type: BooleanConstructor;
123
+ value: false;
124
+ }>;
125
+ isQueuedForValidation: Readonly<{
118
126
  type: BooleanConstructor;
119
127
  value: false;
120
128
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"uploadEntrySchema.d.ts","sourceRoot":"","sources":["uploadEntrySchema.js"],"names":[],"mappings":"AAGA,gBAAgB;AAChB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;eAkGsB,KAAK,EAAE;;;;;;;;;;;;;;;GAe1B;8BAEW,OAAO,aAAa,EAAE,qBAAqB,CAAC,OAAO,iBAAiB,CAAC;mCAErE,OAAO,gBAAgB,EAAE,SAAS,CAAC,OAAO,iBAAiB,CAAC;8BAE5D,OAAO,gBAAgB,EAAE,qBAAqB,CAAC,OAAO,iBAAiB,CAAC;+BA1HvD,2BAA2B"}
1
+ {"version":3,"file":"uploadEntrySchema.d.ts","sourceRoot":"","sources":["uploadEntrySchema.js"],"names":[],"mappings":"AAGA,gBAAgB;AAChB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;eAkGsB,OAAO,UAAU,EAAE,eAAe,EAAE;;;;;;;;;;;;;;;;;;;;;;;GAuBvD;8BAEW,OAAO,aAAa,EAAE,qBAAqB,CAAC,OAAO,iBAAiB,CAAC;mCAErE,OAAO,gBAAgB,EAAE,SAAS,CAAC,OAAO,iBAAiB,CAAC;8BAE5D,OAAO,gBAAgB,EAAE,qBAAqB,CAAC,OAAO,iBAAiB,CAAC;+BAlIvD,2BAA2B"}