@cobre-npm/library-portal-core 0.56.0 → 0.57.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.
package/README.md CHANGED
@@ -440,8 +440,10 @@ And two on rule 1: `{ minAmount: 1 }` is equality, not `>=`, which is rarely wha
440
440
  ```ts
441
441
  import {
442
442
  getTransactionTypes, queryTransactionTypes, type TransactionType, type TransactionTypeQuery,
443
+ collapseTransactionTypes, type TransactionTypeGroup, type TransactionTypeGroupOption,
443
444
  type Transaction, type EnrichedTransaction, /* ...interfaces */
444
445
  } from "@cobre-npm/library-portal-core/transactions"
446
+ import { isGroupOption, expandGroupSelection } from "@cobre-npm/library-portal-core/filterClassification"
445
447
 
446
448
  getTransactionTypes("en").spei_debit.label // "Outgoing transfer · SPEI"
447
449
  getTransactionTypes("es-mex").spei_debit.label // "Transferencia enviada · SPEI"
@@ -458,6 +460,33 @@ queryTransactionTypes({ lang: "en", category: "top_up" }) // col_top_up_credit
458
460
  "· débito" / "· crédito" (en "· debit" / "· credit") suffix, except `offramp_treasury_credit`, whose label has none; elsewhere the direction is in the verb
459
461
  ("Outgoing transfer", "Incoming transfer"). `col_cb_*` keeps "Cobre Balance" in its label. `misc_*`,
460
462
  `internal_*` and `adjustment_*` have `line: "unclassified"`, and `misc_*` also `category: "unclassified"`.
463
+ Each type also carries a required `section: FilterClassificationSection`, the heading it is listed under in the
464
+ grouped filter (group members take their group's section; `internal_spei_*`, `col_cb_debit` → `internal`,
465
+ `misc_*` → `connected_account`).
466
+ - **conditional marker**: five rarely used types (`misc_debit`, `misc_credit`, `col_cb_debit`, `internal_spei_debit`,
467
+ `internal_spei_credit`) carry `filterDisplay: "when_present"`: the grouped filter should list them only when the
468
+ data has them. It is descriptive, not a visibility switch: there is no default, `queryTransactionTypes()` still
469
+ returns them and their labels are unchanged, so flat filters see no difference. The field is absent on every
470
+ other type, so read it with `"filterDisplay" in type`.
471
+ - **group**: every type carries a required `group: TransactionTypeGroup | null`. The 14 debit/credit legs name
472
+ one of 7 UI-only groups (`cbmm`, `global_pay_to_usa`, `usa_pay_to_global`, `on_ramp`, `off_ramp`,
473
+ `stable_payout`, `internal`); every other type is `null`. A group code is **never** a transaction type and is
474
+ never sent to the API: selecting a group means selecting its member codes (`expandGroupSelection`). There is no
475
+ separate groups catalog; group labels come out of `collapseTransactionTypes`.
476
+ - **collapse** (i18n): `collapseTransactionTypes({ lang, ...filters })` takes the same query as
477
+ `queryTransactionTypes`, filters first, then folds each group into one `TransactionTypeGroupOption`
478
+ `{ code, members, line, category, section, label }`, placed at its first member's position. A group collapses
479
+ only if **all** its legs survive the filter; otherwise the surviving legs come out as plain options. Tell the
480
+ two apart with `isGroupOption` (from [`filterClassification`](#filterclassification)), which also feeds
481
+ `expandGroupSelection` / `getGroupSelectionState`:
482
+
483
+ ```ts
484
+ collapseTransactionTypes({ lang: "en", category: "conversions" }).map(option => option.code)
485
+ // 7 conversion types → 4 options: ["on_ramp", "off_ramp", "stable_payout", "offramp_treasury_credit"]
486
+ collapseTransactionTypes({ lang: "en", creditDebitType: "debit" }) // no group survives: plain legs only
487
+ const groups = collapseTransactionTypes({ lang: "en" }).filter(isGroupOption)
488
+ expandGroupSelection(["cbmm", "spei_debit"], groups) // ["cbmm_debit", "cbmm_credit", "spei_debit"]
489
+ ```
461
490
  - **types query** (i18n `queryX()`): `queryTransactionTypes({ lang, ...filters })` — `lang` is **required inside
462
491
  the query object**, not a separate argument, so the result is already localized. There is no default field
463
492
  (unlike `currencies`' `scope`): every transaction type comes back when only `lang` is given.
@@ -483,7 +512,7 @@ the headings inside a chip, and **types** (movement / transaction types) are the
483
512
  ```ts
484
513
  import {
485
514
  getFilterClassificationCategoryFamilies, getFilterClassificationSections, splitTypeLabel,
486
- expandGroupSelection, getGroupSelectionState,
515
+ expandGroupSelection, getGroupSelectionState, isGroupOption,
487
516
  type FilterClassificationCategoryFamily, type FilterClassificationSection,
488
517
  type FilterClassificationCategory, type FilterClassificationRecord,
489
518
  } from "@cobre-npm/library-portal-core/filterClassification"
@@ -493,6 +522,7 @@ declare const record: { section: FilterClassificationSection } // one of tho
493
522
  declare const groups: FilterClassificationRecord<string>[] // the UI's group records
494
523
  declare const group: FilterClassificationRecord<string> // one of them
495
524
  declare const selectedCodes: string[] // what the user has ticked
525
+ declare const options: ({ code: string } | FilterClassificationRecord<string>)[] // a mixed list: plain and group options
496
526
 
497
527
  const families = getFilterClassificationCategoryFamilies("en")
498
528
  families.between_accounts.label // "Between accounts"
@@ -503,6 +533,7 @@ splitTypeLabel("Transfer · ACH") // { title: "Transfe
503
533
  splitTypeLabel("International") // { title: "International" } — no empty rail
504
534
  expandGroupSelection(["stablecoin_group", "ach"], groups) // member codes + "ach"; the group code is never returned
505
535
  getGroupSelectionState(group, selectedCodes) // "checked" | "indeterminate" | "unchecked"
536
+ options.filter(isGroupOption) // only the group options, typed as such
506
537
  ```
507
538
 
508
539
  - **Family** (`FilterClassificationCategoryFamily`): the chips of the grouped type filter, in chip order: `payments`, `collections`,
@@ -517,9 +548,9 @@ getGroupSelectionState(group, selectedCodes) // "checked" | "indet
517
548
  never sent to an API. `getFilterClassificationSections(lang)`. `internal` and `connected_account` exist but no movement type uses
518
549
  them yet.
519
550
  - **`splitTypeLabel(label)`**: splits at the first `" · "` into `{ title, rail? }` for two-line options.
520
- - **group helpers**: `FilterClassificationRecord<Code>` (`code`, `members`, `line`, `category`, `section`). A group code is a UI
521
- identifier: `expandGroupSelection` swaps it for its members before calling an API, and `getGroupSelectionState`
522
- gives the checkbox state from the selected member codes.
551
+ - **group helpers**: `FilterClassificationRecord<Code, Member = Code>` (`code`, `members`, `line`, `category`, `section`). A group code is a UI
552
+ identifier: `expandGroupSelection` swaps it for its members before calling an API, `getGroupSelectionState`
553
+ gives the checkbox state from the selected member codes, and `isGroupOption` tells group options from plain ones in a mixed list.
523
554
 
524
555
  ### `trustedSessions`
525
556
 
@@ -5,9 +5,9 @@ import type { FilterClassificationSection } from "../sections/catalog";
5
5
  * A selectable group of type codes (one checkbox that stands for several types). The group `code` is a UI
6
6
  * identifier: it is never sent to an API, only its `members` are — see `expandGroupSelection`.
7
7
  */
8
- export type FilterClassificationRecord<Code extends string> = {
8
+ export type FilterClassificationRecord<Code extends string, Member extends string = Code> = {
9
9
  readonly code: Code;
10
- readonly members: readonly Code[];
10
+ readonly members: readonly Member[];
11
11
  readonly line: BusinessLine;
12
12
  readonly category: FilterClassificationCategory;
13
13
  readonly section: FilterClassificationSection;
@@ -1,9 +1,13 @@
1
1
  import type { FilterClassificationRecord } from "../interfaces/filter-classification.interface";
2
2
  export type GroupSelectionState = "checked" | "indeterminate" | "unchecked";
3
+ /** Tells a group option (it has `members`) from a plain option, narrowing a mixed list of both. */
4
+ export declare const isGroupOption: <Option extends object>(option: Option) => option is Extract<Option, {
5
+ readonly members: readonly string[];
6
+ }>;
3
7
  /**
4
8
  * The codes to send to an API: each selected group code is replaced by its members, anything else passes
5
9
  * through. The group code itself never appears in the output, and repeated codes are dropped.
6
10
  */
7
- export declare const expandGroupSelection: <Code extends string>(selected: readonly Code[], groups: readonly FilterClassificationRecord<Code>[]) => Code[];
11
+ export declare const expandGroupSelection: <Code extends string, Member extends string = Code>(selected: readonly (Code | Member)[], groups: readonly FilterClassificationRecord<Code, Member>[]) => Member[];
8
12
  /** checked = every member selected, indeterminate = some, unchecked = none (or a group without members). */
9
- export declare const getGroupSelectionState: <Code extends string>(group: FilterClassificationRecord<Code>, selected: readonly Code[]) => GroupSelectionState;
13
+ export declare const getGroupSelectionState: <Code extends string, Member extends string = Code>(group: FilterClassificationRecord<Code, Member>, selected: readonly Member[]) => GroupSelectionState;
@@ -1,6 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getGroupSelectionState = exports.expandGroupSelection = void 0;
3
+ exports.getGroupSelectionState = exports.expandGroupSelection = exports.isGroupOption = void 0;
4
+ /** Tells a group option (it has `members`) from a plain option, narrowing a mixed list of both. */
5
+ const isGroupOption = (option) => "members" in option;
6
+ exports.isGroupOption = isGroupOption;
4
7
  /**
5
8
  * The codes to send to an API: each selected group code is replaced by its members, anything else passes
6
9
  * through. The group code itself never appears in the output, and repeated codes are dropped.
@@ -1,3 +1,3 @@
1
- export type { TransactionType } from "./types/catalog";
1
+ export type { TransactionType, TransactionTypeGroup } from "./types/catalog";
2
2
  export * from "./types/utils/transaction-type.utils";
3
3
  export * from "./interfaces/response.interface";
@@ -4,289 +4,397 @@ export declare const TRANSACTION_TYPES: {
4
4
  readonly code: "spei_debit";
5
5
  readonly line: "payout";
6
6
  readonly category: "payments";
7
+ readonly section: "mxn";
8
+ readonly group: null;
7
9
  };
8
10
  readonly spei_credit: {
9
11
  readonly creditDebitType: "credit";
10
12
  readonly code: "spei_credit";
11
13
  readonly line: "payin";
12
14
  readonly category: "collections";
15
+ readonly section: "mxn";
16
+ readonly group: null;
13
17
  };
14
18
  readonly spei_return: {
15
19
  readonly creditDebitType: "credit";
16
20
  readonly code: "spei_return";
17
21
  readonly line: "payout";
18
22
  readonly category: "payments";
23
+ readonly section: "mxn";
24
+ readonly group: null;
19
25
  };
20
26
  readonly spei_rejected: {
21
27
  readonly creditDebitType: "credit";
22
28
  readonly code: "spei_rejected";
23
29
  readonly line: "payout";
24
30
  readonly category: "payments";
31
+ readonly section: "mxn";
32
+ readonly group: null;
25
33
  };
26
34
  readonly internal_spei_debit: {
27
35
  readonly creditDebitType: "debit";
28
36
  readonly code: "internal_spei_debit";
29
37
  readonly line: "unclassified";
30
38
  readonly category: "between_accounts";
39
+ readonly section: "internal";
40
+ readonly group: null;
41
+ readonly filterDisplay: "when_present";
31
42
  };
32
43
  readonly internal_spei_credit: {
33
44
  readonly creditDebitType: "credit";
34
45
  readonly code: "internal_spei_credit";
35
46
  readonly line: "unclassified";
36
47
  readonly category: "between_accounts";
48
+ readonly section: "internal";
49
+ readonly group: null;
50
+ readonly filterDisplay: "when_present";
37
51
  };
38
52
  readonly adjustment_credit: {
39
53
  readonly creditDebitType: "credit";
40
54
  readonly code: "adjustment_credit";
41
55
  readonly line: "unclassified";
42
56
  readonly category: "adjustment";
57
+ readonly section: "internal";
58
+ readonly group: null;
43
59
  };
44
60
  readonly adjustment_debit: {
45
61
  readonly creditDebitType: "debit";
46
62
  readonly code: "adjustment_debit";
47
63
  readonly line: "unclassified";
48
64
  readonly category: "adjustment";
65
+ readonly section: "internal";
66
+ readonly group: null;
49
67
  };
50
68
  readonly mex_debit: {
51
69
  readonly creditDebitType: "debit";
52
70
  readonly code: "mex_debit";
53
71
  readonly line: "payout";
54
72
  readonly category: "payments";
73
+ readonly section: "connected_account";
74
+ readonly group: null;
55
75
  };
56
76
  readonly mex_credit: {
57
77
  readonly creditDebitType: "credit";
58
78
  readonly code: "mex_credit";
59
79
  readonly line: "payout";
60
80
  readonly category: "payments";
81
+ readonly section: "connected_account";
82
+ readonly group: null;
61
83
  };
62
84
  readonly col_debit: {
63
85
  readonly creditDebitType: "debit";
64
86
  readonly code: "col_debit";
65
87
  readonly line: "payout";
66
88
  readonly category: "payments";
89
+ readonly section: "connected_account";
90
+ readonly group: null;
67
91
  };
68
92
  readonly col_credit: {
69
93
  readonly creditDebitType: "credit";
70
94
  readonly code: "col_credit";
71
95
  readonly line: "payout";
72
96
  readonly category: "payments";
97
+ readonly section: "connected_account";
98
+ readonly group: null;
73
99
  };
74
100
  readonly misc_debit: {
75
101
  readonly creditDebitType: "debit";
76
102
  readonly code: "misc_debit";
77
103
  readonly line: "unclassified";
78
104
  readonly category: "unclassified";
105
+ readonly section: "connected_account";
106
+ readonly group: null;
107
+ readonly filterDisplay: "when_present";
79
108
  };
80
109
  readonly misc_credit: {
81
110
  readonly creditDebitType: "credit";
82
111
  readonly code: "misc_credit";
83
112
  readonly line: "unclassified";
84
113
  readonly category: "unclassified";
114
+ readonly section: "connected_account";
115
+ readonly group: null;
116
+ readonly filterDisplay: "when_present";
85
117
  };
86
118
  readonly internal_credit: {
87
119
  readonly creditDebitType: "credit";
88
120
  readonly code: "internal_credit";
89
121
  readonly line: "unclassified";
90
122
  readonly category: "between_accounts";
123
+ readonly section: "internal";
124
+ readonly group: "internal";
91
125
  };
92
126
  readonly internal_debit: {
93
127
  readonly creditDebitType: "debit";
94
128
  readonly code: "internal_debit";
95
129
  readonly line: "unclassified";
96
130
  readonly category: "between_accounts";
131
+ readonly section: "internal";
132
+ readonly group: "internal";
97
133
  };
98
134
  readonly r2p_credit: {
99
135
  readonly creditDebitType: "credit";
100
136
  readonly code: "r2p_credit";
101
137
  readonly line: "payin";
102
138
  readonly category: "collections";
139
+ readonly section: "cop";
140
+ readonly group: null;
103
141
  };
104
142
  readonly cbmm_debit: {
105
143
  readonly creditDebitType: "debit";
106
144
  readonly code: "cbmm_debit";
107
145
  readonly line: "cbmm";
108
146
  readonly category: "international";
147
+ readonly section: "corridors";
148
+ readonly group: "cbmm";
109
149
  };
110
150
  readonly cbmm_credit: {
111
151
  readonly creditDebitType: "credit";
112
152
  readonly code: "cbmm_credit";
113
153
  readonly line: "cbmm";
114
154
  readonly category: "international";
155
+ readonly section: "corridors";
156
+ readonly group: "cbmm";
115
157
  };
116
158
  readonly dd_credit: {
117
159
  readonly creditDebitType: "credit";
118
160
  readonly code: "dd_credit";
119
161
  readonly line: "payin";
120
162
  readonly category: "collections";
163
+ readonly section: "cop";
164
+ readonly group: null;
121
165
  };
122
166
  readonly col_cb_credit: {
123
167
  readonly creditDebitType: "credit";
124
168
  readonly code: "col_cb_credit";
125
169
  readonly line: "payin";
126
170
  readonly category: "between_accounts";
171
+ readonly section: "internal";
172
+ readonly group: null;
127
173
  };
128
174
  readonly col_cb_debit: {
129
175
  readonly creditDebitType: "debit";
130
176
  readonly code: "col_cb_debit";
131
177
  readonly line: "payin";
132
178
  readonly category: "between_accounts";
179
+ readonly section: "internal";
180
+ readonly group: null;
181
+ readonly filterDisplay: "when_present";
133
182
  };
134
183
  readonly breb_credit: {
135
184
  readonly creditDebitType: "credit";
136
185
  readonly code: "breb_credit";
137
186
  readonly line: "payin";
138
187
  readonly category: "collections";
188
+ readonly section: "cop";
189
+ readonly group: null;
139
190
  };
140
191
  readonly breb_debit: {
141
192
  readonly creditDebitType: "debit";
142
193
  readonly code: "breb_debit";
143
194
  readonly line: "payout";
144
195
  readonly category: "payments";
196
+ readonly section: "cop";
197
+ readonly group: null;
145
198
  };
146
199
  readonly r2p_breb_credit: {
147
200
  readonly creditDebitType: "credit";
148
201
  readonly code: "r2p_breb_credit";
149
202
  readonly line: "payin";
150
203
  readonly category: "collections";
204
+ readonly section: "cop";
205
+ readonly group: null;
151
206
  };
152
207
  readonly breb_rejected: {
153
208
  readonly creditDebitType: "credit";
154
209
  readonly code: "breb_rejected";
155
210
  readonly line: "payout";
156
211
  readonly category: "payments";
212
+ readonly section: "cop";
213
+ readonly group: null;
157
214
  };
158
215
  readonly col_top_up_credit: {
159
216
  readonly creditDebitType: "credit";
160
217
  readonly code: "col_top_up_credit";
161
218
  readonly line: "payin";
162
219
  readonly category: "top_up";
220
+ readonly section: "internal";
221
+ readonly group: null;
163
222
  };
164
223
  readonly global_debit: {
165
224
  readonly creditDebitType: "debit";
166
225
  readonly code: "global_debit";
167
226
  readonly line: "payout";
168
227
  readonly category: "payments";
228
+ readonly section: "usd_global";
229
+ readonly group: null;
169
230
  };
170
231
  readonly global_credit: {
171
232
  readonly creditDebitType: "credit";
172
233
  readonly code: "global_credit";
173
234
  readonly line: "cbmm";
174
235
  readonly category: "collections";
236
+ readonly section: "usd_global";
237
+ readonly group: null;
175
238
  };
176
239
  readonly r2p_spei_credit: {
177
240
  readonly creditDebitType: "credit";
178
241
  readonly code: "r2p_spei_credit";
179
242
  readonly line: "payin";
180
243
  readonly category: "collections";
244
+ readonly section: "mxn";
245
+ readonly group: null;
181
246
  };
182
247
  readonly transfer_credit: {
183
248
  readonly creditDebitType: "credit";
184
249
  readonly code: "transfer_credit";
185
250
  readonly line: "payin";
186
251
  readonly category: "collections";
252
+ readonly section: "connected_account";
253
+ readonly group: null;
187
254
  };
188
255
  readonly fedwire_debit: {
189
256
  readonly creditDebitType: "debit";
190
257
  readonly code: "fedwire_debit";
191
258
  readonly line: "payout";
192
259
  readonly category: "payments";
260
+ readonly section: "usd_global";
261
+ readonly group: null;
193
262
  };
194
263
  readonly fedwire_credit: {
195
264
  readonly creditDebitType: "credit";
196
265
  readonly code: "fedwire_credit";
197
266
  readonly line: "cbmm";
198
267
  readonly category: "collections";
268
+ readonly section: "usd_global";
269
+ readonly group: null;
199
270
  };
200
271
  readonly reward_credit: {
201
272
  readonly creditDebitType: "credit";
202
273
  readonly code: "reward_credit";
203
274
  readonly line: "stable";
204
275
  readonly category: "reward";
276
+ readonly section: "internal";
277
+ readonly group: null;
205
278
  };
206
279
  readonly global_pay_to_usa_debit: {
207
280
  readonly creditDebitType: "debit";
208
281
  readonly code: "global_pay_to_usa_debit";
209
282
  readonly line: "cbmm";
210
283
  readonly category: "international";
284
+ readonly section: "corridors";
285
+ readonly group: "global_pay_to_usa";
211
286
  };
212
287
  readonly global_pay_to_usa_credit: {
213
288
  readonly creditDebitType: "credit";
214
289
  readonly code: "global_pay_to_usa_credit";
215
290
  readonly line: "cbmm";
216
291
  readonly category: "international";
292
+ readonly section: "corridors";
293
+ readonly group: "global_pay_to_usa";
217
294
  };
218
295
  readonly usa_pay_to_global_debit: {
219
296
  readonly creditDebitType: "debit";
220
297
  readonly code: "usa_pay_to_global_debit";
221
298
  readonly line: "cbmm";
222
299
  readonly category: "international";
300
+ readonly section: "corridors";
301
+ readonly group: "usa_pay_to_global";
223
302
  };
224
303
  readonly usa_pay_to_global_credit: {
225
304
  readonly creditDebitType: "credit";
226
305
  readonly code: "usa_pay_to_global_credit";
227
306
  readonly line: "cbmm";
228
307
  readonly category: "international";
308
+ readonly section: "corridors";
309
+ readonly group: "usa_pay_to_global";
229
310
  };
230
311
  readonly onramp_credit: {
231
312
  readonly creditDebitType: "credit";
232
313
  readonly code: "onramp_credit";
233
314
  readonly line: "stable";
234
315
  readonly category: "conversions";
316
+ readonly section: "usd_global";
317
+ readonly group: "on_ramp";
235
318
  };
236
319
  readonly offramp_debit: {
237
320
  readonly creditDebitType: "debit";
238
321
  readonly code: "offramp_debit";
239
322
  readonly line: "stable";
240
323
  readonly category: "conversions";
324
+ readonly section: "usd_global";
325
+ readonly group: "off_ramp";
241
326
  };
242
327
  readonly stable_payout_debit: {
243
328
  readonly creditDebitType: "debit";
244
329
  readonly code: "stable_payout_debit";
245
330
  readonly line: "stable";
246
331
  readonly category: "conversions";
332
+ readonly section: "usd_global";
333
+ readonly group: "stable_payout";
247
334
  };
248
335
  readonly stable_payout_credit: {
249
336
  readonly creditDebitType: "credit";
250
337
  readonly code: "stable_payout_credit";
251
338
  readonly line: "stable";
252
339
  readonly category: "conversions";
340
+ readonly section: "usd_global";
341
+ readonly group: "stable_payout";
253
342
  };
254
343
  readonly global_pay_to_generic_debit: {
255
344
  readonly creditDebitType: "debit";
256
345
  readonly code: "global_pay_to_generic_debit";
257
346
  readonly line: "payout";
258
347
  readonly category: "payments";
348
+ readonly section: "usd_global";
349
+ readonly group: null;
259
350
  };
260
351
  readonly global_pay_to_generic_credit: {
261
352
  readonly creditDebitType: "credit";
262
353
  readonly code: "global_pay_to_generic_credit";
263
354
  readonly line: "cbmm";
264
355
  readonly category: "collections";
356
+ readonly section: "usd_global";
357
+ readonly group: null;
265
358
  };
266
359
  readonly global_rejected: {
267
360
  readonly creditDebitType: "credit";
268
361
  readonly code: "global_rejected";
269
362
  readonly line: "cbmm";
270
363
  readonly category: "collections";
364
+ readonly section: "usd_global";
365
+ readonly group: null;
271
366
  };
272
367
  readonly offramp_treasury_credit: {
273
368
  readonly creditDebitType: "credit";
274
369
  readonly code: "offramp_treasury_credit";
275
370
  readonly line: "stable";
276
371
  readonly category: "conversions";
372
+ readonly section: "usd_global";
373
+ readonly group: null;
277
374
  };
278
375
  readonly onramp_debit: {
279
376
  readonly creditDebitType: "debit";
280
377
  readonly code: "onramp_debit";
281
378
  readonly line: "stable";
282
379
  readonly category: "conversions";
380
+ readonly section: "usd_global";
381
+ readonly group: "on_ramp";
283
382
  };
284
383
  readonly offramp_credit: {
285
384
  readonly creditDebitType: "credit";
286
385
  readonly code: "offramp_credit";
287
386
  readonly line: "stable";
288
387
  readonly category: "conversions";
388
+ readonly section: "usd_global";
389
+ readonly group: "off_ramp";
289
390
  };
290
391
  };
392
+ /** `when_present`: shown in the grouped type filter only when the data contains it. */
393
+ export type TransactionTypeFilterDisplay = "when_present";
291
394
  export type TransactionType = keyof typeof TRANSACTION_TYPES;
292
395
  export type TransactionTypeRecord = (typeof TRANSACTION_TYPES)[TransactionType];
396
+ /**
397
+ * UI-only code for the debit/credit legs shown as one option in the grouped type filter. Derived from the
398
+ * catalog's `group` values; never a key of TRANSACTION_TYPES and never sent to an API (see `expandGroupSelection`).
399
+ */
400
+ export type TransactionTypeGroup = Exclude<TransactionTypeRecord["group"], null>;