@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,310 @@
1
+ export const DEFAULT_BULK_TRANSLATE_UNITS_COLLECTION_SLUG = 'bulk-translate-units';
2
+ /**
3
+ * Per-(collection, documentId, locale) work item for a bulk translate
4
+ * batch. Plugin v1.2.0+.
5
+ *
6
+ * Source of truth for unit-level state in a bulk run. Read by:
7
+ * 1. The `shouldSkipDocument`-equivalent check at task-entry and the
8
+ * per-doc retry endpoint (Decision #19 v2): "is there already a
9
+ * pending/running unit for this (collection, doc, locale) in some
10
+ * other in-flight batch?". A partial unique index on
11
+ * `(collection, document_id, locale) WHERE status IN
12
+ * ('pending','running')` enforces the invariant in Postgres
13
+ * regardless of application-layer races (F-DA-TOCTOU).
14
+ * 2. The revert action: paginates over `success` units, reads
15
+ * `preRunSnapshot` + `schemaHash`, restores the pre-run value.
16
+ * 3. The Hub monitor UI's drill-down view of failed units.
17
+ *
18
+ * `preRunSnapshot` is jsonb and stores ONLY the localized translatable
19
+ * fields, captured via Payload `select` (Decision #30 + F-SEC-SNAPSHOT).
20
+ * Never the full document — that would leak `password` / `email` /
21
+ * `roles` and other `excludeFields` content into a queryable
22
+ * collection.
23
+ *
24
+ * Read access is locked to `admin` role only (Decision #31, unchanged
25
+ * in 1.2.8). The snapshot column contains pre-translation source
26
+ * content which, even scoped to translatable fields, may include
27
+ * unpublished drafts editor-role users should not see. Editors who
28
+ * need unit-level drill-down (e.g., per-locale outcomes, failure
29
+ * reasons) read through the shaped `/api/translation-hub/bulk-translate/:id`
30
+ * (`status` endpoint, 1.2.8 opened to editor+admin) and `/failures`
31
+ * endpoints — those serialize a redacted view that excludes
32
+ * `preRunSnapshot` entirely.
33
+ */ export function createBulkTranslateUnitsCollection(readAccess, slug = DEFAULT_BULK_TRANSLATE_UNITS_COLLECTION_SLUG, batchesCollectionSlug = 'bulk-translate-batches') {
34
+ const isAdminDefault = ({ req })=>{
35
+ const user = req.user;
36
+ const roles = user?.roles;
37
+ if (Array.isArray(roles) && roles.includes('admin')) return true;
38
+ return false;
39
+ };
40
+ return {
41
+ slug,
42
+ // System rows are never edited in the admin document view, so
43
+ // Payload's document-locking buys nothing here — and its lock check
44
+ // costs a second pool connection inside every update transaction
45
+ // (core's checkDocumentLockStatus runs a find without `req`). Under
46
+ // concurrent updates (e.g. dismiss-all on alerts) that exhausted the
47
+ // pool and deadlocked a consumer in prod on 2026-06-10.
48
+ lockDocuments: false,
49
+ labels: {
50
+ singular: 'Bulk Translate Unit',
51
+ plural: 'Bulk Translate Units'
52
+ },
53
+ admin: {
54
+ group: 'Translation',
55
+ useAsTitle: 'id',
56
+ defaultColumns: [
57
+ 'batchId',
58
+ 'collection',
59
+ 'documentId',
60
+ 'locale',
61
+ 'status',
62
+ 'attempts',
63
+ 'failureCode',
64
+ 'completedAt'
65
+ ],
66
+ hidden: ({ user })=>{
67
+ const roles = user?.roles;
68
+ return !Array.isArray(roles) || !roles.includes('admin');
69
+ },
70
+ description: 'Per-(doc, locale) work item for a bulk-translate batch. One row per translation unit. Status transitions: pending → running → success | failed | skipped. Reverted units track replay of pre-run snapshots.'
71
+ },
72
+ access: {
73
+ read: readAccess ?? isAdminDefault,
74
+ create: ()=>false,
75
+ update: ()=>false,
76
+ delete: isAdminDefault
77
+ },
78
+ fields: [
79
+ {
80
+ name: 'batchId',
81
+ type: 'relationship',
82
+ relationTo: batchesCollectionSlug,
83
+ required: true,
84
+ index: true,
85
+ admin: {
86
+ readOnly: true
87
+ }
88
+ },
89
+ {
90
+ name: 'collection',
91
+ type: 'text',
92
+ required: true,
93
+ index: true,
94
+ admin: {
95
+ readOnly: true
96
+ }
97
+ },
98
+ {
99
+ name: 'documentId',
100
+ type: 'text',
101
+ required: true,
102
+ index: true,
103
+ admin: {
104
+ readOnly: true
105
+ }
106
+ },
107
+ {
108
+ name: 'locale',
109
+ type: 'text',
110
+ required: true,
111
+ index: true,
112
+ admin: {
113
+ readOnly: true
114
+ }
115
+ },
116
+ {
117
+ name: 'status',
118
+ type: 'select',
119
+ required: true,
120
+ index: true,
121
+ defaultValue: 'pending',
122
+ options: [
123
+ {
124
+ label: 'Pending (queued)',
125
+ value: 'pending'
126
+ },
127
+ {
128
+ label: 'Running',
129
+ value: 'running'
130
+ },
131
+ {
132
+ label: 'Success',
133
+ value: 'success'
134
+ },
135
+ {
136
+ label: 'Failed',
137
+ value: 'failed'
138
+ },
139
+ {
140
+ label: 'Skipped (no change)',
141
+ value: 'skipped'
142
+ },
143
+ {
144
+ label: 'Reverted',
145
+ value: 'reverted'
146
+ }
147
+ ],
148
+ admin: {
149
+ readOnly: true
150
+ }
151
+ },
152
+ {
153
+ name: 'attempts',
154
+ type: 'number',
155
+ defaultValue: 0,
156
+ admin: {
157
+ readOnly: true
158
+ }
159
+ },
160
+ // Classifies the failure for retry policy + UI drill-down. The
161
+ // worker maps known errors to these classes; unknown errors fall
162
+ // back to `unknown`. Permanent classes never auto-retry.
163
+ {
164
+ name: 'failureCode',
165
+ type: 'select',
166
+ options: [
167
+ {
168
+ label: 'Transient — rate-limited',
169
+ value: 'transient.rate_limited'
170
+ },
171
+ {
172
+ label: 'Transient — provider 5xx',
173
+ value: 'transient.provider'
174
+ },
175
+ {
176
+ label: 'Transient — crashed (janitor)',
177
+ value: 'transient.crashed'
178
+ },
179
+ {
180
+ label: 'Permanent — schema invalid',
181
+ value: 'permanent.schema'
182
+ },
183
+ {
184
+ label: 'Permanent — too large',
185
+ value: 'permanent.too_large'
186
+ },
187
+ {
188
+ label: 'Permanent — auth/config',
189
+ value: 'permanent.config'
190
+ },
191
+ {
192
+ label: 'Permanent — doc deleted',
193
+ value: 'permanent.deleted'
194
+ },
195
+ {
196
+ label: 'Unknown',
197
+ value: 'unknown'
198
+ }
199
+ ],
200
+ admin: {
201
+ readOnly: true
202
+ }
203
+ },
204
+ {
205
+ name: 'failureMessage',
206
+ type: 'textarea',
207
+ admin: {
208
+ readOnly: true
209
+ }
210
+ },
211
+ {
212
+ name: 'preRunSnapshot',
213
+ type: 'json',
214
+ admin: {
215
+ readOnly: true,
216
+ description: 'TARGET-locale values of ONLY the localized translatable fields, captured by the worker just before its first write for this unit (v1.2.12+). Used by revert. Never the full doc — see F-SEC-SNAPSHOT. Rows written before v1.2.12 hold SOURCE-locale values (captured at enqueue) and are refused by revert — replaying them stamped source-language content over translated locales.'
217
+ }
218
+ },
219
+ {
220
+ // v1.2.12: which locale's values `preRunSnapshot` holds. Revert
221
+ // requires snapshotLocale === locale; legacy rows (null) are
222
+ // refused — their snapshots were captured from the SOURCE-locale
223
+ // enumeration read and replaying them destroys translations.
224
+ name: 'snapshotLocale',
225
+ type: 'text',
226
+ admin: {
227
+ readOnly: true
228
+ }
229
+ },
230
+ // Hash of the localized translatable fields' schema at snapshot
231
+ // time. Revert refuses if schema-hash differs at restore time
232
+ // unless the admin sets `force: true` (Decision #34 +
233
+ // F-DA-REVERT-SCHEMA). Prevents silent data drift when a field
234
+ // is renamed or removed between snapshot and revert.
235
+ {
236
+ name: 'schemaHash',
237
+ type: 'text',
238
+ admin: {
239
+ readOnly: true
240
+ }
241
+ },
242
+ {
243
+ name: 'costUsd',
244
+ type: 'number',
245
+ defaultValue: 0,
246
+ admin: {
247
+ readOnly: true
248
+ }
249
+ },
250
+ {
251
+ name: 'startedAt',
252
+ type: 'date',
253
+ admin: {
254
+ readOnly: true,
255
+ description: 'When the worker handler entered for this unit. Includes any pending-queue wait the unit served before being picked up.'
256
+ }
257
+ },
258
+ {
259
+ name: 'completedAt',
260
+ type: 'date',
261
+ admin: {
262
+ readOnly: true,
263
+ description: 'When the worker handler finished (success or terminal failure).'
264
+ }
265
+ },
266
+ {
267
+ // Real translation-call duration in milliseconds. Captured around
268
+ // the `translateApi.translateDocument(...)` call inside the worker —
269
+ // excludes token-bucket wait, provider rate-limit backoff, and
270
+ // queue scheduling. This is what the editor cares about: "how long
271
+ // did the AI actually spend on this." `completedAt - startedAt`
272
+ // includes throttle wait and is reported separately as
273
+ // wallclock-in-worker for engineering.
274
+ name: 'processingDurationMs',
275
+ type: 'number',
276
+ admin: {
277
+ readOnly: true,
278
+ description: 'Time the AI translation call itself took, in milliseconds. Excludes throttle / rate-limit wait — that gets folded into the difference between startedAt and completedAt instead.'
279
+ }
280
+ }
281
+ ],
282
+ indexes: [
283
+ // Composite index for the shouldSkipDocument-equivalent lookup at
284
+ // task entry + retry endpoint. The application-layer query is:
285
+ // findFirst WHERE collection=? AND documentId=? AND status IN
286
+ // ('pending','running')
287
+ // A partial unique index on the same predicate is added via raw
288
+ // SQL migration (F-DA-PARTIAL-IDX) — Payload's index generator
289
+ // doesn't emit partial uniqueness today.
290
+ //
291
+ // TODO(migration): hand-write the partial unique index as part
292
+ // of the v1.2.0 migrations bundle. Exact SQL:
293
+ //
294
+ // CREATE UNIQUE INDEX bulk_translate_units_active_dedup
295
+ // ON bulk_translate_units (collection, document_id, locale)
296
+ // WHERE status IN ('pending','running');
297
+ //
298
+ // Note the three-column uniqueness — `(collection, doc, locale)`,
299
+ // not `(collection, doc)`. Allows different locales for the same
300
+ // doc to run concurrently while serializing per-locale writes.
301
+ {
302
+ fields: [
303
+ 'collection',
304
+ 'documentId',
305
+ 'status'
306
+ ]
307
+ }
308
+ ]
309
+ };
310
+ }
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ type EstimatedCostCellProps = {
3
+ cellData?: number | null;
4
+ };
5
+ export declare function EstimatedCostCell({ cellData }: EstimatedCostCellProps): React.JSX.Element;
6
+ export {};
@@ -0,0 +1,12 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import React from 'react';
4
+ import { formatCost } from '../views/shared/format.js';
5
+ export function EstimatedCostCell({ cellData }) {
6
+ if (cellData === null || cellData === undefined) return /*#__PURE__*/ _jsx("span", {
7
+ children: "—"
8
+ });
9
+ return /*#__PURE__*/ _jsx("span", {
10
+ children: formatCost(cellData)
11
+ });
12
+ }
@@ -0,0 +1,45 @@
1
+ import type React from 'react';
2
+ type Props = {
3
+ /**
4
+ * Field path Payload assigns at render time, e.g.
5
+ * `perCollection.0.excludedFieldPaths`. We strip the trailing
6
+ * segment to address the sibling `slug` field of the same row.
7
+ */
8
+ path: string;
9
+ };
10
+ /**
11
+ * Custom admin component for `perCollection[i].excludedFieldPaths`.
12
+ *
13
+ * Stores an exclude-list (top-level field paths the admin opted OUT of
14
+ * translation). Rendered as a grouped list — one checkbox per
15
+ * top-level field on the surface. Unchecking a top-level field
16
+ * excludes EVERY descendant path under it (prefix-match in
17
+ * `isPathExcluded`).
18
+ *
19
+ * Design rationale:
20
+ *
21
+ * 1. **Editor mental model.** Editors think in terms of the fields
22
+ * they see in the doc editor ("Layout", "Meta"), not internal dot-
23
+ * paths. The earlier flat list of paths like
24
+ * `layout.columns.link.label` was technically correct but useless
25
+ * for non-developers.
26
+ * 2. **One checkbox per top-level field.** Coarse but predictable:
27
+ * "uncheck Layout" → nothing under `layout.*` is translated.
28
+ * Per-leaf exclusions are still expressible via direct DB writes
29
+ * or future per-field controls if needed; the common case is
30
+ * coverage at the section level.
31
+ * 3. **Disclosure of details.** A collapsible "Show 14 sub-paths"
32
+ * affordance reveals every descendant path the resolver found, so
33
+ * a developer / careful editor can verify what's actually
34
+ * affected. Read-only — not interactive.
35
+ * 4. **Exclude-list semantics.** Default = empty array = translate
36
+ * everything. New localized fields added later start "checked"
37
+ * automatically.
38
+ *
39
+ * Sibling slug derivation: Payload doesn't give the component direct
40
+ * access to its row neighbours, so we strip the trailing
41
+ * `.excludedFieldPaths` segment from `path` and append `.slug` to
42
+ * address the sibling.
43
+ */
44
+ export declare function ExcludedFieldsField({ path }: Props): React.JSX.Element;
45
+ export {};