@declarion/react 0.56.0 → 0.59.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 (167) hide show
  1. package/README.md +0 -2
  2. package/dist-lib/AgentChatPanel.impl-DBH1Ff4G.js +1200 -0
  3. package/dist-lib/DetailAuditStrip-GNRA_eP5.js +289 -0
  4. package/dist-lib/{DraggableChildrenTable-BV5sb8Uo.js → DraggableChildrenTable-4RZC351U.js} +87 -86
  5. package/dist-lib/Grid-CQabaBLx.js +405 -0
  6. package/dist-lib/{LayoutRenderer-C9AH9cXf.js → LayoutRenderer-DGKWZKpW.js} +1000 -1114
  7. package/dist-lib/{ListCardsBody-DXcDg536.js → ListCardsBody-DfGmyNIu.js} +84 -84
  8. package/dist-lib/MarkdownRenderer-BDbzDv_y.js +87 -0
  9. package/dist-lib/{RefreshControl-CNtN8zSl.js → RefreshControl-Bhoib0ZA.js} +126 -155
  10. package/dist-lib/SmartDetailPage.impl-Ds2RGg6K.js +1565 -0
  11. package/dist-lib/SmartListPage.impl-BrZLE_Gb.js +3046 -0
  12. package/dist-lib/{SmartRecordListPage.impl-Bkl9aZJ8.js → SmartRecordListPage.impl-C1FJLr80.js} +281 -280
  13. package/dist-lib/SortHeaderMenu-Cijxk4cX.js +107 -0
  14. package/dist-lib/action-dispatch-DY0c8U81.js +1967 -0
  15. package/dist-lib/api/client.d.ts +5 -0
  16. package/dist-lib/api/data.d.ts +2 -4
  17. package/dist-lib/api/entities.d.ts +8 -15
  18. package/dist-lib/api/events.d.ts +3 -3
  19. package/dist-lib/cardProjection-Bkl2SSYz.js +499 -0
  20. package/dist-lib/components/actions/ResponsiveActionBar.d.ts +17 -16
  21. package/dist-lib/components/agents/AgentChatPanel.d.ts +3 -13
  22. package/dist-lib/components/agents/AgentChatPanel.impl.d.ts +14 -0
  23. package/dist-lib/components/agents/AgentPicker.d.ts +1 -2
  24. package/dist-lib/components/chrome/PageShell.d.ts +7 -0
  25. package/dist-lib/components/chrome/RecordHeader.d.ts +1 -2
  26. package/dist-lib/components/detail-layout/ChildrenBlock.d.ts +1 -1
  27. package/dist-lib/components/detail-layout/DetailAuditStrip.d.ts +1 -2
  28. package/dist-lib/components/detail-layout/DetailHighlights.d.ts +1 -2
  29. package/dist-lib/components/detail-layout/blockMeta.d.ts +2 -1
  30. package/dist-lib/components/fields/BoolField.d.ts +1 -1
  31. package/dist-lib/components/fields/EnumField.d.ts +1 -1
  32. package/dist-lib/components/fields/IntArrayField.d.ts +1 -1
  33. package/dist-lib/components/fields/MultilangArrayField.d.ts +2 -0
  34. package/dist-lib/components/fields/MultilangField.d.ts +1 -1
  35. package/dist-lib/components/fields/MultilangTextField.d.ts +1 -1
  36. package/dist-lib/components/fields/NumberField.d.ts +1 -1
  37. package/dist-lib/components/fields/PasswordField.d.ts +1 -1
  38. package/dist-lib/components/fields/RefCombobox.d.ts +1 -1
  39. package/dist-lib/components/fields/SecretField.d.ts +1 -1
  40. package/dist-lib/components/fields/StringArrayField.d.ts +1 -1
  41. package/dist-lib/components/fields/TimestampField.d.ts +1 -1
  42. package/dist-lib/components/fields/cells/registry.d.ts +2 -1
  43. package/dist-lib/components/fields/index.d.ts +2 -1
  44. package/dist-lib/components/fields/langMap.d.ts +2 -0
  45. package/dist-lib/components/fields/secretValue.d.ts +2 -0
  46. package/dist-lib/components/file-widgets/UnknownFileWidget.d.ts +3 -0
  47. package/dist-lib/components/file-widgets/UploadFailureText.d.ts +4 -0
  48. package/dist-lib/components/file-widgets/helpers.d.ts +1 -1
  49. package/dist-lib/components/file-widgets/host.d.ts +4 -3
  50. package/dist-lib/components/file-widgets/types.d.ts +1 -0
  51. package/dist-lib/components/file-widgets/upload.d.ts +18 -3
  52. package/dist-lib/components/filters/filter-op-label.d.ts +3 -0
  53. package/dist-lib/components/layout/ImpersonationBanner.d.ts +1 -1
  54. package/dist-lib/components/layout/ImpersonationFrame.d.ts +1 -1
  55. package/dist-lib/components/layout/Layout.d.ts +2 -1
  56. package/dist-lib/components/layout/Sidebar.d.ts +2 -1
  57. package/dist-lib/components/layout/TenantChip.d.ts +1 -1
  58. package/dist-lib/components/list/ViewSwitcher.d.ts +4 -2
  59. package/dist-lib/components/pages/DocumentsMenu.d.ts +1 -2
  60. package/dist-lib/components/pages/ExportMenu.d.ts +3 -5
  61. package/dist-lib/components/pages/RecordDocumentsPanel.d.ts +1 -2
  62. package/dist-lib/components/pages/auth/AuthShell.d.ts +4 -31
  63. package/dist-lib/components/pages/exportRequest.d.ts +4 -6
  64. package/dist-lib/components/pages/list/DeleteViewDialog.d.ts +8 -0
  65. package/dist-lib/components/pages/list/ListCardRow.d.ts +1 -2
  66. package/dist-lib/components/pages/list/ListCardsBody.d.ts +0 -1
  67. package/dist-lib/components/pages/list/ListFloatbar.d.ts +2 -2
  68. package/dist-lib/components/pages/list/ListHeader.d.ts +2 -2
  69. package/dist-lib/components/pages/list/ListNoRows.d.ts +4 -5
  70. package/dist-lib/components/pages/list/ListToolbar.d.ts +3 -2
  71. package/dist-lib/components/pages/list/ListUrlBanner.d.ts +10 -0
  72. package/dist-lib/components/pages/list/RowActionsCell.d.ts +2 -4
  73. package/dist-lib/components/pages/list/RowContextMenu.d.ts +1 -2
  74. package/dist-lib/components/pages/list/columns.d.ts +2 -1
  75. package/dist-lib/components/pages/list/filter-meta.d.ts +2 -1
  76. package/dist-lib/components/pages/list/useActiveView.d.ts +38 -0
  77. package/dist-lib/components/pages/list/useListColumnLayout.d.ts +6 -5
  78. package/dist-lib/components/pages/list/useListQuery.d.ts +4 -4
  79. package/dist-lib/components/pages/list/useListSort.d.ts +5 -4
  80. package/dist-lib/components/pages/list/useListViews.d.ts +18 -8
  81. package/dist-lib/components/pages/list/useRowMenu.d.ts +2 -3
  82. package/dist-lib/components/pages/profile/Profile.d.ts +3 -0
  83. package/dist-lib/components/params/ParamsBlock.d.ts +1 -13
  84. package/dist-lib/components/params/param-editors.d.ts +3 -11
  85. package/dist-lib/components/primitives/ClassifiedFieldLocked.d.ts +1 -2
  86. package/dist-lib/components/shared/DynamicIcon.d.ts +2 -2
  87. package/dist-lib/components/shared/ErrorBoundary.d.ts +1 -1
  88. package/dist-lib/components/shared/LoadingSkeleton.d.ts +1 -0
  89. package/dist-lib/components/shared/LucideIcon.d.ts +1 -1
  90. package/dist-lib/components/shared/useOwnRefresh.d.ts +1 -1
  91. package/dist-lib/declarion-react.css +1 -1
  92. package/dist-lib/embed/theme.d.ts +1 -1
  93. package/dist-lib/embed/useEmbedNavigate.d.ts +1 -1
  94. package/dist-lib/failure-v-uGSpbX.js +158 -0
  95. package/dist-lib/{field-classification-D6xQYn-h.js → field-classification-C28XE-_P.js} +514 -307
  96. package/dist-lib/format-count-DA4wmmWR.js +1771 -0
  97. package/dist-lib/hooks/useEntityData.d.ts +1 -1
  98. package/dist-lib/hooks/useFilters.d.ts +7 -5
  99. package/dist-lib/hooks/useLanguage.d.ts +4 -0
  100. package/dist-lib/hooks/useParams.d.ts +4 -51
  101. package/dist-lib/hooks/useRegisterScreenTab.d.ts +1 -1
  102. package/dist-lib/hooks/useSSE.d.ts +3 -3
  103. package/dist-lib/hooks/useTabTitle.d.ts +2 -0
  104. package/dist-lib/hooks/useText.d.ts +3 -3
  105. package/dist-lib/hooks/useVersionWatcher.d.ts +1 -1
  106. package/dist-lib/hooks/useViews.d.ts +20 -0
  107. package/dist-lib/index.d.ts +8 -7
  108. package/dist-lib/index.js +2716 -5795
  109. package/dist-lib/lib/action-dispatch.d.ts +2 -1
  110. package/dist-lib/lib/actions.d.ts +30 -42
  111. package/dist-lib/lib/anchor.d.ts +3 -4
  112. package/dist-lib/lib/decimal-text.d.ts +1 -0
  113. package/dist-lib/lib/document-templates.d.ts +1 -2
  114. package/dist-lib/lib/download.d.ts +2 -1
  115. package/dist-lib/lib/evidence-verdict.d.ts +2 -1
  116. package/dist-lib/lib/failure.d.ts +2 -0
  117. package/dist-lib/lib/field-classification.d.ts +3 -3
  118. package/dist-lib/lib/filters.d.ts +18 -2
  119. package/dist-lib/lib/format-count.d.ts +8 -7
  120. package/dist-lib/lib/language.d.ts +19 -0
  121. package/dist-lib/lib/mass-edit.d.ts +2 -1
  122. package/dist-lib/lib/realtime-query-keys.d.ts +1 -1
  123. package/dist-lib/lib/realtime-reconcile.d.ts +3 -4
  124. package/dist-lib/lib/screen-back.d.ts +4 -6
  125. package/dist-lib/lib/sort.d.ts +9 -9
  126. package/dist-lib/lib/timestamp.d.ts +5 -7
  127. package/dist-lib/lib/ui-actions.d.ts +2 -1
  128. package/dist-lib/peekDraftStore-D-cTbiIr.js +199 -0
  129. package/dist-lib/registry-Cb3W-czW.js +1950 -0
  130. package/dist-lib/safe-url-oSJw5pzO.js +34 -0
  131. package/dist-lib/stores/icon-registry.d.ts +2 -2
  132. package/dist-lib/stores/list-layout.d.ts +3 -4
  133. package/dist-lib/stores/realtime.d.ts +1 -1
  134. package/dist-lib/stores/tabs.d.ts +3 -2
  135. package/dist-lib/testing.d.ts +6 -0
  136. package/dist-lib/testing.js +98 -76
  137. package/dist-lib/types/api.d.ts +7 -8
  138. package/dist-lib/types/fieldType.d.ts +1 -1
  139. package/dist-lib/types/files.d.ts +4 -4
  140. package/dist-lib/types/schema.d.ts +44 -50
  141. package/dist-lib/useAgentConversation-D97IqE-J.js +623 -0
  142. package/dist-lib/{useCurrentScreen-CzwzQpoW.js → useCurrentScreen-BL5NZFCw.js} +2777 -3768
  143. package/dist-lib/useListQuery-BG1GyKtJ.js +103 -0
  144. package/dist-lib/useProperties-4Lg3odrt.js +83 -0
  145. package/dist-lib/{useTabSearchMirror-C39U85cg.js → useTabSearchMirror-ZVLlINBX.js} +49 -51
  146. package/dist-lib/useText-BFDCTUSo.js +952 -0
  147. package/dist-lib/{value-Bo8C8WMU.js → value-By1-WJ8J.js} +74 -76
  148. package/dist-lib/vite/fingerprint-plugin.d.ts +2 -3
  149. package/package.json +13 -12
  150. package/dist-lib/Grid-DWgUPuZ3.js +0 -404
  151. package/dist-lib/MarkdownRenderer-CcSFc2N3.js +0 -85
  152. package/dist-lib/RecordIdBadge-CGxPR-8q.js +0 -24
  153. package/dist-lib/SmartDetailPage.impl-lskCd-WG.js +0 -1846
  154. package/dist-lib/SmartListPage.impl-CrGbdzyK.js +0 -2854
  155. package/dist-lib/SortHeaderMenu-SYSAaqQJ.js +0 -106
  156. package/dist-lib/action-dispatch-CR4ajBtT.js +0 -1985
  157. package/dist-lib/cardProjection-CW5RIMko.js +0 -699
  158. package/dist-lib/components/pages/home/HomeStub.d.ts +0 -6
  159. package/dist-lib/components/pages/jobs/Jobs.d.ts +0 -1
  160. package/dist-lib/components/pages/pipeline/Pipeline.d.ts +0 -1
  161. package/dist-lib/format-count-Dobmi-Ji.js +0 -1551
  162. package/dist-lib/hooks/useUserLocale.d.ts +0 -1
  163. package/dist-lib/lib/messages.d.ts +0 -12
  164. package/dist-lib/peekDraftStore-5wQ7lq_V.js +0 -194
  165. package/dist-lib/registry-CjgUaF7C.js +0 -1768
  166. package/dist-lib/useListQuery-D7Hr5WM1.js +0 -96
  167. package/dist-lib/useProperties-CqtCzFCr.js +0 -81
@@ -1,6 +1,7 @@
1
1
  import { type UIActionContext } from "./ui-actions.d.ts";
2
2
  import type { UIStep } from "../types/schema.d.ts";
3
- export declare function dispatchAction(code: string, action: {
3
+ import type { TextFn } from "./language.d.ts";
4
+ export declare function dispatchAction(errorTitle: TextFn, code: string, action: {
4
5
  ui_steps?: UIStep[];
5
6
  handler?: string;
6
7
  entity?: string;
@@ -1,4 +1,5 @@
1
1
  import type { Action, ActionCondition, Entity, LocalizedString, Schema } from "../types/schema.d.ts";
2
+ import type { TextFn } from "./language.d.ts";
2
3
  /**
3
4
  * Row-menu navigation platform-default action codes. The server injects them
4
5
  * into every entity and (for explicit action_layout trees) prepends them so the
@@ -64,35 +65,27 @@ export declare function filterUnavailableMutationActions(actions: Array<{
64
65
  * Checks if an action has parameters that need user input.
65
66
  */
66
67
  export declare function actionHasParams(action: Action): boolean;
67
- /**
68
- * Default confirmation copy for a destructive action that declares none. A
69
- * LocalizedString like every user-facing string in the platform, resolved
70
- * against the caller's locale by `actionConfirmMessage`. A consumer's own
71
- * `confirmation` (also localized) overrides it.
72
- */
73
- export declare const DEFAULT_DESTRUCTIVE_CONFIRM: LocalizedString;
74
68
  /**
75
69
  * The confirmation message to show before running an action, or null when no
76
70
  * confirm step is needed. This is the SINGLE source of confirm semantics, read
77
71
  * by every dispatch surface (the ActionRunner and ActionButton) so they cannot
78
- * drift (see docs/ui-internals.md "Action dialogs and dispatch"):
72
+ * drift:
79
73
  * - a declared `confirmation` wins (works on any action, destructive or not);
80
74
  * - else a `destructive` action gets the default danger warning;
81
75
  * - else null (no confirm).
82
- * Both the declared text and the default are localized and resolved against
83
- * `locale`. `destructive` is a semantic class (danger colour + trailing
76
+ * Both the declared text and the default are declared words, read through `t`. `destructive` is a semantic class (danger colour + trailing
84
77
  * placement + the server impersonation gate + agent HITL); the confirm is one
85
78
  * of its effects, and `confirmation` only tunes the TEXT - not a second gate.
86
79
  */
87
- export declare function actionConfirmMessage(action: Action | undefined, locale: string): string | null;
80
+ export declare function actionConfirmMessage(t: TextFn, action: Action | undefined): string | null;
88
81
  /**
89
82
  * True when the action must show a confirm step (destructive OR a declared
90
- * confirmation). Locale-independent - it is a presence check, so the runner can
83
+ * confirmation). Language-independent - it is a presence check, so the runner can
91
84
  * decide whether to open the dialog without resolving the text.
92
85
  */
93
86
  export declare function actionNeedsConfirm(action: Action | undefined): boolean;
94
87
  /**
95
- * Tooltip text for an action control (plan 2026-07-02-action-display-description).
88
+ * Tooltip text for an action control.
96
89
  * Precedence: disabled-reason > description > name.
97
90
  *
98
91
  * A labeled control already shows the name, so its tooltip is the description
@@ -101,7 +94,7 @@ export declare function actionNeedsConfirm(action: Action | undefined): boolean;
101
94
  * on its own line, then the description. Absent description falls back to the
102
95
  * name.
103
96
  */
104
- export declare function actionTooltip(action: Action | undefined, name: string, isDisabled: boolean, reason: string | null | undefined,
97
+ export declare function actionTooltip(t: TextFn, action: Action | undefined, name: string, isDisabled: boolean, reason: string | null | undefined,
105
98
  /**
106
99
  * True when the button is rendering WITHOUT its label right now - either
107
100
  * because the author declared `display.icon_only`, or because the row ran out
@@ -115,7 +108,7 @@ labelHidden?: boolean): string;
115
108
  export declare function fullActionCode(entityCode: string | undefined, actionCode: string): string;
116
109
  /**
117
110
  * Checks if an action is an association navigation action.
118
- * Reason: per new wire format (unified-toolbar plan §1-§2), dispatch mode is
111
+ * Reason: in the wire format, dispatch mode is
119
112
  * encoded by which dispatch field is set; the `association` field is the mode.
120
113
  */
121
114
  export declare function isAssociationAction(action: Action): boolean;
@@ -132,7 +125,7 @@ export declare function findListScreenForEntity(schema: Schema | undefined, enti
132
125
  * Enabled defaults true from server; client sets false when enabled_if fails.
133
126
  * Reason carries the localized tooltip text when Enabled is false.
134
127
  *
135
- * Wire format (plan §8): {"kind":"action","code":"approve","enabled":true,"reason":null}
128
+ * Wire format: {"kind":"action","code":"approve","enabled":true,"reason":null}
136
129
  */
137
130
  export interface ResolvedActionLeaf {
138
131
  kind: "action";
@@ -144,7 +137,7 @@ export interface ResolvedActionLeaf {
144
137
  * Resolved group node. Kind discriminator "group".
145
138
  * Items is always non-empty after pruning (empty groups are dropped).
146
139
  *
147
- * Wire format (plan §8): {"kind":"group","name":{...},"icon":"...","items":[...]}
140
+ * Wire format: {"kind":"group","name":{...},"icon":"...","items":[...]}
148
141
  */
149
142
  export interface ResolvedActionGroup {
150
143
  kind: "group";
@@ -159,7 +152,7 @@ export interface ResolvedActionGroup {
159
152
  export type ResolvedActionLayoutNode = ResolvedActionLeaf | ResolvedActionGroup;
160
153
  /**
161
154
  * applyRowState walks an RBAC-pruned ResolvedActionLayoutNode[] and applies
162
- * per-row visible_if / enabled_if evaluation (plan §4, §5).
155
+ * per-row visible_if / enabled_if evaluation.
163
156
  *
164
157
  * Drop conditions:
165
158
  * - visible_if conditions not satisfied by row -> leaf dropped
@@ -178,34 +171,18 @@ export type ResolvedActionLayoutNode = ResolvedActionLeaf | ResolvedActionGroup;
178
171
  * @param rowSelection All selected rows for bulk context (list_toolbar bulk mode).
179
172
  * Pass empty array for non-bulk contexts.
180
173
  */
181
- export declare function applyRowState(layout: ResolvedActionLayoutNode[], entityActions: Record<string, Action> | undefined, globalActions: Record<string, Action> | undefined, row: Record<string, unknown>, rowSelection: Record<string, unknown>[], allowedActionCodes?: ReadonlySet<string>): ResolvedActionLayoutNode[];
182
- /**
183
- * Composes a flat ResolvedActionLayoutNode[] from an entity's actions map,
184
- * filtered to those that include the given slot in their visibility array,
185
- * sorted by position ascending (ties broken by declaration order).
186
- *
187
- * This is the fallback used when neither screen.action_layout nor
188
- * entity.action_layout is present (plan §3: "runtime MUST compose a flat
189
- * layout from all actions matching the slot's visibility[], sorted by
190
- * position ascending").
191
- *
192
- * All leaves are emitted with enabled=true; client applies visible_if /
193
- * enabled_if via applyRowState.
194
- *
195
- * @param actions Entity-level actions map from the (already RBAC-pruned) schema.
196
- * @param slot Placement slot code (e.g. "detail", "list_row", "list_toolbar").
197
- */
174
+ export declare function applyRowState(t: TextFn, layout: ResolvedActionLayoutNode[], entityActions: Record<string, Action> | undefined, globalActions: Record<string, Action> | undefined, row: Record<string, unknown>, rowSelection: Record<string, unknown>[], allowedActionCodes?: ReadonlySet<string>): ResolvedActionLayoutNode[];
198
175
  /**
199
176
  * Filters a server-emitted ResolvedActionLayoutNode tree to a single slot,
200
177
  * preserving group structure. Drops leaves whose action's visibility[] does
201
178
  * not include the slot. Drops groups whose entire item list pruned out
202
- * (plan §5 empty-group auto-hide). Additional filters via `opts`:
179
+ * (empty-group auto-hide). Additional filters via `opts`:
203
180
  *
204
181
  * - opts.bulkRequired: when set, gates list_toolbar leaves whose effective
205
182
  * "bulk-required" semantic matches the request. The old wire-format flag
206
- * `bulk_selection_required` was removed in unified-toolbar Phase 1 (the
207
- * server now derives this from `handler.invoke`); until Task 38 replaces
208
- * this code path the caller passes a predicate that decides per action.
183
+ * `bulk_selection_required` was removed (the server now derives this
184
+ * from `handler.invoke`), so the caller passes a predicate that decides
185
+ * per action.
209
186
  * Reason: keep the slot+bulk filtering surface intact while removing the
210
187
  * field; the call sites supply the legacy predicate.
211
188
  * - opts.excludeIf: drop leaves where the predicate returns true. Common
@@ -237,9 +214,6 @@ export declare function resolveActionLayoutForSlot(screenActionLayout: ResolvedA
237
214
  * does not derive) we fall back to the historical proxy: slot membership in
238
215
  * `list_floatbar`. Absent MUST NOT be read as false, or every handler action
239
216
  * would silently read as page-level against an older server.
240
- *
241
- * See docs/architecture.md "List Toolbar Selection Model" and plan
242
- * 2026-06-22-toolbar-action-slots-and-id-arity.md.
243
217
  */
244
218
  export declare function actionRequiresSelection(action: Action): boolean;
245
219
  /**
@@ -263,4 +237,18 @@ export declare function actionInFloatbarSlot(action: Action): boolean;
263
237
  * are selected.
264
238
  */
265
239
  export declare function disableLeavesWhere(layout: ResolvedActionLayoutNode[], entityActions: Record<string, Action> | undefined, globalActions: Record<string, Action> | undefined, predicate: (action: Action) => boolean, reason: string): ResolvedActionLayoutNode[];
240
+ /**
241
+ * Composes a flat ResolvedActionLayoutNode[] from an entity's actions map,
242
+ * filtered to those that include the given slot in their visibility array,
243
+ * sorted by position ascending (ties broken by action code).
244
+ *
245
+ * This is the fallback used when neither screen.action_layout nor
246
+ * entity.action_layout is present.
247
+ *
248
+ * All leaves are emitted with enabled=true; client applies visible_if /
249
+ * enabled_if via applyRowState.
250
+ *
251
+ * @param actions Entity-level actions map from the (already RBAC-pruned) schema.
252
+ * @param slot Placement slot code (e.g. "detail", "list_row", "list_toolbar").
253
+ */
266
254
  export declare function defaultFlatForSlot(actions: Record<string, Action> | undefined, slot: string): ResolvedActionLayoutNode[];
@@ -1,10 +1,9 @@
1
1
  /**
2
2
  * The anchor expression, TypeScript side.
3
3
  *
4
- * One grammar for "a moment relative to now", shared with the server
5
- * (golang/internal/engine/anchor.go + duration.go). The language boundary is
6
- * the only reason there are two implementations; nothing else may declare a
7
- * third.
4
+ * One grammar for "a moment relative to now", shared with the server. The
5
+ * language boundary is the only reason there are two implementations; nothing
6
+ * else may declare a third.
8
7
  *
9
8
  * now the current instant
10
9
  * now+3w three weeks ahead
@@ -0,0 +1 @@
1
+ export declare function formatDecimalText(value: string, formatter: Intl.NumberFormat): string;
@@ -4,8 +4,7 @@ import type { Schema } from "../types/schema.d.ts";
4
4
  * can manage TENANT document templates: the `document_template` entity is
5
5
  * present in the projected schema (schema.entities is already RBAC-pruned -
6
6
  * `document_template` appears only when the caller can read it). Gates the
7
- * lazy `document.templates.available` tenant-template visibility probe
8
- * (Business Case 6, plan 2026-07-08-document-generation-hardening) so a
7
+ * lazy `document.templates.available` tenant-template visibility probe so a
9
8
  * caller who cannot manage templates never fires it, which is the default.
10
9
  * One shared predicate so SmartDetailPage and SmartListPage agree.
11
10
  */
@@ -1,3 +1,4 @@
1
+ import type { TextFn } from "./language.d.ts";
1
2
  export declare class DownloadError extends Error {
2
3
  readonly code?: string | undefined;
3
4
  constructor(message: string, code?: string | undefined);
@@ -17,4 +18,4 @@ export declare function isMissingArtifactError(err: unknown): boolean;
17
18
  * 403, etc.) surfaces as a thrown DownloadError instead of silently
18
19
  * navigating the browser to an error page.
19
20
  */
20
- export declare function downloadFile(url: string, filename?: string): Promise<void>;
21
+ export declare function downloadFile(errorTitle: TextFn, url: string, filename?: string): Promise<void>;
@@ -1,4 +1,5 @@
1
1
  import type { PillTone } from "../components/primitives/Pill.d.ts";
2
+ import type { TextFn } from "./language.d.ts";
2
3
  export declare const EVIDENCE_VERDICT: {
3
4
  readonly verified: "verified";
4
5
  readonly unverified: "unverified";
@@ -6,5 +7,5 @@ export declare const EVIDENCE_VERDICT: {
6
7
  readonly indeterminate: "indeterminate";
7
8
  readonly outsideCoverage: "outside_coverage";
8
9
  };
9
- export declare function verdictLabel(verdict: string): string;
10
+ export declare function verdictLabel(t: TextFn, verdict: string): string;
10
11
  export declare function verdictTone(verdict: string): PillTone;
@@ -0,0 +1,2 @@
1
+ import type { TextFn } from "./language";
2
+ export declare function failureTitle(errorTitle: TextFn, err: unknown): string;
@@ -3,14 +3,14 @@ import type { Entity, FieldAccessInfo, ClassificationTierDef, Schema } from "../
3
3
  * isFieldReadable returns true when the caller can see the field's
4
4
  * value. Non-classified fields are always readable (no entry in
5
5
  * field_access). Classified fields are readable when field_access
6
- * marks read="granted". Plan §B9.
6
+ * marks read="granted".
7
7
  */
8
8
  export declare function isFieldReadable(entity: Entity | undefined, fieldName: string): boolean;
9
9
  /**
10
10
  * isFieldWritable returns true when the caller can submit a new value
11
11
  * for the field. Form components disable input + show a lock badge
12
12
  * when this returns false. Non-classified fields are always writable
13
- * (gating happens via entity-level RBAC at the HTTP layer). Plan §B9.
13
+ * (gating happens via entity-level RBAC at the HTTP layer).
14
14
  */
15
15
  export declare function isFieldWritable(entity: Entity | undefined, fieldName: string): boolean;
16
16
  /**
@@ -24,7 +24,7 @@ export declare function fieldClassification(entity: Entity | undefined, fieldNam
24
24
  * fieldRequiredPermission returns the exact grant string an
25
25
  * administrator must add to a role to unlock the field for the
26
26
  * current caller. Returns undefined when the field is readable +
27
- * writable (no hint needed). Plan §B9 — operator hand-off surface.
27
+ * writable (no hint needed).
28
28
  */
29
29
  export declare function fieldRequiredPermission(entity: Entity | undefined, fieldName: string): string | undefined;
30
30
  /**
@@ -39,16 +39,32 @@ export declare const NO_VALUE_OPS: Set<FilterOp>;
39
39
  export declare const MULTI_VALUE_OPS: Set<FilterOp>;
40
40
  /** Human-friendly display names for operators. */
41
41
  export declare const OP_LABELS: Record<FilterOp, string>;
42
+ export type FilterURLErrorCode = "filter.url_not_json" | "filter.url_not_tree";
43
+ export declare class FilterURLError extends Error {
44
+ readonly code: FilterURLErrorCode;
45
+ constructor(code: FilterURLErrorCode, message: string);
46
+ }
42
47
  export interface FilterURLState {
43
48
  filters: FilterNode[];
44
49
  error: string | null;
50
+ errorCode: FilterURLErrorCode | null;
45
51
  }
46
52
  /** Parse filters from URL search params (JSON `filters` param). */
47
53
  export declare function parseFilterURLState(searchParams: URLSearchParams): FilterURLState;
48
54
  /** Parse the final tree and reject malformed URL state instead of treating it as no filter. */
49
55
  export declare function parseFiltersFromURL(searchParams: URLSearchParams): FilterNode[];
50
- /** Write filters to URL search params. */
51
- export declare function setFiltersInURL(filters: FilterNode[], searchParams: URLSearchParams): void;
56
+ /** True when two filter trees say the same thing. */
57
+ export declare function filtersEqual(a: FilterNode[], b: FilterNode[]): boolean;
58
+ /**
59
+ * Write filters to URL search params.
60
+ *
61
+ * The parameter is present only while the tree differs from `defaults` - what
62
+ * this list resolves to with no `filters` in the URL, which is the active
63
+ * view's tree on a list screen and nothing anywhere else. So an empty tree is
64
+ * an OVERRIDE where a view supplies conditions (`filters=[]`, no conditions)
65
+ * and an absence where nothing does.
66
+ */
67
+ export declare function setFiltersInURL(filters: FilterNode[], searchParams: URLSearchParams, defaults?: FilterNode[]): void;
52
68
  /**
53
69
  * Convert FilterNode array to API query params.
54
70
  * Uses the JSON `filters` param for the API request.
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Row-count formatting for list views. Display precision MUST match data
3
- * accuracy (docs/plans/2026-05-18-declarative-row-count.md, Principle 3):
3
+ * accuracy:
4
4
  *
5
5
  * - an exact count renders to the unit with thousands separators
6
6
  * (3,613,711) - it is known precisely;
@@ -13,7 +13,8 @@
13
13
  */
14
14
  /**
15
15
  * formatEstimatedCount renders a coarse estimate: a `~` prefix, ~2
16
- * significant figures, and a magnitude suffix (K/M/B).
16
+ * significant figures, and the magnitude suffix of Intl compact notation in
17
+ * `language` (K/M/B in English, "mil"/"M" in Spanish, "тыс."/"млн" in Russian).
17
18
  *
18
19
  * 3_613_711 -> "~3.6M"
19
20
  * 850_000 -> "~850K"
@@ -25,16 +26,16 @@
25
26
  * the leading digit is single); 12_000 -> 12K (no decimal because 2 leading
26
27
  * digits already give 2 sig figs).
27
28
  */
28
- export declare function formatEstimatedCount(total: number): string;
29
+ export declare function formatEstimatedCount(total: number, language?: string): string;
29
30
  /**
30
- * formatExactCount renders an exact count to the unit with locale thousands
31
- * separators: 3613711 -> "3,613,711".
31
+ * formatExactCount renders an exact count to the unit with the thousands
32
+ * separators of `language`: 3613711 -> "3,613,711" in English.
32
33
  */
33
- export declare function formatExactCount(total: number): string;
34
+ export declare function formatExactCount(total: number, language?: string): string;
34
35
  /**
35
36
  * formatCount picks the rendering by the count strategy actually used to
36
37
  * produce `total` (the server's `meta.count_mode`), NOT the entity schema:
37
38
  * a forced exact count must render exact even on a `count: estimated`
38
39
  * entity.
39
40
  */
40
- export declare function formatCount(total: number, mode: "exact" | "estimated"): string;
41
+ export declare function formatCount(total: number, mode: "exact" | "estimated", language?: string): string;
@@ -0,0 +1,19 @@
1
+ import { type ReactNode } from "react";
2
+ import type { LocalizedString } from "../types/schema.d.ts";
3
+ export declare const MANDATORY_LANGUAGE = "en";
4
+ export declare const LANGUAGE_PARAMETER = "ui_language";
5
+ export declare function pickLocalizedEntry(ls: LocalizedString | null | undefined, language: string, deploymentLanguage: string): [code: string, value: string] | undefined;
6
+ export declare function pickLocalized(ls: LocalizedString | null | undefined, language: string, deploymentLanguage: string): string | undefined;
7
+ export type TextVars = Record<string, string | number>;
8
+ export interface TextFn {
9
+ (code: string, fallback: string, vars?: TextVars): string;
10
+ (value: LocalizedString | null | undefined): string;
11
+ readonly language: string;
12
+ readonly deploymentLanguage: string;
13
+ }
14
+ export declare function makeTextFn(messages: Record<string, LocalizedString> | undefined, language: string, deploymentLanguage: string): TextFn;
15
+ export declare function pluralText(t: TextFn, code: string, count: number, english: {
16
+ one: string;
17
+ other: string;
18
+ }, more?: TextVars): string;
19
+ export declare function textWithNodes(text: string, nodes: Record<string, ReactNode>): ReactNode[];
@@ -1,4 +1,5 @@
1
1
  import type { Entity, EntityField, PropertyDef, StatusGroupDef } from "../types/schema.d.ts";
2
+ import type { TextFn } from "./language.d.ts";
2
3
  /** Target kinds mirror engine.MassEditTargetKind in Go. */
3
4
  export type MassEditTargetKind = "field" | "status" | "property";
4
5
  /** Metadata a property-grid row needs to render a target + editable value cell. */
@@ -28,4 +29,4 @@ export declare function parseTargetFilter(raw: string | undefined): string[];
28
29
  * - entities without generic update globally hide every target (UI mirrors
29
30
  * the server gate; the dispatcher still enforces permissions).
30
31
  */
31
- export declare function buildMassEditTargets(entity: Entity | undefined, whitelistRaw?: string | string[]): MassEditTarget[];
32
+ export declare function buildMassEditTargets(t: TextFn, entity: Entity | undefined, whitelistRaw?: string | string[]): MassEditTarget[];
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Every list-shaped cache the SDK ships. The REFETCH-ONLY kind is the cursor
3
- * list, whose cold tables a key does not prune. docs/realtime.md.
3
+ * list, whose cold tables a key does not prune.
4
4
  */
5
5
  export declare const NARROWED_LIST_CACHE_KEYS: readonly ["entity-data", "entity-data-all"];
6
6
  export declare const REFETCH_ONLY_LIST_CACHE_KEYS: readonly ["entity-data-cursor"];
@@ -1,7 +1,6 @@
1
1
  /**
2
- * What a change frame does to the list caches of one entity. The outcome table
3
- * it applies, and why the client decides nothing itself, is docs/realtime.md
4
- * "Frontend Invalidation".
2
+ * What a change frame does to the list caches of one entity: the client applies
3
+ * a fixed outcome table and decides nothing itself.
5
4
  */
6
5
  import type { QueryClient } from "@tanstack/react-query";
7
6
  import type { ListParams } from "../types/api.d.ts";
@@ -10,7 +9,7 @@ export interface ChangedRow {
10
9
  pk: Record<string, string>;
11
10
  /**
12
11
  * True when nothing but a creation named this row in this window - the one
13
- * absence the client may read as certain. docs/realtime.md.
12
+ * absence the client may read as certain.
14
13
  */
15
14
  createdOnly: boolean;
16
15
  }
@@ -17,7 +17,7 @@ export interface CaptureLocation {
17
17
  * `current` to `destinationPathname`. Returns `undefined` (no capture) when:
18
18
  * - the current path is not a same-origin in-app route,
19
19
  * - the current path is an excluded (auth) route,
20
- * - the destination shares the current PATHNAME (self guard, Invariant 7) -
20
+ * - the destination shares the current PATHNAME (self guard) -
21
21
  * a same-screen, different-query link must not self-stamp a Back.
22
22
  *
23
23
  * `originTab` supplies metadata (id/title/icon/screen) for switching to or
@@ -61,11 +61,9 @@ export interface ResolvedBack {
61
61
  * SWITCH vs REOPEN; the destination URL is always the CAPTURED snapshot. Embed
62
62
  * yields `null` (Back is fallback-only in embed; no tab ops).
63
63
  *
64
- * Divergence from the plan's Invariant 5 (reasoned): the plan preferred the
65
- * live tab's CURRENT search over the captured one, premised on every origin
66
- * screen mirroring its URL into the tab store. That premise is false for custom
67
- * screens (Compare, dashboards) with no per-page mirror, so preferring live
68
- * search loses URL-encoded state (Business Case 3). The captured `returnTo` is
64
+ * The captured `returnTo` wins over the live tab's CURRENT search. Custom
65
+ * screens (Compare, dashboards) do not mirror their URL into the tab store, so
66
+ * the live search would lose URL-encoded state. The captured `returnTo` is
69
67
  * exact at drill time ("where I came from"), so it is the single source of
70
68
  * truth for the destination URL - no per-screen search mirror needed.
71
69
  */
@@ -8,7 +8,7 @@ export interface SortCol {
8
8
  /**
9
9
  * Parse a sort expression string into a list of SortCol entries.
10
10
  *
11
- * Tolerant per plan §5.2:
11
+ * Tolerant:
12
12
  * - empty/null/undefined → []
13
13
  * - missing direction defaults to "asc"
14
14
  * - missing nulls segment is left undefined (system default applies server-side)
@@ -17,12 +17,12 @@ export interface SortCol {
17
17
  */
18
18
  export declare function parseSort(s: string | null | undefined): SortCol[];
19
19
  /**
20
- * Filter a raw sort URL string so $property.* segments (deferred per plan §2)
20
+ * Filter a raw sort URL string so $property.* segments (not yet sortable)
21
21
  * don't reach the backend's strict parser. EVERY OTHER token passes through
22
22
  * unchanged - including malformed grammar like `:nulls_middle` or extra
23
23
  * colons - so the backend can return a typed ValidationError and the SDK
24
- * surfaces the error to the user. Plan §14 strict-parse contract requires
25
- * that grammar violations are NOT silently rewritten on the client.
24
+ * surfaces the error to the user. Grammar violations are NOT silently
25
+ * rewritten on the client.
26
26
  */
27
27
  export declare function stripUnsupportedSortSegments(s: string | null | undefined): string | undefined;
28
28
  /**
@@ -31,12 +31,12 @@ export declare function stripUnsupportedSortSegments(s: string | null | undefine
31
31
  */
32
32
  export declare function serializeSort(cols: SortCol[]): string;
33
33
  /**
34
- * Server-enforced cap (plan §3 Decision 4, §4.2). Mirrored on the client so
34
+ * Server-enforced cap. Mirrored on the client so
35
35
  * we never POST a sort the server will reject with HTTP 400.
36
36
  */
37
37
  export declare const MAX_SORT_COLS = 5;
38
38
  /**
39
- * Shift-click on a column header (plan §7.1).
39
+ * Shift-click on a column header.
40
40
  *
41
41
  * - field already in `prev` → remove it (toggle off).
42
42
  * - field not in `prev` → append { field, dir: "asc" } to the tail.
@@ -54,10 +54,10 @@ export declare const MAX_SORT_COLS = 5;
54
54
  */
55
55
  export declare function applyShiftClickSort(prev: SortCol[], field: string): SortCol[];
56
56
  /**
57
- * "Add to multi-sort" menu action (plan §7.2). Adds `col` to the sort tail
57
+ * "Add to multi-sort" menu action. Adds `col` to the sort tail
58
58
  * with the caller-chosen `dir` + `nulls`. Dedupes: if `col.field` is already
59
59
  * present in `prev`, the earlier occurrence is removed and the new one
60
- * appended at the tail (server rejects duplicate fields, plan §4.2).
60
+ * appended at the tail (server rejects duplicate fields).
61
61
  *
62
62
  * Refuses to grow past {@link MAX_SORT_COLS}: when appending would exceed
63
63
  * the cap AND the field is not already present, returns `prev` unchanged.
@@ -66,7 +66,7 @@ export declare function applyShiftClickSort(prev: SortCol[], field: string): Sor
66
66
  */
67
67
  export declare function applyAppendSort(prev: SortCol[], col: SortCol): SortCol[];
68
68
  /**
69
- * "Clear sort on this column" menu action (plan §7.2). Removes the one
69
+ * "Clear sort on this column" menu action. Removes the one
70
70
  * entry matching `field` from `prev`; returns `prev` unchanged if absent.
71
71
  */
72
72
  export declare function removeSortField(prev: SortCol[], field: string): SortCol[];
@@ -6,8 +6,6 @@
6
6
  * ui-actions `${now}`, TimestampField submit, quick-add defaults, status
7
7
  * history `set_at`. The offset makes the instant unambiguous for passthrough
8
8
  * fields and is stripped by the backend for fields with configured timezone.
9
- *
10
- * See docs/gotchas.md#timezone--unit-conversions.
11
9
  */
12
10
  export declare function formatWireDateTime(date?: Date): string;
13
11
  /**
@@ -25,12 +23,12 @@ export declare function formatWireDateTime(date?: Date): string;
25
23
  * Single source of the offset-resolution algorithm; callers (`formatOffsetTimestamp`
26
24
  * here, `TimestampField`'s display formatter) differ ONLY in the Intl options.
27
25
  */
28
- export declare function formatInOffsetZone(raw: string, options: Intl.DateTimeFormatOptions, locale?: string): string;
26
+ export declare function formatInOffsetZone(raw: string, options: Intl.DateTimeFormatOptions, language?: string): string;
29
27
  /**
30
28
  * Format an offset-aware timestamp for display WITHOUT browser-local
31
29
  * conversion.
32
30
  *
33
- * `DD-MM-YYYY HH:mm`, the same in every locale. Deliberately NOT
31
+ * `DD-MM-YYYY HH:mm`, the same in every language. Deliberately NOT
34
32
  * `dateStyle: "medium"`: that renders "Aug 15, 2026" for one reader and
35
33
  * "15 авг. 2026 г." for another, so two people reading the same screen cannot
36
34
  * quote the same date to each other.
@@ -39,8 +37,8 @@ export declare function formatOffsetTimestamp(raw: string): string;
39
37
  /**
40
38
  * Relative-or-absolute timestamp formatting for the time_ago cell renderer.
41
39
  *
42
- * Returns a short relative phrase ("5 minutes ago", "2 days ago") when the
43
- * timestamp is within the last 30 days, and an ISO date ("2026-01-15") when
40
+ * Returns a short relative phrase in `language` ("5 minutes ago", "hace 2 días")
41
+ * when the timestamp is within 30 days of `now`, and an ISO date ("2026-01-15") when
44
42
  * older. Linear / Stripe / Datadog convention — avoids the "1y 4mo 12d ago"
45
43
  * eyesore for stable historical data.
46
44
  *
@@ -49,7 +47,7 @@ export declare function formatOffsetTimestamp(raw: string): string;
49
47
  *
50
48
  * Bare or unparseable input falls back to the raw string for both fields.
51
49
  */
52
- export declare function formatRelativeOrAbsolute(raw: string | Date | null | undefined, now?: Date): {
50
+ export declare function formatRelativeOrAbsolute(language: string, raw: string | Date | null | undefined, now?: Date): {
53
51
  text: string;
54
52
  absolute: string;
55
53
  };
@@ -1,10 +1,11 @@
1
+ import type { TextFn } from "./language.d.ts";
1
2
  import type { UIStep } from "../types/schema.d.ts";
2
3
  export interface UIActionContext {
3
4
  row?: Record<string, unknown>;
4
5
  params?: Record<string, unknown>;
5
6
  }
6
7
  export declare function interpolate(template: string, ctx: UIActionContext): unknown;
7
- export declare function executeUISteps(steps: UIStep[], ctx: UIActionContext): Promise<void>;
8
+ export declare function executeUISteps(errorTitle: TextFn, steps: UIStep[], ctx: UIActionContext): Promise<void>;
8
9
  export declare function isUIAction(action: {
9
10
  ui_steps?: UIStep[];
10
11
  handler?: string;