@pam-ai/pam-ordo-contracts 3.15.1 → 3.16.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/dist/contract-invariants.d.ts +134 -0
- package/dist/contract-invariants.d.ts.map +1 -0
- package/dist/contract-invariants.js +8 -0
- package/dist/contract-invariants.js.map +1 -0
- package/dist/generated.d.ts +137 -4
- package/dist/generated.d.ts.map +1 -1
- package/dist/index.d.ts +97 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/fixtures/manifest.json +37 -31
- package/fixtures/mention-ref-legacy.json +5 -0
- package/fixtures/mention-ref-outstanding.json +7 -0
- package/fixtures/mention-ref-resolved.json +7 -0
- package/fixtures/resolve-mention-command.json +6 -0
- package/fixtures/resolve-mention-result-nothing-outstanding.json +11 -0
- package/fixtures/resolve-mention-result.json +11 -0
- package/openapi/openapi.json +315 -6
- package/package.json +1 -1
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import type { MentionRef, ResolveMentionResult, SearchInboxContactsParams } from './index.js';
|
|
2
|
+
type Assert<T extends true> = T;
|
|
3
|
+
type Accepts<Value, Shape> = Value extends Shape ? true : false;
|
|
4
|
+
type Rejects<Value, Shape> = Value extends Shape ? false : true;
|
|
5
|
+
/**
|
|
6
|
+
* `GET /v1/inbox/contacts` takes a query, a roState, or both — never neither,
|
|
7
|
+
* and never a roState that names no state.
|
|
8
|
+
*/
|
|
9
|
+
export type SearchInboxContactsInvariants = [
|
|
10
|
+
Assert<Accepts<{
|
|
11
|
+
query: 'ellery';
|
|
12
|
+
}, SearchInboxContactsParams>>,
|
|
13
|
+
Assert<Accepts<{
|
|
14
|
+
roState: ['OPEN'];
|
|
15
|
+
}, SearchInboxContactsParams>>,
|
|
16
|
+
Assert<Accepts<{
|
|
17
|
+
query: 'ellery';
|
|
18
|
+
roState: ['OPEN'];
|
|
19
|
+
}, SearchInboxContactsParams>>,
|
|
20
|
+
Assert<Accepts<{
|
|
21
|
+
roState: ['OPEN'];
|
|
22
|
+
limit: 25;
|
|
23
|
+
}, SearchInboxContactsParams>>,
|
|
24
|
+
Assert<Rejects<Record<string, never>, SearchInboxContactsParams>>,
|
|
25
|
+
Assert<Rejects<{
|
|
26
|
+
limit: 25;
|
|
27
|
+
}, SearchInboxContactsParams>>,
|
|
28
|
+
Assert<Rejects<{
|
|
29
|
+
roState: [];
|
|
30
|
+
}, SearchInboxContactsParams>>,
|
|
31
|
+
Assert<Rejects<{
|
|
32
|
+
roState: [];
|
|
33
|
+
limit: 25;
|
|
34
|
+
}, SearchInboxContactsParams>>
|
|
35
|
+
];
|
|
36
|
+
/** A Mention's two resolution fields move together, or are both absent. */
|
|
37
|
+
export type MentionRefInvariants = [
|
|
38
|
+
Assert<Accepts<{
|
|
39
|
+
id: '1';
|
|
40
|
+
userId: 'u';
|
|
41
|
+
createdAt: 't';
|
|
42
|
+
}, MentionRef>>,
|
|
43
|
+
Assert<Accepts<{
|
|
44
|
+
id: '1';
|
|
45
|
+
userId: 'u';
|
|
46
|
+
createdAt: 't';
|
|
47
|
+
resolvedAt: null;
|
|
48
|
+
resolvedByUserId: null;
|
|
49
|
+
}, MentionRef>>,
|
|
50
|
+
Assert<Accepts<{
|
|
51
|
+
id: '1';
|
|
52
|
+
userId: 'u';
|
|
53
|
+
createdAt: 't';
|
|
54
|
+
resolvedAt: 't';
|
|
55
|
+
resolvedByUserId: 'u';
|
|
56
|
+
}, MentionRef>>,
|
|
57
|
+
Assert<Rejects<{
|
|
58
|
+
id: '1';
|
|
59
|
+
userId: 'u';
|
|
60
|
+
createdAt: 't';
|
|
61
|
+
resolvedAt: 't';
|
|
62
|
+
resolvedByUserId: null;
|
|
63
|
+
}, MentionRef>>,
|
|
64
|
+
Assert<Rejects<{
|
|
65
|
+
id: '1';
|
|
66
|
+
userId: 'u';
|
|
67
|
+
createdAt: 't';
|
|
68
|
+
resolvedAt: null;
|
|
69
|
+
resolvedByUserId: 'u';
|
|
70
|
+
}, MentionRef>>,
|
|
71
|
+
Assert<Rejects<{
|
|
72
|
+
id: '1';
|
|
73
|
+
userId: 'u';
|
|
74
|
+
createdAt: 't';
|
|
75
|
+
resolvedAt: 't';
|
|
76
|
+
}, MentionRef>>,
|
|
77
|
+
Assert<Rejects<{
|
|
78
|
+
id: '1';
|
|
79
|
+
userId: 'u';
|
|
80
|
+
createdAt: 't';
|
|
81
|
+
resolvedByUserId: 'u';
|
|
82
|
+
}, MentionRef>>
|
|
83
|
+
];
|
|
84
|
+
type Outcome = {
|
|
85
|
+
operationId: 'op';
|
|
86
|
+
applied: true;
|
|
87
|
+
replayed: false;
|
|
88
|
+
conversationId: 'c';
|
|
89
|
+
workCycleId: 'w';
|
|
90
|
+
};
|
|
91
|
+
/** Resolving something means it happened at a time. Zero says nothing either way. */
|
|
92
|
+
export type ResolveMentionResultInvariants = [
|
|
93
|
+
Assert<Accepts<{
|
|
94
|
+
data: Outcome & {
|
|
95
|
+
resolvedCount: 3;
|
|
96
|
+
resolvedAt: 't';
|
|
97
|
+
};
|
|
98
|
+
}, ResolveMentionResult>>,
|
|
99
|
+
Assert<Accepts<{
|
|
100
|
+
data: Outcome & {
|
|
101
|
+
resolvedCount: 0;
|
|
102
|
+
resolvedAt: null;
|
|
103
|
+
};
|
|
104
|
+
}, ResolveMentionResult>>,
|
|
105
|
+
Assert<Accepts<{
|
|
106
|
+
data: Outcome & {
|
|
107
|
+
resolvedCount: 0;
|
|
108
|
+
resolvedAt: 't';
|
|
109
|
+
};
|
|
110
|
+
}, ResolveMentionResult>>,
|
|
111
|
+
Assert<Accepts<{
|
|
112
|
+
data: Outcome & {
|
|
113
|
+
resolvedCount: 0;
|
|
114
|
+
};
|
|
115
|
+
}, ResolveMentionResult>>,
|
|
116
|
+
Assert<Rejects<{
|
|
117
|
+
data: Outcome & {
|
|
118
|
+
resolvedCount: 3;
|
|
119
|
+
resolvedAt: null;
|
|
120
|
+
};
|
|
121
|
+
}, ResolveMentionResult>>,
|
|
122
|
+
Assert<Rejects<{
|
|
123
|
+
data: Outcome & {
|
|
124
|
+
resolvedCount: 3;
|
|
125
|
+
};
|
|
126
|
+
}, ResolveMentionResult>>
|
|
127
|
+
];
|
|
128
|
+
/**
|
|
129
|
+
* `resolvedAt` narrows the pairing, which is the reason a reader wants it: the
|
|
130
|
+
* resolver comes back a `string`, not a `string | null`.
|
|
131
|
+
*/
|
|
132
|
+
export declare function mentionResolver(mention: MentionRef): string | null;
|
|
133
|
+
export {};
|
|
134
|
+
//# sourceMappingURL=contract-invariants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract-invariants.d.ts","sourceRoot":"","sources":["../src/contract-invariants.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `resolvedAt` narrows the pairing, which is the reason a reader wants it: the
|
|
3
|
+
* resolver comes back a `string`, not a `string | null`.
|
|
4
|
+
*/
|
|
5
|
+
export function mentionResolver(mention) {
|
|
6
|
+
return mention.resolvedAt ? mention.resolvedByUserId : null;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=contract-invariants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract-invariants.js","sourceRoot":"","sources":["../src/contract-invariants.ts"],"names":[],"mappings":"AA2FA;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,OAAmB;IACjD,OAAO,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9D,CAAC"}
|
package/dist/generated.d.ts
CHANGED
|
@@ -84,6 +84,7 @@ export interface paths {
|
|
|
84
84
|
/**
|
|
85
85
|
* Search the rooftop's Customers to start an outbound Conversation
|
|
86
86
|
* @description The outbound half of the Inbox. The Inbox itself is incoming-only, so a Conversation an advisor needs to START cannot be found in it: the Customer may have no thread at all, only an open repair order, or a thread another advisor owns. This searches the whole rooftop's Customers rather than the reader's own Conversations, and reports how each one already relates to them so the picker can say what opening it will do. Requires VIEW_CUSTOMER_DIRECTORY, which is a stronger grant than VIEW_OWN_INBOX: it exposes Customers the reader has never messaged. Contact detail is hydrated from the system that masters it, so a hydration gap degrades a field and never removes a Customer.
|
|
87
|
+
* SEARCH OR BROWSE, AND ONE OF THEM IS REQUIRED. Supply a query, a roState, or both; supplying neither is a 400 rather than the rooftop's entire book of business, which is a page nobody asked for and the one request most likely to be slow.
|
|
87
88
|
*/
|
|
88
89
|
get: operations["searchInboxContacts"];
|
|
89
90
|
put?: never;
|
|
@@ -418,6 +419,23 @@ export interface paths {
|
|
|
418
419
|
patch?: never;
|
|
419
420
|
trace?: never;
|
|
420
421
|
};
|
|
422
|
+
"/v1/inbox/commands/resolve-mention": {
|
|
423
|
+
parameters: {
|
|
424
|
+
query?: never;
|
|
425
|
+
header?: never;
|
|
426
|
+
path?: never;
|
|
427
|
+
cookie?: never;
|
|
428
|
+
};
|
|
429
|
+
get?: never;
|
|
430
|
+
put?: never;
|
|
431
|
+
/** Mark the caller's outstanding Mentions on one WorkCycle dealt with */
|
|
432
|
+
post: operations["resolveInboxMentions"];
|
|
433
|
+
delete?: never;
|
|
434
|
+
options?: never;
|
|
435
|
+
head?: never;
|
|
436
|
+
patch?: never;
|
|
437
|
+
trace?: never;
|
|
438
|
+
};
|
|
421
439
|
"/v1/inbox/commands/dismiss-notification": {
|
|
422
440
|
parameters: {
|
|
423
441
|
query?: never;
|
|
@@ -827,6 +845,11 @@ export interface components {
|
|
|
827
845
|
data: {
|
|
828
846
|
contacts: components["schemas"]["ContactRow"][];
|
|
829
847
|
};
|
|
848
|
+
/** @description Present on a browse, which can exceed one page. A search is bounded by its own query and may omit this entirely, which is why the envelope is optional rather than required — an existing consumer that never reads it stays valid. */
|
|
849
|
+
meta?: {
|
|
850
|
+
/** @description Opaque keyset cursor, or null on the last page. */
|
|
851
|
+
nextCursor: string | null;
|
|
852
|
+
};
|
|
830
853
|
};
|
|
831
854
|
InboxListResponse: {
|
|
832
855
|
data: {
|
|
@@ -883,7 +906,21 @@ export interface components {
|
|
|
883
906
|
userId: string;
|
|
884
907
|
/** Format: date-time */
|
|
885
908
|
createdAt: string;
|
|
886
|
-
|
|
909
|
+
/**
|
|
910
|
+
* Format: date-time
|
|
911
|
+
* @description When the recipient marked this Mention dealt with, or null while it is still outstanding. A Mention was previously immutable and this is the one thing that may change about it: the words, the author and the recipient never do, and resolution records what the recipient did about it rather than editing what was said. Optional so a producer that predates DASH-322 is still valid; absent reads the same as null.
|
|
912
|
+
*/
|
|
913
|
+
resolvedAt?: string | null;
|
|
914
|
+
/** @description Who resolved it, which is always the recipient — a Mention is recipient-scoped and nobody else can clear somebody's claim on their own attention. Published so a reader can tell a resolution apart from a Mention that was never raised, and so the two fields cannot disagree. Null exactly when resolvedAt is null. */
|
|
915
|
+
resolvedByUserId?: string | null;
|
|
916
|
+
} & (unknown | {
|
|
917
|
+
resolvedAt: null;
|
|
918
|
+
resolvedByUserId: null;
|
|
919
|
+
} | {
|
|
920
|
+
/** Format: date-time */
|
|
921
|
+
resolvedAt: string;
|
|
922
|
+
resolvedByUserId: string;
|
|
923
|
+
});
|
|
887
924
|
VehicleRef: {
|
|
888
925
|
sourceSystem: string;
|
|
889
926
|
externalId: string;
|
|
@@ -934,6 +971,13 @@ export interface components {
|
|
|
934
971
|
displayNumber: components["schemas"]["HydratedText"];
|
|
935
972
|
status: components["schemas"]["HydratedText"];
|
|
936
973
|
vehicle: components["schemas"]["VehicleRef"] | null;
|
|
974
|
+
/**
|
|
975
|
+
* Format: date-time
|
|
976
|
+
* @description When this repair order was opened.
|
|
977
|
+
* ON THE REPAIR ORDER RATHER THAN ON THE ROW THAT CARRIES IT, because that is whose fact it is. Sorting Customers by "most recent open RO" was previously impossible at any cost: neither ContactRow nor this carried a single timestamp, so recency could not be derived by a client or asked for from the service.
|
|
978
|
+
* Nullable, and null is not a defect: a source system that reports a repair order without an open date is publishing what it has, and a row must not disappear because an enrichment did not arrive. Rows with no openedAt sort last under RECENT_REPAIR_ORDER.
|
|
979
|
+
*/
|
|
980
|
+
openedAt?: string | null;
|
|
937
981
|
availability: components["schemas"]["Availability"];
|
|
938
982
|
};
|
|
939
983
|
ConversationDetailResponse: {
|
|
@@ -1420,6 +1464,42 @@ export interface components {
|
|
|
1420
1464
|
/** Format: uuid */
|
|
1421
1465
|
notificationId: string;
|
|
1422
1466
|
};
|
|
1467
|
+
/**
|
|
1468
|
+
* @description Mark the caller's outstanding Mentions on one WorkCycle dealt with.
|
|
1469
|
+
* CONVERSATION-WIDE, NOT PER-MENTION, and the shape is the point. A recipient does not think in Mentions; they think "I have handled this thread". Two colleagues naming the same person in one exchange raises two Mentions, and clearing one of them would leave the row on the Mentions list with nothing on screen to explain why.
|
|
1470
|
+
* It resolves only the CALLER's Mentions. A Mention is a claim on one person's attention, so nobody else can discharge it, and the command carries no recipient for that reason: the identity comes from the token.
|
|
1471
|
+
* Idempotent by operationId, and monotonic besides — resolving an already resolved Mention keeps the first resolvedAt rather than moving it, so a retry cannot rewrite when somebody dealt with something.
|
|
1472
|
+
*/
|
|
1473
|
+
ResolveMentionCommand: {
|
|
1474
|
+
operationId: string;
|
|
1475
|
+
clientOrgId: string;
|
|
1476
|
+
/** Format: uuid */
|
|
1477
|
+
conversationId: string;
|
|
1478
|
+
/** Format: uuid */
|
|
1479
|
+
workCycleId: string;
|
|
1480
|
+
};
|
|
1481
|
+
ResolveMentionResult: {
|
|
1482
|
+
/**
|
|
1483
|
+
* @description RESOLVING SOMETHING MEANS IT HAPPENED AT A TIME. resolvedCount was required while resolvedAt stayed optional and nullable regardless of it, so `{ resolvedCount: 3, resolvedAt: null }` validated — three Mentions dealt with at no moment, which no reader can render and which the rows themselves cannot be in, since the pairing CHECK on conversation_mentions gives every resolved row a timestamp.
|
|
1484
|
+
* One-directional on purpose. A count of zero says nothing about resolvedAt: pressing Done twice, or replying and then pressing it, resolves nothing new and still has a real moment to report from the first time — and a caller who never had a Mention here has none. Both are honest answers, so zero admits a timestamp or null.
|
|
1485
|
+
*/
|
|
1486
|
+
data: {
|
|
1487
|
+
operationId: string;
|
|
1488
|
+
applied: boolean;
|
|
1489
|
+
replayed: boolean;
|
|
1490
|
+
/** Format: uuid */
|
|
1491
|
+
conversationId: string;
|
|
1492
|
+
/** Format: uuid */
|
|
1493
|
+
workCycleId: string;
|
|
1494
|
+
/** @description How many of the caller's Mentions this resolved. Zero is a success, not a failure: it means they had none outstanding, which is the ordinary result of pressing Done twice or of replying first and then pressing it. */
|
|
1495
|
+
resolvedCount: number;
|
|
1496
|
+
/**
|
|
1497
|
+
* Format: date-time
|
|
1498
|
+
* @description When they were resolved. Set whenever anything is or was resolved; null only when the caller had nothing outstanding and nothing already resolved to report.
|
|
1499
|
+
*/
|
|
1500
|
+
resolvedAt?: string | null;
|
|
1501
|
+
};
|
|
1502
|
+
};
|
|
1423
1503
|
BaseCommand: components["schemas"]["CommandEnvelope"];
|
|
1424
1504
|
UserAssignmentTarget: {
|
|
1425
1505
|
/**
|
|
@@ -1674,6 +1754,16 @@ export interface components {
|
|
|
1674
1754
|
"application/json": components["schemas"]["CustomerNoteCommandResult"];
|
|
1675
1755
|
};
|
|
1676
1756
|
};
|
|
1757
|
+
/** @description Applied, replayed, or no-op Mention resolution result. */
|
|
1758
|
+
MentionsResolved: {
|
|
1759
|
+
headers: {
|
|
1760
|
+
"x-correlation-id": components["headers"]["CorrelationId"];
|
|
1761
|
+
[name: string]: unknown;
|
|
1762
|
+
};
|
|
1763
|
+
content: {
|
|
1764
|
+
"application/json": components["schemas"]["ResolveMentionResult"];
|
|
1765
|
+
};
|
|
1766
|
+
};
|
|
1677
1767
|
/** @description Applied, replayed, or monotonic no-op notification state result. */
|
|
1678
1768
|
NotificationCommandApplied: {
|
|
1679
1769
|
headers: {
|
|
@@ -1843,6 +1933,11 @@ export interface components {
|
|
|
1843
1933
|
"application/json": components["schemas"]["DeleteCustomerNoteCommand"];
|
|
1844
1934
|
};
|
|
1845
1935
|
};
|
|
1936
|
+
ResolveMentionCommand: {
|
|
1937
|
+
content: {
|
|
1938
|
+
"application/json": components["schemas"]["ResolveMentionCommand"];
|
|
1939
|
+
};
|
|
1940
|
+
};
|
|
1846
1941
|
NotificationCommand: {
|
|
1847
1942
|
content: {
|
|
1848
1943
|
"application/json": components["schemas"]["NotificationCommand"];
|
|
@@ -2022,9 +2117,25 @@ export interface operations {
|
|
|
2022
2117
|
};
|
|
2023
2118
|
searchInboxContacts: {
|
|
2024
2119
|
parameters: {
|
|
2025
|
-
query
|
|
2026
|
-
/**
|
|
2027
|
-
|
|
2120
|
+
query?: {
|
|
2121
|
+
/**
|
|
2122
|
+
* @description A name fragment, or a telephone number in any format.
|
|
2123
|
+
* OPTIONAL SINCE 3.16.0. It was required, which made the picker a search box and nothing else: an advisor who knew they wanted "whoever has a car in the shop" had to guess a name first. Omitting it now browses rather than searches, and roState is what makes that a useful list instead of the rooftop's entire book of business.
|
|
2124
|
+
*/
|
|
2125
|
+
query?: string;
|
|
2126
|
+
/**
|
|
2127
|
+
* @description Narrow to Customers by the state of their car, using the same three values and the same meanings as the Conversation list: OPEN is a currently active repair order, CLOSED has had one and has none now, NONE never had one.
|
|
2128
|
+
* This is what makes an omitted query answerable. "Everyone with a car in the shop right now" is a question an advisor actually has, and it is bounded by the service drive rather than by the size of the rooftop; "everyone" is not, which is why browsing without either a query or a roState is refused.
|
|
2129
|
+
* An EMPTY ARRAY IS A 400, not an unfiltered browse. Presence is not a filter: `?roState=` names no state, so it would satisfy the at-least-one rule while asking for exactly the unbounded page that rule exists to refuse — and it is the shape a client reaches by serialising an empty selection rather than omitting the parameter, so it arrives by accident rather than by intent.
|
|
2130
|
+
*/
|
|
2131
|
+
roState?: ("OPEN" | "CLOSED" | "NONE")[];
|
|
2132
|
+
/**
|
|
2133
|
+
* @description RECENT_REPAIR_ORDER puts the most recently opened repair order first, which is the order a service drive works in — the car that just arrived is the call that has not been made yet. NAME is the stable alphabetical order a search result wants.
|
|
2134
|
+
* Defaults to NAME when a query is given and RECENT_REPAIR_ORDER when one is not, because a browse has no relevance to fall back on.
|
|
2135
|
+
*/
|
|
2136
|
+
sort?: "NAME" | "RECENT_REPAIR_ORDER";
|
|
2137
|
+
/** @description Opaque keyset cursor. Present because a browse is not bounded the way a search is: a busy rooftop can carry several hundred open repair orders, and a limit alone would silently truncate the answer. */
|
|
2138
|
+
cursor?: string;
|
|
2028
2139
|
/** @description Which side of the directory to read. MINE returns only Customers whose Conversation the reader owns; EVERYONE returns the rest. One set is always in the way of the other, so this is a switch rather than a filter. */
|
|
2029
2140
|
relationship?: "MINE" | "EVERYONE";
|
|
2030
2141
|
limit?: number;
|
|
@@ -2476,6 +2587,28 @@ export interface operations {
|
|
|
2476
2587
|
503: components["responses"]["ServiceUnavailable"];
|
|
2477
2588
|
};
|
|
2478
2589
|
};
|
|
2590
|
+
resolveInboxMentions: {
|
|
2591
|
+
parameters: {
|
|
2592
|
+
query?: never;
|
|
2593
|
+
header: {
|
|
2594
|
+
/** @description Authorized rooftop context. For commands this value must match body.clientOrgId; neither value is trusted without DASH-233 resolution. */
|
|
2595
|
+
"x-client-org-id": components["parameters"]["ClientOrgId"];
|
|
2596
|
+
};
|
|
2597
|
+
path?: never;
|
|
2598
|
+
cookie?: never;
|
|
2599
|
+
};
|
|
2600
|
+
requestBody: components["requestBodies"]["ResolveMentionCommand"];
|
|
2601
|
+
responses: {
|
|
2602
|
+
200: components["responses"]["MentionsResolved"];
|
|
2603
|
+
400: components["responses"]["BadRequest"];
|
|
2604
|
+
401: components["responses"]["Unauthorized"];
|
|
2605
|
+
403: components["responses"]["Forbidden"];
|
|
2606
|
+
404: components["responses"]["NotFound"];
|
|
2607
|
+
409: components["responses"]["Conflict"];
|
|
2608
|
+
500: components["responses"]["InternalError"];
|
|
2609
|
+
503: components["responses"]["ServiceUnavailable"];
|
|
2610
|
+
};
|
|
2611
|
+
};
|
|
2479
2612
|
dismissInboxNotification: {
|
|
2480
2613
|
parameters: {
|
|
2481
2614
|
query?: never;
|