@delmaredigital/payload-experiments 0.3.0-rc.4 → 0.4.0-rc.2

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 (299) hide show
  1. package/README.md +122 -27
  2. package/dist/admin/MetricSourceSelect.js +3 -3
  3. package/dist/admin/PlacementStatus.d.ts +3 -0
  4. package/dist/admin/PlacementStatus.js +54 -0
  5. package/dist/admin/PreviewLinks.d.ts +2 -1
  6. package/dist/admin/PreviewLinks.js +2 -2
  7. package/dist/admin/TestsDashboardCards.d.ts +1 -0
  8. package/dist/admin/TestsDashboardCards.js +4 -8
  9. package/dist/admin/TestsNavLink.d.ts +1 -0
  10. package/dist/admin/TestsNavLink.js +4 -10
  11. package/dist/admin/actions/ConfirmDialog.d.ts +2 -1
  12. package/dist/admin/actions/ConfirmDialog.js +2 -2
  13. package/dist/admin/actions/DecideDialog.d.ts +2 -1
  14. package/dist/admin/actions/DecideDialog.js +2 -2
  15. package/dist/admin/api.d.ts +18 -2
  16. package/dist/admin/api.js +47 -2
  17. package/dist/admin/blocks/BlockPanel.d.ts +4 -0
  18. package/dist/admin/blocks/BlockPanel.js +199 -0
  19. package/dist/admin/blocks/TestBlockField.d.ts +5 -0
  20. package/dist/admin/blocks/TestBlockField.js +163 -0
  21. package/dist/admin/blocks/formApi.d.ts +46 -0
  22. package/dist/admin/blocks/formApi.js +159 -0
  23. package/dist/admin/blocks/inject.d.ts +7 -0
  24. package/dist/admin/blocks/inject.js +41 -0
  25. package/dist/admin/blocks/model.d.ts +17 -0
  26. package/dist/admin/blocks/model.js +45 -0
  27. package/dist/admin/blocks/statusCache.d.ts +9 -0
  28. package/dist/admin/blocks/statusCache.js +92 -0
  29. package/dist/admin/blocks/useBlockForm.d.ts +17 -0
  30. package/dist/admin/blocks/useBlockForm.js +46 -0
  31. package/dist/admin/copy/actions.d.ts +2 -0
  32. package/dist/admin/copy/actions.js +9 -0
  33. package/dist/admin/copy/blocks.d.ts +43 -0
  34. package/dist/admin/copy/blocks.js +64 -0
  35. package/dist/admin/copy/common.d.ts +1 -0
  36. package/dist/admin/copy/common.js +1 -1
  37. package/dist/admin/copy/goals.d.ts +2 -0
  38. package/dist/admin/copy/goals.js +4 -1
  39. package/dist/admin/copy/newTest.d.ts +10 -0
  40. package/dist/admin/copy/newTest.js +10 -0
  41. package/dist/admin/copy/pages.d.ts +24 -0
  42. package/dist/admin/copy/pages.js +24 -0
  43. package/dist/admin/copy/readiness.d.ts +23 -3
  44. package/dist/admin/copy/readiness.js +24 -3
  45. package/dist/admin/copy/results.d.ts +1 -0
  46. package/dist/admin/copy/results.js +1 -0
  47. package/dist/admin/copy/testPage.d.ts +4 -0
  48. package/dist/admin/copy/testPage.js +4 -0
  49. package/dist/admin/goals/XpGoalField.d.ts +4 -0
  50. package/dist/admin/goals/XpGoalField.js +168 -0
  51. package/dist/admin/goals/xpGoalField.css +48 -0
  52. package/dist/admin/metricSource.model.d.ts +2 -0
  53. package/dist/admin/metricSource.model.js +4 -0
  54. package/dist/admin/pageCollections.d.ts +10 -0
  55. package/dist/admin/pageCollections.js +20 -0
  56. package/dist/admin/paths.d.ts +9 -0
  57. package/dist/admin/paths.js +9 -0
  58. package/dist/admin/placementStatus.model.d.ts +2 -0
  59. package/dist/admin/placementStatus.model.js +19 -0
  60. package/dist/admin/placements/placementLabels.d.ts +11 -0
  61. package/dist/admin/placements/placementLabels.js +21 -0
  62. package/dist/admin/placements/placementLabels.model.d.ts +13 -0
  63. package/dist/admin/placements/placementLabels.model.js +12 -0
  64. package/dist/admin/placements/usePlacementLabels.d.ts +12 -0
  65. package/dist/admin/placements/usePlacementLabels.js +102 -0
  66. package/dist/admin/results/DataQualityPanel.js +4 -1
  67. package/dist/admin/results/results.model.d.ts +3 -0
  68. package/dist/admin/results/results.model.js +8 -4
  69. package/dist/admin/surface/TestsHome.js +39 -10
  70. package/dist/admin/surface/TestsSurface.js +7 -6
  71. package/dist/admin/surface/contracts.d.ts +6 -5
  72. package/dist/admin/surface/goals/GoalForm.js +71 -44
  73. package/dist/admin/surface/goals/GoalsList.js +5 -4
  74. package/dist/admin/surface/goals/data.js +4 -1
  75. package/dist/admin/surface/goals/goals.model.d.ts +1 -2
  76. package/dist/admin/surface/goals/goals.model.js +1 -3
  77. package/dist/admin/surface/home.model.d.ts +3 -3
  78. package/dist/admin/surface/home.model.js +8 -4
  79. package/dist/admin/surface/newTest/NewTest.js +56 -17
  80. package/dist/admin/surface/newTest/PageWizard.d.ts +7 -0
  81. package/dist/admin/surface/newTest/PageWizard.js +214 -0
  82. package/dist/admin/surface/pagePicker/CopyRoute.d.ts +6 -0
  83. package/dist/admin/surface/pagePicker/CopyRoute.js +53 -0
  84. package/dist/admin/surface/pagePicker/PageCombobox.d.ts +10 -0
  85. package/dist/admin/surface/pagePicker/PageCombobox.js +395 -0
  86. package/dist/admin/surface/pagePicker/pagePicker.css +10 -0
  87. package/dist/admin/surface/pagePicker/pagePicker.model.d.ts +27 -0
  88. package/dist/admin/surface/pagePicker/pagePicker.model.js +25 -0
  89. package/dist/admin/surface/readiness/ActionDialogs.js +99 -64
  90. package/dist/admin/surface/readiness/Banner.js +30 -6
  91. package/dist/admin/surface/readiness/readiness.model.d.ts +8 -1
  92. package/dist/admin/surface/readiness/readiness.model.js +92 -9
  93. package/dist/admin/surface/results/ReleasePages.d.ts +3 -1
  94. package/dist/admin/surface/results/ReleasePages.js +3 -7
  95. package/dist/admin/surface/results/ResultsBody.js +21 -2
  96. package/dist/admin/surface/results/ResultsHeader.js +5 -13
  97. package/dist/admin/surface/results/useResults.d.ts +20 -1
  98. package/dist/admin/surface/test/AdvancedSection.js +111 -104
  99. package/dist/admin/surface/test/GoalSection.js +94 -14
  100. package/dist/admin/surface/test/LengthSection.js +1 -1
  101. package/dist/admin/surface/test/PageHoldout.d.ts +3 -0
  102. package/dist/admin/surface/test/PageHoldout.js +67 -0
  103. package/dist/admin/surface/test/TestPage.js +5 -9
  104. package/dist/admin/surface/test/VersionsSection.js +12 -5
  105. package/dist/admin/surface/test/fields.d.ts +13 -4
  106. package/dist/admin/surface/test/fields.js +46 -14
  107. package/dist/admin/surface/test/jumpToSection.d.ts +1 -1
  108. package/dist/admin/surface/test/jumpToSection.js +4 -3
  109. package/dist/admin/surface/test/pageParts.d.ts +4 -1
  110. package/dist/admin/surface/test/pageParts.js +49 -1
  111. package/dist/admin/surface/test/testPage.css +3 -1
  112. package/dist/admin/surface/testDocument.model.d.ts +1 -0
  113. package/dist/admin/surface/testDocument.model.js +2 -1
  114. package/dist/admin/surface/useTestDocument.d.ts +15 -2
  115. package/dist/admin/surface/useTestDocument.js +53 -15
  116. package/dist/admin/surfaceUrls.d.ts +7 -0
  117. package/dist/admin/surfaceUrls.js +19 -0
  118. package/dist/admin/theme.css +2 -0
  119. package/dist/admin/useApi.d.ts +21 -2
  120. package/dist/admin/useApi.js +3 -5
  121. package/dist/admin/views/CollectionListRedirect.d.ts +1 -0
  122. package/dist/admin/views/CollectionListRedirect.js +1 -1
  123. package/dist/admin/views/ExperimentsRootView.js +28 -133
  124. package/dist/admin/views/GoalEditRedirect.d.ts +4 -0
  125. package/dist/admin/views/GoalEditRedirect.js +14 -0
  126. package/dist/admin/views/GoalsCollectionListView.d.ts +2 -0
  127. package/dist/admin/views/GoalsCollectionListView.js +4 -0
  128. package/dist/admin/views/TestsCollectionListView.d.ts +2 -0
  129. package/dist/admin/views/TestsCollectionListView.js +4 -0
  130. package/dist/admin/views/TestsNavLinkServer.d.ts +1 -0
  131. package/dist/admin/views/TestsNavLinkServer.js +1 -1
  132. package/dist/admin/views/buildSurfaceProps.d.ts +8 -0
  133. package/dist/admin/views/buildSurfaceProps.js +143 -0
  134. package/dist/admin/views/renderCollectionList.d.ts +2 -0
  135. package/dist/admin/views/renderCollectionList.js +34 -0
  136. package/dist/admin/views/renderTestsSurface.d.ts +3 -0
  137. package/dist/admin/views/renderTestsSurface.js +34 -0
  138. package/dist/blocks/bindings.d.ts +3 -0
  139. package/dist/blocks/bindings.js +34 -0
  140. package/dist/blocks/createExperimentBlock.d.ts +6 -0
  141. package/dist/blocks/createExperimentBlock.js +77 -0
  142. package/dist/blocks/formState.d.ts +31 -0
  143. package/dist/blocks/formState.js +146 -0
  144. package/dist/blocks/model.d.ts +41 -0
  145. package/dist/blocks/model.js +34 -0
  146. package/dist/client/ExperimentGroup.d.ts +6 -0
  147. package/dist/client/ExperimentGroup.js +9 -0
  148. package/dist/client/ExperimentsProvider.js +20 -4
  149. package/dist/client/clickGoals.d.ts +4 -0
  150. package/dist/client/clickGoals.js +43 -0
  151. package/dist/collections/experiments/config.js +21 -7
  152. package/dist/collections/experiments/deleteGuard.d.ts +2 -1
  153. package/dist/collections/experiments/deleteGuard.js +12 -1
  154. package/dist/collections/experiments/editability.js +4 -2
  155. package/dist/collections/experiments/pickSlug.d.ts +2 -0
  156. package/dist/collections/experiments/pickSlug.js +8 -0
  157. package/dist/collections/labels.d.ts +3 -0
  158. package/dist/collections/labels.js +20 -0
  159. package/dist/collections/metrics.js +28 -6
  160. package/dist/collections/phases.js +1 -0
  161. package/dist/collections/serialize.js +7 -0
  162. package/dist/db/clickGoals.d.ts +9 -0
  163. package/dist/db/clickGoals.js +22 -0
  164. package/dist/db/delete.d.ts +1 -0
  165. package/dist/db/delete.js +1 -0
  166. package/dist/db/locks.d.ts +8 -0
  167. package/dist/db/locks.js +27 -4
  168. package/dist/db/names.d.ts +4 -0
  169. package/dist/db/names.js +4 -0
  170. package/dist/db/pageBindings.d.ts +4 -0
  171. package/dist/db/pageBindings.js +17 -0
  172. package/dist/db/pageBusy.d.ts +2 -0
  173. package/dist/db/pageBusy.js +10 -0
  174. package/dist/db/pageContent.d.ts +10 -0
  175. package/dist/db/pageContent.js +79 -0
  176. package/dist/db/placements.d.ts +33 -0
  177. package/dist/db/placements.js +54 -0
  178. package/dist/db/slugs.d.ts +8 -0
  179. package/dist/db/slugs.js +40 -0
  180. package/dist/db/snapshots.d.ts +6 -0
  181. package/dist/db/snapshots.js +8 -5
  182. package/dist/endpoints/clickKeys.d.ts +5 -0
  183. package/dist/endpoints/clickKeys.js +17 -0
  184. package/dist/endpoints/events.js +4 -1
  185. package/dist/endpoints/index.js +28 -0
  186. package/dist/endpoints/pages.d.ts +5 -0
  187. package/dist/endpoints/pages.js +120 -0
  188. package/dist/endpoints/placementStatus.d.ts +6 -0
  189. package/dist/endpoints/placementStatus.js +238 -0
  190. package/dist/endpoints/readBody.d.ts +2 -0
  191. package/dist/endpoints/readBody.js +24 -0
  192. package/dist/endpoints/results.js +5 -1
  193. package/dist/endpoints/summary.js +11 -4
  194. package/dist/endpoints/wrapBlock.d.ts +6 -0
  195. package/dist/endpoints/wrapBlock.js +76 -0
  196. package/dist/errors.d.ts +3 -3
  197. package/dist/errors.js +4 -4
  198. package/dist/events/rows.d.ts +1 -1
  199. package/dist/events/rows.js +5 -3
  200. package/dist/exports/adminClient.d.ts +5 -0
  201. package/dist/exports/adminClient.js +5 -0
  202. package/dist/exports/adminRsc.d.ts +3 -0
  203. package/dist/exports/adminRsc.js +3 -0
  204. package/dist/exports/blocks.d.ts +2 -0
  205. package/dist/exports/blocks.js +1 -0
  206. package/dist/exports/client.d.ts +1 -0
  207. package/dist/exports/client.js +1 -0
  208. package/dist/exports/index.d.ts +6 -1
  209. package/dist/exports/index.js +3 -0
  210. package/dist/exports/puck.d.ts +3 -1
  211. package/dist/exports/puck.js +2 -0
  212. package/dist/exports/puckEditor.d.ts +3 -0
  213. package/dist/exports/puckEditor.js +2 -0
  214. package/dist/exports/rsc.d.ts +3 -0
  215. package/dist/exports/rsc.js +2 -0
  216. package/dist/fields/xpGoal.d.ts +3 -0
  217. package/dist/fields/xpGoal.js +16 -0
  218. package/dist/globals/state.js +10 -0
  219. package/dist/goals/cache.d.ts +3 -0
  220. package/dist/goals/cache.js +35 -0
  221. package/dist/goals/fairness.d.ts +40 -0
  222. package/dist/goals/fairness.js +200 -0
  223. package/dist/goals/key.d.ts +4 -0
  224. package/dist/goals/key.js +3 -0
  225. package/dist/goals/picker/clickGoalPicker.model.d.ts +29 -0
  226. package/dist/goals/picker/clickGoalPicker.model.js +45 -0
  227. package/dist/goals/picker/copy.d.ts +16 -0
  228. package/dist/goals/picker/copy.js +15 -0
  229. package/dist/goals/picker/useClickGoalPicker.d.ts +30 -0
  230. package/dist/goals/picker/useClickGoalPicker.js +220 -0
  231. package/dist/goals/validate.d.ts +3 -0
  232. package/dist/goals/validate.js +14 -0
  233. package/dist/hooks/pageGuard.d.ts +5 -1
  234. package/dist/hooks/pageGuard.js +157 -95
  235. package/dist/hooks/puckGoals.d.ts +3 -0
  236. package/dist/hooks/puckGoals.js +38 -0
  237. package/dist/onInit.js +29 -0
  238. package/dist/options.d.ts +2 -0
  239. package/dist/options.js +41 -1
  240. package/dist/plugin.js +50 -43
  241. package/dist/puck/copy.d.ts +1 -0
  242. package/dist/puck/copy.js +1 -0
  243. package/dist/puck/editor/editor.chrome.css +14 -0
  244. package/dist/puck/editor/editor.css +106 -0
  245. package/dist/puck/editor/editor.model.d.ts +4 -2
  246. package/dist/puck/editor/editor.model.js +6 -3
  247. package/dist/puck/editor/integration.d.ts +10 -0
  248. package/dist/puck/editor/integration.js +30 -0
  249. package/dist/puck/editor/xpGoalPuckEditorField.d.ts +7 -0
  250. package/dist/puck/editor/xpGoalPuckEditorField.js +142 -0
  251. package/dist/puck/integration.d.ts +6 -0
  252. package/dist/puck/integration.js +21 -0
  253. package/dist/puck/xpGoalField.d.ts +3 -0
  254. package/dist/puck/xpGoalField.js +6 -0
  255. package/dist/results/health.d.ts +4 -0
  256. package/dist/results/health.js +27 -0
  257. package/dist/results/snapshot.js +15 -2
  258. package/dist/sanitizeReadinessDetail.js +43 -0
  259. package/dist/server/pageKindSeoContract.d.ts +27 -0
  260. package/dist/server/pageKindSeoContract.js +80 -0
  261. package/dist/server/recordContentChange.js +58 -8
  262. package/dist/server/resolveExperimentBlocks.d.ts +5 -0
  263. package/dist/server/resolveExperimentBlocks.js +54 -0
  264. package/dist/server/runResults.js +56 -15
  265. package/dist/server/toClientAssignments.js +2 -1
  266. package/dist/transitions/addMetric.d.ts +2 -1
  267. package/dist/transitions/addMetric.js +28 -1
  268. package/dist/transitions/checkStart.d.ts +14 -1
  269. package/dist/transitions/checkStart.js +92 -8
  270. package/dist/transitions/decide.js +25 -0
  271. package/dist/transitions/deleteExperiment.d.ts +3 -1
  272. package/dist/transitions/deleteExperiment.js +27 -1
  273. package/dist/transitions/kernel.js +4 -0
  274. package/dist/transitions/makeContent.d.ts +5 -0
  275. package/dist/transitions/makeContent.js +39 -11
  276. package/dist/transitions/pageCollection.d.ts +10 -0
  277. package/dist/transitions/pageCollection.js +20 -0
  278. package/dist/transitions/pageVersions.d.ts +10 -0
  279. package/dist/transitions/pageVersions.js +44 -0
  280. package/dist/transitions/phaseRecord.d.ts +1 -0
  281. package/dist/transitions/placementInteractions.d.ts +40 -0
  282. package/dist/transitions/placementInteractions.js +94 -0
  283. package/dist/transitions/placements.d.ts +8 -0
  284. package/dist/transitions/placements.js +148 -1
  285. package/dist/transitions/preflightData.d.ts +2 -2
  286. package/dist/transitions/preflightData.js +137 -5
  287. package/dist/transitions/resolveCaps.d.ts +1 -0
  288. package/dist/transitions/resolveCaps.js +6 -2
  289. package/dist/transitions/start.js +46 -1
  290. package/dist/types/admin.d.ts +1 -1
  291. package/dist/types/assignments.d.ts +1 -0
  292. package/dist/types/contracts.d.ts +15 -0
  293. package/dist/types/endpoints.d.ts +92 -5
  294. package/dist/types/index.d.ts +3 -0
  295. package/dist/types/puck.d.ts +7 -1
  296. package/dist/types/snapshot.d.ts +17 -4
  297. package/dist/types/surface.d.ts +13 -0
  298. package/dist/ui/ui.css +4 -0
  299. package/package.json +8 -1
@@ -7,8 +7,10 @@ import { jumpToSection } from '../test/jumpToSection.js';
7
7
  import { actionGroupLabel, availableActions } from '../../actions/actions.model.js';
8
8
  import { createApi } from '../../api.js';
9
9
  import { READINESS_COPY as C, decidedCopy, nextCopy, runningCopy, stoppedCopy } from '../../copy/readiness.js';
10
- import { READINESS, daysRemaining, displayDate, nextStep } from './readiness.model.js';
10
+ import { READINESS, daysRemaining, displayDate, nextStep, pageReadinessContext } from './readiness.model.js';
11
11
  import { AddMetricAction, AllocateAction, ConfirmAction } from './ActionDialogs.js';
12
+ import { preflightPlacementLabel } from '../../placements/placementLabels.js';
13
+ import { placementUncheckedCopy } from '../../copy/readiness.js';
12
14
  import { useTransition } from './useTransition.js';
13
15
  const RUNNING_ACTIONS = [
14
16
  'stop',
@@ -49,10 +51,17 @@ export function ReadinessContent({ test, surface, resultsVersion, bar = false })
49
51
  ]);
50
52
  const decision = doc.decision;
51
53
  const winner = actionGroupLabel(decision?.winnerArm ?? 'control', doc.arms.find((item)=>item.key === decision?.winnerArm)?.label);
52
- const next = nextStep(test.preflight, {
53
- ...doc,
54
- flagPoints: surface.flagPoints
55
- });
54
+ const labelledPreflight = test.preflight ? {
55
+ ...test.preflight,
56
+ checks: test.preflight.checks.map((check)=>check.code === 'placement-unchecked' ? {
57
+ ...check,
58
+ detail: {
59
+ ...check.detail,
60
+ title: preflightPlacementLabel(check.detail, test.preflight, surface.adminRoute).title
61
+ }
62
+ } : check)
63
+ } : null;
64
+ const next = nextStep(labelledPreflight, pageReadinessContext(doc, test.preflight, surface));
56
65
  const setup = doc.status === 'draft' || doc.status === 'stopped';
57
66
  const ready = Boolean(test.preflight && !test.preflightPending && !test.preflightError && test.preflight.checks.every((check)=>check.ok));
58
67
  const unsaved = test.hasUnsaved || test.saving === 'saving';
@@ -96,7 +105,7 @@ export function ReadinessContent({ test, surface, resultsVersion, bar = false })
96
105
  href: `#section-${next.section}`,
97
106
  onClick: (event)=>{
98
107
  event.preventDefault();
99
- if (next.section !== 'header') jumpToSection(next.section);
108
+ if (next.section !== 'header') jumpToSection(next.section, next.arm);
100
109
  },
101
110
  children: [
102
111
  sentence,
@@ -119,6 +128,21 @@ export function ReadinessContent({ test, surface, resultsVersion, bar = false })
119
128
  test.preflight?.checks.filter((check)=>check.code === 'make-content-unsupported' && check.warning).map((check)=>/*#__PURE__*/ _jsx("p", {
120
129
  children: READINESS[check.code].next(check.detail, doc)
121
130
  }, check.code)),
131
+ test.preflight?.checks.filter((check)=>check.warning && [
132
+ 'goal-in-some-versions',
133
+ 'placement-unchecked'
134
+ ].includes(check.code)).map((check, index)=>{
135
+ const placement = check.code === 'placement-unchecked' ? preflightPlacementLabel(check.detail, test.preflight, surface.adminRoute) : undefined;
136
+ return /*#__PURE__*/ _jsx("p", {
137
+ children: placement ? placement.href ? /*#__PURE__*/ _jsx("a", {
138
+ href: placement.href,
139
+ children: placementUncheckedCopy(placement.title)
140
+ }) : placementUncheckedCopy(placement.title) : READINESS[check.code].next(check.detail, doc)
141
+ }, `${check.code}:${index}`);
142
+ }),
143
+ test.preflight?.goalNotes?.map((note)=>/*#__PURE__*/ _jsx("p", {
144
+ children: note.message
145
+ }, note.metricId)),
122
146
  doc.status === 'stopped' ? /*#__PURE__*/ _jsx("p", {
123
147
  children: stoppedCopy(displayDate(doc.stoppedAt))
124
148
  }) : null,
@@ -1,18 +1,22 @@
1
1
  import type { ReadinessCode, PreflightResult } from '../../../types/endpoints.js';
2
2
  import type { SerializedFlagPoint } from '../../../types/admin.js';
3
3
  import type { TestDocument } from '../testDocument.model.js';
4
+ import type { SurfaceProps } from '../contracts.js';
4
5
  import { type SectionId } from '../contracts.js';
5
6
  export type ReadinessContext = Pick<TestDocument, 'arms' | 'unitType' | 'flagPoint'> & {
7
+ collectionLabel?: string;
8
+ pagePlacements?: PreflightResult['pagePlacements'];
6
9
  flagPoints?: readonly Pick<SerializedFlagPoint, 'id' | 'params'>[];
7
10
  };
8
11
  /** Exhaustive mapping of the checkStart ReadinessCode union, including all ten invariant checks. */
9
12
  export declare const READINESS: Record<ReadinessCode, {
10
13
  section: SectionId | 'header';
11
14
  next(detail: unknown, ctx: ReadinessContext): string | null;
12
- nextStep?: string;
15
+ nextStep?: string | ((detail: unknown, ctx: ReadinessContext) => string);
13
16
  }>;
14
17
  export declare function nextStep(preflight: PreflightResult | null, ctx: ReadinessContext): {
15
18
  nextStep?: string | undefined;
19
+ arm?: import("../../../types/contracts.js").ArmKey | undefined;
16
20
  section: "header" | SectionId;
17
21
  sentence: string;
18
22
  code: ReadinessCode;
@@ -22,3 +26,6 @@ export declare function sectionDone(test: {
22
26
  }): Record<SectionId, boolean>;
23
27
  export declare function displayDate(value: unknown): string | null;
24
28
  export declare function daysRemaining(doc: TestDocument, now: number): number | null;
29
+ export declare function pageReadinessContext(doc: TestDocument, preflight: PreflightResult | null, surface: SurfaceProps): ReadinessContext;
30
+ /** First affected row in arm order; shared by the wizard and the test-page jump. */
31
+ export declare function readinessArm(code: ReadinessCode, detail: unknown, ctx: ReadinessContext): import("../../../types/contracts.js").ArmKey | undefined;
@@ -1,6 +1,9 @@
1
+ import { SURFACE_COPY } from '../../copy/surface.js';
1
2
  import { formatDate } from '../../format/date.js';
2
3
  import { actionGroupLabel } from '../../actions/actions.model.js';
3
- import { unsupportedContentCopy, versionPageUnavailableCopy, versionPageUncheckedCopy, placementFailureCopy, pageInUseCopy, unpublishedPageCopy, READINESS_COPY as C, attributeNext, contentNext, goalPeopleNext, parameterNext, placementNext, ruleNext, versionsNext } from '../../copy/readiness.js';
4
+ import { asymmetricGoalsCopy, placementUncheckedCopy, interactingTestsCopy, sameAddressCopy, identicalVersionCopy, unsupportedContentCopy, versionPageUnavailableCopy, versionPageUncheckedCopy, placementFailureCopy, pageInUseCopy, unpublishedPageCopy, READINESS_COPY as C, attributeNext, contentNext, goalPeopleNext, parameterNext, placementNext, ruleNext, versionsNext } from '../../copy/readiness.js';
5
+ import { normalisePath } from '../../../runtime/normalisePath.js';
6
+ import { testPageCollection } from '../pagePicker/pagePicker.model.js';
4
7
  import { SECTION_ORDER } from '../contracts.js';
5
8
  const object = (value)=>value && typeof value === 'object' && !Array.isArray(value) ? value : {};
6
9
  const first = (value)=>object(Array.isArray(value) ? value[0] : value);
@@ -17,8 +20,31 @@ const row = (section, next)=>({
17
20
  const versions = row('versions', (detail)=>versionsNext(detailText(detail, C.versionFallback)));
18
21
  /** Exhaustive mapping of the checkStart ReadinessCode union, including all ten invariant checks. */ export const READINESS = {
19
22
  'make-content-unsupported': row('header', (detail)=>unsupportedContentCopy(text(detail, 'This page'))),
23
+ 'goal-in-some-versions': {
24
+ ...row('win', (detail)=>asymmetricGoalsCopy(detail)),
25
+ nextStep: 'Edit the versions'
26
+ },
27
+ 'placement-unchecked': {
28
+ ...row('versions', (detail)=>placementUncheckedCopy(text(object(detail).title ?? object(detail).path, 'This page'))),
29
+ nextStep: (detail)=>`Open ${text(object(detail).title ?? object(detail).path, 'the page')}`
30
+ },
20
31
  'invalid-status': row('header', ()=>null),
21
32
  'no-placements': row('what', (detail)=>detail === undefined ? C.noPlacements : placementFailureCopy(detail)),
33
+ 'placement-removed': row('what', ()=>C.placementRemoved),
34
+ 'placement-unpublished': {
35
+ ...row('versions', (detail)=>(Array.isArray(detail) && detail.length ? detail : [
36
+ detail
37
+ ]).map((placement)=>`The block you're testing is only on a draft of ${text(object(placement).title, 'this page')}. Publish the page before you start.`).join('\n')),
38
+ nextStep: 'Publish the page'
39
+ },
40
+ 'duplicate-version-row': {
41
+ ...row('versions', (detail)=>`The Experiment block on ${text(first(detail).title, 'this page')} has the same version twice. Remove one of them, then save.`),
42
+ nextStep: (detail)=>`Edit ${text(first(detail).title, 'this page')}`
43
+ },
44
+ 'interacting-tests': {
45
+ ...row('versions', (detail)=>interactingTestsCopy(text(first(detail).path, 'this page'), text(first(detail).status, 'running'), text(first(detail).name, 'another test'), first(detail).version === true)),
46
+ nextStep: (detail)=>`Open ${text(first(detail).name, 'the test')}${first(detail).version === true ? `\nEdit ${text(first(detail).path, 'this page')}` : ''}`
47
+ },
22
48
  'empty-slot': row('versions', (detail, ctx)=>{
23
49
  const placements = Array.isArray(detail) ? detail : [];
24
50
  const missing = ctx.arms.find((item)=>item.kind !== 'holdout' && placements.some((placement)=>{
@@ -50,14 +76,39 @@ const versions = row('versions', (detail)=>versionsNext(detailText(detail, C.ver
50
76
  'layer-full': row('versions', ()=>C.full),
51
77
  'layer-unit-mismatch': row('header', ()=>C.differentPeople),
52
78
  'page-in-use': {
53
- ...row('versions', (detail)=>{
79
+ ...row('versions', (detail, ctx)=>{
54
80
  const paths = object(detail).paths;
55
- return pageInUseCopy(text(Array.isArray(paths) ? paths[0] : undefined, 'this page'));
81
+ const path = text(Array.isArray(paths) ? paths[0] : undefined, 'this page');
82
+ return pageInUseCopy(path, pageArm(path, ctx)?.kind === 'variant');
56
83
  }),
57
- nextStep: C.chooseDifferentPage
84
+ nextStep: C.choosePages
85
+ },
86
+ 'page-no-targets': {
87
+ ...row('versions', ()=>C.noTargets),
88
+ nextStep: 'Choose pages'
89
+ },
90
+ 'unknown-collection': row('versions', ()=>"That page type isn't set up for tests."),
91
+ 'version-identical': {
92
+ ...row('versions', (detail, ctx)=>identicalVersionCopy(text(object(detail).path, object(detail).title ? `${group(object(detail).arm, ctx)} on ${text(object(detail).title, 'this page')}` : group(object(detail).arm, ctx)))),
93
+ nextStep: (detail, ctx)=>`Edit ${text(object(detail).path, group(object(detail).arm, ctx))}`
94
+ },
95
+ 'version-same-address': {
96
+ ...row('versions', (detail, ctx)=>sameAddressCopy(group(object(detail).arm, ctx), group(object(detail).otherArm, ctx), text(object(detail).path, 'this address'), ctx.collectionLabel)),
97
+ nextStep: 'Choose pages'
98
+ },
99
+ 'page-target-unpublished': {
100
+ ...row('versions', (detail, ctx)=>{
101
+ const path = text(typeof detail === 'string' ? detail : object(detail).path, 'This page');
102
+ const arm = ctx.arms.find((item)=>item.key === object(detail).arm) ?? pageArm(path, ctx);
103
+ const placement = (arm ? ctx.pagePlacements?.find((entry)=>entry.arm === arm.key) : undefined) ?? ctx.pagePlacements?.find((entry)=>normalisePath(entry.path) === normalisePath(path));
104
+ return unpublishedPageCopy(path, ctx.pagePlacements && ctx.collectionLabel ? {
105
+ original: arm?.kind === 'control',
106
+ found: placement?.id != null && placement.published === false,
107
+ collection: ctx.collectionLabel
108
+ } : undefined);
109
+ }),
110
+ nextStep: C.choosePages
58
111
  },
59
- 'page-no-targets': row('versions', ()=>C.noTargets),
60
- 'page-target-unpublished': row('versions', (detail)=>unpublishedPageCopy(text(detail, 'This page'))),
61
112
  'page-targets-unchecked': row('versions', ()=>C.uncheckedPages),
62
113
  'version-page-unavailable': row('versions', (detail)=>versionPageUnavailableCopy(text(detail, 'This page'))),
63
114
  'version-page-unchecked': row('versions', (detail)=>versionPageUncheckedCopy(text(detail, 'This page'))),
@@ -91,15 +142,28 @@ export function nextStep(preflight, ctx) {
91
142
  ...SECTION_ORDER
92
143
  ]){
93
144
  for (const check of preflight?.checks ?? []){
145
+ if (!Object.hasOwn(READINESS, check.code)) {
146
+ if (!check.ok && section === SECTION_ORDER[0]) return {
147
+ section,
148
+ sentence: SURFACE_COPY.next,
149
+ code: check.code
150
+ };
151
+ continue;
152
+ }
94
153
  const mapping = READINESS[check.code];
95
154
  if (check.ok || mapping.section !== section) continue;
96
155
  const sentence = mapping.next(check.detail, ctx);
156
+ const nextStep = typeof mapping.nextStep === 'function' ? mapping.nextStep(check.detail, ctx) : mapping.nextStep;
157
+ const arm = readinessArm(check.code, check.detail, ctx);
97
158
  if (sentence) return {
98
159
  section,
99
160
  sentence,
100
161
  code: check.code,
101
- ...mapping.nextStep ? {
102
- nextStep: mapping.nextStep
162
+ ...arm ? {
163
+ arm
164
+ } : {},
165
+ ...nextStep ? {
166
+ nextStep
103
167
  } : {}
104
168
  };
105
169
  }
@@ -109,7 +173,7 @@ export function nextStep(preflight, ctx) {
109
173
  export function sectionDone(test) {
110
174
  return Object.fromEntries(SECTION_ORDER.map((section)=>[
111
175
  section,
112
- test.preflight ? !test.preflight.checks.some((check)=>!check.ok && READINESS[check.code].section === section) : section === 'who' || section === 'advanced'
176
+ test.preflight ? !test.preflight.checks.some((check)=>!check.ok && (Object.hasOwn(READINESS, check.code) ? READINESS[check.code].section : SECTION_ORDER[0]) === section) : section === 'who' || section === 'advanced'
113
177
  ]));
114
178
  }
115
179
  export function displayDate(value) {
@@ -121,3 +185,22 @@ export function daysRemaining(doc, now) {
121
185
  const start = typeof doc.startedAt === 'string' ? Date.parse(doc.startedAt) : NaN;
122
186
  return typeof days === 'number' && days > 0 && Number.isFinite(start) ? Math.max(0, Math.ceil(days - (now - start) / 86_400_000)) : null;
123
187
  }
188
+ function pageArm(path, ctx) {
189
+ return ctx.arms.find((arm)=>arm.pageTarget && normalisePath(arm.pageTarget) === normalisePath(path));
190
+ }
191
+ export function pageReadinessContext(doc, preflight, surface) {
192
+ return {
193
+ ...doc,
194
+ flagPoints: surface.flagPoints,
195
+ pagePlacements: preflight?.pagePlacements,
196
+ collectionLabel: testPageCollection(surface.pageCollections, doc, preflight?.pagePlacements)?.label
197
+ };
198
+ }
199
+ /** First affected row in arm order; shared by the wizard and the test-page jump. */ export function readinessArm(code, detail, ctx) {
200
+ if (code === 'version-same-address') return ctx.arms.find((arm)=>arm.key === object(detail).arm)?.key;
201
+ if (code === 'page-no-targets') return ctx.arms.find((arm)=>arm.kind !== 'holdout' && !arm.pageTarget)?.key;
202
+ const paths = code === 'page-in-use' ? object(detail).paths : code === 'page-target-unpublished' ? [
203
+ detail
204
+ ] : [];
205
+ return ctx.arms.find((arm)=>arm.kind !== 'holdout' && arm.pageTarget && Array.isArray(paths) && paths.some((path)=>typeof path === 'string' && normalisePath(path) === normalisePath(arm.pageTarget)))?.key;
206
+ }
@@ -8,7 +8,9 @@ export declare function ReleasePagesDialog({ id, apiRoute, onClose, onSuccess, o
8
8
  onRefusal(message: string): void;
9
9
  }): import("react").JSX.Element;
10
10
  /** An inaccessible or deleted author never hides the recorded release date. */
11
- export declare function PagesReleased({ decision, apiRoute }: {
11
+ export declare function PagesReleased({ decision, apiRoute, userId, userCollection: collection }: {
12
12
  decision: PageReleaseDecision;
13
13
  apiRoute: string;
14
+ userId?: DocId;
15
+ userCollection?: string;
14
16
  }): import("react").JSX.Element;
@@ -1,7 +1,6 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useEffect, useRef, useState } from 'react';
4
- import { useAuth, useConfig } from '@payloadcms/ui';
5
4
  import { Button } from '../../../ui/Button.js';
6
5
  import { Dialog } from '../../../ui/Dialog.js';
7
6
  import { createApi } from '../../api.js';
@@ -63,10 +62,7 @@ export function ReleasePagesDialog({ id, apiRoute, onClose, onSuccess, onRefusal
63
62
  ]
64
63
  });
65
64
  }
66
- /** An inaccessible or deleted author never hides the recorded release date. */ export function PagesReleased({ decision, apiRoute }) {
67
- const { user } = useAuth();
68
- const { config } = useConfig();
69
- const collection = config.admin.user;
65
+ /** An inaccessible or deleted author never hides the recorded release date. */ export function PagesReleased({ decision, apiRoute, userId, userCollection: collection }) {
70
66
  const by = decision.pagesReleasedBy;
71
67
  const [resolved, setResolved] = useState(null);
72
68
  const key = JSON.stringify([
@@ -74,7 +70,7 @@ export function ReleasePagesDialog({ id, apiRoute, onClose, onSuccess, onRefusal
74
70
  collection,
75
71
  by
76
72
  ]);
77
- const own = pagesReleasedBy(by, user?.id);
73
+ const own = pagesReleasedBy(by, userId);
78
74
  useEffect(()=>{
79
75
  if (!by || own || !collection) return;
80
76
  const controller = new AbortController();
@@ -109,7 +105,7 @@ export function ReleasePagesDialog({ id, apiRoute, onClose, onSuccess, onRefusal
109
105
  key,
110
106
  own
111
107
  ]);
112
- const name = own ?? pagesReleasedBy(by, user?.id, resolved?.key === key ? resolved.author : null);
108
+ const name = own ?? pagesReleasedBy(by, userId, resolved?.key === key ? resolved.author : null);
113
109
  return /*#__PURE__*/ _jsx("p", {
114
110
  children: pagesReleasedCopy(formatDate(decision.pagesReleasedAt), name)
115
111
  });
@@ -27,6 +27,7 @@ import { DecideDialog } from '../../actions/DecideDialog.js';
27
27
  import { Banner } from '../../../ui/Banner.js';
28
28
  import { canReleasePages } from '../../results/releasePages.model.js';
29
29
  import { PagesReleased, ReleasePagesDialog } from './ReleasePages.js';
30
+ import { usePlacementLabels } from '../../placements/usePlacementLabels.js';
30
31
  export function ResultsBody({ id, surface, onRecomputed, onPagesReleased, renderPage }) {
31
32
  // A different test owns an independent selection and action lifecycle.
32
33
  return /*#__PURE__*/ _jsx(ResultsContent, {
@@ -116,12 +117,20 @@ function ResultsContent({ id, surface, onRecomputed, onPagesReleased, renderPage
116
117
  isDecidedTestRound,
117
118
  winnerLabel: winner
118
119
  }) : null;
120
+ const placementLabels = usePlacementLabels({
121
+ details: shown?.health?.filter((item)=>item.code === 'placement-unchecked').map((item)=>item.detail) ?? [],
122
+ apiRoute: surface.apiRoute,
123
+ adminRoute: surface.adminRoute,
124
+ canManage: manage,
125
+ collectionTitles: surface.collectionTitles
126
+ });
119
127
  const context = {
120
128
  status,
121
129
  phase,
122
130
  inLayer: doc?.layer != null,
123
131
  layerSlices: doc?.layerSlices,
124
- allocation: doc?.allocation
132
+ allocation: doc?.allocation,
133
+ placementLabels
125
134
  };
126
135
  const primary = phase?.metrics.find((metric)=>metric.role === 'primary');
127
136
  // The endpoint decides the current round; historical rounds are read-only.
@@ -147,7 +156,9 @@ function ResultsContent({ id, surface, onRecomputed, onPagesReleased, renderPage
147
156
  // Release details come only from the manager's own document, never the results response.
148
157
  const released = manage && doc?.decision?.pagesReleasedAt ? /*#__PURE__*/ _jsx(PagesReleased, {
149
158
  decision: doc.decision,
150
- apiRoute: surface.apiRoute
159
+ apiRoute: surface.apiRoute,
160
+ userId: surface.userId,
161
+ userCollection: surface.userCollection
151
162
  }) : null;
152
163
  const meta = /*#__PURE__*/ _jsxs(_Fragment, {
153
164
  children: [
@@ -263,6 +274,9 @@ function ResultsContent({ id, surface, onRecomputed, onPagesReleased, renderPage
263
274
  }, context),
264
275
  sinceShipping: rolloutLine(shown, phase, phases, decision ?? undefined)
265
276
  }),
277
+ primary?.clickGoal ? /*#__PURE__*/ _jsx("p", {
278
+ children: C.clickPrimary
279
+ }) : null,
266
280
  /*#__PURE__*/ _jsxs("div", {
267
281
  className: "xp-stat-tiles",
268
282
  children: [
@@ -309,6 +323,9 @@ function ResultsContent({ id, surface, onRecomputed, onPagesReleased, renderPage
309
323
  })
310
324
  ]
311
325
  }) : null,
326
+ shown.goalFairnessNotice ? /*#__PURE__*/ _jsx("p", {
327
+ children: shown.goalFairnessNotice
328
+ }) : null,
312
329
  /*#__PURE__*/ _jsx(DataQualityPanel, {
313
330
  problem: shown.verdict.code === 'data-problem',
314
331
  items: dataQuality(shown, context)
@@ -340,6 +357,7 @@ function ResultsContent({ id, surface, onRecomputed, onPagesReleased, renderPage
340
357
  })
341
358
  }),
342
359
  /*#__PURE__*/ _jsx(PreviewLinks, {
360
+ apiRoute: surface.apiRoute,
343
361
  experimentId: id,
344
362
  flagPoint: doc?.flagPoint,
345
363
  placements: placements,
@@ -360,6 +378,7 @@ function ResultsContent({ id, surface, onRecomputed, onPagesReleased, renderPage
360
378
  ]
361
379
  }) : null,
362
380
  deciding && manage && phase ? /*#__PURE__*/ _jsx(DecideDialog, {
381
+ apiRoute: surface.apiRoute,
363
382
  id: id,
364
383
  arms: phase.arms,
365
384
  checks: checks,
@@ -1,5 +1,6 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { surfaceUrls } from '../../surfaceUrls.js';
3
4
  import { useEffect, useState } from 'react';
4
5
  import { formatAdminURL } from 'payload/shared';
5
6
  import { SurfaceShell } from '../SurfaceShell.js';
@@ -8,7 +9,7 @@ import { Banner, StatusChip } from '../../../ui/Feedback.js';
8
9
  import { createApi } from '../../api.js';
9
10
  import { availableActions, actionGroupLabel } from '../../actions/actions.model.js';
10
11
  import { AllocateAction, ConfirmAction } from '../readiness/ActionDialogs.js';
11
- import { READINESS, daysRemaining, displayDate, nextStep } from '../readiness/readiness.model.js';
12
+ import { READINESS, daysRemaining, displayDate, nextStep, pageReadinessContext } from '../readiness/readiness.model.js';
12
13
  import { READINESS_COPY as R, runningCopy, stoppedCopy, decidedCopy } from '../../copy/readiness.js';
13
14
  import { RESULTS_COPY as C } from '../../copy/results.js';
14
15
  import { TEST_PAGE } from '../../copy/testPage.js';
@@ -54,10 +55,7 @@ export function ResultsHeader({ test, surface, resultsVersion, children, actions
54
55
  'allocate',
55
56
  'stop'
56
57
  ].indexOf(b.id) : 0);
57
- const next = nextStep(test.preflight, {
58
- ...doc,
59
- flagPoints: surface.flagPoints
60
- });
58
+ const next = nextStep(test.preflight, pageReadinessContext(doc, test.preflight, surface));
61
59
  const ready = Boolean(test.preflight && !test.preflightPending && !test.preflightError && test.preflight.checks.every((check)=>check.ok));
62
60
  const startReason = next?.sentence ?? (!ready ? test.preflightError ? R.checkError : R.checking : undefined);
63
61
  const action = available.find((item)=>item.id === selected);
@@ -72,10 +70,7 @@ export function ResultsHeader({ test, surface, resultsVersion, children, actions
72
70
  crumbs: [
73
71
  {
74
72
  label: C.tests,
75
- href: formatAdminURL({
76
- adminRoute: surface.adminRoute,
77
- path: '/experiments'
78
- })
73
+ href: surface.canManage ? surfaceUrls.home(surface.adminRoute) : undefined
79
74
  },
80
75
  {
81
76
  label: doc.name,
@@ -160,10 +155,7 @@ export function ReaderResultsShell({ surface, children, data }) {
160
155
  crumbs: [
161
156
  {
162
157
  label: C.tests,
163
- href: formatAdminURL({
164
- adminRoute: surface.adminRoute,
165
- path: '/experiments'
166
- })
158
+ href: surface.canManage ? surfaceUrls.home(surface.adminRoute) : undefined
167
159
  },
168
160
  {
169
161
  label: title
@@ -29,17 +29,34 @@ export declare function useResults(id: DocId, { apiRoute, canReadResults, canMan
29
29
  canManage?: boolean;
30
30
  }): {
31
31
  api: {
32
+ findTestIdBySlug: (slug: string) => Promise<Extract<ApiResult<DocId>, {
33
+ ok: false;
34
+ }> | {
35
+ ok: true;
36
+ data: DocId;
37
+ }>;
38
+ deleteTest: (id: DocId) => Promise<ApiResult<unknown>>;
39
+ wrapBlock: (body: import("../../../types/endpoints.js").WrapBlockBody) => Promise<ApiResult<Record<string, unknown>>>;
40
+ pages: (query: {
41
+ collection: string;
42
+ q?: string;
43
+ path?: string;
44
+ page?: number;
45
+ }, signal?: AbortSignal) => Promise<ApiResult<import("../../../types/endpoints.js").PagesResult>>;
46
+ placementStatus: (body: import("../../../types/endpoints.js").PlacementStatusBody) => Promise<ApiResult<import("../../../types/endpoints.js").PlacementStatusResult>>;
32
47
  start: (id: DocId) => Promise<ApiResult<import("../../../types/endpoints.js").TransitionSuccess>>;
33
48
  allocate: (id: DocId, body: import("../../../types/endpoints.js").AllocateBody, options?: {
34
49
  notFound?: string;
50
+ forbidden?: string;
35
51
  codes?: Readonly<Record<string, string>>;
36
52
  fallback?: string;
37
53
  }) => Promise<ApiResult<import("../../../types/endpoints.js").TransitionSuccess>>;
38
54
  addMetric: (id: DocId, body: import("../../../types/endpoints.js").AddMetricBody, options?: {
39
55
  notFound?: string;
56
+ forbidden?: string;
40
57
  codes?: Readonly<Record<string, string>>;
41
58
  fallback?: string;
42
- }) => Promise<ApiResult<import("../../../types/endpoints.js").TransitionSuccess>>;
59
+ }) => Promise<ApiResult<import("../../../types/endpoints.js").AddMetricResult>>;
43
60
  stop: (id: DocId) => Promise<ApiResult<import("../../../types/endpoints.js").TransitionSuccess>>;
44
61
  decide: (id: DocId, body: import("../../../types/endpoints.js").DecideBody) => Promise<ApiResult<import("../../../types/endpoints.js").TransitionSuccess>>;
45
62
  releaseHoldout: (id: DocId) => Promise<ApiResult<import("../../../types/endpoints.js").TransitionSuccess>>;
@@ -48,6 +65,7 @@ export declare function useResults(id: DocId, { apiRoute, canReadResults, canMan
48
65
  dismissContentEntry: (id: DocId, body: import("../../../types/endpoints.js").DismissContentEntryBody) => Promise<ApiResult<import("../../../types/endpoints.js").DismissContentEntryResult>>;
49
66
  restoreContentEntry: (id: DocId, body: import("../../../types/endpoints.js").RestoreContentEntryBody) => Promise<ApiResult<import("../../../types/endpoints.js").RestoreContentEntryResult>>;
50
67
  archive: (id: DocId, body: import("../../../types/endpoints.js").ArchiveBody) => Promise<ApiResult<import("../../../types/endpoints.js").TransitionSuccess>>;
68
+ clickKeys: (id: DocId) => Promise<ApiResult<import("../../../types/endpoints.js").ClickKeysResult>>;
51
69
  preflight: (id: DocId) => Promise<ApiResult<import("../../../types/endpoints.js").PreflightResult>>;
52
70
  previewToken: (id: DocId, arm: string) => Promise<ApiResult<import("../../../types/endpoints.js").PreviewTokenResult>>;
53
71
  results: (id: DocId, options?: {
@@ -55,6 +73,7 @@ export declare function useResults(id: DocId, { apiRoute, canReadResults, canMan
55
73
  series?: boolean;
56
74
  } & {
57
75
  notFound?: string;
76
+ forbidden?: string;
58
77
  codes?: Readonly<Record<string, string>>;
59
78
  fallback?: string;
60
79
  }) => Promise<ApiResult<ResultsResponse>>;