@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.
@@ -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"}
@@ -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
- /** @description A name fragment, or a telephone number in any format. */
2027
- query: string;
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;