@purposeinplay/payload-ai-translate 0.1.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 (301) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +714 -0
  3. package/dist/alerts-collection.d.ts +21 -0
  4. package/dist/alerts-collection.js +159 -0
  5. package/dist/api.d.ts +4 -0
  6. package/dist/api.js +918 -0
  7. package/dist/bulk-translate-batches-collection.d.ts +29 -0
  8. package/dist/bulk-translate-batches-collection.js +404 -0
  9. package/dist/bulk-translate-units-collection.d.ts +35 -0
  10. package/dist/bulk-translate-units-collection.js +310 -0
  11. package/dist/client/estimated-cost-cell.d.ts +6 -0
  12. package/dist/client/estimated-cost-cell.js +12 -0
  13. package/dist/client/excluded-fields-field.d.ts +45 -0
  14. package/dist/client/excluded-fields-field.js +553 -0
  15. package/dist/client/field-translate-button.d.ts +6 -0
  16. package/dist/client/field-translate-button.js +199 -0
  17. package/dist/client/index.d.ts +6 -0
  18. package/dist/client/index.js +6 -0
  19. package/dist/client/lib/use-global-kill-switches.d.ts +20 -0
  20. package/dist/client/lib/use-global-kill-switches.js +58 -0
  21. package/dist/client/translate-button.d.ts +2 -0
  22. package/dist/client/translate-button.js +228 -0
  23. package/dist/client/translate-modal.d.ts +16 -0
  24. package/dist/client/translate-modal.js +549 -0
  25. package/dist/client/translation-progress.d.ts +10 -0
  26. package/dist/client/translation-progress.js +297 -0
  27. package/dist/components/TranslationNavGroup.d.ts +45 -0
  28. package/dist/components/TranslationNavGroup.js +104 -0
  29. package/dist/defaults.d.ts +11 -0
  30. package/dist/defaults.js +16 -0
  31. package/dist/endpoints/client-config.d.ts +44 -0
  32. package/dist/endpoints/client-config.js +145 -0
  33. package/dist/endpoints/estimate.d.ts +5 -0
  34. package/dist/endpoints/estimate.js +237 -0
  35. package/dist/endpoints/progress.d.ts +2 -0
  36. package/dist/endpoints/progress.js +314 -0
  37. package/dist/endpoints/translate.d.ts +11 -0
  38. package/dist/endpoints/translate.js +376 -0
  39. package/dist/endpoints/translation-hub/_helpers.d.ts +140 -0
  40. package/dist/endpoints/translation-hub/_helpers.js +297 -0
  41. package/dist/endpoints/translation-hub/active.d.ts +21 -0
  42. package/dist/endpoints/translation-hub/active.js +220 -0
  43. package/dist/endpoints/translation-hub/cancel.d.ts +22 -0
  44. package/dist/endpoints/translation-hub/cancel.js +233 -0
  45. package/dist/endpoints/translation-hub/enqueue.d.ts +70 -0
  46. package/dist/endpoints/translation-hub/enqueue.js +529 -0
  47. package/dist/endpoints/translation-hub/failures.d.ts +12 -0
  48. package/dist/endpoints/translation-hub/failures.js +67 -0
  49. package/dist/endpoints/translation-hub/force-reset.d.ts +20 -0
  50. package/dist/endpoints/translation-hub/force-reset.js +144 -0
  51. package/dist/endpoints/translation-hub/index.d.ts +21 -0
  52. package/dist/endpoints/translation-hub/index.js +20 -0
  53. package/dist/endpoints/translation-hub/list.d.ts +40 -0
  54. package/dist/endpoints/translation-hub/list.js +182 -0
  55. package/dist/endpoints/translation-hub/preflight.d.ts +19 -0
  56. package/dist/endpoints/translation-hub/preflight.js +141 -0
  57. package/dist/endpoints/translation-hub/retry-failed.d.ts +38 -0
  58. package/dist/endpoints/translation-hub/retry-failed.js +235 -0
  59. package/dist/endpoints/translation-hub/revert.d.ts +88 -0
  60. package/dist/endpoints/translation-hub/revert.js +405 -0
  61. package/dist/endpoints/translation-hub/status.d.ts +45 -0
  62. package/dist/endpoints/translation-hub/status.js +391 -0
  63. package/dist/endpoints/translation-hub/usage-summary.d.ts +114 -0
  64. package/dist/endpoints/translation-hub/usage-summary.js +481 -0
  65. package/dist/exports/client.d.ts +6 -0
  66. package/dist/exports/client.js +6 -0
  67. package/dist/exports/components.d.ts +6 -0
  68. package/dist/exports/components.js +5 -0
  69. package/dist/exports/index.d.ts +8 -0
  70. package/dist/exports/index.js +7 -0
  71. package/dist/exports/providers.d.ts +9 -0
  72. package/dist/exports/providers.js +5 -0
  73. package/dist/exports/views-client.d.ts +23 -0
  74. package/dist/exports/views-client.js +22 -0
  75. package/dist/exports/views.d.ts +30 -0
  76. package/dist/exports/views.js +29 -0
  77. package/dist/hooks/after-change-global.d.ts +4 -0
  78. package/dist/hooks/after-change-global.js +109 -0
  79. package/dist/hooks/after-change.d.ts +16 -0
  80. package/dist/hooks/after-change.js +205 -0
  81. package/dist/hooks/after-delete.d.ts +30 -0
  82. package/dist/hooks/after-delete.js +95 -0
  83. package/dist/index.d.ts +5 -0
  84. package/dist/index.js +5 -0
  85. package/dist/jobs-collection.d.ts +17 -0
  86. package/dist/jobs-collection.js +139 -0
  87. package/dist/lexical/classifier.d.ts +3 -0
  88. package/dist/lexical/classifier.js +108 -0
  89. package/dist/lexical/deserializer.d.ts +4 -0
  90. package/dist/lexical/deserializer.js +263 -0
  91. package/dist/lexical/placeholder-integrity.d.ts +6 -0
  92. package/dist/lexical/placeholder-integrity.js +21 -0
  93. package/dist/lexical/placeholders.d.ts +21 -0
  94. package/dist/lexical/placeholders.js +117 -0
  95. package/dist/lexical/serializer.d.ts +21 -0
  96. package/dist/lexical/serializer.js +233 -0
  97. package/dist/lexical/types.d.ts +32 -0
  98. package/dist/lexical/types.js +1 -0
  99. package/dist/lib/auth-diagnostics.d.ts +14 -0
  100. package/dist/lib/auth-diagnostics.js +19 -0
  101. package/dist/lib/batch-counts.d.ts +58 -0
  102. package/dist/lib/batch-counts.js +105 -0
  103. package/dist/lib/bulk-translate-migrations.d.ts +92 -0
  104. package/dist/lib/bulk-translate-migrations.js +153 -0
  105. package/dist/lib/coalescing-queue.d.ts +38 -0
  106. package/dist/lib/coalescing-queue.js +69 -0
  107. package/dist/lib/content-extractor.d.ts +16 -0
  108. package/dist/lib/content-extractor.js +410 -0
  109. package/dist/lib/content-hash.d.ts +1 -0
  110. package/dist/lib/content-hash.js +19 -0
  111. package/dist/lib/content-patcher.d.ts +15 -0
  112. package/dist/lib/content-patcher.js +293 -0
  113. package/dist/lib/cost-guards.d.ts +2 -0
  114. package/dist/lib/cost-guards.js +18 -0
  115. package/dist/lib/daily-spend-cap.d.ts +58 -0
  116. package/dist/lib/daily-spend-cap.js +233 -0
  117. package/dist/lib/effective-locales.d.ts +181 -0
  118. package/dist/lib/effective-locales.js +302 -0
  119. package/dist/lib/error-messages.d.ts +245 -0
  120. package/dist/lib/error-messages.js +626 -0
  121. package/dist/lib/events.d.ts +39 -0
  122. package/dist/lib/events.js +146 -0
  123. package/dist/lib/exclude-fields.d.ts +3 -0
  124. package/dist/lib/exclude-fields.js +64 -0
  125. package/dist/lib/field-breadcrumb.d.ts +31 -0
  126. package/dist/lib/field-breadcrumb.js +227 -0
  127. package/dist/lib/field-diff.d.ts +1 -0
  128. package/dist/lib/field-diff.js +25 -0
  129. package/dist/lib/field-empty.d.ts +2 -0
  130. package/dist/lib/field-empty.js +68 -0
  131. package/dist/lib/field-resolver.d.ts +3 -0
  132. package/dist/lib/field-resolver.js +164 -0
  133. package/dist/lib/group-soft-skips.d.ts +39 -0
  134. package/dist/lib/group-soft-skips.js +45 -0
  135. package/dist/lib/locale-merge.d.ts +44 -0
  136. package/dist/lib/locale-merge.js +357 -0
  137. package/dist/lib/locale-row-check.d.ts +30 -0
  138. package/dist/lib/locale-row-check.js +64 -0
  139. package/dist/lib/logger.d.ts +74 -0
  140. package/dist/lib/logger.js +97 -0
  141. package/dist/lib/manual-edit-guard.d.ts +128 -0
  142. package/dist/lib/manual-edit-guard.js +393 -0
  143. package/dist/lib/output-validation.d.ts +48 -0
  144. package/dist/lib/output-validation.js +148 -0
  145. package/dist/lib/payload-read.d.ts +16 -0
  146. package/dist/lib/payload-read.js +51 -0
  147. package/dist/lib/per-doc-claim.d.ts +90 -0
  148. package/dist/lib/per-doc-claim.js +140 -0
  149. package/dist/lib/per-doc-lock.d.ts +94 -0
  150. package/dist/lib/per-doc-lock.js +119 -0
  151. package/dist/lib/persist-usage.d.ts +91 -0
  152. package/dist/lib/persist-usage.js +116 -0
  153. package/dist/lib/progress-store.d.ts +103 -0
  154. package/dist/lib/progress-store.js +314 -0
  155. package/dist/lib/rate-limiter.d.ts +3 -0
  156. package/dist/lib/rate-limiter.js +53 -0
  157. package/dist/lib/snapshot-select.d.ts +43 -0
  158. package/dist/lib/snapshot-select.js +108 -0
  159. package/dist/lib/translate-prompt.d.ts +31 -0
  160. package/dist/lib/translate-prompt.js +66 -0
  161. package/dist/lib/translation-token-bucket.d.ts +57 -0
  162. package/dist/lib/translation-token-bucket.js +365 -0
  163. package/dist/lib/truncate-source-value.d.ts +1 -0
  164. package/dist/lib/truncate-source-value.js +27 -0
  165. package/dist/manual-edit-collection.d.ts +22 -0
  166. package/dist/manual-edit-collection.js +124 -0
  167. package/dist/plugin.d.ts +3 -0
  168. package/dist/plugin.js +934 -0
  169. package/dist/providers/ai-sdk-adapter.d.ts +35 -0
  170. package/dist/providers/ai-sdk-adapter.js +100 -0
  171. package/dist/providers/anthropic.d.ts +31 -0
  172. package/dist/providers/anthropic.js +66 -0
  173. package/dist/providers/custom.d.ts +36 -0
  174. package/dist/providers/custom.js +24 -0
  175. package/dist/providers/gemini.d.ts +20 -0
  176. package/dist/providers/gemini.js +48 -0
  177. package/dist/providers/mock.d.ts +2 -0
  178. package/dist/providers/mock.js +29 -0
  179. package/dist/providers/openai.d.ts +28 -0
  180. package/dist/providers/openai.js +69 -0
  181. package/dist/settings-global.d.ts +74 -0
  182. package/dist/settings-global.js +216 -0
  183. package/dist/tasks/bulk-translate-coordinator.d.ts +115 -0
  184. package/dist/tasks/bulk-translate-coordinator.js +708 -0
  185. package/dist/tasks/bulk-translate-doc-task.d.ts +142 -0
  186. package/dist/tasks/bulk-translate-doc-task.js +1000 -0
  187. package/dist/tasks/bulk-translate-janitor.d.ts +87 -0
  188. package/dist/tasks/bulk-translate-janitor.js +311 -0
  189. package/dist/tasks/translate-job-task.d.ts +51 -0
  190. package/dist/tasks/translate-job-task.js +154 -0
  191. package/dist/translate.d.ts +113 -0
  192. package/dist/translate.js +911 -0
  193. package/dist/translation-daily-spend-collection.d.ts +24 -0
  194. package/dist/translation-daily-spend-collection.js +133 -0
  195. package/dist/translation-rate-limits-collection.d.ts +30 -0
  196. package/dist/translation-rate-limits-collection.js +144 -0
  197. package/dist/types.d.ts +672 -0
  198. package/dist/types.js +1 -0
  199. package/dist/usage-collection.d.ts +14 -0
  200. package/dist/usage-collection.js +377 -0
  201. package/dist/views/BulkRunsHub/BatchRow.d.ts +32 -0
  202. package/dist/views/BulkRunsHub/BatchRow.js +1222 -0
  203. package/dist/views/BulkRunsHub/BucketRow.d.ts +62 -0
  204. package/dist/views/BulkRunsHub/BucketRow.js +982 -0
  205. package/dist/views/BulkRunsHub/BulkRunsHub.client.d.ts +18 -0
  206. package/dist/views/BulkRunsHub/BulkRunsHub.client.js +331 -0
  207. package/dist/views/BulkRunsHub/EmptyState.d.ts +6 -0
  208. package/dist/views/BulkRunsHub/EmptyState.js +64 -0
  209. package/dist/views/BulkRunsHub/FilterBar.d.ts +16 -0
  210. package/dist/views/BulkRunsHub/FilterBar.js +284 -0
  211. package/dist/views/BulkRunsHub/InFlightBanner.d.ts +14 -0
  212. package/dist/views/BulkRunsHub/InFlightBanner.js +59 -0
  213. package/dist/views/BulkRunsHub/StatusBadge.d.ts +64 -0
  214. package/dist/views/BulkRunsHub/StatusBadge.js +248 -0
  215. package/dist/views/BulkRunsHub/SummaryStrip.d.ts +22 -0
  216. package/dist/views/BulkRunsHub/SummaryStrip.js +249 -0
  217. package/dist/views/BulkRunsHub/bucket-grouping.d.ts +200 -0
  218. package/dist/views/BulkRunsHub/bucket-grouping.js +344 -0
  219. package/dist/views/BulkRunsHub/bucketFailureSummary.d.ts +9 -0
  220. package/dist/views/BulkRunsHub/bucketFailureSummary.js +36 -0
  221. package/dist/views/BulkRunsHub/dedupedStatusFetch.d.ts +5 -0
  222. package/dist/views/BulkRunsHub/dedupedStatusFetch.js +45 -0
  223. package/dist/views/BulkRunsHub/index.d.ts +17 -0
  224. package/dist/views/BulkRunsHub/index.js +80 -0
  225. package/dist/views/BulkRunsHub/urlFilters.d.ts +14 -0
  226. package/dist/views/BulkRunsHub/urlFilters.js +50 -0
  227. package/dist/views/BulkRunsHub/useBulkRunsList.d.ts +26 -0
  228. package/dist/views/BulkRunsHub/useBulkRunsList.js +204 -0
  229. package/dist/views/BulkRunsHub/useUrlFilters.d.ts +10 -0
  230. package/dist/views/BulkRunsHub/useUrlFilters.js +88 -0
  231. package/dist/views/TranslationHub/ActiveJobs.d.ts +6 -0
  232. package/dist/views/TranslationHub/ActiveJobs.js +320 -0
  233. package/dist/views/TranslationHub/AdvancedPanel.d.ts +17 -0
  234. package/dist/views/TranslationHub/AdvancedPanel.js +996 -0
  235. package/dist/views/TranslationHub/AlertBanner.d.ts +6 -0
  236. package/dist/views/TranslationHub/AlertBanner.js +568 -0
  237. package/dist/views/TranslationHub/AuditPanel.d.ts +6 -0
  238. package/dist/views/TranslationHub/AuditPanel.helpers.d.ts +44 -0
  239. package/dist/views/TranslationHub/AuditPanel.helpers.js +71 -0
  240. package/dist/views/TranslationHub/AuditPanel.js +1367 -0
  241. package/dist/views/TranslationHub/BulkTranslate.types.d.ts +242 -0
  242. package/dist/views/TranslationHub/BulkTranslate.types.js +36 -0
  243. package/dist/views/TranslationHub/BulkTranslateFailureDrawer.d.ts +19 -0
  244. package/dist/views/TranslationHub/BulkTranslateFailureDrawer.js +332 -0
  245. package/dist/views/TranslationHub/BulkTranslateMonitor.d.ts +28 -0
  246. package/dist/views/TranslationHub/BulkTranslateMonitor.js +305 -0
  247. package/dist/views/TranslationHub/BulkTranslateNarrowViewportBanner.d.ts +3 -0
  248. package/dist/views/TranslationHub/BulkTranslateNarrowViewportBanner.js +42 -0
  249. package/dist/views/TranslationHub/BulkTranslatePostEnqueueTransition.d.ts +26 -0
  250. package/dist/views/TranslationHub/BulkTranslatePostEnqueueTransition.js +95 -0
  251. package/dist/views/TranslationHub/BulkTranslatePreflightModal.d.ts +22 -0
  252. package/dist/views/TranslationHub/BulkTranslatePreflightModal.js +879 -0
  253. package/dist/views/TranslationHub/BulkTranslateTerminalCard.d.ts +29 -0
  254. package/dist/views/TranslationHub/BulkTranslateTerminalCard.js +445 -0
  255. package/dist/views/TranslationHub/BulkTranslateTrigger.d.ts +66 -0
  256. package/dist/views/TranslationHub/BulkTranslateTrigger.js +161 -0
  257. package/dist/views/TranslationHub/EditorRecentRunsPanel.d.ts +33 -0
  258. package/dist/views/TranslationHub/EditorRecentRunsPanel.js +290 -0
  259. package/dist/views/TranslationHub/Hub.client.d.ts +74 -0
  260. package/dist/views/TranslationHub/Hub.client.js +357 -0
  261. package/dist/views/TranslationHub/ModelCombobox.d.ts +14 -0
  262. package/dist/views/TranslationHub/ModelCombobox.js +415 -0
  263. package/dist/views/TranslationHub/PerCollectionConfig.d.ts +10 -0
  264. package/dist/views/TranslationHub/PerCollectionConfig.helpers.d.ts +16 -0
  265. package/dist/views/TranslationHub/PerCollectionConfig.helpers.js +19 -0
  266. package/dist/views/TranslationHub/PerCollectionConfig.js +759 -0
  267. package/dist/views/TranslationHub/SettingsRail.d.ts +11 -0
  268. package/dist/views/TranslationHub/SettingsRail.js +382 -0
  269. package/dist/views/TranslationHub/StatusStrip.d.ts +6 -0
  270. package/dist/views/TranslationHub/StatusStrip.js +451 -0
  271. package/dist/views/TranslationHub/UsageTable.d.ts +6 -0
  272. package/dist/views/TranslationHub/UsageTable.helpers.d.ts +69 -0
  273. package/dist/views/TranslationHub/UsageTable.helpers.js +49 -0
  274. package/dist/views/TranslationHub/UsageTable.js +1240 -0
  275. package/dist/views/TranslationHub/alertGrouping.d.ts +70 -0
  276. package/dist/views/TranslationHub/alertGrouping.js +99 -0
  277. package/dist/views/TranslationHub/index.d.ts +20 -0
  278. package/dist/views/TranslationHub/index.js +109 -0
  279. package/dist/views/TranslationHub/tabNavigation.d.ts +53 -0
  280. package/dist/views/TranslationHub/tabNavigation.js +74 -0
  281. package/dist/views/TranslationHub/terminalBannerVisibility.d.ts +33 -0
  282. package/dist/views/TranslationHub/terminalBannerVisibility.js +124 -0
  283. package/dist/views/TranslationHub/useBulkTranslateActive.d.ts +49 -0
  284. package/dist/views/TranslationHub/useBulkTranslateActive.js +251 -0
  285. package/dist/views/TranslationHub/useFocusTrap.d.ts +6 -0
  286. package/dist/views/TranslationHub/useFocusTrap.js +81 -0
  287. package/dist/views/TranslationHub/useTranslationHubUsageSummary.d.ts +77 -0
  288. package/dist/views/TranslationHub/useTranslationHubUsageSummary.js +267 -0
  289. package/dist/views/shared/EditorError.d.ts +97 -0
  290. package/dist/views/shared/EditorError.js +205 -0
  291. package/dist/views/shared/ModelCell.d.ts +18 -0
  292. package/dist/views/shared/ModelCell.js +31 -0
  293. package/dist/views/shared/docHref.d.ts +16 -0
  294. package/dist/views/shared/docHref.js +26 -0
  295. package/dist/views/shared/fetch-error-body.d.ts +25 -0
  296. package/dist/views/shared/fetch-error-body.js +42 -0
  297. package/dist/views/shared/filterPillStyle.d.ts +35 -0
  298. package/dist/views/shared/filterPillStyle.js +40 -0
  299. package/dist/views/shared/format.d.ts +75 -0
  300. package/dist/views/shared/format.js +131 -0
  301. package/package.json +141 -0
@@ -0,0 +1,29 @@
1
+ import type { Access, CollectionConfig } from 'payload';
2
+ export declare const DEFAULT_BULK_TRANSLATE_BATCHES_COLLECTION_SLUG = "bulk-translate-batches";
3
+ /**
4
+ * Sidecar collection for the bulk-translate feature (plugin v1.2.0+).
5
+ * One row per bulk run. Persists the trigger context (who, when, scope,
6
+ * model snapshot), aggregate counts (total / running / completed /
7
+ * failed / skipped), and lifecycle timestamps (queued, started,
8
+ * completed, cancelled, reverted) so admins can reconstruct any bulk
9
+ * operation after the fact.
10
+ *
11
+ * `read` access defaults to `admin` role explicitly (Decision #31 in
12
+ * the bulk-translate design doc) — the `triggeredByEmail`,
13
+ * `triggerReason`, and `failures` fields can carry sensitive
14
+ * operational context that editor-role users should not see.
15
+ *
16
+ * Status semantics:
17
+ * - `queued` : row exists, coordinator task enqueued but not started
18
+ * - `running` : coordinator is enumerating / fan-out in progress
19
+ * - `completed` : every unit reached `success`
20
+ * - `partial` : terminal — some succeeded, some failed
21
+ * - `failed` : terminal — no successes
22
+ * - `cancelled` : terminal — cancel endpoint hit before completion
23
+ * - `reverted` : terminal — revert endpoint replayed pre-run snapshots
24
+ *
25
+ * Model/provider/sourceLocale are snapshotted at enqueue time
26
+ * (Decision #5) so an admin toggling settings mid-run does not bisect
27
+ * the batch across configurations.
28
+ */
29
+ export declare function createBulkTranslateBatchesCollection(readAccess?: Access, slug?: string): CollectionConfig;
@@ -0,0 +1,404 @@
1
+ export const DEFAULT_BULK_TRANSLATE_BATCHES_COLLECTION_SLUG = 'bulk-translate-batches';
2
+ /**
3
+ * Sidecar collection for the bulk-translate feature (plugin v1.2.0+).
4
+ * One row per bulk run. Persists the trigger context (who, when, scope,
5
+ * model snapshot), aggregate counts (total / running / completed /
6
+ * failed / skipped), and lifecycle timestamps (queued, started,
7
+ * completed, cancelled, reverted) so admins can reconstruct any bulk
8
+ * operation after the fact.
9
+ *
10
+ * `read` access defaults to `admin` role explicitly (Decision #31 in
11
+ * the bulk-translate design doc) — the `triggeredByEmail`,
12
+ * `triggerReason`, and `failures` fields can carry sensitive
13
+ * operational context that editor-role users should not see.
14
+ *
15
+ * Status semantics:
16
+ * - `queued` : row exists, coordinator task enqueued but not started
17
+ * - `running` : coordinator is enumerating / fan-out in progress
18
+ * - `completed` : every unit reached `success`
19
+ * - `partial` : terminal — some succeeded, some failed
20
+ * - `failed` : terminal — no successes
21
+ * - `cancelled` : terminal — cancel endpoint hit before completion
22
+ * - `reverted` : terminal — revert endpoint replayed pre-run snapshots
23
+ *
24
+ * Model/provider/sourceLocale are snapshotted at enqueue time
25
+ * (Decision #5) so an admin toggling settings mid-run does not bisect
26
+ * the batch across configurations.
27
+ */ export function createBulkTranslateBatchesCollection(readAccess, slug = DEFAULT_BULK_TRANSLATE_BATCHES_COLLECTION_SLUG) {
28
+ const isAdminDefault = ({ req })=>{
29
+ const user = req.user;
30
+ const roles = user?.roles;
31
+ if (Array.isArray(roles) && roles.includes('admin')) {
32
+ return true;
33
+ }
34
+ return false;
35
+ };
36
+ // 1.2.8: read opened to editor+admin so the Translation Hub's Recent
37
+ // translations table can fetch batches for editors. Cost / model /
38
+ // token fields are masked at the field level below so editors see
39
+ // attribution + status but not provider economics. Delete / update
40
+ // stay admin-only — mutations route through the hub endpoints
41
+ // (cancel / retry / revert) which layer ownership checks on top.
42
+ const isEditorOrAdminDefault = ({ req })=>{
43
+ const user = req.user;
44
+ const roles = user?.roles;
45
+ if (!Array.isArray(roles)) {
46
+ return false;
47
+ }
48
+ return roles.includes('admin') || roles.includes('editor');
49
+ };
50
+ // Field-level read access for the cost / model surface. Admins see
51
+ // everything; editors see nothing on these fields. Returning `false`
52
+ // here strips the field from the API response (Payload contract) —
53
+ // not just hides it client-side.
54
+ const fieldAdminOnlyRead = ({ req })=>{
55
+ // Field access is boolean-only (a `Where` clause cannot scope a field),
56
+ // so coerce the collection-level Access result to a strict boolean here.
57
+ // Matches the documented intent: only literal admin access reveals the
58
+ // field; anything else strips it from the API response.
59
+ return isAdminDefault({
60
+ req
61
+ }) === true;
62
+ };
63
+ return {
64
+ slug,
65
+ // System rows are never edited in the admin document view, so
66
+ // Payload's document-locking buys nothing here — and its lock check
67
+ // costs a second pool connection inside every update transaction
68
+ // (core's checkDocumentLockStatus runs a find without `req`). Under
69
+ // concurrent updates (e.g. dismiss-all on alerts) that exhausted the
70
+ // pool and deadlocked a consumer in prod on 2026-06-10.
71
+ lockDocuments: false,
72
+ labels: {
73
+ singular: 'Bulk Translate Batch',
74
+ plural: 'Bulk Translate Batches'
75
+ },
76
+ admin: {
77
+ group: 'Translation',
78
+ useAsTitle: 'id',
79
+ defaultColumns: [
80
+ 'id',
81
+ 'status',
82
+ 'mode',
83
+ 'totalUnits',
84
+ 'completedUnits',
85
+ 'failedUnits',
86
+ 'estimatedCostUsd',
87
+ 'actualCostUsd',
88
+ 'startedAt'
89
+ ],
90
+ hidden: ({ user })=>{
91
+ const roles = user?.roles;
92
+ return !(Array.isArray(roles) && roles.includes('admin'));
93
+ },
94
+ description: 'One row per bulk-translation run. Persists scope, snapshotted model/provider, cost estimates, and aggregate progress. Use this to audit who ran a bulk operation, when, and what the outcome was. Per-(doc, locale) detail lives in `Bulk Translate Units`.'
95
+ },
96
+ access: {
97
+ // 1.2.8: defaults to editor+admin so the Hub Recent translations
98
+ // table populates for editors. Consumers can still override via
99
+ // `readAccess` if they want a stricter policy.
100
+ read: readAccess ?? isEditorOrAdminDefault,
101
+ create: ()=>false,
102
+ update: ()=>false,
103
+ delete: isAdminDefault
104
+ },
105
+ fields: [
106
+ {
107
+ name: 'scope',
108
+ type: 'json',
109
+ required: true,
110
+ admin: {
111
+ readOnly: true,
112
+ description: 'Scope filter resolved at enqueue: `{ collections, globals, locales, excludeCollections, documentIds }`. Used by retry-failed / revert to re-resolve membership.'
113
+ }
114
+ },
115
+ {
116
+ name: 'mode',
117
+ type: 'select',
118
+ required: true,
119
+ options: [
120
+ {
121
+ label: 'Changed (diff-only)',
122
+ value: 'changed'
123
+ },
124
+ {
125
+ label: 'Force re-translate',
126
+ value: 'force'
127
+ },
128
+ {
129
+ label: 'Canary (limited sample)',
130
+ value: 'canary'
131
+ }
132
+ ],
133
+ admin: {
134
+ readOnly: true
135
+ }
136
+ },
137
+ {
138
+ name: 'canaryLimit',
139
+ type: 'number',
140
+ admin: {
141
+ readOnly: true,
142
+ condition: (data)=>data?.mode === 'canary',
143
+ description: 'Number of (doc, locale) units the canary fan-out is capped at. Selection is random-stratified across configured collections.'
144
+ }
145
+ },
146
+ // Snapshotted provider/model/source-locale at enqueue time
147
+ // (Decision #5 + F-DA-MODEL-SWAP). The active OpenRouter model
148
+ // can change while a batch drains; snapshotting here pins the
149
+ // batch's behavior to what the admin saw in the pre-flight modal.
150
+ {
151
+ name: 'snapshotProviderKey',
152
+ type: 'text',
153
+ required: true,
154
+ admin: {
155
+ readOnly: true
156
+ },
157
+ // 1.2.8: provider key is operational telemetry — admins only.
158
+ access: {
159
+ read: fieldAdminOnlyRead
160
+ }
161
+ },
162
+ {
163
+ name: 'snapshotModelId',
164
+ type: 'text',
165
+ required: true,
166
+ admin: {
167
+ readOnly: true
168
+ },
169
+ // 1.2.8: model is operational telemetry — admins only.
170
+ access: {
171
+ read: fieldAdminOnlyRead
172
+ }
173
+ },
174
+ {
175
+ name: 'snapshotSourceLocale',
176
+ type: 'text',
177
+ required: true,
178
+ admin: {
179
+ readOnly: true
180
+ }
181
+ },
182
+ {
183
+ name: 'estimatedCostUsd',
184
+ type: 'number',
185
+ required: true,
186
+ admin: {
187
+ readOnly: true
188
+ },
189
+ // 1.2.8: USD figures hidden from editors — cost is admin-only.
190
+ access: {
191
+ read: fieldAdminOnlyRead
192
+ }
193
+ },
194
+ {
195
+ name: 'actualCostUsd',
196
+ type: 'number',
197
+ defaultValue: 0,
198
+ admin: {
199
+ readOnly: true
200
+ },
201
+ access: {
202
+ read: fieldAdminOnlyRead
203
+ }
204
+ },
205
+ {
206
+ name: 'status',
207
+ type: 'select',
208
+ required: true,
209
+ index: true,
210
+ defaultValue: 'queued',
211
+ options: [
212
+ {
213
+ label: 'Queued',
214
+ value: 'queued'
215
+ },
216
+ {
217
+ label: 'Running',
218
+ value: 'running'
219
+ },
220
+ {
221
+ label: 'Cancelling',
222
+ value: 'cancelling'
223
+ },
224
+ // Terminal success vocab is `'success'` (matches units
225
+ // collection + BulkTranslateBatchStatus type union). Pre-1.2.4
226
+ // wrote `'completed'` here; lib/bulk-translate-migrations.ts
227
+ // ships an idempotent data migration helper.
228
+ {
229
+ label: 'Completed',
230
+ value: 'success'
231
+ },
232
+ {
233
+ label: 'Partial (some failed)',
234
+ value: 'partial'
235
+ },
236
+ {
237
+ label: 'Failed',
238
+ value: 'failed'
239
+ },
240
+ {
241
+ label: 'Cancelled',
242
+ value: 'cancelled'
243
+ },
244
+ {
245
+ label: 'Reverted',
246
+ value: 'reverted'
247
+ }
248
+ ],
249
+ admin: {
250
+ readOnly: true
251
+ }
252
+ },
253
+ {
254
+ name: 'totalUnits',
255
+ type: 'number',
256
+ defaultValue: 0,
257
+ admin: {
258
+ readOnly: true
259
+ }
260
+ },
261
+ {
262
+ name: 'completedUnits',
263
+ type: 'number',
264
+ defaultValue: 0,
265
+ admin: {
266
+ readOnly: true
267
+ }
268
+ },
269
+ {
270
+ name: 'failedUnits',
271
+ type: 'number',
272
+ defaultValue: 0,
273
+ admin: {
274
+ readOnly: true
275
+ }
276
+ },
277
+ {
278
+ name: 'skippedUnits',
279
+ type: 'number',
280
+ defaultValue: 0,
281
+ admin: {
282
+ readOnly: true
283
+ }
284
+ },
285
+ // Identity carried as `(userId, email)` rather than a relation so
286
+ // the audit trail survives user-record deletion. F-BIZ-07.
287
+ {
288
+ name: 'triggeredByUserId',
289
+ type: 'text',
290
+ required: true,
291
+ index: true,
292
+ admin: {
293
+ readOnly: true
294
+ }
295
+ },
296
+ {
297
+ name: 'triggeredByEmail',
298
+ type: 'text',
299
+ admin: {
300
+ readOnly: true
301
+ }
302
+ },
303
+ {
304
+ name: 'triggerReason',
305
+ type: 'textarea',
306
+ admin: {
307
+ readOnly: true,
308
+ description: 'Optional admin-supplied rationale for the run. Surfaces in audit and helps reconstruct intent post-hoc.'
309
+ }
310
+ },
311
+ {
312
+ name: 'cancelledByUserId',
313
+ type: 'text',
314
+ admin: {
315
+ readOnly: true
316
+ }
317
+ },
318
+ {
319
+ name: 'cancelledAt',
320
+ type: 'date',
321
+ admin: {
322
+ readOnly: true
323
+ }
324
+ },
325
+ {
326
+ name: 'revertedByUserId',
327
+ type: 'text',
328
+ admin: {
329
+ readOnly: true
330
+ }
331
+ },
332
+ {
333
+ name: 'revertedAt',
334
+ type: 'date',
335
+ admin: {
336
+ readOnly: true
337
+ }
338
+ },
339
+ // Two distinct timestamps:
340
+ // - enqueuedAt: when the batch row was created (always set)
341
+ // - startedAt: when the coordinator task first ran (may
342
+ // lag the enqueue by up to the cron tick interval; null
343
+ // until then). Both readonly in admin; written by the
344
+ // enqueue endpoint and coordinator respectively.
345
+ {
346
+ name: 'enqueuedAt',
347
+ type: 'date',
348
+ required: true,
349
+ index: true,
350
+ admin: {
351
+ readOnly: true
352
+ }
353
+ },
354
+ {
355
+ name: 'startedAt',
356
+ type: 'date',
357
+ admin: {
358
+ readOnly: true
359
+ }
360
+ },
361
+ {
362
+ name: 'completedAt',
363
+ type: 'date',
364
+ admin: {
365
+ readOnly: true
366
+ }
367
+ },
368
+ // Coordinator's enumeration cursor — persists across cron ticks so
369
+ // a crash mid-enumeration resumes from the last persisted point
370
+ // rather than re-enqueueing every doc (which would deduplicate
371
+ // via the partial unique index but waste cron cycles).
372
+ {
373
+ name: 'lastEnumerationCursor',
374
+ type: 'json',
375
+ admin: {
376
+ readOnly: true,
377
+ description: 'Internal coordinator state. Pagination cursor for the per-collection enumeration loop.'
378
+ }
379
+ },
380
+ // Soft lease lock: a coordinator updates this at the start of
381
+ // every tick (and clears it at finishTick when finished=true).
382
+ // If a second coordinator starts a tick and finds the lock
383
+ // updated within the lease window, it exits early — prevents
384
+ // the exponential trampoline fan-out that Round-5 pr-reviewer
385
+ // flagged when admin retries + queue duplicate-delivery race.
386
+ {
387
+ name: 'coordinatorActiveAt',
388
+ type: 'date',
389
+ admin: {
390
+ readOnly: true,
391
+ description: 'Internal lock. Coordinator heartbeat — updated each tick. A second coordinator finding this fresh within the lease window exits to avoid duplicate trampoline fan-out.'
392
+ }
393
+ },
394
+ {
395
+ name: 'failures',
396
+ type: 'json',
397
+ admin: {
398
+ readOnly: true,
399
+ description: 'Aggregated failure summary: `{ errorClass: count }`. Per-unit detail lives in `Bulk Translate Units`.'
400
+ }
401
+ }
402
+ ]
403
+ };
404
+ }
@@ -0,0 +1,35 @@
1
+ import type { Access, CollectionConfig } from 'payload';
2
+ export declare const DEFAULT_BULK_TRANSLATE_UNITS_COLLECTION_SLUG = "bulk-translate-units";
3
+ /**
4
+ * Per-(collection, documentId, locale) work item for a bulk translate
5
+ * batch. Plugin v1.2.0+.
6
+ *
7
+ * Source of truth for unit-level state in a bulk run. Read by:
8
+ * 1. The `shouldSkipDocument`-equivalent check at task-entry and the
9
+ * per-doc retry endpoint (Decision #19 v2): "is there already a
10
+ * pending/running unit for this (collection, doc, locale) in some
11
+ * other in-flight batch?". A partial unique index on
12
+ * `(collection, document_id, locale) WHERE status IN
13
+ * ('pending','running')` enforces the invariant in Postgres
14
+ * regardless of application-layer races (F-DA-TOCTOU).
15
+ * 2. The revert action: paginates over `success` units, reads
16
+ * `preRunSnapshot` + `schemaHash`, restores the pre-run value.
17
+ * 3. The Hub monitor UI's drill-down view of failed units.
18
+ *
19
+ * `preRunSnapshot` is jsonb and stores ONLY the localized translatable
20
+ * fields, captured via Payload `select` (Decision #30 + F-SEC-SNAPSHOT).
21
+ * Never the full document — that would leak `password` / `email` /
22
+ * `roles` and other `excludeFields` content into a queryable
23
+ * collection.
24
+ *
25
+ * Read access is locked to `admin` role only (Decision #31, unchanged
26
+ * in 1.2.8). The snapshot column contains pre-translation source
27
+ * content which, even scoped to translatable fields, may include
28
+ * unpublished drafts editor-role users should not see. Editors who
29
+ * need unit-level drill-down (e.g., per-locale outcomes, failure
30
+ * reasons) read through the shaped `/api/translation-hub/bulk-translate/:id`
31
+ * (`status` endpoint, 1.2.8 opened to editor+admin) and `/failures`
32
+ * endpoints — those serialize a redacted view that excludes
33
+ * `preRunSnapshot` entirely.
34
+ */
35
+ export declare function createBulkTranslateUnitsCollection(readAccess?: Access, slug?: string, batchesCollectionSlug?: string): CollectionConfig;